docs: address spec review findings — 5 critical, 8 major issues fixed
- Add model naming convention table (fp.* for new, fusion.plating.* for existing)
- Add fusion_plating_certificates as dedicated module with fp.thickness.reading model
- Fix complexity_surcharge: companion model instead of JSON text field
- Add recipe_id domain constraint [('node_type', '=', 'recipe')]
- Align security groups with existing 4-level privilege hierarchy
- Add currency_id to all monetary models
- Clarify fp.quote.configurator as persistent model with state lifecycle
- Fix canonical model names (fusion.plating.portal.job, fusion.plating.delivery)
- Add auto-population rules for invoice strategy and configurator defaults
- Lighten bridge_mrp deps: gates as mixins in receiving/invoicing modules
- Add deployment strategy for fusion_tasks (same server, not standalone)
- Add data migration section for existing quote request coexistence
- Add work centre mapping note (fusion.plating.work.center ↔ mrp.workcenter)
- Change x_fc_account_hold_date to Datetime for audit precision
- Add bilingual CoC implementation note (QWeb, not ir.translation)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,17 @@
|
||||
|
||||
Complete end-to-end ERP workflow for an electroless nickel plating shop, replacing Steelhead Software. The system covers customer inquiry through invoicing, with a quotation configurator, parts receiving/inspection, flexible invoicing strategies, automated email notifications, certificate management, and local delivery dispatch.
|
||||
|
||||
### Model Naming Convention
|
||||
|
||||
| Context | Convention | Example |
|
||||
|---------|-----------|---------|
|
||||
| New custom models (all new modules) | `fp.*` prefix | `fp.part.catalog`, `fp.certificate` |
|
||||
| Existing custom models (already in codebase) | Keep `fusion.plating.*` | `fusion.plating.portal.job`, `fusion.plating.delivery` |
|
||||
| New fields on standard Odoo models | `x_fc_*` prefix | `x_fc_po_number` on `sale.order` |
|
||||
| Legacy fields (from Studio era) | `x_studio_*` | Preserved, not renamed |
|
||||
|
||||
The `fp.*` prefix is the new short-form convention for all models created in the new modules. Existing `fusion.plating.*` models are NOT renamed — they keep their current `_name`. All references in this spec use canonical `_name` values.
|
||||
|
||||
### Architecture: Approach 2 — Dedicated Modules per Sub-System
|
||||
|
||||
| Module | Purpose | Location |
|
||||
@@ -19,10 +30,11 @@ Complete end-to-end ERP workflow for an electroless nickel plating shop, replaci
|
||||
| `fusion_plating_receiving` | Parts receiving, inspection, damage logging, PO matching | `fusion-plating/` |
|
||||
| `fusion_plating_invoicing` | Invoice strategy engine (deposit/progress/net/COD), account holds | `fusion-plating/` |
|
||||
| `fusion_plating_notifications` | Auto-email engine, notification templates, audit log | `fusion-plating/` |
|
||||
| `fusion_plating_certificates` | Certificate registry (CoC, thickness, Nadcap, customer-specific) | `fusion-plating/` |
|
||||
| `fusion_tasks` | Local delivery dispatch (forked from Westin, stripped of claims) | `Entech Plating/` |
|
||||
|
||||
Plus updates to existing modules:
|
||||
- `fusion_plating_bridge_mrp` — Recipe-to-WO generation, manufacturing gates
|
||||
- `fusion_plating_bridge_mrp` — Recipe-to-WO generation (lightweight; gates live in their own modules)
|
||||
- `fusion_plating_portal` — Customer-facing configurator UI, 3D preview
|
||||
- `fusion_plating_reports` — CoC template updates, thickness report template
|
||||
- `fusion_plating_quality` — Thickness reading model for Fischerscope data
|
||||
@@ -43,7 +55,7 @@ Fusion Plating (app)
|
||||
│ ├── Customers (res.partner, customer_rank > 0)
|
||||
│ └── Part Catalog (fp.part.catalog)
|
||||
├── Configurator
|
||||
│ ├── New Quote (fp.quote.configurator wizard)
|
||||
│ ├── New Quote (fp.quote.configurator, persistent model)
|
||||
│ ├── Coating Configurations (fp.coating.config)
|
||||
│ └── Pricing Rules (fp.pricing.rule)
|
||||
├── Manufacturing
|
||||
@@ -90,17 +102,21 @@ Fusion Plating (app)
|
||||
|
||||
### Permission-Based Visibility
|
||||
|
||||
| Group | Sees |
|
||||
|-------|------|
|
||||
| `fp_group_estimator` | Sales, Configurator, Customers, Part Catalog |
|
||||
| `fp_group_shop_manager` | Everything (full menu) |
|
||||
| `fp_group_shop_floor` | Manufacturing, Work Orders, Plant Overview only |
|
||||
| `fp_group_receiving` | Receiving & Inspection, can view Sales (read-only) |
|
||||
| `fp_group_shipping` | Shipping & Delivery, can view Sales (read-only) |
|
||||
| `fp_group_quality` | Quality, can view Manufacturing |
|
||||
| `fp_group_accounting` | Sales (invoicing fields), Reports |
|
||||
The existing codebase defines a 4-level privilege hierarchy in `fusion_plating/security/fp_security.xml`: Operator → Supervisor → Manager → Administrator. These new groups are **role-based** and work **alongside** (not replacing) the existing privilege levels. A user has both a privilege level (what they can do: read/write/create/delete) and one or more roles (what they can see: which menus appear).
|
||||
|
||||
These are Fusion Plating security groups layered on top of standard Odoo groups.
|
||||
| Role Group | Menu Visibility | Required Privilege Level |
|
||||
|------------|----------------|------------------------|
|
||||
| `fp_group_estimator` | Sales, Configurator, Customers, Part Catalog | Supervisor+ |
|
||||
| `fp_group_shop_manager` | Everything (full menu) | Manager+ |
|
||||
| `fp_group_shop_floor` | Manufacturing, Work Orders, Plant Overview only | Operator+ |
|
||||
| `fp_group_receiving` | Receiving & Inspection, can view Sales (read-only) | Operator+ |
|
||||
| `fp_group_shipping` | Shipping & Delivery, can view Sales (read-only) | Operator+ |
|
||||
| `fp_group_quality` | Quality, can view Manufacturing | Supervisor+ |
|
||||
| `fp_group_accounting` | Sales (invoicing fields), Reports | Supervisor+ |
|
||||
|
||||
Users are assigned to one or more role groups. The existing privilege hierarchy controls CRUD permissions; role groups control menu/view visibility. `fp_group_shop_manager` implies all other role groups (full access).
|
||||
|
||||
Standard Odoo groups are still required for underlying model access (e.g. `sales_team.group_sale_salesman` for SO access).
|
||||
|
||||
---
|
||||
|
||||
@@ -146,7 +162,7 @@ These are Fusion Plating security groups layered on top of standard Odoo groups.
|
||||
|-------|------|-------------|
|
||||
| `name` | Char | e.g. "EN Mid-Phos AMS 2404" |
|
||||
| `process_type_id` | Many2one fusion.plating.process.type | Process type |
|
||||
| `recipe_id` | Many2one fusion.plating.process.node | Default recipe |
|
||||
| `recipe_id` | Many2one fusion.plating.process.node | Default recipe. **Domain: `[('node_type', '=', 'recipe')]`** |
|
||||
| `phosphorus_level` | Selection | low_phos, mid_phos, high_phos, na |
|
||||
| `thickness_min` | Float | Min thickness |
|
||||
| `thickness_max` | Float | Max thickness |
|
||||
@@ -164,6 +180,7 @@ These are Fusion Plating security groups layered on top of standard Odoo groups.
|
||||
| `name` | Char | e.g. "Bead Blast", "Zincate", "Bake" |
|
||||
| `treatment_type` | Selection | pre, post |
|
||||
| `default_duration_minutes` | Float | Estimated duration |
|
||||
| `currency_id` | Many2one res.currency | Company currency (default) |
|
||||
| `default_cost` | Monetary | Cost per application |
|
||||
|
||||
#### `fp.pricing.rule` — Formula-Based Pricing Engine
|
||||
@@ -175,9 +192,10 @@ These are Fusion Plating security groups layered on top of standard Odoo groups.
|
||||
| `substrate_material` | Selection | Optional filter |
|
||||
| `certification_level` | Selection | Optional filter |
|
||||
| `pricing_method` | Selection | per_sqin, per_sqft, per_piece, flat_rate, formula |
|
||||
| `currency_id` | Many2one res.currency | Company currency (default) |
|
||||
| `base_rate` | Monetary | $ per unit |
|
||||
| `thickness_factor` | Float | Multiplier per mil of thickness |
|
||||
| `complexity_surcharge` | Text/JSON | Mapping complexity → surcharge % |
|
||||
| `complexity_surcharge_ids` | One2many fp.pricing.complexity.surcharge | Surcharges by complexity level |
|
||||
| `masking_rate_per_zone` | Monetary | $ per masking area |
|
||||
| `setup_fee` | Monetary | One-time per batch |
|
||||
| `minimum_charge` | Monetary | Floor price |
|
||||
@@ -185,10 +203,22 @@ These are Fusion Plating security groups layered on top of standard Odoo groups.
|
||||
| `sequence` | Integer | Priority — first matching rule wins |
|
||||
| `active` | Boolean | |
|
||||
|
||||
#### `fp.quote.configurator` — The Configurator Session
|
||||
#### `fp.pricing.complexity.surcharge` — Complexity-Based Surcharge Line
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `rule_id` | Many2one fp.pricing.rule | Parent rule (cascade) |
|
||||
| `complexity` | Selection | simple, moderate, complex, very_complex |
|
||||
| `surcharge_percent` | Float | Surcharge % for this complexity level |
|
||||
|
||||
#### `fp.quote.configurator` — The Configurator Session (Persistent Model)
|
||||
|
||||
This is a `models.Model` (NOT transient). Records persist for audit trail, re-quoting, and linking back from sale orders. The SO links back via `x_fc_configurator_id`.
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | Char | Auto-sequence (CFG-00001) |
|
||||
| `state` | Selection | draft, confirmed, cancelled |
|
||||
| `partner_id` | Many2one res.partner | Customer |
|
||||
| `part_catalog_id` | Many2one fp.part.catalog | For repeat parts |
|
||||
| `coating_config_id` | Many2one fp.coating.config | Coating selection |
|
||||
@@ -197,17 +227,21 @@ These are Fusion Plating security groups layered on top of standard Odoo groups.
|
||||
| `surface_area` | Float | From catalog or entered |
|
||||
| `thickness_requested` | Float | |
|
||||
| `masking_zones` | Integer | |
|
||||
| `complexity` | Selection | |
|
||||
| `complexity` | Selection | simple, moderate, complex, very_complex |
|
||||
| `rush_order` | Boolean | |
|
||||
| `turnaround_days` | Integer | |
|
||||
| `delivery_method` | Selection | local_delivery, shipping_partner, customer_pickup |
|
||||
| `currency_id` | Many2one res.currency | Company currency (default) |
|
||||
| `shipping_fee` | Monetary | |
|
||||
| `delivery_fee` | Monetary | |
|
||||
| `calculated_price` | Monetary | Computed from pricing rules |
|
||||
| `price_breakdown_html` | Html | Rendered breakdown |
|
||||
| `estimator_override_price` | Monetary | Final price (defaults to calculated) |
|
||||
| `sale_order_id` | Many2one sale.order | Created SO (set on "Create Quotation") |
|
||||
| `notes` | Text | |
|
||||
|
||||
**Lifecycle:** draft → (estimator builds quote) → confirmed (when SO created) → cancelled (if abandoned). Confirmed records are read-only. Re-quoting creates a new configurator record.
|
||||
|
||||
### Price Calculation Flow
|
||||
|
||||
```
|
||||
@@ -258,7 +292,7 @@ Part Catalog (surface area, complexity, masking)
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | Char | Auto-sequence (RCV-00001) |
|
||||
| `sale_order_id` | Many2one sale.order | Required |
|
||||
| `sale_order_id` | Many2one sale.order | Required. **Design decision:** one receiving record per SO. If a customer ships parts for multiple SOs in one box, create separate receiving records per SO (receiver splits the count). This keeps the SO↔receiving link clean and avoids Many2many complexity. |
|
||||
| `partner_id` | Many2one res.partner | Related from SO |
|
||||
| `po_number` | Char | Related from SO x_fc_po_number |
|
||||
| `received_by_id` | Many2one res.users | Who logged it |
|
||||
@@ -344,13 +378,29 @@ SO Confirmed → Receiving record auto-created (state=draft)
|
||||
| `payment_term_id` | Many2one account.payment.term | |
|
||||
| `notes` | Text | |
|
||||
|
||||
### Auto-Population Rules
|
||||
|
||||
When a customer is selected on a new SO:
|
||||
1. Look up `fp.invoice.strategy.default` for that `partner_id`
|
||||
2. If found → auto-fill `x_fc_invoice_strategy` and `x_fc_deposit_percent` from the default
|
||||
3. If not found → leave blank (estimator must select manually)
|
||||
4. Estimator can always override per order
|
||||
|
||||
When a coating config is selected in the configurator:
|
||||
1. Auto-fill `thickness_requested` from `coating_config.thickness_min` (default to minimum)
|
||||
2. Auto-fill surface area UOM from company default setting
|
||||
|
||||
When a part catalog entry is selected:
|
||||
1. Auto-fill `surface_area`, `complexity`, `masking_zones`, `substrate_material` from the catalog entry
|
||||
2. These can be overridden per-quote if the part has changed
|
||||
|
||||
### Account Hold (extends `res.partner`)
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `x_fc_account_hold` | Boolean | Manually set by accounting |
|
||||
| `x_fc_account_hold_reason` | Text | Why hold was placed |
|
||||
| `x_fc_account_hold_date` | Date | When placed |
|
||||
| `x_fc_account_hold_date` | Datetime | When placed (Datetime for audit precision) |
|
||||
| `x_fc_account_hold_by_id` | Many2one res.users | Who placed it |
|
||||
|
||||
### Account Hold Behaviour
|
||||
@@ -460,11 +510,18 @@ Based on Fischerscope XDAL 600 output:
|
||||
- Operator, date/time
|
||||
- Data entry: manual for now, future Fischerscope CSV import
|
||||
|
||||
### Work Centre Mapping Note
|
||||
|
||||
The codebase has two work centre models: `fusion.plating.work.center` (core) and `mrp.workcenter` (standard MRP). Recipe nodes reference `fusion.plating.work.center`; MRP work orders use `mrp.workcenter`. The recipe-to-WO generation logic in `fusion_plating_bridge_mrp` must map between them. Each `fusion.plating.work.center` should have an `x_fc_mrp_workcenter_id` field linking to the corresponding `mrp.workcenter`. This mapping field should be added to the core module.
|
||||
|
||||
---
|
||||
|
||||
## 7. Certificate Registry — `fp.certificate`
|
||||
## 7. `fusion_plating_certificates` — Certificate Registry
|
||||
|
||||
Unified model logging every certificate issued.
|
||||
**Module owner:** `fusion_plating_certificates` (NEW dedicated module).
|
||||
**Dependencies:** `fusion_plating`, `fusion_plating_portal`, `fusion_plating_reports`, `mrp`
|
||||
|
||||
This module owns `fp.certificate` and `fp.thickness.reading`. It depends on `fusion_plating_portal` for the `fusion.plating.portal.job` link and on `fusion_plating_reports` for report generation.
|
||||
|
||||
### Model: `fp.certificate`
|
||||
|
||||
@@ -475,7 +532,7 @@ Unified model logging every certificate issued.
|
||||
| `partner_id` | Many2one res.partner | Customer |
|
||||
| `sale_order_id` | Many2one sale.order | |
|
||||
| `production_id` | Many2one mrp.production | |
|
||||
| `portal_job_id` | Many2one fp.portal.job | |
|
||||
| `portal_job_id` | Many2one fusion.plating.portal.job | Uses canonical model name |
|
||||
| `part_number` | Char | Denormalized for fast search |
|
||||
| `process_description` | Char | e.g. "ELECTROLESS NICKEL PLATING PER AMS 2404" |
|
||||
| `spec_reference` | Char | |
|
||||
@@ -491,9 +548,31 @@ Unified model logging every certificate issued.
|
||||
| `void_reason` | Text | |
|
||||
| `notes` | Html | |
|
||||
|
||||
### Model: `fp.thickness.reading` — Fischerscope Measurement Data
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `certificate_id` | Many2one fp.certificate | Parent certificate (cascade) |
|
||||
| `production_id` | Many2one mrp.production | Link to MO (independent of cert) |
|
||||
| `reading_number` | Integer | Reading sequence (n=1, n=2, n=3) |
|
||||
| `nip_mils` | Float(10,4) | NiP thickness in mils |
|
||||
| `ni_percent` | Float(6,3) | Nickel content % |
|
||||
| `p_percent` | Float(6,4) | Phosphorus content % |
|
||||
| `position_label` | Char | Where on the part this reading was taken |
|
||||
| `equipment_model` | Char | e.g. "Fischerscope XDAL 600" |
|
||||
| `product_ref` | Char | e.g. "2805031 / NiP/Al-alloys 2805030" |
|
||||
| `calibration_std_ref` | Char | e.g. "NiP/Al STD SET SN 100174568" |
|
||||
| `microscope_image_id` | Many2one ir.attachment | Microscope photo |
|
||||
| `operator_id` | Many2one res.users | Who took the reading |
|
||||
| `reading_datetime` | Datetime | When reading was taken |
|
||||
| `measuring_time_seconds` | Integer | e.g. 120 |
|
||||
|
||||
**Statistical fields** (computed from reading lines per certificate):
|
||||
- `mean_nip_mils`, `stddev_nip_mils`, `cov_percent`, `range_nip_mils` — computed on `fp.certificate` from its `thickness_reading_ids`
|
||||
|
||||
### Auto-Creation
|
||||
|
||||
When CoC or thickness report is generated, fp.certificate record auto-created with PDF attached.
|
||||
When CoC or thickness report is generated, `fp.certificate` record auto-created with PDF attached.
|
||||
|
||||
### Views
|
||||
|
||||
@@ -501,6 +580,10 @@ When CoC or thickness report is generated, fp.certificate record auto-created wi
|
||||
- **Search**: Quick filters by Customer, Certificate Type, Date Range, Part Number, PO Number. Group by: Customer, Type, Month, Issued By.
|
||||
- **Form**: Certificate type badge, state buttons (Issue/Void), customer info, part details, tabs for Thickness Readings, Attachments, Notes. "Regenerate PDF" and "Send to Customer" buttons.
|
||||
|
||||
### CoC Bilingual Implementation
|
||||
|
||||
The bilingual EN/FR certification statement uses QWeb template logic with `t-if` on a `bilingual` flag (default: True for Canadian compliance). The English and French text blocks are both rendered in the same template — not using Odoo's `ir.translation` system, since both languages must appear on the same document simultaneously.
|
||||
|
||||
---
|
||||
|
||||
## 8. `fusion_tasks` (Entech Plating) — Local Delivery Dispatch
|
||||
@@ -541,10 +624,10 @@ Renamed from `fusion.technician.task`.
|
||||
|-------|------|-------------|
|
||||
| `delivery_id` | Many2one fusion.plating.delivery | Links to logistics |
|
||||
| `sale_order_id` | Many2one sale.order | |
|
||||
| `portal_job_id` | Many2one fp.portal.job | |
|
||||
| `portal_job_id` | Many2one fusion.plating.portal.job | Uses canonical model name |
|
||||
| `partner_id` | Many2one res.partner | Customer |
|
||||
| `driver_id` | Many2one hr.employee | Renamed from technician_id |
|
||||
| `vehicle_id` | Many2one fusion.plating.vehicle | |
|
||||
| `vehicle_id` | Many2one fusion.plating.vehicle | From logistics module |
|
||||
| `packages_count` | Integer | Number of boxes/crates |
|
||||
| `weight_total` | Float | Total weight |
|
||||
| `requires_signature` | Boolean | POD required |
|
||||
@@ -555,12 +638,14 @@ Renamed from `fusion.technician.task`.
|
||||
- `action_mark_delivered()`: logs GPS + timestamp, captures signature/photo, updates fp.delivery → delivered, cascades to portal job → shipped, triggers shipment notification email
|
||||
- `action_mark_failed()`: logs reason, creates follow-up activity
|
||||
|
||||
### Dependencies
|
||||
### Dependencies & Deployment
|
||||
|
||||
```python
|
||||
'depends': ['base', 'mail', 'hr', 'fusion_plating_logistics'],
|
||||
```
|
||||
|
||||
**Deployment strategy:** `fusion_tasks` lives in a separate repo (`Entech Plating/`) but is deployed to the SAME server as the fusion_plating modules. Both repos are copied to `/mnt/extra-addons/custom/` on the target server. The `fusion_plating_logistics` dependency is therefore always available at install time. There is no standalone driver-only install scenario — drivers access the system via the same Odoo instance. The standalone "Delivery Dispatch" menu (below) provides a driver-focused view without needing a separate deployment.
|
||||
|
||||
### Menu Placement
|
||||
|
||||
Inside Fusion Plating: Shipping & Delivery → Local Delivery Tasks, Driver Map
|
||||
@@ -683,23 +768,29 @@ fusion_plating (core)
|
||||
│ └── depends: fusion_plating, sale_management
|
||||
├── fusion_plating_receiving
|
||||
│ └── depends: fusion_plating, sale_management
|
||||
│ └── provides: mrp.production gate mixin (overrides action_confirm)
|
||||
├── fusion_plating_invoicing
|
||||
│ └── depends: fusion_plating, sale_management, account
|
||||
│ └── provides: invoice strategy automation, account hold on res.partner
|
||||
├── fusion_plating_notifications
|
||||
│ └── depends: fusion_plating, fusion_plating_reports, mail
|
||||
├── fusion_plating_bridge_mrp
|
||||
│ └── depends: fusion_plating, fusion_plating_configurator,
|
||||
│ fusion_plating_receiving, fusion_plating_invoicing,
|
||||
│ mrp
|
||||
├── fusion_plating_certificates
|
||||
│ └── depends: fusion_plating, fusion_plating_portal,
|
||||
│ fusion_plating_reports, mrp
|
||||
├── fusion_plating_bridge_mrp (lighter — gates live in receiving/invoicing)
|
||||
│ └── depends: fusion_plating, fusion_plating_configurator, mrp
|
||||
│ └── soft-depends: fusion_plating_receiving, fusion_plating_invoicing
|
||||
├── fusion_plating_portal
|
||||
│ └── depends: fusion_plating, fusion_plating_configurator,
|
||||
│ fusion_plating_notifications, portal
|
||||
├── fusion_plating_logistics
|
||||
│ └── depends: fusion_plating
|
||||
└── fusion_tasks (Entech Plating — separate repo)
|
||||
└── fusion_tasks (Entech Plating — separate repo, same server)
|
||||
└── depends: fusion_plating_logistics, hr, mail
|
||||
```
|
||||
|
||||
**Note on bridge_mrp:** The receiving gate and invoice strategy gates are implemented as lightweight mixins within `fusion_plating_receiving` and `fusion_plating_invoicing` respectively (each overrides `mrp.production` independently). This avoids funnelling all dependencies through bridge_mrp. Bridge_mrp focuses on recipe-to-WO generation and the configurator link.
|
||||
|
||||
---
|
||||
|
||||
## 11. Pricing Variables Reference
|
||||
@@ -737,7 +828,20 @@ All 10 pricing variables that drive the configurator:
|
||||
|
||||
---
|
||||
|
||||
## 13. Roadmap Items (Not in Initial Build)
|
||||
## 13. Data Migration: Existing Quote Request Flow
|
||||
|
||||
The existing `fusion.plating.quote.request` model has an `action_create_sale_order()` method that creates basic SOs. The new configurator introduces a parallel, richer path.
|
||||
|
||||
**Coexistence strategy:**
|
||||
- The existing `action_create_sale_order()` on `fusion.plating.quote.request` remains functional — it is the "quick path" for simple quotes that don't need the full configurator
|
||||
- The new configurator is the "full path" for detailed quotes with part catalog, coating config, and pricing rules
|
||||
- When a quote request comes in via portal, the estimator chooses: use the configurator (creates `fp.quote.configurator` → SO) or use the quick path (existing `action_create_sale_order()`)
|
||||
- Both paths create SOs with `x_fc_*` fields. The quick path leaves configurator-specific fields blank; the full path populates everything
|
||||
- No existing data needs migration — the two paths coexist
|
||||
|
||||
---
|
||||
|
||||
## 14. Roadmap Items (Not in Initial Build)
|
||||
|
||||
- Claude Vision for PDF drawing measurement extraction
|
||||
- Auto account hold computed from invoice aging
|
||||
|
||||
Reference in New Issue
Block a user