barker/bookie/src/app/sales/bill.service.ts
Amritanshu dcaf23b390 Tax is added directly to product for sale
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
2019-08-11 01:37:14 +05:30

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