refactor(fusion_portal): rename from fusion_authorizer_portal + modern photo cards on accessibility selector

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>
This commit is contained in:
gsinghpal
2026-06-01 22:38:14 -04:00
parent c527c7cade
commit 747c814249
112 changed files with 391 additions and 12242 deletions

View File

@@ -33,6 +33,8 @@
15. **There is NO `sale.subscription` model in Odoo 19** (Enterprise `sale_subscription`). A subscription is a **`sale.order`** with `is_subscription=True`, `plan_id` → **`sale.subscription.plan`** (the recurrence), plus `subscription_state` / `next_invoice_date` / `recurring_monthly`. Any Many2one or relation that targets "a subscription" must point at `sale.order` (filter `domain=[('is_subscription','=',True)]`) — **not** `sale.subscription`, which does not exist and fails at install. The surviving `sale.subscription.*` records are only the plan + wizards/reports (`sale.subscription.plan`, `sale.subscription.report`, `sale.subscription.change.customer.wizard`, `sale.subscription.close.reason.wizard`). Verified on live `nexamain` (odoo-nexa, 19.0): `SELECT model FROM ir_model WHERE model LIKE 'sale.subscription%'`.
16. **Renaming a module's technical name needs a DB rename, not just a folder rename.** The technical name is baked into the database: `ir_module_module.name`, every external ID in `ir_model_data.module`, each view's `ir_ui_view.key` prefix, and the `ir_module_module_dependency.name` rows of every module that depends on it. Rename only the folder + in-code references and Odoo treats the new name as a fresh uninstalled module — installing it **duplicates** groups/templates/menus and **orphans** all existing data. On every DB that already has it installed, run an in-place SQL rename (the 4 tables above) **before** `-u <newname>`; a fresh DB needs nothing. Reference script + full rationale: [`fusion_portal/rename_module.sql`](fusion_portal/rename_module.sql) (written for the `fusion_authorizer_portal` → `fusion_portal` rename). Also update cross-module `depends`, `inherit_id="<old>.view"`, `t-call`, `env.ref('<old>.xmlid')`, asset paths (`<old>/static/...`), and `from odoo.addons.<old>... import`.
## Card Styling — Copy Odoo's Kanban Pattern
Don't rely on `var(--bs-border-color)` or `var(--bs-body-bg)` for card surfaces — they drift between themes/addons and often render **invisible**. Odoo's own kanban (`.o_kanban_record`) uses **explicit hex** values:
```css
@@ -94,7 +96,7 @@ Odoo content-hashes the compiled bundle URL (`/web/assets/<hash>/...`). When CSS
## Module-Specific Notes
- **fusion_clock** — developed in **Claude Code** (no longer Cursor; no concurrent-editing conflicts). Changed a lot recently (NFC kiosk: tap-to-clock, enrollment + program-from-unknown-tap, manager page, sounds, screen lock, guided profile-photo capture, faster animations). Still read files fresh before editing rather than assuming the layout. Live on entech (`odoo-entech` / LXC 111 on `pve-worker5`).
- **fusion_repairs** — read [`fusion_repairs/cloud.md`](fusion_repairs/cloud.md) before feature work. **Version `19.0.2.2.4`.** Bundles 111 shipped in repo (intake, portals, dashboard, pricing, flowcharts, parts/PO). **Not production-deployed** to Westin as of 2026-05-27. Local: `docker exec odoo-modsdev-app odoo -d fusion-dev -u fusion_repairs --stop-after-init`. Outstanding: RingCentral SMS, C2 history sidebar UI, office follow-up crons (config keys only), `tests/`, more flowchart content, sales-rep dashboard tile in `fusion_authorizer_portal`.
- **fusion_repairs** — read [`fusion_repairs/cloud.md`](fusion_repairs/cloud.md) before feature work. **Version `19.0.2.2.4`.** Bundles 111 shipped in repo (intake, portals, dashboard, pricing, flowcharts, parts/PO). **Not production-deployed** to Westin as of 2026-05-27. Local: `docker exec odoo-modsdev-app odoo -d fusion-dev -u fusion_repairs --stop-after-init`. Outstanding: RingCentral SMS, C2 history sidebar UI, office follow-up crons (config keys only), `tests/`, more flowchart content, sales-rep dashboard tile in `fusion_portal`.
## Workflow
- Local dev: `docker exec odoo-modsdev-app odoo -d fusion-dev -u <module> --stop-after-init`

View File

@@ -28,7 +28,7 @@
'website',
'mail',
'fusion_claims',
'fusion_authorizer_portal',
'fusion_portal',
],
'data': [
'security/security.xml',

View File

@@ -109,7 +109,7 @@ Every feature below has been accepted for inclusion (full scope). Phase assignme
| T1 | **Open in Maps button on task** | 2 | `geo:` / Apple Maps URL; one-tap |
| T2 | **AI pre-visit brief on mobile form** | 2 | Surfaces `x_fc_ai_summary` prominently; "What to bring" + safety flags |
| T3 | Labour timer via fusion_clock | 3 | Tap Start/Pause; final time pre-fills visit report |
| T4 | **Client signature on completion** | 2 | OWL signature pad on visit report wizard; attached to repair (pattern from [`fusion_authorizer_portal`](fusion_authorizer_portal)) |
| T4 | **Client signature on completion** | 2 | OWL signature pad on visit report wizard; attached to repair (pattern from [`fusion_portal`](fusion_portal)) |
| T5 | "Found another issue" button | 2 | Spawn new repair from current visit, same partner, different equipment |
| T6 | Parts replaced — serial capture | 3 | Scan/type replaced part serials; stores for OEM warranty + traceability |
| T7 | No-show photo proof | 3 | "Client not home" → camera → photo attached → repair flagged + service-call fee added |
@@ -164,11 +164,11 @@ Every feature below has been accepted for inclusion (full scope). Phase assignme
| CL19 | **Voice input → AI transcription** | 4 | Client speaks the problem into mic, AI transcribes + classifies |
| CL20 | **Resolution survey + Google review** | 2 | After "resolved" outcome, ask "save you time today?" + Google review CTA |
### Sales rep portal (mirrors fusion_authorizer_portal pattern)
### Sales rep portal (mirrors fusion_portal pattern)
| ID | Feature | Phase | Notes |
|----|---------|-------|-------|
| S1 | **Sales rep web intake form** | 1 | `/my/repair/new` — same question flow as backend wizard, mobile-friendly. Reuses `is_sales_rep_portal` flag on `res.partner` from [`fusion_authorizer_portal/security/portal_security.xml`](fusion_authorizer_portal/security/portal_security.xml) line 11 |
| S1 | **Sales rep web intake form** | 1 | `/my/repair/new` — same question flow as backend wizard, mobile-friendly. Reuses `is_sales_rep_portal` flag on `res.partner` from [`fusion_portal/security/portal_security.xml`](fusion_portal/security/portal_security.xml) line 11 |
| S2 | Sales rep dashboard tile | 1 | Add "Service Calls" tile to `/my/sales-rep/dashboard` showing count of repairs they logged + recent 5 |
| S3 | **My Service Calls** list page | 1 | `/my/repairs` — sales rep sees their submitted repairs, status, assigned tech, scheduled date |
| S4 | View repair status from portal | 1 | `/my/repair/<id>` — read-only timeline, chatter for non-internal messages, ability to add a comment |
@@ -183,7 +183,7 @@ Every feature below has been accepted for inclusion (full scope). Phase assignme
**Routing namespace:** `/my/repair/*` (intake + my list) and a `/my/sales-rep/repairs` summary route added to the existing sales rep dashboard.
**Record rule** (mirrors [`fusion_authorizer_portal/security/portal_security.xml`](fusion_authorizer_portal/security/portal_security.xml) line 129 pattern):
**Record rule** (mirrors [`fusion_portal/security/portal_security.xml`](fusion_portal/security/portal_security.xml) line 129 pattern):
```xml
<record id="rule_repair_order_sales_rep_portal" model="ir.rule">
@@ -236,7 +236,7 @@ Every feature below has been accepted for inclusion (full scope). Phase assignme
'website', # QWeb portal templates
'fusion_tasks', # technician tasks + fusion.email.builder.mixin
'fusion_poynt', # payment collection
'fusion_authorizer_portal', # sales rep portal flag + group + dashboard scaffold
'fusion_portal', # sales rep portal flag + group + dashboard scaffold
]
# Phase 3 soft-add: 'appointment', 'fusion_schedule' for client self-booking
# Phase 3 soft-add: 'fusion_clock' for tech labour timer (T3)
@@ -245,7 +245,7 @@ Every feature below has been accepted for inclusion (full scope). Phase assignme
# Phase 3 soft-add: 'fusion_ringcentral' for SMS verify (CL12) + voicemail greeting (CL16) + caller-ID launch (Phase 4)
# Phase 4 soft-add: 'fusion_shipping', 'fusion_canada_post' for mail-in repairs (M4)
# Soft-call (no depend) at runtime: 'fusion.api.service' via try/except per fusion-api-integration rule
# NOTE: fusion_authorizer_portal transitively pulls fusion_claims — accepted for portal reuse
# NOTE: fusion_portal transitively pulls fusion_claims — accepted for portal reuse
```
Before coding any Odoo 19 view/JS, read reference files from local OrbStack Docker per project rules.
@@ -712,7 +712,7 @@ Themes adapt via project SCSS rules — no hardcoded colours per CLAUDE.md.
---
## Sales rep portal (Phase 1 — mirrors fusion_authorizer_portal)
## Sales rep portal (Phase 1 — mirrors fusion_portal)
**Goal:** A sales rep on the road takes a client call and submits a repair request from their phone — same intake flow as backend CS wizard, no Odoo login screen.
@@ -720,10 +720,10 @@ Themes adapt via project SCSS rules — no hardcoded colours per CLAUDE.md.
| Option | Recommendation |
|--------|----------------|
| **Hard depend on `fusion_authorizer_portal`** | RECOMMENDED — reuses the existing `is_sales_rep_portal` flag, `group_sales_rep_portal`, sales rep dashboard scaffolding. Transitively pulls fusion_claims (already core in your stack). |
| **Hard depend on `fusion_portal`** | RECOMMENDED — reuses the existing `is_sales_rep_portal` flag, `group_sales_rep_portal`, sales rep dashboard scaffolding. Transitively pulls fusion_claims (already core in your stack). |
| Soft depend (try/except + own fallback flag) | Possible but doubles the code: own `is_sales_rep_portal` mirror + own group. Only worth it if you ever want fusion_repairs standalone. |
We go with hard depend. Add `fusion_authorizer_portal` to the manifest `depends` list.
We go with hard depend. Add `fusion_portal` to the manifest `depends` list.
### Architecture
@@ -740,7 +740,7 @@ flowchart LR
### Controller layout ([`controllers/portal_sales_rep_repair.py`](fusion_repairs/controllers/portal_sales_rep_repair.py))
Routes scoped to `is_sales_rep_portal` users (gate at controller top, pattern from [`fusion_authorizer_portal/controllers/portal_assessment.py`](fusion_authorizer_portal/controllers/portal_assessment.py) line 25):
Routes scoped to `is_sales_rep_portal` users (gate at controller top, pattern from [`fusion_portal/controllers/portal_assessment.py`](fusion_portal/controllers/portal_assessment.py) line 25):
| Route | Type | Purpose |
|-------|------|---------|
@@ -767,14 +767,14 @@ Avoids the trap of two intake flows drifting out of sync.
### Templates ([`views/portal_sales_rep_templates.xml`](fusion_repairs/views/portal_sales_rep_templates.xml))
QWeb templates following [`fusion_authorizer_portal/views/portal_assessment_express.xml`](fusion_authorizer_portal/views/portal_assessment_express.xml) style:
QWeb templates following [`fusion_portal/views/portal_assessment_express.xml`](fusion_portal/views/portal_assessment_express.xml) style:
- `portal_repair_intake_form` — multi-step (accordion or stepper) with same 5 sections as backend wizard
- `portal_repair_list` — card list with status badge, scheduled date, tech name
- `portal_repair_detail` — timeline + chatter
- `portal_repair_intake_thanks` — confirmation page with "Submit Another" button (common on multi-call days)
Reuses portal gradient/header style via `portal_gradient` template variable already set by [`portal_main.home()`](fusion_authorizer_portal/controllers/portal_main.py) line 85.
Reuses portal gradient/header style via `portal_gradient` template variable already set by [`portal_main.home()`](fusion_portal/controllers/portal_main.py) line 85.
### JS ([`static/src/js/portal_repair_intake.js`](fusion_repairs/static/src/js/portal_repair_intake.js))
@@ -860,7 +860,7 @@ Extend repair order form view with Intake tab (answers), Maintenance tab, and st
**Reused (do NOT recreate):**
- [`fusion_tasks.group_field_technician`](fusion_tasks/security/security.xml) — for technician access to `repair.order` (parallel to existing tech task rules). Same domain `('technician_id', '=', user.id)` adapted as `('x_fc_technician_task_ids.technician_id', '=', user.id)` on repair orders
- [`fusion_authorizer_portal.group_sales_rep_portal`](fusion_authorizer_portal/security/portal_security.xml) — for sales rep portal access (see Sales rep portal section)
- [`fusion_portal.group_sales_rep_portal`](fusion_portal/security/portal_security.xml) — for sales rep portal access (see Sales rep portal section)
**New groups specific to fusion_repairs:**
- `group_fusion_repairs_user` — CS intake, view repairs (implied by `base.group_user`)
@@ -896,7 +896,7 @@ Extend repair order form view with Intake tab (answers), Maintenance tab, and st
**Sales rep portal (S1-S4, S6, S8):**
- Portal controllers `/my/repair/new`, `/my/repairs`, `/my/repair/<id>`
- Mobile-friendly QWeb templates following [`fusion_authorizer_portal/views/portal_assessment_express.xml`](fusion_authorizer_portal/views/portal_assessment_express.xml) style
- Mobile-friendly QWeb templates following [`fusion_portal/views/portal_assessment_express.xml`](fusion_portal/views/portal_assessment_express.xml) style
- Same intake question flow as backend (via shared service layer)
- Mobile photo / camera capture
- Client history sidebar exposed in portal form
@@ -1137,7 +1137,7 @@ After implementation, test on local dev only:
| Backend wizard and sales rep portal drift apart | Both call the same `fusion.repair.intake.service.create_repair_orders(payload)` AbstractModel method; no duplicate business logic |
| Sales rep accidentally sees other reps' repairs | Record rule `('x_fc_intake_user_id', '=', user.id)` scoped to `base.group_portal`; integration test asserts cross-rep isolation |
| Portal form abandoned mid-flow on call drop | Save partial state to `localStorage` keyed by partner + timestamp; "Resume" prompt on `/my/repair/new` if recent draft exists |
| fusion_authorizer_portal install becomes mandatory | Documented in module description; if a deployment doesn't want fusion_authorizer_portal, fall back to a `fusion_repairs_portal_lite` companion module that recreates only the `is_sales_rep_portal` flag |
| fusion_portal install becomes mandatory | Documented in module description; if a deployment doesn't want fusion_portal, fall back to a `fusion_repairs_portal_lite` companion module that recreates only the `is_sales_rep_portal` flag |
| **Public form spam / abuse** | reCAPTCHA v3 + honeypot + per-IP rate limit + per-phone rate limit + SMS verify before submit (Phase 2). Block ASN ranges via Odoo's `ir.rule` if needed |
| **AI giving unsafe medical advice** | Strict system prompt + JSON schema validation + keyword filter (rejects "diagnose", "you have", "stop using"); falls back to deterministic rules on any malformed/unsafe output; legal disclaimer "this is not medical advice" shown on every AI step |
| **AI cost runaway from public traffic** | Hard daily/monthly budget cap via `fusion.api.service`; CAPTCHA gates AI calls; cache results for identical symptom-category pairs; deterministic fallback never costs anything |

Binary file not shown.

View File

@@ -1,883 +0,0 @@
# Graph Report - /Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal (2026-04-22)
## Corpus Check
- 33 files · ~40,589 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 470 nodes · 550 edges · 123 communities detected
- Extraction: 89% EXTRACTED · 11% INFERRED · 0% AMBIGUOUS · INFERRED: 60 edges (avg confidence: 0.76)
- Token cost: 0 input · 0 output
## Community Hubs (Navigation)
- [[_COMMUNITY_Community 0|Community 0]]
- [[_COMMUNITY_Community 1|Community 1]]
- [[_COMMUNITY_Community 2|Community 2]]
- [[_COMMUNITY_Community 3|Community 3]]
- [[_COMMUNITY_Community 4|Community 4]]
- [[_COMMUNITY_Community 5|Community 5]]
- [[_COMMUNITY_Community 6|Community 6]]
- [[_COMMUNITY_Community 7|Community 7]]
- [[_COMMUNITY_Community 8|Community 8]]
- [[_COMMUNITY_Community 9|Community 9]]
- [[_COMMUNITY_Community 10|Community 10]]
- [[_COMMUNITY_Community 11|Community 11]]
- [[_COMMUNITY_Community 12|Community 12]]
- [[_COMMUNITY_Community 13|Community 13]]
- [[_COMMUNITY_Community 14|Community 14]]
- [[_COMMUNITY_Community 15|Community 15]]
- [[_COMMUNITY_Community 16|Community 16]]
- [[_COMMUNITY_Community 17|Community 17]]
- [[_COMMUNITY_Community 18|Community 18]]
- [[_COMMUNITY_Community 19|Community 19]]
- [[_COMMUNITY_Community 20|Community 20]]
- [[_COMMUNITY_Community 21|Community 21]]
- [[_COMMUNITY_Community 22|Community 22]]
- [[_COMMUNITY_Community 23|Community 23]]
- [[_COMMUNITY_Community 24|Community 24]]
- [[_COMMUNITY_Community 25|Community 25]]
- [[_COMMUNITY_Community 26|Community 26]]
- [[_COMMUNITY_Community 27|Community 27]]
- [[_COMMUNITY_Community 28|Community 28]]
- [[_COMMUNITY_Community 29|Community 29]]
- [[_COMMUNITY_Community 30|Community 30]]
- [[_COMMUNITY_Community 31|Community 31]]
- [[_COMMUNITY_Community 32|Community 32]]
- [[_COMMUNITY_Community 33|Community 33]]
- [[_COMMUNITY_Community 34|Community 34]]
- [[_COMMUNITY_Community 35|Community 35]]
- [[_COMMUNITY_Community 36|Community 36]]
- [[_COMMUNITY_Community 37|Community 37]]
- [[_COMMUNITY_Community 38|Community 38]]
- [[_COMMUNITY_Community 39|Community 39]]
- [[_COMMUNITY_Community 40|Community 40]]
- [[_COMMUNITY_Community 41|Community 41]]
- [[_COMMUNITY_Community 42|Community 42]]
- [[_COMMUNITY_Community 43|Community 43]]
- [[_COMMUNITY_Community 44|Community 44]]
- [[_COMMUNITY_Community 45|Community 45]]
- [[_COMMUNITY_Community 46|Community 46]]
- [[_COMMUNITY_Community 47|Community 47]]
- [[_COMMUNITY_Community 48|Community 48]]
- [[_COMMUNITY_Community 49|Community 49]]
- [[_COMMUNITY_Community 50|Community 50]]
- [[_COMMUNITY_Community 51|Community 51]]
- [[_COMMUNITY_Community 52|Community 52]]
- [[_COMMUNITY_Community 53|Community 53]]
- [[_COMMUNITY_Community 54|Community 54]]
- [[_COMMUNITY_Community 55|Community 55]]
- [[_COMMUNITY_Community 56|Community 56]]
- [[_COMMUNITY_Community 57|Community 57]]
- [[_COMMUNITY_Community 58|Community 58]]
- [[_COMMUNITY_Community 59|Community 59]]
- [[_COMMUNITY_Community 60|Community 60]]
- [[_COMMUNITY_Community 61|Community 61]]
- [[_COMMUNITY_Community 62|Community 62]]
- [[_COMMUNITY_Community 63|Community 63]]
- [[_COMMUNITY_Community 64|Community 64]]
- [[_COMMUNITY_Community 65|Community 65]]
- [[_COMMUNITY_Community 66|Community 66]]
- [[_COMMUNITY_Community 67|Community 67]]
- [[_COMMUNITY_Community 68|Community 68]]
- [[_COMMUNITY_Community 69|Community 69]]
- [[_COMMUNITY_Community 70|Community 70]]
- [[_COMMUNITY_Community 71|Community 71]]
- [[_COMMUNITY_Community 72|Community 72]]
- [[_COMMUNITY_Community 73|Community 73]]
- [[_COMMUNITY_Community 74|Community 74]]
- [[_COMMUNITY_Community 75|Community 75]]
- [[_COMMUNITY_Community 76|Community 76]]
- [[_COMMUNITY_Community 77|Community 77]]
- [[_COMMUNITY_Community 78|Community 78]]
- [[_COMMUNITY_Community 79|Community 79]]
- [[_COMMUNITY_Community 80|Community 80]]
- [[_COMMUNITY_Community 81|Community 81]]
- [[_COMMUNITY_Community 82|Community 82]]
- [[_COMMUNITY_Community 83|Community 83]]
- [[_COMMUNITY_Community 84|Community 84]]
- [[_COMMUNITY_Community 85|Community 85]]
- [[_COMMUNITY_Community 86|Community 86]]
- [[_COMMUNITY_Community 87|Community 87]]
- [[_COMMUNITY_Community 88|Community 88]]
- [[_COMMUNITY_Community 89|Community 89]]
- [[_COMMUNITY_Community 90|Community 90]]
- [[_COMMUNITY_Community 91|Community 91]]
- [[_COMMUNITY_Community 92|Community 92]]
- [[_COMMUNITY_Community 93|Community 93]]
- [[_COMMUNITY_Community 94|Community 94]]
- [[_COMMUNITY_Community 95|Community 95]]
- [[_COMMUNITY_Community 96|Community 96]]
- [[_COMMUNITY_Community 97|Community 97]]
- [[_COMMUNITY_Community 98|Community 98]]
- [[_COMMUNITY_Community 99|Community 99]]
- [[_COMMUNITY_Community 100|Community 100]]
- [[_COMMUNITY_Community 101|Community 101]]
- [[_COMMUNITY_Community 102|Community 102]]
- [[_COMMUNITY_Community 103|Community 103]]
- [[_COMMUNITY_Community 104|Community 104]]
- [[_COMMUNITY_Community 105|Community 105]]
- [[_COMMUNITY_Community 106|Community 106]]
- [[_COMMUNITY_Community 107|Community 107]]
- [[_COMMUNITY_Community 108|Community 108]]
- [[_COMMUNITY_Community 109|Community 109]]
- [[_COMMUNITY_Community 110|Community 110]]
- [[_COMMUNITY_Community 111|Community 111]]
- [[_COMMUNITY_Community 112|Community 112]]
- [[_COMMUNITY_Community 113|Community 113]]
- [[_COMMUNITY_Community 114|Community 114]]
- [[_COMMUNITY_Community 115|Community 115]]
- [[_COMMUNITY_Community 116|Community 116]]
- [[_COMMUNITY_Community 117|Community 117]]
- [[_COMMUNITY_Community 118|Community 118]]
- [[_COMMUNITY_Community 119|Community 119]]
- [[_COMMUNITY_Community 120|Community 120]]
- [[_COMMUNITY_Community 121|Community 121]]
- [[_COMMUNITY_Community 122|Community 122]]
## God Nodes (most connected - your core abstractions)
1. `create()` - 22 edges
2. `FusionAssessment` - 20 edges
3. `AuthorizerPortal` - 19 edges
4. `ResPartner` - 16 edges
5. `accessibility_assessment_save()` - 12 edges
6. `FusionAccessibilityAssessment` - 11 edges
7. `selectField()` - 11 edges
8. `PDFTemplateFiller` - 10 edges
9. `SaleOrder` - 10 edges
10. `FusionPdfTemplate` - 9 edges
## Surprising Connections (you probably didn't know these)
- `create_field()` --calls--> `create()` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/controllers/pdf_editor.py → /Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/accessibility_assessment.py
- `FusionPdfTemplatePreview` --uses--> `PDFTemplateFiller` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/pdf_template.py → /Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/utils/pdf_filler.py
- `FusionPdfTemplateField` --uses--> `PDFTemplateFiller` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/pdf_template.py → /Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/utils/pdf_filler.py
- `Generate PNG preview images from the PDF using poppler (pdftoppm). Falls` --uses--> `PDFTemplateFiller` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/pdf_template.py → /Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/utils/pdf_filler.py
- `Set template to active.` --uses--> `PDFTemplateFiller` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/pdf_template.py → /Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/utils/pdf_filler.py
## Communities
### Community 0 - "Community 0"
Cohesion: 0.05
Nodes (29): accessibility_bathroom(), accessibility_ceiling_lift(), accessibility_ramp(), accessibility_stairlift_curved(), accessibility_stairlift_straight(), accessibility_tub_cutout(), accessibility_vpl(), home() (+21 more)
### Community 1 - "Community 1"
Cohesion: 0.06
Nodes (20): Assign role-specific portal groups to a portal user based on contact checkboxes., Assign backend groups to an internal user based on contact checkboxes. A, Grant portal access to this partner, or update permissions for existing users., Create a role-specific welcome Knowledge article for the new portal user., Send a professional portal invitation email to the partner. Gen, Resend portal invitation email to an existing portal user., Open the list of assigned sale orders, Open the list of assessments for this partner (+12 more)
### Community 2 - "Community 2"
Cohesion: 0.07
Nodes (19): create(), FusionAssessment, Format assessment data as HTML table for chatter, Format wheelchair specifications for the sale order notes (legacy), Generate document records for signed pages, Send email notifications when assessment is completed, View related documents, View the created sale order (+11 more)
### Community 3 - "Community 3"
Cohesion: 0.08
Nodes (15): create(), FusionAccessibilityAssessment, Complete the assessment and create a Sale Order. 2026-04 portal audit f, Add a tag to the sale order based on assessment type, Copy assessment photos to sale order chatter, Send email notification to office about assessment completion, Schedule a follow-up activity for the sales rep, Find or create a partner for the client (+7 more)
### Community 4 - "Community 4"
Cohesion: 0.08
Nodes (20): Complete express assessment and create draft sale order (no signatures required), CustomerPortal, Ensure all module views are active after install/update. Odoo silently deac, _reactivate_views(), AssessmentPortal, portal_assessment_express_edit(), portal_assessment_express_new(), portal_assessment_express_save() (+12 more)
### Community 5 - "Community 5"
Cohesion: 0.09
Nodes (14): authorizer_cases_search(), sales_rep_cases_search(), get_authorizer_portal_cases(), get_sales_rep_portal_cases(), Open composer to send message to authorizer only, Send email when an authorizer is assigned to the order, View portal documents, Get data for portal display, excluding sensitive information (+6 more)
### Community 6 - "Community 6"
Cohesion: 0.12
Nodes (14): preview_pdf(), _draw_field(), fill_template(), PDFTemplateFiller, Generic PDF template filler. Works with any template, any number of pages., create(), FusionPdfTemplate, FusionPdfTemplateField (+6 more)
### Community 7 - "Community 7"
Cohesion: 0.11
Nodes (14): accessibility_assessment_save(), AuthorizerPortal, Portal controller for Authorizers (OTs/Therapists), Parse straight stair lift specific fields, Parse curved stair lift specific fields, Parse VPL specific fields, Parse ceiling lift specific fields, Parse ramp specific fields (+6 more)
### Community 8 - "Community 8"
Cohesion: 0.21
Nodes (22): buildDataKeyOptions(), buildDataKeysSidebar(), init(), jsonrpc(), loadFields(), normalize(), onFieldDragStart(), renderFieldMarker() (+14 more)
### Community 9 - "Community 9"
Cohesion: 0.29
Nodes (11): checkClockStatus(), ensureModal(), getLocation(), hideModal(), isTechnicianPortal(), logLocation(), showDeniedBanner(), showModal() (+3 more)
### Community 10 - "Community 10"
Cohesion: 0.18
Nodes (3): ADPDocument, Download the document, Get the download URL for portal access
### Community 11 - "Community 11"
Cohesion: 0.2
Nodes (5): create_field(), FusionPdfEditorController, Controller for the PDF field position visual editor., update_field(), upload_preview_image()
### Community 12 - "Community 12"
Cohesion: 0.38
Nodes (4): page11_sign_form(), page11_sign_submit(), Page11PublicSignController, Look up and validate a signing request by token.
### Community 13 - "Community 13"
Cohesion: 0.4
Nodes (1): migrate()
### Community 14 - "Community 14"
Cohesion: 0.5
Nodes (1): AuthorizerComment
### Community 15 - "Community 15"
Cohesion: 0.83
Nodes (3): _detectAndSaveTimezone(), _getCookie(), start()
### Community 16 - "Community 16"
Cohesion: 0.67
Nodes (1): FusionLoanerCheckoutAssessment
### Community 17 - "Community 17"
Cohesion: 0.67
Nodes (0):
### Community 18 - "Community 18"
Cohesion: 1.0
Nodes (2): registerPushSubscription(), urlBase64ToUint8Array()
### Community 19 - "Community 19"
Cohesion: 1.0
Nodes (0):
### Community 20 - "Community 20"
Cohesion: 1.0
Nodes (0):
### Community 21 - "Community 21"
Cohesion: 1.0
Nodes (0):
### Community 22 - "Community 22"
Cohesion: 1.0
Nodes (0):
### Community 23 - "Community 23"
Cohesion: 1.0
Nodes (1): Fill a PDF template by overlaying text/checkmarks/signatures at configured posit
### Community 24 - "Community 24"
Cohesion: 1.0
Nodes (1): Draw a single field onto the reportlab canvas. Args: c: rep
### Community 25 - "Community 25"
Cohesion: 1.0
Nodes (1): Override create to generate reference number
### Community 26 - "Community 26"
Cohesion: 1.0
Nodes (1): Get authorizer from x_fc_authorizer_id field
### Community 27 - "Community 27"
Cohesion: 1.0
Nodes (1): Get cases for authorizer portal with optional search
### Community 28 - "Community 28"
Cohesion: 1.0
Nodes (1): Get cases for sales rep portal with optional search
### Community 29 - "Community 29"
Cohesion: 1.0
Nodes (1): Override create to handle revision numbering
### Community 30 - "Community 30"
Cohesion: 1.0
Nodes (1): Get documents for a sale order, optionally filtered by type
### Community 31 - "Community 31"
Cohesion: 1.0
Nodes (1): Get all revisions of a specific document type
### Community 32 - "Community 32"
Cohesion: 1.0
Nodes (1): Override create to set author from current user if not provided
### Community 33 - "Community 33"
Cohesion: 1.0
Nodes (1): Kanban group expansion — always show all 6 workflow states.
### Community 34 - "Community 34"
Cohesion: 1.0
Nodes (1): Straight stair lift: (steps × nose_to_nose) + 13" top landing
### Community 35 - "Community 35"
Cohesion: 1.0
Nodes (1): Use manual override if provided, otherwise use calculated
### Community 36 - "Community 36"
Cohesion: 1.0
Nodes (1): Curved stair lift calculation: - 12" per step - 16" per curve
### Community 37 - "Community 37"
Cohesion: 1.0
Nodes (1): Use manual override if provided, otherwise use calculated
### Community 38 - "Community 38"
Cohesion: 1.0
Nodes (1): Ontario Building Code: 12 inches length per 1 inch height (1:12 ratio)
### Community 39 - "Community 39"
Cohesion: 1.0
Nodes (1): Landing required every 30 feet (360 inches)
### Community 40 - "Community 40"
Cohesion: 1.0
Nodes (1): Total length including landings (5 feet = 60 inches each)
### Community 41 - "Community 41"
Cohesion: 1.0
Nodes (1): Compute portal access status based on user account and login history.
### Community 42 - "Community 42"
Cohesion: 1.0
Nodes (1): Count sale orders where this partner is the authorizer
### Community 43 - "Community 43"
Cohesion: 1.0
Nodes (1): Count assessments where this partner is involved
### Community 44 - "Community 44"
Cohesion: 1.0
Nodes (1): Count sale orders assigned to this partner as delivery technician
### Community 45 - "Community 45"
Cohesion: 1.0
Nodes (0):
### Community 46 - "Community 46"
Cohesion: 1.0
Nodes (0):
### Community 47 - "Community 47"
Cohesion: 1.0
Nodes (0):
### Community 48 - "Community 48"
Cohesion: 1.0
Nodes (0):
### Community 49 - "Community 49"
Cohesion: 1.0
Nodes (0):
### Community 50 - "Community 50"
Cohesion: 1.0
Nodes (1): Display the Page 11 signing form.
### Community 51 - "Community 51"
Cohesion: 1.0
Nodes (1): Process the submitted Page 11 signature.
### Community 52 - "Community 52"
Cohesion: 1.0
Nodes (1): Download the signed Page 11 PDF.
### Community 53 - "Community 53"
Cohesion: 1.0
Nodes (1): Start a new assessment
### Community 54 - "Community 54"
Cohesion: 1.0
Nodes (1): View/edit an assessment
### Community 55 - "Community 55"
Cohesion: 1.0
Nodes (1): Save assessment data (create or update)
### Community 56 - "Community 56"
Cohesion: 1.0
Nodes (1): Signature capture page
### Community 57 - "Community 57"
Cohesion: 1.0
Nodes (1): Save a signature (AJAX)
### Community 58 - "Community 58"
Cohesion: 1.0
Nodes (1): Complete the assessment
### Community 59 - "Community 59"
Cohesion: 1.0
Nodes (1): Start a new express assessment (Page 1 - Equipment Selection)
### Community 60 - "Community 60"
Cohesion: 1.0
Nodes (1): Continue/edit an express assessment
### Community 61 - "Community 61"
Cohesion: 1.0
Nodes (1): Save express assessment data (create or update)
### Community 62 - "Community 62"
Cohesion: 1.0
Nodes (1): Public page for booking an accessibility assessment.
### Community 63 - "Community 63"
Cohesion: 1.0
Nodes (1): Process assessment booking form submission.
### Community 64 - "Community 64"
Cohesion: 1.0
Nodes (1): Render the visual field editor for a PDF template.
### Community 65 - "Community 65"
Cohesion: 1.0
Nodes (1): Return all fields for a template.
### Community 66 - "Community 66"
Cohesion: 1.0
Nodes (1): Update a field's position or properties.
### Community 67 - "Community 67"
Cohesion: 1.0
Nodes (1): Create a new field on a template.
### Community 68 - "Community 68"
Cohesion: 1.0
Nodes (1): Delete a field from a template.
### Community 69 - "Community 69"
Cohesion: 1.0
Nodes (1): Return the preview image URL for a specific page.
### Community 70 - "Community 70"
Cohesion: 1.0
Nodes (1): Upload a preview image for a template page directly from the editor.
### Community 71 - "Community 71"
Cohesion: 1.0
Nodes (1): Generate a preview filled PDF with sample data.
### Community 72 - "Community 72"
Cohesion: 1.0
Nodes (1): Auto-save browser-detected timezone to the user profile if not already set.
### Community 73 - "Community 73"
Cohesion: 1.0
Nodes (1): Override home to add ADP posting info for Fusion users
### Community 74 - "Community 74"
Cohesion: 1.0
Nodes (1): Authorizer dashboard - simplified mobile-first view
### Community 75 - "Community 75"
Cohesion: 1.0
Nodes (1): List of cases assigned to the authorizer
### Community 76 - "Community 76"
Cohesion: 1.0
Nodes (1): AJAX search endpoint for real-time search
### Community 77 - "Community 77"
Cohesion: 1.0
Nodes (1): Add a comment to a case - posts to sale order chatter and emails salesperson
### Community 78 - "Community 78"
Cohesion: 1.0
Nodes (1): Upload a document for a case
### Community 79 - "Community 79"
Cohesion: 1.0
Nodes (1): Download an attachment from sale order (original application, xml, proof of deli
### Community 80 - "Community 80"
Cohesion: 1.0
Nodes (1): View an approval photo
### Community 81 - "Community 81"
Cohesion: 1.0
Nodes (1): Sales rep dashboard with search and filters
### Community 82 - "Community 82"
Cohesion: 1.0
Nodes (1): List of cases for the sales rep
### Community 83 - "Community 83"
Cohesion: 1.0
Nodes (1): AJAX search endpoint for sales rep real-time search
### Community 84 - "Community 84"
Cohesion: 1.0
Nodes (1): View a specific case for sales rep
### Community 85 - "Community 85"
Cohesion: 1.0
Nodes (1): Add a comment to a case (sales rep) - posts to sale order chatter and emails aut
### Community 86 - "Community 86"
Cohesion: 1.0
Nodes (1): List of funding claims for the client
### Community 87 - "Community 87"
Cohesion: 1.0
Nodes (1): View a specific funding claim
### Community 88 - "Community 88"
Cohesion: 1.0
Nodes (1): Download a document from a funding claim
### Community 89 - "Community 89"
Cohesion: 1.0
Nodes (1): Download proof of delivery from a funding claim
### Community 90 - "Community 90"
Cohesion: 1.0
Nodes (1): Technician dashboard - today's schedule with timeline.
### Community 91 - "Community 91"
Cohesion: 1.0
Nodes (1): List of all tasks for the technician.
### Community 92 - "Community 92"
Cohesion: 1.0
Nodes (1): View a specific technician task.
### Community 93 - "Community 93"
Cohesion: 1.0
Nodes (1): Add notes (and optional photos) to a completed task. :param notes: text
### Community 94 - "Community 94"
Cohesion: 1.0
Nodes (1): Handle task status changes (start, complete, en_route, cancel). Location
### Community 95 - "Community 95"
Cohesion: 1.0
Nodes (1): Transcribe voice recording using OpenAI Whisper, translate to English.
### Community 96 - "Community 96"
Cohesion: 1.0
Nodes (1): Use GPT to clean up and format raw notes text.
### Community 97 - "Community 97"
Cohesion: 1.0
Nodes (1): Format transcription with GPT and complete the task.
### Community 98 - "Community 98"
Cohesion: 1.0
Nodes (1): Next day preparation view.
### Community 99 - "Community 99"
Cohesion: 1.0
Nodes (1): View schedule for a specific date.
### Community 100 - "Community 100"
Cohesion: 1.0
Nodes (1): Admin map view showing latest technician locations using Google Maps.
### Community 101 - "Community 101"
Cohesion: 1.0
Nodes (1): Log the technician's current GPS location.
### Community 102 - "Community 102"
Cohesion: 1.0
Nodes (1): Check if the current technician is clocked in. Returns {clocked_in: boo
### Community 103 - "Community 103"
Cohesion: 1.0
Nodes (1): Save the technician's personal start location.
### Community 104 - "Community 104"
Cohesion: 1.0
Nodes (1): Register a push notification subscription.
### Community 105 - "Community 105"
Cohesion: 1.0
Nodes (1): Legacy: List of deliveries for the technician (redirects to tasks).
### Community 106 - "Community 106"
Cohesion: 1.0
Nodes (1): View a specific delivery for technician (legacy, still works).
### Community 107 - "Community 107"
Cohesion: 1.0
Nodes (1): POD signature capture page - accessible by technicians and sales reps
### Community 108 - "Community 108"
Cohesion: 1.0
Nodes (1): Save POD signature via AJAX
### Community 109 - "Community 109"
Cohesion: 1.0
Nodes (1): Task-level POD signature capture page (works for all tasks including shadow).
### Community 110 - "Community 110"
Cohesion: 1.0
Nodes (1): Save POD signature directly on a task.
### Community 111 - "Community 111"
Cohesion: 1.0
Nodes (1): Show the accessibility assessment type selector
### Community 112 - "Community 112"
Cohesion: 1.0
Nodes (1): List all accessibility assessments for the current user (sales rep or authorizer
### Community 113 - "Community 113"
Cohesion: 1.0
Nodes (1): Straight stair lift assessment form
### Community 114 - "Community 114"
Cohesion: 1.0
Nodes (1): Curved stair lift assessment form
### Community 115 - "Community 115"
Cohesion: 1.0
Nodes (1): Vertical Platform Lift assessment form
### Community 116 - "Community 116"
Cohesion: 1.0
Nodes (1): Ceiling Lift assessment form
### Community 117 - "Community 117"
Cohesion: 1.0
Nodes (1): Custom Ramp assessment form
### Community 118 - "Community 118"
Cohesion: 1.0
Nodes (1): Bathroom Modification assessment form
### Community 119 - "Community 119"
Cohesion: 1.0
Nodes (1): Tub Cutout assessment form
### Community 120 - "Community 120"
Cohesion: 1.0
Nodes (1): Save an accessibility assessment and optionally create a Sale Order
### Community 121 - "Community 121"
Cohesion: 1.0
Nodes (1): Render the rental pickup inspection form for the technician.
### Community 122 - "Community 122"
Cohesion: 1.0
Nodes (1): Save the rental inspection results.
## Knowledge Gaps
- **177 isolated node(s):** `Ensure all module views are active after install/update. Odoo silently deac`, `Generic PDF template filler. Works with any template, any number of pages.`, `Fill a PDF template by overlaying text/checkmarks/signatures at configured posit`, `Draw a single field onto the reportlab canvas. Args: c: rep`, `Override create to generate reference number` (+172 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **Thin community `Community 19`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 20`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 21`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 22`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 23`** (1 nodes): `Fill a PDF template by overlaying text/checkmarks/signatures at configured posit`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 24`** (1 nodes): `Draw a single field onto the reportlab canvas. Args: c: rep`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 25`** (1 nodes): `Override create to generate reference number`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 26`** (1 nodes): `Get authorizer from x_fc_authorizer_id field`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 27`** (1 nodes): `Get cases for authorizer portal with optional search`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 28`** (1 nodes): `Get cases for sales rep portal with optional search`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 29`** (1 nodes): `Override create to handle revision numbering`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 30`** (1 nodes): `Get documents for a sale order, optionally filtered by type`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 31`** (1 nodes): `Get all revisions of a specific document type`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 32`** (1 nodes): `Override create to set author from current user if not provided`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 33`** (1 nodes): `Kanban group expansion — always show all 6 workflow states.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 34`** (1 nodes): `Straight stair lift: (steps × nose_to_nose) + 13" top landing`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 35`** (1 nodes): `Use manual override if provided, otherwise use calculated`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 36`** (1 nodes): `Curved stair lift calculation: - 12" per step - 16" per curve`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 37`** (1 nodes): `Use manual override if provided, otherwise use calculated`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 38`** (1 nodes): `Ontario Building Code: 12 inches length per 1 inch height (1:12 ratio)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 39`** (1 nodes): `Landing required every 30 feet (360 inches)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 40`** (1 nodes): `Total length including landings (5 feet = 60 inches each)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 41`** (1 nodes): `Compute portal access status based on user account and login history.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 42`** (1 nodes): `Count sale orders where this partner is the authorizer`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 43`** (1 nodes): `Count assessments where this partner is involved`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 44`** (1 nodes): `Count sale orders assigned to this partner as delivery technician`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 45`** (1 nodes): `assessment_form.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 46`** (1 nodes): `technician_sw.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 47`** (1 nodes): `loaner_portal.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 48`** (1 nodes): `signature_pad.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 49`** (1 nodes): `portal_search.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 50`** (1 nodes): `Display the Page 11 signing form.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 51`** (1 nodes): `Process the submitted Page 11 signature.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 52`** (1 nodes): `Download the signed Page 11 PDF.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 53`** (1 nodes): `Start a new assessment`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 54`** (1 nodes): `View/edit an assessment`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 55`** (1 nodes): `Save assessment data (create or update)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 56`** (1 nodes): `Signature capture page`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 57`** (1 nodes): `Save a signature (AJAX)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 58`** (1 nodes): `Complete the assessment`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 59`** (1 nodes): `Start a new express assessment (Page 1 - Equipment Selection)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 60`** (1 nodes): `Continue/edit an express assessment`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 61`** (1 nodes): `Save express assessment data (create or update)`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 62`** (1 nodes): `Public page for booking an accessibility assessment.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 63`** (1 nodes): `Process assessment booking form submission.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 64`** (1 nodes): `Render the visual field editor for a PDF template.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 65`** (1 nodes): `Return all fields for a template.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 66`** (1 nodes): `Update a field's position or properties.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 67`** (1 nodes): `Create a new field on a template.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 68`** (1 nodes): `Delete a field from a template.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 69`** (1 nodes): `Return the preview image URL for a specific page.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 70`** (1 nodes): `Upload a preview image for a template page directly from the editor.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 71`** (1 nodes): `Generate a preview filled PDF with sample data.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 72`** (1 nodes): `Auto-save browser-detected timezone to the user profile if not already set.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 73`** (1 nodes): `Override home to add ADP posting info for Fusion users`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 74`** (1 nodes): `Authorizer dashboard - simplified mobile-first view`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 75`** (1 nodes): `List of cases assigned to the authorizer`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 76`** (1 nodes): `AJAX search endpoint for real-time search`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 77`** (1 nodes): `Add a comment to a case - posts to sale order chatter and emails salesperson`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 78`** (1 nodes): `Upload a document for a case`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 79`** (1 nodes): `Download an attachment from sale order (original application, xml, proof of deli`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 80`** (1 nodes): `View an approval photo`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 81`** (1 nodes): `Sales rep dashboard with search and filters`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 82`** (1 nodes): `List of cases for the sales rep`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 83`** (1 nodes): `AJAX search endpoint for sales rep real-time search`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 84`** (1 nodes): `View a specific case for sales rep`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 85`** (1 nodes): `Add a comment to a case (sales rep) - posts to sale order chatter and emails aut`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 86`** (1 nodes): `List of funding claims for the client`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 87`** (1 nodes): `View a specific funding claim`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 88`** (1 nodes): `Download a document from a funding claim`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 89`** (1 nodes): `Download proof of delivery from a funding claim`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 90`** (1 nodes): `Technician dashboard - today's schedule with timeline.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 91`** (1 nodes): `List of all tasks for the technician.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 92`** (1 nodes): `View a specific technician task.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 93`** (1 nodes): `Add notes (and optional photos) to a completed task. :param notes: text`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 94`** (1 nodes): `Handle task status changes (start, complete, en_route, cancel). Location`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 95`** (1 nodes): `Transcribe voice recording using OpenAI Whisper, translate to English.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 96`** (1 nodes): `Use GPT to clean up and format raw notes text.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 97`** (1 nodes): `Format transcription with GPT and complete the task.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 98`** (1 nodes): `Next day preparation view.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 99`** (1 nodes): `View schedule for a specific date.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 100`** (1 nodes): `Admin map view showing latest technician locations using Google Maps.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 101`** (1 nodes): `Log the technician's current GPS location.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 102`** (1 nodes): `Check if the current technician is clocked in. Returns {clocked_in: boo`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 103`** (1 nodes): `Save the technician's personal start location.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 104`** (1 nodes): `Register a push notification subscription.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 105`** (1 nodes): `Legacy: List of deliveries for the technician (redirects to tasks).`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 106`** (1 nodes): `View a specific delivery for technician (legacy, still works).`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 107`** (1 nodes): `POD signature capture page - accessible by technicians and sales reps`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 108`** (1 nodes): `Save POD signature via AJAX`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 109`** (1 nodes): `Task-level POD signature capture page (works for all tasks including shadow).`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 110`** (1 nodes): `Save POD signature directly on a task.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 111`** (1 nodes): `Show the accessibility assessment type selector`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 112`** (1 nodes): `List all accessibility assessments for the current user (sales rep or authorizer`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 113`** (1 nodes): `Straight stair lift assessment form`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 114`** (1 nodes): `Curved stair lift assessment form`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 115`** (1 nodes): `Vertical Platform Lift assessment form`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 116`** (1 nodes): `Ceiling Lift assessment form`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 117`** (1 nodes): `Custom Ramp assessment form`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 118`** (1 nodes): `Bathroom Modification assessment form`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 119`** (1 nodes): `Tub Cutout assessment form`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 120`** (1 nodes): `Save an accessibility assessment and optionally create a Sale Order`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 121`** (1 nodes): `Render the rental pickup inspection form for the technician.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 122`** (1 nodes): `Save the rental inspection results.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `create()` connect `Community 3` to `Community 0`, `Community 1`, `Community 4`, `Community 7`, `Community 11`?**
_High betweenness centrality (0.080) - this node is a cross-community bridge._
- **Why does `FusionAssessment` connect `Community 2` to `Community 4`?**
_High betweenness centrality (0.059) - this node is a cross-community bridge._
- **Why does `AuthorizerPortal` connect `Community 7` to `Community 0`, `Community 4`?**
_High betweenness centrality (0.047) - this node is a cross-community bridge._
- **Are the 17 inferred relationships involving `create()` (e.g. with `._generate_tutorial_articles()` and `.action_grant_portal_access()`) actually correct?**
_`create()` has 17 INFERRED edges - model-reasoned connections that need verification._
- **Are the 2 inferred relationships involving `accessibility_assessment_save()` (e.g. with `create()` and `.action_complete()`) actually correct?**
_`accessibility_assessment_save()` has 2 INFERRED edges - model-reasoned connections that need verification._
- **What connects `Ensure all module views are active after install/update. Odoo silently deac`, `Generic PDF template filler. Works with any template, any number of pages.`, `Fill a PDF template by overlaying text/checkmarks/signatures at configured posit` to the rest of the system?**
_177 weakly-connected nodes found - possible documentation gaps or missing edges._
- **Should `Community 0` be split into smaller, more focused modules?**
_Cohesion score 0.05 - nodes in this community are weakly interconnected._

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_authorizer_comment_py", "label": "authorizer_comment.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L1"}, {"id": "authorizer_comment_authorizercomment", "label": "AuthorizerComment", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L9"}, {"id": "authorizer_comment_compute_display_name", "label": "_compute_display_name()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L70"}, {"id": "authorizer_comment_create", "label": "create()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L78"}, {"id": "authorizer_comment_rationale_79", "label": "Override create to set author from current user if not provided", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L79"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_authorizer_comment_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_authorizer_comment_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_authorizer_comment_py", "target": "authorizer_comment_authorizercomment", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_authorizer_comment_py", "target": "authorizer_comment_compute_display_name", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L70", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_authorizer_comment_py", "target": "authorizer_comment_create", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L78", "weight": 1.0}, {"source": "authorizer_comment_rationale_79", "target": "authorizer_comment_authorizercomment_create", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L79", "weight": 1.0}], "raw_calls": [{"caller_nid": "authorizer_comment_compute_display_name", "callee": "strftime", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L73"}, {"caller_nid": "authorizer_comment_compute_display_name", "callee": "_", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L75"}, {"caller_nid": "authorizer_comment_create", "callee": "get", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L81"}, {"caller_nid": "authorizer_comment_create", "callee": "get", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L83"}, {"caller_nid": "authorizer_comment_create", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/authorizer_comment.py", "source_location": "L85"}]}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_5_0_end_migrate_py", "label": "end-migrate.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.5.0/end-migrate.py", "source_location": "L1"}, {"id": "end_migrate_migrate", "label": "migrate()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.5.0/end-migrate.py", "source_location": "L16"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_5_0_end_migrate_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.5.0/end-migrate.py", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_5_0_end_migrate_py", "target": "end_migrate_migrate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.5.0/end-migrate.py", "source_location": "L16", "weight": 1.0}], "raw_calls": [{"caller_nid": "end_migrate_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.5.0/end-migrate.py", "source_location": "L20"}, {"caller_nid": "end_migrate_migrate", "callee": "fetchall", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.5.0/end-migrate.py", "source_location": "L31"}, {"caller_nid": "end_migrate_migrate", "callee": "warning", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.5.0/end-migrate.py", "source_location": "L33"}, {"caller_nid": "end_migrate_migrate", "callee": "len", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.5.0/end-migrate.py", "source_location": "L35"}]}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_chatter_message_authorizer_js", "label": "chatter_message_authorizer.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L1"}, {"id": "chatter_message_authorizer_setup", "label": "setup()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L14"}, {"id": "chatter_message_authorizer_onclickmessageauthorizer", "label": "onClickMessageAuthorizer()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L20"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_chatter_message_authorizer_js", "target": "chatter", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_chatter_message_authorizer_js", "target": "patch", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L10", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_chatter_message_authorizer_js", "target": "hooks", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L11", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_chatter_message_authorizer_js", "target": "chatter_message_authorizer_setup", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L14", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_chatter_message_authorizer_js", "target": "chatter_message_authorizer_onclickmessageauthorizer", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L20", "weight": 1.0}], "raw_calls": [{"caller_nid": "chatter_message_authorizer_setup", "callee": "useService", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L16"}, {"caller_nid": "chatter_message_authorizer_setup", "callee": "useService", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L17"}, {"caller_nid": "chatter_message_authorizer_onclickmessageauthorizer", "callee": "call", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L25"}, {"caller_nid": "chatter_message_authorizer_onclickmessageauthorizer", "callee": "map", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L32"}, {"caller_nid": "chatter_message_authorizer_onclickmessageauthorizer", "callee": "split", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L32"}, {"caller_nid": "chatter_message_authorizer_onclickmessageauthorizer", "callee": "doAction", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L34"}, {"caller_nid": "chatter_message_authorizer_onclickmessageauthorizer", "callee": "warn", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js", "source_location": "L37"}]}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L7", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L8", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L10", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/__init__.py", "source_location": "L11", "weight": 1.0}], "raw_calls": []}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_timezone_detect_js", "label": "timezone_detect.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L1"}, {"id": "timezone_detect_start", "label": "start()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L8"}, {"id": "timezone_detect_detectandsavetimezone", "label": "_detectAndSaveTimezone()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L13"}, {"id": "timezone_detect_getcookie", "label": "_getCookie()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L30"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_timezone_detect_js", "target": "public_widget", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_timezone_detect_js", "target": "timezone_detect_start", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L8", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_timezone_detect_js", "target": "timezone_detect_detectandsavetimezone", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L13", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_timezone_detect_js", "target": "timezone_detect_getcookie", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L30", "weight": 1.0}, {"source": "timezone_detect_start", "target": "timezone_detect_detectandsavetimezone", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L10", "weight": 1.0}, {"source": "timezone_detect_detectandsavetimezone", "target": "timezone_detect_getcookie", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L22", "weight": 1.0}], "raw_calls": [{"caller_nid": "timezone_detect_start", "callee": "_super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L9"}, {"caller_nid": "timezone_detect_detectandsavetimezone", "callee": "resolvedOptions", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L16"}, {"caller_nid": "timezone_detect_detectandsavetimezone", "callee": "DateTimeFormat", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L16"}, {"caller_nid": "timezone_detect_detectandsavetimezone", "callee": "catch", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L27"}, {"caller_nid": "timezone_detect_detectandsavetimezone", "callee": "_rpc", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L27"}, {"caller_nid": "timezone_detect_getcookie", "callee": "match", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L31"}, {"caller_nid": "timezone_detect_getcookie", "callee": "decodeURIComponent", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/timezone_detect.js", "source_location": "L32"}]}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_controllers_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/controllers/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_controllers_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_controllers_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/controllers/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_controllers_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_controllers_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/controllers/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_controllers_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_controllers_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/controllers/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_controllers_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_controllers_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/controllers/__init__.py", "source_location": "L6", "weight": 1.0}], "raw_calls": []}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_6_0_end_migrate_py", "label": "end-migrate.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L1"}, {"id": "end_migrate_migrate", "label": "migrate()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L24"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_6_0_end_migrate_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L11", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_6_0_end_migrate_py", "target": "end_migrate_migrate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L24", "weight": 1.0}], "raw_calls": [{"caller_nid": "end_migrate_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L28"}, {"caller_nid": "end_migrate_migrate", "callee": "fetchone", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L33"}, {"caller_nid": "end_migrate_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L35"}, {"caller_nid": "end_migrate_migrate", "callee": "info", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L36"}, {"caller_nid": "end_migrate_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L39"}, {"caller_nid": "end_migrate_migrate", "callee": "info", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L44"}, {"caller_nid": "end_migrate_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L49"}, {"caller_nid": "end_migrate_migrate", "callee": "fetchall", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L60"}, {"caller_nid": "end_migrate_migrate", "callee": "warning", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L62"}, {"caller_nid": "end_migrate_migrate", "callee": "len", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.6.0/end-migrate.py", "source_location": "L64"}]}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L1"}, {"id": "init_reactivate_views", "label": "_reactivate_views()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L7"}, {"id": "init_rationale_8", "label": "Ensure all module views are active after install/update. Odoo silently deac", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L8"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_init_py", "target": "init_reactivate_views", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L7", "weight": 1.0}, {"source": "init_rationale_8", "target": "init_reactivate_views", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L8", "weight": 1.0}], "raw_calls": [{"caller_nid": "init_reactivate_views", "callee": "search", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L15"}, {"caller_nid": "init_reactivate_views", "callee": "sudo", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L15"}, {"caller_nid": "init_reactivate_views", "callee": "write", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L20"}, {"caller_nid": "init_reactivate_views", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L21"}, {"caller_nid": "init_reactivate_views", "callee": "fetchall", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L26"}, {"caller_nid": "init_reactivate_views", "callee": "warning", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L28"}, {"caller_nid": "init_reactivate_views", "callee": "getLogger", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L28"}, {"caller_nid": "init_reactivate_views", "callee": "len", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__init__.py", "source_location": "L29"}]}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_signature_pad_js", "label": "signature_pad.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/signature_pad.js", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_assessment_form_js", "label": "assessment_form.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/assessment_form.js", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_4_0_end_migrate_py", "label": "end-migrate.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.4.0/end-migrate.py", "source_location": "L1"}, {"id": "end_migrate_migrate", "label": "migrate()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.4.0/end-migrate.py", "source_location": "L16"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_4_0_end_migrate_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.4.0/end-migrate.py", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_4_0_end_migrate_py", "target": "end_migrate_migrate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.4.0/end-migrate.py", "source_location": "L16", "weight": 1.0}], "raw_calls": [{"caller_nid": "end_migrate_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.4.0/end-migrate.py", "source_location": "L20"}, {"caller_nid": "end_migrate_migrate", "callee": "fetchall", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.4.0/end-migrate.py", "source_location": "L31"}, {"caller_nid": "end_migrate_migrate", "callee": "warning", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.4.0/end-migrate.py", "source_location": "L33"}, {"caller_nid": "end_migrate_migrate", "callee": "len", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.4.0/end-migrate.py", "source_location": "L35"}]}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_3_0_end_migrate_py", "label": "end-migrate.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.3.0/end-migrate.py", "source_location": "L1"}, {"id": "end_migrate_migrate", "label": "migrate()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.3.0/end-migrate.py", "source_location": "L16"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_3_0_end_migrate_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.3.0/end-migrate.py", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_migrations_19_0_2_3_0_end_migrate_py", "target": "end_migrate_migrate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.3.0/end-migrate.py", "source_location": "L16", "weight": 1.0}], "raw_calls": [{"caller_nid": "end_migrate_migrate", "callee": "execute", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.3.0/end-migrate.py", "source_location": "L20"}, {"caller_nid": "end_migrate_migrate", "callee": "fetchall", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.3.0/end-migrate.py", "source_location": "L31"}, {"caller_nid": "end_migrate_migrate", "callee": "warning", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.3.0/end-migrate.py", "source_location": "L33"}, {"caller_nid": "end_migrate_migrate", "callee": "len", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/migrations/19.0.2.3.0/end-migrate.py", "source_location": "L35"}]}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_portal_search_js", "label": "portal_search.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/portal_search.js", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_loaner_checkout_py", "label": "loaner_checkout.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/loaner_checkout.py", "source_location": "L1"}, {"id": "loaner_checkout_fusionloanercheckoutassessment", "label": "FusionLoanerCheckoutAssessment", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/loaner_checkout.py", "source_location": "L6"}, {"id": "loaner_checkout_fusionloanercheckoutassessment_action_view_assessment", "label": ".action_view_assessment()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/loaner_checkout.py", "source_location": "L17"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_loaner_checkout_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/loaner_checkout.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_models_loaner_checkout_py", "target": "loaner_checkout_fusionloanercheckoutassessment", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/loaner_checkout.py", "source_location": "L6", "weight": 1.0}, {"source": "loaner_checkout_fusionloanercheckoutassessment", "target": "loaner_checkout_fusionloanercheckoutassessment_action_view_assessment", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/loaner_checkout.py", "source_location": "L17", "weight": 1.0}], "raw_calls": [{"caller_nid": "loaner_checkout_fusionloanercheckoutassessment_action_view_assessment", "callee": "ensure_one", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/models/loaner_checkout.py", "source_location": "L18"}]}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_loaner_portal_js", "label": "loaner_portal.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/loaner_portal.js", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_loaner_portal_js", "target": "public_widget", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/loaner_portal.js", "source_location": "L3", "weight": 1.0}], "raw_calls": []}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_static_src_js_technician_sw_js", "label": "technician_sw.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/static/src/js/technician_sw.js", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -1 +0,0 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_utils_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/utils/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_utils_init_py", "target": "users_gurpreet_github_odoo_modules_fusion_authorizer_portal_utils_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/fusion_authorizer_portal/utils/__init__.py", "source_location": "L3", "weight": 1.0}], "raw_calls": []}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -33,14 +33,14 @@ fusion_ringcentral, fusion_tasks
`wizard/odsp_submit_to_odsp_wizard.py` calls into `fusion_faxes.send.fax.wizard` (the fax composer) and reads `partner.x_ff_fax_number`**but `fusion_faxes` is NOT in `__manifest__.py.depends`**. The fax actions are guarded by `hasattr` checks so the wizard still loads if `fusion_faxes` is missing, but the "Send Fax" / "Send Email + Fax" buttons will fail at click-time. If you're moving this module to a new database, install `fusion_faxes` alongside it.
### ⚠ Reverse-dependency: `fusion_authorizer_portal` always installed alongside
### ⚠ Reverse-dependency: `fusion_portal` always installed alongside
The dependency direction is **`fusion_authorizer_portal``fusion_claims`** (hard, declared in fusion_authorizer_portal's manifest), but fusion_claims uses APIs that only exist when fusion_authorizer_portal is installed:
The dependency direction is **`fusion_portal``fusion_claims`** (hard, declared in fusion_portal's manifest), but fusion_claims uses APIs that only exist when fusion_portal is installed:
- `sale.order._apply_pod_signature_to_approval_form` imports `PDFTemplateFiller` from `odoo.addons.fusion_authorizer_portal.utils.pdf_filler``ImportError` if missing.
- `fusion.page11.sign.request` renders PDFs using `fusion.pdf.template` records — that **model lives in fusion_authorizer_portal**, not here.
- The `/page11/sign/<token>` URL that the Page 11 wizard generates is handled by `fusion_authorizer_portal.controllers.portal_page11_sign` — without it the public signing flow is dead.
- `page11_sign_request._generate_signed_pdf` references `fusion.assessment` records — that model also lives in fusion_authorizer_portal.
- `sale.order._apply_pod_signature_to_approval_form` imports `PDFTemplateFiller` from `odoo.addons.fusion_portal.utils.pdf_filler``ImportError` if missing.
- `fusion.page11.sign.request` renders PDFs using `fusion.pdf.template` records — that **model lives in fusion_portal**, not here.
- The `/page11/sign/<token>` URL that the Page 11 wizard generates is handled by `fusion_portal.controllers.portal_page11_sign` — without it the public signing flow is dead.
- `page11_sign_request._generate_signed_pdf` references `fusion.assessment` records — that model also lives in fusion_portal.
In practice both modules are always installed together. See §29 for the full integration map.
@@ -861,7 +861,7 @@ Mirrors the MOD on_hold pattern. `x_fc_odsp_previous_status_before_hold` saves t
| Method | Used when | Mechanism |
|---|---|---|
| `action_sign_sa_mobility_form` | Client signs the SA Mobility form directly (Page 2 client consent) | **Hard-coded coordinates**: writes printed name at `(180, h-180)` and `(72, h-560)`, date at `(350, h-560)`, signature image at `(72, h-540, 200×50px)`. Uses `reportlab.pdfgen.canvas` + `odoo.tools.pdf.PdfFileReader/Writer`. **Brittle** — if the gov PDF layout changes, the coordinates must be re-measured. |
| `_apply_pod_signature_to_approval_form` | POD signature collected (auto-fired by `write` override when `x_fc_pod_signature` is set) | **PDFTemplateFiller** from `fusion_authorizer_portal` — reads field positions from the active `fusion.pdf.template` (category=`odsp`), uses per-case `x_fc_sa_signature_page`. Configurable via drag-and-drop visual editor, not code. Bypass via `skip_pod_signature_hook=True` context. |
| `_apply_pod_signature_to_approval_form` | POD signature collected (auto-fired by `write` override when `x_fc_pod_signature` is set) | **PDFTemplateFiller** from `fusion_portal` — reads field positions from the active `fusion.pdf.template` (category=`odsp`), uses per-case `x_fc_sa_signature_page`. Configurable via drag-and-drop visual editor, not code. Bypass via `skip_pod_signature_hook=True` context. |
The PDFTemplateFiller approach is the preferred path going forward — it survives gov form revisions because positions live in the database, not in Python code.
@@ -1588,7 +1588,7 @@ All user-facing text is **Canadian English** (per repo CLAUDE.md). All monetary
74. **`odsp_sa_mobility_wizard._get_template_path()` uses raw `os.path`** instead of Odoo's `tools.misc.file_path`. If the module is ever deployed as a zip (rare in Odoo deployments but possible), this will fail. Migrate to `file_path('fusion_claims/static/src/pdf/sa_mobility_form_template.pdf')` if you ship this for multi-tenant.
75. **PDF template field positions for ODSP signing live in `fusion.pdf.template` (category=odsp)** — managed via a drag-and-drop editor that lives in `fusion_authorizer_portal`. The OWL editor reads field positions per-page; `_apply_pod_signature_to_approval_form` consumes them. If the gov SA form layout changes, edit the template via the visual editor, not by changing Python coordinates.
75. **PDF template field positions for ODSP signing live in `fusion.pdf.template` (category=odsp)** — managed via a drag-and-drop editor that lives in `fusion_portal`. The OWL editor reads field positions per-page; `_apply_pod_signature_to_approval_form` consumes them. If the gov SA form layout changes, edit the template via the visual editor, not by changing Python coordinates.
76. **SA Mobility wizard limits rows**: 6 parts, 5 labour, 4 fees. The gov PDF only has that many slots. If the SO has more lines, the rest are silently dropped from the form fill (but still appear in the invoice). The wizard truncates via slicing in `default_get`.
@@ -1862,11 +1862,11 @@ This module is the **lower-level engine**. Two sibling modules layer on top of i
The whole technician task → sale order coupling lives in `fusion_claims/models/technician_task.py:674` — and the calendar / map / scheduling logic stays in the base `fusion.technician.task` model in fusion_tasks.
### 29.2 `fusion_authorizer_portal` (portal layer — undeclared but co-installed)
### 29.2 `fusion_portal` (portal layer — undeclared but co-installed)
fusion_authorizer_portal manifest declares `fusion_claims` + `fusion_tasks` + `fusion_loaners_management` as hard deps. fusion_claims uses APIs that only exist when fusion_authorizer_portal is installed — see the dependency note at the top of §2.
fusion_portal manifest declares `fusion_claims` + `fusion_tasks` + `fusion_loaners_management` as hard deps. fusion_claims uses APIs that only exist when fusion_portal is installed — see the dependency note at the top of §2.
| Provided by fusion_authorizer_portal | Used by fusion_claims |
| Provided by fusion_portal | Used by fusion_claims |
|---|---|
| `PDFTemplateFiller` class (`utils/pdf_filler.py`) | `sale.order._apply_pod_signature_to_approval_form` imports it. Same pattern as Odoo Enterprise Sign module — overlays text/checkmarks/signatures via reportlab Canvas + `mergePage()`. |
| `fusion.pdf.template` model + `fusion.pdf.template.field` + `fusion.pdf.template.preview` | Drag-and-drop visual editor for placing fields on PDF preview images. Categories: `adp`, `mod`, `odsp`, `hardship`, `other`. fusion_claims searches for `(category='odsp', state='active')` for SA Mobility / OW signature overlays. The Page 11 wizard searches for `name ilike 'adp_page_11'` or `'page 11'`. |
@@ -1888,7 +1888,7 @@ fusion_authorizer_portal manifest declares `fusion_claims` + `fusion_tasks` + `f
- Renaming a field on `sale.order` likely affects portal templates (`portal_templates.xml`, `portal_assessment_express.xml`, `portal_accessibility_*.xml`) that reference it via QWeb.
- Adding a new `x_fc_adp_application_status` value may need a portal-side handler in `portal_main.py` to render the new state.
- The `fusion.pdf.template` schema (page-positioned fields) is the ground truth for ODSP signature placement — DON'T hard-code coordinates in fusion_claims when you could create a template field instead.
- The `_reactivate_views` post-init hook on fusion_authorizer_portal exists specifically because the inheritance from this module's views is fragile — if you rename a field referenced by an xpath in fusion_authorizer_portal, that view goes dead and stays dead.
- The `_reactivate_views` post-init hook on fusion_portal exists specifically because the inheritance from this module's views is fragile — if you rename a field referenced by an xpath in fusion_portal, that view goes dead and stays dead.
### 29.3 Other co-installed Nexa modules
@@ -1896,7 +1896,7 @@ fusion_authorizer_portal manifest declares `fusion_claims` + `fusion_tasks` + `f
|---|---|---|
| `fusion_ringcentral` | RingCentral softphone, click-to-dial widget, fax composer | Click-to-dial works on any phone field — no direct API calls from this module |
| `fusion_faxes` | `fusion_faxes.send.fax.wizard` + `partner.x_ff_fax_number` | Hard-soft-dep: `odsp_submit_to_odsp_wizard` calls the fax wizard for ODSP submissions |
| `fusion_loaners_management` | Loaner equipment lending | fusion_authorizer_portal depends on this; fusion_claims doesn't touch it directly |
| `fusion_loaners_management` | Loaner equipment lending | fusion_portal depends on this; fusion_claims doesn't touch it directly |
| `fusion_pdf_preview` | PDF preview client action + report intercept | Project CLAUDE.md says prefer this over `act_url`+`target=new` for attachments. fusion_claims still has legacy attachment buttons using the old pattern — see gotcha #12 |
## 30. Per-funder workflow state machines
@@ -2323,7 +2323,7 @@ Creates a `fusion.technician.location` record on the remote with `source='sync'`
- `context['skip_travel_recalc']` — prevents the pull from triggering local recalculations.
- Terminal-state tasks (`completed`, `cancelled`) — push side does write, but pull side does NOT update existing shadow records that are already terminal (defensive against late race conditions).
## 33. `fusion.assessment` (OT assessment model — lives in `fusion_authorizer_portal`)
## 33. `fusion.assessment` (OT assessment model — lives in `fusion_portal`)
The 1,636-line model that captures an OT's assessment of a client + their equipment needs, then generates the draft sale order.
@@ -2395,7 +2395,7 @@ The model has `signature_page_11` + `signature_page_12` binary fields. `signatur
`action_complete_express()` skips step 3 (signatures) entirely — used for the "express" assessment route from the sales-rep portal where the rep just needs to spec a wheelchair without doing the full ADP assessment.
## 34. `fusion.accessibility.assessment` (MOD/accessibility assessment — lives in `fusion_authorizer_portal`)
## 34. `fusion.accessibility.assessment` (MOD/accessibility assessment — lives in `fusion_portal`)
The 966-line sibling for accessibility modifications (not ADP).
@@ -2466,7 +2466,7 @@ The model has hundreds of measurement fields, only some of which are visible per
`stairlift_curved`, `vpl`, `ceiling_lift`, `ramp`, `bathroom`, `tub_cutout` each have their own set of fields.
## 35. `fusion_authorizer_portal` controller routes — detailed
## 35. `fusion_portal` controller routes — detailed
Full per-route inventory from `portal_main.py` (2,827 lines), `portal_assessment.py` (1,238), `portal_page11_sign.py` (206), `pdf_editor.py` (218).
@@ -2816,7 +2816,7 @@ All filtered to `move_type in ['out_invoice', 'out_refund']` (customer invoices
ACSD (Assistance to Children with Severe Disabilities) is a CLIENT TYPE, not a sale type. The menu has a dedicated ACSD entry that catches any sale type but with `client_type='ACS'`.
## 40. `fusion_authorizer_portal.sale_order` extensions (266 lines)
## 40. `fusion_portal.sale_order` extensions (266 lines)
Adds 6 fields to `sale.order` + 5 methods:
@@ -2843,7 +2843,7 @@ JSON-RPC methods (called from portal JS):
`_get_partner_address_display()` — formatted address string.
`_get_product_lines_for_portal()` — product lines minus internal-only data.
## 41. `fusion_authorizer_portal.res_partner` extensions (767 lines)
## 41. `fusion_portal.res_partner` extensions (767 lines)
Adds geolocation + portal access management:
@@ -3019,7 +3019,7 @@ ssh odoo-westin "docker exec odoo-dev-app odoo -d westin-v19 -u fusion_claims --
ssh odoo-mobility "docker exec odoo-mobility-app odoo -d mobility -u fusion_claims --stop-after-init && docker restart odoo-mobility-app"
```
For multiple modules: `-u fusion_claims,fusion_tasks,fusion_authorizer_portal`.
For multiple modules: `-u fusion_claims,fusion_tasks,fusion_portal`.
### 46.3 Database probes
@@ -3077,7 +3077,7 @@ After 9 rounds of deep diving, here's what CLAUDE.md covers vs the codebase:
- Every cron job with cadence + logic
- Every constraint method with regex + rule
- Every special-character/edge-case behaviour I encountered
- Every cross-module integration point with both sibling modules (fusion_tasks, fusion_authorizer_portal)
- Every cross-module integration point with both sibling modules (fusion_tasks, fusion_portal)
- Every PDF report's conditional sections + business logic
- Every ICP setting (~60+)
- Every gotcha (~83)
@@ -3103,4 +3103,4 @@ After 9 rounds of deep diving, here's what CLAUDE.md covers vs the codebase:
- Build new reports following the established color/header/footer conventions
- Add new gotchas in the right format
- Understand the soft-dep on `fusion_faxes` + `fusion_pdf_preview`
- Know the deployment fact that fusion_authorizer_portal is always co-installed
- Know the deployment fact that fusion_portal is always co-installed

View File

@@ -1709,7 +1709,7 @@ class SaleOrder(models.Model):
return
import base64
from odoo.addons.fusion_authorizer_portal.utils.pdf_filler import PDFTemplateFiller
from odoo.addons.fusion_portal.utils.pdf_filler import PDFTemplateFiller
tpl = self.env['fusion.pdf.template'].search([
('category', '=', 'odsp'), ('state', '=', 'active'),

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Clock link removed from portal home - now handled by fusion_authorizer_portal -->
<!-- Clock link removed from portal home - now handled by fusion_portal -->
<template id="portal_my_home_clock" name="Portal My Home: Clock"
inherit_id="portal.portal_my_home" priority="60">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">

View File

@@ -79,7 +79,7 @@ This module integrates with the `fusion_claims` module to provide a seamless wor
1. **Copy the module** to your Odoo addons directory:
```bash
cp -r fusion_authorizer_portal /path/to/odoo/custom-addons/
cp -r fusion_portal /path/to/odoo/custom-addons/
```
2. **Update the apps list** in Odoo:
@@ -627,14 +627,14 @@ Enable debug logging for this module:
```python
import logging
_logger = logging.getLogger('fusion_authorizer_portal')
_logger = logging.getLogger('fusion_portal')
_logger.setLevel(logging.DEBUG)
```
Or in Odoo configuration:
```ini
[options]
log_handler = fusion_authorizer_portal:DEBUG
log_handler = fusion_portal:DEBUG
```
---
@@ -671,7 +671,7 @@ log_handler = fusion_authorizer_portal:DEBUG
## File Structure
```
fusion_authorizer_portal/
fusion_portal/
├── __init__.py
├── __manifest__.py
├── README.md

View File

@@ -13,14 +13,14 @@ def _reactivate_views(env):
This hook prevents that from silently breaking the portal.
"""
views = env['ir.ui.view'].sudo().search([
('key', 'like', 'fusion_authorizer_portal.%'),
('key', 'like', 'fusion_portal.%'),
('active', '=', False),
])
if views:
views.write({'active': True})
env.cr.execute("""
SELECT key FROM ir_ui_view
WHERE key LIKE 'fusion_authorizer_portal.%%'
WHERE key LIKE 'fusion_portal.%%'
AND id = ANY(%s)
""", [views.ids])
keys = [r[0] for r in env.cr.fetchall()]

View File

@@ -82,20 +82,20 @@ This module provides external portal access for:
],
'assets': {
'web.assets_backend': [
'fusion_authorizer_portal/static/src/xml/chatter_message_authorizer.xml',
'fusion_authorizer_portal/static/src/js/chatter_message_authorizer.js',
'fusion_portal/static/src/xml/chatter_message_authorizer.xml',
'fusion_portal/static/src/js/chatter_message_authorizer.js',
],
'web.assets_frontend': [
'fusion_authorizer_portal/static/src/css/portal_style.css',
'fusion_authorizer_portal/static/src/css/technician_portal.css',
'fusion_authorizer_portal/static/src/js/portal_search.js',
'fusion_authorizer_portal/static/src/js/assessment_form.js',
'fusion_authorizer_portal/static/src/js/signature_pad.js',
'fusion_portal/static/src/css/portal_style.css',
'fusion_portal/static/src/css/technician_portal.css',
'fusion_portal/static/src/js/portal_search.js',
'fusion_portal/static/src/js/assessment_form.js',
'fusion_portal/static/src/js/signature_pad.js',
'fusion_authorizer_portal/static/src/js/pdf_field_editor.js',
'fusion_authorizer_portal/static/src/js/technician_push.js',
'fusion_authorizer_portal/static/src/js/technician_location.js',
'fusion_authorizer_portal/static/src/js/timezone_detect.js',
'fusion_portal/static/src/js/pdf_field_editor.js',
'fusion_portal/static/src/js/technician_push.js',
'fusion_portal/static/src/js/technician_location.js',
'fusion_portal/static/src/js/timezone_detect.js',
],
},
'images': ['static/description/icon.png'],

View File

@@ -38,7 +38,7 @@ class FusionPdfEditorController(http.Controller):
'text_align',
])
return request.render('fusion_authorizer_portal.portal_pdf_field_editor', {
return request.render('fusion_portal.portal_pdf_field_editor', {
'template': template,
'fields': fields,
'preview_url': preview_url,

View File

@@ -91,7 +91,7 @@ class AssessmentPortal(CustomerPortal):
'page_name': 'assessments',
}
return request.render('fusion_authorizer_portal.portal_assessments', values)
return request.render('fusion_portal.portal_assessments', values)
@http.route('/my/assessment/new', type='http', auth='user', website=True)
def portal_assessment_new(self, **kw):
@@ -116,7 +116,7 @@ class AssessmentPortal(CustomerPortal):
'page_name': 'assessment_new',
}
return request.render('fusion_authorizer_portal.portal_assessment_form', values)
return request.render('fusion_portal.portal_assessment_form', values)
@http.route('/my/assessment/<int:assessment_id>', type='http', auth='user', website=True)
def portal_assessment_view(self, assessment_id, **kw):
@@ -166,7 +166,7 @@ class AssessmentPortal(CustomerPortal):
'photos': photos,
}
return request.render('fusion_authorizer_portal.portal_assessment_form', values)
return request.render('fusion_portal.portal_assessment_form', values)
@http.route('/my/assessment/save', type='http', auth='user', website=True, methods=['POST'], csrf=True)
def portal_assessment_save(self, assessment_id=None, **kw):
@@ -312,7 +312,7 @@ class AssessmentPortal(CustomerPortal):
'page_name': 'assessment_signatures',
}
return request.render('fusion_authorizer_portal.portal_assessment_signatures', values)
return request.render('fusion_portal.portal_assessment_signatures', values)
@http.route('/my/assessment/<int:assessment_id>/save_signature', type='jsonrpc', auth='user')
def portal_save_signature(self, assessment_id, signature_type='', signature_data='', signer_name='', **kw):
@@ -461,7 +461,7 @@ class AssessmentPortal(CustomerPortal):
'google_maps_api_key': google_maps_api_key,
}
return request.render('fusion_authorizer_portal.portal_assessment_express', values)
return request.render('fusion_portal.portal_assessment_express', values)
@http.route('/my/assessment/express/<int:assessment_id>', type='http', auth='user', website=True)
def portal_assessment_express_edit(self, assessment_id, page=1, **kw):
@@ -528,7 +528,7 @@ class AssessmentPortal(CustomerPortal):
'google_maps_api_key': google_maps_api_key,
}
return request.render('fusion_authorizer_portal.portal_assessment_express', values)
return request.render('fusion_portal.portal_assessment_express', values)
@http.route('/my/assessment/express/save', type='http', auth='user', website=True, methods=['POST'], csrf=True)
def portal_assessment_express_save(self, **kw):
@@ -1050,7 +1050,7 @@ class AssessmentPortal(CustomerPortal):
'success': kw.get('success'),
'error': kw.get('error'),
}
return request.render('fusion_authorizer_portal.portal_book_assessment', values)
return request.render('fusion_portal.portal_book_assessment', values)
@http.route('/book-assessment/submit', type='http', auth='public', website=True, methods=['POST'], csrf=True)
def portal_book_assessment_submit(self, **kw):

View File

@@ -286,7 +286,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'authorizer_dashboard',
}
return request.render('fusion_authorizer_portal.portal_authorizer_dashboard', values)
return request.render('fusion_portal.portal_authorizer_dashboard', values)
@http.route(['/my/authorizer/cases', '/my/authorizer/cases/page/<int:page>'], type='http', auth='user', website=True)
def authorizer_cases(self, page=1, search='', sortby='date', sale_type='', **kw):
@@ -364,7 +364,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'authorizer_cases',
}
return request.render('fusion_authorizer_portal.portal_authorizer_cases', values)
return request.render('fusion_portal.portal_authorizer_cases', values)
@http.route('/my/authorizer/cases/search', type='jsonrpc', auth='user')
def authorizer_cases_search(self, query='', **kw):
@@ -455,7 +455,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'authorizer_case_detail',
}
return request.render('fusion_authorizer_portal.portal_authorizer_case_detail', values)
return request.render('fusion_portal.portal_authorizer_case_detail', values)
@http.route('/my/authorizer/case/<int:order_id>/comment', type='http', auth='user', website=True, methods=['POST'])
def authorizer_add_comment(self, order_id, comment='', **kw):
@@ -758,7 +758,7 @@ class AuthorizerPortal(CustomerPortal):
'status_filter': status,
}
values.update(self._get_clock_status_data())
return request.render('fusion_authorizer_portal.portal_sales_dashboard', values)
return request.render('fusion_portal.portal_sales_dashboard', values)
@http.route(['/my/sales/cases', '/my/sales/cases/page/<int:page>'], type='http', auth='user', website=True)
def sales_rep_cases(self, page=1, search='', sortby='date', **kw):
@@ -818,7 +818,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'sales_cases',
}
return request.render('fusion_authorizer_portal.portal_sales_cases', values)
return request.render('fusion_portal.portal_sales_cases', values)
@http.route('/my/sales/cases/search', type='jsonrpc', auth='user')
def sales_rep_cases_search(self, query='', **kw):
@@ -910,7 +910,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'sales_case_detail',
}
return request.render('fusion_authorizer_portal.portal_sales_case_detail', values)
return request.render('fusion_portal.portal_sales_case_detail', values)
@http.route('/my/sales/case/<int:order_id>/comment', type='http', auth='user', website=True, methods=['POST'])
def sales_rep_add_comment(self, order_id, comment='', **kw):
@@ -1018,7 +1018,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'funding_claims',
}
return request.render('fusion_authorizer_portal.portal_client_claims', values)
return request.render('fusion_portal.portal_client_claims', values)
@http.route('/my/funding-claims/<int:order_id>', type='http', auth='user', website=True)
def client_funding_claim_detail(self, order_id, **kw):
@@ -1055,7 +1055,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'funding_claim_detail',
}
return request.render('fusion_authorizer_portal.portal_client_claim_detail', values)
return request.render('fusion_portal.portal_client_claim_detail', values)
@http.route('/my/funding-claims/<int:order_id>/document/<int:doc_id>/download', type='http', auth='user')
def client_download_document(self, order_id, doc_id, **kw):
@@ -1269,7 +1269,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'technician_dashboard',
}
values.update(clock_data)
return request.render('fusion_authorizer_portal.portal_technician_dashboard', values)
return request.render('fusion_portal.portal_technician_dashboard', values)
@http.route(['/my/technician/tasks', '/my/technician/tasks/page/<int:page>'], type='http', auth='user', website=True)
def technician_tasks(self, page=1, search='', filter_status='all', filter_date='', **kw):
@@ -1323,7 +1323,7 @@ class AuthorizerPortal(CustomerPortal):
'filter_date': filter_date,
'page_name': 'technician_tasks',
}
return request.render('fusion_authorizer_portal.portal_technician_tasks', values)
return request.render('fusion_portal.portal_technician_tasks', values)
@http.route('/my/technician/task/<int:task_id>', type='http', auth='user', website=True)
def technician_task_detail(self, task_id, **kw):
@@ -1382,7 +1382,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'technician_task_detail',
'earlier_incomplete': earlier_incomplete,
}
return request.render('fusion_authorizer_portal.portal_technician_task_detail', values)
return request.render('fusion_portal.portal_technician_task_detail', values)
@http.route('/my/technician/task/<int:task_id>/add-notes', type='json', auth='user', website=True)
def technician_task_add_notes(self, task_id, notes, photos=None, **kw):
@@ -1866,7 +1866,7 @@ class AuthorizerPortal(CustomerPortal):
'all_equipment': all_equipment,
'page_name': 'technician_tomorrow',
}
return request.render('fusion_authorizer_portal.portal_technician_tomorrow', values)
return request.render('fusion_portal.portal_technician_tomorrow', values)
@http.route('/my/technician/schedule/<string:date>', type='http', auth='user', website=True)
def technician_schedule_date(self, date, **kw):
@@ -1898,7 +1898,7 @@ class AuthorizerPortal(CustomerPortal):
'total_travel': total_travel,
'page_name': 'technician_schedule',
}
return request.render('fusion_authorizer_portal.portal_technician_schedule_date', values)
return request.render('fusion_portal.portal_technician_schedule_date', values)
@http.route('/my/technician/admin/map', type='http', auth='user', website=True)
def technician_location_map(self, **kw):
@@ -1916,7 +1916,7 @@ class AuthorizerPortal(CustomerPortal):
'locations': locations,
'google_maps_api_key': api_key,
}
return request.render('fusion_authorizer_portal.portal_technician_map', values)
return request.render('fusion_portal.portal_technician_map', values)
@http.route('/my/technician/location/log', type='json', auth='user', website=True)
def technician_location_log(self, latitude, longitude, accuracy=None, **kw):
@@ -2000,7 +2000,7 @@ class AuthorizerPortal(CustomerPortal):
'order': order,
'page_name': 'technician_delivery_detail',
}
return request.render('fusion_authorizer_portal.portal_technician_delivery_detail_legacy', values)
return request.render('fusion_portal.portal_technician_delivery_detail_legacy', values)
# ==================== POD SIGNATURE CAPTURE ====================
@@ -2068,7 +2068,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'pod_signature',
}
return request.render('fusion_authorizer_portal.portal_pod_signature', values)
return request.render('fusion_portal.portal_pod_signature', values)
@http.route('/my/pod/<int:order_id>/sign', type='json', auth='user', methods=['POST'])
def pod_save_signature(self, order_id, client_name, signature_data, signature_date=None, **kw):
@@ -2246,7 +2246,7 @@ class AuthorizerPortal(CustomerPortal):
'has_existing_signature': bool(task.pod_signature),
'page_name': 'task_pod_signature',
}
return request.render('fusion_authorizer_portal.portal_task_pod_signature', values)
return request.render('fusion_portal.portal_task_pod_signature', values)
@http.route('/my/technician/task/<int:task_id>/pod/sign', type='json', auth='user', methods=['POST'])
def task_pod_save_signature(self, task_id, client_name, signature_data, signature_date=None, **kw):
@@ -2366,7 +2366,7 @@ class AuthorizerPortal(CustomerPortal):
'page_name': 'accessibility_selector',
'google_maps_api_key': google_maps_api_key,
}
return request.render('fusion_authorizer_portal.portal_accessibility_selector', values)
return request.render('fusion_portal.portal_accessibility_selector', values)
@http.route('/my/accessibility/list', type='http', auth='user', website=True)
def accessibility_assessment_list(self, page=1, **kw):
@@ -2407,7 +2407,7 @@ class AuthorizerPortal(CustomerPortal):
'assessments': assessments,
'pager': pager,
}
return request.render('fusion_authorizer_portal.portal_accessibility_list', values)
return request.render('fusion_portal.portal_accessibility_list', values)
@http.route('/my/accessibility/stairlift/straight', type='http', auth='user', website=True)
def accessibility_stairlift_straight(self, **kw):
@@ -2467,16 +2467,16 @@ class AuthorizerPortal(CustomerPortal):
# Route to specific template based on type
template_map = {
'stairlift_straight': 'fusion_authorizer_portal.portal_accessibility_stairlift_straight',
'stairlift_curved': 'fusion_authorizer_portal.portal_accessibility_stairlift_curved',
'vpl': 'fusion_authorizer_portal.portal_accessibility_vpl',
'ceiling_lift': 'fusion_authorizer_portal.portal_accessibility_ceiling',
'ramp': 'fusion_authorizer_portal.portal_accessibility_ramp',
'bathroom': 'fusion_authorizer_portal.portal_accessibility_bathroom',
'tub_cutout': 'fusion_authorizer_portal.portal_accessibility_tub_cutout',
'stairlift_straight': 'fusion_portal.portal_accessibility_stairlift_straight',
'stairlift_curved': 'fusion_portal.portal_accessibility_stairlift_curved',
'vpl': 'fusion_portal.portal_accessibility_vpl',
'ceiling_lift': 'fusion_portal.portal_accessibility_ceiling',
'ramp': 'fusion_portal.portal_accessibility_ramp',
'bathroom': 'fusion_portal.portal_accessibility_bathroom',
'tub_cutout': 'fusion_portal.portal_accessibility_tub_cutout',
}
template = template_map.get(assessment_type, 'fusion_authorizer_portal.portal_accessibility_selector')
template = template_map.get(assessment_type, 'fusion_portal.portal_accessibility_selector')
return request.render(template, values)
@http.route('/my/accessibility/save', type='json', auth='user', methods=['POST'], csrf=True)

View File

@@ -41,18 +41,18 @@ class Page11PublicSignController(http.Controller):
if status == 'not_found':
return request.render(
'fusion_authorizer_portal.portal_page11_sign_invalid', {}
'fusion_portal.portal_page11_sign_invalid', {}
)
if status in ('expired', 'cancelled'):
return request.render(
'fusion_authorizer_portal.portal_page11_sign_expired',
'fusion_portal.portal_page11_sign_expired',
{'sign_request': sign_req},
)
if status == 'already_signed':
return request.render(
'fusion_authorizer_portal.portal_page11_sign_success',
'fusion_portal.portal_page11_sign_success',
{'sign_request': sign_req, 'token': token},
)
@@ -100,7 +100,7 @@ class Page11PublicSignController(http.Controller):
'client_health_card_version': client_health_card_version,
}
return request.render(
'fusion_authorizer_portal.portal_page11_public_sign', values,
'fusion_portal.portal_page11_public_sign', values,
)
@http.route('/page11/sign/<string:token>/submit', type='http',
@@ -177,7 +177,7 @@ class Page11PublicSignController(http.Controller):
_logger.error("Sale order update failed for sign request %s: %s", sign_req.id, e)
return request.render(
'fusion_authorizer_portal.portal_page11_sign_success',
'fusion_portal.portal_page11_sign_success',
{'sign_request': sign_req, 'token': token},
)

View File

@@ -10,7 +10,7 @@ import logging
_logger = logging.getLogger(__name__)
MODULE = 'fusion_authorizer_portal'
MODULE = 'fusion_portal'
def migrate(cr, version):

View File

@@ -10,7 +10,7 @@ import logging
_logger = logging.getLogger(__name__)
MODULE = 'fusion_authorizer_portal'
MODULE = 'fusion_portal'
def migrate(cr, version):

View File

@@ -10,7 +10,7 @@ import logging
_logger = logging.getLogger(__name__)
MODULE = 'fusion_authorizer_portal'
MODULE = 'fusion_portal'
def migrate(cr, version):

View File

@@ -12,7 +12,7 @@ import logging
_logger = logging.getLogger(__name__)
MODULE = 'fusion_authorizer_portal'
MODULE = 'fusion_portal'
MOVED_XMLIDS = [
'portal_schedule_page',

View File

@@ -785,7 +785,7 @@ class FusionAccessibilityAssessment(models.Model):
'origin': f'Accessibility: {self.reference} ({type_label})',
'x_fc_sale_type': sale_type,
# Back-reference so the sale order knows which accessibility
# assessment spawned it (see field definition in fusion_authorizer_portal/models/sale_order.py).
# assessment spawned it (see field definition in fusion_portal/models/sale_order.py).
'accessibility_assessment_id': self.id,
}

View File

@@ -1458,7 +1458,7 @@ class FusionAssessment(models.Model):
# Send to authorizer
if self.authorizer_id and self.authorizer_id.email:
try:
template = self.env.ref('fusion_authorizer_portal.mail_template_assessment_complete_authorizer', raise_if_not_found=False)
template = self.env.ref('fusion_portal.mail_template_assessment_complete_authorizer', raise_if_not_found=False)
if template:
template.send_mail(self.id, force_send=True)
_logger.info(f"Sent assessment completion email to authorizer {self.authorizer_id.email}")
@@ -1468,7 +1468,7 @@ class FusionAssessment(models.Model):
# Send to client
if self.client_email:
try:
template = self.env.ref('fusion_authorizer_portal.mail_template_assessment_complete_client', raise_if_not_found=False)
template = self.env.ref('fusion_portal.mail_template_assessment_complete_client', raise_if_not_found=False)
if template:
template.send_mail(self.id, force_send=True)
_logger.info(f"Sent assessment completion email to client {self.client_email}")

View File

@@ -137,15 +137,15 @@ class ResPartner(models.Model):
"""Assign role-specific portal groups to a portal user based on contact checkboxes."""
groups_to_add = []
if self.is_technician_portal:
g = self.env.ref('fusion_authorizer_portal.group_technician_portal', raise_if_not_found=False)
g = self.env.ref('fusion_portal.group_technician_portal', raise_if_not_found=False)
if g and g not in portal_user.group_ids:
groups_to_add.append((4, g.id))
if self.is_authorizer:
g = self.env.ref('fusion_authorizer_portal.group_authorizer_portal', raise_if_not_found=False)
g = self.env.ref('fusion_portal.group_authorizer_portal', raise_if_not_found=False)
if g and g not in portal_user.group_ids:
groups_to_add.append((4, g.id))
if self.is_sales_rep_portal:
g = self.env.ref('fusion_authorizer_portal.group_sales_rep_portal', raise_if_not_found=False)
g = self.env.ref('fusion_portal.group_sales_rep_portal', raise_if_not_found=False)
if g and g not in portal_user.group_ids:
groups_to_add.append((4, g.id))
if groups_to_add:
@@ -367,23 +367,23 @@ class ResPartner(models.Model):
# Determine role and template
if self.is_technician_portal:
template_xmlid = 'fusion_authorizer_portal.welcome_article_technician'
template_xmlid = 'fusion_portal.welcome_article_technician'
icon = '🔧'
title = f"Welcome {self.name} - Technician Portal"
elif self.is_authorizer:
template_xmlid = 'fusion_authorizer_portal.welcome_article_authorizer'
template_xmlid = 'fusion_portal.welcome_article_authorizer'
icon = '📋'
title = f"Welcome {self.name} - Authorizer Portal"
elif self.is_sales_rep_portal:
template_xmlid = 'fusion_authorizer_portal.welcome_article_sales_rep'
template_xmlid = 'fusion_portal.welcome_article_sales_rep'
icon = '💼'
title = f"Welcome {self.name} - Sales Portal"
elif self.is_client_portal:
template_xmlid = 'fusion_authorizer_portal.welcome_article_client'
template_xmlid = 'fusion_portal.welcome_article_client'
icon = '👤'
title = f"Welcome {self.name}"
else:
template_xmlid = 'fusion_authorizer_portal.welcome_article_client'
template_xmlid = 'fusion_portal.welcome_article_client'
icon = '👋'
title = f"Welcome {self.name}"

View File

@@ -85,7 +85,7 @@ class ResUsers(models.Model):
try:
body = self.env['ir.qweb']._render(
'fusion_authorizer_portal.welcome_article_internal',
'fusion_portal.welcome_article_internal',
render_ctx,
minimal_qcontext=True,
raise_if_not_found=False,

View File

@@ -133,7 +133,7 @@ class SaleOrder(models.Model):
return
try:
template = self.env.ref('fusion_authorizer_portal.mail_template_case_assigned', raise_if_not_found=False)
template = self.env.ref('fusion_portal.mail_template_case_assigned', raise_if_not_found=False)
if template:
template.send_mail(self.id, force_send=False)
_logger.info(f"Sent case assignment notification to {self.x_fc_authorizer_id.email} for {self.name}")

View File

@@ -0,0 +1,81 @@
-- ============================================================================
-- One-time module rename: fusion_authorizer_portal -> fusion_portal
-- ============================================================================
-- WHY THIS IS NEEDED
-- ------------------
-- Odoo identifies an installed module by its TECHNICAL NAME (the addon folder
-- name) and stores that name in many places: the module record itself, every
-- external ID (ir_model_data), each view's `key`, and the dependency rows of
-- every other module that depends on it.
--
-- Renaming only the folder + the in-code references makes Odoo treat
-- `fusion_portal` as a BRAND-NEW, uninstalled module while the old
-- `fusion_authorizer_portal` records stay behind. Installing fresh would then
-- DUPLICATE groups / mail templates / menus and ORPHAN all existing data
-- (assessments, fusion.pdf.template records, portal users' group links, ...).
--
-- This script renames the DB rows in place so the existing install simply
-- "becomes" fusion_portal, after which a normal -u fusion_portal reloads all
-- XML data cleanly under the new external IDs.
--
-- WHEN TO RUN
-- -----------
-- Run ONCE against every database that already has the module installed
-- (e.g. westin, entech), BEFORE the first -u fusion_portal.
-- Fresh databases that never had fusion_authorizer_portal do NOT need this.
-- It is idempotent — re-running after the rename matches nothing and is a no-op.
--
-- HOW TO RUN
-- ----------
-- 1. Stop Odoo (or do it during a maintenance window).
-- 2. psql into the target DB and execute this file:
-- \i rename_module.sql
-- (or paste the BEGIN..COMMIT block).
-- 3. Confirm the four "remaining" counts at the end are all 0.
-- 4. Start Odoo with: -u fusion_portal
-- 5. (optional) hard-refresh browsers / clear bundle cache — the asset paths
-- changed from /fusion_authorizer_portal/... to /fusion_portal/...
-- ============================================================================
BEGIN;
-- 1) The module record itself.
UPDATE ir_module_module
SET name = 'fusion_portal'
WHERE name = 'fusion_authorizer_portal';
-- 2) Every external ID owned by the module (groups, views, templates, menus,
-- server actions, record rules, ACLs, cron, ...).
UPDATE ir_model_data
SET module = 'fusion_portal'
WHERE module = 'fusion_authorizer_portal';
-- 3) View keys are stored ON the view row (not derived from ir_model_data),
-- and the post_init hook / migrations search by this key prefix.
UPDATE ir_ui_view
SET key = replace(key, 'fusion_authorizer_portal.', 'fusion_portal.')
WHERE key LIKE 'fusion_authorizer_portal.%';
-- 4) Dependency rows of OTHER modules that depend on this one
-- (fusion_schedule, fusion_repairs, fusion_quotations, and any future ones).
UPDATE ir_module_module_dependency
SET name = 'fusion_portal'
WHERE name = 'fusion_authorizer_portal';
-- ---------------------------------------------------------------------------
-- Verification — every count below must be 0 after the updates above.
-- ---------------------------------------------------------------------------
SELECT 'ir_module_module' AS table, count(*) AS remaining FROM ir_module_module WHERE name = 'fusion_authorizer_portal'
UNION ALL
SELECT 'ir_model_data', count(*) FROM ir_model_data WHERE module = 'fusion_authorizer_portal'
UNION ALL
SELECT 'ir_ui_view.key', count(*) FROM ir_ui_view WHERE key LIKE 'fusion_authorizer_portal.%'
UNION ALL
SELECT 'ir_module_module_dependency', count(*) FROM ir_module_module_dependency WHERE name = 'fusion_authorizer_portal';
-- If all four show 0, COMMIT. Otherwise ROLLBACK and investigate.
COMMIT;
-- Optional: force a clean recompile of web asset bundles (paths changed).
-- DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%';
-- (safe; Odoo regenerates bundles on next page load / -u.)

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -862,3 +862,82 @@
padding: 14px 18px;
}
}
/* ============================================================= */
/* Accessibility Assessment selector — modern photo cards */
/* Per-card colour is set inline via --fp-acc-accent / --fp-acc-fg */
/* ============================================================= */
.fp-acc-card {
display: flex;
flex-direction: column;
color: inherit;
background-color: #ffffff;
border: 1px solid #e6e8eb;
border-radius: 14px;
overflow: hidden;
transition: transform .18s ease, box-shadow .18s ease;
}
.fp-acc-card:hover,
.fp-acc-card:focus {
color: inherit;
transform: translateY(-4px);
box-shadow: 0 14px 30px rgba(16, 24, 40, .15) !important;
}
.fp-acc-thumb {
position: relative;
aspect-ratio: 3 / 2;
overflow: hidden;
background-color: #f1f3f5;
}
.fp-acc-thumb img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: transform .4s ease;
}
.fp-acc-card:hover .fp-acc-thumb img {
transform: scale(1.06);
}
.fp-acc-thumb::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 4px;
background-color: var(--fp-acc-accent, #0d6efd);
}
.fp-acc-card .card-body {
display: flex;
flex-direction: column;
flex: 1 1 auto;
padding: 1rem 1.15rem 1.2rem;
text-align: center;
}
.fp-acc-title {
font-weight: 600;
color: #1a1d21;
margin-bottom: .4rem;
}
.fp-acc-card .card-text {
flex: 1 1 auto;
}
.fp-acc-btn {
display: inline-flex;
align-items: center;
gap: .45rem;
align-self: center;
margin-top: .85rem;
padding: .5rem 1rem;
font-weight: 600;
font-size: .9rem;
line-height: 1;
border-radius: 8px;
color: var(--fp-acc-fg, #ffffff);
background-color: var(--fp-acc-accent, #0d6efd);
transition: filter .15s ease;
}
.fp-acc-card:hover .fp-acc-btn {
filter: brightness(.92);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@@ -2,7 +2,7 @@
* Fusion Authorizer Portal - Assessment Form
*/
odoo.define('fusion_authorizer_portal.assessment_form', function (require) {
odoo.define('fusion_portal.assessment_form', function (require) {
'use strict';
var publicWidget = require('web.public.widget');

View File

@@ -2,7 +2,7 @@
* Fusion Authorizer Portal - Real-time Search
*/
odoo.define('fusion_authorizer_portal.portal_search', function (require) {
odoo.define('fusion_portal.portal_search', function (require) {
'use strict';
var publicWidget = require('web.public.widget');

View File

@@ -3,7 +3,7 @@
* Touch-enabled digital signature capture
*/
odoo.define('fusion_authorizer_portal.signature_pad', function (require) {
odoo.define('fusion_portal.signature_pad', function (require) {
'use strict';
var publicWidget = require('web.public.widget');

View File

@@ -35,7 +35,7 @@
try {
// Register service worker
var registration = await navigator.serviceWorker.register(
'/fusion_authorizer_portal/static/src/js/technician_sw.js',
'/fusion_portal/static/src/js/technician_sw.js',
{scope: '/my/technician/'}
);

View File

@@ -15,8 +15,8 @@ self.addEventListener('push', function(event) {
var options = {
body: data.body || '',
icon: '/fusion_authorizer_portal/static/description/icon.png',
badge: '/fusion_authorizer_portal/static/description/icon.png',
icon: '/fusion_portal/static/description/icon.png',
badge: '/fusion_portal/static/description/icon.png',
tag: 'tech-task-' + (data.task_id || 'general'),
renotify: true,
data: {

View File

@@ -34,7 +34,7 @@
<input type="hidden" name="assessment_type" value="stairlift_straight"/>
<!-- Client Info -->
<t t-call="fusion_authorizer_portal.accessibility_client_info_section"/>
<t t-call="fusion_portal.accessibility_client_info_section"/>
<!-- Stair Measurements -->
<div class="card mb-4">
@@ -130,18 +130,18 @@
</div>
<!-- Photos -->
<t t-call="fusion_authorizer_portal.accessibility_photo_section"/>
<t t-call="fusion_portal.accessibility_photo_section"/>
<!-- Notes -->
<t t-call="fusion_authorizer_portal.accessibility_notes_section"/>
<t t-call="fusion_portal.accessibility_notes_section"/>
<!-- Submit Buttons -->
<t t-call="fusion_authorizer_portal.accessibility_submit_buttons"/>
<t t-call="fusion_portal.accessibility_submit_buttons"/>
</form>
</div>
<!-- Scripts -->
<t t-call="fusion_authorizer_portal.accessibility_form_scripts"/>
<t t-call="fusion_portal.accessibility_form_scripts"/>
<script type="text/javascript">
// Constants for track calculations
@@ -282,7 +282,7 @@
<input type="hidden" name="assessment_type" value="stairlift_curved"/>
<!-- Client Info -->
<t t-call="fusion_authorizer_portal.accessibility_client_info_section"/>
<t t-call="fusion_portal.accessibility_client_info_section"/>
<!-- Stair Measurements -->
<div class="card mb-4">
@@ -491,18 +491,18 @@
</div>
<!-- Photos -->
<t t-call="fusion_authorizer_portal.accessibility_photo_section"/>
<t t-call="fusion_portal.accessibility_photo_section"/>
<!-- Notes -->
<t t-call="fusion_authorizer_portal.accessibility_notes_section"/>
<t t-call="fusion_portal.accessibility_notes_section"/>
<!-- Submit Buttons -->
<t t-call="fusion_authorizer_portal.accessibility_submit_buttons"/>
<t t-call="fusion_portal.accessibility_submit_buttons"/>
</form>
</div>
<!-- Scripts -->
<t t-call="fusion_authorizer_portal.accessibility_form_scripts"/>
<t t-call="fusion_portal.accessibility_form_scripts"/>
<script type="text/javascript">
// Landing type track lengths (in inches)
@@ -703,7 +703,7 @@
<input type="hidden" name="assessment_type" value="vpl"/>
<!-- Client Info -->
<t t-call="fusion_authorizer_portal.accessibility_client_info_section"/>
<t t-call="fusion_portal.accessibility_client_info_section"/>
<!-- Room Dimensions -->
<div class="card mb-4">
@@ -808,18 +808,18 @@
</div>
<!-- Photos -->
<t t-call="fusion_authorizer_portal.accessibility_photo_section"/>
<t t-call="fusion_portal.accessibility_photo_section"/>
<!-- Notes -->
<t t-call="fusion_authorizer_portal.accessibility_notes_section"/>
<t t-call="fusion_portal.accessibility_notes_section"/>
<!-- Submit Buttons -->
<t t-call="fusion_authorizer_portal.accessibility_submit_buttons"/>
<t t-call="fusion_portal.accessibility_submit_buttons"/>
</form>
</div>
<!-- Scripts -->
<t t-call="fusion_authorizer_portal.accessibility_form_scripts"/>
<t t-call="fusion_portal.accessibility_form_scripts"/>
</t>
</template>
@@ -850,7 +850,7 @@
<input type="hidden" name="assessment_type" value="ceiling_lift"/>
<!-- Client Info -->
<t t-call="fusion_authorizer_portal.accessibility_client_info_section"/>
<t t-call="fusion_portal.accessibility_client_info_section"/>
<!-- Track Specifications -->
<div class="card mb-4">
@@ -905,18 +905,18 @@
</div>
<!-- Photos -->
<t t-call="fusion_authorizer_portal.accessibility_photo_section"/>
<t t-call="fusion_portal.accessibility_photo_section"/>
<!-- Notes -->
<t t-call="fusion_authorizer_portal.accessibility_notes_section"/>
<t t-call="fusion_portal.accessibility_notes_section"/>
<!-- Submit Buttons -->
<t t-call="fusion_authorizer_portal.accessibility_submit_buttons"/>
<t t-call="fusion_portal.accessibility_submit_buttons"/>
</form>
</div>
<!-- Scripts -->
<t t-call="fusion_authorizer_portal.accessibility_form_scripts"/>
<t t-call="fusion_portal.accessibility_form_scripts"/>
</t>
</template>
@@ -947,7 +947,7 @@
<input type="hidden" name="assessment_type" value="ramp"/>
<!-- Client Info -->
<t t-call="fusion_authorizer_portal.accessibility_client_info_section"/>
<t t-call="fusion_portal.accessibility_client_info_section"/>
<!-- Ramp Measurements -->
<div class="card mb-4">
@@ -1022,18 +1022,18 @@
</div>
<!-- Photos -->
<t t-call="fusion_authorizer_portal.accessibility_photo_section"/>
<t t-call="fusion_portal.accessibility_photo_section"/>
<!-- Notes -->
<t t-call="fusion_authorizer_portal.accessibility_notes_section"/>
<t t-call="fusion_portal.accessibility_notes_section"/>
<!-- Submit Buttons -->
<t t-call="fusion_authorizer_portal.accessibility_submit_buttons"/>
<t t-call="fusion_portal.accessibility_submit_buttons"/>
</form>
</div>
<!-- Scripts -->
<t t-call="fusion_authorizer_portal.accessibility_form_scripts"/>
<t t-call="fusion_portal.accessibility_form_scripts"/>
<script type="text/javascript">
function calculateRampLength() {
@@ -1089,7 +1089,7 @@
<input type="hidden" name="assessment_type" value="bathroom"/>
<!-- Client Info -->
<t t-call="fusion_authorizer_portal.accessibility_client_info_section"/>
<t t-call="fusion_portal.accessibility_client_info_section"/>
<!-- Modification Description -->
<div class="card mb-4">
@@ -1116,18 +1116,18 @@
</div>
<!-- Photos -->
<t t-call="fusion_authorizer_portal.accessibility_photo_section"/>
<t t-call="fusion_portal.accessibility_photo_section"/>
<!-- Notes -->
<t t-call="fusion_authorizer_portal.accessibility_notes_section"/>
<t t-call="fusion_portal.accessibility_notes_section"/>
<!-- Submit Buttons -->
<t t-call="fusion_authorizer_portal.accessibility_submit_buttons"/>
<t t-call="fusion_portal.accessibility_submit_buttons"/>
</form>
</div>
<!-- Scripts -->
<t t-call="fusion_authorizer_portal.accessibility_form_scripts"/>
<t t-call="fusion_portal.accessibility_form_scripts"/>
</t>
</template>
@@ -1158,7 +1158,7 @@
<input type="hidden" name="assessment_type" value="tub_cutout"/>
<!-- Client Info -->
<t t-call="fusion_authorizer_portal.accessibility_client_info_section"/>
<t t-call="fusion_portal.accessibility_client_info_section"/>
<!-- Tub Measurements -->
<div class="card mb-4">
@@ -1204,18 +1204,18 @@
</div>
<!-- Photos -->
<t t-call="fusion_authorizer_portal.accessibility_photo_section"/>
<t t-call="fusion_portal.accessibility_photo_section"/>
<!-- Notes -->
<t t-call="fusion_authorizer_portal.accessibility_notes_section"/>
<t t-call="fusion_portal.accessibility_notes_section"/>
<!-- Submit Buttons -->
<t t-call="fusion_authorizer_portal.accessibility_submit_buttons"/>
<t t-call="fusion_portal.accessibility_submit_buttons"/>
</form>
</div>
<!-- Scripts -->
<t t-call="fusion_authorizer_portal.accessibility_form_scripts"/>
<t t-call="fusion_portal.accessibility_form_scripts"/>
</t>
</template>

View File

@@ -39,134 +39,134 @@
<div class="row">
<!-- Stair Lifts -->
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="mb-3">
<i class="fa fa-level-up fa-3x text-primary"></i>
</div>
<h5 class="card-title">Straight Stair Lift</h5>
<a href="/my/accessibility/stairlift/straight" class="card h-100 shadow-sm fp-acc-card text-decoration-none" style="--fp-acc-accent: #0d6efd; --fp-acc-fg: #ffffff;">
<div class="fp-acc-thumb">
<img src="/fusion_portal/static/src/img/accessibility/straight-stair-lift.jpg" alt="Straight Stair Lift" loading="lazy"/>
</div>
<div class="card-body">
<h5 class="card-title fp-acc-title">Straight Stair Lift</h5>
<p class="card-text text-muted small">
Standard stair lift for straight staircases.
Includes track length calculation.
</p>
<a href="/my/accessibility/stairlift/straight" class="btn btn-primary btn-block">
<span class="fp-acc-btn">
<i class="fa fa-plus-circle"></i> Start Assessment
</a>
</span>
</div>
</div>
</a>
</div>
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="mb-3">
<i class="fa fa-refresh fa-3x text-info"></i>
</div>
<h5 class="card-title">Curved Stair Lift</h5>
<a href="/my/accessibility/stairlift/curved" class="card h-100 shadow-sm fp-acc-card text-decoration-none" style="--fp-acc-accent: #17a2b8; --fp-acc-fg: #ffffff;">
<div class="fp-acc-thumb">
<img src="/fusion_portal/static/src/img/accessibility/curved-stair-lift.jpg" alt="Curved Stair Lift" loading="lazy"/>
</div>
<div class="card-body">
<h5 class="card-title fp-acc-title">Curved Stair Lift</h5>
<p class="card-text text-muted small">
Custom curved stair lift with parking options.
Includes curve and step calculations.
</p>
<a href="/my/accessibility/stairlift/curved" class="btn btn-info btn-block">
<span class="fp-acc-btn">
<i class="fa fa-plus-circle"></i> Start Assessment
</a>
</span>
</div>
</div>
</a>
</div>
<!-- VPL -->
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="mb-3">
<i class="fa fa-arrows-v fa-3x text-success"></i>
</div>
<h5 class="card-title">Vertical Platform Lift</h5>
<a href="/my/accessibility/vpl" class="card h-100 shadow-sm fp-acc-card text-decoration-none" style="--fp-acc-accent: #198754; --fp-acc-fg: #ffffff;">
<div class="fp-acc-thumb">
<img src="/fusion_portal/static/src/img/accessibility/vertical-platform-lift.jpg" alt="Vertical Platform Lift" loading="lazy"/>
</div>
<div class="card-body">
<h5 class="card-title fp-acc-title">Vertical Platform Lift</h5>
<p class="card-text text-muted small">
VPL assessment with room dimensions,
power requirements, and certification.
</p>
<a href="/my/accessibility/vpl" class="btn btn-success btn-block">
<span class="fp-acc-btn">
<i class="fa fa-plus-circle"></i> Start Assessment
</a>
</span>
</div>
</div>
</a>
</div>
<!-- Ceiling Lift -->
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="mb-3">
<i class="fa fa-cloud-upload fa-3x text-warning"></i>
</div>
<h5 class="card-title">Ceiling Lift</h5>
<a href="/my/accessibility/ceiling-lift" class="card h-100 shadow-sm fp-acc-card text-decoration-none" style="--fp-acc-accent: #ffc107; --fp-acc-fg: #212529;">
<div class="fp-acc-thumb">
<img src="/fusion_portal/static/src/img/accessibility/ceiling-lift.jpg" alt="Ceiling Lift" loading="lazy"/>
</div>
<div class="card-body">
<h5 class="card-title fp-acc-title">Ceiling Lift</h5>
<p class="card-text text-muted small">
Ceiling lift with track length, movement type,
and additional features.
</p>
<a href="/my/accessibility/ceiling-lift" class="btn btn-warning btn-block">
<span class="fp-acc-btn">
<i class="fa fa-plus-circle"></i> Start Assessment
</a>
</span>
</div>
</div>
</a>
</div>
<!-- Custom Ramp -->
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="mb-3">
<i class="fa fa-road fa-3x text-danger"></i>
</div>
<h5 class="card-title">Custom Ramp</h5>
<a href="/my/accessibility/ramp" class="card h-100 shadow-sm fp-acc-card text-decoration-none" style="--fp-acc-accent: #dc3545; --fp-acc-fg: #ffffff;">
<div class="fp-acc-thumb">
<img src="/fusion_portal/static/src/img/accessibility/custom-ramp.jpg" alt="Custom Ramp" loading="lazy"/>
</div>
<div class="card-body">
<h5 class="card-title fp-acc-title">Custom Ramp</h5>
<p class="card-text text-muted small">
Ramp with Ontario Building Code compliance.
Auto-calculates length and landings.
</p>
<a href="/my/accessibility/ramp" class="btn btn-danger btn-block">
<span class="fp-acc-btn">
<i class="fa fa-plus-circle"></i> Start Assessment
</a>
</span>
</div>
</div>
</a>
</div>
<!-- Bathroom Modifications -->
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="mb-3">
<i class="fa fa-bath fa-3x text-secondary"></i>
</div>
<h5 class="card-title">Bathroom Modification</h5>
<a href="/my/accessibility/bathroom" class="card h-100 shadow-sm fp-acc-card text-decoration-none" style="--fp-acc-accent: #6c757d; --fp-acc-fg: #ffffff;">
<div class="fp-acc-thumb">
<img src="/fusion_portal/static/src/img/accessibility/bathroom-modification.jpg" alt="Bathroom Modification" loading="lazy"/>
</div>
<div class="card-body">
<h5 class="card-title fp-acc-title">Bathroom Modification</h5>
<p class="card-text text-muted small">
General bathroom modifications.
Free-form description with photos.
</p>
<a href="/my/accessibility/bathroom" class="btn btn-secondary btn-block">
<span class="fp-acc-btn">
<i class="fa fa-plus-circle"></i> Start Assessment
</a>
</span>
</div>
</div>
</a>
</div>
<!-- Tub Cutout -->
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="mb-3">
<i class="fa fa-cut fa-3x" style="color: #6c5ce7;"></i>
</div>
<h5 class="card-title">Tub Cutout</h5>
<a href="/my/accessibility/tub-cutout" class="card h-100 shadow-sm fp-acc-card text-decoration-none" style="--fp-acc-accent: #6c5ce7; --fp-acc-fg: #ffffff;">
<div class="fp-acc-thumb">
<img src="/fusion_portal/static/src/img/accessibility/tub-cutout.jpg" alt="Tub Cutout" loading="lazy"/>
</div>
<div class="card-body">
<h5 class="card-title fp-acc-title">Tub Cutout</h5>
<p class="card-text text-muted small">
Tub cutout assessment with internal and
external height measurements.
</p>
<a href="/my/accessibility/tub-cutout" class="btn btn-block" style="background: #6c5ce7; color: white;">
<span class="fp-acc-btn">
<i class="fa fa-plus-circle"></i> Start Assessment
</a>
</span>
</div>
</div>
</a>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More