Chore: In overlord / sale / bill.service now the BillViewItem is just a view item
The data is kept as the original bill object and this view generated on every change. It has no sanctity. To deal with the challenges of Selection of items in the bill.component.html created a bill selection item. This is converted to string while checking else the selection model fails. Feature: It now checks if Happy Hour items have equivalent regular items in each kot. Feature: Discount won't apply to happy hour items. Checks for both are both in front end and back end.
This commit is contained in:
parent
28952402aa
commit
6c83c74424
@ -2,6 +2,8 @@ import uuid
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
import barker.schemas.voucher as schemas
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import Session
|
||||
@ -116,3 +118,17 @@ def do_update_settlements(voucher: Voucher, others: List[SettleSchema], db: Sess
|
||||
for i in (i for i in voucher.settlements if i.settled not in [x.id_ for x in settlements]):
|
||||
voucher.settlements.remove(i)
|
||||
db.delete(i)
|
||||
|
||||
|
||||
def happy_hour_items_balanced(inventories: [schemas.Inventory]):
|
||||
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
|
||||
)
|
||||
return happy == other
|
||||
|
||||
|
||||
def happy_hour_has_discount(inventories: [schemas.Inventory]):
|
||||
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
|
||||
|
@ -24,6 +24,8 @@ from ...routers.voucher import (
|
||||
get_bill_id,
|
||||
get_guest_book,
|
||||
get_tax,
|
||||
happy_hour_has_discount,
|
||||
happy_hour_items_balanced,
|
||||
)
|
||||
from ...schemas.auth import UserToken
|
||||
|
||||
@ -99,6 +101,16 @@ def do_save(
|
||||
for k in data.kots:
|
||||
if not len(k.inventories):
|
||||
continue
|
||||
if not happy_hour_items_balanced(k.inventories):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Happy hour products are not balanced.",
|
||||
)
|
||||
if happy_hour_has_discount(k.inventories):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Discount is not allowed on happy hour products.",
|
||||
)
|
||||
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)
|
||||
|
@ -24,6 +24,8 @@ from ...routers.voucher import (
|
||||
get_bill_id,
|
||||
get_guest_book,
|
||||
get_tax,
|
||||
happy_hour_has_discount,
|
||||
happy_hour_items_balanced,
|
||||
)
|
||||
from ...schemas.auth import UserToken
|
||||
|
||||
@ -87,6 +89,17 @@ def update(
|
||||
i.discount = next(
|
||||
round(inv.discount, 5) for ko in data.kots for inv in ko.inventories if inv.id_ == i.id
|
||||
)
|
||||
for k in data.kots:
|
||||
if happy_hour_has_discount(k.inventories):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Discount is not allowed on happy hour products.",
|
||||
)
|
||||
if not happy_hour_items_balanced(k.inventories):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Happy hour products are not balanced.",
|
||||
)
|
||||
for k in (k for k in data.kots if k.id_ is None and len(k.inventories) > 0):
|
||||
need_to_print_kot = True
|
||||
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
|
||||
|
@ -4,42 +4,32 @@ import { Tax } from './tax';
|
||||
|
||||
export class BillViewItem {
|
||||
id: string | undefined;
|
||||
kotId: string | undefined;
|
||||
isKot: boolean;
|
||||
info: string;
|
||||
|
||||
kotId: string;
|
||||
product: Product;
|
||||
productId: string | undefined;
|
||||
productId: string;
|
||||
isHappyHour: boolean;
|
||||
isPrinted: boolean;
|
||||
price: number;
|
||||
quantity: number;
|
||||
discount: number;
|
||||
taxRate: number;
|
||||
tax: Tax;
|
||||
modifiers: Modifier[];
|
||||
|
||||
public get isOldKot(): boolean {
|
||||
return this.isKot && this.id !== undefined;
|
||||
return this.isKot && this.kotId !== undefined;
|
||||
}
|
||||
|
||||
public get isNewKot(): boolean {
|
||||
return this.isKot && this.id === undefined;
|
||||
return this.isKot && this.kotId === undefined;
|
||||
}
|
||||
|
||||
public constructor(init?: Partial<BillViewItem>) {
|
||||
this.isKot = true;
|
||||
this.info = '';
|
||||
this.kotId = '';
|
||||
this.product = new Product();
|
||||
this.productId = this.product.id;
|
||||
this.productId = '';
|
||||
this.isHappyHour = false;
|
||||
this.isPrinted = false;
|
||||
this.price = 0;
|
||||
this.quantity = 0;
|
||||
this.discount = 0;
|
||||
this.taxRate = 0;
|
||||
this.tax = new Tax();
|
||||
this.modifiers = [];
|
||||
Object.assign(this, init);
|
||||
}
|
||||
|
@ -2,8 +2,9 @@ import { SelectionModel } from '@angular/cdk/collections';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { round } from 'mathjs';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { BehaviorSubject, throwError } from 'rxjs';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
import { BillViewItem } from '../core/bill-view-item';
|
||||
import { ModifierCategory } from '../core/modifier-category';
|
||||
@ -15,6 +16,7 @@ import { ToasterService } from '../core/toaster.service';
|
||||
import { ModifierCategoryService } from '../modifier-categories/modifier-category.service';
|
||||
|
||||
import { Bill } from './bills/bill';
|
||||
import { BillSelectionItem } from './bills/bill-selection-item';
|
||||
import { Inventory } from './bills/inventory';
|
||||
import { Kot } from './bills/kot';
|
||||
import { VoucherType } from './bills/voucher-type';
|
||||
@ -24,13 +26,13 @@ import { ModifiersComponent } from './modifiers/modifiers.component';
|
||||
@Injectable()
|
||||
export class BillService {
|
||||
public dataObs: BehaviorSubject<BillViewItem[]>;
|
||||
public data: BillViewItem[];
|
||||
public bill: Bill = new Bill();
|
||||
public netAmount: BehaviorSubject<number>;
|
||||
public discountAmount: BehaviorSubject<number>;
|
||||
public taxAmount: BehaviorSubject<number>;
|
||||
public amount: BehaviorSubject<number>;
|
||||
public selection = new SelectionModel<BillViewItem>(true, []);
|
||||
public amountVal: number;
|
||||
public selection = new SelectionModel<string>(true, []);
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
@ -38,21 +40,28 @@ export class BillService {
|
||||
private ser: VoucherService,
|
||||
private modifierCategoryService: ModifierCategoryService,
|
||||
) {
|
||||
this.data = [];
|
||||
this.dataObs = new BehaviorSubject<BillViewItem[]>(this.data);
|
||||
this.dataObs = new BehaviorSubject<BillViewItem[]>([]);
|
||||
this.netAmount = new BehaviorSubject(0);
|
||||
this.discountAmount = new BehaviorSubject(0);
|
||||
this.taxAmount = new BehaviorSubject(0);
|
||||
this.amount = new BehaviorSubject(0);
|
||||
this.amountVal = 0;
|
||||
this.amount.pipe(tap((x) => (this.amountVal = x)));
|
||||
}
|
||||
|
||||
loadData(bill: Bill): void {
|
||||
this.bill = bill;
|
||||
const view: BillViewItem[][] = this.bill.kots.map((k: Kot) => [
|
||||
displayBill(): void {
|
||||
const data = this.transformBillToView(this.bill);
|
||||
this.dataObs.next(data);
|
||||
this.updateAmounts();
|
||||
}
|
||||
|
||||
transformBillToView(bill: Bill): BillViewItem[] {
|
||||
const view: BillViewItem[] = bill.kots
|
||||
.map((k: Kot) => [
|
||||
new BillViewItem({
|
||||
id: k.id,
|
||||
kotId: k.id,
|
||||
isKot: true,
|
||||
info: `Kot: ${k.code} / ${k.date} (${k.user.name}) `,
|
||||
info: k.id ? `Kot: ${k.code} / ${k.date} (${k.user.name})` : '== New Kot ==',
|
||||
}),
|
||||
...k.inventories.map(
|
||||
(i) =>
|
||||
@ -60,37 +69,41 @@ export class BillService {
|
||||
id: i.id,
|
||||
kotId: k.id,
|
||||
isKot: false,
|
||||
product: i.product,
|
||||
productId: i.product.id,
|
||||
isHappyHour: i.isHappyHour,
|
||||
isPrinted: true,
|
||||
isPrinted: !!k.id,
|
||||
info: `${i.product.name} @ ${i.price} - ${round(i.discount * 100, 2)}%`,
|
||||
price: i.price,
|
||||
quantity: i.quantity,
|
||||
discount: i.discount,
|
||||
taxRate: i.taxRate,
|
||||
tax: i.tax,
|
||||
modifiers: i.modifiers,
|
||||
}),
|
||||
),
|
||||
]);
|
||||
this.data = view.reduce((a, c) => a.concat(c), []);
|
||||
this.data.push(new BillViewItem({ isKot: true, info: '== New Kot ==' }));
|
||||
this.dataObs.next(this.data);
|
||||
this.updateAmounts();
|
||||
])
|
||||
.reduce((a, c) => a.concat(c), []);
|
||||
return view;
|
||||
}
|
||||
|
||||
loadData(bill: Bill): void {
|
||||
bill.kots.push(new Kot());
|
||||
this.bill = bill;
|
||||
this.displayBill();
|
||||
}
|
||||
|
||||
minimum(productId: string, happyHour: boolean): number {
|
||||
return this.data.reduce(
|
||||
(a, c) => (c.productId === productId && c.isHappyHour === happyHour ? a + c.quantity : a),
|
||||
return this.bill.kots.reduce(
|
||||
(t, k) =>
|
||||
k.inventories.reduce(
|
||||
(a, c) =>
|
||||
c.product.id === productId && c.isHappyHour === happyHour ? a + c.quantity : a,
|
||||
0,
|
||||
) + t,
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
addProduct(product: Product, quantity: number, discount: number): void {
|
||||
const old = this.data.find(
|
||||
(x) =>
|
||||
!x.isKot && !x.id && x.productId === product.id && x.isHappyHour === product.hasHappyHour,
|
||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
||||
const old = newKot.inventories.find(
|
||||
(x) => x.product.id === product.id && x.isHappyHour === product.hasHappyHour,
|
||||
);
|
||||
if (quantity < 0) {
|
||||
const minimum = this.minimum(product.id as string, product.hasHappyHour) + quantity;
|
||||
@ -102,38 +115,34 @@ export class BillService {
|
||||
if (old !== undefined) {
|
||||
old.quantity += quantity;
|
||||
} else {
|
||||
const item = new BillViewItem({
|
||||
isKot: false,
|
||||
const item = new Inventory({
|
||||
product,
|
||||
productId: product.id,
|
||||
isHappyHour: product.hasHappyHour,
|
||||
info: `${product.name} @ ${product.price} - ${0}%`,
|
||||
price: product.price,
|
||||
quantity,
|
||||
discount,
|
||||
price: product.price,
|
||||
isHappyHour: product.hasHappyHour,
|
||||
taxRate: product.tax.rate,
|
||||
tax: product.tax,
|
||||
discount,
|
||||
modifiers: [],
|
||||
});
|
||||
this.data.push(item);
|
||||
newKot.inventories.push(item);
|
||||
this.modifierCategoryService.listForProduct(product.id as string).subscribe((result) => {
|
||||
if (result.reduce((a: number, c: ModifierCategory) => a + c.minimum, 0)) {
|
||||
this.showModifier(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.dataObs.next(this.data);
|
||||
this.updateAmounts();
|
||||
this.displayBill();
|
||||
}
|
||||
|
||||
showModifier(item: BillViewItem): void {
|
||||
showModifier(item: Inventory): void {
|
||||
// [routerLink]="['/sales', 'modifiers', item.id]"
|
||||
const dialogRef = this.dialog.open(ModifiersComponent, {
|
||||
position: {
|
||||
top: '10vh',
|
||||
},
|
||||
data: {
|
||||
list: this.modifierCategoryService.listForProduct(item.productId as string),
|
||||
list: this.modifierCategoryService.listForProduct(item.product.id as string),
|
||||
selected: item.modifiers,
|
||||
},
|
||||
});
|
||||
@ -143,75 +152,99 @@ export class BillService {
|
||||
item.modifiers = result;
|
||||
}
|
||||
});
|
||||
this.displayBill();
|
||||
}
|
||||
|
||||
addOne(item: BillViewItem): void {
|
||||
item.quantity += 1;
|
||||
this.dataObs.next(this.data);
|
||||
this.updateAmounts();
|
||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
||||
const old = newKot.inventories.find(
|
||||
(x) => x.product.id === item.productId && x.isHappyHour === item.isHappyHour,
|
||||
) as Inventory;
|
||||
old.quantity += 1;
|
||||
this.displayBill();
|
||||
}
|
||||
|
||||
quantity(item: BillViewItem, quantity: number): void {
|
||||
item.quantity = quantity;
|
||||
this.dataObs.next(this.data);
|
||||
this.updateAmounts();
|
||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
||||
const old = newKot.inventories.find(
|
||||
(x) => x.product.id === item.productId && x.isHappyHour === item.isHappyHour,
|
||||
) as Inventory;
|
||||
old.quantity = quantity;
|
||||
this.displayBill();
|
||||
}
|
||||
|
||||
subtractOne(item: BillViewItem, canEdit: boolean): void {
|
||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
||||
const old = newKot.inventories.find(
|
||||
(x) => x.product.id === item.productId && x.isHappyHour === item.isHappyHour,
|
||||
) as Inventory;
|
||||
if (
|
||||
item.quantity > 1 ||
|
||||
(canEdit && this.minimum(item.productId as string, item.isHappyHour) >= 1)
|
||||
) {
|
||||
item.quantity -= 1;
|
||||
this.dataObs.next(this.data);
|
||||
this.updateAmounts();
|
||||
old.quantity -= 1;
|
||||
} else if (item.quantity === 0) {
|
||||
this.removeItem(item);
|
||||
newKot.inventories.splice(newKot.inventories.indexOf(old), 1);
|
||||
}
|
||||
this.displayBill();
|
||||
}
|
||||
|
||||
removeItem(item: BillViewItem): void {
|
||||
this.data.splice(this.data.indexOf(item), 1);
|
||||
this.dataObs.next(this.data);
|
||||
this.updateAmounts();
|
||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
||||
const old = newKot.inventories.find(
|
||||
(x) => x.product.id === item.productId && x.isHappyHour === item.isHappyHour,
|
||||
) as Inventory;
|
||||
newKot.inventories.splice(newKot.inventories.indexOf(old), 1);
|
||||
this.displayBill();
|
||||
}
|
||||
|
||||
modifier(item: BillViewItem): void {
|
||||
this.showModifier(item);
|
||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
||||
const old = newKot.inventories.find(
|
||||
(x) => x.product.id === item.productId && x.isHappyHour === item.isHappyHour,
|
||||
) as Inventory;
|
||||
this.showModifier(old);
|
||||
}
|
||||
|
||||
discount(discounts: { id: string; name: string; discount: number }[]): void {
|
||||
this.data.forEach((x) => {
|
||||
if (!x.isKot) {
|
||||
const e = discounts.find((d) => d.id === (x.product.saleCategory as SaleCategory).id);
|
||||
if (e !== undefined) {
|
||||
x.discount = e.discount;
|
||||
x.info = `${x.product.name} @ ${x.price} - ${round(x.discount * 100, 2)}%`;
|
||||
for (const kot of this.bill.kots) {
|
||||
const noDiscount = kot.inventories
|
||||
.filter((x) => x.isHappyHour)
|
||||
.map((x) => x.product.id as string);
|
||||
for (const inventory of kot.inventories) {
|
||||
const e = discounts.find(
|
||||
(d) => d.id === (inventory.product.saleCategory as SaleCategory).id,
|
||||
);
|
||||
if (e === undefined || noDiscount.indexOf(inventory.product.id as string) !== -1) {
|
||||
continue;
|
||||
}
|
||||
inventory.discount = e.discount;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.dataObs.next(this.data);
|
||||
this.updateAmounts();
|
||||
this.displayBill();
|
||||
}
|
||||
|
||||
printKot(guestBookId: string | null): Observable<boolean> {
|
||||
const item = JSON.parse(JSON.stringify(this.bill));
|
||||
const newKot = this.getKot();
|
||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
||||
if (newKot.inventories.length === 0) {
|
||||
this.toaster.show('Error', 'Cannot print a blank KOT\nPlease add some products!');
|
||||
return throwError('Cannot print a blank KOT\nPlease add some products!');
|
||||
}
|
||||
if (!this.happyHourItemsBalanced()) {
|
||||
return throwError('Happy hour products are not balanced.');
|
||||
}
|
||||
item.kots.push(newKot);
|
||||
return this.ser.saveOrUpdate(item, VoucherType.Kot, guestBookId, true);
|
||||
}
|
||||
|
||||
printBill(guest_book_id: string | null, voucherType: VoucherType): Observable<boolean> {
|
||||
const item = JSON.parse(JSON.stringify(this.bill));
|
||||
item.kots.forEach((k: Kot) => {
|
||||
k.inventories.forEach((i: Inventory) => {
|
||||
i.discount = (this.data.find((x) => !x.isKot && x.id === i.id) as BillViewItem).discount;
|
||||
});
|
||||
});
|
||||
item.kots.push(this.getKot());
|
||||
const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
|
||||
if (item.kots.length === 1 && newKot.inventories.length === 0) {
|
||||
return throwError('Cannot print a blank Bill\nPlease add some products!');
|
||||
}
|
||||
if (!this.happyHourItemsBalanced()) {
|
||||
return throwError('Happy hour products are not balanced.');
|
||||
}
|
||||
return this.ser.saveOrUpdate(item, voucherType, guest_book_id, true);
|
||||
}
|
||||
|
||||
@ -246,88 +279,73 @@ export class BillService {
|
||||
updateAmounts() {
|
||||
this.netAmount.next(
|
||||
round(
|
||||
this.data
|
||||
.filter((x) => !x.isKot)
|
||||
.reduce(
|
||||
(ca: number, c: BillViewItem) => ca + (c.isHappyHour ? 0 : c.price) * c.quantity,
|
||||
this.bill.kots.reduce(
|
||||
(t, k) =>
|
||||
k.inventories.reduce((a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity, 0) + t,
|
||||
0,
|
||||
),
|
||||
),
|
||||
);
|
||||
this.discountAmount.next(
|
||||
round(
|
||||
this.data
|
||||
.filter((x) => !x.isKot)
|
||||
.reduce(
|
||||
(ca: number, c: BillViewItem) =>
|
||||
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * c.discount,
|
||||
this.bill.kots.reduce(
|
||||
(t, k) =>
|
||||
k.inventories.reduce(
|
||||
(a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * c.discount,
|
||||
0,
|
||||
) + t,
|
||||
0,
|
||||
),
|
||||
),
|
||||
);
|
||||
this.taxAmount.next(
|
||||
round(
|
||||
this.data
|
||||
.filter((x) => !x.isKot)
|
||||
.reduce(
|
||||
(ca: number, c: BillViewItem) =>
|
||||
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate,
|
||||
this.bill.kots.reduce(
|
||||
(t, k) =>
|
||||
k.inventories.reduce(
|
||||
(a, c) =>
|
||||
a + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate,
|
||||
0,
|
||||
) + t,
|
||||
0,
|
||||
),
|
||||
),
|
||||
);
|
||||
this.amount.next(
|
||||
round(
|
||||
this.data
|
||||
.filter((x) => !x.isKot)
|
||||
.reduce(
|
||||
(ca: number, c: BillViewItem) =>
|
||||
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate),
|
||||
0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
amountVal(): number {
|
||||
return round(
|
||||
this.bill.kots.reduce(
|
||||
(ka: number, k: Kot) =>
|
||||
ka +
|
||||
(t, k) =>
|
||||
k.inventories.reduce(
|
||||
(ca: number, c: Inventory) =>
|
||||
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate),
|
||||
(a, c) =>
|
||||
a + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate),
|
||||
0,
|
||||
) + t,
|
||||
0,
|
||||
),
|
||||
0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
splitBill(table: Table): Observable<boolean> {
|
||||
const inventoriesToMove: string[] = this.selection.selected.map(
|
||||
(x: BillViewItem) => x.id as string,
|
||||
(x: string) => (JSON.parse(x) as BillSelectionItem).inventoryId as string,
|
||||
);
|
||||
return this.ser.splitBill(this.bill.id as string, inventoriesToMove, table);
|
||||
}
|
||||
|
||||
private getKot(): Kot {
|
||||
return new Kot({
|
||||
inventories: this.data
|
||||
.filter((x) => !x.isKot && !x.isPrinted)
|
||||
.map(
|
||||
(y) =>
|
||||
new Inventory({
|
||||
product: y.product,
|
||||
quantity: y.quantity,
|
||||
price: y.price,
|
||||
isHappyHour: y.isHappyHour,
|
||||
discount: y.discount,
|
||||
modifiers: y.modifiers,
|
||||
taxRate: y.taxRate,
|
||||
tax: y.tax,
|
||||
}),
|
||||
),
|
||||
});
|
||||
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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
14
bookie/src/app/sales/bills/bill-selection-item.ts
Normal file
14
bookie/src/app/sales/bills/bill-selection-item.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export class BillSelectionItem {
|
||||
kotId?: string;
|
||||
inventoryId?: string;
|
||||
productId: string;
|
||||
isHappyHour: boolean;
|
||||
|
||||
public constructor(init?: Partial<BillSelectionItem>) {
|
||||
this.kotId = undefined;
|
||||
this.inventoryId = undefined;
|
||||
this.productId = '';
|
||||
this.isHappyHour = false;
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
@ -62,8 +62,8 @@
|
||||
*ngIf="!row.isKot"
|
||||
[disabled]="!row.id"
|
||||
(click)="$event.stopPropagation()"
|
||||
(change)="$event ? bs.selection.toggle(row) : null"
|
||||
[checked]="bs.selection.isSelected(row)"
|
||||
(change)="$event ? toggle(row) : null"
|
||||
[checked]="isSelected(row)"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</mat-cell>
|
||||
|
@ -16,7 +16,9 @@ import { QuantityComponent } from '../quantity/quantity.component';
|
||||
import { TablesDialogComponent } from '../tables-dialog/tables-dialog.component';
|
||||
|
||||
import { Bill } from './bill';
|
||||
import { BillSelectionItem } from './bill-selection-item';
|
||||
import { BillsDataSource } from './bills-datasource';
|
||||
import { Inventory } from './inventory';
|
||||
import { Kot } from './kot';
|
||||
import { VoucherType } from './voucher-type';
|
||||
|
||||
@ -66,33 +68,88 @@ export class BillsComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
isAllSelected(kot: Kot) {
|
||||
return this.bs.data
|
||||
.filter((x) => x.kotId === kot.id)
|
||||
.reduce((p: boolean, c: BillViewItem) => p && this.bs.selection.isSelected(c), true);
|
||||
isAllSelected(kotView: BillViewItem): boolean {
|
||||
const kot = this.bs.bill.kots.find((k) => k.id === kotView.kotId) as Kot;
|
||||
return kot.inventories.reduce(
|
||||
(p: boolean, c: Inventory) =>
|
||||
p &&
|
||||
this.bs.selection.isSelected(
|
||||
JSON.stringify(
|
||||
new BillSelectionItem({
|
||||
kotId: kot.id,
|
||||
inventoryId: c.id,
|
||||
productId: c.product.id,
|
||||
isHappyHour: c.isHappyHour,
|
||||
}),
|
||||
),
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
isAnySelected(kot: Kot) {
|
||||
toggle(invView: BillViewItem) {
|
||||
const key = JSON.stringify(
|
||||
new BillSelectionItem({
|
||||
kotId: invView.kotId,
|
||||
inventoryId: invView.id,
|
||||
productId: invView.productId,
|
||||
isHappyHour: invView.isHappyHour,
|
||||
}),
|
||||
);
|
||||
this.bs.selection.toggle(key);
|
||||
}
|
||||
|
||||
isSelected(invView: BillViewItem): boolean {
|
||||
const key = JSON.stringify(
|
||||
new BillSelectionItem({
|
||||
kotId: invView.kotId,
|
||||
inventoryId: invView.id,
|
||||
productId: invView.productId,
|
||||
isHappyHour: invView.isHappyHour,
|
||||
}),
|
||||
);
|
||||
return this.bs.selection.isSelected(key);
|
||||
}
|
||||
|
||||
isAnySelected(kotView: BillViewItem) {
|
||||
const kot = this.bs.bill.kots.find((k) => k.id === kotView.kotId) as Kot;
|
||||
let total = 0;
|
||||
let found = 0;
|
||||
this.bs.data
|
||||
.filter((x) => x.kotId === kot.id)
|
||||
.forEach((c: BillViewItem) => {
|
||||
for (const item of kot.inventories) {
|
||||
const key = JSON.stringify(
|
||||
new BillSelectionItem({
|
||||
kotId: kot.id,
|
||||
inventoryId: item.id,
|
||||
productId: item.product.id,
|
||||
isHappyHour: item.isHappyHour,
|
||||
}),
|
||||
);
|
||||
total += 1;
|
||||
if (this.bs.selection.isSelected(c)) {
|
||||
if (this.bs.selection.isSelected(key)) {
|
||||
found += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
return found > 0 && found < total;
|
||||
}
|
||||
|
||||
masterToggle(kot: Kot) {
|
||||
const isAllSelected = this.isAllSelected(kot);
|
||||
this.bs.data
|
||||
.filter((x) => x.kotId === kot.id)
|
||||
.forEach((row) =>
|
||||
isAllSelected ? this.bs.selection.deselect(row) : this.bs.selection.select(row),
|
||||
masterToggle(kotView: BillViewItem) {
|
||||
const isAllSelected = this.isAllSelected(kotView);
|
||||
const kot = this.bs.bill.kots.find((k) => k.id === kotView.kotId) as Kot;
|
||||
for (const item of kot.inventories) {
|
||||
const key = JSON.stringify(
|
||||
new BillSelectionItem({
|
||||
kotId: kot.id,
|
||||
inventoryId: item.id,
|
||||
productId: item.product.id,
|
||||
isHappyHour: item.isHappyHour,
|
||||
}),
|
||||
);
|
||||
if (isAllSelected) {
|
||||
this.bs.selection.deselect(key);
|
||||
} else {
|
||||
this.bs.selection.select(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addOne(item: BillViewItem): void {
|
||||
@ -109,18 +166,7 @@ export class BillsComponent implements OnInit {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
if (!item.isPrinted) {
|
||||
this.bs.quantity(item, result as number);
|
||||
} else {
|
||||
const quantity = result as number;
|
||||
const product = {
|
||||
...item.product,
|
||||
hasHappyHour: item.isHappyHour,
|
||||
tax: item.tax,
|
||||
price: item.price,
|
||||
};
|
||||
this.bs.addProduct(product, quantity, item.discount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ export class SalesHomeComponent {
|
||||
if (!this.receivePaymentAllowed()) {
|
||||
return;
|
||||
}
|
||||
const amount = this.bs.amountVal();
|
||||
const amount = this.bs.amountVal;
|
||||
const type = this.bs.type();
|
||||
this.dialog
|
||||
.open(ReceivePaymentComponent, {
|
||||
|
Loading…
x
Reference in New Issue
Block a user