docs(portal): session handoff + sub-A IA spec + plan
Captures everything the next Claude session needs to pick up cold:
- Live module versions on entech (portal 19.0.3.7.0, jobs/reports
versions, all 5 tests green)
- What shipped this session (24+ commits, summarised by area)
- Sub-A (IA + sidebar) brainstorm decisions locked, spec written,
plan ready to execute (11 tasks, 4 phases)
- What's deferred (sub-B multi-user, sub-C search, drafts, real
statements, RMA portal, top-recurring-parts) and WHY — so next
session doesn't re-litigate
- Gotchas hit + fixed this session that aren't obvious from code
- Deploy recipe (file copy + module upgrade + cache bust) used 20+
times this session
CLAUDE.md's Recent Session Handoff section now points to the new
handoff doc; the previous handoff is kept as 'superseded but kept
for context' below it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
# Portal Redesign — Session Handoff (2026-05-17)
|
||||
|
||||
> **Read this first.** This session ran long; the next session picks up here. Everything below is intentionally short. Authoritative details live in the linked spec / plan files.
|
||||
|
||||
## TL;DR
|
||||
|
||||
Customer-portal redesign across two long sessions. Dashboard + jobs + detail page + configurator are LIVE on entech. The next step (sidebar nav + page audit + Account Summary view) has an APPROVED PLAN ready to execute — do not re-brainstorm, just execute.
|
||||
|
||||
**Immediately actionable:** execute [`docs/superpowers/plans/2026-05-17-portal-ia-sidebar-plan.md`](../plans/2026-05-17-portal-ia-sidebar-plan.md) via `superpowers:subagent-driven-development` or `superpowers:executing-plans`. User was offered both at handoff time and chose subagent-driven (preferred). 11 tasks across 4 phases.
|
||||
|
||||
## Live state on entech (2026-05-17)
|
||||
|
||||
| Module | Version live | Notes |
|
||||
|---|---|---|
|
||||
| `fusion_plating_portal` | `19.0.3.7.0` | Dashboard, job cards, configurator, detail page, doc downloads, repeat order, animations — all shipped |
|
||||
| `fusion_plating_jobs` | `19.0.10.8.0` + write-hook + create-init | fp.job → fp.portal.job state-sync hook on write, initial state derive on create |
|
||||
| `fusion_plating_reports` | `19.0.11.15.0` | Customer Acceptance / Authorized Representative signature blocks removed from `report_fp_sale_portrait/landscape` |
|
||||
| All 5 portal unit tests green | | `--test-tags=fp_portal` |
|
||||
|
||||
Branch: `main`. Local repo is many commits ahead of `origin/main`; user has not been asked to push (per system-prompt safety default). Run `git log --oneline origin/main..HEAD` at session start to see what's outstanding.
|
||||
|
||||
## What shipped this session (high-level)
|
||||
|
||||
1. **Dashboard rebuild** — `/my/home` → jobs-forward layout (KPI tiles → Active Work Orders hero → 5 secondary panels). Welcome line summarises status in plain words. EN Plating teal brand palette with gradient CTAs.
|
||||
2. **Job card upgrade** — shared `fp_portal_job_card` macro (used by `/my/home` + `/my/jobs`). Wrap div + inner anchor + sibling actions footer (4 doc download chips + Repeat Order POST form). Part info + ship-to address pulled inline. Pulse animation on the active step circle + matching detail-page timeline dot.
|
||||
3. **Detail page** — V2 stepper + V3 timestamps + 5-group document panel (From You / Specifications / Work Order / Quality / Shipping). Sales Order Confirmation, Work Order Detail, CoC, Packing Slip all sudo-render from the FP custom reports. Hero shows part + ship-to.
|
||||
4. **Configurator fixes** — `/my/configurator/coating` 500 fixed (`fp.coating.config` → `fusion.plating.process.type`). Manual measurements hidden in step 1. Split single-file upload into Drawing (PDF) + 3D Model.
|
||||
5. **Sale report cleanup** — Customer Acceptance / Authorized Representative signature block removed.
|
||||
6. **Misc** — `/my` route added, button sizing normalised, hover-underline suppressed globally, sidebar of legacy stuff redirected, dashboard expanded to 5 panels (Quote Requests + Purchase Orders added).
|
||||
|
||||
24+ commits this session, all on `main`. Browse `git log --oneline -30` for the full sweep.
|
||||
|
||||
## What's queued for execution
|
||||
|
||||
**Sub-A (Portal IA + Sidebar):** plan ready, not yet executed. Brainstorm decisions baked in:
|
||||
|
||||
| Decision | Choice |
|
||||
|---|---|
|
||||
| Sidebar shape | **B** — Dashboard top, then grouped Activity / Documents / Account sections |
|
||||
| Account Summary tabs | 3 (Invoices / Credit Memos / Statements) + Open Balance pill in header |
|
||||
| Statements V1 | Placeholder card ("Coming soon") — real statement generation deferred |
|
||||
| Legacy URL redirects | `/my/fp_invoices` → `/my/account_summary`; `/my/purchase_orders` → `/my/orders` (Odoo default); `/my/quote_requests/new` GET → `/my/configurator/new` |
|
||||
| Future Users / Search slots | Omit from V1 (no "coming soon" placeholders); add when sub-B/sub-C ship |
|
||||
|
||||
Spec: [`docs/superpowers/specs/2026-05-17-portal-ia-sidebar-design.md`](../specs/2026-05-17-portal-ia-sidebar-design.md)
|
||||
|
||||
## What's deferred (do NOT re-litigate in next session)
|
||||
|
||||
These were explicitly scoped OUT during brainstorming. Open new brainstorm sessions for each when their turn comes:
|
||||
|
||||
- **Sub-B Multi-user account management** — invite teammates, role per user, per-action ACLs. Will add a Users item under the Account section of the sidebar.
|
||||
- **Sub-C Portal search** — global search across jobs / quotes / invoices / certs. Search input slot above Dashboard in the sidebar.
|
||||
- **Saved drafts (RFQ)** — user mentioned wanting drafts during configurator. Three scoping options proposed (minimal/medium/big); awaiting user direction. Not part of sub-A.
|
||||
- **Real Statements generation** — account.followup integration OR cron-precomputed monthly PDFs. Decide during sub-A Phase 3 implementation or defer to its own follow-up.
|
||||
- **Top Recurring Parts / Favorites / SerialNumber Lookup** — competitor-style features; deferred until customer demand confirmed.
|
||||
- **RMA customer portal** — sub-12 RMA backend exists; portal exposure is its own sub-project.
|
||||
|
||||
## Gotchas that bit us this session
|
||||
|
||||
Future Claude will hit these too unless documented. Most are already inline in CLAUDE.md or MEMORY.md. Worth a re-skim before touching the portal:
|
||||
|
||||
1. **`fp.coating.config` is retired** (Sub-11 cleanup). Use `fusion.plating.process.type` as the customer-facing coating taxonomy. Multiple `*.py` files still reference the dead model in COMMENTS — don't pattern-match from those.
|
||||
2. **Portal users can't read `fp.job` directly.** Controllers that return `fp.portal.job` records to a template MUST `sudo()` the search if the template traverses `job.x_fc_job_id`. Same pattern is already used for `sale.order`, `account.move`, `stock.picking`. Domain still filters to commercial partner tree.
|
||||
3. **`sale_pdf_quote_builder` gates on `report_name == 'sale.report_saleorder'`** (already in MEMORY.md). For customer-facing SO PDFs on the portal, render the FP custom `fusion_plating_reports.report_fp_sale_portrait` instead, and use a dedicated portal route that sudo-renders so the QWeb template can walk into `fp.part.catalog` etc.
|
||||
4. **Forms inside anchors is invalid HTML.** When making a whole card clickable AND embedding a Repeat-Order form inside, use a wrap div + inner anchor (main click target) + sibling actions footer (form lives here). Don't nest `<form>` inside `<a>`.
|
||||
5. **Groups list indexing drift.** `_fp_group_documents` builds the docs panel by appending to `groups[N]`. If you reorder the initial list or insert a new group mid-helper, every `groups[N]` reference shifts. The code has an inline warning comment now; respect it.
|
||||
6. **Per-stage timestamps are NULL on records created before the write hook deployed.** `_fp_get_stage_timeline` has a Date-fallback chain (received_date → received_at; actual_ship_date → shipped_at) plus linear interpolation for middle stages. Records created post-hook get real datetimes from the `fp.job.write()` mirror.
|
||||
7. **Stepper SCSS — `.o_fp_step_line` MUST stay nested inside `.o_fp_stepper`** (inline comment in the SCSS warns about this). When `flex:1` isn't applied because the rule slipped outside the parent, circles cluster on the left of the row.
|
||||
8. **Stepper labels align via absolute positioning per-unit** (not as a separate flex container). Wider labels like "Inspected" overflow equally to both sides of their circle's centre. Don't revert to the dual-container approach.
|
||||
9. **`fp.portal.job` state-sync map** uses `_FP_JOB_STATE_TO_PORTAL_STATE` in `fusion_plating_jobs/models/fp_job.py`. `on_hold` and `cancelled` deliberately NOT mirrored to the customer-facing state. Manager decision what to surface.
|
||||
|
||||
## How to deploy (entech LXC 111 on pve-worker5)
|
||||
|
||||
Same recipe used 20+ times this session. Per file:
|
||||
|
||||
```bash
|
||||
cat K:/Github/Odoo-Modules/fusion_plating/<module>/<path> | \
|
||||
ssh pve-worker5 "pct exec 111 -- bash -c 'cat > /mnt/extra-addons/custom/<module>/<path>'"
|
||||
```
|
||||
|
||||
Then upgrade module + run tests:
|
||||
|
||||
```bash
|
||||
ssh pve-worker5 "pct exec 111 -- bash -c 'systemctl stop odoo && \
|
||||
su - odoo -s /bin/bash -c \"/usr/bin/odoo -c /etc/odoo/odoo.conf -d admin \
|
||||
-u fusion_plating_portal --test-tags=fp_portal --stop-after-init 2>&1 | tail -25\" && \
|
||||
systemctl start odoo'"
|
||||
```
|
||||
|
||||
Bust asset cache for SCSS/JS changes:
|
||||
|
||||
```bash
|
||||
ssh pve-worker5 "pct exec 111 -- su - postgres -c \
|
||||
\"psql -d admin -c \\\"DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%';\\\"\""
|
||||
```
|
||||
|
||||
Service status / version check:
|
||||
|
||||
```bash
|
||||
ssh pve-worker5 "pct exec 111 -- bash -c 'systemctl is-active odoo'"
|
||||
ssh pve-worker5 "pct exec 111 -- su - postgres -c \
|
||||
\"psql -d admin -t -c \\\"SELECT latest_version FROM ir_module_module \
|
||||
WHERE name='fusion_plating_portal';\\\"\""
|
||||
```
|
||||
|
||||
## How to start the next session
|
||||
|
||||
1. Open Claude Code in `K:\Github\Odoo-Modules\fusion-plating` (or `K:\Github\Odoo-Modules\fusion_plating` — both work, the dash dir has only 3 modules but it's the active working dir for the user's terminal).
|
||||
2. First message: "Resume the portal sub-A IA work — execute the approved plan from this session."
|
||||
3. New session should:
|
||||
- Read `CLAUDE.md` (auto-loaded) — the "Recent Session Handoff" section at the top points back to this file
|
||||
- Read this handoff doc
|
||||
- Read the plan: `docs/superpowers/plans/2026-05-17-portal-ia-sidebar-plan.md`
|
||||
- Invoke `superpowers:subagent-driven-development` (or `executing-plans` for inline mode)
|
||||
- Execute the 11 tasks across 4 phases
|
||||
4. Optional but useful: re-run the existing test suite first to confirm starting from green: `--test-tags=fp_portal --stop-after-init`.
|
||||
|
||||
## Brainstorm artifacts
|
||||
|
||||
Visual companion mockups for this session live in `.superpowers/brainstorm/*/content/` (gitignored). Useful for visual comparison if needed:
|
||||
- `design-direction.html` — Modern SaaS / Corporate / Industrial picker
|
||||
- `saas-refinements.html` — V1/V2/V3 card variants
|
||||
- `dashboard-layout.html` — 6-card grid vs jobs-forward
|
||||
- `job-detail.html`, `branded-job-detail.html` — detail page mockups
|
||||
- `branded-dashboard.html` — final brand-applied dashboard
|
||||
- `sidebar-structure.html` — flat vs grouped vs hybrid (chose grouped)
|
||||
|
||||
Brainstorm server idles out after 30 min. Restart command:
|
||||
|
||||
```bash
|
||||
"C:/Users/gur_p/.claude/plugins/cache/claude-plugins-official/superpowers/5.0.7/skills/brainstorming/scripts/start-server.sh" \
|
||||
--project-dir "K:/Github/Odoo-Modules/fusion_plating"
|
||||
```
|
||||
|
||||
(Run in background; URL appears in `.superpowers/brainstorm/*/state/server-info`.)
|
||||
|
||||
## Critical files modified this session
|
||||
|
||||
If the next session needs to read context fast:
|
||||
- `fusion_plating_portal/controllers/portal.py` — most changes here
|
||||
- `fusion_plating_portal/controllers/portal_configurator.py` — coating model swap + dual upload
|
||||
- `fusion_plating_portal/views/fp_portal_dashboard.xml` — jobs-forward layout
|
||||
- `fusion_plating_portal/views/fp_portal_templates.xml` — jobs list + detail rewrites
|
||||
- `fusion_plating_portal/views/fp_portal_macros.xml` — `fp_portal_job_card`, `fp_portal_stepper`, `fp_portal_status_badge`, `fp_portal_doc_chip`, `fp_portal_doc_group`
|
||||
- `fusion_plating_portal/static/src/scss/_fp_portal_tokens.scss` — brand tokens
|
||||
- `fusion_plating_portal/static/src/scss/fp_portal_*.scss` — 7 partials (buttons, badges, cards, stepper, timeline, dashboard, legacy catch-all)
|
||||
- `fusion_plating_portal/models/fp_portal_job.py` — per-stage Datetime fields + write/create snapshot hooks
|
||||
- `fusion_plating_jobs/models/fp_job.py` — fp.job → fp.portal.job state-sync hook
|
||||
- `fusion_plating_portal/tests/test_portal_dashboard.py` — 5 tests, all green
|
||||
|
||||
## What user feedback is still outstanding
|
||||
|
||||
Nothing concrete waiting on user. Last thing the user did was approve the plan and say "create a handsoff script so i start a new session" — i.e., they want to pause here. Next session resumes execution.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,235 @@
|
||||
# Customer Portal — Information Architecture + Sidebar Nav
|
||||
|
||||
**Module**: `fusion_plating_portal` (touches `portal.portal_layout` inherit)
|
||||
**Date**: 2026-05-17
|
||||
**Status**: Design locked, awaiting implementation plan
|
||||
**Surface**: every `/my/*` page on `https://enplating.com`
|
||||
**Sub-project**: A (of A/B/C); B = multi-user, C = portal search — deferred to separate brainstorms.
|
||||
|
||||
## Problem
|
||||
|
||||
The post-2026-05-17 portal redesign gave us a credible dashboard + jobs-detail page, but the navigation between pages is still "scroll the standard Odoo portal cards and hope you find the right entry point." Eight distinct customer surfaces (`/my/home`, `/my/jobs`, `/my/quote_requests`, `/my/configurator`, `/my/purchase_orders`, `/my/fp_invoices`, `/my/deliveries`, `/my/certifications`) and there's no persistent way to move between them. The customer's competitor screenshot (Mobility Specialties Inc / Drive Medical) shows the right pattern: a sticky left sidebar that lists every section, current page highlighted, secondary "Company Account" group at the bottom.
|
||||
|
||||
This spec restructures the portal around that sidebar pattern, audits the existing pages (replace thin custom pages with Odoo defaults where the default is better), and adds one missing page — a consolidated **Account Summary** with tabbed Invoices / Credit Memos / Statements + an Open Balance pill — that the existing thin `/my/fp_invoices` page doesn't deliver.
|
||||
|
||||
## User stories
|
||||
|
||||
1. **As a returning customer**, I want a persistent sidebar showing every section so I can jump between Quote Requests and Work Orders without going through the dashboard.
|
||||
2. **As an accounting clerk**, when I open the portal I want a single Account Summary page with Open Balance + filterable invoices + credit memos + downloadable monthly statements — without hunting through three separate menu items.
|
||||
3. **As any customer**, I want the active page visually marked so I always know where I am.
|
||||
4. **As a mobile user**, the sidebar should collapse to a hamburger so the page content gets the screen.
|
||||
|
||||
## Locked design decisions (from brainstorming 2026-05-17)
|
||||
|
||||
| Decision | Choice | Why |
|
||||
|---|---|---|
|
||||
| Decomposition | A first (IA), B (multi-user) + C (search) deferred to separate brainstorms | Sidebar + pages are the foundation; building search before pages exist or a Users tab before the sidebar shape is locked would be rework. |
|
||||
| Sidebar shape | Option B — Dashboard at top, then 3 grouped sections (Activity / Documents / Account) | 10 items needs grouping to scan; matches how the redesigned dashboard already groups (KPI tiles → jobs hero → secondary panels). |
|
||||
| Account Summary tabs | 3 tabs: Invoices · Credit Memos · Statements, plus an "Open Balance: $X" pill in the page header | Mirrors competitor; one summary number front-of-mind, three drilldowns. |
|
||||
| Future placeholders | NEITHER "Users (soon)" nor a search input shown in the sidebar today | Empty placeholders add visual noise; ship them when sub-B / sub-C land. |
|
||||
| Sidebar persistence | Sticky on scroll; visible on every `/my/*` page (including Odoo defaults via `portal.portal_layout` inherit); sub-pages keep their parent highlighted | Industry standard. Consistency means the customer never loses their place. |
|
||||
| Mobile collapse | Below 768px the sidebar collapses to a hamburger button in the page header; opens as a slide-in drawer | Standard portal pattern, no content rearrangement needed. |
|
||||
| Single quote-creation path | `/my/quote_requests/new` redirects to `/my/configurator/new` | Two paths to the same outcome confuses customers; the configurator is the more complete flow. |
|
||||
| Sign Out placement | Bottom of sidebar, separated by a hairline border | Matches competitor; gets sign-out off the page chrome. |
|
||||
|
||||
## Scope
|
||||
|
||||
**IN SCOPE — pages restructured / new:**
|
||||
|
||||
- `/my/home` — keep dashboard, gets sidebar
|
||||
- `/my/jobs` — keep list, gets sidebar
|
||||
- `/my/jobs/<id>` — keep detail, gets sidebar (highlight parent)
|
||||
- `/my/quote_requests` — keep list, gets sidebar
|
||||
- `/my/quote_requests/<id>` — keep detail, gets sidebar
|
||||
- `/my/quote_requests/new` — **REDIRECT** to `/my/configurator/new`
|
||||
- `/my/configurator` — keep landing, gets sidebar
|
||||
- `/my/configurator/new`, `.../coating`, `.../estimate` — keep wizard, gets sidebar
|
||||
- `/my/purchase_orders` — **REDIRECT** to Odoo default `/my/orders`; controller + template deleted
|
||||
- `/my/fp_invoices` — **REDIRECT** to new `/my/account_summary`; controller + template deleted
|
||||
- `/my/account_summary` — **NEW** tabbed page (this spec)
|
||||
- `/my/deliveries` — keep, gets sidebar
|
||||
- `/my/certifications` — keep, gets sidebar
|
||||
- `/my/account` — Odoo default, gets sidebar
|
||||
- `/my/orders/<id>` — Odoo default, gets sidebar
|
||||
|
||||
**IN SCOPE — chrome:**
|
||||
|
||||
- New `fp_portal_shell` template that inherits `portal.portal_layout` and wraps every `o_portal` page body with a sticky 240px sidebar on the left.
|
||||
- Sidebar SCSS partial (`fp_portal_sidebar.scss`) — brand-teal active state, mint gradient highlight, hairline section dividers.
|
||||
- Mobile breakpoint: hamburger toggle + slide-in drawer below 768px.
|
||||
- All Odoo default portal pages (`/my/account`, `/my/orders`, `/my/orders/<id>`, `/my/invoices/<id>`, etc.) get the sidebar via the `portal.portal_layout` inherit — zero per-page edits.
|
||||
|
||||
**OUT OF SCOPE — deferred to other sub-projects:**
|
||||
|
||||
- Multi-user account management (sub-project B): Users tab in sidebar, invitation flow, per-action ACLs.
|
||||
- Portal search (sub-project C): global search input above Dashboard, search-result page.
|
||||
- Saved drafts (separate brainstorm — needs its own scoping).
|
||||
- Top Recurring Parts / Favorites / SerialNumber Lookup (defer until customer demand confirmed).
|
||||
- RMA customer portal (sub-project after RMA backend ships).
|
||||
|
||||
**OUT OF SCOPE — explicit non-goals:**
|
||||
|
||||
- Top-bar navigation, breadcrumbs redesign, footer changes — none of these are part of A.
|
||||
- Restyling Odoo default `/my/account` or `/my/orders/<id>` page BODIES. We give them the sidebar via the layout inherit, but their content stays Odoo-standard.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Sidebar shell
|
||||
|
||||
```
|
||||
fusion_plating_portal/views/fp_portal_shell.xml
|
||||
└── inherits portal.portal_layout
|
||||
└── injects .o_fp_portal_shell wrapper that contains:
|
||||
├── <aside class="o_fp_portal_sidebar"> (sticky, 240px)
|
||||
│ └── partner header + 4 sections + sign-out
|
||||
└── <main class="o_fp_portal_main"> (existing portal body)
|
||||
```
|
||||
|
||||
Per Odoo's `portal.portal_layout` extension pattern, we inherit and use `<xpath expr="//div[@id='wrap']" position="replace">` (or `position="inside"` on the right anchor — TBD during implementation) to wrap the existing layout. The sidebar is a single shared template (`fp_portal_sidebar`) rendered above the existing portal page body.
|
||||
|
||||
Active-state marker: each sidebar `<a>` reads the current `page_name` from the template context (already set by every FP route — `fp_dashboard`, `fp_jobs`, etc.) and applies `o_fp_sidebar_active` when matched. Falls back to URL prefix match for Odoo default pages (`/my/orders` → Purchase Orders highlighted, `/my/account` → Profile highlighted).
|
||||
|
||||
### Sidebar items (final list)
|
||||
|
||||
```
|
||||
ACME AEROSPACE <-- partner.commercial_partner_id.name
|
||||
─────────────────────────────────────────
|
||||
🏠 Dashboard /my/home
|
||||
ACTIVITY
|
||||
📄 Quote Requests /my/quote_requests
|
||||
+ Get a Quote /my/configurator
|
||||
🛒 Purchase Orders /my/orders (Odoo)
|
||||
⚙️ Work Orders /my/jobs
|
||||
DOCUMENTS
|
||||
📑 Certifications /my/certifications
|
||||
📦 Packing Slips /my/deliveries
|
||||
💰 Account Summary /my/account_summary (NEW)
|
||||
ACCOUNT
|
||||
👤 Profile /my/account (Odoo)
|
||||
─────────────────────────────────────────
|
||||
↪ Sign Out /web/session/logout
|
||||
```
|
||||
|
||||
Section headers (`ACTIVITY` / `DOCUMENTS` / `ACCOUNT`) are display-only, not links. The whole list is rendered from a single Python data structure in the template context (passed by a small helper on `FpCustomerPortal`), so adding the future Users / Drafts / Search items is a one-line addition.
|
||||
|
||||
### Account Summary page
|
||||
|
||||
**URL**: `/my/account_summary`
|
||||
**Controller method**: `portal_account_summary(self, **kw)` on `FpCustomerPortal`
|
||||
**Template**: `portal_my_account_summary` in `fp_portal_account_summary.xml` (new file)
|
||||
|
||||
**Page structure:**
|
||||
|
||||
```
|
||||
[ Account Summary ] Open Balance: $4,820.00
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
[ Invoices ] [ Credit Memos ] [ Statements ]
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
Showing: Open · Closed · All [Search PO or #__________ ] [Sort ▾]
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
# | Status | Posted On | PO # | Due Date | Balance | View PDF
|
||||
─────────────────────────────────────────────────────────────────────────────
|
||||
0035180274 | ● Open | May 13, 2026 | 53469 | Jun 12, 2026 | C$305.73 | View PDF
|
||||
...
|
||||
◀ Prev 1 2 3 4 5 Next ▶
|
||||
```
|
||||
|
||||
**Data sources (per tab):**
|
||||
|
||||
| Tab | Model + domain | Notes |
|
||||
|---|---|---|
|
||||
| Invoices | `account.move` where `move_type='out_invoice'`, `partner_id child_of commercial`, `state='posted'` | Today's `/my/fp_invoices` already does this; relocated here. |
|
||||
| Credit Memos | `account.move` where `move_type='out_refund'`, `partner_id child_of commercial`, `state='posted'` | Surfaces RMA credits when sub-12 RMA flow runs. Tab shows empty state with "No credits yet" when partner has none. |
|
||||
| Statements | Generated PDF per month via `account.followup` or a custom QWeb cron — **decided during implementation; preferred = use account.followup report directly per-customer with date filter** | Tab UI: month picker + Download button. |
|
||||
|
||||
**Open Balance pill** = sum of `amount_residual` across all open `out_invoice` records (regardless of tab). Computed in the controller, shown in the page header.
|
||||
|
||||
**Search box** = case-insensitive substring match on `name` (invoice number) OR `ref` (customer PO). Server-side filter, not JS.
|
||||
|
||||
**Sort options:** Newest → Oldest (default), Oldest → Newest, Largest balance, Smallest balance.
|
||||
|
||||
**Filter pills:** `Open` (residual > 0) / `Closed` (residual = 0) / `All`.
|
||||
|
||||
**Pagination:** 10 per page, server-side via `portal_pager`.
|
||||
|
||||
Invoice detail = existing Odoo `/my/invoices/<id>` page (no rewrite); the table's "View PDF" link goes to `/my/invoices/<id>?report_type=pdf&download=true` per Odoo's standard portal pattern.
|
||||
|
||||
### Mobile behavior
|
||||
|
||||
```scss
|
||||
@media (max-width: 768px) {
|
||||
.o_fp_portal_sidebar {
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.2s ease;
|
||||
position: fixed; top: 0; left: 0; bottom: 0;
|
||||
z-index: 1040;
|
||||
}
|
||||
.o_fp_portal_sidebar.o_fp_open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
.o_fp_portal_hamburger { display: inline-flex; }
|
||||
}
|
||||
@media (min-width: 769px) {
|
||||
.o_fp_portal_hamburger { display: none; }
|
||||
}
|
||||
```
|
||||
|
||||
Hamburger button lives in the page header (above the main content). Click toggles `o_fp_open` on the sidebar via 5-line vanilla JS (no framework). Backdrop click closes the drawer.
|
||||
|
||||
## Files
|
||||
|
||||
**NEW:**
|
||||
|
||||
- `fusion_plating_portal/views/fp_portal_shell.xml` — `portal.portal_layout` inherit + sidebar markup
|
||||
- `fusion_plating_portal/views/fp_portal_account_summary.xml` — `portal_my_account_summary` template
|
||||
- `fusion_plating_portal/static/src/scss/fp_portal_sidebar.scss` — sidebar styling (sticky, active state, sections, mobile drawer)
|
||||
- `fusion_plating_portal/static/src/js/fp_portal_sidebar.js` — hamburger toggle (vanilla JS, no OWL)
|
||||
|
||||
**MODIFY:**
|
||||
|
||||
- `fusion_plating_portal/controllers/portal.py`
|
||||
- NEW route `portal_account_summary` at `/my/account_summary`
|
||||
- DELETE route `portal_my_fp_invoices` (the thin invoice list at `/my/fp_invoices`)
|
||||
- REPLACE route `portal_my_purchase_orders` body with `return request.redirect('/my/orders')`
|
||||
- REPLACE the GET handler for `portal_my_quote_request_new` with `return request.redirect('/my/configurator/new')` (or delete entirely if the configurator already exposes the equivalent form)
|
||||
- NEW helper `_fp_sidebar_items(self)` returning the sidebar data structure (consumed by `fp_portal_sidebar` template via inherited `_prepare_portal_layout_values`)
|
||||
- Extend `_prepare_portal_layout_values()` to inject `fp_sidebar_items` + `fp_partner_display_name` into every portal page's context so the sidebar renders correctly on Odoo default pages too.
|
||||
- `fusion_plating_portal/views/fp_portal_templates.xml` — delete `portal_my_fp_invoices` template body (route is gone). Remaining templates (jobs list, jobs detail, deliveries, certifications) get the sidebar **for free** via the `portal.portal_layout` inherit; no per-template edits.
|
||||
- `fusion_plating_portal/views/fp_portal_dashboard.xml` — dashboard template gets the sidebar via the layout inherit; no edits needed.
|
||||
- `fusion_plating_portal/__manifest__.py` — version bump + register the new XML/SCSS/JS files. Add `fp_portal_shell.xml` near the TOP of the `data` list (loaded before any template that uses sidebar variables).
|
||||
|
||||
**DELETE (or stub):**
|
||||
|
||||
- The `portal_my_fp_invoices` template body and the `portal_my_purchase_orders` template body. Routes redirected, templates unused. Keep route stubs so existing bookmarks 302 cleanly instead of 404.
|
||||
|
||||
## Migration / backward compatibility
|
||||
|
||||
| Old URL | New behavior |
|
||||
|---|---|
|
||||
| `/my/fp_invoices` | 302 → `/my/account_summary` |
|
||||
| `/my/purchase_orders` | 302 → `/my/orders` |
|
||||
| `/my/quote_requests/new` | 302 → `/my/configurator/new` |
|
||||
|
||||
No DB migration. No template namespace changes that break inherits. The page audit removes routes from the controller and templates from the data list; Odoo's module-upgrade cycle handles the ORM-side cleanup.
|
||||
|
||||
## Open items to verify during implementation
|
||||
|
||||
1. **`portal.portal_layout` extension pattern** — confirm the cleanest xpath for injecting the sidebar wrapper without breaking Odoo's existing portal CSS (`#wrap`, `.o_portal`). Likely `position="before"` on the main content slot. If unclear, fall back to inheriting at the `website.layout` level and writing a wholly new shell template.
|
||||
2. **Statements tab data source** — decide between (a) inline render of `account.followup` report per requested month, vs (b) precomputed monthly statement PDFs stored as attachments. Latter is simpler for V1; cron generates last-month statement on the 1st.
|
||||
3. **Mobile hamburger placement** — header anchor: a small button at the top-left of the main content area (above the page title) on mobile only. Confirm during Phase 4 visual pass.
|
||||
4. **Page-name → active-item mapping** — most FP routes set a clean `page_name` (e.g., `fp_jobs`, `fp_dashboard`). Odoo defaults don't; we'll match by URL prefix (`/my/orders` → `purchase_orders` item). One-helper `_fp_resolve_active_sidebar_item(url, page_name)` keeps the mapping in one place.
|
||||
5. **Account Summary Statements scope** — confirm whether monthly statements are something EN Plating currently generates, or if this is a new artifact we need to define a template for. If the latter, that's a separate small spec.
|
||||
|
||||
## What ships in a "done" state
|
||||
|
||||
- Every `/my/*` page (FP + Odoo default) shows the new sidebar.
|
||||
- Active page is visually marked.
|
||||
- Sidebar collapses to hamburger drawer below 768px.
|
||||
- `/my/account_summary` exists with 3 tabs, Open Balance pill, search + filter pills + sort + pagination.
|
||||
- 3 legacy URLs (`/my/fp_invoices`, `/my/purchase_orders`, `/my/quote_requests/new`) 302-redirect to their new homes.
|
||||
- Unit tests cover the new account_summary controller (3 tabs return the right counts, filter/search produce the right subset, Open Balance sums residuals correctly).
|
||||
- Module version bumped, deployed to entech, all 5 existing portal tests still green plus 3+ new tests for Account Summary.
|
||||
|
||||
---
|
||||
|
||||
*Sub-projects B (multi-user) and C (portal search) are tracked separately — they'll consume the sidebar slot conventions (insertion under ACCOUNT for Users, above DASHBOARD for the search input) defined here.*
|
||||
Reference in New Issue
Block a user