171 lines
4.9 KiB
Python
171 lines
4.9 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 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)
|