loopable / platform /core /context.py
fsanyoto's picture
Deploy AIOS web (React glide grid + FastAPI slice)
c14ceee verified
Raw
History Blame Contribute Delete
2.28 kB
"""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
# label -> team_id used by the sidebar Brand (DBA) selector
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 # None = All DBAs (consolidated); 5 = Fisch; 6 = Royal
doc_mode: str = 'order' # reserved: 'order' vs 'invoice' recognition basis
@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)