From 80887d60989d3bfb6de7c324dcbfcbe47ae0225e Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Mon, 25 May 2026 08:17:29 -0400 Subject: [PATCH] changes --- .../fusion_plating_jobs/__manifest__.py | 2 +- .../views/jobs_in_shopfloor_menu.xml | 9 +- .../fusion_plating_shopfloor/__manifest__.py | 6 +- .../controllers/shopfloor_controller.py | 46 +---- .../data/fp_demo_shopfloor_data.xml | 37 +--- .../data/fp_sequence_data.xml | 9 - .../migrations/19.0.33.2.0/pre-migrate.py | 89 +++++++++ .../models/__init__.py | 1 - .../models/fp_first_piece_gate.py | 128 ------------ .../models/fp_operator_queue.py | 15 +- .../models/fp_tank.py | 13 +- .../security/ir.model.access.csv | 3 - .../static/src/js/shopfloor_tablet.js | 12 +- .../static/src/xml/plant_kanban.xml | 2 +- .../static/src/xml/shopfloor_tablet.xml | 50 +---- .../views/fp_first_piece_gate_views.xml | 185 ------------------ .../views/fp_menu.xml | 6 - fusion_plating/scripts/fp_demo_seed.py | 50 +---- fusion_plating/scripts/fp_e2e_workforce.py | 12 +- 19 files changed, 117 insertions(+), 558 deletions(-) create mode 100644 fusion_plating/fusion_plating_shopfloor/migrations/19.0.33.2.0/pre-migrate.py delete mode 100644 fusion_plating/fusion_plating_shopfloor/models/fp_first_piece_gate.py delete mode 100644 fusion_plating/fusion_plating_shopfloor/views/fp_first_piece_gate_views.xml diff --git a/fusion_plating/fusion_plating_jobs/__manifest__.py b/fusion_plating/fusion_plating_jobs/__manifest__.py index 0ad8cfb3..2b18fb34 100644 --- a/fusion_plating/fusion_plating_jobs/__manifest__.py +++ b/fusion_plating/fusion_plating_jobs/__manifest__.py @@ -3,7 +3,7 @@ # License OPL-1 (Odoo Proprietary License v1.0) { 'name': 'Fusion Plating — Native Jobs', - 'version': '19.0.10.30.0', + 'version': '19.0.10.31.0', 'category': 'Manufacturing/Plating', 'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.', 'author': 'Nexa Systems Inc.', diff --git a/fusion_plating/fusion_plating_jobs/views/jobs_in_shopfloor_menu.xml b/fusion_plating/fusion_plating_jobs/views/jobs_in_shopfloor_menu.xml index 7de66f64..df2174a8 100644 --- a/fusion_plating/fusion_plating_jobs/views/jobs_in_shopfloor_menu.xml +++ b/fusion_plating/fusion_plating_jobs/views/jobs_in_shopfloor_menu.xml @@ -1,16 +1,21 @@ diff --git a/fusion_plating/fusion_plating_shopfloor/__manifest__.py b/fusion_plating/fusion_plating_shopfloor/__manifest__.py index b9c796e9..8e0ce0f3 100644 --- a/fusion_plating/fusion_plating_shopfloor/__manifest__.py +++ b/fusion_plating/fusion_plating_shopfloor/__manifest__.py @@ -5,10 +5,9 @@ { 'name': 'Fusion Plating — Shop Floor', - 'version': '19.0.33.1.13', + 'version': '19.0.33.2.0', 'category': 'Manufacturing/Plating', - 'summary': 'Shop-floor tablet stations, QR scanning, bake window enforcer, ' - 'first-piece inspection gates.', + 'summary': 'Shop-floor tablet stations, QR scanning, bake window enforcer.', 'description': """ Fusion Plating — Shop Floor =========================== @@ -53,7 +52,6 @@ Copyright (c) 2026 Nexa Systems Inc. All rights reserved. 'views/res_users_views.xml', 'views/fp_bake_oven_views.xml', 'views/fp_bake_window_views.xml', - 'views/fp_first_piece_gate_views.xml', 'views/fp_plant_overview_views.xml', 'views/tank_status_template.xml', 'views/fp_tablet_session_event_views.xml', diff --git a/fusion_plating/fusion_plating_shopfloor/controllers/shopfloor_controller.py b/fusion_plating/fusion_plating_shopfloor/controllers/shopfloor_controller.py index 15bcb659..a628a77c 100644 --- a/fusion_plating/fusion_plating_shopfloor/controllers/shopfloor_controller.py +++ b/fusion_plating/fusion_plating_shopfloor/controllers/shopfloor_controller.py @@ -641,8 +641,8 @@ class FpShopfloorController(http.Controller): # /fp/landing/kanban. The Tablet Station menu now points at the new # surface. This endpoint stays live as long as the legacy # fp_shopfloor_tablet OWL component is still registered — it consumes - # the rich payload (my_queue, active_wo, baths, bake_windows, gates, - # holds, pending_qcs, stations). Phase 5 cleanup will retire both the + # the rich payload (my_queue, active_wo, baths, bake_windows, holds, + # pending_qcs, stations). Phase 5 cleanup will retire both the # legacy component and this endpoint together. @http.route('/fp/shopfloor/tablet_overview', type='jsonrpc', auth='user') def tablet_overview(self, station_id=None, facility_id=None): @@ -673,7 +673,6 @@ class FpShopfloorController(http.Controller): Step = env['fp.job.step'] BakeWindow = env['fusion.plating.bake.window'] - Gate = env['fusion.plating.first.piece.gate'] Hold = env['fusion.plating.quality.hold'] def _fac_dom(dom): @@ -704,7 +703,6 @@ class FpShopfloorController(http.Controller): awaiting = BakeWindow.search_count(bake_dom + [('state', '=', 'awaiting_bake')]) in_progress_bakes = BakeWindow.search_count(bake_dom + [('state', '=', 'bake_in_progress')]) missed = BakeWindow.search_count(bake_dom + [('state', '=', 'missed_window')]) - pending_gates = Gate.search_count(_fac_dom([('result', '=', 'pending')])) hold_dom = [('state', 'in', ('on_hold', 'under_review'))] if my_job_ids_for_kpi and 'x_fc_job_id' in Hold._fields: hold_dom.append(('x_fc_job_id', 'in', my_job_ids_for_kpi)) @@ -715,7 +713,6 @@ class FpShopfloorController(http.Controller): {'label': 'In Progress', 'value': steps_progress, 'tone': 'success', 'icon': 'fa-cogs'}, {'label': 'Awaiting Bake', 'value': awaiting, 'tone': 'warning', 'icon': 'fa-fire'}, {'label': 'Missed Windows', 'value': missed, 'tone': 'danger' if missed else 'muted', 'icon': 'fa-exclamation-triangle'}, - {'label': 'First-Piece', 'value': pending_gates, 'tone': 'info', 'icon': 'fa-flag-checkered'}, {'label': 'Quality Holds', 'value': open_holds, 'tone': 'danger' if open_holds else 'muted', 'icon': 'fa-pause-circle'}, ] @@ -873,23 +870,6 @@ class FpShopfloorController(http.Controller): for bw in bws ] - # -- First-piece gates ------------------------------------------- - gate_domain = _fac_dom([('result', 'in', ('pending', 'fail'))]) - gates = Gate.search(gate_domain, order='first_piece_produced desc', limit=6) - gates_data = [ - { - 'id': g.id, - 'name': g.name, - 'part_ref': g.part_ref or '', - 'customer': g.customer_ref or '', - 'bath': g.bath_id.name or '', - 'result': g.result, - 'first_piece': fp_format(request.env, g.first_piece_produced), - 'inspector': g.inspector_id.name or '', - } - for g in gates - ] - # -- Quality holds ----------------------------------------------- # v19.0.24.3.0 — scope holds to operator's jobs so Carlos's # sidebar isn't flooded with plant-wide HOLD-XXXX from other @@ -986,7 +966,6 @@ class FpShopfloorController(http.Controller): 'active_wo': active_wo, 'baths': baths_data, 'bake_windows': bw_data, - 'gates': gates_data, 'holds': holds_data, 'pending_qcs': pending_qcs, 'stations': stations, @@ -1007,26 +986,6 @@ class FpShopfloorController(http.Controller): }) return {'ok': True} - # ---------------------------------------------------------------------- - # Mark a first-piece gate result from the tablet - # ---------------------------------------------------------------------- - @http.route('/fp/shopfloor/mark_gate', type='jsonrpc', auth='user') - def mark_gate(self, gate_id, result): - env = request.env - gate = env['fusion.plating.first.piece.gate'].browse(int(gate_id)) - if not gate.exists(): - return {'ok': False, 'error': 'Gate not found.'} - try: - if result == 'pass': - gate.action_mark_pass() - elif result == 'fail': - gate.action_mark_fail() - else: - return {'ok': False, 'error': f'Unknown result {result}'} - except UserError as e: - return {'ok': False, 'error': str(e.args[0]) if e.args else str(e)} - return {'ok': True, 'state': gate.result} - # ---------------------------------------------------------------------- # Operator queue snapshot (legacy fusion.plating.operator.queue helper) # ---------------------------------------------------------------------- @@ -1403,7 +1362,6 @@ class FpShopfloorController(http.Controller): 'due_today': 25, 'priority': 20, 'due_soon': 15, - 'first_piece': 10, 'normal': 0, } diff --git a/fusion_plating/fusion_plating_shopfloor/data/fp_demo_shopfloor_data.xml b/fusion_plating/fusion_plating_shopfloor/data/fp_demo_shopfloor_data.xml index 9d5b2ac6..1c6731ad 100644 --- a/fusion_plating/fusion_plating_shopfloor/data/fp_demo_shopfloor_data.xml +++ b/fusion_plating/fusion_plating_shopfloor/data/fp_demo_shopfloor_data.xml @@ -120,39 +120,8 @@

Window missed — operator shift change, parts left on rack. Flagged for quality review.

- - - - P/N 4422-B — Hydraulic Cylinder Rod - WO-8841 - - - - pass - -

Thickness: 0.0005" ± 0.0001" — within spec. Adhesion bend test passed. Lot released for full production.

-
- - - - P/N 7810-A — Landing Gear Pin - WO-8835 - - - pending - - - - - - P/N 3300-F — Enclosure Panel - WO-8830 - - - - fail - -

Colour variation on test coupon — dye bath concentration too low. Bath adjusted and retested before proceeding.

-
+
diff --git a/fusion_plating/fusion_plating_shopfloor/data/fp_sequence_data.xml b/fusion_plating/fusion_plating_shopfloor/data/fp_sequence_data.xml index 797c637c..c44d6af8 100644 --- a/fusion_plating/fusion_plating_shopfloor/data/fp_sequence_data.xml +++ b/fusion_plating/fusion_plating_shopfloor/data/fp_sequence_data.xml @@ -14,13 +14,4 @@ - - Fusion Plating: First-Piece Gate - fusion.plating.first.piece.gate - FPG/%(year)s/ - 5 - - - - diff --git a/fusion_plating/fusion_plating_shopfloor/migrations/19.0.33.2.0/pre-migrate.py b/fusion_plating/fusion_plating_shopfloor/migrations/19.0.33.2.0/pre-migrate.py new file mode 100644 index 00000000..2e9ab8db --- /dev/null +++ b/fusion_plating/fusion_plating_shopfloor/migrations/19.0.33.2.0/pre-migrate.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 (Odoo Proprietary License v1.0) +"""19.0.33.2.0 — Drop fp.first.piece.gate model + all dependents. + +The first-piece gate model was a skeleton: manual-create only, no +enforcement gate, no FK to fp.job, 0 production rows on entech after +months. Audit on 2026-05-25 concluded REMOVE. + +Per Rule "Removing menus/records — Odoo does NOT auto-delete orphans": +deleting / tags from XML does NOT remove the +corresponding DB rows. We have to explicitly drop them here. + +Pre-migrate (vs post-migrate): runs BEFORE the new XML loads, so +there's no window where the loader tries to reference the deleted +model/action/view records and fails. Also runs before model __init__, +so the registry never sees the (now-removed) Python class try to +match against an existing-but-renamed DB table. +""" +import logging + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + _logger.info("Dropping fp.first.piece.gate model + all dependents") + + # ---- 1. Drop the table (CASCADE wipes any inbound FKs we missed) ---- + cr.execute(""" + DROP TABLE IF EXISTS fusion_plating_first_piece_gate CASCADE + """) + + # ---- 2. ir.model row (cascades to ir.model.fields, ir.model.access, + # and ir.model.constraint via Odoo's own FK rules) ----------- + cr.execute(""" + DELETE FROM ir_model + WHERE model = 'fusion.plating.first.piece.gate' + """) + + # ---- 3. Orphan ir.ui.menu — the menuitem was removed from + # fp_menu.xml; without explicit delete it'd linger ---------- + cr.execute(""" + DELETE FROM ir_ui_menu + WHERE id IN ( + SELECT res_id FROM ir_model_data + WHERE module = 'fusion_plating_shopfloor' + AND model = 'ir.ui.menu' + AND name = 'menu_fp_shopfloor_first_piece' + ) + """) + + # ---- 4. Orphan ir.actions.act_window ------------------------------ + cr.execute(""" + DELETE FROM ir_act_window + WHERE id IN ( + SELECT res_id FROM ir_model_data + WHERE module = 'fusion_plating_shopfloor' + AND model = 'ir.actions.act_window' + AND name = 'action_fp_first_piece_gate' + ) + """) + + # ---- 5. Drop the ir.sequence row + its companion postgres + # sequence (Odoo creates a real PG seq named "fusion_plating_first_piece_gate") ---- + cr.execute(""" + DELETE FROM ir_sequence + WHERE code = 'fusion.plating.first.piece.gate' + """) + cr.execute(""" + DROP SEQUENCE IF EXISTS fusion_plating_first_piece_gate + """) + + # ---- 6. Drop ALL remaining ir.model.data rows tagged for the + # retired model so noupdate=1 demo seeds, view xmlids, etc. + # don't ghost-haunt future upgrades ------------------------ + cr.execute(""" + DELETE FROM ir_model_data + WHERE module = 'fusion_plating_shopfloor' + AND ( name = 'menu_fp_shopfloor_first_piece' + OR name = 'action_fp_first_piece_gate' + OR name = 'seq_fp_first_piece_gate' + OR name LIKE 'view_fp_first_piece%' + OR name LIKE 'demo_fpg_%') + """) + + _logger.info( + "fp.first.piece.gate removal complete: table dropped, ir.model " + "row gone, menu/action/sequence/views/demo xmlids purged." + ) diff --git a/fusion_plating/fusion_plating_shopfloor/models/__init__.py b/fusion_plating/fusion_plating_shopfloor/models/__init__.py index 286a1ecc..4cd178ed 100644 --- a/fusion_plating/fusion_plating_shopfloor/models/__init__.py +++ b/fusion_plating/fusion_plating_shopfloor/models/__init__.py @@ -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 diff --git a/fusion_plating/fusion_plating_shopfloor/models/fp_first_piece_gate.py b/fusion_plating/fusion_plating_shopfloor/models/fp_first_piece_gate.py deleted file mode 100644 index 2fd5b04e..00000000 --- a/fusion_plating/fusion_plating_shopfloor/models/fp_first_piece_gate.py +++ /dev/null @@ -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, - }) diff --git a/fusion_plating/fusion_plating_shopfloor/models/fp_operator_queue.py b/fusion_plating/fusion_plating_shopfloor/models/fp_operator_queue.py index f0f7b7e3..e0e6f0e9 100644 --- a/fusion_plating/fusion_plating_shopfloor/models/fp_operator_queue.py +++ b/fusion_plating/fusion_plating_shopfloor/models/fp_operator_queue.py @@ -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: diff --git a/fusion_plating/fusion_plating_shopfloor/models/fp_tank.py b/fusion_plating/fusion_plating_shopfloor/models/fp_tank.py index c6d48ac3..0d0bfae8 100644 --- a/fusion_plating/fusion_plating_shopfloor/models/fp_tank.py +++ b/fusion_plating/fusion_plating_shopfloor/models/fp_tank.py @@ -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.""" diff --git a/fusion_plating/fusion_plating_shopfloor/security/ir.model.access.csv b/fusion_plating/fusion_plating_shopfloor/security/ir.model.access.csv index aaf400b8..c3c849f6 100644 --- a/fusion_plating/fusion_plating_shopfloor/security/ir.model.access.csv +++ b/fusion_plating/fusion_plating_shopfloor/security/ir.model.access.csv @@ -8,9 +8,6 @@ access_fp_bake_oven_manager,fp.bake.oven.manager,model_fusion_plating_bake_oven, access_fp_bake_window_operator,fp.bake.window.operator,model_fusion_plating_bake_window,fusion_plating.group_fp_technician,1,1,1,0 access_fp_bake_window_supervisor,fp.bake.window.supervisor,model_fusion_plating_bake_window,fusion_plating.group_fp_shop_manager_v2,1,1,1,0 access_fp_bake_window_manager,fp.bake.window.manager,model_fusion_plating_bake_window,fusion_plating.group_fp_manager,1,1,1,1 -access_fp_first_piece_gate_operator,fp.first.piece.gate.operator,model_fusion_plating_first_piece_gate,fusion_plating.group_fp_technician,1,1,1,0 -access_fp_first_piece_gate_supervisor,fp.first.piece.gate.supervisor,model_fusion_plating_first_piece_gate,fusion_plating.group_fp_shop_manager_v2,1,1,1,0 -access_fp_first_piece_gate_manager,fp.first.piece.gate.manager,model_fusion_plating_first_piece_gate,fusion_plating.group_fp_manager,1,1,1,1 access_fp_operator_queue_operator,fp.operator.queue.operator,model_fusion_plating_operator_queue,fusion_plating.group_fp_technician,1,1,1,1 access_fp_operator_queue_supervisor,fp.operator.queue.supervisor,model_fusion_plating_operator_queue,fusion_plating.group_fp_shop_manager_v2,1,1,1,1 access_fp_operator_queue_manager,fp.operator.queue.manager,model_fusion_plating_operator_queue,fusion_plating.group_fp_manager,1,1,1,1 diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/js/shopfloor_tablet.js b/fusion_plating/fusion_plating_shopfloor/static/src/js/shopfloor_tablet.js index 5104566d..d5c3fed1 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/js/shopfloor_tablet.js +++ b/fusion_plating/fusion_plating_shopfloor/static/src/js/shopfloor_tablet.js @@ -239,16 +239,8 @@ export class ShopfloorTablet extends Component { await this.refresh(); } - async onGateResult(gateId, result) { - try { - await rpc("/fp/shopfloor/mark_gate", { gate_id: gateId, result }); - this.setMessage(`First-piece marked ${result.toUpperCase()}.`, - result === "pass" ? "success" : "danger"); - } catch (err) { - this.setMessage(`Gate update failed: ${err.message || err}`, "danger"); - } - await this.refresh(); - } + // onGateResult / /fp/shopfloor/mark_gate retired with the + // fp.first.piece.gate model removal (19.0.33.2.0). async onQueueItemClick(row) { if (row.source_model && row.source_id) { diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/xml/plant_kanban.xml b/fusion_plating/fusion_plating_shopfloor/static/src/xml/plant_kanban.xml index 953e7fc2..e279ec32 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/xml/plant_kanban.xml +++ b/fusion_plating/fusion_plating_shopfloor/static/src/xml/plant_kanban.xml @@ -31,7 +31,7 @@
diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml b/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml index 763532a1..5ca4d2cb 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml +++ b/fusion_plating/fusion_plating_shopfloor/static/src/xml/shopfloor_tablet.xml @@ -342,53 +342,9 @@ -
-
-

First-Piece Gates

- -
-
- -
No pending first-piece inspections.
-
-
    - -
  • -
    -
    - - -
    -
    - - · Bath -
    -
    -
    - - - -
    -
    - - - -
    -
  • -
    -
-
+ diff --git a/fusion_plating/fusion_plating_shopfloor/views/fp_first_piece_gate_views.xml b/fusion_plating/fusion_plating_shopfloor/views/fp_first_piece_gate_views.xml deleted file mode 100644 index 6fbe193f..00000000 --- a/fusion_plating/fusion_plating_shopfloor/views/fp_first_piece_gate_views.xml +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - fp.first.piece.gate.list - fusion.plating.first.piece.gate - - - - - - - - - - - - - - - - - - fp.first.piece.gate.form - fusion.plating.first.piece.gate - -
-
-
- -
-
- - - - - - - - - - - - - - - - - -
- - -
-
- - - - fp.first.piece.gate.kanban - fusion.plating.first.piece.gate - - - - - - - - - - - - - -
-
- -
-
- -
-
- - - - · - - - -
-
- - - - · - - - -
- -
-
-
-
-
-
- - - fp.first.piece.gate.search - fusion.plating.first.piece.gate - - - - - - - - - - - - - - - - - - - - - - - - - - - First-Piece Gates - fusion.plating.first.piece.gate - kanban,list,form - - {'search_default_pending': 1} - - -
diff --git a/fusion_plating/fusion_plating_shopfloor/views/fp_menu.xml b/fusion_plating/fusion_plating_shopfloor/views/fp_menu.xml index 666f0c3d..d83c7531 100644 --- a/fusion_plating/fusion_plating_shopfloor/views/fp_menu.xml +++ b/fusion_plating/fusion_plating_shopfloor/views/fp_menu.xml @@ -43,12 +43,6 @@ action="action_fp_bake_window" sequence="20"/> - - Thickness 1.95 mils — within tolerance. Lot released pending planner signoff.

', - }) - Gate.create({ - 'bath_id': bath_en.id, - 'part_ref': 'CY-STR-240', - 'customer_ref': 'Cyclone Manufacturing', - 'routing_first_run': True, - 'first_piece_produced': datetime.now() - timedelta(hours=6), - 'first_piece_inspected': datetime.now() - timedelta(hours=5, minutes=30), - 'inspector_id': env.user.id, - 'result': 'fail', - 'notes': '

Thickness 0.8 mils — below spec (min 1.2). Rework required.

', - }) - LOG(" 4 first-piece gates: 1 pending / 1 passed+released / 1 passed-holding / 1 failed") -else: - LOG(f" Already has {Gate.search_count([])} first-piece gates — skipping") +# First-piece-gate seeding retired with the model (19.0.33.2.0). # Quality holds on active MOs — gives the Shop Floor quality-holds panel content Hold = env['fusion.plating.quality.hold'] @@ -1374,7 +1327,6 @@ LOG(f" Bath logs: {env['fusion.plating.bath.log'].search_count([])}") LOG(f" Replenishments: {env['fusion.plating.bath.replenishment.suggestion'].search_count([])}") LOG(f" Bake windows: {env['fusion.plating.bake.window'].search_count([])}") LOG(f" Stations: {env['fusion.plating.shopfloor.station'].search_count([])}") -LOG(f" First-piece: {env['fusion.plating.first.piece.gate'].search_count([])}") LOG(f" Quality holds: {env['fusion.plating.quality.hold'].search_count([])}") LOG(f" Racks: {env['fusion.plating.rack'].search_count([])}") LOG(f" Operator certs: {env['fp.operator.certification'].search_count([])}") diff --git a/fusion_plating/scripts/fp_e2e_workforce.py b/fusion_plating/scripts/fp_e2e_workforce.py index 035d617a..deb75e6c 100644 --- a/fusion_plating/scripts/fp_e2e_workforce.py +++ b/fusion_plating/scripts/fp_e2e_workforce.py @@ -853,17 +853,7 @@ if BakeWin is not None and job: 'bake window auto-created', f'{len(bw)} record(s) for {job.name}') -# First-piece gate auto-created? -FPG = env.get('fusion.plating.first.piece.gate') -if FPG is not None: - # FPG model may not have production_id either; try common link fields - fpg = FPG.search([]) # take any recent - fpg_for_mo = fpg.filtered( - lambda g: getattr(g, 'production_id', False) and g.production_id.id == mo.id - ) if 'production_id' in FPG._fields else fpg.browse([]) - finding('PASS' if fpg_for_mo else 'WARN', - 'first-piece gate', - f'{len(fpg_for_mo)} for MO (coating-driven; OK if 0)') +# First-piece-gate check retired with the model (19.0.33.2.0). # Each operator can see their OWN assigned WOs via the tablet # (queue is a TransientModel; tablet calls build_for_user on load)