The wizard's dynamic fields were non-functional: the "Existing customer" box had
no search (no endpoint, no handler — the typed string was only sent on submit),
and address autocomplete never attached (google_address_autocomplete.js patches
FormController, which a client action is not).
Live client search:
- new jsonrpc endpoint /fusion_claims/service_booking/search_customers — searches
res.partner (name/phone/email) and resolves a typed SO number to its partner.
- JS: debounced (250ms) onCustSearch -> .sb-cust-results dropdown; pickCustomer()
sets state.partnerId + fills the contact, which action_book_from_wizard already
consumes for cust_mode='existing'.
- FIELD-SAFE domain: res.partner has NO `mobile` field in Odoo 19 — referencing it
raises ValueError and the swallowed exception made the search silently return
nothing. Build the OR domain only over fields in Partner._fields. Smoke-tested on
prod data ('25450'->1, '1 905-'->8).
Address autocomplete (wizard-local):
- component loads Google Places (key = ICP fusion_claims.google_maps_api_key, which
IS configured on westin), attaches via useRef('root')+onMounted/onPatched to every
input.sb-addr-input, writes street/city/lat/lng into reactive state. Fully guarded
(per-input _sbAc, _addrStarted/_addrNoKey gate, .catch on both hooks) so a missing
key degrades to manual entry and can never break render.
Verified: pyflakes clean, JS node --check, SCSS compiles, XML well-formed, dropdown
UI rendered against Bootstrap+compiled CSS. Documented in fusion_claims/CLAUDE.md §48.
Bump fusion_claims 19.0.9.6.0 -> 19.0.9.7.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 19.0.9.5.0 CSS pass (padding/scroll) did not fix "fields sitting on each
other" on small screens. Deep dive against the live web.assets_backend bundle
found two compounding root causes (both measured, not guessed):
1. Dead media query. The @media(max-width:560px) collapse for the inner field
grids (.two/.three) and .timepick was nested BEFORE the base .two/.three/
.timepick rules. Equal specificity → the later base rule wins → the media
query never applied. matchMedia matched at 320/390px yet grids stayed 2–3
columns and crammed/truncated. Moved all @media overrides to the END of the
.o_service_booking block so they win the cascade.
2. Bootstrap class collision. The wizard reused row/card/grid/btn; Odoo's
backend Bootstrap applies .row{display:flex;margin:0 -16px}, .card{display:flex},
etc. globally even under the scoped parent (they win for properties the scoped
rule doesn't set). Measured: every .row computed display:flex + margin-left/
right:-16px. Renamed all layout classes to sb-* (sb-row/sb-card/sb-grid/sb-btn)
in service_booking.xml + service_booking.scss.
Verified at 320/390/768/1280 against the real prod bundle (computed
grid-template-columns now 1fr at <=560px; .sb-row margin 0 / display block;
2-col desktop intact). Documented both gotchas in fusion_claims/CLAUDE.md §47.
Bump fusion_claims 19.0.9.5.0 -> 19.0.9.6.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reported on the live wizard: no scroll on small screens, not responsive, fields
look unpadded.
- .o_service_booking: min-height:100% -> height:100% so the root is capped to the
action area and overflow:auto scrolls INTERNALLY (min-height let it grow to
content height, so the clipping action container never scrolled).
- input/select/textarea.f: padding 10px 12px !important + line-height 1.4 so
Odoo's backend input normalisation can't strip the field padding.
- add a <=560px media query collapsing the .two/.three sub-grids, wrapping the
time picker, and tightening margins (the main .grid already collapses at 780px).
- bump version 19.0.9.4.0 -> 19.0.9.5.0 (asset cache-bust).
Also harden scripts/verify_service_booking.sh: force-compile web.assets_backend +
web.assets_web_dark on the clone after tests, so a broken SCSS fails the deploy
gate BEFORE prod (a bad stylesheet would break the whole backend bundle; -u does
not compile assets — Odoo compiles them lazily).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Real install verified on the Westin clone; these were test-only bugs:
- Task-create tests hardcoded scheduled_date 2026-06-03, now in the past, which
the base _check_no_overlap rejects ('Cannot schedule tasks in the past'). Use
future dates (tz test pins a future July date so Toronto stays EDT for the
9:00->13:00 UTC assertion).
- Service-rate resolver tests created rows with seeded codes (callout_standard_normal,
per_km) -> UNIQUE(code) violation post-install. Assert against the seed instead.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The <template>_product_variant auto external-ID is not reliably created in this
Odoo 19 (only 5 exist on westin-v19; none for these products or product_labor_hourly),
so the rate rows' product_id refs failed at install: 'External ID not found:
..._product_variant'. Seed each product as model=product.product (the xmlid IS the
variant; name/price/uom/etc. delegate via _inherits) and reference it directly.
In-shop labour now uses a dedicated product_labour_inshop ($75) rather than reusing
product_labor_hourly, whose variant xmlid likewise does not exist. Caught on the
Westin clone install.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
product.template lost the separate purchase-UoM field uom_po_id in Odoo 19
(only uom_id remains). The plan's seed carried uom_po_id, which ParseErrors at
install: 'Invalid field uom_po_id in product.template'. Caught on first real
clone-install on the Westin Enterprise clone. The existing product_labor_hourly
uses uom_id only — match that.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Move the call-type select handler into onCallType() — OWL cannot compile a
multi-statement inline t-on body (was a render-breaking crash on mount).
- Replace color-mix() inside border shorthands with var(--sb-border) (Odoo-19
SCSS drops color-mix in a border shorthand).
- Technician placeholder option value '' (not 'false') so the required-tech
guard isn't bypassed.
- Remove dead setTiming(); null-coalesce the refdata onWillStart load.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review follow-up: the base fusion.technician.task.description is required=True and
non-in-store tasks require an address (_check_address_required). So:
- action_book_from_wizard now defaults description to 'Service booking' when the
payload carries neither description nor issue (avoids a required-field failure).
- test_task_without_order_is_allowed now sets description + is_in_store=True so it
exercises only the relaxed _check_order_link, not those unrelated base constraints.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Relaxes _check_order_link to a no-op (service bookings auto-create their SO;
in-shop/walk-in tasks may have none) and adds x_fc_is_service_repair on
sale.order. The 'Service Repair' crm.tag from the plan is intentionally
omitted: fusion_claims does not depend on crm and sale.order has no tag_ids;
the boolean flag is the repair-SO identity.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rename module fusion_authorizer_portal -> fusion_portal everywhere:
manifest/assets, controllers, models, views, JS (odoo.define + asset URLs),
migration MODULE constants; plus cross-module refs in fusion_schedule,
fusion_repairs, fusion_quotations (depends + inherit_id) and the pdf_filler
import in fusion_claims. Add rename_module.sql for the one-time in-place DB
rename (ir_module_module, ir_model_data, ir_ui_view.key,
ir_module_module_dependency) required on installed envs before -u fusion_portal.
Document the rename gotcha as rule 16 in CLAUDE.md.
Redesign the Accessibility Assessment selector: replace Font Awesome icon tiles
with photo-banner cards using 7 optimized images (1000x750 PNG -> 800x600 JPEG,
~8MB -> 488KB), per-type colour accent bar + centered pill button, hover
lift/zoom. Images ship as module static files so they deploy/sync with the module.
Drop the regenerable graphify-out cache from the module.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Aggressive sheet override: flex-basis 100%%, !important on width and
max-width to beat parent flex/media-query constraints. Also overrides
the o_form_sheet_bg wrapper.
Layout at xl (>=1200px) now splits into 3 columns:
- Col 1 (3/12): Your Activities + Bottlenecks
- Col 2 (5/12): ADP Pre + ADP Post + MOD
- Col 3 (4/12): Aging + Other Funders + Recent ADP Exports
Falls back to 5/7 on lg (Col 3 wraps below as full row) and stacked
single column on md and below.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The .o_fc_dashboard .o_form_sheet override wasn't winning specificity
against Odoo's default form-sheet constraints. Added a dedicated class
o_fc_dashboard_sheet directly on the <sheet> element + !important
overrides on max-width, width, and flex to stretch the sheet to the
full container width.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds 4 new sections:
- This Month rollup: submitted/approved/delivered/billed counts MTD
- Pipeline $ by stage: pre-submit / submitted / approved / ready-to-bill amounts
- Aging buckets: 30-59d, 60-89d, 90+ days
- Recent ADP Exports: last 5 with totals
Also overrides Odoo's form-sheet max-width on .o_fc_dashboard so the
dashboard uses the full browser width.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The dashboard action existed but no menuitem ever pointed to it (latent
bug in the original module). Adding menu_fusion_claims_dashboard as the
first child of menu_adp_claims_root so the dashboard becomes the default
landing for the Fusion Claims app.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Action-oriented dashboard replacing the existing 4-panel HTML overview:
posting-week banner with live countdown, 3 KPI tiles, 8 funder hotlinks,
ADP + MOD workflow flag tiles, role-aware filtering, dark-mode aware SCSS.
Spec captures all design decisions from the brainstorm session; ready to
hand off to writing-plans.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switched the section title from group string= (which Odoo was rendering
as a left-side column label) to a real <separator/>, so the heading
sits above the radio and the options use the full form width.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reverts the label shortening and instead sets col=1 on the radio group
so the group's inner layout is a single column. With the full wizard
width available, the full labels fit on one line each.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The group title already says "How were pages 11 & 12 provided?", so the
radio labels don't need to repeat "Pages 11 & 12". Shortened to:
"Inside the original application" / "Separate file" / "Sign remotely".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps fusion_claims version to bust the asset bundle cache after the
Application Received wizard refactor.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three-mode radio at the top of the Application Received wizard. The
Signed Pages 11 & 12 group is only shown in Separate mode; the remote
sign banner/button is only shown in Remote mode. Adds a read-only
'Detected pages' indicator next to the uploaded original PDF.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds intake_mode (bundled / separate / remote) so staff can mark
applications received with a single bundled PDF, the existing
separate-pages-file flow, or a pending remote signature. Folds in
content-based PDF validation, a friendlier status-gate message,
and a page-count helper for the original application.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The signed-pages verification step on case close now treats the bundled
flag as 'pages present', matching the ready-for-submission gate and the
audit trail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both the has_documents indicator and the action_confirm missing-items
gate now read x_fc_has_signed_pages_11_12, so orders with pages 11 & 12
bundled inside the original PDF can move to Ready for Submission without
a separate signed-pages file.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
x_fc_trail_has_signed_pages now reads x_fc_has_signed_pages_11_12, so
the trail correctly shows complete when pages 11 & 12 are bundled inside
the original application.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New boolean on sale.order tracks whether pages 11 & 12 are bundled
inside the original application PDF. Computed helper
x_fc_has_signed_pages_11_12 ORs bundled flag with separate-file and
remote-signing presence so downstream gates can read one field.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>