chore(plating): de-dash shipped code + intake-neutral customer emails

Replace em-dashes and en-dashes with hyphens across 789 shipped source
files (py/xml/js/scss) so the delivered module reads as human-written;
em-dashes had become a recognizable AI-generated tell. Internal .md dev
notes are excluded. The WO-sticker mojibake strippers keep their dash
search targets (now written — / –). No logic changes: comments
and display strings only; validated with py_compile + lxml parse.

Rewrite the 7 customer notification emails to be intake-neutral
(ship-in / drop-off / pickup) and repair-aware, and fix the Shipped
email documents line (packing slip vs bill of lading; certificate only
when issued). Subjects use a hyphen separator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-06-05 00:16:19 -04:00
parent c9eb61ee0c
commit 8c76a16366
789 changed files with 4692 additions and 4692 deletions

View File

@@ -4,5 +4,5 @@
#
# This package holds standalone migration / audit scripts for the native
# job model rollout. Scripts under this directory are NOT imported at
# module load time they are invoked manually from `odoo shell` by the
# module load time - they are invoked manually from `odoo shell` by the
# cutover engineer. See README.md in this directory for usage.

View File

@@ -3,7 +3,7 @@
# License OPL-1 (Odoo Proprietary License v1.0)
#
# Post-migration audit. Verifies migration counts match expectations.
# Read-only does NOT modify data. Run from `odoo shell`.
# Read-only - does NOT modify data. Run from `odoo shell`.
import logging
@@ -47,7 +47,7 @@ def run(env):
if step_migrated < wo_total:
print('WARNING: %d WOs not migrated' % (wo_total - step_migrated))
# Cross-references for each dependent model, show counts of records
# Cross-references - for each dependent model, show counts of records
# with the LEGACY production_id set vs the NEW x_fc_job_id set. After
# migration, the second column should match the first (we don't clear
# production_id during shadow period).
@@ -163,7 +163,7 @@ def run(env):
try:
run(env) # noqa: F821 `env` is provided by odoo shell
run(env) # noqa: F821 - `env` is provided by odoo shell
except NameError:
print(
'This script expects to run inside `odoo shell` where `env` is defined.'

View File

@@ -3,7 +3,7 @@
# License OPL-1 (Odoo Proprietary License v1.0)
#
# Pre-migration audit. Reports row counts and data-quality concerns
# before running migrate_to_fp_jobs.py. Read-only does NOT modify data.
# before running migrate_to_fp_jobs.py. Read-only - does NOT modify data.
#
# Run from `odoo shell` where `env` is in scope. See ./README.md.
@@ -58,7 +58,7 @@ def run(env):
no_wc = cr.fetchone()[0]
print('WOs without workcenter_id:', no_wc)
# Dependent records check by model registry (truthful even when
# Dependent records - check by model registry (truthful even when
# the schema names differ from defaults).
if 'fp.quality.hold' in env:
cr.execute(
@@ -111,6 +111,6 @@ def run(env):
# Run when the script is exec'd from odoo shell (env is in scope).
try:
run(env) # noqa: F821 `env` is provided by odoo shell
run(env) # noqa: F821 - `env` is provided by odoo shell
except NameError:
print('This script expects to run inside `odoo shell` where `env` is defined.')

View File

@@ -27,7 +27,7 @@ def run(env):
print(' Deleted %d fp.job.node.override rows' % n)
# 3. Deliveries linked to jobs OR with job_ref set OR linked to a SO that
# we will delete. Delete ALL deliveries they're test data.
# we will delete. Delete ALL deliveries - they're test data.
if 'fusion.plating.delivery' in env:
deliveries = env['fusion.plating.delivery'].sudo().search([])
n = len(deliveries)
@@ -62,7 +62,7 @@ def run(env):
portals.unlink()
print(' Deleted %d fusion.plating.portal.job rows' % n)
# 8. Racking inspections required FK to mrp.production, so delete
# 8. Racking inspections - required FK to mrp.production, so delete
# BEFORE we kill the productions.
if 'fp.racking.inspection' in env:
insps = env['fp.racking.inspection'].sudo().search([])
@@ -70,7 +70,7 @@ def run(env):
insps.unlink()
print(' Deleted %d fp.racking.inspection rows' % n)
# 9. Receiving records (required FK to sale.order delete before SOs)
# 9. Receiving records (required FK to sale.order - delete before SOs)
if 'fp.receiving' in env:
recs = env['fp.receiving'].sudo().search([])
n = len(recs)
@@ -92,7 +92,7 @@ def run(env):
env['mrp.workorder'].sudo().search([]).unlink()
print(' Deleted %d mrp.workorder rows' % n)
# 13. mrp.production (legacy) force state via SQL so unlink() bypasses
# 13. mrp.production (legacy) - force state via SQL so unlink() bypasses
# Odoo's _unlink_except_done guard (which forbids deleting done MOs)
# and the action_cancel guard (which forbids cancelling done MOs).
# Demo data only.
@@ -111,7 +111,7 @@ def run(env):
env['mrp.production'].sudo().search([]).unlink()
print(' Deleted %d mrp.production rows' % n)
# 14. Account payments (must come before invoices payment is reconciled
# 14. Account payments (must come before invoices - payment is reconciled
# against move lines)
Payment = env['account.payment'].sudo()
payments = Payment.search([])
@@ -230,7 +230,7 @@ def run(env):
)
print(' Deleted %d stock.move rows' % n)
# 17. Sale orders (cancel any non-cancel state first). Delete ALL
# 17. Sale orders (cancel any non-cancel state first). Delete ALL -
# demo data only.
sos = env['sale.order'].sudo().search([])
n = len(sos)

View File

@@ -15,15 +15,15 @@
# fp.job.step with same name, work centre (mapped via legacy
# code), sequence, durations, state.
# 4. Time logs: copy mrp.workorder.time_ids if available.
# 5. Rebind cross-references on dependent models (defensive only
# 5. Rebind cross-references on dependent models (defensive - only
# writes a value when the field exists on both sides AND the
# target field is currently empty).
# 6. Write audit log to /tmp/fp_jobs_migration.log.
#
# This is NOT an Odoo upgrade hook it is an explicit cutover step.
# This is NOT an Odoo upgrade hook - it is an explicit cutover step.
# Run from `odoo shell -d <db>` so the surrounding transaction can be
# rolled back manually if the operator spots a problem (`env.cr.rollback()`).
# At the end of run() we env.cr.commit() the operator can comment that
# At the end of run() we env.cr.commit() - the operator can comment that
# out if they want to inspect changes before persisting.
#
# See ./README.md for usage.
@@ -60,7 +60,7 @@ def map_work_centre(env, mrp_wc):
"""Find the fp.work.centre that corresponds to a mrp.workcenter.
Strategy: match by code. If no match, return False (the step will
have no work centre operator can fix manually post-cutover).
have no work centre - operator can fix manually post-cutover).
"""
if not mrp_wc:
return False
@@ -120,7 +120,7 @@ def migrate_mo(env, mo, audit):
'state': JOB_STATE_MAP.get(mo.state, 'draft'),
'legacy_mrp_production_id': mo.id,
}
# Optional fields only set when the source has them
# Optional fields - only set when the source has them
if 'x_fc_facility_id' in mo._fields and mo.x_fc_facility_id:
if 'facility_id' in Job._fields:
vals['facility_id'] = mo.x_fc_facility_id.id
@@ -140,7 +140,7 @@ def migrate_mo(env, mo, audit):
if 'coating_config_id' in Job._fields:
vals['coating_config_id'] = mo.x_fc_coating_config_id.id
# Bypass any auto-create lifecycle hooks while migrating the source
# Bypass any auto-create lifecycle hooks while migrating - the source
# MO already had its hooks run when it was originally created. We
# don't want a second portal job / racking inspection / etc.
job = Job.with_context(
@@ -196,7 +196,7 @@ def migrate_wo(env, wo, job, audit):
).create(vals)
audit['wo_migrated'] += 1
# Migrate time logs only if both sides have a time-log model
# Migrate time logs - only if both sides have a time-log model
if 'time_ids' in wo._fields and wo.time_ids \
and 'fp.job.step.timelog' in env:
TimeLog = env['fp.job.step.timelog']
@@ -382,7 +382,7 @@ def run(env):
# every run.
if 'legacy_mrp_production_id' not in env['fp.job']._fields:
msg = (
'fp.job.legacy_mrp_production_id field missing upgrade '
'fp.job.legacy_mrp_production_id field missing - upgrade '
'fusion_plating_jobs to v19.0.2.0.0+ before running this '
'script.'
)
@@ -391,7 +391,7 @@ def run(env):
return None
if 'legacy_mrp_workorder_id' not in env['fp.job.step']._fields:
msg = (
'fp.job.step.legacy_mrp_workorder_id field missing upgrade '
'fp.job.step.legacy_mrp_workorder_id field missing - upgrade '
'fusion_plating_jobs to v19.0.2.0.0+ before running this '
'script.'
)
@@ -404,7 +404,7 @@ def run(env):
# fp.job.button_mark_done to skip lifecycle side-effects (creating
# portal jobs, QC checks, racking inspections, deliveries, certs,
# notifications). The migration script rebinds existing records via
# x_fc_job_id directly so the side-effects would create duplicates.
# x_fc_job_id directly - so the side-effects would create duplicates.
env = env(context=dict(env.context, fp_jobs_migration=True))
MO = env['mrp.production']
all_mos = MO.search([])
@@ -480,7 +480,7 @@ def run(env):
# Run when exec'd from odoo shell
try:
result = run(env) # noqa: F821 `env` is provided by odoo shell
result = run(env) # noqa: F821 - `env` is provided by odoo shell
except NameError:
print(
'This script expects to run inside `odoo shell` where `env` is defined.'

View File

@@ -133,4 +133,4 @@ print('=' * 60)
print(f'PASS: every doc tied to parent {parent}')
print('=' * 60)
env.cr.rollback()
print('(rolled back DB unchanged)')
print('(rolled back - DB unchanged)')

View File

@@ -60,7 +60,7 @@ def _build_combos(env):
def _create_so(env, partner, part, coating, qty, deadline_offset_days):
"""Create + confirm a SO with one plating line. Returns (so, job)."""
# fp.part.catalog has no product_id field use a generic product
# fp.part.catalog has no product_id field - use a generic product
# for the SO line. Plating-specific fields (x_fc_part_catalog_id,
# x_fc_coating_config_id) carry the real linkage.
fallback_product = env['product.product'].search(
@@ -106,7 +106,7 @@ def _create_job_direct(env, partner, part, recipe, qty, deadline_offset_days):
}
if part:
vals['part_catalog_id'] = part.id
# fp.part.catalog has no product_id field leave fp.job.product_id
# fp.part.catalog has no product_id field - leave fp.job.product_id
# null. It's an optional field used as a "Reference Product".
return Job.create(vals)

View File

@@ -18,7 +18,7 @@ def run(env):
coatings_with_recipe = Coating.search([('recipe_id', '!=', False)])
if not coatings_with_recipe:
print(' No coatings with recipes available abort')
print(' No coatings with recipes available - abort')
return
print(f' Coatings with recipes: {len(coatings_with_recipe)}')