# -*- 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 class FpTank(models.Model): """A physical vessel that holds a bath. Tanks are long-lived assets. Baths come and go inside a tank. The separation lets a shop dump an exhausted bath without losing the tank's history, QR code, or equipment records. Each tank carries a unique QR code for operator scanning at the shop-floor station. """ _name = 'fusion.plating.tank' _description = 'Fusion Plating — Tank' _inherit = ['mail.thread', 'mail.activity.mixin'] _order = 'facility_id, work_center_id, sequence, code' name = fields.Char( string='Tank', required=True, tracking=True, ) code = fields.Char( string='Code', required=True, tracking=True, help='Short unique tank identifier (e.g. "T-01", "EN-A1").', ) qr_code = fields.Char( string='QR Code', help='Scannable identifier. Defaults to code, can be set to a longer URI.', ) sequence = fields.Integer( string='Sequence', default=10, ) active = fields.Boolean( string='Active', default=True, ) facility_id = fields.Many2one( 'fusion.plating.facility', string='Facility', required=True, ondelete='restrict', tracking=True, ) work_center_id = fields.Many2one( 'fusion.plating.work.center', string='Work Center', domain="[('facility_id','=',facility_id)]", ondelete='restrict', tracking=True, ) # ----- Physical properties -------------------------------------------- volume = fields.Float( string='Volume', help='Working volume.', ) volume_uom = fields.Selection( [ ('l', 'Litres'), ('gal_us', 'US gallons'), ('gal_imp', 'Imperial gallons'), ('m3', 'Cubic metres'), ], string='Volume Unit', default='l', ) material = fields.Selection( [ ('polypro', 'Polypropylene'), ('pvc', 'PVC'), ('pvdf', 'PVDF'), ('ss', 'Stainless Steel'), ('lined_steel', 'Lined Steel'), ('glass', 'Glass'), ('other', 'Other'), ], string='Construction', ) heating_type = fields.Selection( [ ('none', 'None'), ('immersion', 'Immersion Heater'), ('steam_coil', 'Steam Coil'), ('jacket', 'Jacketed'), ('external', 'External Heat Exchanger'), ], string='Heating', default='none', ) has_filtration = fields.Boolean( string='Has Filtration', ) has_rectifier = fields.Boolean( string='Has Rectifier', help='Required for electrolytic processes (chrome, anodize, strike).', ) # ----- State ---------------------------------------------------------- state = fields.Selection( [ ('empty', 'Empty'), ('filled', 'Filled'), ('in_use', 'In Use'), ('draining', 'Draining'), ('maintenance', 'Maintenance'), ('out_of_service', 'Out of Service'), ], string='Status', default='empty', tracking=True, ) # ----- Relations ------------------------------------------------------ bath_ids = fields.One2many( 'fusion.plating.bath', 'tank_id', string='Bath History', ) current_bath_id = fields.Many2one( 'fusion.plating.bath', string='Current Bath', compute='_compute_current_bath', store=True, ) current_process_id = fields.Many2one( 'fusion.plating.process.type', string='Current Process', related='current_bath_id.process_type_id', store=True, ) bath_count = fields.Integer( compute='_compute_bath_count', ) _sql_constraints = [ ( 'fp_tank_code_facility_uniq', 'unique(code, facility_id)', 'Tank code must be unique within a facility.', ), ] @api.depends('bath_ids', 'bath_ids.state') def _compute_current_bath(self): for rec in self: active = rec.bath_ids.filtered( lambda b: b.state in ('operational', 'under_review') ) rec.current_bath_id = active[:1].id if active else False def _compute_bath_count(self): for rec in self: rec.bath_count = len(rec.bath_ids) @api.model_create_multi def create(self, vals_list): for vals in vals_list: if not vals.get('qr_code') and vals.get('code'): vals['qr_code'] = f"FP-TANK:{vals['code']}" return super().create(vals_list)