Files
Odoo-Modules/fusion_plating/fusion_plating_quality/models/fp_customer_spec.py
gsinghpal 406cac1362 feat(promote-customer-spec): Phase A — recipe + spec foundation
- Add fp.recipe.thickness model (replaces fp.coating.thickness, scoped to recipe root)
- Add spec metadata + bake-relief fields to fusion.plating.process.node (recipe root):
  phosphorus_level, thickness_min/max/uom, thickness_option_ids,
  requires_bake_relief + bake_window_hours/temperature/duration
- Add recipe_ids M2M + print_on_cert to fusion.plating.customer.spec
- Add applicable_spec_ids reverse M2M as inherit in fusion_plating_quality
  (avoids circular dep — core can't reference customer.spec which lives in quality)
- Surface new fields on recipe form ("Specification & Bake" notebook page)
- Surface recipe linkage on customer spec form

Pure additive. Foundation for Phases B-E.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 00:50:17 -04:00

116 lines
3.5 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
from odoo import fields, models
class FpCustomerSpec(models.Model):
"""Customer specification library entry.
Holds the metadata about a specification (industry, customer, or
internal) so jobs and process types can reference it. The actual
document lives at document_url — could be a SharePoint link, a
Google Drive URL, or any other location the shop already uses.
"""
_name = 'fusion.plating.customer.spec'
_description = 'Fusion Plating — Customer Specification'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'spec_type, code, revision desc'
_rec_name = 'display_name'
name = fields.Char(
string='Title',
required=True,
tracking=True,
)
display_name = fields.Char(
compute='_compute_display_name',
store=True,
)
code = fields.Char(
string='Spec Code',
required=True,
tracking=True,
help='e.g. AMS 2404, ASTM B733, MIL-C-26074',
)
revision = fields.Char(
string='Revision',
tracking=True,
)
effective_date = fields.Date(
string='Effective Date',
tracking=True,
)
partner_id = fields.Many2one(
'res.partner',
string='Customer',
help='Leave blank for industry / internal specs.',
)
process_type_ids = fields.Many2many(
'fusion.plating.process.type',
'fp_customer_spec_process_rel',
'spec_id',
'process_type_id',
string='Applicable Processes',
)
spec_type = fields.Selection(
[
('industry', 'Industry / Standard'),
('customer', 'Customer'),
('internal', 'Internal'),
],
string='Type',
default='industry',
required=True,
tracking=True,
)
document_url = fields.Char(
string='Document URL',
help='Link to the controlled copy of the specification (SharePoint, '
'Google Drive, etc.).',
)
notes = fields.Html(
string='Notes',
)
recipe_ids = fields.Many2many(
'fusion.plating.process.node',
'fp_customer_spec_recipe_rel',
'spec_id', 'recipe_id',
domain="[('node_type', '=', 'recipe'), ('parent_id', '=', False)]",
string='Applicable Recipes',
help='Recipes that can produce work to this specification. '
'Many-to-many — one spec can cover multiple processes; '
'one recipe can satisfy multiple specs.',
)
print_on_cert = fields.Boolean(
string='Print on Certificate',
default=True,
help="When enabled, this spec's code+revision appear on the CoC "
'when the spec is selected on the SO line.',
)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company,
)
active = fields.Boolean(default=True)
_sql_constraints = [
(
'fp_customer_spec_code_rev_uniq',
'unique(code, revision, company_id)',
'A specification at the same revision must be unique per company.',
),
]
def _compute_display_name(self):
for rec in self:
parts = [rec.code or '']
if rec.revision:
parts.append(f'Rev {rec.revision}')
if rec.name:
parts.append(f'{rec.name}')
rec.display_name = ' '.join(p for p in parts if p)