Files
Odoo-Modules/fusion_plating/fusion_plating_quality/models/fp_qc_template.py
gsinghpal d9f58b9851 changes
2026-04-26 15:05:17 -04:00

172 lines
6.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
#
# Phase 1 (Sub 11) — relocated from fusion_plating_bridge_mrp.
# This model never had MRP fields; the bridge module was just its
# initial home. Now lives under fusion_plating_jobs.
"""QC Checklist Template — admin config for per-customer QC requirements.
Customers differ wildly in what they expect from quality control:
* commercial job-shop accounts often just want "did it plate?" — one
visual check
* aerospace / Nadcap customers expect visual, dimensional,
adhesion, and Fischerscope thickness readings — every part, every
lot, signed off
* internal rework jobs may have no QC requirement at all
Rather than coding that policy into the shop, each customer gets their
own checklist template. On job confirm, the active template is cloned
into a fresh `fusion.plating.quality.check` — the instance operators
actually fill in.
"""
from odoo import api, fields, models, _
class FpQcChecklistTemplate(models.Model):
_name = 'fp.qc.checklist.template'
_description = 'Fusion Plating — QC Checklist Template'
_inherit = ['mail.thread']
_order = 'partner_id, sequence, name'
name = fields.Char(
string='Template Name', required=True, tracking=True,
help='e.g. "Standard Aerospace CoC + Thickness" or '
'"Commercial — Visual Only".',
)
sequence = fields.Integer(default=10)
active = fields.Boolean(default=True)
partner_id = fields.Many2one(
'res.partner', string='Customer',
domain="[('customer_rank', '>', 0)]",
help='Leave blank for the global default template. A customer-'
'specific template wins over the default when both exist.',
tracking=True,
)
notes = fields.Html(
string='Notes',
help='Context for QC inspectors — what this customer cares '
'about, common reject reasons, spec docs to reference.',
)
line_ids = fields.One2many(
'fp.qc.checklist.template.line', 'template_id',
string='Checklist Items', copy=True,
)
require_thickness_readings = fields.Boolean(
string='Require Thickness Readings', default=False, tracking=True,
help='Job cannot be marked done unless at least one '
'fp.thickness.reading is logged against it. Use for '
'aerospace / Nadcap accounts.',
)
require_thickness_report_pdf = fields.Boolean(
string='Require Thickness Report PDF', default=False, tracking=True,
help='Job cannot be marked done unless the operator has '
'uploaded the Fischerscope / XDAL 600 PDF report to the '
'quality check.',
)
require_inspector_signoff = fields.Boolean(
string='Require Inspector Sign-off', default=True, tracking=True,
help='The quality check itself must be in the "passed" state '
'(not just draft or in-progress).',
)
check_count = fields.Integer(
string='# QC Checks Created', compute='_compute_check_count',
)
def _compute_check_count(self):
Check = self.env['fusion.plating.quality.check']
for rec in self:
rec.check_count = Check.search_count([
('template_id', '=', rec.id),
])
@api.model
def resolve_for_partner(self, partner):
"""Return the best-matching template for a customer.
Order: active customer-specific template > active default template >
None (no QC required).
"""
if partner:
specific = self.search([
('partner_id', '=', partner.id),
('active', '=', True),
], limit=1)
if specific:
return specific
return self.search([
('partner_id', '=', False),
('active', '=', True),
], limit=1)
def action_view_checks(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': _('QC Checks — %s') % self.name,
'res_model': 'fusion.plating.quality.check',
'view_mode': 'list,form',
'domain': [('template_id', '=', self.id)],
'target': 'current',
}
class FpQcChecklistTemplateLine(models.Model):
_name = 'fp.qc.checklist.template.line'
_description = 'Fusion Plating — QC Checklist Template Line'
_order = 'sequence, id'
template_id = fields.Many2one(
'fp.qc.checklist.template', string='Template',
required=True, ondelete='cascade',
)
sequence = fields.Integer(default=10)
name = fields.Char(
string='Check Item', required=True, translate=True,
help='The operator-facing question, e.g. "No visible pits or '
'blemishes on surface", "Thickness within 0.00050.0010".',
)
description = fields.Text(
string='Inspection Guidance',
help='Extra detail shown on the tablet when the operator taps '
'the item. Use for photos-to-compare-against, acceptable-'
'colour ranges, how to position the part, etc.',
)
check_type = fields.Selection(
[
('visual', 'Visual Inspection'),
('dimensional', 'Dimensional'),
('thickness', 'Thickness'),
('adhesion', 'Adhesion'),
('hardness', 'Hardness'),
('salt_spray', 'Salt Spray'),
('functional', 'Functional'),
('other', 'Other'),
],
string='Check Type', default='visual', required=True,
)
required = fields.Boolean(
string='Required', default=True,
help='If off, the inspector can skip this item without blocking '
'the QC from passing.',
)
requires_value = fields.Boolean(
string='Requires Numeric Value', default=False,
help='Inspector must enter a measurement. If min/max are set, '
'the reading must fall inside to count as pass.',
)
value_min = fields.Float(string='Min Value', digits=(12, 4))
value_max = fields.Float(string='Max Value', digits=(12, 4))
value_uom = fields.Char(
string='Unit',
help='Free text. e.g. "mils", "microns", "HV", "µm".',
)
requires_photo = fields.Boolean(
string='Requires Photo', default=False,
help='Inspector must attach a photo of the part.',
)