diff --git a/fusion_plating/fusion_plating_configurator/migrations/19.0.9.0.0/__init__.py b/fusion_plating/fusion_plating_configurator/migrations/19.0.9.0.0/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/fusion_plating/fusion_plating_configurator/migrations/19.0.9.0.0/post-migration.py b/fusion_plating/fusion_plating_configurator/migrations/19.0.9.0.0/post-migration.py new file mode 100644 index 00000000..684e9816 --- /dev/null +++ b/fusion_plating/fusion_plating_configurator/migrations/19.0.9.0.0/post-migration.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 +# Sub 2 — Part Data Model Overhaul. Runs on upgrade from < 19.0.9.0.0. +# Idempotent (NULL / empty guards). Safe to re-run. + +import logging + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + if not version: + return # Fresh install — nothing to migrate + + _logger.info("Sub 2: starting part-data-model migration to %s", version) + + # Step 1: Backfill part_number from name where empty + cr.execute(""" + UPDATE fp_part_catalog + SET part_number = name + WHERE part_number IS NULL OR part_number = '' + """) + _logger.info("Sub 2: backfilled part_number on %d records", cr.rowcount) + + # Step 2: Backfill revision with 'A' where empty + cr.execute(""" + UPDATE fp_part_catalog + SET revision = 'A' + WHERE revision IS NULL OR revision = '' + """) + _logger.info("Sub 2: backfilled revision on %d records", cr.rowcount) + + # Step 3: Split fp_sale_description_template.description into two columns + # Copy existing description into BOTH internal_description and + # customer_facing_description. Estimators split them later. + cr.execute(""" + UPDATE fp_sale_description_template + SET internal_description = description, + customer_facing_description = description + WHERE description IS NOT NULL + AND description <> '' + AND (internal_description IS NULL OR internal_description = '') + """) + _logger.info( + "Sub 2: duplicated description into new columns on %d template rows", + cr.rowcount, + ) + + # Step 4: Backfill x_fc_internal_description on sale.order.line + # Copy the existing `name` (Odoo's line description) into internal so + # historical lines satisfy the required-field check when it flips. + cr.execute(""" + UPDATE sale_order_line + SET x_fc_internal_description = name + WHERE x_fc_internal_description IS NULL OR x_fc_internal_description = '' + """) + _logger.info( + "Sub 2: backfilled x_fc_internal_description on %d SO lines", + cr.rowcount, + ) + + # Step 5: Default certificate_requirement to 'inherit' on any rows + # where it's NULL (shouldn't happen given Odoo default=, but defensive). + cr.execute(""" + UPDATE fp_part_catalog + SET certificate_requirement = 'inherit' + WHERE certificate_requirement IS NULL + """) + _logger.info( + "Sub 2: defaulted certificate_requirement to 'inherit' on %d parts", + cr.rowcount, + ) + + _logger.info("Sub 2: migration complete") diff --git a/fusion_plating/fusion_plating_configurator/migrations/__init__.py b/fusion_plating/fusion_plating_configurator/migrations/__init__.py new file mode 100644 index 00000000..e69de29b