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:
gsinghpal
2026-04-12 17:57:56 -04:00
parent 2b84c31a12
commit f69b3ac855

View File

@@ -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