import { Component } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; import { Observable, of as observableOf, throwError } from 'rxjs'; import { map, switchMap, tap } from 'rxjs/operators'; import { AuthService } from '../../auth/auth.service'; import { Table } from '../../core/table'; import { ToasterService } from '../../core/toaster.service'; import { SaleCategoryService } from '../../sale-category/sale-category.service'; import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dialog.component'; import { TableService } from '../../tables/table.service'; import { BillTypeComponent } from '../bill-type/bill-type.component'; import { BillService } from '../bill.service'; import { PrintType } from '../bills/print-type'; import { DiscountComponent } from '../discount/discount.component'; import { ReasonComponent } from '../reason/reason.component'; import { ReceivePaymentComponent } from '../receive-payment/receive-payment.component'; import { TablesDialogComponent } from '../tables-dialog/tables-dialog.component'; @Component({ selector: 'app-sales-home', templateUrl: './sales-home.component.html', styleUrls: ['./sales-home.component.css'], }) export class SalesHomeComponent { constructor( private route: ActivatedRoute, private router: Router, private dialog: MatDialog, private auth: AuthService, private toaster: ToasterService, private mcSer: SaleCategoryService, private tSer: TableService, private bs: BillService, ) {} printKotAllowed(): boolean { if (this.auth.user && this.auth.user.perms.indexOf('print-kot') === -1) { return false; } if (!this.bs.bill.id) { return true; } if (this.bs.bill.voucherType !== PrintType.Kot) { return false; } if (this.bs.bill.isVoid) { return false; } return true; } printKot() { if (!this.printKotAllowed()) { return; } let guestBookId = null; if (this.route.snapshot.queryParamMap.has('guest')) { guestBookId = this.route.snapshot.queryParamMap.get('guest'); } this.bs.printKot(guestBookId).subscribe(() => { this.toaster.show('Success', ''); this.router.navigate(['/sales']); }); } discountAllowed(): boolean { return this.auth.user && this.auth.user.perms.indexOf('discount') !== -1; } showDiscount(): Observable { if (this.discountAllowed()) { const dialogRef = this.dialog.open(DiscountComponent, { // width: '750px', data: this.mcSer.listForDiscount(), }); return dialogRef.afterClosed(); } return observableOf(false); } discount(): void { this.showDiscount().subscribe( (result: boolean | { id: string; name: string; discount: number }[]) => { if (result) { this.bs.discount(result as { id: string; name: string; discount: number }[]); } }, ); } billTypeDialog() { if (this.bs.bill.voucherType !== PrintType.Kot) { return observableOf(this.bs.bill.voucherType); } return this.dialog .open(BillTypeComponent) .afterClosed() .pipe( tap((x) => { if (!x) { throwError('No Bill Type Chosen'); } }), ); } confirmTableDialog(table: Table): Observable<{ table: Table; confirmed: boolean }> { return this.dialog .open(ConfirmDialogComponent, { width: '250px', data: { title: 'Select Table?', content: 'Are you sure?' }, }) .afterClosed() .pipe(map((x: boolean) => ({ table, confirmed: x }))); } confirmVoidDialog(reason: string): Observable { return this.dialog .open(ConfirmDialogComponent, { width: '250px', data: { title: 'Void Bill?', content: 'Are you sure?' }, }) .afterClosed() .pipe(map((x: boolean) => (x ? reason : x))); } printBillAllowed(): boolean { if (this.auth.user && this.auth.user.perms.indexOf('print-bill') === -1) { return false; } if (!this.bs.bill.id) { return true; } if ( this.bs.bill.voucherType !== PrintType.Kot && this.auth.user.perms.indexOf('edit-printed-bill') === -1 ) { return false; } if (this.bs.bill.isVoid) { return false; } return true; } printBill() { if (!this.printBillAllowed()) { return; } let guestBookId = null; if (this.route.snapshot.queryParamMap.has('guest')) { guestBookId = this.route.snapshot.queryParamMap.get('guest'); } this.showDiscount() .pipe( tap((result: boolean | { id: string; name: string; discount: number }[]) => { if (result) { this.bs.discount(result as { id: string; name: string; discount: number }[]); } }), switchMap(() => this.billTypeDialog()), switchMap((x: boolean | PrintType) => { if (x) { return this.bs.printBill(guestBookId, x as PrintType); } return throwError(x); }), ) .subscribe( () => { this.toaster.show('Success', ''); this.router.navigate(['/sales']); }, () => { this.toaster.show('Error', 'No Bill Type Chosen'); }, ); } receivePaymentAllowed(): boolean { if (this.auth.user && this.auth.user.perms.indexOf('settle-bill') === -1) { return false; } if (!this.bs.bill.id) { return false; } if (this.bs.bill.voucherType === PrintType.Kot) { return false; } if (this.bs.bill.isVoid) { return false; } return true; } receivePaymentWithReason(type: string, amount: number): Observable { const types = { NO_CHARGE: [ { id: 4, name: 'No Charge', amount, }, ], STAFF: [ { id: 10, name: 'Staff Account', amount, }, ], }; return this.dialog .open(ReasonComponent, { // width: '750px' data: { title: type === 'NO_CHARGE' ? 'NC for whom' : 'Staff name' }, }) .afterClosed() .pipe( switchMap((value: boolean | string) => { if (value) { return this.bs.receivePayment(types[type], value as string); } return throwError('Cancelled'); }), ); } receiveRegularPayment(type: string, amount: number): Observable { return this.dialog .open(ReceivePaymentComponent, { // width: '750px', data: { type, amount, }, }) .afterClosed() .pipe( switchMap((value: boolean | { id: number; name: string; amount: number }[]) => { if (value) { return this.bs.receivePayment( value as { id: number; name: string; amount: number }[], '', ); } return throwError('Cancelled'); }), ); } receivePayment() { if (!this.receivePaymentAllowed()) { return; } const amount = this.bs.amountVal(); const type = this.bs.type(); let obs: any; if (type === 'NO_CHARGE' || type === 'STAFF') { obs = this.receivePaymentWithReason(type, amount); } else { obs = this.receiveRegularPayment(type, amount); } obs.subscribe(() => { this.toaster.show('Success', ''); this.router.navigate(['/sales']); }); } moveTableAllowed(): boolean { // TODO: Check if this condition should be "and" or "or" if ( this.auth.user && this.auth.user.perms.indexOf('move-table') === -1 && this.auth.user.perms.indexOf('merge-tables') === -1 ) { return false; } if (!this.bs.bill.id) { return false; } return true; } moveTable() { if (!this.moveTableAllowed()) { return; } const canMergeTables = this.auth.user.perms.indexOf('merge-tables') !== -1; this.dialog .open(TablesDialogComponent, { // width: '750px', data: { list: this.tSer.running(), canChooseRunning: canMergeTables, }, }) .afterClosed() .pipe( switchMap((x: boolean | Table) => { if (x) { return this.confirmTableDialog(x as Table); } return throwError('Please choose a table'); }), // eslint-disable-next-line @typescript-eslint/no-unused-vars switchMap((value: { table: Table; confirmed: boolean }, index: number) => { if (!value.confirmed) { return throwError('Please confirm move'); } if (value.table.status) { return this.bs.mergeTable(value.table); } return this.bs.moveTable(value.table); }), ) .subscribe( () => { this.toaster.show('Success', ''); this.router.navigate(['/sales']); }, (x) => { this.toaster.show('Error', x); }, ); } voidBillAllowed(): boolean { if (this.auth.user && this.auth.user.perms.indexOf('void-bill') === -1) { return false; } if (!this.bs.bill.id) { return false; } return true; } voidBill() { if (!this.voidBillAllowed()) { return; } this.dialog .open(ReasonComponent, { // width: '750px' data: { title: 'Void Reason', reasons: [ 'Discount', 'Printing fault', 'Item changed', 'Quantity reduced', 'Costing bill for party', 'Cashier mistake', 'Management free sale', ], }, }) .afterClosed() .pipe( switchMap((x: boolean | string) => { if (x) { return this.confirmVoidDialog(x as string); } return throwError('Please choose a reason to void the bill'); }), switchMap((x: boolean | string) => { if (x) { return this.bs.voidBill(x as string); } return throwError('You chose not to void the bill'); }), ) .subscribe( () => { this.toaster.show('Success', ''); this.router.navigate(['/sales']); }, (x) => { this.toaster.show('Error', x); }, ); } splitBillAllowed(): boolean { if (this.auth.user && this.auth.user.perms.indexOf('split-bill') === -1) { return false; } if (!this.bs.bill.id) { return false; } return true; } splitBill() { if (!this.splitBillAllowed()) { return; } this.dialog .open(TablesDialogComponent, { // width: '750px', data: { list: this.tSer.running(), canChooseRunning: false, }, }) .afterClosed() .pipe( switchMap((x: boolean | Table) => { if (x) { return this.confirmTableDialog(x as Table); } return throwError('Please choose a table'); }), // eslint-disable-next-line @typescript-eslint/no-unused-vars switchMap((value: { table: Table; confirmed: boolean }, index: number) => { if (!value.confirmed) { return throwError('Please confirm split'); } return this.bs.splitBill(value.table); }), ) .subscribe( () => { this.toaster.show('Success', ''); this.router.navigate(['/sales']); }, (x) => { this.toaster.show('Error', x); }, ); } }