feat(numbering): add parent_number + counters to sale.order
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
{
|
||||
'name': 'Fusion Plating — Native Jobs',
|
||||
'version': '19.0.8.21.5',
|
||||
'version': '19.0.8.22.0',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
||||
'author': 'Nexa Systems Inc.',
|
||||
|
||||
@@ -32,6 +32,40 @@ class SaleOrder(models.Model):
|
||||
'to drill through the linked Plating Job first.',
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Parent-number hierarchy (2026-05-12 design)
|
||||
# See docs/superpowers/specs/2026-05-12-parent-number-hierarchy-design.md
|
||||
# ------------------------------------------------------------------
|
||||
x_fc_parent_number = fields.Integer(
|
||||
string='Parent Number',
|
||||
readonly=True,
|
||||
copy=False,
|
||||
index=True,
|
||||
help='Set on confirm. Drives every linked document\'s name '
|
||||
'(WO-NNN, IN-NNN, CoC-NNN, ...). Immutable post-assignment.',
|
||||
)
|
||||
x_fc_quote_ref = fields.Char(
|
||||
string='Originally Quoted As',
|
||||
readonly=True,
|
||||
copy=False,
|
||||
help='The quote-stage name (e.g. Q202605-200). Preserved when '
|
||||
'the SO is renamed on confirm.',
|
||||
)
|
||||
# Per-model counters — monotonic, never decrement. Source of truth
|
||||
# for the next sibling's x_fc_doc_index. Updated via row-locked SQL
|
||||
# in fp.parent.numbered.mixin so concurrent creates can't drift.
|
||||
x_fc_wo_count = fields.Integer(string='WO Count', readonly=True, copy=False, default=0)
|
||||
x_fc_invoice_count = fields.Integer(string='Invoice Count', readonly=True, copy=False, default=0)
|
||||
x_fc_cn_count = fields.Integer(string='Credit Note Count', readonly=True, copy=False, default=0)
|
||||
x_fc_cert_count = fields.Integer(string='Certificate Count', readonly=True, copy=False, default=0)
|
||||
x_fc_delivery_count = fields.Integer(string='Delivery Count', readonly=True, copy=False, default=0)
|
||||
x_fc_receiving_count = fields.Integer(string='Receiving Count', readonly=True, copy=False, default=0)
|
||||
x_fc_pickup_count = fields.Integer(string='Pickup Count', readonly=True, copy=False, default=0)
|
||||
x_fc_ncr_count = fields.Integer(string='NCR Count', readonly=True, copy=False, default=0)
|
||||
x_fc_capa_count = fields.Integer(string='CAPA Count', readonly=True, copy=False, default=0)
|
||||
x_fc_hold_count = fields.Integer(string='Hold Count', readonly=True, copy=False, default=0)
|
||||
x_fc_rma_count = fields.Integer(string='RMA Count', readonly=True, copy=False, default=0)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Phase 4 (Sub 11) — workflow-stage field + assigned-manager field
|
||||
# relocated from fusion_plating_bridge_mrp. Field re-declared with
|
||||
@@ -278,13 +312,23 @@ class SaleOrder(models.Model):
|
||||
part = self.x_fc_part_catalog_id or False
|
||||
if not coating and 'x_fc_coating_config_id' in self._fields:
|
||||
coating = self.x_fc_coating_config_id or False
|
||||
# Recipe lookup priority:
|
||||
# Recipe lookup priority (specific → generic):
|
||||
# 1. line.x_fc_process_variant_id — Sarah explicitly picked
|
||||
# a part-scoped variant on this order line. Always wins.
|
||||
# 2. coating.recipe_id — coating-config recipe.
|
||||
# 3. part.default_process_id — part's flagged default.
|
||||
# 2. part.default_process_id — part's flagged default
|
||||
# variant. This is the customer-and-part-tuned recipe
|
||||
# (months of process refinement) and must beat any
|
||||
# generic template attached to the coating config.
|
||||
# 3. coating.recipe_id — coating-config recipe
|
||||
# (generic template fallback when no part variant exists).
|
||||
# 4. part.recipe_id — legacy fallback.
|
||||
#
|
||||
# Order swap 2026-05-12: before this, step (3) ran before (2),
|
||||
# so jobs with both a part variant AND a coating-attached
|
||||
# template silently picked the template. WO #01373 (S00063)
|
||||
# is the documented case — part 9876699373 Rev A had its own
|
||||
# variant but the job linked to ENP-ALUM-BASIC instead.
|
||||
#
|
||||
# If multiple lines in the same WO group have different
|
||||
# variants we use the FIRST line's variant (consistent with
|
||||
# everything else in this loop using `first_line`).
|
||||
@@ -296,12 +340,12 @@ class SaleOrder(models.Model):
|
||||
)
|
||||
if picked_variant:
|
||||
recipe = picked_variant
|
||||
if not recipe and coating and 'recipe_id' in coating._fields \
|
||||
and coating.recipe_id:
|
||||
recipe = coating.recipe_id
|
||||
if not recipe and part and 'default_process_id' in part._fields \
|
||||
and part.default_process_id:
|
||||
recipe = part.default_process_id
|
||||
if not recipe and coating and 'recipe_id' in coating._fields \
|
||||
and coating.recipe_id:
|
||||
recipe = coating.recipe_id
|
||||
if not recipe and part and 'recipe_id' in part._fields \
|
||||
and part.recipe_id:
|
||||
recipe = part.recipe_id
|
||||
|
||||
Reference in New Issue
Block a user