Product Sale Report double counts the Bundle Items as it lists them as well as the bundle.

Menu Engineering Report double counts the Bundle Items as it lists them as well as the bundle.

All reports fixed.
This commit is contained in:
2026-02-05 01:12:56 +00:00
parent 8957e4ce8c
commit 7382d487ac
10 changed files with 37 additions and 96 deletions
+2 -2
View File
@@ -42,14 +42,14 @@ def dates_overlap(start1: date | None, end1: date | None, start2: date | None, e
return start1 <= end2 and start2 <= end1
def _pv_active(date_: date):
def _pv_active(date_: date | Label[Any]):
return and_(
or_(ProductVersion.valid_from == None, ProductVersion.valid_from <= date_), # noqa: E711
or_(ProductVersion.valid_till == None, ProductVersion.valid_till >= date_), # noqa: E711
)
def _sv_active(date_: date):
def _sv_active(date_: date | Label[Any]):
return and_(
or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= date_), # noqa: E711
or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= date_), # noqa: E711
@@ -1,16 +1,15 @@
from datetime import date, timedelta
from operator import or_
from fastapi import APIRouter, Depends, Security
from sqlalchemy import Date, and_
from sqlalchemy import Date
from sqlalchemy.sql.expression import func, select
from ...core.config import settings
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionFuture
from ...models.inventory import Inventory
from ...models.inventory_type import InventoryType
from ...models.kot import Kot
from ...models.product import Product
from ...models.product_version import ProductVersion
from ...models.sku_version import SkuVersion
from ...models.stock_keeping_unit import StockKeepingUnit
@@ -18,6 +17,7 @@ from ...models.voucher import Voucher
from ...models.voucher_type import VoucherType
from ...schemas.beer_consumption_report import BeerConsumptionReport, BeerConsumptionReportItem
from ...schemas.user_token import UserToken
from .. import _pv_onclause, _sv_onclause
from . import check_audit_permission, report_finish_date, report_start_date
@@ -39,22 +39,8 @@ def beer_consumption(
Voucher.date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES - settings.NEW_DAY_OFFSET_MINUTES), Date
).label("day")
sum_ = func.sum(Inventory.quantity * SkuVersion.fraction).label("sum")
product_version_onclause = and_(
ProductVersion.product_id == Product.id,
or_(
ProductVersion.valid_from == None, # noqa: E711
ProductVersion.valid_from <= day,
),
or_(
ProductVersion.valid_till == None, # noqa: E711
ProductVersion.valid_till >= day,
),
)
sku_version_onclause = and_(
SkuVersion.sku_id == StockKeepingUnit.id,
or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= day), # noqa: E711
or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= day), # noqa: E711
)
product_version_onclause = _pv_onclause(day)
sku_version_onclause = _sv_onclause(day)
query = (
select(day, ProductVersion.name, sum_, ProductVersion.fraction_units)
.join(Voucher.kots)
@@ -64,6 +50,7 @@ def beer_consumption(
.join(StockKeepingUnit.product)
.join(ProductVersion, onclause=product_version_onclause)
.where(
Inventory.type_ != InventoryType.bundle,
day >= start_date,
day <= finish_date,
)
@@ -3,24 +3,24 @@ import uuid
from datetime import date, timedelta
from fastapi import APIRouter, Cookie, Depends, Security
from sqlalchemy import Date, and_, func, or_, select
from sqlalchemy import Date, func, select
from sqlalchemy.orm import Session
from ...core.config import settings
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionFuture
from ...models.inventory import Inventory
from ...models.inventory_type import InventoryType
from ...models.kot import Kot
from ...models.product import Product
from ...models.product_version import ProductVersion
from ...models.sale_category import SaleCategory
from ...models.sku_version import SkuVersion
from ...models.stock_keeping_unit import StockKeepingUnit
from ...models.voucher import Voucher
from ...models.voucher_type import VoucherType
from ...printing.discount_report import print_discount_report
from ...schemas.discount_report import DiscountReport, DiscountReportItem
from ...schemas.user_token import UserToken
from .. import _pv_onclause
from . import check_audit_permission, report_finish_date, report_start_date
@@ -47,33 +47,18 @@ def get_discount_report(start_date: date, finish_date: date, db: Session) -> lis
Voucher.date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES - settings.NEW_DAY_OFFSET_MINUTES), Date
).label("day")
amount = func.sum(Inventory.quantity * Inventory.effective_price * Inventory.discount).label("Amount")
product_version_onclause = and_(
ProductVersion.product_id == Product.id,
or_(
ProductVersion.valid_from == None, # noqa: E711
ProductVersion.valid_from <= day,
),
or_(
ProductVersion.valid_till == None, # noqa: E711
ProductVersion.valid_till >= day,
),
)
sku_version_onclause = and_(
SkuVersion.sku_id == StockKeepingUnit.id,
or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= day), # noqa: E711
or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= day), # noqa: E711
)
product_version_onclause = _pv_onclause(day)
list_ = db.execute(
select(SaleCategory.name, amount)
.join(Voucher.kots)
.join(Kot.inventories)
.join(Inventory.sku)
.join(SkuVersion, onclause=sku_version_onclause)
.join(StockKeepingUnit.product)
.join(ProductVersion, onclause=product_version_onclause)
.join(ProductVersion.sale_category)
.where(
Inventory.discount != 0,
Inventory.type_ != InventoryType.bundle,
day >= start_date,
day <= finish_date,
Voucher.voucher_type.in_([VoucherType.REGULAR_BILL, VoucherType.KOT]),
@@ -4,7 +4,7 @@ from datetime import date, timedelta
from decimal import Decimal
from fastapi import APIRouter, Depends, Security
from sqlalchemy import Date, and_, func, nulls_last, or_, select
from sqlalchemy import Date, func, nulls_last, select
from sqlalchemy.orm import Session
from ...core.config import settings
@@ -22,6 +22,7 @@ from ...models.voucher import Voucher
from ...models.voucher_type import VoucherType
from ...schemas.menu_engineering_report import MeItem, MeReport
from ...schemas.user_token import UserToken
from .. import _pv_active, _sv_active
from . import check_audit_permission, report_finish_date, report_start_date
@@ -48,20 +49,8 @@ def menu_engineering_report(start_date: date, finish_date: date, db: Session) ->
day = func.cast(
Voucher.date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES - settings.NEW_DAY_OFFSET_MINUTES), Date
).label("day")
product_version_valid = and_(
or_(
ProductVersion.valid_from == None, # noqa: E711
ProductVersion.valid_from <= day,
),
or_(
ProductVersion.valid_till == None, # noqa: E711
ProductVersion.valid_till >= day,
),
)
sku_version_valid = and_(
or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= day), # noqa: E711
or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= day), # noqa: E711
)
product_version_active = _pv_active(day)
sku_version_active = _sv_active(day)
list_ = db.execute(
select(
SaleCategory.name,
@@ -87,8 +76,8 @@ def menu_engineering_report(start_date: date, finish_date: date, db: Session) ->
day >= start_date,
day <= finish_date,
Voucher.voucher_type == VoucherType.REGULAR_BILL,
product_version_valid,
sku_version_valid,
product_version_active,
sku_version_active,
)
.group_by(
SaleCategory.name,
@@ -4,7 +4,7 @@ from datetime import date, timedelta
from typing import Annotated
from fastapi import APIRouter, Cookie, Depends, Query, Security
from sqlalchemy import Date, and_, func, or_, select
from sqlalchemy import Date, func, select
from sqlalchemy.orm import Session
from ...core.config import settings
@@ -14,7 +14,6 @@ from ...models.food_table import FoodTable
from ...models.inventory import Inventory
from ...models.kot import Kot
from ...models.menu_category import MenuCategory
from ...models.product import Product
from ...models.product_version import ProductVersion
from ...models.sale_category import SaleCategory
from ...models.sku_version import SkuVersion
@@ -24,6 +23,7 @@ from ...models.voucher_type import VoucherType
from ...printing.product_sale_report import print_product_sale_report
from ...schemas.product_sale_report import ProductSaleReport, ProductSaleReportItem, UserLink
from ...schemas.user_token import UserToken
from .. import _pv_onclause, _sv_onclause
from . import check_audit_permission, report_finish_date, report_start_date
@@ -54,22 +54,8 @@ def product_sale_report(
day = func.cast(
Voucher.date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES - settings.NEW_DAY_OFFSET_MINUTES), Date
).label("day")
product_version_onclause = and_(
ProductVersion.product_id == Product.id,
or_(
ProductVersion.valid_from == None, # noqa: E711
ProductVersion.valid_from <= day,
),
or_(
ProductVersion.valid_till == None, # noqa: E711
ProductVersion.valid_till >= day,
),
)
sku_version_onclause = and_(
SkuVersion.sku_id == StockKeepingUnit.id,
or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= day), # noqa: E711
or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= day), # noqa: E711
)
product_version_onclause = _pv_onclause(day)
sku_version_onclause = _sv_onclause(day)
query = (
select(
ProductVersion.id,
+9 -14
View File
@@ -5,7 +5,7 @@ from decimal import Decimal
from typing import Annotated
from fastapi import APIRouter, Cookie, Depends, Query, Security
from sqlalchemy import Date, and_, func, or_, select
from sqlalchemy import Date, func, select
from sqlalchemy.orm import Session
from ...core.config import settings
@@ -13,18 +13,20 @@ from ...core.security import get_current_active_user as get_user
from ...db.session import SessionFuture
from ...models.food_table import FoodTable
from ...models.inventory import Inventory
from ...models.inventory_type import InventoryType
from ...models.kot import Kot
from ...models.product import Product
from ...models.product_version import ProductVersion
from ...models.sale_category import SaleCategory
from ...models.settle_option import SettleOption
from ...models.settlement import Settlement
from ...models.stock_keeping_unit import StockKeepingUnit
from ...models.voucher import Voucher
from ...models.voucher_type import VoucherType
from ...printing.sale_report import print_sale_report
from ...schemas.sale_report import SaleReport, SaleReportItem
from ...schemas.user import UserLink
from ...schemas.user_token import UserToken
from .. import _pv_onclause
from . import check_audit_permission, report_finish_date, report_start_date
from .tax_report import get_tax
@@ -60,26 +62,19 @@ def get_sale(start_date: date, finish_date: date, id_: uuid.UUID | None, db: Ses
day = func.cast(
Voucher.date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES - settings.NEW_DAY_OFFSET_MINUTES), Date
).label("day")
product_version_onclause = and_(
ProductVersion.product_id == Product.id,
or_(
ProductVersion.valid_from == None, # noqa: E711
ProductVersion.valid_from <= day,
),
or_(
ProductVersion.valid_till == None, # noqa: E711
ProductVersion.valid_till >= day,
),
)
product_version_onclause = _pv_onclause(day)
query = (
select(SaleCategory.name, func.sum(Inventory.net))
.select_from(Inventory)
.join(Inventory.kot)
.join(Kot.voucher)
.join(Inventory.product)
.join(Inventory.sku)
.join(StockKeepingUnit.product)
.join(ProductVersion, onclause=product_version_onclause)
.join(ProductVersion.sale_category)
.join(Voucher.food_table)
.where(
Inventory.type_ != InventoryType.bundle,
day >= start_date,
day <= finish_date,
Voucher.voucher_type == VoucherType.REGULAR_BILL,
@@ -13,6 +13,7 @@ from ...core.security import get_current_active_user as get_user
from ...db.session import SessionFuture
from ...models.food_table import FoodTable
from ...models.inventory import Inventory
from ...models.inventory_type import InventoryType
from ...models.kot import Kot
from ...models.tax import Tax
from ...models.voucher import Voucher
@@ -60,6 +61,7 @@ def get_tax(s: date, f: date, id_: uuid.UUID | None, db: Session) -> list[TaxRep
.join(Inventory.tax)
.join(Voucher.food_table)
.where(
Inventory.type_ != InventoryType.bundle,
Voucher.date >= start_date,
Voucher.date <= finish_date,
Voucher.voucher_type == VoucherType.REGULAR_BILL,
+1 -2
View File
@@ -7,8 +7,6 @@ from fastapi import APIRouter, HTTPException, Security, status
from sqlalchemy import Date, func, select
from sqlalchemy.orm import Session, contains_eager
from barker.models.inventory_type import InventoryType
from ...core.config import settings
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionFuture
@@ -16,6 +14,7 @@ from ...models.bill import Bill
from ...models.food_table import FoodTable
from ...models.guest_book import GuestBook
from ...models.inventory import Inventory
from ...models.inventory_type import InventoryType
from ...models.kot import Kot
from ...models.overview import Overview
from ...models.product import Product
+1 -2
View File
@@ -9,8 +9,6 @@ from sqlalchemy import Date, delete, func, select
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from barker.routers import _pv_onclause, _sv_onclause
from ...core.config import settings
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionFuture
@@ -22,6 +20,7 @@ from ...models.overview import Overview
from ...models.settle_option import SettleOption
from ...models.voucher import Voucher
from ...models.voucher_type import VoucherType
from ...routers import _pv_onclause, _sv_onclause
from ...routers.voucher import (
check_permissions,
do_update_bill_numbers,
+1 -2
View File
@@ -5,8 +5,7 @@ from typing import Annotated
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from barker.models.inventory_type import InventoryType
from ..models.inventory_type import InventoryType
from . import Daf, to_camel
from .customer import CustomerLink
from .modifier import ModifierLink