# -*- 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, ) # Step 6: Drop legacy description column (all reads migrated to new fields). # Runs after Steps 3 duplicated data into internal_description + # customer_facing_description. Idempotent via IF EXISTS. cr.execute(""" ALTER TABLE fp_sale_description_template DROP COLUMN IF EXISTS description """) _logger.info("Sub 2: dropped legacy description column") _logger.info("Sub 2: migration complete")