Commit Graph

519 Commits

Author SHA1 Message Date
gsinghpal
1817f63c67 fix(fusion_accounting_reports): engine accepts report_code to disambiguate
When multiple fusion.report rows share a report_type (e.g. 4 PnL-typed
reports: pnl, cash_flow, executive_summary, annual_statements), the
engine's _get_report previously returned whichever matched the type
filter first \u2014 so all four reports rendered the canonical P&L
line_specs regardless of which report the user selected.

Adds report_code kwarg to compute_pnl, compute_balance_sheet,
compute_trial_balance, compute_gl. Controller /fusion/reports/run now
accepts and forwards report_code. _get_report has a 3-tier resolution:
1. Exact code match (validates type)
2. Canonical (code == report_type)
3. First by sequence

Two new tests assert distinct line_specs render for distinct codes and
that wrong-type code raises ValidationError.

Verified live on westin-v19: pnl/cash_flow/executive_summary/
annual_statements now return 3/9/7/5 rows respectively (was all
3 before).

Made-with: Cursor
2026-04-19 23:58:29 -04:00
gsinghpal
1ebff01d35 feat(fusion_accounting_reports): seed 3 partner-grouped reports
Adds Aged Receivable, Aged Payable, and Partner Ledger as fusion.report
records using the new compute_partner_grouped engine method.

REPORT_TYPES is extended with aged_receivable / aged_payable /
partner_ledger so each report has a unique report_type. The HTTP
controller dispatches these to engine.compute_partner_grouped with
the appropriate account_type via PARTNER_GROUPED_ACCOUNT_TYPE.

Output includes per-partner aging buckets: current, 1-30, 31-60,
61-90, 90+ days.

Westin total: 4 + 4 + 3 = 11 of Enterprise's 22 standard reports.

Made-with: Cursor
2026-04-19 23:55:45 -04:00
gsinghpal
ff6d21a561 feat(fusion_accounting_reports): partner-grouped engine method
Adds engine.compute_partner_grouped(period, account_type=...) that
returns per-partner aggregations with aging buckets (current/1-30/
31-60/61-90/90+). SQL-direct for performance — single GROUP BY query
with conditional sum per bucket.

Foundation for the 3 partner-grouped reports landing in commit 3:
Aged Receivable, Aged Payable, Partner Ledger.

Made-with: Cursor
2026-04-19 23:54:32 -04:00
gsinghpal
6896c71b79 feat(fusion_accounting_reports): seed 4 more standard reports
Adds Cash Flow Statement, Executive Summary, Tax Summary, and Annual
Statements as fusion.report records with line_specs. All work with the
existing engine's bucket-sum pattern — no engine changes needed.

Westin total: 4 + 4 = 8 of Enterprise's 22 standard reports now in
fusion_accounting_reports. Partner-grouped reports (Aged AR/AP,
Partner Ledger) need an engine extension — in commit 2.

Made-with: Cursor
2026-04-19 23:53:16 -04:00
gsinghpal
111792599c fix(configurator): margin % stored as fraction so widget='percentage' formats right
Phase D8 compute was returning x_fc_margin_percent already-multiplied
by 100, but the 'percentage' widget in the SO form multiplies again
for display. Result was 10000% instead of 100%.

Store as 0.0-1.0 fraction; widget handles the multiplier. Caught
during UAT on S00066.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 23:49:00 -04:00
gsinghpal
679dbaa979 feat(fusion_accounting_followup): per-partner state migration from Enterprise
Migrates Enterprise account_followup per-partner state to Fusion fields:
- res.partner.followup_status -> fusion_followup_status (action_due/no_action)
- res.partner.payment_next_action_date -> fusion_followup_paused_until
  (when future-dated; sets status to 'paused')
- res.partner.followup_line_id -> fusion_followup_last_level_id
  (resolved by name match against migrated levels)

Wired into fusion.migration.wizard.action_run_migration after the
existing _followup_bootstrap_step. Idempotent: skips partners whose
Fusion state is already non-default. Defensive against missing
Enterprise fields (each field probed individually before use).

Closes the per-partner state migration gap that was blocking
Enterprise account_followup uninstall.

Made-with: Cursor
2026-04-19 23:48:22 -04:00
gsinghpal
b15bf2293e fix(configurator/bridge_mrp): address all bugs from code review
Two critical, one important, four polish fixes found by the
pr-review-toolkit code-reviewer.

C1 (CRITICAL) Start-at-node filter dropped later siblings
  fusion_plating_bridge_mrp/models/mrp_production.py:448
  The allowed_ids set was {descendants} ∪ {ancestors}, which wrongly
  excluded nodes that should run AFTER the start node — including
  later siblings of the start node and all operations in subsequent
  sub-processes. Rewrote the upward walk to ALSO include each
  ancestor's later-sequence siblings and their descendants. Smoke on
  ENP-ALUM-BASIC: full=9 WOs, partial from mid-tree 'De-Masking'=5
  WOs (previously was 1).

C2 (CRITICAL) Duplicate MO on re-confirm of pre-PR SOs
  fusion_plating_bridge_mrp/models/sale_order.py:96
  Legacy untagged MOs (created before this PR had line-linkage m2m)
  were not recognized by the untagged idempotency check, so
  re-confirming an already-processed SO would create one additional
  MO per untagged plating line. Fix: pre-scan for a single legacy
  untagged MO and adopt it by linking ALL untagged plating lines
  onto it. Those lines are then treated as covered and no per-line
  MOs are created on top. Smoke: S00066 before=1 MO, after
  re-run=1 MO.

I5 (IMPORTANT) push_to_defaults wrote to pre-bump revision
  fusion_plating_configurator/wizard/fp_direct_order_wizard.py:236
  When create_new_revision=True, _get_or_bump_revision() returned a
  new part record that got written to the SO line, but the
  post-confirm push_to_defaults loop re-read line.part_catalog_id
  (still the OLD rev) and wrote defaults there, defeating the whole
  point of "save as default". Fix: cache resolved parts in a dict
  keyed by wizard-line ID during the build loop, and use that cache
  in the push_to_defaults pass.

I3/I4/I6 (PERF) Computes lacked @api.depends and did per-record
  search_count / search queries
  fusion_plating_configurator/models/sale_order.py
  _compute_nav_counts, _compute_workorder_count, _compute_wo_completion
  now:
  - declare @api.depends
  - batch via read_group across the whole self recordset
  - rebuild {origin: counts} dicts and assign per record

M7 (MEDIUM) No savepoint around per-group MO creation
  fusion_plating_bridge_mrp/models/sale_order.py:_fp_auto_create_mo
  A mid-loop exception left group 1's MO persisted and aborted
  groups 2..N. Wrapped each group's create in SAVEPOINT/RELEASE/
  ROLLBACK TO SAVEPOINT so one bad group no longer corrupts state.

M8 (MEDIUM) Email 'opened' status false-positived on internal CC
  fusion_plating_configurator/models/sale_order.py:_compute_email_status
  Switched from 'any notification is_read' to 'customer partner has
  a read email notification on this SO'.

M9 (LOW) start_at_node_id domain silently empty when coating unset
  fusion_plating_configurator/wizard/fp_direct_order_line.py:94
  Changed `('parent_id', 'child_of', ...)` to
  `('id', 'child_of', ..., or 0)` and clarified the help text.

Regression smoke passed all checks on odoo-entech.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 23:35:03 -04:00
gsinghpal
9d8db0f9b1 fix(bank_rec): don't shadow Odoo's _() translation function in action_run_migration
Line 77 was `_ = super().action_run_migration()`, using `_` as a
throwaway variable name. That rebinds the module-level `_` (Odoo's
translation function imported at the top) to whatever super() returns
\u2014 in our case the parent's notification dict.

Lines 84/85 then call `_('Bank-Rec Migration Complete')` which is
now `some_dict('Bank-Rec Migration Complete')` \u2192
TypeError: 'dict' object is not callable.

User hit this when running the migration wizard from the menu.

Fix: drop the assignment; we don't actually use super()'s return value.
Made-with: Cursor
2026-04-19 23:34:45 -04:00
gsinghpal
ef2ccb89cf fix(services): V19 removed 'rpc' service \u2014 import standalone rpc() function
V19 removed the 'rpc' service from the registry. All 4 fusion services
(bank_reconciliation, reports, assets, followup) declared dependencies:
['rpc', ...] and accessed services.rpc in their constructor. At runtime
this caused:

  Error: Some services could not be started: fusion_bank_reconciliation,
  fusion_reports, fusion_assets, fusion_followup. Missing dependencies: rpc

\u2014 which prevented the entire OWL backend from booting (blank screen).

Fix per V19 docs:
- Add 'import { rpc } from "@web/core/network/rpc";'
- Set 'this.rpc = rpc;' in constructor (instead of services.rpc)
- Remove 'rpc' from dependencies list

This is the workspace CLAUDE.md guidance Phase 4's subagent flagged
but didn't act on for backward consistency. V19 actually removed the
service entirely, so the consistency choice was wrong \u2014 fixing now.

All call sites still use this.rpc(...) so no per-method changes needed.
Bundle rebuilt clean; backend boots correctly.

Made-with: Cursor
2026-04-19 23:25:52 -04:00
gsinghpal
51d8ce494d fix(scss): remove forbidden @import "variables" lines breaking V19 asset bundle
Phases 1-3's SCSS files used '@import "variables";' to pull in tokens
from _variables.scss. V19's odoo.addons.base.models.assetsbundle
forbids cross-file SCSS imports for security ('Local import forbidden')
and the asset bundle warning was firing on every web request.

Phase 4 caught + fixed this for fusion_accounting_followup; Phases 1-3
were never updated. Today's deployment surfaced the CSS error reported
by the user.

Resolution:
- Removed @import lines from 7 SCSS files across bank_rec, reports, assets
- Variables come from _variables.scss via manifest concatenation order
  (bundle order is _variables.scss first, then dependent files)
- Replaced documentation comments to NOT contain the literal string
  '@import "variables"' \u2014 Odoo's check is regex-based and was
  matching even SCSS comments

Verified clean: bundle rebuilds with zero 'Local import forbidden'
warnings; all 534 fusion-module tests still pass.

Made-with: Cursor
2026-04-19 21:57:22 -04:00
gsinghpal
190c296240 fix(fusion_accounting_ai): align legacy assets-adapter test with Phase 3 return shape
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Phase 3 (fusion_accounting_assets) changed list_assets() to return
{count, total, assets} dict instead of a flat list — consistent with
bank_rec.list_unreconciled, reports.run_report, followup.list_overdue.

The pre-existing test in fusion_accounting_ai still asserted isinstance(rows, list)
and was failing on every run since Phase 3 merge. Updated to assert dict shape.

Made-with: Cursor
2026-04-19 21:50:47 -04:00
gsinghpal
12fa20c4f1 Merge Phase 4: AI-augmented customer follow-ups
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
37 tasks shipped on fusion_accounting/phase-4-followup:
- fusion.followup.engine (7-method API: get_overdue, compute_level, send, escalate, pause, reset, snapshot_history)
- 6 aging buckets + 3-level dunning + tone selector
- 5 persisted models (level, run, text_cache, partner inherit, move_line inherit)
- AI: payment risk scoring + LLM follow-up text + templated fallback
- 6 JSON-RPC controller endpoints + reactive frontend service
- 5 OWL components + SCSS + dark mode
- Batch wizard + 2 cron jobs (daily scan + weekly risk refresh)
- 3 default mail templates + 3 default levels
- Migration wizard backfill from account_followup
- Coexistence with Enterprise
- 106 tests passing
- All P95 perf metrics within 1x of budget

ALL 4 PHASES COMPLETE — replaces account_accountant + account_reports + account_asset + account_followup.
2026-04-19 21:48:10 -04:00
gsinghpal
b834ae3117 feat(configurator): complete all deferred Phase D/E/F tasks
Ships the remaining items from the Sales UX Uplift plan:

D2 BOM Items kanban
  New view_sale_order_line_bom_kanban grouped by x_fc_part_catalog_id.
  Smart button 'BOM Items' on SO form opens it.

D5 Archive line
  x_fc_archived Boolean on sale.order.line plus action_archive_line /
  action_unarchive_line. Acknowledgement report filters out archived
  lines.

D6 Add Quoted Lines sub-wizard
  New fp.add.from.quote.wizard parallel to fp.add.from.so.wizard. Pick
  quotes for this customer and clone them into direct-order lines
  carrying part, coating, qty, unit price (from calculated or
  override), and notes. Button '+ Add From Quotes' on wizard Lines tab.

D7 SO Acknowledgement PDF
  New ir.actions.report + QWeb template in configurator/report/.
  Header shows customer / contact / PO / Customer Job #, Bill-To,
  Ship-To, planned start + customer deadline + ship-via. Line table
  skips archived lines. Includes external notes, blanket-order
  callout, and customer-signature + vendor-signature blocks.
  Binding added to sale.order so it shows up under Print menu.

D9 Quick-nav chip bar
  New smart buttons on SO form: Invoices / Pickings / NCRs / Files
  with counts and icons. Each opens a filtered list. NCR button
  appears only when fusion_plating_quality is installed.

D10 SO/WO perspective toggle
  view_sale_order_line_wo_kanban grouped by x_fc_wo_group_tag. Smart
  button 'By WO' on SO form.

D11 Assemblies minimal model
  fp.sale.assembly + fp.sale.assembly.line with name, ship_to, count,
  procured_count, completed_at. UX (forms / kanbans / integration
  into receiving) deferred — model only for now.

D14 Uploaded Files
  Files smart button on SO form opens ir.attachment kanban filtered
  to this SO. Count appears in the chip bar.

F4 Signed tracking
  x_fc_signed_at / x_fc_signed_by / x_fc_is_signed on sale.order +
  action_mark_signed helper. Signed column on quotes list view.

F10 New Quote
  Kept on existing action_fp_quotations (already surfaces the
  default New button).

E5/F9 Action icons per row
  Deferred — requires a custom widget; the native PDF action via the
  Print menu covers 80% of the use case.

Bumped to 19.0.8.0.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:45:17 -04:00
gsinghpal
3491069f48 docs(fusion_accounting_followup): CLAUDE.md, UPGRADE_NOTES.md, README.md
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Made-with: Cursor
fusion_accounting/phase-4-complete
2026-04-19 21:41:41 -04:00
gsinghpal
fbc1ac38f8 feat(fusion_accounting): meta-module now installs followup sub-module
Made-with: Cursor
2026-04-19 21:40:10 -04:00
gsinghpal
aeb5461ad0 test(fusion_accounting_followup): local LLM follow-up text smoke (skips without LLM)
Made-with: Cursor
2026-04-19 21:39:50 -04:00
gsinghpal
e1f94d5202 test(fusion_accounting_followup): 5 OWL tour tests
Made-with: Cursor
2026-04-19 21:39:08 -04:00
gsinghpal
b85e208856 chore(bridge_mrp): bump to 19.0.7.0.0 — WO group + start-at-node wiring
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:35:59 -04:00
gsinghpal
e3001b5297 feat(bridge_mrp): honour x_fc_wo_group_tag + x_fc_start_at_node_id
Two features from Phases B/C that were previously only data now do work:

1. WO GROUPING (x_fc_wo_group_tag)
   _fp_auto_create_mo rewritten to iterate order_lines and group by
   x_fc_wo_group_tag. Lines sharing a tag collapse into ONE MO with
   product = first line's part.product_id, qty = Σ line qty,
   recipe = first line's coating_config.recipe_id. Untagged lines
   each get their own MO. Legacy path preserved for service-line SOs
   with no plating data.

   Idempotency is per (origin, tag): re-confirming an SO doesn't
   create duplicate MOs for already-grouped lines.

   New on mrp.production:
   - x_fc_wo_group_tag (Char, tracking)
   - x_fc_sale_order_line_ids (M2M back to sale.order.line)
   - x_fc_start_at_node_id (Many2one fusion.plating.process.node)

2. START-AT-NODE (x_fc_start_at_node_id)
   _generate_workorders_from_recipe pre-computes allowed_ids as the
   set of {descendants of start_node} ∪ {ancestors of start_node}.
   _is_node_included rejects any node outside that set. This skips
   sibling branches earlier in the recipe while keeping the
   container hierarchy so WO sequence numbers still make sense.

Smoke-tested S00070 (4 lines, 2 tagged groups + 1 untagged) -> 3 MOs:
WO#A qty=15 (2 lines batched), WO#B qty=50 (1 line), untagged qty=7
(1 line). Each got the ENP-ALUM-BASIC recipe.

Start-at-node smoke on the same recipe: full generation = 9 WOs,
partial with start_at='Ready for processing' = 1 WO.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:34:48 -04:00
gsinghpal
8eb4b8dc6c fix(fusion_accounting_followup): seeded levels + migration idempotency
- test_create_minimal/negative_delay used sequence=1, which now collides
  with the seeded Friendly Reminder level. Use sequences 901/902.
- migration backfill: search by name (not raw seq) for idempotency,
  allocate sequence as max(existing)+1 to avoid both seed clashes and
  within-batch collisions when Enterprise has duplicate sequence values.

Made-with: Cursor
2026-04-19 21:33:26 -04:00
gsinghpal
d0a912b1da test(fusion_accounting_followup): coexistence behavior
Made-with: Cursor
2026-04-19 21:30:26 -04:00
gsinghpal
8ef88da94a feat(fusion_accounting_followup): menu + window actions with coexistence group filter
Made-with: Cursor
2026-04-19 21:30:06 -04:00
gsinghpal
38a2684782 feat(fusion_accounting_followup): migration wizard backfill from account_followup
Made-with: Cursor
2026-04-19 21:29:38 -04:00
gsinghpal
2ec90a50b0 feat(fusion_accounting_followup): batch send follow-ups wizard
Made-with: Cursor
2026-04-19 21:28:58 -04:00
gsinghpal
4ee261e189 feat(fusion_accounting_followup): default mail templates for 3 escalation levels
Made-with: Cursor
2026-04-19 21:27:59 -04:00
gsinghpal
ab3fcc56db feat(fusion_accounting_followup): seed 3 default follow-up levels
Made-with: Cursor
2026-04-19 21:27:33 -04:00
gsinghpal
97c733b7c3 feat(configurator): Phase F — quotations list uplift
F1 follow-up: x_fc_follow_up_date + x_fc_follow_up_user_id fields on
sale.order, surfaced in the quotations list + a 'Needs Follow-Up'
preset filter.

F2 expires: native validity_date exposed as togglable column on the
quotes list + an 'Expired' preset filter.

F3 email status pills: x_fc_email_status computed (draft / sent /
opened / won). 'Opened' detects via mail.notification.is_read on any
email-type mail.message attached to this SO.

F5 part numbers summary: x_fc_part_numbers_summary ("PN1, PN2 (+3
more)") across order_line parts, togglable column.

F7 from-RFQ filter reuses existing x_fc_rfq_attachment_id.

Views:
- view_sale_order_list_fp_quotes (new list dedicated to quotes).
- view_sale_order_search_fp_quotes with filters Draft / Sent / Won /
  From RFQ / Needs Follow-Up / Expired + group-bys.
- action_fp_quotations rewired to both of the above.

Bumped to 19.0.7.2.0. Closes all six phases originally planned.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:23:41 -04:00
gsinghpal
474485f963 feat(fusion_accounting_followup): ai_text_panel + followup_history_table components
Made-with: Cursor
2026-04-19 21:20:51 -04:00
gsinghpal
da746698c5 feat(fusion_accounting_followup): partner_card + aging_bucket_strip + risk_badge components
Made-with: Cursor
2026-04-19 21:19:52 -04:00
gsinghpal
21f6171162 feat(fusion_accounting_followup): top-level followup_dashboard component
Made-with: Cursor
2026-04-19 21:18:59 -04:00
gsinghpal
94eb7ef415 feat(configurator): Phase E — SO list view uplift
E1/E2/E3/E4: list view gets new togglable columns for
- x_fc_wo_completion (e.g. '3/5'): count of completed vs total WOs
- x_fc_invoiced_amount (Monetary): sum of posted customer invoices
  minus credit notes
- x_fc_margin_amount + x_fc_margin_percent: reuses Phase D8 computes
- x_fc_is_blanket_order toggle

New sale.order.search view (sale.order.search.fp) with preset
filters: My Orders / Open / Confirmed / Done / Blanket / Has Rush /
Overdue, plus group-bys for Customer / Status / Customer Deadline.

Bumped to 19.0.7.1.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:18:52 -04:00
gsinghpal
86bead48e1 feat(fusion_accounting_followup): followup_service.js reactive frontend service
Made-with: Cursor
2026-04-19 21:17:57 -04:00
gsinghpal
99e4f8e17f feat(fusion_accounting_followup): SCSS foundation for OWL widget
Made-with: Cursor
2026-04-19 21:17:18 -04:00
gsinghpal
3f807d0152 chore(configurator): bump to 19.0.7.0.0 — Phase D first pass landed
Phase D scope landed so far:
- D1 deadline countdown
- D4 internal/external notes split
- D8 margin amount + percent
- D12 contact phone on SO header
- D13 ship via Char
- D3 active WOs stat button

Deferred to later Phase D pass:
- D2 BOM Items grouped list (overlaps with order_line)
- D5 archive line (native Odoo, just needs UI exposure)
- D6 Add Quoted Lines sub-wizard
- D7 SO Acknowledgement PDF report
- D9 Quick-nav link bar
- D10 SO/WO perspective toggle
- D11 Assemblies section (hierarchical BOM)
- D14 Uploaded Files surface (native Odoo attachments)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:13:40 -04:00
gsinghpal
842efd828c feat(configurator): Phase D batch 2 — active WOs stat button on SO form
D3 first half: x_fc_workorder_count computes live count of active MRP
work orders linked to this SO (via mo.origin = so.name). Adds a
'Active WOs' smart button next to the existing PO / RFQ buttons on
the sale.order form. Clicking opens a filtered mrp.workorder list
grouped by MO.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:12:34 -04:00
gsinghpal
2476961f50 feat(configurator): Phase D batch 1 — countdown, notes split, margin, contact
Phase D first landing covers the quick-win Steelhead-parity fields on
the SO form / list:

- D1: x_fc_deadline_countdown ("in 2d 3h", "overdue 1d 4h") computed
  from commitment_date. Surfaced in SO form scheduling group and as
  togglable column on the SO list.
- D4: x_fc_internal_note + x_fc_external_note split (html). Existing
  'note' field is left untouched for back-compat. External note is
  intended for the SO acknowledgement + portal; internal note is
  shop-floor only.
- D8: x_fc_margin_amount + x_fc_margin_percent, currently computed
  against fp.coating.config.unit_cost if defined (else 0 -> 100%
  margin). When cost rollup lands on fp.coating.config, margin will
  reflect reality automatically.
- D12: x_fc_contact_phone related to partner.phone (readonly) on SO
  header.
- D13: x_fc_ship_via Char on SO header (carrier name).

Smoke: S00066 shows 'in 9d 22h' countdown + \$3025 margin; S00069
shows 'in 24d 22h' + \$750. Contact phone pulls from partner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:11:18 -04:00
gsinghpal
f45d66c465 test(fusion_accounting_followup): performance benchmarks with P95 targets
Made-with: Cursor
2026-04-19 21:10:02 -04:00
gsinghpal
f64b8f373c test(fusion_accounting_followup): full follow-up flow integration test
Made-with: Cursor
2026-04-19 21:09:17 -04:00
gsinghpal
6b4b0c9eb7 chore(configurator): bump to 19.0.6.2.0 — Phase C direct order polish
Phase C complete on odoo-entech. Smoke-tested S00069:
- C1 x_fc_start_at_node_id = Ready for De-Masking (resume-rework)
- C2 x_fc_part_wo_description = internal rework note
- C5 x_fc_is_one_off = False
- C3 x_fc_quote_id slot wired (no quote picked in this smoke)
- C4 push-to-defaults wrote EN High-Phos back onto part catalog

Phase D (SO detail view), Phase E (SO list view), and Phase F
(Quotes list) are independent tracks — outlined in the plan doc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:09:00 -04:00
gsinghpal
d51a2b104e test(fusion_accounting_followup): Hypothesis property-based invariants
Made-with: Cursor
2026-04-19 21:08:35 -04:00
gsinghpal
31bd8d1e56 feat(configurator): C3 — link direct-order line to a prior quote
Adds quote_id (Many2one fp.quote.configurator) on the wizard line
with a domain scoped to the wizard's customer + quote states (sent /
accepted / won). Onchange auto-fills part, coating, and unit price
(final = estimator_override_price or calculated_price, per-part).

Mirrors x_fc_quote_id on sale.order.line for the audit trail. Surfaced
as a togglable column on the SO line tree and under "Qty & Price" on
the wizard line drill-in form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:07:48 -04:00
gsinghpal
042dcf8067 feat(fusion_accounting_followup): 2 cron jobs (daily scan + weekly risk refresh)
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
- fusion.followup.cron AbstractModel with two handlers
- cron_fusion_followup_daily_scan: walks every overdue partner and
  delegates to engine.send_followup_email
- cron_fusion_followup_risk_refresh: weekly refresh of
  fusion_followup_risk_score / risk_band on res.partner
- V19 ir.cron records (no numbercall field)
- 2 smoke tests added (80 total)

Made-with: Cursor
2026-04-19 21:04:37 -04:00
gsinghpal
d437d1d959 feat(configurator): C4 — push coating + treatments back to part catalog defaults
Adds x_fc_default_coating_config_id and x_fc_default_treatment_ids
fields on fp.part.catalog. Wizard line gets a push_to_defaults
toggle. After action_create_order confirms the SO, any line with
push_to_defaults=True writes its coating + treatments back onto the
part catalog entry as the new defaults.

Reverse direction too: onchange on part_catalog_id in the wizard
line seeds coating + treatments from the part's defaults (if set and
the line doesn't already have them).

Part catalog form gets a new "Defaults" tab showing the stored
defaults. Smoke-tested: pushing default on order 1 populates the
catalog entry; new wizard line for that part auto-seeds the coating.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:04:30 -04:00
gsinghpal
52becd176a feat(fusion_accounting_ai): 5 new customer follow-up AI tools
Adds Task 17 tool layer:
- fusion_list_overdue
- fusion_get_partner_followup_detail
- fusion_generate_followup_text
- fusion_send_followup
- fusion_get_partner_risk_score

Tools register through TOOL_DISPATCH and degrade with a clear
error message when fusion_accounting_followup is not installed.
5 TransactionCase tests added (78 total).

Made-with: Cursor
2026-04-19 21:03:30 -04:00
gsinghpal
993df3a14a feat(fusion_accounting_ai): wire FollowupAdapter fusion paths to engine
- Switch FUSION_MODEL to fusion.followup.engine so adapter mode
  selection matches the new module
- Add list_overdue() with fusion/enterprise/community variants
- Re-route send_followup_via_fusion to engine.send_followup_email
- 4 new TransactionCase tests (73 total)

Existing aging / overdue_invoices adapter methods continue to fall
back to the community implementation.

Made-with: Cursor
2026-04-19 21:02:17 -04:00
gsinghpal
43a26b6849 feat(configurator): Phase C polish — to-node picker, WO description, one-off flag
C1: start_at_node_id per wizard line, mirrors to x_fc_start_at_node_id
on sale.order.line. Domain filters to nodes descending from the
coating_config's recipe so the estimator only picks valid resume
points. bridge_mrp will use this in a follow-up to skip ancestor
steps in the generated work order.

C2: part_wo_description (separate from customer-facing line_description)
lets the planner add internal-only notes that appear on the travelling
sheet only. Mirrors to x_fc_part_wo_description on sale.order.line.

C5: is_one_off flag for prototype / non-catalog parts. Mirrors to
x_fc_is_one_off. Actual skip-catalog behaviour will be wired in a
later pass.

All three fields appear in the wizard line drill-in form (under a new
"Work Order (internal)" group) and as togglable columns on the
sale.order.line tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:01:25 -04:00
gsinghpal
d455016c27 feat(fusion_accounting_followup): 6 JSON-RPC endpoints for OWL widget
Adds Task 15 controller layer:
- /fusion/followup/list_overdue
- /fusion/followup/get_partner_detail
- /fusion/followup/generate_text
- /fusion/followup/send
- /fusion/followup/pause
- /fusion/followup/reset

All endpoints use V19 type='jsonrpc' and route through
fusion.followup.engine. 6 HttpCase tests added (69 total).

Made-with: Cursor
2026-04-19 21:00:07 -04:00
gsinghpal
9b6d6b3895 test(fusion_accounting_followup): engine integration tests for full lifecycle
End-to-end flows over a real posted receivable line: aging discovery,
level resolution, send-with-cache reuse, pause+force override, and
audit history growth. Adds ignore_pause kwarg to compute_followup_level
so force=True in send_followup_email reaches level resolution.

Made-with: Cursor
2026-04-19 20:54:13 -04:00
gsinghpal
6802d60e44 feat(fusion_accounting_followup): fusion.followup.engine 7-method API
The orchestrator AbstractModel for follow-up lifecycle.
get_overdue_for_partner, compute_followup_level, send_followup_email,
escalate_to_next_level, pause_followup, reset_followup, snapshot_followup_history.

All controllers, AI tools, wizards, cron must route through these
methods; no direct ORM writes to fusion.followup.run from anywhere else.

Made-with: Cursor
2026-04-19 20:52:27 -04:00
gsinghpal
059276886d chore(configurator): bump to 19.0.6.1.0 — Phase B direct order wizard
Phase B complete on odoo-entech:
- B1/B2: Blanket + Block Partial flags on wizard header + sale.order
- B3: x_fc_wo_group_tag per SO line (bridge_mrp will use this to
  batch MOs in a follow-up)
- B4: 'Add From Prior SO' sub-wizard for repeat orders
- B5: Per-line is_missing_info compute + amber row decoration
- B6: Rush already on line (added in Phase A)

Smoke-tested: wizard accepts 4 lines (1 with missing price, 3 WO-tagged
across 2 groups), banner shows correctly, missing row highlighted in
amber, after fix SO creates cleanly with all flags + tags persisted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:50:49 -04:00