Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import logging

from openupgradelib import openupgrade

_logger = logging.getLogger(__name__)

# Kept small so each browse+compute+flush cycle stays within the container
# memory budget: the cache is dropped between chunks (invalidate_cache), so
# peak memory is one chunk, not the whole table. No commit inside the loop:
# @openupgrade.migrate() wraps the script in a savepoint (a commit would
# destroy it -> RELEASE SAVEPOINT crashes on exit) and the module upgrade
# must stay transactional; flushed rows live in the module's transaction.
CHUNK = 5000


def _batched_recompute(env, model_name, fname):
"""Recompute one stored computed field over the whole table, in
memory-safe chunks, using the model's OWN compute method via the ORM.

The column was pre-created empty in pre-migration to skip the ORM's
whole-table mass init (which OOM-kills the upgrade). Here we fill it: the
compute is triggered through the ORM (add_to_compute + flush), so the
vendor's real compute logic runs — we never need to read or reimplement
it. Self-contained: the field is created AND filled within this same hop.
"""
model = env[model_name].with_context(active_test=False, prefetch_fields=False)
field = model._fields[fname]
env.cr.execute('SELECT id FROM "%s" ORDER BY id' % model._table)
ids = [row[0] for row in env.cr.fetchall()]
total = len(ids)
_logger.info(
"recompute %s.%s over %s rows (chunk %s)", model_name, fname, total, CHUNK
)
for start in range(0, total, CHUNK):
recs = model.browse(ids[start : start + CHUNK])
env.add_to_compute(field, recs)
recs.flush([fname], recs)
recs.invalidate_cache()
if start and start % (CHUNK * 20) == 0:
_logger.info(" ... %s/%s", start, total)
_logger.info("recompute %s.%s done", model_name, fname)


@openupgrade.migrate()
def migrate(env, version):
_batched_recompute(env, "account.move.line", "l10n_pt_account_expected_balance")
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from openupgradelib import openupgrade


@openupgrade.migrate()
def migrate(env, version):
# Some 14.0 databases already carry l10n_pt_vat_adjustment_norm_id (the
# 15.0 target name) while the old vat_adjustment_norm_id duplicate also
# exists on account_move. The module's own pre-migration then calls
# openupgrade.rename_fields() old -> new and fails because the target
# exists. Drop the old duplicate first, but only when it is provably
# empty. Named pre-00-* so it sorts — and therefore runs — before the
# module's own pre-migration.py (same-version stage scripts execute in
# basename order).
cr = env.cr
if not (
openupgrade.column_exists(cr, "account_move", "vat_adjustment_norm_id")
and openupgrade.column_exists(
cr, "account_move", "l10n_pt_vat_adjustment_norm_id"
)
):
return
cr.execute(
"SELECT count(*) FROM account_move WHERE vat_adjustment_norm_id IS NOT NULL"
)
old_non_null = cr.fetchone()[0]
if old_non_null:
raise RuntimeError(
"Refusing to drop account_move.vat_adjustment_norm_id: "
"%s non-null rows" % old_non_null
)
openupgrade.logged_query(
cr,
"""
DELETE FROM ir_model_data
WHERE model = 'ir.model.fields'
AND res_id IN (
SELECT id FROM ir_model_fields
WHERE model = 'account.move'
AND name = 'vat_adjustment_norm_id'
)
""",
)
openupgrade.logged_query(
cr,
"""
DELETE FROM ir_model_fields
WHERE model = 'account.move'
AND name = 'vat_adjustment_norm_id'
""",
)
openupgrade.logged_query(
cr, "ALTER TABLE account_move DROP COLUMN vat_adjustment_norm_id"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from openupgradelib import openupgrade


@openupgrade.migrate()
def migrate(env, version):
# The 15.0.5.0.0 upgrade adds the stored computed field
# account_move_line.l10n_pt_account_expected_balance. Creating the column
# here makes the ORM skip its whole-table "Storing computed values" pass
# (millions of rows), which cannot fit in memory during `-u all`. The
# field is recomputed in controlled batches at the target version.
openupgrade.logged_query(
env.cr,
"""
ALTER TABLE account_move_line
ADD COLUMN IF NOT EXISTS l10n_pt_account_expected_balance numeric
""",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import logging

from openupgradelib import openupgrade

_logger = logging.getLogger(__name__)

# Kept small so each browse+compute+flush cycle stays within the container
# memory budget: the cache is dropped between chunks (invalidate_cache), so
# peak memory is one chunk, not the whole table. No commit inside the loop:
# @openupgrade.migrate() wraps the script in a savepoint (a commit would
# destroy it -> RELEASE SAVEPOINT crashes on exit) and the module upgrade
# must stay transactional; flushed rows live in the module's transaction.
CHUNK = 5000


def _batched_recompute(env, model_name, fname):
"""Recompute one stored computed field over the whole table, in
memory-safe chunks, using the model's OWN compute method via the ORM.

The column was pre-created empty in pre-migration to skip the ORM's
whole-table mass init (which OOM-kills the upgrade). Here we fill it: the
compute is triggered through the ORM (add_to_compute + flush), so the
vendor's real compute logic runs — we never need to read or reimplement
it. Self-contained: the field is created AND filled within this same hop.
"""
model = env[model_name].with_context(active_test=False, prefetch_fields=False)
field = model._fields[fname]
env.cr.execute('SELECT id FROM "%s" ORDER BY id' % model._table)
ids = [row[0] for row in env.cr.fetchall()]
total = len(ids)
_logger.info(
"recompute %s.%s over %s rows (chunk %s)", model_name, fname, total, CHUNK
)
for start in range(0, total, CHUNK):
recs = model.browse(ids[start : start + CHUNK])
env.add_to_compute(field, recs)
recs.flush([fname], recs)
recs.invalidate_cache()
if start and start % (CHUNK * 20) == 0:
_logger.info(" ... %s/%s", start, total)
_logger.info("recompute %s.%s done", model_name, fname)


@openupgrade.migrate()
def migrate(env, version):
_batched_recompute(env, "stock.picking", "l10n_pt_is_national")
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from openupgradelib import openupgrade


@openupgrade.migrate()
def migrate(env, version):
# The 15.0.5.0.0 upgrade adds the stored computed field
# stock_picking.l10n_pt_is_national. Creating the column here makes the
# ORM skip its whole-table "Storing computed values" pass (millions of
# rows), which cannot fit in memory during `-u all`. The field is
# recomputed in controlled batches at the target version.
openupgrade.logged_query(
env.cr,
"""
ALTER TABLE stock_picking
ADD COLUMN IF NOT EXISTS l10n_pt_is_national boolean
""",
)
Loading