Added feature: Split bill by Sales Category if no item is selected.

This commit is contained in:
Amritanshu Agrawal 2020-12-25 11:47:03 +05:30
parent 6257313792
commit 41d4ef1200
7 changed files with 204 additions and 45 deletions

View File

@ -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<boolean> {
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<boolean> {
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 {

View File

@ -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<Table | boolean> {
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<boolean | string> {
confirmVoidDialog(reason: string): Observable<string | boolean> {
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<Table | undefined | null> {
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);
}
}

View File

@ -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,

View File

@ -0,0 +1,4 @@
.right {
display: flex;
justify-content: flex-end;
}

View File

@ -0,0 +1,23 @@
<h2 mat-dialog-title>Select Sale Categories</h2>
<mat-dialog-content>
<form [formGroup]="form" fxLayout="column">
<div formArrayName="saleCategories">
<div
fxLayout="row"
*ngFor="let sc of list; index as i"
[formGroupName]="i"
fxLayout="row"
fxLayoutAlign="space-around start"
fxLayout.lt-md="column"
fxLayoutGap="20px"
fxLayoutGap.lt-md="0px"
>
<mat-checkbox formControlName="saleCategory" fxFlex>{{ sc.name }}</mat-checkbox>
</div>
</div>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button [mat-dialog-close]="false">Cancel</button>
<button mat-button (click)="accept()" color="primary">Ok</button>
</mat-dialog-actions>

View File

@ -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<SplitBillComponent>;
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [SplitBillComponent],
}).compileComponents();
}),
);
beforeEach(() => {
fixture = TestBed.createComponent(SplitBillComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -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<SplitBillComponent>,
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);
}
}