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:
Amritanshu Agrawal 2020-12-18 13:24:05 +05:30
parent 608dde4619
commit f28cf1eea0
5 changed files with 158 additions and 61 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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>