feat(promote-customer-spec): Phase C — pricing, quality, job, cert re-keyed

Pricing:
- Quality inherit on fp.pricing.rule adds customer_spec_id + recipe_id
- Quality inherit on fp.quote.configurator adds customer_spec_id field
  + extends _find_matching_rule with priority chain:
    spec (+8) > recipe (+6) > coating (+4) > material (+2) > cert (+1)
- View inherit surfaces both new pickers on the rule form

Quality points:
- fp.quality.point now has customer_spec_ids + recipe_ids M2M filters
- Matcher (_matches + _find_matching) accepts new args
- Hook overrides on SO confirm + job confirm/done + step finish
  pass spec/recipe context through to the matcher
- View surfaces both new M2M widgets

Job:
- jobs/sale_order.py wires x_fc_customer_spec_id from SO line to
  fp.job.customer_spec_id on action_confirm

Cert:
- Quality inherit on fp.certificate adds customer_spec_id field +
  create() override auto-fills spec_reference from spec.code+revision
  Resolution priority: explicit spec_reference > cert.customer_spec_id
  > SO line spec (with print_on_cert) > legacy coating fallback

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-15 01:23:06 -04:00
parent 7cafab1b9f
commit c637f82ae2
11 changed files with 278 additions and 6 deletions

View File

@@ -470,6 +470,11 @@ class SaleOrder(models.Model):
and first_line.x_fc_coating_config_id
or False
)
customer_spec = (
'x_fc_customer_spec_id' in first_line._fields
and first_line.x_fc_customer_spec_id
or False
)
if not part and 'x_fc_part_catalog_id' in self._fields:
part = self.x_fc_part_catalog_id or False
if not coating and 'x_fc_coating_config_id' in self._fields:
@@ -489,6 +494,8 @@ class SaleOrder(models.Model):
vals['part_catalog_id'] = part.id
if coating:
vals['coating_config_id'] = coating.id
if customer_spec:
vals['customer_spec_id'] = customer_spec.id
if recipe:
vals['recipe_id'] = recipe.id