Files
Odoo-Modules/fusion_plating/fusion_plating_jobs/migrations/19.0.11.0.0/post-migrate.py
gsinghpal 8c76a16366 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>
2026-06-05 00:16:19 -04:00

92 lines
3.1 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
"""Backfill new awaiting_cert / awaiting_ship states for mid-flight jobs.
Spec: docs/superpowers/specs/2026-05-25-post-shop-cert-shipping-job-states-design.md
Rules:
- in_progress + all steps terminal + draft cert exists → awaiting_cert
- in_progress + all steps terminal + no cert required → awaiting_ship
- done jobs LEFT ALONE - historically completed (already shipped)
Idempotent: re-running on a fresh upgrade is a no-op because no
in_progress job will match the all-terminal predicate after the first
run. Pass 1 and Pass 2 are mutually exclusive (the cert-existence
sub-queries are inverses).
"""
import logging
from odoo import api, SUPERUSER_ID
_logger = logging.getLogger(__name__)
def migrate(cr, version):
"""Post-migrate entrypoint - called by Odoo after the module's
XML/Python loads on -u of fusion_plating_jobs."""
# ---- Pass 1: in_progress + all-terminal + draft cert → awaiting_cert
cr.execute("""
UPDATE fp_job
SET state = 'awaiting_cert'
WHERE id IN (
SELECT j.id
FROM fp_job j
JOIN fp_job_step s ON s.job_id = j.id
WHERE j.state = 'in_progress'
GROUP BY j.id
HAVING count(*) FILTER (
WHERE s.state NOT IN ('done','skipped','cancelled')
) = 0
)
AND EXISTS (
SELECT 1 FROM fp_certificate c
WHERE c.x_fc_job_id = fp_job.id AND c.state = 'draft'
);
""")
n_cert = cr.rowcount
_logger.info(
"post-migrate 19.0.11.0.0: %d jobs migrated to awaiting_cert", n_cert,
)
# ---- Pass 2: in_progress + all-terminal + no cert → awaiting_ship
cr.execute("""
UPDATE fp_job
SET state = 'awaiting_ship'
WHERE id IN (
SELECT j.id
FROM fp_job j
JOIN fp_job_step s ON s.job_id = j.id
WHERE j.state = 'in_progress'
GROUP BY j.id
HAVING count(*) FILTER (
WHERE s.state NOT IN ('done','skipped','cancelled')
) = 0
)
AND NOT EXISTS (
SELECT 1 FROM fp_certificate c
WHERE c.x_fc_job_id = fp_job.id
AND c.state IN ('draft', 'issued')
);
""")
n_ship = cr.rowcount
_logger.info(
"post-migrate 19.0.11.0.0: %d jobs migrated to awaiting_ship", n_ship,
)
# ---- Card_state recompute for affected rows (stored compute) ----
if n_cert or n_ship:
env = api.Environment(cr, SUPERUSER_ID, {})
affected = env['fp.job'].search([
('state', 'in', ('awaiting_cert', 'awaiting_ship')),
])
# Bust cache then read-to-recompute via @api.depends.
affected.invalidate_recordset(['card_state', 'mini_timeline_json'])
affected.mapped('card_state')
affected.mapped('mini_timeline_json')
_logger.info(
"post-migrate 19.0.11.0.0: card_state recomputed on %d jobs",
len(affected),
)