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:
2020-12-16 22:34:41 +05:30
parent 28952402aa
commit 6c83c74424
9 changed files with 304 additions and 195 deletions

View File

@ -2,6 +2,8 @@ import uuid
from typing import List, Optional from typing import List, Optional
import barker.schemas.voucher as schemas
from fastapi import HTTPException, status from fastapi import HTTPException, status
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy.orm import Session 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]): for i in (i for i in voucher.settlements if i.settled not in [x.id_ for x in settlements]):
voucher.settlements.remove(i) voucher.settlements.remove(i)
db.delete(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

View File

@ -24,6 +24,8 @@ from ...routers.voucher import (
get_bill_id, get_bill_id,
get_guest_book, get_guest_book,
get_tax, get_tax,
happy_hour_has_discount,
happy_hour_items_balanced,
) )
from ...schemas.auth import UserToken from ...schemas.auth import UserToken
@ -99,6 +101,16 @@ def do_save(
for k in data.kots: for k in data.kots:
if not len(k.inventories): if not len(k.inventories):
continue 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() 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) kot = Kot(item.id, code, item.food_table_id, item.date, item.user_id)
item.kots.append(kot) item.kots.append(kot)

View File

@ -24,6 +24,8 @@ from ...routers.voucher import (
get_bill_id, get_bill_id,
get_guest_book, get_guest_book,
get_tax, get_tax,
happy_hour_has_discount,
happy_hour_items_balanced,
) )
from ...schemas.auth import UserToken from ...schemas.auth import UserToken
@ -87,6 +89,17 @@ def update(
i.discount = next( i.discount = next(
round(inv.discount, 5) for ko in data.kots for inv in ko.inventories if inv.id_ == i.id 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): for k in (k for k in data.kots if k.id_ is None and len(k.inventories) > 0):
need_to_print_kot = True need_to_print_kot = True
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar() code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()

View File

@ -4,42 +4,32 @@ import { Tax } from './tax';
export class BillViewItem { export class BillViewItem {
id: string | undefined; id: string | undefined;
kotId: string | undefined;
isKot: boolean; isKot: boolean;
info: string; info: string;
kotId: string; productId: string;
product: Product;
productId: string | undefined;
isHappyHour: boolean; isHappyHour: boolean;
isPrinted: boolean; isPrinted: boolean;
price: number;
quantity: number; quantity: number;
discount: number;
taxRate: number;
tax: Tax;
modifiers: Modifier[]; modifiers: Modifier[];
public get isOldKot(): boolean { public get isOldKot(): boolean {
return this.isKot && this.id !== undefined; return this.isKot && this.kotId !== undefined;
} }
public get isNewKot(): boolean { public get isNewKot(): boolean {
return this.isKot && this.id === undefined; return this.isKot && this.kotId === undefined;
} }
public constructor(init?: Partial<BillViewItem>) { public constructor(init?: Partial<BillViewItem>) {
this.isKot = true; this.isKot = true;
this.info = ''; this.info = '';
this.kotId = ''; this.kotId = '';
this.product = new Product(); this.productId = '';
this.productId = this.product.id;
this.isHappyHour = false; this.isHappyHour = false;
this.isPrinted = false; this.isPrinted = false;
this.price = 0;
this.quantity = 0; this.quantity = 0;
this.discount = 0;
this.taxRate = 0;
this.tax = new Tax();
this.modifiers = []; this.modifiers = [];
Object.assign(this, init); Object.assign(this, init);
} }

View File

@ -2,8 +2,9 @@ import { SelectionModel } from '@angular/cdk/collections';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { round } from 'mathjs'; import { round } from 'mathjs';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject, throwError } from 'rxjs';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { tap } from 'rxjs/operators';
import { BillViewItem } from '../core/bill-view-item'; import { BillViewItem } from '../core/bill-view-item';
import { ModifierCategory } from '../core/modifier-category'; 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 { ModifierCategoryService } from '../modifier-categories/modifier-category.service';
import { Bill } from './bills/bill'; import { Bill } from './bills/bill';
import { BillSelectionItem } from './bills/bill-selection-item';
import { Inventory } from './bills/inventory'; import { Inventory } from './bills/inventory';
import { Kot } from './bills/kot'; import { Kot } from './bills/kot';
import { VoucherType } from './bills/voucher-type'; import { VoucherType } from './bills/voucher-type';
@ -24,13 +26,13 @@ import { ModifiersComponent } from './modifiers/modifiers.component';
@Injectable() @Injectable()
export class BillService { export class BillService {
public dataObs: BehaviorSubject<BillViewItem[]>; public dataObs: BehaviorSubject<BillViewItem[]>;
public data: BillViewItem[];
public bill: Bill = new Bill(); public bill: Bill = new Bill();
public netAmount: BehaviorSubject<number>; public netAmount: BehaviorSubject<number>;
public discountAmount: BehaviorSubject<number>; public discountAmount: BehaviorSubject<number>;
public taxAmount: BehaviorSubject<number>; public taxAmount: BehaviorSubject<number>;
public amount: BehaviorSubject<number>; public amount: BehaviorSubject<number>;
public selection = new SelectionModel<BillViewItem>(true, []); public amountVal: number;
public selection = new SelectionModel<string>(true, []);
constructor( constructor(
private dialog: MatDialog, private dialog: MatDialog,
@ -38,21 +40,28 @@ export class BillService {
private ser: VoucherService, private ser: VoucherService,
private modifierCategoryService: ModifierCategoryService, private modifierCategoryService: ModifierCategoryService,
) { ) {
this.data = []; this.dataObs = new BehaviorSubject<BillViewItem[]>([]);
this.dataObs = new BehaviorSubject<BillViewItem[]>(this.data);
this.netAmount = new BehaviorSubject(0); this.netAmount = new BehaviorSubject(0);
this.discountAmount = new BehaviorSubject(0); this.discountAmount = new BehaviorSubject(0);
this.taxAmount = new BehaviorSubject(0); this.taxAmount = new BehaviorSubject(0);
this.amount = new BehaviorSubject(0); this.amount = new BehaviorSubject(0);
this.amountVal = 0;
this.amount.pipe(tap((x) => (this.amountVal = x)));
} }
loadData(bill: Bill): void { displayBill(): void {
this.bill = bill; const data = this.transformBillToView(this.bill);
const view: BillViewItem[][] = this.bill.kots.map((k: Kot) => [ this.dataObs.next(data);
this.updateAmounts();
}
transformBillToView(bill: Bill): BillViewItem[] {
const view: BillViewItem[] = bill.kots
.map((k: Kot) => [
new BillViewItem({ new BillViewItem({
id: k.id, kotId: k.id,
isKot: true, 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( ...k.inventories.map(
(i) => (i) =>
@ -60,37 +69,41 @@ export class BillService {
id: i.id, id: i.id,
kotId: k.id, kotId: k.id,
isKot: false, isKot: false,
product: i.product,
productId: i.product.id, productId: i.product.id,
isHappyHour: i.isHappyHour, isHappyHour: i.isHappyHour,
isPrinted: true, isPrinted: !!k.id,
info: `${i.product.name} @ ${i.price} - ${round(i.discount * 100, 2)}%`, info: `${i.product.name} @ ${i.price} - ${round(i.discount * 100, 2)}%`,
price: i.price,
quantity: i.quantity, quantity: i.quantity,
discount: i.discount,
taxRate: i.taxRate,
tax: i.tax,
modifiers: i.modifiers, modifiers: i.modifiers,
}), }),
), ),
]); ])
this.data = view.reduce((a, c) => a.concat(c), []); .reduce((a, c) => a.concat(c), []);
this.data.push(new BillViewItem({ isKot: true, info: '== New Kot ==' })); return view;
this.dataObs.next(this.data); }
this.updateAmounts();
loadData(bill: Bill): void {
bill.kots.push(new Kot());
this.bill = bill;
this.displayBill();
} }
minimum(productId: string, happyHour: boolean): number { minimum(productId: string, happyHour: boolean): number {
return this.data.reduce( return this.bill.kots.reduce(
(a, c) => (c.productId === productId && c.isHappyHour === happyHour ? a + c.quantity : a), (t, k) =>
k.inventories.reduce(
(a, c) =>
c.product.id === productId && c.isHappyHour === happyHour ? a + c.quantity : a,
0,
) + t,
0, 0,
); );
} }
addProduct(product: Product, quantity: number, discount: number): void { addProduct(product: Product, quantity: number, discount: number): void {
const old = this.data.find( const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
(x) => const old = newKot.inventories.find(
!x.isKot && !x.id && x.productId === product.id && x.isHappyHour === product.hasHappyHour, (x) => x.product.id === product.id && x.isHappyHour === product.hasHappyHour,
); );
if (quantity < 0) { if (quantity < 0) {
const minimum = this.minimum(product.id as string, product.hasHappyHour) + quantity; const minimum = this.minimum(product.id as string, product.hasHappyHour) + quantity;
@ -102,38 +115,34 @@ export class BillService {
if (old !== undefined) { if (old !== undefined) {
old.quantity += quantity; old.quantity += quantity;
} else { } else {
const item = new BillViewItem({ const item = new Inventory({
isKot: false,
product, product,
productId: product.id,
isHappyHour: product.hasHappyHour,
info: `${product.name} @ ${product.price} - ${0}%`,
price: product.price,
quantity, quantity,
discount, price: product.price,
isHappyHour: product.hasHappyHour,
taxRate: product.tax.rate, taxRate: product.tax.rate,
tax: product.tax, tax: product.tax,
discount,
modifiers: [], modifiers: [],
}); });
this.data.push(item); newKot.inventories.push(item);
this.modifierCategoryService.listForProduct(product.id as string).subscribe((result) => { this.modifierCategoryService.listForProduct(product.id as string).subscribe((result) => {
if (result.reduce((a: number, c: ModifierCategory) => a + c.minimum, 0)) { if (result.reduce((a: number, c: ModifierCategory) => a + c.minimum, 0)) {
this.showModifier(item); this.showModifier(item);
} }
}); });
} }
this.dataObs.next(this.data); this.displayBill();
this.updateAmounts();
} }
showModifier(item: BillViewItem): void { showModifier(item: Inventory): void {
// [routerLink]="['/sales', 'modifiers', item.id]" // [routerLink]="['/sales', 'modifiers', item.id]"
const dialogRef = this.dialog.open(ModifiersComponent, { const dialogRef = this.dialog.open(ModifiersComponent, {
position: { position: {
top: '10vh', top: '10vh',
}, },
data: { data: {
list: this.modifierCategoryService.listForProduct(item.productId as string), list: this.modifierCategoryService.listForProduct(item.product.id as string),
selected: item.modifiers, selected: item.modifiers,
}, },
}); });
@ -143,75 +152,99 @@ export class BillService {
item.modifiers = result; item.modifiers = result;
} }
}); });
this.displayBill();
} }
addOne(item: BillViewItem): void { addOne(item: BillViewItem): void {
item.quantity += 1; const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
this.dataObs.next(this.data); const old = newKot.inventories.find(
this.updateAmounts(); (x) => x.product.id === item.productId && x.isHappyHour === item.isHappyHour,
) as Inventory;
old.quantity += 1;
this.displayBill();
} }
quantity(item: BillViewItem, quantity: number): void { quantity(item: BillViewItem, quantity: number): void {
item.quantity = quantity; const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
this.dataObs.next(this.data); const old = newKot.inventories.find(
this.updateAmounts(); (x) => x.product.id === item.productId && x.isHappyHour === item.isHappyHour,
) as Inventory;
old.quantity = quantity;
this.displayBill();
} }
subtractOne(item: BillViewItem, canEdit: boolean): void { 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 ( if (
item.quantity > 1 || item.quantity > 1 ||
(canEdit && this.minimum(item.productId as string, item.isHappyHour) >= 1) (canEdit && this.minimum(item.productId as string, item.isHappyHour) >= 1)
) { ) {
item.quantity -= 1; old.quantity -= 1;
this.dataObs.next(this.data);
this.updateAmounts();
} else if (item.quantity === 0) { } else if (item.quantity === 0) {
this.removeItem(item); newKot.inventories.splice(newKot.inventories.indexOf(old), 1);
} }
this.displayBill();
} }
removeItem(item: BillViewItem): void { removeItem(item: BillViewItem): void {
this.data.splice(this.data.indexOf(item), 1); const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
this.dataObs.next(this.data); const old = newKot.inventories.find(
this.updateAmounts(); (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 { 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 { discount(discounts: { id: string; name: string; discount: number }[]): void {
this.data.forEach((x) => { for (const kot of this.bill.kots) {
if (!x.isKot) { const noDiscount = kot.inventories
const e = discounts.find((d) => d.id === (x.product.saleCategory as SaleCategory).id); .filter((x) => x.isHappyHour)
if (e !== undefined) { .map((x) => x.product.id as string);
x.discount = e.discount; for (const inventory of kot.inventories) {
x.info = `${x.product.name} @ ${x.price} - ${round(x.discount * 100, 2)}%`; 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.displayBill();
this.dataObs.next(this.data);
this.updateAmounts();
} }
printKot(guestBookId: string | null): Observable<boolean> { printKot(guestBookId: string | null): Observable<boolean> {
const item = JSON.parse(JSON.stringify(this.bill)); 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) { 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); return this.ser.saveOrUpdate(item, VoucherType.Kot, guestBookId, true);
} }
printBill(guest_book_id: string | null, voucherType: VoucherType): Observable<boolean> { printBill(guest_book_id: string | null, voucherType: VoucherType): Observable<boolean> {
const item = JSON.parse(JSON.stringify(this.bill)); const item = JSON.parse(JSON.stringify(this.bill));
item.kots.forEach((k: Kot) => { const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
k.inventories.forEach((i: Inventory) => { if (item.kots.length === 1 && newKot.inventories.length === 0) {
i.discount = (this.data.find((x) => !x.isKot && x.id === i.id) as BillViewItem).discount; return throwError('Cannot print a blank Bill\nPlease add some products!');
}); }
}); if (!this.happyHourItemsBalanced()) {
item.kots.push(this.getKot()); return throwError('Happy hour products are not balanced.');
}
return this.ser.saveOrUpdate(item, voucherType, guest_book_id, true); return this.ser.saveOrUpdate(item, voucherType, guest_book_id, true);
} }
@ -246,88 +279,73 @@ export class BillService {
updateAmounts() { updateAmounts() {
this.netAmount.next( this.netAmount.next(
round( round(
this.data this.bill.kots.reduce(
.filter((x) => !x.isKot) (t, k) =>
.reduce( k.inventories.reduce((a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity, 0) + t,
(ca: number, c: BillViewItem) => ca + (c.isHappyHour ? 0 : c.price) * c.quantity,
0, 0,
), ),
), ),
); );
this.discountAmount.next( this.discountAmount.next(
round( round(
this.data this.bill.kots.reduce(
.filter((x) => !x.isKot) (t, k) =>
.reduce( k.inventories.reduce(
(ca: number, c: BillViewItem) => (a, c) => a + (c.isHappyHour ? 0 : c.price) * c.quantity * c.discount,
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * c.discount, 0,
) + t,
0, 0,
), ),
), ),
); );
this.taxAmount.next( this.taxAmount.next(
round( round(
this.data this.bill.kots.reduce(
.filter((x) => !x.isKot) (t, k) =>
.reduce( k.inventories.reduce(
(ca: number, c: BillViewItem) => (a, c) =>
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate, a + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate,
0,
) + t,
0, 0,
), ),
), ),
); );
this.amount.next( this.amount.next(
round( 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( this.bill.kots.reduce(
(ka: number, k: Kot) => (t, k) =>
ka +
k.inventories.reduce( k.inventories.reduce(
(ca: number, c: Inventory) => (a, c) =>
ca + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate), a + (c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate),
0,
) + t,
0, 0,
), ),
0,
), ),
); );
} }
splitBill(table: Table): Observable<boolean> { splitBill(table: Table): Observable<boolean> {
const inventoriesToMove: string[] = this.selection.selected.map( 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); return this.ser.splitBill(this.bill.id as string, inventoriesToMove, table);
} }
private getKot(): Kot { private happyHourItemsBalanced(): boolean {
return new Kot({ const newKot = this.bill.kots.find((k) => k.id === undefined) as Kot;
inventories: this.data const happyHourItems = newKot.inventories
.filter((x) => !x.isKot && !x.isPrinted) .filter((x) => x.isHappyHour)
.map( .map((x) => ({ id: x.product.id as string, quantity: x.quantity }));
(y) => for (const item of happyHourItems) {
new Inventory({ const q = newKot.inventories.find(
product: y.product, (x) => !x.isHappyHour && x.product.id === item.id && x.quantity === item.quantity,
quantity: y.quantity, );
price: y.price, if (q === undefined) {
isHappyHour: y.isHappyHour, return false;
discount: y.discount, }
modifiers: y.modifiers, }
taxRate: y.taxRate, return true;
tax: y.tax,
}),
),
});
} }
} }

View 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);
}
}

View File

@ -62,8 +62,8 @@
*ngIf="!row.isKot" *ngIf="!row.isKot"
[disabled]="!row.id" [disabled]="!row.id"
(click)="$event.stopPropagation()" (click)="$event.stopPropagation()"
(change)="$event ? bs.selection.toggle(row) : null" (change)="$event ? toggle(row) : null"
[checked]="bs.selection.isSelected(row)" [checked]="isSelected(row)"
> >
</mat-checkbox> </mat-checkbox>
</mat-cell> </mat-cell>

View File

@ -16,7 +16,9 @@ import { QuantityComponent } from '../quantity/quantity.component';
import { TablesDialogComponent } from '../tables-dialog/tables-dialog.component'; import { TablesDialogComponent } from '../tables-dialog/tables-dialog.component';
import { Bill } from './bill'; import { Bill } from './bill';
import { BillSelectionItem } from './bill-selection-item';
import { BillsDataSource } from './bills-datasource'; import { BillsDataSource } from './bills-datasource';
import { Inventory } from './inventory';
import { Kot } from './kot'; import { Kot } from './kot';
import { VoucherType } from './voucher-type'; import { VoucherType } from './voucher-type';
@ -66,33 +68,88 @@ export class BillsComponent implements OnInit {
}); });
} }
isAllSelected(kot: Kot) { isAllSelected(kotView: BillViewItem): boolean {
return this.bs.data const kot = this.bs.bill.kots.find((k) => k.id === kotView.kotId) as Kot;
.filter((x) => x.kotId === kot.id) return kot.inventories.reduce(
.reduce((p: boolean, c: BillViewItem) => p && this.bs.selection.isSelected(c), true); (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 total = 0;
let found = 0; let found = 0;
this.bs.data for (const item of kot.inventories) {
.filter((x) => x.kotId === kot.id) const key = JSON.stringify(
.forEach((c: BillViewItem) => { new BillSelectionItem({
kotId: kot.id,
inventoryId: item.id,
productId: item.product.id,
isHappyHour: item.isHappyHour,
}),
);
total += 1; total += 1;
if (this.bs.selection.isSelected(c)) { if (this.bs.selection.isSelected(key)) {
found += 1; found += 1;
} }
}); }
return found > 0 && found < total; return found > 0 && found < total;
} }
masterToggle(kot: Kot) { masterToggle(kotView: BillViewItem) {
const isAllSelected = this.isAllSelected(kot); const isAllSelected = this.isAllSelected(kotView);
this.bs.data const kot = this.bs.bill.kots.find((k) => k.id === kotView.kotId) as Kot;
.filter((x) => x.kotId === kot.id) for (const item of kot.inventories) {
.forEach((row) => const key = JSON.stringify(
isAllSelected ? this.bs.selection.deselect(row) : this.bs.selection.select(row), 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 { addOne(item: BillViewItem): void {
@ -109,18 +166,7 @@ export class BillsComponent implements OnInit {
if (!result) { if (!result) {
return; return;
} }
if (!item.isPrinted) {
this.bs.quantity(item, result as number); 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);
}
}); });
} }

View File

@ -191,7 +191,7 @@ export class SalesHomeComponent {
if (!this.receivePaymentAllowed()) { if (!this.receivePaymentAllowed()) {
return; return;
} }
const amount = this.bs.amountVal(); const amount = this.bs.amountVal;
const type = this.bs.type(); const type = this.bs.type();
this.dialog this.dialog
.open(ReceivePaymentComponent, { .open(ReceivePaymentComponent, {