Commit Graph

9 Commits

Author SHA1 Message Date
gsinghpal
16a4bdddf3 fix(reports): BoL PDF — t-field needs dotted path, branch on delivery_address_id
The Bill of Lading template assigned a temp variable
`<t t-set="dest" t-value="doc.delivery_address_id or doc.partner_id"/>`
and then tried `<div t-field="dest" .../>`. Odoo 19 QWeb asserts
t-field must be `record.field_name` (have a dot) — the temp variable
form fails compilation and the report renders as a multi-page
"Oops! Something went wrong" PDF stuffed with the traceback.

Fix: branch with `t-if`/`t-else` and call `t-field="doc.delivery_address_id"`
or `t-field="doc.partner_id"` directly. Same pattern in both header
and second-page-header sections (lines 49/235).

Verified: BoL render goes from 39 KB error page to 138 KB clean PDF.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 07:14:33 -04:00
gsinghpal
d351a2577b chore(receiving): port received_qty auto-prefill from live entech to main
The auto-prefill logic that fills received_qty from expected_qty on
fp.receiving create was committed to the entech LXC but never made it
back to main. Verified by a full quote→delivery→invoice walkthrough
(scripts/fp_e2e_human.py) — receiving step now passes.

Also adds the human-walkthrough E2E script that exercises every step:
RFQ → quote → SO confirm → MO + portal job auto-create → receiving
prefill → recipe → WO execution → MO done → CoC cert (rich PDF, no
thickness duplicate) → delivery prefill + lifecycle → invoice (posted,
not auto-paid) → notification log audit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 01:26:16 -04:00
gsinghpal
209b1974a7 feat(plating): seed 5 fresh MOs with mixed states + priorities
Stage filler gains step 6g — spins up five new manufacturing orders
so the Manager Desk has a busy shop floor instead of the single
in-flight MO that came out of the base seeder.

Plan, in order of creation:

  WH/MO/00012  HOT     Cyclone Manufacturing      qty 25  unassigned
  WH/MO/00013  Urgent  Westin Manufacturing       qty 60  unassigned
  WH/MO/00014  Normal  Honeywell Aerospace        qty 18  auto-routed
  WH/MO/00015  Normal  Amphenol Canada            qty 40  routed + first WO started
  WH/MO/00016  Normal  Magellan Aerospace         qty 32  auto-routed

Each MO is created via mrp.production.create() and confirmed through
the bridge_mrp action_confirm() override, which auto-creates the
portal job and generates ~9 WOs from the recipe with role-aware
auto-routing. Post-create the script stamps priority on every WO and
optionally clears assignments (HOT + Urgent) or starts the first WO
(MO_00015) for variety.

Recipe lookup was previously by code='ENP-ALUM-BASIC' which silently
failed because the seed file uses code='ENP_ALUM_BASIC' (underscores)
while the display name has dashes. Switched to "first available
recipe of node_type=recipe" so the script works regardless of which
spelling is canonical.

Idempotent — bails early if there are already five-plus active MOs,
so re-runs don't keep stacking new jobs.

Verified on entech: Manager Desk now shows
  - 6 active MOs (was 1)
  - 23 unassigned active WOs (was 2)
  - 30 active+assigned WOs (was 6)
  - 2 WOs in progress now
  - all 7 operators with open queue (Marie 2, James 1, Carlos 8, etc.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 22:41:27 -04:00
gsinghpal
2ce7bd3665 fix(manager-desk): include 'blocked' WOs + populate empty columns
Two complementary fixes — a real bug in the Manager Desk and demo
data that exercises the now-correct view.

The bug
=======
manager_controller.py used an explicit allow-list of WO states for
its Unassigned / Active columns and for the per-operator team load
count: ('pending','waiting','ready','progress'). That set MISSED the
'blocked' state Odoo emits when a WO's predecessor isn't done yet.

Result: an MO whose first WO is still running has all its downstream
WOs in 'blocked' state. They literally don't appear on the Manager
Desk — neither in "Needs a Worker" (even when unassigned) nor in
"In Progress" (even when assigned). The team load count also
under-reports because the operator's blocked queue is invisible.

Fix: switch all three domains from an allow-list to a deny-list
('done','cancel'). Same shape Plant Overview already uses, so the
two dashboards now agree on what "active" means.

Demo data
=========
Stage-filler gains two steps so the now-corrected view has obvious
data:

  6e. _populate_active_wos walks the in-flight MO's blocked routing
      and explicitly assigns the seven downstream WOs in sequence
      order — Diego (training), Carlos (plating), James (demask),
      Priya (oven), TWO unassigned (de-rack + post-bake — feed
      "Needs a Worker"), Aisha (final inspection). Earlier
      keyword-fuzzy matching missed WOs whose names didn't carry
      the expected substring.

  6f. _mark_so_awaiting_manager pushes two confirmed SOs to
      receiving_status='inspected' + assigned_manager_id=False so
      the "Awaiting Assignment" KPI is non-zero.

Verified on entech: 2 unassigned WOs, 6 active+assigned, 2
awaiting-assignment SOs. Six of seven operators carry at least one
open queue item; Marie has zero current load but a healthy past
completion history (she's on shift, between jobs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 22:33:01 -04:00
gsinghpal
0315fee988 feat(plating): demo stage-filler — every workflow step now has data
Companion to fp_demo_seed.py. Bridges the gaps the original seeder
left after the team-skills + timer-audit + presence-aware Manager Desk
work landed (commit 0d12902). Idempotent.

Eight steps, each wrapped in a safe() driver so a failure in one
doesn't abort the rest:

  1. Fill x_fc_work_role_id on any WO that doesn't have one yet.
     Keyword map (mask/rack/plat/bake/oven/inspect/rework) → role
     code, falls back to plating_op. The auto-promotion tracker
     can't credit a worker without a role on the WO.

  2. Backfill the four timer audit fields (started_by/at,
     finished_by/at) on done WOs. Pulls from time_ids when the
     productivity records exist, otherwise synthesises timestamps
     from create_date + duration.

  3. Seed a diverse team of six operators with distinct role
     coverage and lead-hand permissions:
       - Marie Dubois     — masking + racking      (lead: masking)
       - James O'Connor   — plating_op + demask    (lead: plating_op)
       - Priya Sharma     — oven + inspection      (lead: oven, inspection)
       - Diego Ramirez    — racking + plating_op   (TRAINING: 2/3 masking)
       - Aisha Khan       — inspection + rework
       - Carlos Silva     — every role             (lead: every role)
     Each gets a backing res.users so the Manager Desk dropdown
     can assign them.

  3b. Redistribute ~40 historical done WOs across the new team so
      their Task Proficiency lists aren't empty. Plan targets
      realistic per-role counts (Marie 8 masking + 5 racking,
      James 12 plating + 4 demask, etc.) and re-stamps the timer
      audit so finished_by reflects the new owner.

  4. Wipe + rebuild fp.operator.proficiency from completed WOs so
     the per-(employee, role) tally is deterministic. Auto-promotion
     fires naturally during the rebuild — workers who already cleared
     the threshold get promoted=True with timestamps. Diego is
     deliberately seeded at 2/3 on masking so the demo shows the
     "one more job away from promotion" state live.

  5. Clock three operators in via hr.attendance (4-hour shift).
     Wipes any stale open records first because earlier script
     iterations left future-dated check_in timestamps that the
     attendance validator refused to close.

  6a. Two extra quality holds (damaged + out_of_spec).

  6b. Mark the in-progress WO with a started_at but no finished_at
      so the demo has a "paused for lunch" exemplar.

  6c. Three portal RFQs (one per workflow state: new / under_review
      / quoted) so the funnel front-end has data.

  6d. Push one draft SO to "sent" so the quotation pipeline has
      data in every column (was draft → confirmed previously).

Verified on entech: 21 of 21 workflow stages now , including
Diego's 2/3 masking row that shows the auto-promotion mechanic
in flight.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 22:22:31 -04:00
gsinghpal
e07002d550 feat(shopfloor): rich Tablet Station dashboard + full shop-floor demo data
Tablet Station rebuilt as a live dashboard (not just a QR scanner):

  * KPI strip — WOs Ready/Progress, Awaiting/Missed bakes,
    First-Piece pending, Quality Holds (each tinted by state)
  * Active WO banner with pulsing indicator when a WO is running
  * My Queue panel (left) — priority-badged operator next-up list,
    clickable rows that jump to the WO/bake/gate form
  * Baths tile grid (right) — last-log status chips, MTO count,
    hover jump to chemistry log
  * Bake Windows list — inline Start/End/Open actions, colour-coded
    by state (awaiting / in-progress / missed)
  * First-Piece Gates — Pass/Fail buttons for pending inspections
  * Quality Holds — Review jump when any open holds exist
  * Station picker + scan drawer (collapsed by default)
  * 30s auto-refresh, persists picked station in localStorage

New controller endpoints: /fp/shopfloor/tablet_overview,
/fp/shopfloor/pair_station, /fp/shopfloor/mark_gate.

Demo seeder (Phase 12.5) now populates:
  * 5 shop-floor stations (Plating, Bake, Inspection, Shipping, Receiving)
  * +3 bake windows (awaiting / in-progress / near-due)
  * 4 first-piece gates (1 pending, 1 passed+released, 1 passed-holding, 1 failed)
  * 2 quality holds on active MOs (one on_hold, one under_review)

All four Shop Floor menu pages (Plant Overview, Tablet Station, Bake
Windows, First-Piece Gates) now have meaningful content.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 07:43:10 -04:00
gsinghpal
838b41cb89 fix(bridge_mrp): WO recipe generator + demo work-order backfill
bridge_mrp._generate_workorders_from_recipe was writing 'description'
on mrp.workorder, which doesn't exist in Odoo 19 — instead the step
instructions now post to each WO's chatter after bulk create, which
is where the operator sees them anyway.

Demo seeder now creates the full WO chain:
- 9 MRP work centres paired with 9 FP work centres (FP-QUEUE, -RACK,
  -MASK, -EN, -BAKE, -INSP, -DERACK, -DEMASK, -POSTBAKE) with
  costs_hour set so actuals-vs-quoted margin can compute.
- Wires the existing ENP-ALUM-BASIC recipe's 9 operation nodes to
  those FP work centres by matching names.
- Links every coating config to the recipe so the auto-assign hook
  (mrp.production.action_confirm → _auto_assign_recipe_from_so) has
  something to pull.
- Backfills work orders on all existing demo MOs: calls the generator
  once recipe is set. For historical (done) MOs, marks all their WOs
  done with backdated durations (25-90 min). For the Cyclone active
  MO, sets a realistic progression: first WO done, second in progress
  (priority: Hot), rest in 'ready'.

Verified: 90 WOs live, 10 per work centre. One MO shows the full
progression state mix. WO Traveller PDF renders (132KB) — both
portrait + landscape variants still work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 02:18:08 -04:00
gsinghpal
96ecf7a9e1 feat(coc): professional CoC with accreditation badges + signature + company branding
Problem: the rebuilt CoC rendered mostly empty because accreditation logos
had to be uploaded manually via Settings first, and no signature existed —
looked unprofessional next to the Steelhead reference.

Fix:
- Seeder now auto-generates clean text-based accreditation badges with PIL
  (Nadcap blue, AS9100D/ISO 9001 blue, CGP red) sized to match the
  reference layout. Client can swap in real trademarked logos via Settings
  → Fusion Plating → Accreditation Logos at any time.
- Seeder creates a demo "Kris Pathinather" user, sets them as the
  certificate owner on res.company, and renders a scripted-looking
  signature image that matches the printed name on the cert.
- Seeder uploads a generated "Amphenol Canada Corp." badge to Amphenol's
  res.partner.image_1920 so that customer's CoCs include their logo
  on the top-right corner (mirrors how the reference shows it).
- coc_body template: guard hr.employee.signature access with a field-
  exists check (the field is provided by an optional module not
  installed on every Odoo).
- CoC uses web.html_container directly instead of wrapping in
  web.basic_layout — the outer wrapper was injecting top padding that
  pushed the title ~25% down the page. Now starts cleanly at the top.
- Tightened CoC CSS: removed unused label classes, added @page margin
  directive, fixed vertical-align on header cells so logos and company
  contact stay middle-aligned regardless of row height.
- Invoice PDF PAID stamp now also triggers on payment_state =
  'in_payment', so historical demo invoices look paid without needing
  full bank reconciliation.

Verified: renders a 152KB PDF with 5 embedded images, signer name
matches signature, all accreditation badges visible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 01:42:35 -04:00
gsinghpal
fbaf318832 chore(fusion_plating): add story-driven demo seeder + polish invoice PAID stamp
Demo seeder (scripts/fp_demo_seed.py):
- Idempotent Python script run via odoo shell; populates ~60 records
  across 6 customer stories covering every workflow state for live demo
- Customers: Amphenol (net-terms, deep history), Magellan (progress
  billing, active), Cyclone (deposit, in-production), Honeywell
  (net-terms, just confirmed), Westin (COD, direct-order path),
  Delinquent Industries (account hold — Confirm raises UserError)
- Coating configs with realistic AMS specs (2404, 2700 Rev G, 2406)
  and bake-relief flags set on applicable processes
- Part catalog with revision chains (Rev 1 / Rev 2 / Rev 3 for hot parts)
- Customer price lists with volume tiers
- Per-customer invoice strategy defaults
- Bath chemistry logs (15 readings, last 2 OOS → pending replenishment
  suggestion visible in menu)
- Racks: 4 active + 1 needing strip (MTO 3.2 / 3.0) for kanban demo
- Bake windows: 1 awaiting (ticking down), 1 baked, 1 missed (alert)
- Quote configurator sessions: 3 draft, 3 confirmed/won, 3 lost (with
  reasons), 1 expired — populates the win/loss analysis
- Historical closed orders: 8 jobs backdated across 4 months with
  SO → MO → Delivery → Invoice → Payment run through each hook so
  portal-job progression, certificates with thickness readings, and
  invoice AR aging all look real
- Active orders at every workflow stage for the live demo cycle

Polish:
- report_fp_invoice PAID stamp now also triggers on payment_state ==
  'in_payment' (in addition to 'paid'). Odoo leaves payments in
  'in_payment' until the bank reconciliation job matches them against
  a statement line, so historical demo invoices would otherwise never
  show as stamped even though the payment is posted and the customer
  owes nothing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 01:30:53 -04:00