barker/barker/barker/routers/voucher/change.py

110 lines
3.9 KiB
Python

import uuid
import barker.schemas.voucher as schemas
from fastapi import APIRouter, HTTPException, Security, status
from sqlalchemy import select, update
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionFuture
from ...models.overview import Overview
from ...models.reprint import Reprint
from ...models.settle_option import SettleOption
from ...models.voucher import Voucher
from ...models.voucher_type import VoucherType
from ...printing.bill import print_bill
from ...printing.kot import print_kot
from ...routers.voucher import (
do_update_bill_numbers,
do_update_settlements,
get_guest_book,
)
from ...schemas.receive_payment import ReceivePaymentItem as SettleSchema
from ...schemas.user_token import UserToken
from .save import do_save
router = APIRouter()
@router.put("/change/{id_}")
def change(
id_: uuid.UUID,
data: schemas.VoucherIn,
u: bool, # Update table?
g: uuid.UUID | None = None, # Guest book id
user: UserToken = Security(get_user, scopes=["edit-printed-bill"]),
):
try:
with SessionFuture() as db:
old: Voucher = db.execute(select(Voucher).where(Voucher.id == id_)).scalar_one()
if old.voucher_type == VoucherType.VOID:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Voucher cannot be reprinted. It is already void.",
)
bill_changed: bool = (
len(
set((i.id, i.amount) for k in old.kots for i in k.inventories)
^ set((i.id_, i.amount) for k in data.kots for i in k.inventories)
)
!= 0
)
new_kot: bool = len([k for k in data.kots if k.id_ is None and len(k.inventories) > 0]) > 0
if bill_changed:
id_ = void_and_issue_new_bill(data, u, g, old, db, user)
else:
if data.customer is not None:
old.customer_id = data.customer.id_
else:
old.customer_id = None
reprint_bill(id_, user.id_, db)
db.commit()
with SessionFuture() as db:
if bill_changed and new_kot:
print_kot(id_, db)
print_bill(id_, db)
except SQLAlchemyError as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(e),
)
def reprint_bill(voucher_id: uuid.UUID, user_id: uuid.UUID, db: Session):
item = Reprint(voucher_id=voucher_id, user_id=user_id)
db.add(item)
def void_and_issue_new_bill(
data: schemas.VoucherIn,
u: bool,
g: uuid.UUID | None,
old: Voucher,
db: Session,
user: UserToken,
) -> uuid.UUID:
update_table = u
guest_book = get_guest_book(g, db)
item: Voucher = do_save(data, old.voucher_type, guest_book, db, user)
db.flush()
new_bill_id = (", ".join(f"{x.regime.prefix}-{x.bill_number}" for x in item.bills),)
old_bill_id = (", ".join(f"{x.regime.prefix}-{x.bill_number}" for x in old.bills),)
old.reason = f"Bill Discounted or Changed / Old Bill: {old_bill_id} / New Bill: {new_bill_id}."
old.voucher_type = VoucherType.VOID
do_update_bill_numbers(old, db)
do_update_settlements(old, [SettleSchema(id=SettleOption.VOID(), amount=round(old.amount))], db)
if update_table:
if old.status is None:
guest_book_id = None if guest_book is None else guest_book.id
item.status = Overview(
voucher_id=None, food_table_id=item.food_table_id, guest_book_id=guest_book_id, status="printed"
)
db.add(item.status)
else:
db.execute(update(Overview).where(Overview.voucher_id == old.id).values(voucher_id=item.id))
return item.id