From 41d4ef1200926e9d500e95a51bc213ea73d72088 Mon Sep 17 00:00:00 2001 From: tanshu Date: Fri, 25 Dec 2020 11:47:03 +0530 Subject: [PATCH] Added feature: Split bill by Sales Category if no item is selected. --- bookie/src/app/sales/bill.service.ts | 22 ++- .../app/sales/home/sales-home.component.ts | 126 ++++++++++++------ bookie/src/app/sales/sales.module.ts | 2 + .../sales/split-bill/split-bill.component.css | 4 + .../split-bill/split-bill.component.html | 23 ++++ .../split-bill/split-bill.component.spec.ts | 26 ++++ .../sales/split-bill/split-bill.component.ts | 46 +++++++ 7 files changed, 204 insertions(+), 45 deletions(-) create mode 100644 bookie/src/app/sales/split-bill/split-bill.component.css create mode 100644 bookie/src/app/sales/split-bill/split-bill.component.html create mode 100644 bookie/src/app/sales/split-bill/split-bill.component.spec.ts create mode 100644 bookie/src/app/sales/split-bill/split-bill.component.ts diff --git a/bookie/src/app/sales/bill.service.ts b/bookie/src/app/sales/bill.service.ts index 8999448..3af4bce 100644 --- a/bookie/src/app/sales/bill.service.ts +++ b/bookie/src/app/sales/bill.service.ts @@ -89,6 +89,7 @@ export class BillService { this.updateTable = updateTable; bill.kots.push(new Kot()); this.bill = bill; + this.selection.clear(); this.displayBill(); } @@ -331,11 +332,22 @@ export class BillService { ); } - splitBill(table: Table): Observable { - const inventoriesToMove: string[] = this.selection.selected.map( - (x: string) => (JSON.parse(x) as BillSelectionItem).inventoryId as string, - ); - return this.ser.splitBill(this.bill.id as string, inventoriesToMove, table, this.updateTable); + splitBill(inventories: string[], table: Table): Observable { + return this.ser.splitBill(this.bill.id as string, inventories, table, this.updateTable); + } + + public getInventories(saleCategories: string[]): { move: string[]; keep: string[] } { + const data: { move: string[]; keep: string[] } = { move: [], keep: [] }; + for (const kot of this.bill.kots) { + for (const inv of kot.inventories) { + if (saleCategories.indexOf(inv.product.saleCategory?.id as string) === -1) { + data.keep.push(inv.id as string); + } else { + data.move.push(inv.id as string); + } + } + } + return data; } private happyHourItemsBalanced(): boolean { diff --git a/bookie/src/app/sales/home/sales-home.component.ts b/bookie/src/app/sales/home/sales-home.component.ts index 5d4cab3..c67f30c 100644 --- a/bookie/src/app/sales/home/sales-home.component.ts +++ b/bookie/src/app/sales/home/sales-home.component.ts @@ -13,10 +13,12 @@ import { ConfirmDialogComponent } from '../../shared/confirm-dialog/confirm-dial import { TableService } from '../../tables/table.service'; import { BillTypeComponent } from '../bill-type/bill-type.component'; import { BillService } from '../bill.service'; +import { BillSelectionItem } from '../bills/bill-selection-item'; import { VoucherType } from '../bills/voucher-type'; import { DiscountComponent } from '../discount/discount.component'; import { ReasonComponent } from '../reason/reason.component'; import { ReceivePaymentComponent } from '../receive-payment/receive-payment.component'; +import { SplitBillComponent } from '../split-bill/split-bill.component'; import { TablesDialogComponent } from '../tables-dialog/tables-dialog.component'; @Component({ @@ -100,17 +102,17 @@ export class SalesHomeComponent { return this.dialog.open(BillTypeComponent).afterClosed(); } - confirmTableDialog(table: Table): Observable<{ table: Table; confirmed: boolean }> { + confirmTableDialog(table: Table): Observable { return this.dialog .open(ConfirmDialogComponent, { width: '250px', data: { title: 'Select Table?', content: 'Are you sure?' }, }) .afterClosed() - .pipe(map((x: boolean) => ({ table, confirmed: x }))); + .pipe(map((x: boolean) => (x ? table : x))); } - confirmVoidDialog(reason: string): Observable { + confirmVoidDialog(reason: string): Observable { return this.dialog .open(ConfirmDialogComponent, { width: '250px', @@ -237,32 +239,22 @@ export class SalesHomeComponent { return; } const canMergeTables = this.auth.allowed('merge-tables'); - this.dialog - .open(TablesDialogComponent, { - // width: '750px', - data: { - list: this.tSer.running(), - canChooseRunning: canMergeTables, - }, - }) - .afterClosed() + this.showChooseTableDialog(canMergeTables) .pipe( - switchMap((x: boolean | Table) => { - if (x) { - return this.confirmTableDialog(x as Table); + tap((x) => { + if (!x) { + throw new Error('Please choose a table'); } - throw new Error('Please choose a table'); }), - // eslint-disable-next-line @typescript-eslint/no-unused-vars - switchMap((value: { table: Table; confirmed: boolean }, index: number) => { - if (!value.confirmed) { - throw new Error('Please confirm move'); + map((x) => x as Table), + switchMap((x: Table) => this.confirmTableDialog(x)), + tap((x) => { + if (!x) { + throw new Error('Move Table Cancelled'); } - if (value.table.status) { - return this.bs.mergeTable(value.table); - } - return this.bs.moveTable(value.table); }), + map((x) => x as Table), + switchMap((x: Table) => (x.status ? this.bs.mergeTable(x) : this.bs.moveTable(x))), ) .subscribe( () => { @@ -341,33 +333,56 @@ export class SalesHomeComponent { return true; } - splitBill() { - if (!this.splitBillAllowed()) { - return; - } - this.dialog + showBillSplitChoices(): Observable< + { id: string; name: string; selected: boolean }[] | undefined | false + > { + return this.dialog + .open(SplitBillComponent, { + data: this.mcSer + .list() + .pipe(map((x) => x.map((y) => ({ id: y.id, name: y.name, selected: false })))), + }) + .afterClosed(); + } + + showChooseTableDialog(canChooseRunning: boolean): Observable
{ + return this.dialog .open(TablesDialogComponent, { // width: '750px', data: { list: this.tSer.running(), - canChooseRunning: false, + canChooseRunning, }, }) - .afterClosed() + .afterClosed(); + } + + splitBill() { + if (!this.splitBillAllowed()) { + return; + } + const obs = this.bs.selection.isEmpty() + ? this.splitBillWithChoice() + : this.splitBillWithSelection(); + let inventories: string[]; + obs .pipe( - switchMap((x: boolean | Table) => { - if (x) { - return this.confirmTableDialog(x as Table); + tap((x) => (inventories = x)), + switchMap((x) => this.showChooseTableDialog(false)), + tap((x) => { + if (!x) { + throw new Error('Please choose a table'); } - throw new Error('Please choose a table'); }), - // eslint-disable-next-line @typescript-eslint/no-unused-vars - switchMap((value: { table: Table; confirmed: boolean }, index: number) => { - if (!value.confirmed) { - throw new Error('Please confirm split'); + map((x) => x as Table), + switchMap((x: Table) => this.confirmTableDialog(x)), + tap((x) => { + if (!x) { + throw new Error('Bill Split Cancelled'); } - return this.bs.splitBill(value.table); }), + map((x) => x as Table), + switchMap((x: Table) => this.bs.splitBill(inventories, x)), ) .subscribe( () => { @@ -379,4 +394,35 @@ export class SalesHomeComponent { }, ); } + + splitBillWithChoice() { + let inventories: string[]; + return this.showBillSplitChoices().pipe( + tap((x) => { + if (x === undefined || x === false) { + throw new Error('Cancelled'); + } + }), + map((x) => + (x as { id: string; name: string; selected: boolean }[]) + .filter((y) => y.selected) + .map((y) => y.id), + ), + tap((x: string[]) => { + const sel = this.bs.getInventories(x); + if (sel.keep.length === 0 || sel.move.length === 0) { + throw new Error('This will move either All or None of the items. Cancelled'); + } + inventories = sel.move; + }), + map((x) => inventories), + ); + } + + splitBillWithSelection() { + const inventories: string[] = this.bs.selection.selected.map( + (x: string) => (JSON.parse(x) as BillSelectionItem).inventoryId as string, + ); + return observableOf(inventories); + } } diff --git a/bookie/src/app/sales/sales.module.ts b/bookie/src/app/sales/sales.module.ts index 006dace..f934408 100644 --- a/bookie/src/app/sales/sales.module.ts +++ b/bookie/src/app/sales/sales.module.ts @@ -35,6 +35,7 @@ import { ReasonComponent } from './reason/reason.component'; import { ReceivePaymentComponent } from './receive-payment/receive-payment.component'; import { RunningTablesComponent } from './running-tables/running-tables.component'; import { SalesRoutingModule } from './sales-routing.module'; +import { SplitBillComponent } from './split-bill/split-bill.component'; import { TablesDialogComponent } from './tables-dialog/tables-dialog.component'; @NgModule({ @@ -51,6 +52,7 @@ import { TablesDialogComponent } from './tables-dialog/tables-dialog.component'; QuantityComponent, ReceivePaymentComponent, RunningTablesComponent, + SplitBillComponent, SalesHomeComponent, TablesDialogComponent, ReasonComponent, diff --git a/bookie/src/app/sales/split-bill/split-bill.component.css b/bookie/src/app/sales/split-bill/split-bill.component.css new file mode 100644 index 0000000..a9626b3 --- /dev/null +++ b/bookie/src/app/sales/split-bill/split-bill.component.css @@ -0,0 +1,4 @@ +.right { + display: flex; + justify-content: flex-end; +} diff --git a/bookie/src/app/sales/split-bill/split-bill.component.html b/bookie/src/app/sales/split-bill/split-bill.component.html new file mode 100644 index 0000000..5c80487 --- /dev/null +++ b/bookie/src/app/sales/split-bill/split-bill.component.html @@ -0,0 +1,23 @@ +

Select Sale Categories

+ +
+
+
+ {{ sc.name }} +
+
+ +
+ + + + diff --git a/bookie/src/app/sales/split-bill/split-bill.component.spec.ts b/bookie/src/app/sales/split-bill/split-bill.component.spec.ts new file mode 100644 index 0000000..c64a3e4 --- /dev/null +++ b/bookie/src/app/sales/split-bill/split-bill.component.spec.ts @@ -0,0 +1,26 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { SplitBillComponent } from './split-bill.component'; + +describe('SplitBillComponent', () => { + let component: SplitBillComponent; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [SplitBillComponent], + }).compileComponents(); + }), + ); + + beforeEach(() => { + fixture = TestBed.createComponent(SplitBillComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/bookie/src/app/sales/split-bill/split-bill.component.ts b/bookie/src/app/sales/split-bill/split-bill.component.ts new file mode 100644 index 0000000..71c58cc --- /dev/null +++ b/bookie/src/app/sales/split-bill/split-bill.component.ts @@ -0,0 +1,46 @@ +import { Component, Inject } from '@angular/core'; +import { FormArray, FormBuilder, FormGroup } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Observable } from 'rxjs'; + +@Component({ + selector: 'app-split-bill', + templateUrl: './split-bill.component.html', + styleUrls: ['./split-bill.component.css'], +}) +export class SplitBillComponent { + list: { id: string; name: string; selected: boolean }[] = []; + form: FormGroup; + + constructor( + public dialogRef: MatDialogRef, + private fb: FormBuilder, + @Inject(MAT_DIALOG_DATA) + public data: Observable<{ id: string; name: string; selected: boolean }[]>, + ) { + this.form = this.fb.group({ + saleCategories: this.fb.array([]), + }); + this.data.subscribe((list: { id: string; name: string; selected: boolean }[]) => { + this.list = list; + this.form.setControl( + 'saleCategories', + this.fb.array( + this.list.map((x) => + this.fb.group({ + saleCategory: x.selected, + }), + ), + ), + ); + }); + } + + accept(): void { + const array = this.form.get('saleCategories') as FormArray; + this.list.forEach((item, index) => { + item.selected = array.controls[index].value.saleCategory; + }); + this.dialogRef.close(this.list); + } +}