dcaf23b390
Auth guard and auth service simplified and fixed so that user is updated upon login Home component changed to use square buttons Fixed showing the totals in the bill ng linted the project
253 lines
7.7 KiB
TypeScript
253 lines
7.7 KiB
TypeScript
import { Injectable } from '@angular/core';
|
|
import { MatDialog } from '@angular/material';
|
|
import { BehaviorSubject } from 'rxjs';
|
|
import { Observable } from 'rxjs/internal/Observable';
|
|
import * as math from 'mathjs';
|
|
import { Product } from '../core/product';
|
|
import { ModifiersComponent } from './modifiers/modifiers.component';
|
|
import { ModifierCategoryService } from '../modifier-categories/modifier-category.service';
|
|
import { ModifierCategory } from '../core/modifier-category';
|
|
import { Bill, Inventory, Kot, PrintType } from './bills/bill';
|
|
import { VoucherService } from './bills/voucher.service';
|
|
import { ToasterService } from '../core/toaster.service';
|
|
import { tap } from 'rxjs/operators';
|
|
import { Table } from '../core/table';
|
|
|
|
@Injectable()
|
|
export class BillService {
|
|
public dataObs;
|
|
public data;
|
|
private bill;
|
|
public netAmount: BehaviorSubject<number>;
|
|
public discountAmount: BehaviorSubject<number>;
|
|
public taxAmount: BehaviorSubject<number>;
|
|
public amount: BehaviorSubject<number>;
|
|
|
|
constructor(
|
|
private dialog: MatDialog,
|
|
private toaster: ToasterService,
|
|
private ser: VoucherService,
|
|
private modifierCategoryService: ModifierCategoryService
|
|
) {
|
|
this.data = [];
|
|
this.dataObs = new BehaviorSubject<any[]>(this.data);
|
|
this.netAmount = new BehaviorSubject(0);
|
|
this.discountAmount = new BehaviorSubject(0);
|
|
this.taxAmount = new BehaviorSubject(0);
|
|
this.amount = new BehaviorSubject(0);
|
|
}
|
|
|
|
loadData(bill: Bill): void {
|
|
this.bill = bill;
|
|
const view = this.bill.kots.map(k => {
|
|
return [{
|
|
isKot: true,
|
|
oldKot: true,
|
|
info: `Kot: ${k.code} / ${k.date} (${k.user.name}) `
|
|
}, ...k.inventories.map(i => {
|
|
return {
|
|
id: i.id,
|
|
isKot: false,
|
|
product: i.product,
|
|
productId: i.product.id,
|
|
isHappyHour: i.isHappyHour,
|
|
isPrinted: true,
|
|
info: `${i.product.name} (${i.product.units}) @ ${i.price} - ${math.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({isKot: true, newKot: true, info: '== New Kot =='});
|
|
this.dataObs.next(this.data);
|
|
this.updateAmounts();
|
|
|
|
}
|
|
addProduct(product: Product): void {
|
|
const old = this.data.find(
|
|
x => !x.isKot && !x.id && x.productId === product.id && x.isHappyHour === product.hasHappyHour
|
|
);
|
|
if (old !== undefined) {
|
|
old.quantity += 1;
|
|
} else {
|
|
const item = {
|
|
isKot: false,
|
|
product: product,
|
|
productId: product.id,
|
|
isHappyHour: product.hasHappyHour,
|
|
info: `${product.name} (${product.units}) @ ${product.price} - ${0}%`,
|
|
price: product.price,
|
|
quantity: 1,
|
|
discount: 0,
|
|
taxRate: product.tax.rate,
|
|
tax: product.tax,
|
|
modifiers: []
|
|
};
|
|
this.data.push(item);
|
|
this.modifierCategoryService.listIsActiveOfProduct(product.id).subscribe(result => {
|
|
if (result.reduce((a: any, c: ModifierCategory) => {
|
|
return a + c.minimum;
|
|
}, 0)) {
|
|
this.showModifier(item);
|
|
}
|
|
});
|
|
}
|
|
this.dataObs.next(this.data);
|
|
this.updateAmounts();
|
|
}
|
|
|
|
showModifier(item: any): void {
|
|
// [routerLink]="['/sales', 'modifiers', item.id]"
|
|
const dialogRef = this.dialog.open(ModifiersComponent, {
|
|
position: {
|
|
top: '10vh'
|
|
},
|
|
data: {
|
|
list: this.modifierCategoryService.listIsActiveOfProduct(item.productId),
|
|
selected: item.modifiers
|
|
}
|
|
});
|
|
|
|
dialogRef.afterClosed().subscribe(result => {
|
|
if (result !== undefined) {
|
|
item.modifiers = result;
|
|
}
|
|
});
|
|
}
|
|
|
|
addOne(item: any): void {
|
|
item.quantity += 1;
|
|
this.dataObs.next(this.data);
|
|
this.updateAmounts();
|
|
}
|
|
|
|
quantity(item: any, quantity: number): void {
|
|
item.quantity = quantity;
|
|
this.dataObs.next(this.data);
|
|
this.updateAmounts();
|
|
}
|
|
|
|
subtractOne(item: any): void {
|
|
if (item.quantity > 1) {
|
|
item.quantity -= 1;
|
|
this.dataObs.next(this.data);
|
|
this.updateAmounts();
|
|
} else if (item.quantity === 0) {
|
|
this.removeItem(item);
|
|
}
|
|
}
|
|
|
|
removeItem(item: any): void {
|
|
this.data.splice(this.data.indexOf(item), 1);
|
|
this.dataObs.next(this.data);
|
|
this.updateAmounts();
|
|
}
|
|
|
|
modifier(item: any): void {
|
|
this.showModifier(item);
|
|
}
|
|
|
|
discount(discounts: {id: string, name: string, discount: number}[]): void {
|
|
this.data.forEach(x => {
|
|
if (!x.isKot) {
|
|
x.discount = discounts.find(d => d.id === x.product.saleCategory.id).discount / 100;
|
|
x.info = `${x.product.name} (${x.product.units}) @ ${x.price} - ${math.round(x.discount * 100, 2)}%`;
|
|
}
|
|
});
|
|
this.dataObs.next(this.data);
|
|
this.updateAmounts();
|
|
}
|
|
|
|
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
|
|
}))
|
|
});
|
|
}
|
|
|
|
printKot(guest_book_id: string): Observable<Bill> {
|
|
const item = JSON.parse(JSON.stringify(this.bill));
|
|
const newKot = this.getKot();
|
|
if (newKot.inventories.length == 0) {
|
|
this.toaster.show('Error', 'Cannot print a blank KOT\nPlease add some products!');
|
|
}
|
|
item.kots.push(newKot);
|
|
return this.ser.saveOrUpdate(item, PrintType.Kot, guest_book_id, true);
|
|
}
|
|
|
|
printBill(guest_book_id: string, printType: PrintType): Observable<Bill> {
|
|
const item = JSON.parse(JSON.stringify(this.bill));
|
|
item.kots.forEach(k => {
|
|
k.inventories.forEach(i => {
|
|
i.discount = this.data.find(x => !x.isKot && x.id === i.id).discount;
|
|
});
|
|
});
|
|
item.kots.push(this.getKot());
|
|
return this.ser.saveOrUpdate(item, printType, guest_book_id, true);
|
|
}
|
|
|
|
type() {
|
|
return this.bill.voucherType;
|
|
}
|
|
|
|
receivePayment(amounts: { id: string; name: string; amount: number }[]): Observable<boolean> {
|
|
return this.ser.receivePayment(this.bill.id, amounts, true);
|
|
}
|
|
|
|
moveTable(table: Table): Observable<boolean> {
|
|
return this.ser.moveTable(this.bill.id, table);
|
|
}
|
|
|
|
moveKot(id: string, table: Table): Observable<boolean> {
|
|
return this.ser.moveKot(this.bill.id, id, table);
|
|
}
|
|
|
|
voidBill(reason: string): Observable<boolean> {
|
|
return this.ser.voidBill(this.bill.id, reason, true);
|
|
}
|
|
|
|
updateAmounts() {
|
|
this.netAmount.next(
|
|
math.round(this.data.filter(x => !x.isKot).reduce(
|
|
(ca: number, c: any) => ca + ((c.isHappyHour ? 0 : c.price) * c.quantity)
|
|
, 0))
|
|
);
|
|
this.discountAmount.next(
|
|
math.round(this.data.filter(x => !x.isKot).reduce(
|
|
(ca: number, c: Inventory) => ca + ((c.isHappyHour ? 0 : c.price) * c.quantity * c.discount)
|
|
, 0))
|
|
);
|
|
this.taxAmount.next(
|
|
math.round(this.data.filter(x => !x.isKot).reduce(
|
|
(ca: number, c: Inventory) => ca + ((c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * c.taxRate)
|
|
, 0))
|
|
);
|
|
this.amount.next(
|
|
math.round(this.data.filter(x => !x.isKot).reduce(
|
|
(ca: number, c: Inventory) => ca + ((c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate))
|
|
, 0))
|
|
);
|
|
}
|
|
|
|
amountVal(): number {
|
|
return math.round(this.bill.kots.reduce(
|
|
(ka: number, k: Kot) => ka + k.inventories.reduce(
|
|
(ca: number, c: Inventory) => ca + ((c.isHappyHour ? 0 : c.price) * c.quantity * (1 - c.discount) * (1 + c.taxRate))
|
|
, 0)
|
|
, 0));
|
|
}
|
|
}
|