From 5f030803742f31e2105ee8332adb1f39ab9afe3c Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sat, 23 May 2026 00:47:20 -0400 Subject: [PATCH] feat(shopfloor): switch action-path RPCs to fpRpc + wire plant_overview/move_card (P6.3.5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JobWorkspace, ShopfloorLanding, ManagerDashboard, and the embedded FpHoldComposer now call fpRpc() for write-path endpoints (start/finish step, hold create, sign-off, milestone advance, work-centre move, assign-worker, assign-tank, manager takeover). fpRpc auto-injects tablet_tech_id from the tech_store so the server can rebind env via env_for_tablet_tech() and credit the right user. Read-path RPCs (workspace/load, landing/kanban, manager/overview, manager/funnel, manager/approval_inbox, manager/at_risk, shopfloor/scan) stay as plain rpc() — no audit benefit, no need for the extra plumbing. Also wires tablet_tech_id into /fp/shopfloor/plant_overview/move_card which I missed in P6.3.3 — surfaced when grepping JS for write callers. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../controllers/shopfloor_controller.py | 10 ++++++---- .../static/src/js/components/hold_composer.js | 4 ++-- .../static/src/js/job_workspace.js | 9 +++++---- .../static/src/js/manager_dashboard.js | 7 ++++--- .../static/src/js/shopfloor_landing.js | 3 ++- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/fusion_plating/fusion_plating_shopfloor/controllers/shopfloor_controller.py b/fusion_plating/fusion_plating_shopfloor/controllers/shopfloor_controller.py index f49f0020..0a068793 100644 --- a/fusion_plating/fusion_plating_shopfloor/controllers/shopfloor_controller.py +++ b/fusion_plating/fusion_plating_shopfloor/controllers/shopfloor_controller.py @@ -1108,21 +1108,23 @@ class FpShopfloorController(http.Controller): @http.route('/fp/shopfloor/plant_overview/move_card', type='jsonrpc', auth='user') def plant_overview_move_card(self, card_id, source_model=None, - target_workcenter_id=None): + target_workcenter_id=None, + tablet_tech_id=None): """Move a step card to a different work centre (drag & drop). `source_model` is accepted for backward compatibility but ignored — Plant Overview now only ever serves fp.job.step cards. A target of 0 / falsy clears the work centre. """ - Step = request.env['fp.job.step'] + env = env_for_tablet_tech(request.env, tablet_tech_id) + Step = env['fp.job.step'] step = Step.browse(int(card_id)) if not step.exists(): return {'ok': False, 'error': f'Step {card_id} not found.'} wc_id = int(target_workcenter_id) if target_workcenter_id else False if wc_id: - wc = request.env['fp.work.centre'].browse(wc_id) + wc = env['fp.work.centre'].browse(wc_id) if not wc.exists(): return {'ok': False, 'error': f'Work centre {target_workcenter_id} not found.'} @@ -1132,7 +1134,7 @@ class FpShopfloorController(http.Controller): _logger.info( 'Plant Overview: moved step %s (%s) → WC %s by uid %s', step.id, step.name, wc_id or 'unassigned', - request.env.uid, + env.uid, ) except Exception as exc: _logger.exception('Plant Overview move_card failed') diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/js/components/hold_composer.js b/fusion_plating/fusion_plating_shopfloor/static/src/js/components/hold_composer.js index 32667b88..26ff9600 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/js/components/hold_composer.js +++ b/fusion_plating/fusion_plating_shopfloor/static/src/js/components/hold_composer.js @@ -14,7 +14,7 @@ import { Component, useState } from "@odoo/owl"; import { Dialog } from "@web/core/dialog/dialog"; -import { rpc } from "@web/core/network/rpc"; +import { fpRpc } from "../services/fp_rpc"; import { useService } from "@web/core/utils/hooks"; // Hold reasons kept here so the picker doesn't need a server roundtrip. @@ -75,7 +75,7 @@ export class FpHoldComposer extends Component { } this.state.submitting = true; try { - const res = await rpc("/fp/workspace/hold", { + const res = await fpRpc("/fp/workspace/hold", { job_id: this.props.jobId, step_id: this.props.stepId || null, part_ref: this.props.partRef || "", diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/js/job_workspace.js b/fusion_plating/fusion_plating_shopfloor/static/src/js/job_workspace.js index 58e91f32..0e071585 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/js/job_workspace.js +++ b/fusion_plating/fusion_plating_shopfloor/static/src/js/job_workspace.js @@ -20,6 +20,7 @@ import { Component, useState, onMounted, onWillUnmount } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { rpc } from "@web/core/network/rpc"; +import { fpRpc } from "./services/fp_rpc"; import { useService } from "@web/core/utils/hooks"; import { WorkflowChip } from "./components/workflow_chip"; import { GateViz } from "./components/gate_viz"; @@ -116,7 +117,7 @@ export class FpJobWorkspace extends Component { // ---- Step actions ------------------------------------------------------ async onStartStep(stepId) { try { - const res = await rpc("/fp/shopfloor/start_wo", { workorder_id: stepId }); + const res = await fpRpc("/fp/shopfloor/start_wo", { workorder_id: stepId }); if (res && res.ok) { this.notification.add("Step started.", { type: "success" }); await this.refresh(); @@ -135,7 +136,7 @@ export class FpJobWorkspace extends Component { contextLabel: `${this.state.data.job.display_wo_name} · Step ${step.sequence_display}: ${step.name}`, onSubmit: async (dataUri) => { try { - const res = await rpc("/fp/workspace/sign_off", { + const res = await fpRpc("/fp/workspace/sign_off", { step_id: step.id, signature_data_uri: dataUri, }); @@ -154,7 +155,7 @@ export class FpJobWorkspace extends Component { } // Plain finish — no signature required try { - const res = await rpc("/fp/shopfloor/stop_wo", { + const res = await fpRpc("/fp/shopfloor/stop_wo", { workorder_id: step.id, finish: true, }); if (res && res.ok) { @@ -201,7 +202,7 @@ export class FpJobWorkspace extends Component { async onAdvanceMilestone() { try { - const res = await rpc("/fp/workspace/advance_milestone", { + const res = await fpRpc("/fp/workspace/advance_milestone", { job_id: this.state.jobId, }); if (res && res.ok) { diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/js/manager_dashboard.js b/fusion_plating/fusion_plating_shopfloor/static/src/js/manager_dashboard.js index dd8de876..3b443d94 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/js/manager_dashboard.js +++ b/fusion_plating/fusion_plating_shopfloor/static/src/js/manager_dashboard.js @@ -15,6 +15,7 @@ import { Component, useState, onMounted, onWillUnmount } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { rpc } from "@web/core/network/rpc"; +import { fpRpc } from "./services/fp_rpc"; import { useService } from "@web/core/utils/hooks"; import { QrScanner } from "./qr_scanner"; import { FpTabletLock } from "./tablet_lock"; @@ -208,7 +209,7 @@ export class ManagerDashboard extends Component { async onAssignWorker(step, userIdRaw) { const userId = parseInt(userIdRaw) || null; try { - const res = await rpc("/fp/manager/assign_worker", { + const res = await fpRpc("/fp/manager/assign_worker", { step_id: step.id, user_id: userId, }); if (res && res.ok) { @@ -226,7 +227,7 @@ export class ManagerDashboard extends Component { async onAssignTank(step, tankIdRaw) { const tankId = parseInt(tankIdRaw) || null; try { - const res = await rpc("/fp/manager/assign_tank", { + const res = await fpRpc("/fp/manager/assign_tank", { step_id: step.id, tank_id: tankId, }); if (res && res.ok) { @@ -243,7 +244,7 @@ export class ManagerDashboard extends Component { async onTakeOver(step) { try { - const res = await rpc("/fp/manager/take_over", { + const res = await fpRpc("/fp/manager/take_over", { step_id: step.id, }); if (res && res.ok) { diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/js/shopfloor_landing.js b/fusion_plating/fusion_plating_shopfloor/static/src/js/shopfloor_landing.js index 923bf472..7dff654d 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/js/shopfloor_landing.js +++ b/fusion_plating/fusion_plating_shopfloor/static/src/js/shopfloor_landing.js @@ -20,6 +20,7 @@ import { Component, useState, onMounted, onWillUnmount } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { rpc } from "@web/core/network/rpc"; +import { fpRpc } from "./services/fp_rpc"; import { useService } from "@web/core/utils/hooks"; import { QrScanner } from "./qr_scanner"; import { FpKanbanCard } from "./components/kanban_card"; @@ -254,7 +255,7 @@ export class FpShopfloorLanding extends Component { this._movesInFlight += 1; this._lastDropAt = Date.now(); try { - const res = await rpc("/fp/shopfloor/plant_overview/move_card", { + const res = await fpRpc("/fp/shopfloor/plant_overview/move_card", { card_id: dragged.id, target_workcenter_id: col.work_center_id, });