docs: EN Tech end-to-end workflow design spec
Complete design covering 5 new modules + updates to existing: - fusion_plating_configurator (3D viewer, pricing engine, part catalog) - fusion_plating_receiving (inspection, damage logging, PO matching) - fusion_plating_invoicing (deposit/progress/net/COD, account holds) - fusion_plating_notifications (auto-email, certificate assembly) - fusion_tasks fork (local delivery dispatch, GPS tracking) Plus: sales integration, certificate registry, 9-stage workflow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,750 @@
|
|||||||
|
# EN Tech Plating — End-to-End Workflow Design Spec
|
||||||
|
|
||||||
|
**Date:** 2026-04-12
|
||||||
|
**Author:** Nexa Systems (Claude-assisted)
|
||||||
|
**Client:** EN Technologies (Electroless Nickel Technologies Inc.)
|
||||||
|
**Status:** Approved for implementation planning
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Overview
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
### Architecture: Approach 2 — Dedicated Modules per Sub-System
|
||||||
|
|
||||||
|
| Module | Purpose | Location |
|
||||||
|
|--------|---------|----------|
|
||||||
|
| `fusion_plating_configurator` | Quotation configurator, 3D viewer, pricing engine, part catalog | `fusion-plating/` |
|
||||||
|
| `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_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_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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Sales Integration — Fusion Plating as Single Hub
|
||||||
|
|
||||||
|
The Fusion Plating app becomes the single workspace. Users never leave it. Sale orders are managed with custom plating-specific views.
|
||||||
|
|
||||||
|
### Menu Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
Fusion Plating (app)
|
||||||
|
├── Sales (default landing)
|
||||||
|
│ ├── Quotations (sale.order, state=draft/sent)
|
||||||
|
│ ├── Sale Orders (sale.order, state=sale)
|
||||||
|
│ ├── Customers (res.partner, customer_rank > 0)
|
||||||
|
│ └── Part Catalog (fp.part.catalog)
|
||||||
|
├── Configurator
|
||||||
|
│ ├── New Quote (fp.quote.configurator wizard)
|
||||||
|
│ ├── Coating Configurations (fp.coating.config)
|
||||||
|
│ └── Pricing Rules (fp.pricing.rule)
|
||||||
|
├── Manufacturing
|
||||||
|
│ ├── Manufacturing Orders
|
||||||
|
│ ├── Work Orders
|
||||||
|
│ └── Plant Overview
|
||||||
|
├── Receiving & Inspection
|
||||||
|
├── Shipping & Delivery
|
||||||
|
│ ├── Deliveries (fp.delivery)
|
||||||
|
│ ├── Local Delivery Tasks (fusion.delivery.task)
|
||||||
|
│ └── Routes (fp.route)
|
||||||
|
├── Certificates
|
||||||
|
│ ├── All Certificates (fp.certificate)
|
||||||
|
│ ├── Certificates of Conformance (filtered: type=coc)
|
||||||
|
│ └── Thickness Reports (filtered: type=thickness_report)
|
||||||
|
├── Quality
|
||||||
|
├── Portal Jobs
|
||||||
|
├── Reports
|
||||||
|
└── Configuration
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sale Order Extensions (fields on `sale.order`)
|
||||||
|
|
||||||
|
- `x_fc_configurator_id` — link back to configurator session
|
||||||
|
- `x_fc_part_catalog_id` — customer part being ordered
|
||||||
|
- `x_fc_coating_config_id` — coating configuration
|
||||||
|
- `x_fc_po_number` — customer PO reference (Char)
|
||||||
|
- `x_fc_po_attachment_id` — uploaded PO document
|
||||||
|
- `x_fc_po_received` — Boolean
|
||||||
|
- `x_fc_po_override` — Boolean (manager override — proceed without PO)
|
||||||
|
- `x_fc_po_override_reason` — Text
|
||||||
|
- `x_fc_invoice_strategy` — Selection (deposit, progress, net_terms, cod_prepay)
|
||||||
|
- `x_fc_deposit_percent` — Float
|
||||||
|
- `x_fc_rush_order` — Boolean
|
||||||
|
- `x_fc_delivery_method` — Selection (local_delivery, shipping_partner, customer_pickup)
|
||||||
|
- `x_fc_receiving_status` — Selection (not_received, partial, received, inspected) — computed
|
||||||
|
- Smart buttons: Portal Job, Manufacturing Order, Delivery, Receiving, Invoices, Certificates
|
||||||
|
|
||||||
|
### Custom Sale Order Views
|
||||||
|
|
||||||
|
- **List**: Customer, PO#, Part, Coating, Qty, Total, Receiving Status, Job Status, Delivery Method
|
||||||
|
- **Form**: inherits sale.order form, adds plating tabs (Part Details, Coating Config, Receiving, Job Tracking)
|
||||||
|
- **Kanban**: cards grouped by stage (Draft → Quoted → PO Received → Parts Received → In Production → Shipped → Invoiced)
|
||||||
|
|
||||||
|
### 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 |
|
||||||
|
|
||||||
|
These are Fusion Plating security groups layered on top of standard Odoo groups.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. `fusion_plating_configurator` — Quotation Configurator & Pricing Engine
|
||||||
|
|
||||||
|
### Users
|
||||||
|
|
||||||
|
- **Primary:** Internal estimator (full control, detailed configurator, price override)
|
||||||
|
- **Secondary:** Portal customer (simplified self-service, estimated pricing, 3D preview, lead gen)
|
||||||
|
|
||||||
|
### Core Models
|
||||||
|
|
||||||
|
#### `fp.part.catalog` — Customer Part Library
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `partner_id` | Many2one res.partner | Customer (required) |
|
||||||
|
| `name` | Char | Part name/description |
|
||||||
|
| `part_number` | Char | Customer's part number |
|
||||||
|
| `revision` | Char | Revision letter/number |
|
||||||
|
| `substrate_material` | Selection | aluminium, steel, stainless, copper, titanium, other |
|
||||||
|
| `geometry_source` | Selection | 3d_model, manual, pdf_drawing |
|
||||||
|
| `model_attachment_id` | Many2one ir.attachment | STEP/STL/IGES file |
|
||||||
|
| `drawing_attachment_ids` | Many2many ir.attachment | PDF drawings |
|
||||||
|
| `surface_area` | Float | Surface area value |
|
||||||
|
| `surface_area_uom` | Selection | sq_in, sq_ft, sq_cm, sq_m |
|
||||||
|
| `weight` | Float | For shipping cost calc |
|
||||||
|
| `dimensions_length` | Float | Manual measurement |
|
||||||
|
| `dimensions_width` | Float | Manual measurement |
|
||||||
|
| `dimensions_height` | Float | Manual measurement |
|
||||||
|
| `complexity` | Selection | simple, moderate, complex, very_complex |
|
||||||
|
| `masking_zones` | Integer | Number of areas requiring masking |
|
||||||
|
| `masking_description` | Text | e.g. "mask threaded holes" |
|
||||||
|
| `has_blind_holes` | Boolean | Complexity flag |
|
||||||
|
| `has_recesses` | Boolean | Complexity flag |
|
||||||
|
| `has_threads` | Boolean | Complexity flag |
|
||||||
|
| `notes` | Html | |
|
||||||
|
| `active` | Boolean | Archivable |
|
||||||
|
|
||||||
|
#### `fp.coating.config` — Coating Configuration Template
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `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 |
|
||||||
|
| `phosphorus_level` | Selection | low_phos, mid_phos, high_phos, na |
|
||||||
|
| `thickness_min` | Float | Min thickness |
|
||||||
|
| `thickness_max` | Float | Max thickness |
|
||||||
|
| `thickness_uom` | Selection | mils, microns, inches |
|
||||||
|
| `spec_reference` | Char | e.g. "AMS 2404" |
|
||||||
|
| `certification_level` | Selection | commercial, mil_spec, nadcap, nuclear |
|
||||||
|
| `pre_treatment_ids` | Many2many fp.treatment | Bead blast, zincate, etc. |
|
||||||
|
| `post_treatment_ids` | Many2many fp.treatment | Bake, passivate, chromate, etc. |
|
||||||
|
| `active` | Boolean | |
|
||||||
|
|
||||||
|
#### `fp.treatment` — Pre/Post Treatment
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `name` | Char | e.g. "Bead Blast", "Zincate", "Bake" |
|
||||||
|
| `treatment_type` | Selection | pre, post |
|
||||||
|
| `default_duration_minutes` | Float | Estimated duration |
|
||||||
|
| `default_cost` | Monetary | Cost per application |
|
||||||
|
|
||||||
|
#### `fp.pricing.rule` — Formula-Based Pricing Engine
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `name` | Char | Rule description |
|
||||||
|
| `coating_config_id` | Many2one fp.coating.config | Optional filter (global if blank) |
|
||||||
|
| `substrate_material` | Selection | Optional filter |
|
||||||
|
| `certification_level` | Selection | Optional filter |
|
||||||
|
| `pricing_method` | Selection | per_sqin, per_sqft, per_piece, flat_rate, formula |
|
||||||
|
| `base_rate` | Monetary | $ per unit |
|
||||||
|
| `thickness_factor` | Float | Multiplier per mil of thickness |
|
||||||
|
| `complexity_surcharge` | Text/JSON | Mapping complexity → surcharge % |
|
||||||
|
| `masking_rate_per_zone` | Monetary | $ per masking area |
|
||||||
|
| `setup_fee` | Monetary | One-time per batch |
|
||||||
|
| `minimum_charge` | Monetary | Floor price |
|
||||||
|
| `rush_surcharge_percent` | Float | Rush premium % |
|
||||||
|
| `sequence` | Integer | Priority — first matching rule wins |
|
||||||
|
| `active` | Boolean | |
|
||||||
|
|
||||||
|
#### `fp.quote.configurator` — The Configurator Session
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `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 |
|
||||||
|
| `quantity` | Integer | Number of parts |
|
||||||
|
| `batch_size` | Integer | Parts per rack/barrel |
|
||||||
|
| `surface_area` | Float | From catalog or entered |
|
||||||
|
| `thickness_requested` | Float | |
|
||||||
|
| `masking_zones` | Integer | |
|
||||||
|
| `complexity` | Selection | |
|
||||||
|
| `rush_order` | Boolean | |
|
||||||
|
| `turnaround_days` | Integer | |
|
||||||
|
| `delivery_method` | Selection | local_delivery, shipping_partner, customer_pickup |
|
||||||
|
| `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) |
|
||||||
|
| `notes` | Text | |
|
||||||
|
|
||||||
|
### Price Calculation Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Part Catalog (surface area, complexity, masking)
|
||||||
|
+ Coating Config (process, thickness, spec level)
|
||||||
|
+ Pricing Rules (matched by coating + substrate + cert level)
|
||||||
|
+ Quantity / Batch Size
|
||||||
|
+ Rush surcharge (if applicable)
|
||||||
|
+ Delivery / Shipping fees
|
||||||
|
= Calculated Price
|
||||||
|
→ Estimator reviews & overrides if needed
|
||||||
|
→ Final quote price
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3D Viewer
|
||||||
|
|
||||||
|
- OWL component using **Three.js** for STL rendering and **OCCT (OpenCascade) WASM** for STEP parsing
|
||||||
|
- Renders on both backend configurator form and portal page
|
||||||
|
- Features: wireframe/solid toggle, rotate/zoom, surface area highlight
|
||||||
|
- Server-side surface area calculation: Python `trimesh` (STL) / `cadquery`/`OCP` (STEP)
|
||||||
|
- Fallback: manual measurements if server can't parse the file
|
||||||
|
- Roadmap: Claude Vision for PDF drawing measurement extraction
|
||||||
|
|
||||||
|
### Portal Side (Customer-Facing)
|
||||||
|
|
||||||
|
- Simplified wizard: upload part → select coating type → see estimated price range
|
||||||
|
- Uses same `fp.quote.configurator` model with restricted fields
|
||||||
|
- Customer sees estimated price range (not exact), 3D preview
|
||||||
|
- Submits → creates `fp.quote.request` with configurator data attached
|
||||||
|
- Internal estimator sees customer's config and refines it
|
||||||
|
|
||||||
|
### Configurator → Sale Order Flow
|
||||||
|
|
||||||
|
1. Estimator opens Configurator → builds quote
|
||||||
|
2. Clicks "Create Quotation" → sale.order created with all x_fc_* fields
|
||||||
|
3. SO line(s) auto-created (product = service product per coating type, qty, price = estimator's final price)
|
||||||
|
4. Estimator reviews SO → sends quotation
|
||||||
|
5. Customer accepts → confirms SO → triggers downstream flow
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. `fusion_plating_receiving` — Parts Receiving & Inspection
|
||||||
|
|
||||||
|
### Core Models
|
||||||
|
|
||||||
|
#### `fp.receiving` — Receiving Record
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `name` | Char | Auto-sequence (RCV-00001) |
|
||||||
|
| `sale_order_id` | Many2one sale.order | Required |
|
||||||
|
| `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 |
|
||||||
|
| `received_date` | Datetime | Default=now |
|
||||||
|
| `state` | Selection | draft, inspecting, accepted, discrepancy, resolved |
|
||||||
|
| `expected_qty` | Integer | From SO line |
|
||||||
|
| `received_qty` | Integer | Entered by receiver |
|
||||||
|
| `qty_match` | Boolean | Computed: received == expected |
|
||||||
|
| `carrier_name` | Char | Who delivered |
|
||||||
|
| `carrier_tracking` | Char | Inbound tracking # |
|
||||||
|
| `notes` | Html | |
|
||||||
|
| `line_ids` | One2many fp.receiving.line | Per-part detail |
|
||||||
|
| `damage_ids` | One2many fp.receiving.damage | Damage log |
|
||||||
|
| `attachment_ids` | Many2many ir.attachment | Photos |
|
||||||
|
|
||||||
|
#### `fp.receiving.line` — Per-Part Receiving Detail
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `receiving_id` | Many2one fp.receiving | Cascade |
|
||||||
|
| `part_catalog_id` | Many2one fp.part.catalog | Optional |
|
||||||
|
| `part_number` | Char | |
|
||||||
|
| `description` | Char | |
|
||||||
|
| `expected_qty` | Integer | |
|
||||||
|
| `received_qty` | Integer | |
|
||||||
|
| `condition` | Selection | good, damaged, mixed |
|
||||||
|
| `notes` | Text | |
|
||||||
|
|
||||||
|
#### `fp.receiving.damage` — Damage Log Entry
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `receiving_id` | Many2one fp.receiving | Cascade |
|
||||||
|
| `description` | Text | What's damaged |
|
||||||
|
| `severity` | Selection | cosmetic, functional, rejected |
|
||||||
|
| `photo_ids` | Many2many ir.attachment | |
|
||||||
|
| `action_required` | Selection | none, notify_customer, return_parts, proceed_as_is |
|
||||||
|
| `customer_notified` | Boolean | |
|
||||||
|
| `customer_response` | Text | |
|
||||||
|
| `resolved` | Boolean | |
|
||||||
|
|
||||||
|
### Workflow
|
||||||
|
|
||||||
|
```
|
||||||
|
SO Confirmed → Receiving record auto-created (state=draft)
|
||||||
|
→ Parts arrive → receiver enters qty, inspects condition
|
||||||
|
→ Match + good → state=accepted
|
||||||
|
→ Mismatch or damage → state=discrepancy
|
||||||
|
→ SO flagged, follow-up activity created
|
||||||
|
→ Customer contacted → resolution logged → state=resolved
|
||||||
|
→ Accepted/Resolved → SO x_fc_receiving_status = 'received'
|
||||||
|
→ Manufacturing can proceed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manufacturing Gate
|
||||||
|
|
||||||
|
- `mrp.production.action_confirm()` checks `sale_order.x_fc_receiving_status`
|
||||||
|
- If not received → warning dialog (manager can override)
|
||||||
|
- Soft gate — warns, doesn't hard-block (flexibility for handshake deals, urgent jobs)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. `fusion_plating_invoicing` — Invoice Strategy Engine
|
||||||
|
|
||||||
|
### Invoice Strategies
|
||||||
|
|
||||||
|
| Strategy | Behaviour |
|
||||||
|
|----------|-----------|
|
||||||
|
| `deposit` | Deposit invoice for X% on SO confirmation. Balance after shipping. |
|
||||||
|
| `progress` | Invoice per MO as each completes. |
|
||||||
|
| `net_terms` | Single invoice after shipping. Payment on terms. |
|
||||||
|
| `cod_prepay` | Full invoice on SO confirmation. Manufacturing blocked until paid. |
|
||||||
|
|
||||||
|
### Core Models
|
||||||
|
|
||||||
|
#### `fp.invoice.strategy.default` — Customer-Level Default
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `partner_id` | Many2one res.partner | Unique per customer |
|
||||||
|
| `default_strategy` | Selection | deposit, progress, net_terms, cod_prepay |
|
||||||
|
| `default_deposit_percent` | Float | e.g. 50.0 |
|
||||||
|
| `payment_term_id` | Many2one account.payment.term | |
|
||||||
|
| `notes` | Text | |
|
||||||
|
|
||||||
|
### 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_by_id` | Many2one res.users | Who placed it |
|
||||||
|
|
||||||
|
### Account Hold Behaviour
|
||||||
|
|
||||||
|
| Action | Hold Active | Result |
|
||||||
|
|--------|-------------|--------|
|
||||||
|
| Create new SO | Yes | Warning banner. SO can still be created. |
|
||||||
|
| Confirm SO | Yes | Blocked. Manager override available. |
|
||||||
|
| Create invoice | Yes | Blocked. Manager override available. |
|
||||||
|
| Ship / mark delivered | Yes | Blocked. Manager override available. |
|
||||||
|
| Customer visits portal | Yes | No visible indication. |
|
||||||
|
|
||||||
|
Roadmap: auto-hold computed from account.move aging.
|
||||||
|
|
||||||
|
### Invoice Automation
|
||||||
|
|
||||||
|
- **Deposit:** SO confirmed → auto-create deposit invoice (X%) → balance invoice after shipping
|
||||||
|
- **Progress:** Each MO done → invoice for that MO's portion → final invoice for remaining balance
|
||||||
|
- **Net terms:** Delivery complete → auto-create full invoice → payment terms applied
|
||||||
|
- **COD/Prepay:** SO confirmed → auto-create full invoice → MO blocked until payment reconciled
|
||||||
|
|
||||||
|
### Shipping Method Price Adjustment
|
||||||
|
|
||||||
|
- Method changes after invoicing:
|
||||||
|
- Draft invoice → amend the line
|
||||||
|
- Posted invoice → supplementary invoice or credit note
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. `fusion_plating_notifications` — Auto-Email Engine
|
||||||
|
|
||||||
|
### Notification Triggers
|
||||||
|
|
||||||
|
| Trigger Event | Email Name | Attachments | Recipient |
|
||||||
|
|---------------|-----------|-------------|-----------|
|
||||||
|
| Quotation sent | Quote Ready | Quote PDF | Customer contact |
|
||||||
|
| SO confirmed | Order Confirmation | SO PDF | Customer contact |
|
||||||
|
| Parts received | Parts Received | — | Customer contact |
|
||||||
|
| MO complete | Ready for Pickup/Ship | — | Customer contact |
|
||||||
|
| Delivery shipped (carrier) | Shipment Notification | CoC, Thickness Report, Invoice | Customer contact |
|
||||||
|
| Delivery completed (local) | Delivery Confirmation | CoC, Thickness Report, Invoice, POD | Customer contact |
|
||||||
|
| Invoice posted | Invoice Notification | Invoice PDF | Billing contact |
|
||||||
|
| Deposit invoice created | Deposit Required | Deposit Invoice PDF | Billing contact |
|
||||||
|
|
||||||
|
### Core Models
|
||||||
|
|
||||||
|
#### `fp.notification.template` — Configurable Email Templates
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `name` | Char | Template name |
|
||||||
|
| `trigger_event` | Selection | Event type |
|
||||||
|
| `mail_template_id` | Many2one mail.template | Actual Odoo template |
|
||||||
|
| `active` | Boolean | Can disable specific notifications |
|
||||||
|
| `attach_coc` | Boolean | |
|
||||||
|
| `attach_thickness_report` | Boolean | |
|
||||||
|
| `attach_invoice` | Boolean | |
|
||||||
|
| `attach_packing_list` | Boolean | |
|
||||||
|
| `attach_pod` | Boolean | |
|
||||||
|
| `cc_internal_ids` | Many2many res.users | Internal CCs |
|
||||||
|
|
||||||
|
#### `fp.notification.log` — Audit Trail
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `template_id` | Many2one fp.notification.template | |
|
||||||
|
| `trigger_event` | Selection | |
|
||||||
|
| `sale_order_id` | Many2one sale.order | |
|
||||||
|
| `partner_id` | Many2one res.partner | |
|
||||||
|
| `sent_date` | Datetime | |
|
||||||
|
| `recipient_email` | Char | |
|
||||||
|
| `attachment_names` | Text | Comma-separated list |
|
||||||
|
| `status` | Selection | sent, failed, bounced |
|
||||||
|
| `error_message` | Text | |
|
||||||
|
| `mail_mail_id` | Many2one mail.mail | |
|
||||||
|
|
||||||
|
### Document Assembly (Shipment Email)
|
||||||
|
|
||||||
|
1. Find portal job linked to SO/MO
|
||||||
|
2. Generate CoC PDF (bilingual EN/FR, customer logo, Nadcap badge if applicable)
|
||||||
|
3. Attach thickness report if available
|
||||||
|
4. Attach invoice PDF
|
||||||
|
5. Include tracking info in email body (carrier tracking # or driver ETA)
|
||||||
|
6. Send to customer contact
|
||||||
|
7. Log in fp.notification.log
|
||||||
|
|
||||||
|
### CoC Report Updates
|
||||||
|
|
||||||
|
- Customer logo placement (from partner.image_1920)
|
||||||
|
- Nadcap badge (conditional)
|
||||||
|
- EN Tech branding (replace Steelhead)
|
||||||
|
- Recorded thickness field
|
||||||
|
- Process description with spec references
|
||||||
|
- Bilingual certification statement
|
||||||
|
- Quantities: Shipped/Exp, NC Qty columns
|
||||||
|
- Configurable certifying authority signature
|
||||||
|
|
||||||
|
### Thickness / Measurement Report (NEW template)
|
||||||
|
|
||||||
|
Based on Fischerscope XDAL 600 output:
|
||||||
|
- EN Tech header
|
||||||
|
- Equipment info (model, product, application)
|
||||||
|
- Microscope image (attached photo)
|
||||||
|
- Reading data table (NiP mils, Ni %, P %)
|
||||||
|
- Statistical summary (Mean, Std Dev, CoV%, Range)
|
||||||
|
- Calibration standard reference
|
||||||
|
- Operator, date/time
|
||||||
|
- Data entry: manual for now, future Fischerscope CSV import
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Certificate Registry — `fp.certificate`
|
||||||
|
|
||||||
|
Unified model logging every certificate issued.
|
||||||
|
|
||||||
|
### Model: `fp.certificate`
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `name` | Char | Auto-sequence (CERT-00001) |
|
||||||
|
| `certificate_type` | Selection | coc, thickness_report, mill_test, nadcap_cert, customer_specific |
|
||||||
|
| `partner_id` | Many2one res.partner | Customer |
|
||||||
|
| `sale_order_id` | Many2one sale.order | |
|
||||||
|
| `production_id` | Many2one mrp.production | |
|
||||||
|
| `portal_job_id` | Many2one fp.portal.job | |
|
||||||
|
| `part_number` | Char | Denormalized for fast search |
|
||||||
|
| `process_description` | Char | e.g. "ELECTROLESS NICKEL PLATING PER AMS 2404" |
|
||||||
|
| `spec_reference` | Char | |
|
||||||
|
| `po_number` | Char | Customer PO ref |
|
||||||
|
| `entech_wo_number` | Char | Internal WO # |
|
||||||
|
| `quantity_shipped` | Integer | |
|
||||||
|
| `issued_by_id` | Many2one res.users | |
|
||||||
|
| `certified_by_id` | Many2one res.users | Signing authority |
|
||||||
|
| `issue_date` | Date | Default=today |
|
||||||
|
| `attachment_id` | Many2one ir.attachment | Generated PDF |
|
||||||
|
| `thickness_reading_ids` | One2many fp.thickness.reading | Linked measurements |
|
||||||
|
| `state` | Selection | draft, issued, voided |
|
||||||
|
| `void_reason` | Text | |
|
||||||
|
| `notes` | Html | |
|
||||||
|
|
||||||
|
### Auto-Creation
|
||||||
|
|
||||||
|
When CoC or thickness report is generated, fp.certificate record auto-created with PDF attached.
|
||||||
|
|
||||||
|
### Views
|
||||||
|
|
||||||
|
- **List** (default, newest first): Issue Date, Cert #, Type, Customer, Part #, PO #, Entech WO#, Process, Qty, Issued By, Status
|
||||||
|
- **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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. `fusion_tasks` (Entech Plating) — Local Delivery Dispatch
|
||||||
|
|
||||||
|
### Fork & Strip Strategy
|
||||||
|
|
||||||
|
**Remove:**
|
||||||
|
- Cross-instance sync (fusion.task.sync.config, shadow tasks)
|
||||||
|
- `fusion_claims.*` config parameters → rename to `fusion_tasks.*`
|
||||||
|
- `sales_team` dependency
|
||||||
|
- Irrelevant task types (repair, troubleshoot, assessment, ltc_visit, maintenance, installation)
|
||||||
|
- All sync-related fields (x_fc_sync_*)
|
||||||
|
|
||||||
|
**Keep:**
|
||||||
|
- Google Maps integration (Leaflet.js map view)
|
||||||
|
- GPS tracking (fusion.technician.location → fusion.driver.location)
|
||||||
|
- Geocoding (_geocode_address())
|
||||||
|
- Route planning / scheduling / conflict avoidance
|
||||||
|
- Push notifications (fusion.push.subscription)
|
||||||
|
- Map view JS/SCSS/XML
|
||||||
|
|
||||||
|
### Adapted Model: `fusion.delivery.task`
|
||||||
|
|
||||||
|
Renamed from `fusion.technician.task`.
|
||||||
|
|
||||||
|
**Task Types** (reduced):
|
||||||
|
- `delivery` — outbound delivery
|
||||||
|
- `pickup` — collect parts from customer
|
||||||
|
- `return` — return rejected/damaged parts
|
||||||
|
- `rush` — same-day urgent
|
||||||
|
|
||||||
|
**Status Workflow:**
|
||||||
|
- `pending` → `scheduled` → `en_route` → `delivered` (or `failed`)
|
||||||
|
|
||||||
|
**Key Fields:**
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `delivery_id` | Many2one fusion.plating.delivery | Links to logistics |
|
||||||
|
| `sale_order_id` | Many2one sale.order | |
|
||||||
|
| `portal_job_id` | Many2one fp.portal.job | |
|
||||||
|
| `partner_id` | Many2one res.partner | Customer |
|
||||||
|
| `driver_id` | Many2one hr.employee | Renamed from technician_id |
|
||||||
|
| `vehicle_id` | Many2one fusion.plating.vehicle | |
|
||||||
|
| `packages_count` | Integer | Number of boxes/crates |
|
||||||
|
| `weight_total` | Float | Total weight |
|
||||||
|
| `requires_signature` | Boolean | POD required |
|
||||||
|
| `requires_photo` | Boolean | Photo proof required |
|
||||||
|
| `coc_attachment_id` | Many2one ir.attachment | CoC to hand to customer |
|
||||||
|
|
||||||
|
**Delivery Integration:**
|
||||||
|
- `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
|
||||||
|
|
||||||
|
```python
|
||||||
|
'depends': ['base', 'mail', 'hr', 'fusion_plating_logistics'],
|
||||||
|
```
|
||||||
|
|
||||||
|
### Menu Placement
|
||||||
|
|
||||||
|
Inside Fusion Plating: Shipping & Delivery → Local Delivery Tasks, Driver Map
|
||||||
|
|
||||||
|
Standalone (optional): Delivery Dispatch app for drivers.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Complete End-to-End Workflow
|
||||||
|
|
||||||
|
### Stage 1: Customer Inquiry
|
||||||
|
|
||||||
|
- **Portal path:** Customer uploads 3D/PDF on portal → sees estimated price → submits → fp.quote.request created
|
||||||
|
- **Email/phone path:** Estimator creates fp.quote.request manually, uploads customer's files
|
||||||
|
- **Modules:** fusion_plating_portal, fusion_plating_configurator
|
||||||
|
|
||||||
|
### Stage 2: Quotation
|
||||||
|
|
||||||
|
- Estimator opens Configurator inside Fusion Plating app
|
||||||
|
- Selects/creates part in Part Catalog
|
||||||
|
- 3D model → auto surface area + 3D preview; PDF → manual measurements
|
||||||
|
- Selects Coating Configuration
|
||||||
|
- Pricing engine calculates from rules; estimator reviews/overrides
|
||||||
|
- Adds delivery/shipping fees, sets invoice strategy
|
||||||
|
- "Create Quotation" → sale.order with all x_fc_* fields
|
||||||
|
- Sends quotation → email notification with Quote PDF
|
||||||
|
- **Modules:** fusion_plating_configurator, fusion_plating_notifications
|
||||||
|
|
||||||
|
### Stage 3: Order Confirmation
|
||||||
|
|
||||||
|
- Customer accepts + submits PO (email or portal)
|
||||||
|
- PO number entered on SO, PO document uploaded (or manager override for handshake deals)
|
||||||
|
- SO confirmed:
|
||||||
|
- Account hold check → blocked if hold active (manager override)
|
||||||
|
- Invoice strategy fires (deposit/COD → auto-invoice; net_terms/progress → no invoice yet)
|
||||||
|
- Email: Order Confirmation + SO PDF
|
||||||
|
- Receiving record auto-created (draft)
|
||||||
|
- Portal job auto-created (received)
|
||||||
|
- **Modules:** fusion_plating_invoicing, fusion_plating_receiving, fusion_plating_bridge_mrp, fusion_plating_notifications
|
||||||
|
|
||||||
|
### Stage 4: Parts Receiving
|
||||||
|
|
||||||
|
- Parts arrive → receiver opens receiving record
|
||||||
|
- Counts parts, inspects condition
|
||||||
|
- Good → accepted; damage/mismatch → discrepancy → follow-up → resolved
|
||||||
|
- Email: Parts Received
|
||||||
|
- Portal job → in_progress
|
||||||
|
- **Modules:** fusion_plating_receiving, fusion_plating_notifications
|
||||||
|
|
||||||
|
### Stage 5: Manufacturing Planning
|
||||||
|
|
||||||
|
- MO created from SO (standard sale_mrp)
|
||||||
|
- Receiving gate: warns if parts not received
|
||||||
|
- COD gate: warns if prepay not paid
|
||||||
|
- Planner assigns recipe, configures opt-in/out steps
|
||||||
|
- Recipe → Work Orders generated (one WO per operation node, steps = WO instructions)
|
||||||
|
- **Modules:** fusion_plating_bridge_mrp
|
||||||
|
|
||||||
|
### Stage 6: Manufacturing Execution
|
||||||
|
|
||||||
|
- Operators work WOs on shopfloor (Plant Overview kanban, timers, bath/tank assignment)
|
||||||
|
- Quality holds if needed
|
||||||
|
- All WOs done → MO done:
|
||||||
|
- Portal job → ready_to_ship
|
||||||
|
- fp.delivery auto-created (draft)
|
||||||
|
- Thickness readings entered
|
||||||
|
- CoC + thickness report generated → fp.certificate records created
|
||||||
|
- Progress invoicing: if strategy=progress, invoice this MO's portion
|
||||||
|
- **Modules:** fusion_plating_shopfloor, fusion_plating_bridge_mrp, fusion_plating_quality, fusion_plating_invoicing
|
||||||
|
|
||||||
|
### Stage 7: Shipping / Local Delivery
|
||||||
|
|
||||||
|
**Shipping Partner (Purolator, FedEx, UPS, etc.):**
|
||||||
|
- fp.delivery scheduled with carrier + tracking #
|
||||||
|
- Packing list generated, delivery marked shipped
|
||||||
|
- Module: fusion_plating_logistics
|
||||||
|
|
||||||
|
**Local Delivery (EN Tech driver):**
|
||||||
|
- fusion.delivery.task created, driver + vehicle assigned
|
||||||
|
- Driver Map shows live GPS tracking
|
||||||
|
- Driver delivers → signature/photo POD → cascades to fp.delivery
|
||||||
|
- Module: fusion_tasks (Entech Plating)
|
||||||
|
|
||||||
|
**Customer Pickup:**
|
||||||
|
- Email: Ready for Pickup
|
||||||
|
- Customer arrives → parts released → signature → fp.delivery marked delivered
|
||||||
|
|
||||||
|
**All paths:**
|
||||||
|
- Portal job → shipped
|
||||||
|
- Email: CoC + Thickness Report + Invoice + Tracking/ETA
|
||||||
|
- **Modules:** fusion_plating_logistics, fusion_tasks, fusion_plating_notifications
|
||||||
|
|
||||||
|
### Stage 8: Invoicing & Payment
|
||||||
|
|
||||||
|
- Strategy determines timing:
|
||||||
|
- deposit → balance invoice after shipping
|
||||||
|
- progress → final invoice for remaining balance
|
||||||
|
- net_terms → full invoice after shipping
|
||||||
|
- cod_prepay → already invoiced & paid
|
||||||
|
- Delivery method change after invoice → supplementary invoice or credit note
|
||||||
|
- Invoice posted → portal job → complete → email with Invoice PDF
|
||||||
|
- **Modules:** fusion_plating_invoicing, fusion_plating_bridge_mrp, fusion_plating_notifications
|
||||||
|
|
||||||
|
### Stage 9: Customer Portal
|
||||||
|
|
||||||
|
- Full job lifecycle visible: progress bar (received → complete)
|
||||||
|
- Documents tab: CoC, thickness report, invoice — downloadable
|
||||||
|
- Part catalog: saved parts with 3D preview
|
||||||
|
- Order history: past orders, re-order from catalog
|
||||||
|
- Quote request history, tracking info, notification history
|
||||||
|
- **Modules:** fusion_plating_portal
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Module Dependency Graph
|
||||||
|
|
||||||
|
```
|
||||||
|
fusion_plating (core)
|
||||||
|
├── fusion_plating_configurator
|
||||||
|
│ └── depends: fusion_plating, sale_management
|
||||||
|
├── fusion_plating_receiving
|
||||||
|
│ └── depends: fusion_plating, sale_management
|
||||||
|
├── fusion_plating_invoicing
|
||||||
|
│ └── depends: fusion_plating, sale_management, account
|
||||||
|
├── 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_portal
|
||||||
|
│ └── depends: fusion_plating, fusion_plating_configurator,
|
||||||
|
│ fusion_plating_notifications, portal
|
||||||
|
├── fusion_plating_logistics
|
||||||
|
│ └── depends: fusion_plating
|
||||||
|
└── fusion_tasks (Entech Plating — separate repo)
|
||||||
|
└── depends: fusion_plating_logistics, hr, mail
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Pricing Variables Reference
|
||||||
|
|
||||||
|
All 10 pricing variables that drive the configurator:
|
||||||
|
|
||||||
|
1. **Surface area** — more area = more chemistry consumed
|
||||||
|
2. **Coating type** — EN, chrome, anodize, black oxide (different bath costs)
|
||||||
|
3. **Thickness spec** — more passes/dwell time
|
||||||
|
4. **Substrate material** — aluminium needs zincate pre-treatment
|
||||||
|
5. **Quantity / batch size** — more parts per rack = lower per-unit cost
|
||||||
|
6. **Part complexity** — blind holes, recesses, masking areas
|
||||||
|
7. **Masking requirements** — labour-intensive
|
||||||
|
8. **Spec / certification level** — Nadcap/aerospace = more QC overhead
|
||||||
|
9. **Turnaround time** — rush = premium
|
||||||
|
10. **Pre/post treatment** — bead blast, bake, passivate
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Key Architectural Decisions
|
||||||
|
|
||||||
|
| Decision | Resolution |
|
||||||
|
|----------|------------|
|
||||||
|
| Configurator primary user | Internal estimator; portal is simplified lead-gen |
|
||||||
|
| 3D file handling | STEP/STL auto surface area calc + 3D preview; PDF manual (Claude Vision roadmap) |
|
||||||
|
| Pricing model | Formula-calculated with estimator override |
|
||||||
|
| Part catalog | Customer part library for repeat business + one-off support |
|
||||||
|
| PO requirement | Required before manufacturing, but manager override available |
|
||||||
|
| Invoice strategies | All 4 supported (deposit, progress, net_terms, cod_prepay), configurable per order |
|
||||||
|
| Account hold | Manual for now, auto from aging on roadmap |
|
||||||
|
| Shipping decision | Set at quote time, changeable later with price adjustment |
|
||||||
|
| Local delivery | Fork fusion_tasks, strip claims, keep GPS/maps |
|
||||||
|
| Certificate management | Unified fp.certificate registry with filters, auto-creation on report generation |
|
||||||
|
| Recipe → WO mapping | One WO per operation node, steps become WO instructions |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Roadmap Items (Not in Initial Build)
|
||||||
|
|
||||||
|
- Claude Vision for PDF drawing measurement extraction
|
||||||
|
- Auto account hold computed from invoice aging
|
||||||
|
- Fischerscope CSV import (auto-populate thickness readings)
|
||||||
|
- Multi-driver route optimization
|
||||||
|
- Customer-specific certificate templates
|
||||||
|
- Product configurator on portal (dynamic pricing preview)
|
||||||
|
- Tags on recipe nodes
|
||||||
|
- Dashboard transitions on recipe nodes
|
||||||
|
- Treatment groups / choices on recipe nodes
|
||||||
Reference in New Issue
Block a user