| """Request context — the single object that carries the GLOBAL filters through a page render. |
| |
| Instead of threading date_from / date_to / team_id / ... through every function, a page builds |
| one `Ctx` from the sidebar controls and passes it (or its primitives) down. Modules read only |
| what they need. Add a new global filter once here and every module can opt into it. |
| |
| The DBA (doing-business-as) brand filter lives here as `team_id`: |
| None -> All / consolidated (Fisch + Royal) |
| 5 -> Fisch |
| 6 -> Royal |
| HQ / company-level modules (cash flow, balance sheet, AR/AP, consolidated P&L) ignore brand and |
| call `ctx.consolidated()`; operational modules (sales, customers, products, margins) honour it. |
| """ |
| from dataclasses import dataclass, replace |
| import core.odoo as O |
| import core.periods as P |
|
|
| |
| BRANDS = {'All': None, 'Fisch': 5, 'Royal': 6} |
|
|
|
|
| @dataclass(frozen=True) |
| class Ctx: |
| date_from: str |
| date_to: str |
| period_label: str = 'Year to date' |
| team_id: int | None = None |
| doc_mode: str = 'order' |
|
|
| @property |
| def brand(self) -> str: |
| return O.TEAM_NAMES.get(self.team_id, 'All') if self.team_id else 'All' |
|
|
| @property |
| def teams(self) -> list: |
| """Team ids in scope (single brand, or both when consolidated).""" |
| return [self.team_id] if self.team_id else list(O.TEAM_IDS) |
|
|
| @property |
| def window(self) -> tuple: |
| return self.date_from, self.date_to |
|
|
| def consolidated(self) -> 'Ctx': |
| """All-DBA copy — HQ modules use this so the brand filter never scopes company numbers.""" |
| return replace(self, team_id=None) |
|
|
| def with_period(self, date_from, date_to, label=None) -> 'Ctx': |
| return replace(self, date_from=date_from, date_to=date_to, |
| period_label=label or self.period_label) |
|
|
|
|
| def from_ui(period_label, period_window, brand_label='All', doc_mode='order') -> Ctx: |
| df, dt = period_window |
| return Ctx(df, dt, period_label, BRANDS.get(brand_label), doc_mode) |
|
|
|
|
| def default(t=None) -> Ctx: |
| df, dt = P.ytd(t) |
| return Ctx(df, dt, 'Year to date', None) |
|
|