# -*- 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 api, fields, models def _fp_tz_get(self): """Same selection list Odoo uses on res.partner.tz.""" import pytz return [(tz, tz) for tz in pytz.all_timezones] class ResCompany(models.Model): _inherit = 'res.company' # ----- Fusion Plating default timezone -------------------------------- # Used as the fallback whenever a user's res.users.tz is empty (cron # jobs, batch emails, headless contexts). Auto-populated by the # post_init_hook in fusion_plating/__init__.py. x_fc_default_tz = fields.Selection( _fp_tz_get, string='Fusion Plating Timezone', default=lambda self: self.env.user.tz or 'America/Toronto', help='Timezone used for plating dashboards, reports, and emails when ' 'a user has no personal timezone set. Detected automatically on ' 'install; the admin can change it any time from ' 'Settings > Fusion Plating.', ) # ----- Worker auto-promotion default ----------------------------------- # Default number of successful WO completions a worker needs on a role # before it's auto-added to their Shop Roles. Each role can override # via fp.work.role.mastery_required. x_fc_default_mastery_threshold = fields.Integer( string='Default Mastery Threshold', default=3, help='How many successful WO completions an operator needs on a ' "task before it's added to their Shop Roles automatically. " 'New roles inherit this number; managers can override per ' 'role on the role form. 1 = promote on first success; 3 = ' 'solid baseline; 5+ for tasks that need real practice.', ) # ----- Facility footprint for this legal entity ---------------------- x_fc_facility_ids = fields.One2many( 'fusion.plating.facility', 'company_id', string='Plating Facilities', ) x_fc_facility_count = fields.Integer( string='# Facilities', compute='_compute_x_fc_facility_count', ) x_fc_default_facility_id = fields.Many2one( 'fusion.plating.facility', string='Default Facility', help='Facility used when the context does not specify one (single-site shops).', ) # ----- Unit-of-measure defaults -------------------------------------- # Plating shops in different jurisdictions / industries use different # measurement systems. North-American aerospace shops live in °F + mils; # ROW + most industrial shops use °C + microns. Each company picks its # defaults once here; every WO / oven / bath log / thickness reading # inherits the choice. Per-record overrides remain possible. x_fc_default_temp_uom = fields.Selection( [('F', '°F (Fahrenheit)'), ('C', '°C (Celsius)')], string='Temperature Unit', default='F', help='Used for bake temps, oven setpoints, bath temperatures.', ) x_fc_default_thickness_uom = fields.Selection( [('mils', 'mils'), ('microns', 'µm (microns)'), ('inches', 'inches'), ('mm', 'mm')], string='Thickness Unit', default='mils', help='Used for coating spec targets and Fischerscope readings.', ) x_fc_default_volume_uom = fields.Selection( [('gal', 'US Gallons'), ('L', 'Litres'), ('imp_gal', 'Imperial Gallons')], string='Volume Unit', default='gal', help='Used for bath volumes and chemical addition logs.', ) x_fc_default_mass_uom = fields.Selection( [('lb', 'Pounds (lb)'), ('kg', 'Kilograms (kg)'), ('oz', 'Ounces (oz)'), ('g', 'Grams (g)')], string='Mass Unit', default='lb', help='Used for chemical doses, parts weight, waste manifests.', ) x_fc_default_pressure_uom = fields.Selection( [('psi', 'PSI'), ('bar', 'bar'), ('kPa', 'kPa')], string='Pressure Unit', default='psi', help='Used for compressed-air pressure, agitation, etc.', ) x_fc_default_current_density_uom = fields.Selection( [('asf', 'A/ft² (ASF)'), ('asd', 'A/dm² (ASD)')], string='Current Density Unit', default='asf', help='Used for electrolytic plating bath current density.', ) x_fc_default_area_uom = fields.Selection( [('sq_in', 'sq in'), ('sq_ft', 'sq ft'), ('sq_cm', 'cm²'), ('sq_m', 'm²')], string='Area Unit', default='sq_in', help='Used for part surface area, masking area.', ) def _compute_x_fc_facility_count(self): for rec in self: rec.x_fc_facility_count = len(rec.x_fc_facility_ids) # ===================================================================== # CoC / Certificate report settings # ===================================================================== x_fc_owner_user_id = fields.Many2one( 'res.users', string='Certificate Owner (Default Signer)', help='Quality manager / owner whose signature appears on Certificates ' 'of Conformance by default. Signature is pulled from their linked ' 'HR Employee record.', ) x_fc_coc_signature_override = fields.Binary( string='Signature Override Image', help='Optional. Upload a pre-scanned signature image to use on ' 'Certificates of Conformance. Overrides the Owner user\'s ' 'employee signature when set. Useful if the owner doesn\'t have ' 'an HR record or wants a different signature for plating certs.', ) # --- Accreditation logos shown in CoC header --- x_fc_nadcap_logo = fields.Binary(string='Nadcap Logo') x_fc_nadcap_active = fields.Boolean( string='Nadcap Accredited', help='Show the Nadcap logo on certificates.', ) x_fc_as9100_logo = fields.Binary(string='AS9100 / ISO 9001 Logo') x_fc_as9100_active = fields.Boolean( string='AS9100 / ISO 9001 Certified', help='Show the AS9100 / ISO 9001 logo on certificates.', ) x_fc_cgp_logo = fields.Binary(string='Controlled Goods Program Logo') x_fc_cgp_active = fields.Boolean( string='CGP Registered', help='Show the Controlled Goods Program logo on certificates.', ) # ===================================================================== # Sub 12a — Default recipe editor # ===================================================================== x_fc_default_recipe_editor = fields.Selection( [('tree', 'Tree Editor'), ('simple', 'Simple Editor')], string='Default Recipe Editor', default='tree', help='Which editor opens when a new recipe is created OR when a ' 'recipe with preferred_editor=auto is selected. Per-recipe ' 'preferred_editor (tree/simple) overrides this.', ) # ===================================================================== # Sub 12c+ — Default Certification Statement # ===================================================================== x_fc_default_cert_statement = fields.Text( string='Default Cert Statement', help='Boilerplate text printed in the Certificate of Conformance ' '"Certification Statement" block. Per-customer override on ' 'res.partner.x_fc_cert_statement takes precedence when set. ' 'When BOTH are blank the report falls back to a hardcoded ' 'AS9100/ISO 9001 statement.', ) # ===================================================================== # Phase F — Plating Designated Officials # ===================================================================== # These are SPECIFIC NAMED PEOPLE registered with regulatory bodies. # Stored as Many2one to res.users so the link survives renames. # View-level domain restricts the picker to Owner or Quality Manager # group members (a Python-side domain would resolve groups by id at # recordset load and is fragile across DB migrations). x_fc_cgp_designated_official_id = fields.Many2one( 'res.users', string='CGP Designated Official', tracking=True, help='Specific person registered with PSPC as Designated Official ' 'under Defence Production Act §22. Must be Owner or Quality ' 'Manager.', ) x_fc_nadcap_authority_user_id = fields.Many2one( 'res.users', string='Nadcap Authority', tracking=True, help='Specific person who signs Nadcap-specific certificates and ' 'audits. Must be Owner or Quality Manager.', )