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:
@@ -67,6 +67,23 @@ class FpQualityPoint(models.Model):
|
||||
'fp.coating.config', 'fp_quality_point_coating_rel',
|
||||
'point_id', 'coating_id', string='Coatings',
|
||||
)
|
||||
customer_spec_ids = fields.Many2many(
|
||||
'fusion.plating.customer.spec',
|
||||
'fp_quality_point_spec_rel',
|
||||
'point_id', 'spec_id',
|
||||
string='Specifications',
|
||||
help='If set, this trigger only fires for SOs / jobs whose '
|
||||
'specification is in this list. Leave blank to ignore spec.',
|
||||
)
|
||||
recipe_ids = fields.Many2many(
|
||||
'fusion.plating.process.node',
|
||||
'fp_quality_point_recipe_rel',
|
||||
'point_id', 'recipe_id',
|
||||
domain="[('node_type', '=', 'recipe'), ('parent_id', '=', False)]",
|
||||
string='Recipes',
|
||||
help='If set, this trigger only fires for jobs running one of '
|
||||
'these recipes. Leave blank to ignore recipe.',
|
||||
)
|
||||
step_kind = fields.Selection(STEP_KINDS, string='Step Kind')
|
||||
|
||||
template_id = fields.Many2one(
|
||||
@@ -102,7 +119,8 @@ class FpQualityPoint(models.Model):
|
||||
# ------------------------------------------------------------------
|
||||
# Matching + spawning
|
||||
# ------------------------------------------------------------------
|
||||
def _matches(self, partner=None, part=None, coating=None, step=None):
|
||||
def _matches(self, partner=None, part=None, coating=None, step=None,
|
||||
customer_spec=None, recipe=None):
|
||||
"""Return True if this point's filters all pass against the supplied
|
||||
context. Empty filter == match anything.
|
||||
"""
|
||||
@@ -115,6 +133,13 @@ class FpQualityPoint(models.Model):
|
||||
if self.coating_config_ids and (
|
||||
not coating or coating not in self.coating_config_ids):
|
||||
return False
|
||||
if self.customer_spec_ids and (
|
||||
not customer_spec
|
||||
or customer_spec not in self.customer_spec_ids):
|
||||
return False
|
||||
if self.recipe_ids and (
|
||||
not recipe or recipe not in self.recipe_ids):
|
||||
return False
|
||||
if self.step_kind and step and getattr(step, 'kind', None) \
|
||||
and step.kind != self.step_kind:
|
||||
return False
|
||||
@@ -122,7 +147,7 @@ class FpQualityPoint(models.Model):
|
||||
|
||||
@api.model
|
||||
def _find_matching(self, trigger, partner=None, part=None, coating=None,
|
||||
step=None):
|
||||
step=None, customer_spec=None, recipe=None):
|
||||
"""Return active points whose trigger + filters match the context."""
|
||||
candidates = self.search([
|
||||
('active', '=', True),
|
||||
@@ -130,6 +155,7 @@ class FpQualityPoint(models.Model):
|
||||
])
|
||||
return candidates.filtered(lambda p: p._matches(
|
||||
partner=partner, part=part, coating=coating, step=step,
|
||||
customer_spec=customer_spec, recipe=recipe,
|
||||
))
|
||||
|
||||
def _spawn_check_for(self, source, partner=None, job=None, step=None):
|
||||
|
||||
Reference in New Issue
Block a user