diff --git a/barker/barker/routers/voucher/show.py b/barker/barker/routers/voucher/show.py index ec78825..1c45b9e 100644 --- a/barker/barker/routers/voucher/show.py +++ b/barker/barker/routers/voucher/show.py @@ -46,22 +46,34 @@ def from_bill( item: Voucher = db.query(Voucher) if re.compile(r"^\d{2,}-\d{4}$").match(id_): item = item.filter( - Voucher.bill_id == int(id_.replace("-", "")), - Voucher.voucher_type.in_([1, 3]), + Voucher.bill_id == int(id_.replace("-", "")), Voucher.voucher_type == VoucherType.REGULAR_BILL + ) + elif re.compile(r"^K-\d+$").match(id_): + item = item.filter( + Voucher.kot_id == int(id_.replace("K-", "")), + Voucher.voucher_type == VoucherType.KOT, ) elif re.compile(r"^NC-\d+$").match(id_): item = item.filter( Voucher.bill_id == int(id_.replace("NC-", "")), - Voucher.voucher_type == 2, + Voucher.voucher_type == VoucherType.NO_CHARGE, ) elif re.compile(r"^ST-\d+$").match(id_): item = item.filter( Voucher.bill_id == int(id_.replace("ST-", "")), - Voucher.voucher_type == 4, + Voucher.voucher_type == VoucherType.STAFF, + ) + else: + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Bill Number is invalid", ) item = item.first() if item is None: - return {} + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Bill not found", + ) return voucher_info(item, db) diff --git a/bookie/src/app/sales/bill-number/bill-number.component.css b/bookie/src/app/sales/bill-number/bill-number.component.css new file mode 100644 index 0000000..e69de29 diff --git a/bookie/src/app/sales/bill-number/bill-number.component.html b/bookie/src/app/sales/bill-number/bill-number.component.html new file mode 100644 index 0000000..9c56f7a --- /dev/null +++ b/bookie/src/app/sales/bill-number/bill-number.component.html @@ -0,0 +1,37 @@ + +
+
+ + + KOT + Regular Bill + Staff + No Charge + + + + Bill Number + + +
+
+
+ + + + diff --git a/bookie/src/app/sales/bill-number/bill-number.component.spec.ts b/bookie/src/app/sales/bill-number/bill-number.component.spec.ts new file mode 100644 index 0000000..9277e19 --- /dev/null +++ b/bookie/src/app/sales/bill-number/bill-number.component.spec.ts @@ -0,0 +1,26 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { BillNumberComponent } from './bill-number.component'; + +describe('QuantityComponent', () => { + let component: BillNumberComponent; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [BillNumberComponent], + }).compileComponents(); + }), + ); + + beforeEach(() => { + fixture = TestBed.createComponent(BillNumberComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/bookie/src/app/sales/bill-number/bill-number.component.ts b/bookie/src/app/sales/bill-number/bill-number.component.ts new file mode 100644 index 0000000..7fb082a --- /dev/null +++ b/bookie/src/app/sales/bill-number/bill-number.component.ts @@ -0,0 +1,54 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +@Component({ + selector: 'app-bill-number', + templateUrl: './bill-number.component.html', + styleUrls: ['./bill-number.component.css'], +}) +export class BillNumberComponent implements OnInit { + form: FormGroup; + + constructor(public dialogRef: MatDialogRef, private fb: FormBuilder) { + // Create form + this.form = this.fb.group({ + billType: '', + billNumber: '', + }); + } + + ngOnInit() { + this.form.setValue({ + billType: '1', + billNumber: '', + }); + } + + accept(): void { + const formValue = this.form.value; + const billNumber = parseInt(formValue.billNumber.replace('-', ''), 10); + if (isNaN(billNumber)) { + this.dialogRef.close(undefined); + } else { + let billId: string; + switch (formValue.billType) { + case '0': // KOT + billId = 'K-' + billNumber; + break; + case '1': // Regular Bill + billId = Math.floor(billNumber / 10000) + '-' + (billNumber % 10000); + break; + case '4': // Staff + billId = 'ST-' + billNumber; + break; + case '2': // No Charge + billId = 'NC-' + billNumber; + break; + default: + throw new Error('Unknown Bill Type'); + } + this.dialogRef.close(billId); + } + } +} diff --git a/bookie/src/app/sales/bill.service.ts b/bookie/src/app/sales/bill.service.ts index 3f64136..8999448 100644 --- a/bookie/src/app/sales/bill.service.ts +++ b/bookie/src/app/sales/bill.service.ts @@ -34,6 +34,7 @@ export class BillService { public amountVal: number; public selection = new SelectionModel(true, []); private amountBs: BehaviorSubject; + private updateTable: boolean; constructor( private dialog: MatDialog, @@ -47,6 +48,7 @@ export class BillService { this.taxAmount = new BehaviorSubject(0); this.amountBs = new BehaviorSubject(0); this.amountVal = 0; + this.updateTable = true; this.amount = this.amountBs.pipe(tap((x) => (this.amountVal = x))); } @@ -83,7 +85,8 @@ export class BillService { return view; } - loadData(bill: Bill): void { + loadData(bill: Bill, updateTable: boolean): void { + this.updateTable = updateTable; bill.kots.push(new Kot()); this.bill = bill; this.displayBill(); @@ -234,7 +237,7 @@ export class BillService { if (!this.happyHourItemsBalanced() || this.happyHourItemsMoreThanRegular()) { return throwError('Happy hour products are not balanced.'); } - return this.ser.saveOrUpdate(item, VoucherType.Kot, guestBookId, true); + return this.ser.saveOrUpdate(item, VoucherType.Kot, guestBookId, this.updateTable); } printBill(guest_book_id: string | null, voucherType: VoucherType): Observable { @@ -246,11 +249,16 @@ export class BillService { if (!this.happyHourItemsBalanced() || this.happyHourItemsMoreThanRegular()) { return throwError('Happy hour products are not balanced.'); } - return this.ser.saveOrUpdate(item, voucherType, guest_book_id, true); + return this.ser.saveOrUpdate(item, voucherType, guest_book_id, this.updateTable); } receivePayment(value: { choices: ReceivePaymentItem[]; reason: string }): Observable { - return this.ser.receivePayment(this.bill.id as string, value.choices, value.reason, true); + return this.ser.receivePayment( + this.bill.id as string, + value.choices, + value.reason, + this.updateTable, + ); } moveTable(table: Table): Observable { @@ -270,7 +278,7 @@ export class BillService { } voidBill(reason: string): Observable { - return this.ser.voidBill(this.bill.id as string, reason, true); + return this.ser.voidBill(this.bill.id as string, reason, this.updateTable); } updateAmounts() { @@ -327,7 +335,7 @@ export class BillService { 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); + return this.ser.splitBill(this.bill.id as string, inventoriesToMove, table, this.updateTable); } private happyHourItemsBalanced(): boolean { diff --git a/bookie/src/app/sales/bills/bill-resolver.service.ts b/bookie/src/app/sales/bills/bill-resolver.service.ts index 2c74933..add8a25 100644 --- a/bookie/src/app/sales/bills/bill-resolver.service.ts +++ b/bookie/src/app/sales/bills/bill-resolver.service.ts @@ -12,9 +12,16 @@ export class BillResolver implements Resolve { constructor(private ser: VoucherService) {} resolve(route: ActivatedRouteSnapshot): Observable { - const tableId = route.queryParamMap.get('table') as string; + const tableId = route.queryParamMap.get('table'); const guestId = route.queryParamMap.get('guest'); const voucherId = route.queryParamMap.get('voucher'); - return this.ser.getFromTable(tableId, voucherId, guestId); + const billId = route.queryParamMap.get('bill'); + if (billId !== null) { + return this.ser.getFromBill(billId); + } + if (tableId !== null) { + return this.ser.getFromTable(tableId as string, voucherId, guestId); + } + throw new Error('Unable to get bill'); } } diff --git a/bookie/src/app/sales/bills/bills.component.ts b/bookie/src/app/sales/bills/bills.component.ts index 58ecf81..59153fc 100644 --- a/bookie/src/app/sales/bills/bills.component.ts +++ b/bookie/src/app/sales/bills/bills.component.ts @@ -44,8 +44,8 @@ export class BillsComponent implements OnInit { ngOnInit() { this.route.data.subscribe((value) => { - const data = value as { item: Bill }; - this.bs.loadData(data.item); + const data = value as { item: Bill; updateTable: boolean }; + this.bs.loadData(data.item, data.updateTable); }); this.getPax(); this.dataSource = new BillsDataSource(this.bs.dataObs); diff --git a/bookie/src/app/sales/bills/update-table-resolver.service.ts b/bookie/src/app/sales/bills/update-table-resolver.service.ts new file mode 100644 index 0000000..71c15fe --- /dev/null +++ b/bookie/src/app/sales/bills/update-table-resolver.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; +import { Observable, of as observableOf } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class UpdateTableResolver implements Resolve { + constructor() {} + + resolve(route: ActivatedRouteSnapshot): Observable { + return route.queryParamMap.get('bill') !== null ? observableOf(false) : observableOf(true); + } +} diff --git a/bookie/src/app/sales/bills/voucher.service.ts b/bookie/src/app/sales/bills/voucher.service.ts index a6e7f9c..e2aa96a 100644 --- a/bookie/src/app/sales/bills/voucher.service.ts +++ b/bookie/src/app/sales/bills/voucher.service.ts @@ -50,6 +50,14 @@ export class VoucherService { ) as Observable; } + getFromBill(billId: string): Observable { + return this.http + .get(`${url}/from-bill/${billId}`) + .pipe( + catchError(this.log.handleError(serviceName, `getFromBill billId=${billId}`)), + ) as Observable; + } + save( voucher: Bill, voucherType: VoucherType, @@ -179,8 +187,8 @@ export class VoucherService { ) as Observable; } - splitBill(id: string, inventoriesToMove: string[], table: Table) { - const options = { params: new HttpParams().set('u', 'true') }; + splitBill(id: string, inventoriesToMove: string[], table: Table, updateTable: boolean) { + const options = { params: new HttpParams().set('u', updateTable.toString()) }; return this.http .post( `${urlSplitBill}/${id}`, diff --git a/bookie/src/app/sales/discount/discount.component.ts b/bookie/src/app/sales/discount/discount.component.ts index 5b6b157..418c11c 100644 --- a/bookie/src/app/sales/discount/discount.component.ts +++ b/bookie/src/app/sales/discount/discount.component.ts @@ -1,5 +1,5 @@ import { Component, Inject } from '@angular/core'; -import {FormArray, FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'; +import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { round } from 'mathjs'; import { Observable } from 'rxjs'; @@ -46,13 +46,12 @@ export class DiscountComponent { accept(): void { const array = this.form.get('discounts') as FormArray; - for (let i = this.list.length - 1; i >=0 ; i--) { + for (let i = this.list.length - 1; i >= 0; i--) { const item = this.list[i]; const control = (array.controls[i] as FormGroup).controls.discount as FormControl; if (control.pristine || control.value === null) { this.list.splice(i, 1); - } - else { + } else { item.discount = Math.max( Math.min(round(array.controls[i].value.discount / 100, 5), item.discountLimit), 0, diff --git a/bookie/src/app/sales/running-tables/running-tables.component.css b/bookie/src/app/sales/running-tables/running-tables.component.css index 9310616..f6825a1 100644 --- a/bookie/src/app/sales/running-tables/running-tables.component.css +++ b/bookie/src/app/sales/running-tables/running-tables.component.css @@ -8,6 +8,11 @@ color: #000000; } +.open-bill { + background-color: #8e44ad; + color: #000000; +} + .square-button { min-width: 150px; max-width: 150px; diff --git a/bookie/src/app/sales/running-tables/running-tables.component.html b/bookie/src/app/sales/running-tables/running-tables.component.html index 4f8d2e6..bbf77ed 100644 --- a/bookie/src/app/sales/running-tables/running-tables.component.html +++ b/bookie/src/app/sales/running-tables/running-tables.component.html @@ -19,5 +19,8 @@ {{ table.date }} {{ table.amount | currency: 'INR' }} + +

Open Bill

+
diff --git a/bookie/src/app/sales/running-tables/running-tables.component.ts b/bookie/src/app/sales/running-tables/running-tables.component.ts index 1572942..ad9b711 100644 --- a/bookie/src/app/sales/running-tables/running-tables.component.ts +++ b/bookie/src/app/sales/running-tables/running-tables.component.ts @@ -1,7 +1,11 @@ import { Component, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; +import { map } from 'rxjs/operators'; import { Table } from '../../core/table'; +import { ToasterService } from '../../core/toaster.service'; +import { BillNumberComponent } from '../bill-number/bill-number.component'; @Component({ selector: 'app-running-tables', @@ -11,7 +15,12 @@ import { Table } from '../../core/table'; export class RunningTablesComponent implements OnInit { list: Table[] = []; - constructor(private router: Router, private route: ActivatedRoute) {} + constructor( + private dialog: MatDialog, + private router: Router, + private route: ActivatedRoute, + private toaster: ToasterService, + ) {} ngOnInit() { this.route.data.subscribe((value) => { @@ -33,4 +42,22 @@ export class RunningTablesComponent implements OnInit { }; this.router.navigate(['/sales', 'bill'], navigationExtras); } + + openBill() { + return this.dialog + .open(BillNumberComponent) + .afterClosed() + .pipe( + map((x) => { + if (x === undefined || x === false) { + throw new Error('Invalid Bill Number'); + } + return x; + }), + ) + .subscribe( + (x) => this.router.navigate(['/sales', 'bill'], { queryParams: { bill: x } }), + (x) => this.toaster.show('Error', x), + ); + } } diff --git a/bookie/src/app/sales/sales-routing.module.ts b/bookie/src/app/sales/sales-routing.module.ts index 0d32322..e1e549a 100644 --- a/bookie/src/app/sales/sales-routing.module.ts +++ b/bookie/src/app/sales/sales-routing.module.ts @@ -5,6 +5,7 @@ import { AuthGuard } from '../auth/auth-guard.service'; import { BillResolver } from './bills/bill-resolver.service'; import { BillsComponent } from './bills/bills.component'; +import { UpdateTableResolver } from './bills/update-table-resolver.service'; import { SalesHomeComponent } from './home/sales-home.component'; import { MenuCategoriesResolver } from './menu-categories/menu-categories-resolver.service'; import { MenuCategoriesComponent } from './menu-categories/menu-categories.component'; @@ -46,6 +47,7 @@ const routes: Routes = [ }, resolve: { item: BillResolver, + updateTable: UpdateTableResolver, }, children: [ { diff --git a/bookie/src/app/sales/sales.module.ts b/bookie/src/app/sales/sales.module.ts index 8cd53df..006dace 100644 --- a/bookie/src/app/sales/sales.module.ts +++ b/bookie/src/app/sales/sales.module.ts @@ -8,17 +8,19 @@ import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatCardModule } from '@angular/material/card'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatChipsModule } from '@angular/material/chips'; -import { MatRippleModule } from '@angular/material/core'; +import { MatOptionModule, MatRippleModule } from '@angular/material/core'; import { MatDialogModule } from '@angular/material/dialog'; import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { MatTableModule } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; import { MatTooltipModule } from '@angular/material/tooltip'; import { SharedModule } from '../shared/shared.module'; +import { BillNumberComponent } from './bill-number/bill-number.component'; import { BillTypeComponent } from './bill-type/bill-type.component'; import { BillService } from './bill.service'; import { BillsComponent } from './bills/bills.component'; @@ -39,6 +41,7 @@ import { TablesDialogComponent } from './tables-dialog/tables-dialog.component'; providers: [BillService], declarations: [ BillsComponent, + BillNumberComponent, BillTypeComponent, DiscountComponent, MenuCategoriesComponent, @@ -64,6 +67,7 @@ import { TablesDialogComponent } from './tables-dialog/tables-dialog.component'; MatChipsModule, MatDialogModule, MatDividerModule, + MatOptionModule, MatIconModule, MatInputModule, MatRippleModule, @@ -72,6 +76,7 @@ import { TablesDialogComponent } from './tables-dialog/tables-dialog.component'; MatTooltipModule, SharedModule, SalesRoutingModule, + MatSelectModule, ], }) export class SalesModule {} diff --git a/bookie/src/app/sales/tables-dialog/tables-dialog.component.css b/bookie/src/app/sales/tables-dialog/tables-dialog.component.css index bfd69f5..cd69721 100644 --- a/bookie/src/app/sales/tables-dialog/tables-dialog.component.css +++ b/bookie/src/app/sales/tables-dialog/tables-dialog.component.css @@ -1,13 +1,11 @@ .running { - /* Red 900 */ - background-color: #b71c1c; - color: #ffffff; + background-color: #f8cbad; + color: #000000; } .printed { - /* Green 900 */ - background-color: #1b5e20; - color: #ffffff; + background-color: #c6e0b4; + color: #000000; } .square-button {