folder rename

This commit is contained in:
gsinghpal
2026-04-16 20:53:53 -04:00
parent 3f3ddcbab4
commit 7c7ef06057
634 changed files with 0 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
from . import models

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
{
'name': 'Fusion Plating — Batch Processing',
'version': '19.0.1.0.0',
'category': 'Manufacturing/Plating',
'summary': 'Group parts into rack or barrel loads for tank processing.',
'author': 'Nexa Systems Inc.',
'website': 'https://www.nexasystems.ca',
'maintainer': 'Nexa Systems Inc.',
'support': 'support@nexasystems.ca',
'license': 'OPL-1',
'depends': [
'fusion_plating',
],
'data': [
'security/fp_batch_security.xml',
'security/ir.model.access.csv',
'data/fp_sequence_data.xml',
'views/fp_batch_chemistry_views.xml',
'views/fp_batch_views.xml',
'views/fp_menu.xml',
],
'installable': True,
'auto_install': False,
'application': False,
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Part of the Fusion Plating product family.
-->
<odoo noupdate="1">
<record id="seq_fp_batch" model="ir.sequence">
<field name="name">Fusion Plating: Batch</field>
<field name="code">fusion.plating.batch</field>
<field name="prefix">BATCH-</field>
<field name="padding">4</field>
<field name="company_id" eval="False"/>
</record>
</odoo>

View File

@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
# Part of the Fusion Plating product family.
from . import fp_batch
from . import fp_batch_chemistry

View File

@@ -0,0 +1,141 @@
# -*- 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 FpBatch(models.Model):
"""A rack or barrel load of parts being processed through a tank.
Lifecycle:
draft → loading → in_process → unloading → complete
(any non-complete state) → cancelled
"""
_name = 'fusion.plating.batch'
_description = 'Plating Batch (Rack/Barrel Load)'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'create_date desc'
name = fields.Char(
string='Batch Reference',
required=True,
copy=False,
readonly=True,
default=lambda self: self.env['ir.sequence'].next_by_code(
'fusion.plating.batch') or '/',
tracking=True,
)
facility_id = fields.Many2one(
'fusion.plating.facility',
string='Facility',
required=True,
tracking=True,
)
bath_id = fields.Many2one(
'fusion.plating.bath',
string='Bath',
required=True,
tracking=True,
)
tank_id = fields.Many2one(
'fusion.plating.tank',
string='Tank',
related='bath_id.tank_id',
store=True,
readonly=True,
)
process_type_id = fields.Many2one(
related='bath_id.process_type_id',
store=True,
readonly=True,
)
state = fields.Selection(
selection=[
('draft', 'Draft'),
('loading', 'Loading'),
('in_process', 'In Process'),
('unloading', 'Unloading'),
('complete', 'Complete'),
('cancelled', 'Cancelled'),
],
string='Status',
default='draft',
required=True,
tracking=True,
)
rack_ref = fields.Char(string='Rack / Barrel Ref')
part_count = fields.Integer(string='Part Count')
start_time = fields.Datetime(string='Process Start', tracking=True)
end_time = fields.Datetime(string='Process End', tracking=True)
duration_minutes = fields.Float(
string='Duration (min)',
compute='_compute_duration',
store=True,
)
chemistry_ids = fields.One2many(
'fusion.plating.batch.chemistry',
'batch_id',
string='Chemistry Readings',
)
chemistry_count = fields.Integer(
string='Readings',
compute='_compute_chemistry_count',
)
operator_id = fields.Many2one(
'res.users',
string='Operator',
default=lambda self: self.env.user,
tracking=True,
)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company,
)
notes = fields.Html(string='Notes')
active = fields.Boolean(default=True)
# -------------------------------------------------------------------------
# Compute
# -------------------------------------------------------------------------
@api.depends('start_time', 'end_time')
def _compute_duration(self):
for rec in self:
if rec.start_time and rec.end_time:
delta = rec.end_time - rec.start_time
rec.duration_minutes = delta.total_seconds() / 60.0
else:
rec.duration_minutes = 0.0
@api.depends('chemistry_ids')
def _compute_chemistry_count(self):
for rec in self:
rec.chemistry_count = len(rec.chemistry_ids)
# -------------------------------------------------------------------------
# Actions
# -------------------------------------------------------------------------
def action_start_loading(self):
self.write({'state': 'loading'})
def action_start_process(self):
self.write({
'state': 'in_process',
'start_time': fields.Datetime.now(),
})
def action_start_unloading(self):
self.write({
'state': 'unloading',
'end_time': fields.Datetime.now(),
})
def action_complete(self):
self.write({'state': 'complete'})
def action_cancel(self):
self.write({'state': 'cancelled'})

View File

@@ -0,0 +1,75 @@
# -*- 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 FpBatchChemistry(models.Model):
"""A single chemistry reading taken during batch processing."""
_name = 'fusion.plating.batch.chemistry'
_description = 'Batch Chemistry Reading'
_order = 'reading_time desc, id desc'
batch_id = fields.Many2one(
'fusion.plating.batch',
string='Batch',
required=True,
ondelete='cascade',
)
parameter_id = fields.Many2one(
'fusion.plating.bath.parameter',
string='Parameter',
required=True,
)
value = fields.Float(string='Value', required=True)
reading_time = fields.Datetime(
string='Reading Time',
default=fields.Datetime.now,
)
status = fields.Selection(
selection=[
('pass', 'Pass'),
('warning', 'Warning'),
('fail', 'Fail'),
],
string='Status',
compute='_compute_status',
store=True,
)
notes = fields.Char(string='Notes')
@api.depends('parameter_id', 'value')
def _compute_status(self):
"""Compare value against parameter target range.
Uses the parameter's default target range and warning tolerance.
A reading within [target_min, target_max] is a pass. If it falls
within the warning tolerance band outside that range, it is a
warning. Otherwise it is a fail.
"""
for rec in self:
if not rec.parameter_id:
rec.status = 'pass'
continue
param = rec.parameter_id
target_min = param.target_min
target_max = param.target_max
if not target_min and not target_max:
rec.status = 'pass'
continue
# Value within target range = pass
if target_min <= rec.value <= target_max:
rec.status = 'pass'
continue
# Calculate warning band from tolerance %
tolerance = (param.warning_tolerance or 0.0) / 100.0
span = target_max - target_min if target_max != target_min else abs(target_max) or 1.0
margin = span * tolerance
warning_min = target_min - margin
warning_max = target_max + margin
if warning_min <= rec.value <= warning_max:
rec.status = 'warning'
else:
rec.status = 'fail'

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Part of the Fusion Plating product family.
-->
<odoo>
<!-- ================================================================== -->
<!-- RECORD RULE — Multi-company isolation on batches -->
<!-- ================================================================== -->
<record id="fp_batch_company_rule" model="ir.rule">
<field name="name">Fusion Plating: Batch — multi-company</field>
<field name="model_id" ref="model_fusion_plating_batch"/>
<field name="global" eval="True"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
</record>
</odoo>

View File

@@ -0,0 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_fp_batch_operator,fp.batch.operator,model_fusion_plating_batch,fusion_plating.group_fusion_plating_operator,1,1,1,0
access_fp_batch_supervisor,fp.batch.supervisor,model_fusion_plating_batch,fusion_plating.group_fusion_plating_supervisor,1,1,1,0
access_fp_batch_manager,fp.batch.manager,model_fusion_plating_batch,fusion_plating.group_fusion_plating_manager,1,1,1,1
access_fp_batch_chemistry_operator,fp.batch.chemistry.operator,model_fusion_plating_batch_chemistry,fusion_plating.group_fusion_plating_operator,1,1,1,0
access_fp_batch_chemistry_supervisor,fp.batch.chemistry.supervisor,model_fusion_plating_batch_chemistry,fusion_plating.group_fusion_plating_supervisor,1,1,1,0
access_fp_batch_chemistry_manager,fp.batch.chemistry.manager,model_fusion_plating_batch_chemistry,fusion_plating.group_fusion_plating_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_fp_batch_operator fp.batch.operator model_fusion_plating_batch fusion_plating.group_fusion_plating_operator 1 1 1 0
3 access_fp_batch_supervisor fp.batch.supervisor model_fusion_plating_batch fusion_plating.group_fusion_plating_supervisor 1 1 1 0
4 access_fp_batch_manager fp.batch.manager model_fusion_plating_batch fusion_plating.group_fusion_plating_manager 1 1 1 1
5 access_fp_batch_chemistry_operator fp.batch.chemistry.operator model_fusion_plating_batch_chemistry fusion_plating.group_fusion_plating_operator 1 1 1 0
6 access_fp_batch_chemistry_supervisor fp.batch.chemistry.supervisor model_fusion_plating_batch_chemistry fusion_plating.group_fusion_plating_supervisor 1 1 1 0
7 access_fp_batch_chemistry_manager fp.batch.chemistry.manager model_fusion_plating_batch_chemistry fusion_plating.group_fusion_plating_manager 1 1 1 1

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Part of the Fusion Plating product family.
-->
<odoo>
<!-- ===== LIST ===== -->
<record id="view_fp_batch_chemistry_list" model="ir.ui.view">
<field name="name">fp.batch.chemistry.list</field>
<field name="model">fusion.plating.batch.chemistry</field>
<field name="arch" type="xml">
<list string="Chemistry Readings"
decoration-success="status == 'pass'"
decoration-warning="status == 'warning'"
decoration-danger="status == 'fail'">
<field name="batch_id"/>
<field name="parameter_id"/>
<field name="value"/>
<field name="reading_time"/>
<field name="status" widget="badge"
decoration-success="status == 'pass'"
decoration-warning="status == 'warning'"
decoration-danger="status == 'fail'"/>
<field name="notes"/>
</list>
</field>
</record>
<!-- ===== FORM ===== -->
<record id="view_fp_batch_chemistry_form" model="ir.ui.view">
<field name="name">fp.batch.chemistry.form</field>
<field name="model">fusion.plating.batch.chemistry</field>
<field name="arch" type="xml">
<form string="Chemistry Reading">
<sheet>
<group>
<group>
<field name="batch_id"/>
<field name="parameter_id"/>
<field name="value"/>
</group>
<group>
<field name="reading_time"/>
<field name="status" widget="badge"
decoration-success="status == 'pass'"
decoration-warning="status == 'warning'"
decoration-danger="status == 'fail'"/>
<field name="notes"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!-- ===== SEARCH ===== -->
<record id="view_fp_batch_chemistry_search" model="ir.ui.view">
<field name="name">fp.batch.chemistry.search</field>
<field name="model">fusion.plating.batch.chemistry</field>
<field name="arch" type="xml">
<search string="Chemistry Readings">
<field name="batch_id"/>
<field name="parameter_id"/>
<separator/>
<filter string="Pass" name="pass" domain="[('status','=','pass')]"/>
<filter string="Warning" name="warning" domain="[('status','=','warning')]"/>
<filter string="Fail" name="fail" domain="[('status','=','fail')]"/>
<group>
<filter string="Batch" name="group_batch" context="{'group_by':'batch_id'}"/>
<filter string="Parameter" name="group_parameter" context="{'group_by':'parameter_id'}"/>
<filter string="Status" name="group_status" context="{'group_by':'status'}"/>
</group>
</search>
</field>
</record>
<!-- ===== ACTION ===== -->
<record id="action_fp_batch_chemistry" model="ir.actions.act_window">
<field name="name">Chemistry Readings</field>
<field name="res_model">fusion.plating.batch.chemistry</field>
<field name="view_mode">list,form</field>
<field name="search_view_id" ref="view_fp_batch_chemistry_search"/>
</record>
</odoo>

View File

@@ -0,0 +1,202 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Part of the Fusion Plating product family.
-->
<odoo>
<!-- ===== LIST ===== -->
<record id="view_fp_batch_list" model="ir.ui.view">
<field name="name">fp.batch.list</field>
<field name="model">fusion.plating.batch</field>
<field name="arch" type="xml">
<list string="Batches"
decoration-muted="state == 'cancelled'"
decoration-success="state == 'complete'">
<field name="name"/>
<field name="facility_id"/>
<field name="bath_id"/>
<field name="tank_id" optional="show"/>
<field name="rack_ref" optional="show"/>
<field name="part_count"/>
<field name="operator_id" widget="many2one_avatar_user"/>
<field name="state" widget="badge"
decoration-info="state == 'draft'"
decoration-warning="state == 'loading'"
decoration-primary="state == 'in_process'"
decoration-success="state in ('unloading','complete')"
decoration-danger="state == 'cancelled'"/>
<field name="duration_minutes" optional="show" widget="float_time"/>
<field name="start_time" optional="hide"/>
<field name="end_time" optional="hide"/>
</list>
</field>
</record>
<!-- ===== FORM ===== -->
<record id="view_fp_batch_form" model="ir.ui.view">
<field name="name">fp.batch.form</field>
<field name="model">fusion.plating.batch</field>
<field name="arch" type="xml">
<form string="Batch">
<header>
<button name="action_start_loading" string="Start Loading"
type="object" class="oe_highlight"
invisible="state != 'draft'"/>
<button name="action_start_process" string="Start Process"
type="object" class="oe_highlight"
invisible="state != 'loading'"/>
<button name="action_start_unloading" string="Unload"
type="object" class="oe_highlight"
invisible="state != 'in_process'"/>
<button name="action_complete" string="Complete"
type="object" class="oe_highlight"
invisible="state != 'unloading'"/>
<button name="action_cancel" string="Cancel"
type="object"
invisible="state in ('complete','cancelled')"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,loading,in_process,unloading,complete"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button name="%(fusion_plating_batch.action_fp_batch_chemistry)d"
type="action" class="oe_stat_button" icon="fa-flask"
context="{'search_default_batch_id': id}">
<field name="chemistry_count" widget="statinfo" string="Readings"/>
</button>
</div>
<div class="oe_title">
<label for="name"/>
<h1><field name="name" readonly="1"/></h1>
</div>
<group>
<group>
<field name="facility_id"/>
<field name="bath_id" domain="[('facility_id','=',facility_id)]"/>
<field name="tank_id"/>
<field name="process_type_id"/>
</group>
<group>
<field name="rack_ref"/>
<field name="part_count"/>
<field name="operator_id"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
</group>
<group>
<group>
<field name="start_time"/>
<field name="end_time"/>
<field name="duration_minutes" widget="float_time"/>
</group>
</group>
<notebook>
<page string="Chemistry Readings">
<field name="chemistry_ids">
<list editable="bottom">
<field name="parameter_id"/>
<field name="value"/>
<field name="reading_time"/>
<field name="status" widget="badge"
decoration-success="status == 'pass'"
decoration-warning="status == 'warning'"
decoration-danger="status == 'fail'"/>
<field name="notes"/>
</list>
</field>
</page>
<page string="Notes">
<field name="notes"/>
</page>
</notebook>
</sheet>
<chatter/>
</form>
</field>
</record>
<!-- ===== KANBAN ===== -->
<record id="view_fp_batch_kanban" model="ir.ui.view">
<field name="name">fp.batch.kanban</field>
<field name="model">fusion.plating.batch</field>
<field name="arch" type="xml">
<kanban default_group_by="state" class="o_fp_batch_kanban">
<field name="id"/>
<field name="name"/>
<field name="facility_id"/>
<field name="bath_id"/>
<field name="rack_ref"/>
<field name="part_count"/>
<field name="state"/>
<field name="operator_id"/>
<field name="duration_minutes"/>
<templates>
<t t-name="card">
<div class="o_fp_card o_fp_batch_card">
<div class="d-flex justify-content-between align-items-start">
<strong class="o_fp_card_title"><field name="name"/></strong>
</div>
<div class="small text-muted">
<field name="bath_id"/>
</div>
<div class="small">
<i class="fa fa-cubes me-1 text-muted"/>
<field name="rack_ref"/>
</div>
<div class="d-flex justify-content-between mt-2 small">
<span class="text-muted">Parts</span>
<span class="fw-bold"><field name="part_count"/></span>
</div>
<div class="d-flex justify-content-between small">
<span class="text-muted">Operator</span>
<field name="operator_id" widget="many2one_avatar_user"/>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<!-- ===== SEARCH ===== -->
<record id="view_fp_batch_search" model="ir.ui.view">
<field name="name">fp.batch.search</field>
<field name="model">fusion.plating.batch</field>
<field name="arch" type="xml">
<search string="Batches">
<field name="name"/>
<field name="bath_id"/>
<field name="facility_id"/>
<field name="rack_ref"/>
<field name="operator_id"/>
<separator/>
<filter string="Draft" name="draft" domain="[('state','=','draft')]"/>
<filter string="Loading" name="loading" domain="[('state','=','loading')]"/>
<filter string="In Process" name="in_process" domain="[('state','=','in_process')]"/>
<filter string="Unloading" name="unloading" domain="[('state','=','unloading')]"/>
<filter string="Complete" name="complete" domain="[('state','=','complete')]"/>
<filter string="Cancelled" name="cancelled" domain="[('state','=','cancelled')]"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
<group>
<filter string="Facility" name="group_facility" context="{'group_by':'facility_id'}"/>
<filter string="Bath" name="group_bath" context="{'group_by':'bath_id'}"/>
<filter string="Status" name="group_state" context="{'group_by':'state'}"/>
<filter string="Operator" name="group_operator" context="{'group_by':'operator_id'}"/>
</group>
</search>
</field>
</record>
<!-- ===== ACTION ===== -->
<record id="action_fp_batch" model="ir.actions.act_window">
<field name="name">Batches</field>
<field name="res_model">fusion.plating.batch</field>
<field name="view_mode">kanban,list,form</field>
<field name="search_view_id" ref="view_fp_batch_search"/>
<field name="context">{'search_default_draft': 1, 'search_default_loading': 1, 'search_default_in_process': 1, 'search_default_unloading': 1}</field>
</record>
</odoo>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2026 Nexa Systems Inc.
License OPL-1 (Odoo Proprietary License v1.0)
Part of the Fusion Plating product family.
-->
<odoo>
<!-- Batches menu item under Plating > Operations -->
<menuitem id="menu_fp_batches"
name="Batches"
parent="fusion_plating.menu_fp_operations"
action="action_fp_batch"
sequence="15"/>
</odoo>