Unzip budget-app v7 into repo root
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"""Groups a year's lines by category with computed figures; shared by the API and every report."""
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session, selectinload
|
||||
|
||||
from .calc import LineFigures, Totals, line_figures
|
||||
from .models import BudgetYear, Category, CostLine
|
||||
|
||||
|
||||
@dataclass
|
||||
class LineView:
|
||||
line: CostLine
|
||||
figures: LineFigures
|
||||
|
||||
|
||||
@dataclass
|
||||
class CategoryView:
|
||||
category: Category
|
||||
lines: list[LineView] = field(default_factory=list)
|
||||
totals: Totals = field(default_factory=Totals)
|
||||
|
||||
def name(self, lang: str) -> str:
|
||||
return (self.category.name_pt if lang == "pt" else "") or self.category.name_en
|
||||
|
||||
|
||||
@dataclass
|
||||
class YearView:
|
||||
year: BudgetYear
|
||||
categories: list[CategoryView]
|
||||
revenue: Totals
|
||||
costs: Totals
|
||||
|
||||
def with_lines(self, section: str | None = None) -> list[CategoryView]:
|
||||
return [c for c in self.categories if c.lines and (section is None or c.category.section == section)]
|
||||
|
||||
|
||||
def build_year_view(db: Session, year: BudgetYear, site_id: int | None = None) -> YearView:
|
||||
categories = db.scalars(select(Category).where(Category.department_id == year.department_id)
|
||||
.order_by(Category.sort_order, Category.id)).all()
|
||||
lines = db.scalars(
|
||||
select(CostLine)
|
||||
.where(CostLine.year_id == year.id)
|
||||
.options(selectinload(CostLine.site), selectinload(CostLine.category))
|
||||
.order_by(CostLine.sort_order, CostLine.id)
|
||||
).all()
|
||||
views = {c.id: CategoryView(c) for c in categories}
|
||||
for line in lines:
|
||||
if site_id is not None and line.site_id != site_id:
|
||||
continue
|
||||
lv = LineView(line, line_figures(line, year.default_rate))
|
||||
cv = views.get(line.category_id)
|
||||
if cv is None: # a line whose category was moved to another department
|
||||
cv = views[line.category_id] = CategoryView(line.category)
|
||||
cv.lines.append(lv)
|
||||
cv.totals.add(lv.figures)
|
||||
revenue, costs = Totals(), Totals()
|
||||
shown = []
|
||||
for cv in views.values():
|
||||
if not cv.lines and not (cv.category.active and cv.category.show_when_empty):
|
||||
continue
|
||||
shown.append(cv)
|
||||
target = revenue if cv.category.section == "revenue" else costs
|
||||
for lv in cv.lines:
|
||||
target.add(lv.figures)
|
||||
return YearView(year, shown, revenue, costs)
|
||||
Reference in New Issue
Block a user