barker/barker/barker/routers/reports/menu_engineering_report.py

137 lines
4.7 KiB
Python

import uuid
from datetime import date, datetime, time, timedelta
from typing import Any
from fastapi import APIRouter, Cookie, Depends, Security
from sqlalchemy import func, nulls_last, or_, 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.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.voucher import Voucher
from ...models.voucher_type import VoucherType
from ...printing.product_sale_report import print_product_sale_report
from ...schemas.user_token import UserToken
from . import check_audit_permission, report_finish_date, report_start_date
router = APIRouter()
@router.get("")
def menu_engineering_report_view(
start_date: date = Depends(report_start_date),
finish_date: date = Depends(report_finish_date),
user: UserToken = Security(get_user, scopes=["product-sale-report"]),
):
check_audit_permission(start_date, user.permissions)
with SessionFuture() as db:
return {
"startDate": start_date.strftime("%d-%b-%Y"),
"finishDate": finish_date.strftime("%d-%b-%Y"),
"amounts": menu_engineering_report(start_date, finish_date, db),
}
def menu_engineering_report(s: date, f: date, db: Session):
start_date = datetime.combine(s, time()) + timedelta(
minutes=settings.NEW_DAY_OFFSET_MINUTES - settings.TIMEZONE_OFFSET_MINUTES
)
finish_date = datetime.combine(f, time()) + timedelta(
days=1, minutes=settings.NEW_DAY_OFFSET_MINUTES - settings.TIMEZONE_OFFSET_MINUTES
)
day = func.date_trunc("day", Voucher.date - timedelta(minutes=settings.NEW_DAY_OFFSET_MINUTES)).label("day")
q = (
select(
SaleCategory.name,
MenuCategory.name,
ProductVersion.id,
ProductVersion.full_name,
ProductVersion.price,
func.sum(Inventory.quantity),
func.sum(Inventory.net),
)
.join(ProductVersion.sale_category)
.join(ProductVersion.menu_category)
.join(ProductVersion.product)
.join(Product.inventories, isouter=True)
.join(Inventory.kot, isouter=True)
.join(Kot.voucher, isouter=True)
.where(
or_(
Voucher.date == None, # noqa: E711
Voucher.date >= start_date,
),
or_(
Voucher.date == None, # noqa: E711
Voucher.date <= finish_date,
),
or_(
Voucher.voucher_type == None, # noqa: E711
Voucher.voucher_type == VoucherType.REGULAR_BILL,
),
or_(
ProductVersion.valid_from == None, # noqa: E711
ProductVersion.valid_from <= day,
Voucher.date == None, # noqa: E711
),
or_(
ProductVersion.valid_till == None, # noqa: E711
ProductVersion.valid_till >= day,
Voucher.date == None, # noqa: E711
),
)
.group_by(
SaleCategory.name,
MenuCategory.name,
ProductVersion.id,
ProductVersion.full_name,
)
.order_by(SaleCategory.name, nulls_last(func.sum(Inventory.net).desc()))
)
print(q)
list_ = db.execute(q).all()
info: list[Any] = []
for sc, mc, id_, name, price, quantity, amount in list_:
info.append(
{
"id": id_,
"name": name,
"price": price,
"average": round(amount / quantity) if amount and quantity else price,
"saleCategory": sc,
"menuCategory": mc,
"quantity": quantity,
"amount": amount,
}
)
return info
@router.get("/print", response_model=bool)
def print_report(
start_date: date = Depends(report_start_date),
finish_date: date = Depends(report_finish_date),
device_id: uuid.UUID = Cookie(None),
user: UserToken = Security(get_user, scopes=["product-sale-report"]),
) -> bool:
check_audit_permission(start_date, user.permissions)
with SessionFuture() as db:
report = {
"userName": user.name,
"startDate": start_date.strftime("%d-%b-%Y"),
"finishDate": finish_date.strftime("%d-%b-%Y"),
"amounts": menu_engineering_report(start_date, finish_date, db),
}
print_product_sale_report(report, device_id, db)
return True