From a1d6919d9d30f4e39d11410e7fb9a0fcc5561656 Mon Sep 17 00:00:00 2001 From: Amritanshu Date: Sat, 14 Feb 2026 05:29:11 +0000 Subject: [PATCH] Beer consumption report can choose menu category for beer --- barker/barker/models/inventory.py | 2 +- barker/barker/models/inventory_modifier.py | 2 +- barker/barker/models/role_includes.py | 4 ++-- barker/barker/routers/product.py | 19 +++--------------- .../routers/reports/beer_sale_report.py | 8 ++++++++ .../barker/schemas/beer_consumption_report.py | 2 ++ .../beer-sale-report.component.html | 12 ++++++++++- .../beer-sale-report.component.ts | 20 +++++++++++++++++-- .../beer-sale-report.resolver.ts | 3 ++- .../beer-sale-report.routes.ts | 2 ++ .../beer-sale-report.service.ts | 4 ++++ .../app/beer-sale-report/beer-sale-report.ts | 3 +++ 12 files changed, 57 insertions(+), 24 deletions(-) diff --git a/barker/barker/models/inventory.py b/barker/barker/models/inventory.py index bdd74b58..0f21fbbd 100644 --- a/barker/barker/models/inventory.py +++ b/barker/barker/models/inventory.py @@ -53,7 +53,7 @@ class Inventory: type_: Mapped[InventoryType] = mapped_column( "type", Enum(InventoryType), server_default=text("regular"), nullable=False ) - parent_id: Mapped[uuid.UUID | None] = mapped_column(Uuid, ForeignKey("inventories.id"), nullable=True) + parent_id: Mapped[uuid.UUID | None] = mapped_column(Uuid, ForeignKey("inventories.id"), nullable=True, index=True) kot: Mapped[Kot] = relationship(back_populates="inventories") tax: Mapped[Tax] = relationship(back_populates="inventories") diff --git a/barker/barker/models/inventory_modifier.py b/barker/barker/models/inventory_modifier.py index 3adf8152..a8ad07df 100644 --- a/barker/barker/models/inventory_modifier.py +++ b/barker/barker/models/inventory_modifier.py @@ -22,7 +22,7 @@ class InventoryModifier: __table_args__ = (UniqueConstraint("inventory_id", "modifier_id"),) id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, server_default=text("gen_random_uuid()")) - inventory_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("inventories.id"), nullable=False) + inventory_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("inventories.id"), nullable=False, index=True) modifier_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("modifiers.id"), nullable=False) price: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False) diff --git a/barker/barker/models/role_includes.py b/barker/barker/models/role_includes.py index 4c11ca94..0044e4a2 100644 --- a/barker/barker/models/role_includes.py +++ b/barker/barker/models/role_includes.py @@ -24,5 +24,5 @@ class RoleInclude: id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, server_default=text("gen_random_uuid()")) - role_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("roles.id"), nullable=False) - included_role_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("roles.id"), nullable=False) + role_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("roles.id"), nullable=False, index=True) + included_role_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("roles.id"), nullable=False, index=True) diff --git a/barker/barker/routers/product.py b/barker/barker/routers/product.py index 1e4408f3..1da9cee3 100644 --- a/barker/barker/routers/product.py +++ b/barker/barker/routers/product.py @@ -32,7 +32,7 @@ from ..schemas.sale_category import SaleCategoryLink from ..schemas.stock_keeping_unit import StockKeepingUnit as StockKeepingUnitSchema from ..schemas.tax import TaxLink from ..schemas.user_token import UserToken -from . import _pv_onclause, _sv_onclause, effective_date +from . import _pv_active, _pv_onclause, _sv_onclause, effective_date router = APIRouter() @@ -241,7 +241,6 @@ def update_route( or new_data_sku.has_happy_hour != sku.has_happy_hour or new_data_sku.menu_category.id_ != sku.menu_category_id ) - print(f"SKU Changed: {sku_changed} for {sku.id}") sku.sku.sort_order = new_data_sku.sort_order sku.sku.is_not_available = new_data_sku.is_not_available if sku_changed: @@ -471,7 +470,6 @@ def show_term( ) -> list[ProductQuery]: product_version_onclause = _pv_onclause(date_) sku_version_onclause = _sv_onclause(date_) - print(f"Fetching products for MenuCategory: {mc}, SaleCategory: {sc}, Date: {date_}") list_: list[ProductQuery] = [] query = ( select(SkuVersion) @@ -525,17 +523,6 @@ def show_id( date_: date = Depends(effective_date), user: UserToken = Security(get_user, scopes=["products"]), ) -> schemas.Product: - pv_active = and_( - ProductVersion.product_id == id_, - or_(ProductVersion.valid_from == None, ProductVersion.valid_from <= date_), # noqa: E711 - or_(ProductVersion.valid_till == None, ProductVersion.valid_till >= date_), # noqa: E711 - ) - - sku_version_onclause = and_( - SkuVersion.sku_id == StockKeepingUnit.id, - or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= date_), # noqa: E711 - or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= date_), # noqa: E711 - ) with SessionFuture() as db: version: ProductVersion = ( db.execute( @@ -543,9 +530,9 @@ def show_id( .join(ProductVersion.sale_category) .join(ProductVersion.product) .join(Product.skus) - .join(SkuVersion, onclause=sku_version_onclause) + .join(SkuVersion, onclause=_sv_onclause(date_)) .join(SkuVersion.menu_category) - .where(pv_active) + .where(ProductVersion.product_id == id_, _pv_active(date_)) .order_by( StockKeepingUnit.sort_order, SkuVersion.units, diff --git a/barker/barker/routers/reports/beer_sale_report.py b/barker/barker/routers/reports/beer_sale_report.py index af86afff..b6349f7c 100644 --- a/barker/barker/routers/reports/beer_sale_report.py +++ b/barker/barker/routers/reports/beer_sale_report.py @@ -1,3 +1,5 @@ +import uuid + from datetime import date, timedelta from fastapi import APIRouter, Depends, Security @@ -16,6 +18,7 @@ from ...models.stock_keeping_unit import StockKeepingUnit from ...models.voucher import Voucher from ...models.voucher_type import VoucherType from ...schemas.beer_consumption_report import BeerConsumptionReport, BeerConsumptionReportItem +from ...schemas.menu_category import MenuCategoryLink from ...schemas.user_token import UserToken from .. import _pv_onclause, _sv_onclause from . import check_audit_permission, report_finish_date, report_start_date @@ -28,6 +31,7 @@ router = APIRouter() def beer_consumption( start_date: date = Depends(report_start_date), finish_date: date = Depends(report_finish_date), + m: uuid.UUID | None = None, # Menu Category r: bool | None = True, h: bool | None = True, st: bool | None = True, @@ -47,6 +51,7 @@ def beer_consumption( .join(Kot.inventories) .join(Inventory.sku) .join(SkuVersion, onclause=sku_version_onclause) + .join(SkuVersion.menu_category) .join(StockKeepingUnit.product) .join(ProductVersion, onclause=product_version_onclause) .where( @@ -55,6 +60,8 @@ def beer_consumption( day <= finish_date, ) ) + if m: + query = query.where(SkuVersion.menu_category_id == m) if h is False and r is not False: query = query.where(Inventory.is_happy_hour == h) if r is False and h is not False: @@ -89,6 +96,7 @@ def beer_consumption( return BeerConsumptionReport( start_date=start_date, finish_date=finish_date, + menu_category=MenuCategoryLink(id_=m, name="", skus=[]) if m else None, regular=r, happy=h, staff=st, diff --git a/barker/barker/schemas/beer_consumption_report.py b/barker/barker/schemas/beer_consumption_report.py index 42c670a8..b4083ef4 100644 --- a/barker/barker/schemas/beer_consumption_report.py +++ b/barker/barker/schemas/beer_consumption_report.py @@ -13,6 +13,7 @@ from pydantic import ( ) from . import Daf, to_camel +from .menu_category import MenuCategoryLink class BeerConsumptionReportItem(BaseModel): @@ -56,6 +57,7 @@ class BeerConsumptionReportItem(BaseModel): class BeerConsumptionReport(BaseModel): start_date: date finish_date: date + menu_category: MenuCategoryLink | None regular: bool | None happy: bool | None staff: bool | None diff --git a/bookie/src/app/beer-sale-report/beer-sale-report.component.html b/bookie/src/app/beer-sale-report/beer-sale-report.component.html index 6b5d8969..aa8e90eb 100644 --- a/bookie/src/app/beer-sale-report/beer-sale-report.component.html +++ b/bookie/src/app/beer-sale-report/beer-sale-report.component.html @@ -31,6 +31,16 @@ + + Menu Category + + @for (mc of menuCategories; track mc) { + + {{ mc.name }} + + } + +
@@ -51,7 +61,7 @@ @for (col of info.headers; track col) { {{ col }} - {{ row[col] }} + {{ row[col] | number: '1.2-2' }} } diff --git a/bookie/src/app/beer-sale-report/beer-sale-report.component.ts b/bookie/src/app/beer-sale-report/beer-sale-report.component.ts index 1ea0235a..d20da2c4 100644 --- a/bookie/src/app/beer-sale-report/beer-sale-report.component.ts +++ b/bookie/src/app/beer-sale-report/beer-sale-report.component.ts @@ -1,3 +1,4 @@ +import { CommonModule } from '@angular/common'; import { Component, OnInit, inject } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; @@ -6,10 +7,12 @@ import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { MatTableModule } from '@angular/material/table'; import { ActivatedRoute, Router } from '@angular/router'; import moment from 'moment'; +import { MenuCategory } from '../core/menu-category'; import { ToCsvService } from '../shared/to-csv.service'; import { BeerSaleExportHeaderInterface } from './beer-sale-export-header-interface'; import { BeerSaleReport } from './beer-sale-report'; @@ -20,13 +23,14 @@ import { BeerSaleReportDataSource } from './beer-sale-report-datasource'; templateUrl: './beer-sale-report.component.html', styleUrls: ['./beer-sale-report.component.css'], imports: [ + CommonModule, MatButtonModule, - MatCheckboxModule, MatDatepickerModule, MatFormFieldModule, MatIconModule, MatInputModule, + MatSelectModule, MatTableModule, ReactiveFormsModule, ], @@ -36,11 +40,13 @@ export class BeerSaleReportComponent implements OnInit { private router = inject(Router); private toCsv = inject(ToCsvService); + menuCategories: MenuCategory[] = []; info: BeerSaleReport = new BeerSaleReport(); dataSource: BeerSaleReportDataSource = new BeerSaleReportDataSource(this.info.data); form: FormGroup<{ startDate: FormControl; finishDate: FormControl; + menuCategory: FormControl; regular: FormControl; happy: FormControl; staff: FormControl; @@ -55,6 +61,7 @@ export class BeerSaleReportComponent implements OnInit { this.form = new FormGroup({ startDate: new FormControl(new Date(), { nonNullable: true }), finishDate: new FormControl(new Date(), { nonNullable: true }), + menuCategory: new FormControl('', { nonNullable: true }), regular: new FormControl(true, { nonNullable: true }), happy: new FormControl(true, { nonNullable: true }), staff: new FormControl(true, { nonNullable: true }), @@ -64,12 +71,14 @@ export class BeerSaleReportComponent implements OnInit { ngOnInit() { this.route.data.subscribe((value) => { - const data = value as { info: BeerSaleReport }; + const data = value as { info: BeerSaleReport; menuCategories: MenuCategory[] }; this.info = data.info; + this.menuCategories = data.menuCategories; this.displayedColumns = ['date'].concat(this.info.headers); this.form.setValue({ startDate: moment(this.info.startDate, 'DD-MMM-YYYY').toDate(), finishDate: moment(this.info.finishDate, 'DD-MMM-YYYY').toDate(), + menuCategory: this.info.menuCategory?.id ?? '', regular: this.info.regular, happy: this.info.happy, staff: this.info.staff, @@ -85,6 +94,7 @@ export class BeerSaleReportComponent implements OnInit { queryParams: { startDate: info.startDate, finishDate: info.finishDate, + menuCategory: info.menuCategory?.id ?? '', regular: info.regular, happy: info.happy, staff: info.staff, @@ -93,12 +103,18 @@ export class BeerSaleReportComponent implements OnInit { }); } + filterOn(id: string) { + const mc = this.menuCategories.find((x) => x.id === id); + this.info.menuCategory = mc ? mc : new MenuCategory({ id }); + } + getInfo(): BeerSaleReport { const formModel = this.form.value; return new BeerSaleReport({ startDate: moment(formModel.startDate).format('DD-MMM-YYYY'), finishDate: moment(formModel.finishDate).format('DD-MMM-YYYY'), + menuCategory: this.info.menuCategory, regular: formModel.regular, happy: formModel.happy, staff: formModel.staff, diff --git a/bookie/src/app/beer-sale-report/beer-sale-report.resolver.ts b/bookie/src/app/beer-sale-report/beer-sale-report.resolver.ts index 911997cb..57c5388f 100644 --- a/bookie/src/app/beer-sale-report/beer-sale-report.resolver.ts +++ b/bookie/src/app/beer-sale-report/beer-sale-report.resolver.ts @@ -7,9 +7,10 @@ import { BeerSaleReportService } from './beer-sale-report.service'; export const beerSaleReportResolver: ResolveFn = (route) => { const startDate = route.queryParamMap.get('startDate') ?? null; const finishDate = route.queryParamMap.get('finishDate') ?? null; + const menuCategory = route.queryParamMap.get('menuCategory') ?? null; const regular = route.queryParamMap.get('regular') !== 'false'; const happy = route.queryParamMap.get('happy') !== 'false'; const staff = route.queryParamMap.get('staff') !== 'false'; const nc = route.queryParamMap.get('nc') !== 'false'; - return inject(BeerSaleReportService).get(startDate, finishDate, regular, happy, staff, nc); + return inject(BeerSaleReportService).get(startDate, finishDate, menuCategory, regular, happy, staff, nc); }; diff --git a/bookie/src/app/beer-sale-report/beer-sale-report.routes.ts b/bookie/src/app/beer-sale-report/beer-sale-report.routes.ts index e6a8d8f4..82656a5c 100644 --- a/bookie/src/app/beer-sale-report/beer-sale-report.routes.ts +++ b/bookie/src/app/beer-sale-report/beer-sale-report.routes.ts @@ -1,6 +1,7 @@ import { Routes } from '@angular/router'; import { authGuard } from '../auth/auth-guard.service'; +import { menuCategoryListResolver } from '../menu-category/menu-category-list.resolver'; import { BeerSaleReportComponent } from './beer-sale-report.component'; import { beerSaleReportResolver } from './beer-sale-report.resolver'; @@ -14,6 +15,7 @@ export const routes: Routes = [ }, resolve: { info: beerSaleReportResolver, + menuCategories: menuCategoryListResolver, }, runGuardsAndResolvers: 'always', }, diff --git a/bookie/src/app/beer-sale-report/beer-sale-report.service.ts b/bookie/src/app/beer-sale-report/beer-sale-report.service.ts index e5c9b584..3628ed4a 100644 --- a/bookie/src/app/beer-sale-report/beer-sale-report.service.ts +++ b/bookie/src/app/beer-sale-report/beer-sale-report.service.ts @@ -19,6 +19,7 @@ export class BeerSaleReportService { get( startDate: string | null, finishDate: string | null, + menuCategory: string | null, regular: boolean, happy: boolean, staff: boolean, @@ -31,6 +32,9 @@ export class BeerSaleReportService { if (finishDate !== null) { options.params = options.params.set('f', finishDate); } + if (menuCategory != null) { + options.params = options.params.set('m', menuCategory); + } options.params = options.params.set('r', regular); options.params = options.params.set('h', happy); options.params = options.params.set('st', staff); diff --git a/bookie/src/app/beer-sale-report/beer-sale-report.ts b/bookie/src/app/beer-sale-report/beer-sale-report.ts index b6cf31cc..5be04daa 100644 --- a/bookie/src/app/beer-sale-report/beer-sale-report.ts +++ b/bookie/src/app/beer-sale-report/beer-sale-report.ts @@ -1,8 +1,10 @@ +import { MenuCategory } from '../core/menu-category'; import { BeerSaleReportItem } from './beer-sale-report-item'; export class BeerSaleReport { startDate: string; finishDate: string; + menuCategory: MenuCategory; regular: boolean; happy: boolean; staff: boolean; @@ -13,6 +15,7 @@ export class BeerSaleReport { public constructor(init?: Partial) { this.startDate = ''; this.finishDate = ''; + this.menuCategory = new MenuCategory(); this.regular = true; this.happy = true; this.staff = true;