Skip to content

Commit 76a88d5

Browse files
committed
[MIG] l10n_ar_ux: new approach
1 parent 826bcf2 commit 76a88d5

File tree

2 files changed

+83
-110
lines changed

2 files changed

+83
-110
lines changed
Lines changed: 55 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,74 @@
11
import logging
22

3-
from openupgradelib import openupgrade_merge_records
4-
5-
from odoo import SUPERUSER_ID, api
6-
73
logger = logging.getLogger(__name__)
84

95

10-
def _cleanup_orphan_references(cr, model_table):
11-
"""Nullify references to activities that no longer exist after merging."""
12-
logger.info("Cleaning up orphan references to %s", model_table)
13-
column = "l10n_ar_arca_activity_id"
14-
for table in ["res_company", "account_account"]:
15-
cr.execute(
16-
f"""
17-
UPDATE {table}
18-
SET {column} = NULL
19-
WHERE NOT EXISTS (
20-
SELECT 1 FROM {model_table} WHERE id = {table}.{column}
21-
)
22-
"""
23-
)
24-
if cr.rowcount:
25-
logger.info(
26-
"Cleaned %d orphan references in table '%s'", cr.rowcount, table
27-
)
28-
29-
306
def migrate(cr, version):
31-
"""Merge duplicate records in l10n_ar.arca.activity based on the 'code' field.
32-
33-
This handles the case where activities were user-created in the old model (afip.activity)
34-
but are now created as data in the new model (l10n_ar.arca.activity), which can lead
35-
to duplicates after migration.
7+
"""Update references to use new activity records based on code matching.
8+
After the module loads new l10n_ar.arca.activity records, we update the foreign keys
9+
in account_account and res_company to point to these new records based on matching codes.
3610
"""
37-
model_name = "l10n_ar.arca.activity"
38-
model_table = "l10n_ar_arca_activity"
11+
new_table = "l10n_ar_arca_activity"
12+
backup_table = "afip_activity_bu"
13+
new_field = "l10n_ar_arca_activity_id"
14+
backup_field = "l10n_ar_afip_activity_id_bu"
3915

40-
# Find duplicate codes
16+
# Update account_account references
17+
logger.info("Updating %s references in account_account", new_field)
4118
cr.execute(
4219
f"""
43-
SELECT code, array_agg(id ORDER BY id) as ids
44-
FROM {model_table}
45-
WHERE code IS NOT NULL
46-
GROUP BY code
47-
HAVING COUNT(*) > 1
20+
UPDATE account_account
21+
SET {new_field} = (
22+
SELECT new_act.id
23+
FROM {new_table} new_act
24+
JOIN {backup_table} old_act ON new_act.code = old_act.code
25+
WHERE old_act.id = account_account.{backup_field}
26+
)
27+
WHERE {backup_field} IS NOT NULL
4828
"""
4929
)
30+
logger.info("Updated %d records in account_account", cr.rowcount)
5031

51-
duplicates = cr.fetchall()
52-
if not duplicates:
53-
logger.info("No duplicate activities found based on 'code' field")
54-
return
55-
56-
logger.info("Found %s groups of duplicate activities to merge", len(duplicates))
57-
env = api.Environment(cr, SUPERUSER_ID, {})
58-
59-
for code, record_ids in duplicates:
60-
if len(record_ids) < 2:
61-
continue
62-
63-
# Use the last record (highest ID) as target, which is the original user-created record
64-
# The lower IDs are typically the new data records that were loaded
65-
target_record_id = record_ids[-1]
66-
records_to_merge = record_ids[:-1]
67-
68-
logger.info(
69-
"Merging duplicate activities with code '%s': merging %s into %s",
70-
code,
71-
records_to_merge,
72-
target_record_id,
32+
# Update res_company references
33+
logger.info("Updating %s references in res_company", new_field)
34+
cr.execute(
35+
f"""
36+
UPDATE res_company
37+
SET {new_field} = (
38+
SELECT new_act.id
39+
FROM {new_table} new_act
40+
JOIN {backup_table} old_act ON new_act.code = old_act.code
41+
WHERE old_act.id = res_company.{backup_field}
7342
)
43+
WHERE {backup_field} IS NOT NULL
44+
"""
45+
)
46+
logger.info("Updated %d records in res_company", cr.rowcount)
7447

75-
try:
76-
openupgrade_merge_records.merge_records(
77-
env=env,
78-
model_name=model_name,
79-
record_ids=records_to_merge,
80-
target_record_id=target_record_id,
81-
method="sql",
82-
delete=True,
83-
model_table=model_table,
48+
# Clean up orphan references (activities that don't have a matching code in new data)
49+
logger.info("Cleaning up orphan references")
50+
for table in ["account_account", "res_company"]:
51+
cr.execute(
52+
f"""
53+
UPDATE {table}
54+
SET {new_field} = NULL
55+
WHERE {new_field} IS NOT NULL
56+
AND NOT EXISTS (
57+
SELECT 1 FROM {new_table} WHERE id = {table}.{new_field}
8458
)
59+
"""
60+
)
61+
if cr.rowcount:
8562
logger.info(
86-
"Successfully merged %s duplicate records into record %s",
87-
len(records_to_merge),
88-
target_record_id,
89-
)
90-
except Exception as e:
91-
logger.error(
92-
"Error merging duplicate activities with code '%s': %s", code, str(e)
63+
"Cleaned %d orphan references in table '%s'", cr.rowcount, table
9364
)
94-
# Continue with next group even if one fails
95-
continue
9665

97-
# Clean up any references that might have been broken after the merge
98-
_cleanup_orphan_references(cr, model_table)
66+
# Drop backup table and columns
67+
logger.info("Dropping backup table %s", backup_table)
68+
cr.execute(f"DROP TABLE IF EXISTS {backup_table}")
69+
70+
for table in ["account_account", "res_company"]:
71+
logger.info("Dropping backup column %s from %s", backup_field, table)
72+
cr.execute(f"ALTER TABLE {table} DROP COLUMN IF EXISTS {backup_field}")
73+
74+
logger.info("Post-migration completed successfully")
Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,35 @@
11
import logging
22

3-
from odoo.upgrade import util
3+
from openupgradelib import openupgrade
44

55
logger = logging.getLogger(__name__)
66

7+
# Backup de la tabla vieja antes de que se carguen los nuevos datos
8+
_backup_table = ("afip_activity", "afip_activity_bu")
9+
10+
# Columnas a copiar en las tablas que referencian la actividad
11+
_column_copy = {
12+
"account_account": [
13+
("l10n_ar_afip_activity_id", "l10n_ar_afip_activity_id_bu", None),
14+
],
15+
"res_company": [
16+
("l10n_ar_afip_activity_id", "l10n_ar_afip_activity_id_bu", None),
17+
],
18+
}
19+
720

821
def migrate(cr, version):
9-
model_renames = ("afip.activity", "l10n_ar.arca.activity")
10-
models_to_migrate = ["res.company", "account.account"]
11-
module_renames = ("l10n_ar_ux", "l10n_ar_reports_simple")
12-
old_fieldname = "l10n_ar_afip_activity_id"
13-
new_fieldname = "l10n_ar_arca_activity_id"
14-
15-
# Rename activities model from afip_activity to l10n_ar_arca_activity
16-
util.rename_model(cr, *model_renames)
17-
logger.info("Renaming model %s to %s", model_renames[0], model_renames[1])
18-
19-
# Update XML ID of the model to point to the new module
20-
old_xmlid = f"{module_renames[0]}.model_l10n_ar_arca_activity"
21-
new_xmlid = f"{module_renames[1]}.model_l10n_ar_arca_activity"
22-
util.rename_xmlid(cr, old_xmlid, new_xmlid)
23-
logger.info("Renamed XML ID from %s to %s", old_xmlid, new_xmlid)
24-
25-
for model in models_to_migrate:
26-
# Rename field l10n_ar_afip_activity_id to l10n_ar_arca_activity_id
27-
util.rename_field(cr, model, old_fieldname, new_fieldname)
28-
logger.info("Renombrando campo %s a %s en modelo %s", old_fieldname, new_fieldname, model)
29-
# Move field from l10n_ar_ux to l10n_ar_reports_simple
30-
util.move_field_to_module(cr, model, new_fieldname, *module_renames, skip_inherit=())
31-
logger.info(
32-
"Moviendo campo %s de %s a %s en modelo %s",
33-
new_fieldname,
34-
module_renames[0],
35-
module_renames[1],
36-
model,
37-
)
38-
logger.info("Migración de campos de l10n_ar_ux a l10n_ar_reports_simple finalizada.")
22+
"""Pre-migration to back up old activity data and prepare for new data load. """
23+
24+
# 1. Crear backup de la tabla vieja antes de renombrarla
25+
old_table, backup_table = _backup_table
26+
logger.info("Creating backup table %s from %s", backup_table, old_table)
27+
cr.execute(f"CREATE TABLE {backup_table} AS SELECT * FROM {old_table}")
28+
29+
# 2. Copiar columnas viejas a columnas de backup en tablas referenciadas
30+
for table, columns in _column_copy.items():
31+
for old_col, backup_col, _ in columns:
32+
logger.info("Copying column %s.%s to %s", table, old_col, backup_col)
33+
openupgrade.copy_columns(cr, table, old_col, backup_col)
34+
35+
logger.info("Pre-migration completed successfully")

0 commit comments

Comments
 (0)