Split bill working along with all checks.
Update bill ensures that the total number of happy hour punches of a product in a bill are less than or equal to the regular punches
This commit is contained in:
parent
608dde4619
commit
f28cf1eea0
|
@ -1,5 +1,6 @@
|
|||
import uuid
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
|
||||
import barker.schemas.voucher as schemas
|
||||
|
@ -120,15 +121,32 @@ def do_update_settlements(voucher: Voucher, others: List[SettleSchema], db: Sess
|
|||
db.delete(i)
|
||||
|
||||
|
||||
def happy_hour_items_balanced(inventories: [schemas.Inventory]):
|
||||
def happy_hour_items_balanced(inventories: List[schemas.Inventory]) -> bool:
|
||||
happy = set((i.product.id_, i.quantity) for i in inventories if i.is_happy_hour)
|
||||
other = set(
|
||||
(i.product.id_, i.quantity) for i in inventories if not i.is_happy_hour and (i.product.id_, i.quantity) in happy
|
||||
)
|
||||
products = set(i.product.id_ for i in inventories if i.is_happy_hour)
|
||||
other = set((i.product.id_, i.quantity) for i in inventories if not i.is_happy_hour and i.product.id_ in products)
|
||||
return happy == other
|
||||
|
||||
|
||||
def happy_hour_has_discount(inventories: [schemas.Inventory]):
|
||||
def happy_hour_has_discount(inventories: List[schemas.Inventory]) -> bool:
|
||||
happy = set(i.product.id_ for i in inventories if i.is_happy_hour)
|
||||
offenders = [i for i in inventories if i.product.id_ in happy and i.discount != 0]
|
||||
return len(offenders) > 0
|
||||
|
||||
|
||||
# This is for the whole bill. eg. Kot 1 => Reg 2 + HH 2; Kot 2 => Reg 4; Kot 3 => Reg - 4
|
||||
# This is pass okay in happy hours items balanced, but overall this is wrong. Hence this check
|
||||
def happy_hour_items_more_than_regular(kots: List[schemas.Kot]) -> bool:
|
||||
inventories = {}
|
||||
for kot in kots:
|
||||
for inventory in kot.inventories:
|
||||
if inventory.product.id_ not in inventories:
|
||||
inventories[inventory.product.id_] = {"normal": Decimal(0), "happy": Decimal(0)}
|
||||
if inventory.is_happy_hour:
|
||||
inventories[inventory.product.id_]["happy"] += inventory.quantity
|
||||
else:
|
||||
inventories[inventory.product.id_]["normal"] += inventory.quantity
|
||||
for value in inventories.values():
|
||||
if value["happy"] > value["normal"]:
|
||||
return True
|
||||
return False
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import uuid
|
||||
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
|
||||
import barker.schemas.split as schemas
|
||||
|
@ -49,6 +51,7 @@ def split(
|
|||
update_table = u
|
||||
item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
|
||||
item.bill_id = None
|
||||
original_voucher_type = item.voucher_type
|
||||
item.voucher_type = VoucherType.VOID
|
||||
item.reason = "Bill Split"
|
||||
do_update_settlements(item, [SettleSchema(id=SettleOption.VOID(), amount=round(item.amount))], db)
|
||||
|
@ -62,7 +65,7 @@ def split(
|
|||
one = save(
|
||||
one_inventories,
|
||||
now,
|
||||
item.voucher_type,
|
||||
original_voucher_type,
|
||||
0,
|
||||
data.table_id,
|
||||
item.customer_id,
|
||||
|
@ -74,7 +77,7 @@ def split(
|
|||
two = save(
|
||||
two_inventories,
|
||||
now,
|
||||
item.voucher_type,
|
||||
original_voucher_type,
|
||||
item.pax,
|
||||
item.food_table_id,
|
||||
item.customer_id,
|
||||
|
@ -105,52 +108,97 @@ def save(
|
|||
user_id: uuid.UUID,
|
||||
db: Session,
|
||||
):
|
||||
product_quantities = {}
|
||||
for i in inventories:
|
||||
if (i.product_id, i.is_happy_hour) in product_quantities:
|
||||
product_quantities[(i.product_id, i.is_happy_hour)][1] += i.quantity
|
||||
else:
|
||||
product_quantities[(i.product_id, i.is_happy_hour)] = (i, i.quantity)
|
||||
for (product, happy_hour), (inventory, quantity) in product_quantities.items():
|
||||
if quantity < 0:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Quantity of a product is negative",
|
||||
)
|
||||
if not are_product_quantities_positive(inventories):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Quantity of a product is negative",
|
||||
)
|
||||
if len(inventories) == 0:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="No inventories selected",
|
||||
)
|
||||
if happy_hour_items_more_than_regular(inventories):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="When product has happy hours\n"
|
||||
"Minimum same number of regular items also needed in the whole bill.",
|
||||
)
|
||||
bill_id = get_bill_id(voucher_type, db)
|
||||
kot_id = db.query(func.coalesce(func.max(Voucher.kot_id), 0) + 1).scalar()
|
||||
|
||||
item: Voucher = Voucher(now, pax, bill_id, kot_id, table_id, customer_id, voucher_type, user_id)
|
||||
db.add(item)
|
||||
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
|
||||
kot = Kot(item.id, code, item.food_table_id, item.date, item.user_id)
|
||||
item.kots.append(kot)
|
||||
db.add(kot) # Multiple inventories of the same product give a key error, but combining messes with modifiers, this
|
||||
# will get important when modifiers have a price.
|
||||
for index, (old_inventory, q) in enumerate([i for i in product_quantities.values() if i[1] != 0]):
|
||||
inv = Inventory(
|
||||
kot.id,
|
||||
old_inventory.product_id,
|
||||
q,
|
||||
old_inventory.price,
|
||||
old_inventory.discount,
|
||||
old_inventory.is_happy_hour,
|
||||
old_inventory.tax_id,
|
||||
old_inventory.tax_rate,
|
||||
index,
|
||||
)
|
||||
kot.inventories.append(inv)
|
||||
db.add(inv)
|
||||
for m in old_inventory.modifiers:
|
||||
mod = InventoryModifier(None, m.modifier_id, m.price)
|
||||
inv.modifiers.append(mod)
|
||||
db.add(mod)
|
||||
for split_inventories in split_into_kots(inventories):
|
||||
if not happy_hour_items_balanced(split_inventories):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Happy hour products are not balanced.",
|
||||
)
|
||||
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
|
||||
kot = Kot(item.id, code, item.food_table_id, item.date, item.user_id)
|
||||
item.kots.append(kot)
|
||||
db.add(kot)
|
||||
db.flush()
|
||||
for old_inventory in split_inventories:
|
||||
inv = Inventory(
|
||||
kot.id,
|
||||
old_inventory.product_id,
|
||||
old_inventory.quantity,
|
||||
old_inventory.price,
|
||||
old_inventory.discount,
|
||||
old_inventory.is_happy_hour,
|
||||
old_inventory.tax_id,
|
||||
old_inventory.tax_rate,
|
||||
old_inventory.sort_order,
|
||||
)
|
||||
kot.inventories.append(inv)
|
||||
db.add(inv)
|
||||
for m in old_inventory.modifiers:
|
||||
mod = InventoryModifier(None, m.modifier_id, m.price)
|
||||
inv.modifiers.append(mod)
|
||||
db.add(mod)
|
||||
db.flush()
|
||||
do_update_settlements(item, [], db)
|
||||
|
||||
if len(kot.inventories) == 0:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="No inventories selected",
|
||||
)
|
||||
db.flush()
|
||||
return item
|
||||
|
||||
|
||||
def split_into_kots(inventories: List[Inventory]) -> list:
|
||||
kots = defaultdict(list)
|
||||
for item in inventories:
|
||||
kots[item.kot_id].append(item)
|
||||
return [k for k in kots.values() if len(k) > 0]
|
||||
|
||||
|
||||
def happy_hour_items_balanced(inventories: List[Inventory]) -> bool:
|
||||
happy = set((i.product_id, i.quantity) for i in inventories if i.is_happy_hour)
|
||||
products = set(i.product_id for i in inventories if i.is_happy_hour)
|
||||
other = set((i.product_id, i.quantity) for i in inventories if not i.is_happy_hour and i.product_id in products)
|
||||
return happy == other
|
||||
|
||||
|
||||
def are_product_quantities_positive(inventories: List[Inventory]) -> bool:
|
||||
quantities = defaultdict(Decimal)
|
||||
for i in inventories:
|
||||
key = (i.product_id, i.is_happy_hour)
|
||||
quantities[key] += i.quantity
|
||||
for i in quantities.values():
|
||||
if i < 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def happy_hour_items_more_than_regular(invs: List[Inventory]) -> bool:
|
||||
inventories = {}
|
||||
for inventory in invs:
|
||||
if inventory.product_id not in inventories:
|
||||
inventories[inventory.product_id] = {"normal": Decimal(0), "happy": Decimal(0)}
|
||||
if inventory.is_happy_hour:
|
||||
inventories[inventory.product_id]["happy"] += inventory.quantity
|
||||
else:
|
||||
inventories[inventory.product_id]["normal"] += inventory.quantity
|
||||
for value in inventories.values():
|
||||
if value["happy"] > value["normal"]:
|
||||
return True
|
||||
return False
|
||||
|
|
|
@ -26,6 +26,7 @@ from ...routers.voucher import (
|
|||
get_tax,
|
||||
happy_hour_has_discount,
|
||||
happy_hour_items_balanced,
|
||||
happy_hour_items_more_than_regular,
|
||||
)
|
||||
from ...schemas.auth import UserToken
|
||||
|
||||
|
@ -80,6 +81,12 @@ def update(
|
|||
item.voucher_type = voucher_type
|
||||
item.user_id = user.id_
|
||||
item.last_edit_date = now
|
||||
if happy_hour_items_more_than_regular(data.kots):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="When product has happy hours\n"
|
||||
"Minimum same number of regular items also needed in the whole bill.",
|
||||
)
|
||||
for k in item.kots:
|
||||
for i in k.inventories:
|
||||
i.tax_rate = get_tax(i.tax_rate, voucher_type)
|
||||
|
|
|
@ -230,7 +230,7 @@ export class BillService {
|
|||
if (newKot.inventories.length === 0) {
|
||||
return throwError('Cannot print a blank KOT\nPlease add some products!');
|
||||
}
|
||||
if (!this.happyHourItemsBalanced()) {
|
||||
if (!this.happyHourItemsBalanced() || this.happyHourItemsMoreThanRegular()) {
|
||||
return throwError('Happy hour products are not balanced.');
|
||||
}
|
||||
return this.ser.saveOrUpdate(item, VoucherType.Kot, guestBookId, true);
|
||||
|
@ -242,7 +242,7 @@ export class BillService {
|
|||
if (item.kots.length === 1 && newKot.inventories.length === 0) {
|
||||
return throwError('Cannot print a blank Bill\nPlease add some products!');
|
||||
}
|
||||
if (!this.happyHourItemsBalanced()) {
|
||||
if (!this.happyHourItemsBalanced() || this.happyHourItemsMoreThanRegular()) {
|
||||
return throwError('Happy hour products are not balanced.');
|
||||
}
|
||||
return this.ser.saveOrUpdate(item, voucherType, guest_book_id, true);
|
||||
|
@ -334,18 +334,42 @@ export class BillService {
|
|||
}
|
||||
|
||||
private happyHourItemsBalanced(): boolean {
|
||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
||||
const happyHourItems = newKot.inventories
|
||||
.filter((x) => x.isHappyHour)
|
||||
.map((x) => ({ id: x.product.id as string, quantity: x.quantity }));
|
||||
for (const item of happyHourItems) {
|
||||
const q = newKot.inventories.find(
|
||||
(x) => !x.isHappyHour && x.product.id === item.id && x.quantity === item.quantity,
|
||||
);
|
||||
if (q === undefined) {
|
||||
return false;
|
||||
for (const kot of this.bill.kots) {
|
||||
const happyHourItems = kot.inventories
|
||||
.filter((x) => x.isHappyHour)
|
||||
.map((x) => ({ id: x.product.id as string, quantity: x.quantity }));
|
||||
for (const item of happyHourItems) {
|
||||
const q = kot.inventories.find(
|
||||
(x) => !x.isHappyHour && x.product.id === item.id && x.quantity === item.quantity,
|
||||
);
|
||||
if (q === undefined) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private happyHourItemsMoreThanRegular(): boolean {
|
||||
const invs: { [id: string]: { normal: number; happy: number } } = {};
|
||||
for (const kot of this.bill.kots) {
|
||||
for (const inventory of kot.inventories) {
|
||||
const pid = inventory.product.id as string;
|
||||
if (invs[pid] === undefined) {
|
||||
invs[pid] = { normal: 0, happy: 0 };
|
||||
}
|
||||
if (inventory.isHappyHour) {
|
||||
invs[pid].happy += inventory.quantity;
|
||||
} else {
|
||||
invs[pid].normal += inventory.quantity;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const [, value] of Object.entries(invs)) {
|
||||
if (value.happy > value.normal) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
<button
|
||||
mat-icon-button
|
||||
(click)="moveKot(row)"
|
||||
[disabled]="row.isKot && !row.id"
|
||||
[disabled]="row.isKot && !row.kotId"
|
||||
*ngIf="row.isKot"
|
||||
>
|
||||
<mat-icon class="del">open_in_new</mat-icon>
|
||||
|
|
Loading…
Reference in New Issue