# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) # # Phase 3 — parallel job link on fp.certificate. # Coexists with bridge_mrp's production_id link. # # v19.0.6.20.0 — surface the Fischerscope PDF on the cert form so # operators can SEE that the thickness report will be (or has been) # merged into the CoC. The merge logic itself lives in # fusion_plating_certificates/models/fp_certificate.py — this file # only adds the human-readable indicators. from odoo import api, fields, models class FpCertificate(models.Model): _inherit = 'fp.certificate' x_fc_job_id = fields.Many2one( 'fp.job', string='Work Order', index=True, help="Native fp.job link. Coexists with bridge_mrp's production_id.", ) # ---- Fischerscope thickness-PDF visibility (S19) --------------------- # These three fields are computed from the linked job's QC checks so # the cert form can show the operator BEFORE issuing whether a # Fischerscope report is on file and will be appended as page 2. x_fc_thickness_qc_id = fields.Many2one( 'fusion.plating.quality.check', string='Linked QC (Thickness)', compute='_compute_fischer_visibility', help='Quality check on the linked plating job that has a ' 'Fischerscope / XDAL 600 thickness PDF uploaded. Used to ' 'merge that PDF into the CoC on Issue.', ) x_fc_thickness_pdf_id = fields.Many2one( 'ir.attachment', string='Fischerscope PDF', compute='_compute_fischer_visibility', help='Thickness report PDF that will be appended as page 2 of ' 'the CoC when the certificate is issued.', ) x_fc_thickness_status = fields.Selection( [ ('none', 'No PDF Uploaded'), ('pending', 'Will Append on Issue'), ('merged', 'Merged into CoC'), ], string='Thickness Report', compute='_compute_fischer_visibility', help='none = QC has no Fischerscope upload · ' 'pending = will be appended when Issue is clicked · ' 'merged = already in the issued CoC PDF', ) @api.depends('x_fc_job_id', 'state', 'message_ids', 'attachment_id', 'x_fc_local_thickness_pdf') def _compute_fischer_visibility(self): QC = self.env.get('fusion.plating.quality.check') empty_qc = self.env['fusion.plating.quality.check'] if QC is not None else None empty_att = self.env['ir.attachment'] for rec in self: qc = empty_qc pdf = empty_att status = 'none' # Cert-local upload wins over QC-side PDF (matches the # merge resolution order in fp_certificate.py). if rec.x_fc_local_thickness_pdf: if rec.state == 'issued' and rec.attachment_id: status = 'merged' else: status = 'pending' elif QC is not None and rec.x_fc_job_id: # Same lookup the merge method uses — passed-first, # then any QC with a PDF. qc = QC.sudo().search([ ('job_id', '=', rec.x_fc_job_id.id), ('state', '=', 'passed'), ('thickness_report_pdf_id', '!=', False), ], order='completed_at desc', limit=1) if not qc: qc = QC.sudo().search([ ('job_id', '=', rec.x_fc_job_id.id), ('thickness_report_pdf_id', '!=', False), ], order='create_date desc', limit=1) if qc and qc.thickness_report_pdf_id: pdf = qc.thickness_report_pdf_id if rec.state == 'issued' and rec.attachment_id: status = 'merged' else: status = 'pending' rec.x_fc_thickness_qc_id = qc or empty_qc rec.x_fc_thickness_pdf_id = pdf or empty_att rec.x_fc_thickness_status = status def action_view_thickness_qc(self): """Smart-button target — open the linked QC for inspection.""" self.ensure_one() if not self.x_fc_thickness_qc_id: return False return { 'type': 'ir.actions.act_window', 'name': self.x_fc_thickness_qc_id.name, 'res_model': 'fusion.plating.quality.check', 'res_id': self.x_fc_thickness_qc_id.id, 'view_mode': 'form', 'target': 'current', } def action_open_job(self): """Smart-button target — open the linked plating job.""" self.ensure_one() if not self.x_fc_job_id: return False return { 'type': 'ir.actions.act_window', 'name': self.x_fc_job_id.name, 'res_model': 'fp.job', 'res_id': self.x_fc_job_id.id, 'view_mode': 'form', 'target': 'current', }