diff --git a/barker/barker/routers/reports/beer_sale_report.py b/barker/barker/routers/reports/beer_sale_report.py index e2e7218..88f01fd 100644 --- a/barker/barker/routers/reports/beer_sale_report.py +++ b/barker/barker/routers/reports/beer_sale_report.py @@ -83,7 +83,7 @@ def beer_consumption( for date_, name, quantity in list_: if name not in headers: headers.append(name) - old = next((d for d in data if d["date"] == date_.strftime("%d-%b-%Y")), None) + old = next((d for d in data if d.date_ == date_.date()), None) if old: old[name] = quantity else: diff --git a/barker/barker/routers/reports/product_sale_report.py b/barker/barker/routers/reports/product_sale_report.py index 7d4dd7b..6afbee1 100644 --- a/barker/barker/routers/reports/product_sale_report.py +++ b/barker/barker/routers/reports/product_sale_report.py @@ -20,7 +20,6 @@ from ...models.sale_category import SaleCategory from ...models.voucher import Voucher from ...models.voucher_type import VoucherType from ...printing.product_sale_report import print_product_sale_report -from ...schemas import to_camel from ...schemas.product_sale_report import ProductSaleReport, ProductSaleReportItem, UserLink from ...schemas.user_token import UserToken from . import check_audit_permission, report_finish_date, report_start_date @@ -97,7 +96,7 @@ def product_sale_report( list_ = db.execute(query).all() info: list[ProductSaleReportItem] = [] for product_version_id, name, v_type, hh, quantity in list_: - type_ = to_camel(VoucherType(v_type).name) + type_ = VoucherType(v_type).name old = next((i for i in info if i.product_version_id == product_version_id and i.is_happy_hour == hh), None) if old: old[type_] = old[type_] + quantity diff --git a/barker/barker/schemas/beer_consumption_report.py b/barker/barker/schemas/beer_consumption_report.py new file mode 100644 index 0000000..e37af9f --- /dev/null +++ b/barker/barker/schemas/beer_consumption_report.py @@ -0,0 +1,79 @@ +from datetime import date, datetime +from decimal import Decimal +from typing import Any + +from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator, model_serializer + +from . import Daf, to_camel + + +class BeerConsumptionReportItem(BaseModel): + date_: date + + @field_validator("date_", mode="before") + @classmethod + def parse_date(cls, value: str | date) -> date: + if isinstance(value, date): + return value + return datetime.strptime(value, "%d-%b-%Y").date() + + @field_serializer("date_") + def serialize_date(self, value: date, _info: Any) -> str: + return value.strftime("%d-%b-%Y") + + # dynamic fields (e.g., regular, nc, kot) + dynamic_amounts: dict[str, Daf] = Field(default_factory=dict) + + model_config = ConfigDict(str_strip_whitespace=True, alias_generator=to_camel, populate_by_name=True) + + def __getitem__(self, item: str) -> Daf: + return self.dynamic_amounts.get(item, Decimal(0)) + + def __setitem__(self, key: str, value: Daf) -> None: + self.dynamic_amounts[key] = value + + def __contains__(self, key: str) -> bool: + return key in self.dynamic_amounts + + @model_serializer(mode="plain") + def custom_dump(self) -> dict: # type: ignore + base = { + "date": self.date_.strftime("%d-%b-%Y"), + } + # Merge dynamic fields + base.update({k: v for k, v in self.dynamic_amounts.items()}) # type: ignore + return base + + +class BeerConsumptionReport(BaseModel): + start_date: date + finish_date: date + regular: bool | None + happy: bool | None + staff: bool | None + nc: bool | None + headers: list[str] + data: list[BeerConsumptionReportItem] + model_config = ConfigDict(str_strip_whitespace=True, alias_generator=to_camel, populate_by_name=True) + + @field_validator("start_date", mode="before") + @classmethod + def parse_start_date(cls, value: str | date) -> date: + if isinstance(value, date): + return value + return datetime.strptime(value, "%d-%b-%Y").date() + + @field_serializer("start_date") + def serialize_start_date(self, value: date, _info: Any) -> str: + return value.strftime("%d-%b-%Y") + + @field_validator("finish_date", mode="before") + @classmethod + def parse_finish_date(cls, value: str | date) -> date: + if isinstance(value, date): + return value + return datetime.strptime(value, "%d-%b-%Y").date() + + @field_serializer("finish_date") + def serialize_finish_date(self, value: date, _info: Any) -> str: + return value.strftime("%d-%b-%Y") diff --git a/barker/barker/schemas/product_sale_report.py b/barker/barker/schemas/product_sale_report.py new file mode 100644 index 0000000..03034f0 --- /dev/null +++ b/barker/barker/schemas/product_sale_report.py @@ -0,0 +1,72 @@ +import uuid + +from datetime import date, datetime +from decimal import Decimal +from typing import Any + +from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator, model_serializer + +from . import Daf, to_camel +from .user import UserLink + + +class ProductSaleReportItem(BaseModel): + product_version_id: uuid.UUID + name: str + is_happy_hour: bool + + # dynamic fields (e.g., regular, nc, kot) + dynamic_amounts: dict[str, Daf] = Field(default_factory=dict) + + model_config = ConfigDict(str_strip_whitespace=True, alias_generator=to_camel, populate_by_name=True) + + def __getitem__(self, item: str) -> Daf: + return self.dynamic_amounts.get(item, Decimal(0)) + + def __setitem__(self, key: str, value: Daf) -> None: + self.dynamic_amounts[key] = value + + def __contains__(self, key: str) -> bool: + return key in self.dynamic_amounts + + @model_serializer(mode="plain") + def custom_dump(self) -> dict: # type: ignore + base = { + "productVersionId": str(self.product_version_id), + "name": self.name, + "isHappyHour": self.is_happy_hour, + } + # Merge dynamic fields + base.update({to_camel(k): v for k, v in self.dynamic_amounts.items()}) + return base + + +class ProductSaleReport(BaseModel): + start_date: date + finish_date: date + section_id: uuid.UUID | None + amounts: list[ProductSaleReportItem] + user: UserLink + model_config = ConfigDict(str_strip_whitespace=True, alias_generator=to_camel, populate_by_name=True) + + @field_validator("start_date", mode="before") + @classmethod + def parse_start_date(cls, value: str | date) -> date: + if isinstance(value, date): + return value + return datetime.strptime(value, "%d-%b-%Y").date() + + @field_serializer("start_date") + def serialize_start_date(self, value: date, _info: Any) -> str: + return value.strftime("%d-%b-%Y") + + @field_validator("finish_date", mode="before") + @classmethod + def parse_finish_date(cls, value: str | date) -> date: + if isinstance(value, date): + return value + return datetime.strptime(value, "%d-%b-%Y").date() + + @field_serializer("finish_date") + def serialize_finish_date(self, value: date, _info: Any) -> str: + return value.strftime("%d-%b-%Y")