Added feature: Split bill by Sales Category if no item is selected.
This commit is contained in:
parent
6257313792
commit
41d4ef1200
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.right {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
|
@ -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>
|
|
@ -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();
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue