changes
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
from . import fp_shopfloor_station
|
||||
from . import fp_bake_oven
|
||||
from . import fp_bake_window
|
||||
from . import fp_first_piece_gate
|
||||
from . import fp_operator_queue
|
||||
from . import fp_tank
|
||||
from . import res_users
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
# -*- 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 FpFirstPieceGate(models.Model):
|
||||
"""First-piece inspection gate per routing.
|
||||
|
||||
Aerospace, nuclear and many automotive customers require that the FIRST
|
||||
piece off a routing be inspected and dispositioned BEFORE the rest of
|
||||
the lot is allowed to run. This model captures that gate.
|
||||
"""
|
||||
_name = 'fusion.plating.first.piece.gate'
|
||||
_description = 'Fusion Plating — First-Piece Inspection Gate'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'first_piece_produced desc, id desc'
|
||||
|
||||
name = fields.Char(
|
||||
string='Reference',
|
||||
required=True,
|
||||
copy=False,
|
||||
readonly=True,
|
||||
default=lambda self: self._default_name(),
|
||||
tracking=True,
|
||||
)
|
||||
bath_id = fields.Many2one(
|
||||
'fusion.plating.bath',
|
||||
string='Bath',
|
||||
ondelete='restrict',
|
||||
tracking=True,
|
||||
)
|
||||
facility_id = fields.Many2one(
|
||||
'fusion.plating.facility',
|
||||
related='bath_id.facility_id',
|
||||
store=True,
|
||||
readonly=True,
|
||||
)
|
||||
part_ref = fields.Char(
|
||||
string='Part Reference',
|
||||
tracking=True,
|
||||
)
|
||||
customer_ref = fields.Char(
|
||||
string='Customer Reference',
|
||||
tracking=True,
|
||||
)
|
||||
routing_first_run = fields.Boolean(
|
||||
string='First Run of Routing',
|
||||
help='Tick if this is the first time this routing runs this part.',
|
||||
)
|
||||
|
||||
first_piece_produced = fields.Datetime(
|
||||
string='First Piece Produced',
|
||||
tracking=True,
|
||||
)
|
||||
first_piece_inspected = fields.Datetime(
|
||||
string='First Piece Inspected',
|
||||
tracking=True,
|
||||
)
|
||||
inspector_id = fields.Many2one(
|
||||
'res.users',
|
||||
string='Inspector',
|
||||
tracking=True,
|
||||
)
|
||||
result = fields.Selection(
|
||||
[
|
||||
('pending', 'Pending'),
|
||||
('pass', 'Pass'),
|
||||
('fail', 'Fail'),
|
||||
],
|
||||
string='Result',
|
||||
default='pending',
|
||||
required=True,
|
||||
tracking=True,
|
||||
)
|
||||
rest_of_lot_released = fields.Boolean(
|
||||
string='Rest of Lot Released',
|
||||
tracking=True,
|
||||
)
|
||||
notes = fields.Html(
|
||||
string='Notes',
|
||||
)
|
||||
status_color = fields.Integer(
|
||||
compute='_compute_status_color',
|
||||
)
|
||||
active = fields.Boolean(default=True)
|
||||
|
||||
# ==========================================================================
|
||||
@api.model
|
||||
def _default_name(self):
|
||||
seq = self.env['ir.sequence'].next_by_code('fusion.plating.first.piece.gate')
|
||||
return seq or '/'
|
||||
|
||||
@api.depends('result', 'rest_of_lot_released')
|
||||
def _compute_status_color(self):
|
||||
for rec in self:
|
||||
if rec.result == 'fail':
|
||||
rec.status_color = 1 # red
|
||||
elif rec.result == 'pass' and rec.rest_of_lot_released:
|
||||
rec.status_color = 4 # green
|
||||
elif rec.result == 'pass':
|
||||
rec.status_color = 3 # yellow — passed but not released
|
||||
else:
|
||||
rec.status_color = 5 # purple — pending
|
||||
|
||||
# ==========================================================================
|
||||
# Actions
|
||||
# ==========================================================================
|
||||
def action_mark_pass(self):
|
||||
self.write({
|
||||
'result': 'pass',
|
||||
'first_piece_inspected': fields.Datetime.now(),
|
||||
'inspector_id': self.env.user.id,
|
||||
})
|
||||
|
||||
def action_mark_fail(self):
|
||||
self.write({
|
||||
'result': 'fail',
|
||||
'first_piece_inspected': fields.Datetime.now(),
|
||||
'inspector_id': self.env.user.id,
|
||||
})
|
||||
|
||||
def action_release_lot(self):
|
||||
self.filtered(lambda r: r.result == 'pass').write({
|
||||
'rest_of_lot_released': True,
|
||||
})
|
||||
@@ -65,20 +65,7 @@ class FpOperatorQueue(models.TransientModel):
|
||||
'source_id': bw.id,
|
||||
})
|
||||
|
||||
gate_domain = [('result', '=', 'pending')]
|
||||
if facility_id:
|
||||
gate_domain.append(('facility_id', '=', facility_id))
|
||||
gates = self.env['fusion.plating.first.piece.gate'].search(gate_domain)
|
||||
for g in gates:
|
||||
rows.append({
|
||||
'operator_id': user_id,
|
||||
'facility_id': g.facility_id.id,
|
||||
'label': f"First piece: {g.name}",
|
||||
'description': f"Part {g.part_ref or '?'}",
|
||||
'priority': 80,
|
||||
'source_model': 'fusion.plating.first.piece.gate',
|
||||
'source_id': g.id,
|
||||
})
|
||||
# First-piece-gate aggregation retired (19.0.33.2.0) with the model.
|
||||
|
||||
# ----- MRP work orders (if fusion_plating_bridge_mrp installed) -----
|
||||
# Show two buckets, in this order:
|
||||
|
||||
@@ -17,27 +17,22 @@ class FpTank(models.Model):
|
||||
x_fp_shopfloor_queue_size = fields.Integer(
|
||||
string='Shopfloor Queue',
|
||||
compute='_compute_shopfloor_queue_size',
|
||||
help='Number of bake windows + first-piece gates currently waiting on '
|
||||
'this tank\'s current bath.',
|
||||
help='Number of bake windows currently waiting on this tank\'s '
|
||||
'current bath.',
|
||||
)
|
||||
|
||||
def _compute_shopfloor_queue_size(self):
|
||||
# First-piece-gate contribution dropped 19.0.33.2.0 with the model.
|
||||
BakeWindow = self.env['fusion.plating.bake.window']
|
||||
Gate = self.env['fusion.plating.first.piece.gate']
|
||||
for rec in self:
|
||||
bath_ids = rec.bath_ids.ids
|
||||
if not bath_ids:
|
||||
rec.x_fp_shopfloor_queue_size = 0
|
||||
continue
|
||||
count = BakeWindow.search_count([
|
||||
rec.x_fp_shopfloor_queue_size = BakeWindow.search_count([
|
||||
('bath_id', 'in', bath_ids),
|
||||
('state', 'in', ('awaiting_bake', 'bake_in_progress')),
|
||||
])
|
||||
count += Gate.search_count([
|
||||
('bath_id', 'in', bath_ids),
|
||||
('result', '=', 'pending'),
|
||||
])
|
||||
rec.x_fp_shopfloor_queue_size = count
|
||||
|
||||
def action_open_tablet_view(self):
|
||||
"""Open the tablet client action focused on this tank."""
|
||||
|
||||
Reference in New Issue
Block a user