From f7a4cba5a8732ab98f56d1842851be1163393584 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Fri, 24 Apr 2026 21:54:35 -0400 Subject: [PATCH] =?UTF-8?q?docs(jobs):=20split=20fp.job=20=C2=A75.1=20fiel?= =?UTF-8?q?ds=20by=20module=20ownership=20(Task=201.4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Originally Task 1.4 was to add all spec §5.1 extension fields to fp.job in core. The dependency-graph audit during implementation revealed that 6 of those fields point to models in dependent modules (configurator, quality, portal, logistics, bridge_mrp). Adding them in core would invert the dependency graph. Spec §5.1 now has a Module column. Core-safe fields stay in fusion_plating/models/fp_job.py; cross-module fields are deferred to their owning modules via _inherit = 'fp.job' in Phase 2. Plan Task 1.4 narrative updated to reflect the reduced scope. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../plans/2026-04-25-fp-native-job-model.md | 53 +++++------ .../2026-04-25-fp-native-job-model-design.md | 95 ++++++++++--------- 2 files changed, 75 insertions(+), 73 deletions(-) diff --git a/fusion_plating/docs/superpowers/plans/2026-04-25-fp-native-job-model.md b/fusion_plating/docs/superpowers/plans/2026-04-25-fp-native-job-model.md index 0b06ab9e..257a1d99 100644 --- a/fusion_plating/docs/superpowers/plans/2026-04-25-fp-native-job-model.md +++ b/fusion_plating/docs/superpowers/plans/2026-04-25-fp-native-job-model.md @@ -453,7 +453,10 @@ Create `fusion_plating/data/fp_job_sequences.xml`: ```xml - + + @@ -513,11 +516,20 @@ Co-Authored-By: Claude Opus 4.7 (1M context) " --- -### Task 1.4: Add SO/origin/extension fields to `fp.job` +### Task 1.4: Add core-safe extension fields to `fp.job` -The full field list from spec §5.1 — added in chunks so each commit is reviewable. +**Scope reduction (2026-04-25):** Originally this task added all spec §5.1 fields. +But the dependency audit during Task 1.4 implementation revealed that 6 of those +fields point to models in modules that depend on `fusion_plating` core (configurator, +quality, portal, logistics, bridge_mrp). Adding them in core would invert the +dependency graph. **Per the updated spec §5.1**, those fields are deferred to their +owning modules via `_inherit = 'fp.job'` and re-bundled by `fusion_plating_jobs` in +Phase 2. -- [ ] **Step 1: Add SO + recipe + portal/delivery fields** +This task now lands ONLY the fields whose target models are reachable from core's +existing `depends` (sale_management → sale → account, and our own process.node): + +- [ ] **Step 1: Add SO + recipe core-safe fields** Modify `fusion_plating/models/fp_job.py` — add fields after `company_id`: @@ -528,19 +540,6 @@ Modify `fusion_plating/models/fp_job.py` — add fields after `company_id`: 'job_id', 'line_id', string='Source SO Lines', ) - part_catalog_id = fields.Many2one( - 'fp.part.catalog', - string='Part', - index=True, - ) - coating_config_id = fields.Many2one( - 'fp.coating.config', - string='Coating Configuration', - ) - customer_spec_id = fields.Many2one( - 'fusion.plating.customer.spec', - string='Customer Spec', - ) recipe_id = fields.Many2one( 'fusion.plating.process.node', string='Recipe', @@ -551,26 +550,22 @@ Modify `fusion_plating/models/fp_job.py` — add fields after `company_id`: string='Start at Node', help='Rework: start the job at this recipe node (skip earlier).', ) - portal_job_id = fields.Many2one( - 'fusion.plating.portal.job', - string='Portal Job', - ) - delivery_id = fields.Many2one( - 'fusion.plating.delivery', - string='Delivery', - ) invoice_ids = fields.Many2many( 'account.move', 'fp_job_account_move_rel', 'job_id', 'move_id', string='Invoices', ) - qc_check_id = fields.Many2one( - 'fp.quality.check', - string='Active QC Check', - ) ``` +**Deferred to bridge modules (DO NOT add in this task):** +- `part_catalog_id`, `coating_config_id` → owned by `fusion_plating_configurator` +- `customer_spec_id` → owned by `fusion_plating_quality` +- `portal_job_id` → owned by `fusion_plating_portal` +- `delivery_id` → owned by `fusion_plating_logistics` +- `qc_check_id` → owned by `fusion_plating_jobs` (Phase 2; the underlying model + `fusion.plating.quality.check` currently lives in `fusion_plating_bridge_mrp`) + - [ ] **Step 2: Add cost rollup fields (computed)** Append: diff --git a/fusion_plating/docs/superpowers/specs/2026-04-25-fp-native-job-model-design.md b/fusion_plating/docs/superpowers/specs/2026-04-25-fp-native-job-model-design.md index 65615a6c..9d58051a 100644 --- a/fusion_plating/docs/superpowers/specs/2026-04-25-fp-native-job-model-design.md +++ b/fusion_plating/docs/superpowers/specs/2026-04-25-fp-native-job-model-design.md @@ -96,50 +96,57 @@ process tree with cost/time aggregates. Replaces `mrp.production` for plating jobs. One record per shop-floor job. -| Field | Type | Notes | -|---|---|---| -| `name` | Char | Sequence: `WH/JOB/00033`. The legacy "WH/MO/00033" labels stay only on migrated records (see §7). | -| `state` | Selection | `draft`, `confirmed`, `in_progress`, `done`, `cancelled`, `on_hold` | -| `partner_id` | Many2one(res.partner) | Customer; copied from SO | -| `product_id` | Many2one(product.product) | Reference part product (for inventory only) | -| `part_catalog_id` | Many2one(fp.part.catalog) | The actual part being plated; primary identifier | -| `qty` | Float | Quantity to plate | -| `qty_done` | Float | Quantity completed | -| `qty_scrapped` | Float | Quantity scrapped (rolled up from holds) | -| `date_deadline` | Datetime | Promised completion date | -| `date_planned_start` | Datetime | Planned start | -| `date_started` | Datetime | Actual start (first step start) | -| `date_finished` | Datetime | Actual completion | -| `origin` | Char | SO name for traceability | -| `sale_order_id` | Many2one(sale.order) | Source SO | -| `sale_order_line_ids` | Many2many(sale.order.line) | Lines that fed this job (group_tag collapse) | -| `recipe_id` | Many2one(fusion.plating.process.node) | The recipe template used | -| `step_ids` | One2many(fp.job.step, job_id) | The operations | -| `step_count` | Integer | Computed | -| `step_done_count` | Integer | Computed | -| `step_progress_pct` | Float | Computed: `step_done_count / step_count * 100` | -| `current_step_id` | Many2one(fp.job.step) | The operation currently in progress (or next ready) | -| `coating_config_id` | Many2one(fp.coating.config) | The coating spec | -| `facility_id` | Many2one(fp.facility) | Hard gate at confirm | -| `manager_id` | Many2one(res.users) | Plating manager | -| `priority` | Selection | `low`, `normal`, `high`, `rush` (operator-relevant ordering) | -| `customer_spec_id` | Many2one(fp.customer.spec) | Optional spec | -| `portal_job_id` | Many2one(fp.portal.job) | Customer portal binding (renamed from `x_fc_portal_job_id`) | -| `delivery_id` | Many2one(fp.delivery) | The shipment | -| `invoice_ids` | Many2many(account.move) | Linked invoices | -| `certificate_ids` | One2many(fp.certificate, job_id) | Certs generated | -| `batch_ids` | One2many(fp.batch, job_id) | Batches that ran through | -| `quality_hold_ids` | One2many(fp.quality.hold, job_id) | Holds raised | -| `consumption_ids` | One2many(fp.job.consumption, job_id) | Consumables | -| `qc_check_id` | Many2one(fp.quality.check) | Active QC check | -| `quoted_revenue` | Monetary | From SO | -| `actual_cost` | Monetary | Computed from steps + consumables | -| `margin` | Monetary | Computed | -| `margin_pct` | Float | Computed | -| `start_at_node_id` | Many2one(fusion.plating.process.node) | Rework: start at this recipe node | -| `override_ids` | One2many(fp.job.node.override, job_id) | Per-job opt-in/out | -| `current_location` | Char | Computed: "Queued: Bath 3" / "In progress: Oven A" / "Ready to ship" | -| `mail.thread, mail.activity.mixin` | Inherits | Chatter | +**Module ownership:** `fp.job` lives in `fusion_plating` core. Cross-module fields +(referencing models from `fusion_plating_configurator`, `_portal`, `_logistics`, +`_quality`, `_bridge_mrp`) **cannot** live in core without inverting the dependency +graph. Each owning module extends `fp.job` via `_inherit` to add its field. The +Phase 2 module `fusion_plating_jobs` becomes the umbrella that pulls all the +extensions together. Ownership is called out in the **Module** column below. + +| Field | Type | Module | Notes | +|---|---|---|---| +| `name` | Char | core | Sequence: `WH/JOB/00033`. The legacy "WH/MO/00033" labels stay only on migrated records (see §7). | +| `state` | Selection | core | `draft`, `confirmed`, `in_progress`, `done`, `cancelled`, `on_hold` | +| `partner_id` | Many2one(res.partner) | core | Customer; copied from SO | +| `product_id` | Many2one(product.product) | core | Reference part product (for inventory only) | +| `qty` | Float | core | Quantity to plate | +| `qty_done` | Float | core | Quantity completed | +| `qty_scrapped` | Float | core | Quantity scrapped (rolled up from holds) | +| `date_deadline` | Datetime | core | Promised completion date | +| `date_planned_start` | Datetime | core | Planned start | +| `date_started` | Datetime | core | Actual start (first step start) | +| `date_finished` | Datetime | core | Actual completion | +| `origin` | Char | core | SO name for traceability | +| `sale_order_id` | Many2one(sale.order) | core | Source SO (sale_management is in core depends) | +| `sale_order_line_ids` | Many2many(sale.order.line) | core | Lines that fed this job (group_tag collapse) | +| `recipe_id` | Many2one(fusion.plating.process.node) | core | The recipe template used | +| `step_ids` | One2many(fp.job.step, job_id) | core | The operations | +| `step_count` | Integer | core | Computed | +| `step_done_count` | Integer | core | Computed | +| `step_progress_pct` | Float | core | Computed: `step_done_count / step_count * 100` | +| `current_step_id` | Many2one(fp.job.step) | core | The operation currently in progress (or next ready) | +| `facility_id` | Many2one(fusion.plating.facility) | core | Hard gate at confirm | +| `manager_id` | Many2one(res.users) | core | Plating manager | +| `priority` | Selection | core | `low`, `normal`, `high`, `rush` (operator-relevant ordering) | +| `invoice_ids` | Many2many(account.move) | core | Linked invoices (account is reachable via sale_management → sale → account) | +| `quoted_revenue` | Monetary | core | From SO | +| `actual_cost` | Monetary | core | Computed from steps + consumables | +| `margin` | Monetary | core | Computed | +| `margin_pct` | Float | core | Computed | +| `start_at_node_id` | Many2one(fusion.plating.process.node) | core | Rework: start at this recipe node | +| `current_location` | Char | core | Computed: "Queued: Bath 3" / "In progress: Oven A" / "Ready to ship" | +| `mail.thread, mail.activity.mixin` | Inherits | core | Chatter | +| `part_catalog_id` | Many2one(fp.part.catalog) | **`fusion_plating_configurator`** (`_inherit = 'fp.job'`) | The actual part being plated; primary identifier | +| `coating_config_id` | Many2one(fp.coating.config) | **`fusion_plating_configurator`** | The coating spec | +| `customer_spec_id` | Many2one(fusion.plating.customer.spec) | **`fusion_plating_quality`** | Optional spec | +| `portal_job_id` | Many2one(fusion.plating.portal.job) | **`fusion_plating_portal`** | Customer portal binding | +| `delivery_id` | Many2one(fusion.plating.delivery) | **`fusion_plating_logistics`** | The shipment | +| `qc_check_id` | Many2one(fusion.plating.quality.check) | **`fusion_plating_jobs`** (Phase 2) | Active QC check; model lives in current bridge_mrp, will move to jobs module | +| `certificate_ids` | One2many(fp.certificate, job_id) | **`fusion_plating_certificates`** | Certs generated | +| `batch_ids` | One2many(fp.batch, job_id) | **`fusion_plating_batch`** | Batches that ran through | +| `quality_hold_ids` | One2many(fp.quality.hold, job_id) | **`fusion_plating_quality`** | Holds raised | +| `consumption_ids` | One2many(fp.job.consumption, job_id) | **`fusion_plating_jobs`** (Phase 2) | Consumables | +| `override_ids` | One2many(fp.job.node.override, job_id) | **`fusion_plating_jobs`** (Phase 2) | Per-job opt-in/out | **State machine:** ```