diff --git a/barker/views/voucher/receive_payment.py b/barker/views/voucher/receive_payment.py index 6da82f0..74f5fe0 100644 --- a/barker/views/voucher/receive_payment.py +++ b/barker/views/voucher/receive_payment.py @@ -54,7 +54,6 @@ def receive_payment(request): Overview.voucher_id == item.id ).delete() transaction.commit() - item = request.dbsession.query(Voucher).filter(Voucher.id == item.id).first() - return voucher_info(item) + return True diff --git a/barker/views/voucher/void.py b/barker/views/voucher/void.py index fd20789..535533d 100644 --- a/barker/views/voucher/void.py +++ b/barker/views/voucher/void.py @@ -3,46 +3,55 @@ import uuid import transaction from pyramid.view import view_config -from barker.models import Voucher, SettleOption, Settlement -from barker.views.voucher import get_settlements -from barker.views.voucher.show import voucher_info +from barker.models import Voucher, SettleOption, Settlement, Overview @view_config( request_method="POST", - route_name="voucher_void", + route_name="v1_vouchers_id", renderer="json", + request_param="v", permission="Void Bill", trans=True, ) def void_voucher(request): - update_table = request.GET["u"] - json = request.json_body id_ = uuid.UUID(request.matchdict["id"]) + reason = request.GET["v"] + update_table = request.GET["u"] + item = request.dbsession.query(Voucher).filter(Voucher.id == id_).first() item.void = True - item.void_reason = json["Reason"] + item.void_reason = reason - amount = round(-1 * sum(i.amount for k in item.kots for i in k.inventories), 5) * -1 - s = Settlement(item.id, SettleOption.VOID(), amount) - item.settlements.append(s) - request.dbsession.add(s) - allowed = [ - SettleOption.AMOUNT(), - SettleOption.ROUND_OFF(), - SettleOption.UNSETTLED(), - SettleOption.VOID(), - ] - for i in (s for s in item.settlements if s.settled not in allowed): + settlements = [] + total_amount = item.amount + settlements.append({"id": SettleOption.AMOUNT(), "amount": -total_amount}) + round_off = round(total_amount) - total_amount + if round_off != 0: + settlements.append({"id": SettleOption.ROUND_OFF(), "amount": -round_off}) + settlements.append({"id": SettleOption.VOID(), "amount": round(total_amount)}) + + for i in settlements: + amount = i["amount"] + settlement_type_id = i["id"] + old = [s for s in item.settlements if s.settled == settlement_type_id] + if len(old) == 1: + old[0].amount = amount + else: + s = Settlement(item.id, settlement_type_id, amount) + item.settlements.append(s) + request.dbsession.add(s) + + for i in (i for i in item.settlements if i.settled not in [x["id"] for x in settlements]): item.settlements.remove(i) request.dbsession.delete(i) - get_settlements(item, request.dbsession) if update_table: - request.dbsession.delete(item.status) + request.dbsession.query(Overview).filter( + Overview.voucher_id == item.id + ).delete() transaction.commit() - item = request.dbsession.query(Voucher).filter(Voucher.id == item.id).first() - return voucher_info(item) + return True diff --git a/bookie/src/app/sales/bill.service.ts b/bookie/src/app/sales/bill.service.ts index 0564620..d7107de 100644 --- a/bookie/src/app/sales/bill.service.ts +++ b/bookie/src/app/sales/bill.service.ts @@ -12,6 +12,7 @@ import { VoucherService } from './bills/voucher.service'; import { ToasterService } from "../core/toaster.service"; import { tap } from "rxjs/operators"; import { Table } from "../core/table"; +import {observableToBeFn} from "rxjs/internal/testing/TestScheduler"; @Injectable() export class BillService { @@ -192,7 +193,7 @@ export class BillService { return this.bill.voucherType; } - receivePayment(amounts: { id: string; name: string; amount: number }[]) { + receivePayment(amounts: { id: string; name: string; amount: number }[]): Observable { return this.ser.receivePayment(this.bill.id, amounts, true).pipe( tap(x => console.log(x)) ); @@ -202,6 +203,10 @@ export class BillService { return this.ser.moveTable(this.bill.id, table); } + voidBill(reason: string): Observable { + return this.ser.voidBill(this.bill.id, reason, true); + } + netAmount() { return math.round(this.bill.kots.reduce( (ka: number, k: Kot) => ka + k.inventories.reduce( diff --git a/bookie/src/app/sales/bills/voucher.service.ts b/bookie/src/app/sales/bills/voucher.service.ts index 340ca0c..7e45cdf 100644 --- a/bookie/src/app/sales/bills/voucher.service.ts +++ b/bookie/src/app/sales/bills/voucher.service.ts @@ -5,6 +5,7 @@ import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { ErrorLoggerService } from '../../core/error-logger.service'; import { Bill, PrintType } from './bill'; import { Table } from "../../core/table"; +import {ObjectUnsubscribedError} from "rxjs"; const httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json'}) @@ -77,9 +78,9 @@ export class VoucherService { } } - receivePayment(id: string, amounts: { id: string; name: string; amount: number }[], updateTable: boolean): Observable { + receivePayment(id: string, amounts: { id: string; name: string; amount: number }[], updateTable: boolean): Observable { const options = {params: new HttpParams().set('r', "").set('u', updateTable.toString())}; - return >this.http.post(`${url}/${id}`, amounts, options) + return >this.http.post(`${url}/${id}`, amounts, options) .pipe( catchError(this.log.handleError(serviceName, 'receivePayment')) ); @@ -92,4 +93,12 @@ export class VoucherService { catchError(this.log.handleError(serviceName, 'moveTable')) ); } + + voidBill(id: string, reason: string, updateTable: boolean): Observable { + const options = {params: new HttpParams().set('v', reason).set('u', updateTable.toString())}; + return >this.http.post(`${url}/${id}`, {}, options) + .pipe( + catchError(this.log.handleError(serviceName, 'voidBill')) + ); + } } diff --git a/bookie/src/app/sales/home/sales-home.component.html b/bookie/src/app/sales/home/sales-home.component.html index 6aa99ad..56ef395 100644 --- a/bookie/src/app/sales/home/sales-home.component.html +++ b/bookie/src/app/sales/home/sales-home.component.html @@ -21,7 +21,7 @@

Move Table

- +

Void Bill

diff --git a/bookie/src/app/sales/home/sales-home.component.ts b/bookie/src/app/sales/home/sales-home.component.ts index 09d0214..3d72402 100644 --- a/bookie/src/app/sales/home/sales-home.component.ts +++ b/bookie/src/app/sales/home/sales-home.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from "@angular/router"; import { MatDialog } from "@angular/material"; import { concatMap, map, switchMap, tap } from "rxjs/operators"; -import { iif, Observable, of as observableOf, throwError} from "rxjs"; +import { iif, Observable, of as observableOf, throwError } from "rxjs"; import { BillService } from '../bill.service'; import { ToasterService } from "../../core/toaster.service"; import { DiscountComponent } from "../discount/discount.component"; @@ -15,6 +15,7 @@ import { TableService } from "../../tables/table.service"; import { Table } from "../../core/table"; import { TablesDialogComponent } from "../tables-dialog/tables-dialog.component"; import { ConfirmDialogComponent } from "../../shared/confirm-dialog/confirm-dialog.component"; +import { VoidReasonComponent } from "../void-reason/void-reason.component"; @Component({ selector: 'app-sales-home', @@ -97,6 +98,15 @@ export class SalesHomeComponent implements OnInit { ); } + 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) + ); + } + printBill() { const canGiveDiscount = this.auth.hasPermission("Discount"); let guestBookId = null; @@ -143,19 +153,18 @@ export class SalesHomeComponent implements OnInit { } moveTable() { - const dialogRef = this.dialog.open(TablesDialogComponent, { + this.dialog.open(TablesDialogComponent, { // width: '750px', data: { list: this.tSer.running(), canChooseRunning: false } - }); - dialogRef.afterClosed().pipe( + }).afterClosed().pipe( switchMap((x: boolean | Table) => { if (!!x) { - return this.confirmMoveTableDialog(x as Table) + return this.confirmMoveTableDialog(x as Table); } else { - return throwError("Please choose a table") + return throwError("Please choose a table"); } }), switchMap((value: { table: Table, confirmed: boolean }, index: number) => { @@ -176,6 +185,29 @@ export class SalesHomeComponent implements OnInit { } voidBill() { - + this.dialog.open(VoidReasonComponent, { + // width: '750px' + }).afterClosed().pipe( + switchMap((x: boolean | string) => { + if (!!x) { + return this.confirmVoidDialog(x as string); + } else { + return throwError("Please choose a reason to void the bill"); + } + }), + switchMap((x: boolean | string) => { + if (!!x) { + return this.bs.voidBill(x as string) + } else { + return throwError("You chose not to void the bill") + } + }) + ).subscribe((x) => { + this.toaster.show('Success', ''); + this.router.navigate(['/sales']); + }, + x => { + this.toaster.show('Error', x) + }) } } diff --git a/bookie/src/app/sales/modifiers/modifiers.component.css b/bookie/src/app/sales/modifiers/modifiers.component.css index add4d3a..0a3d256 100644 --- a/bookie/src/app/sales/modifiers/modifiers.component.css +++ b/bookie/src/app/sales/modifiers/modifiers.component.css @@ -5,3 +5,7 @@ cursor: pointer; margin: 20px; } + +.selected { + background-color: #dddddd; +} diff --git a/bookie/src/app/sales/modifiers/modifiers.component.html b/bookie/src/app/sales/modifiers/modifiers.component.html index c66e293..52fbf8e 100644 --- a/bookie/src/app/sales/modifiers/modifiers.component.html +++ b/bookie/src/app/sales/modifiers/modifiers.component.html @@ -7,11 +7,12 @@ {{item.minimum}} - {{item.maximum}} - - - {{m.name}} - - +
+ +

{{m.name}}

+
+
diff --git a/bookie/src/app/sales/products/products.component.css b/bookie/src/app/sales/products/products.component.css index fb099a5..ca1c92c 100644 --- a/bookie/src/app/sales/products/products.component.css +++ b/bookie/src/app/sales/products/products.component.css @@ -15,6 +15,11 @@ text-align: center; } -.warn { - background-color: red; +.yellow300 { + background-color: #fff176; +} + +.red700 { + background-color: #d32f2f; + color: #ffffff; } diff --git a/bookie/src/app/sales/products/products.component.html b/bookie/src/app/sales/products/products.component.html index ec08885..d6f7cf9 100644 --- a/bookie/src/app/sales/products/products.component.html +++ b/bookie/src/app/sales/products/products.component.html @@ -1,9 +1,9 @@ - +

{{item.name}}

-

Back

diff --git a/bookie/src/app/sales/sales.module.ts b/bookie/src/app/sales/sales.module.ts index 787f092..8f5c375 100644 --- a/bookie/src/app/sales/sales.module.ts +++ b/bookie/src/app/sales/sales.module.ts @@ -29,6 +29,7 @@ import { DiscountComponent } from "./discount/discount.component"; import { BillTypeComponent } from "./bill-type/bill-type.component"; import { ReceivePaymentComponent } from "./receive-payment/receive-payment.component"; import { TablesDialogComponent } from "./tables-dialog/tables-dialog.component"; +import { VoidReasonComponent } from "./void-reason/void-reason.component"; @NgModule({ providers: [ @@ -45,7 +46,8 @@ import { TablesDialogComponent } from "./tables-dialog/tables-dialog.component"; ReceivePaymentComponent, RunningTablesComponent, SalesHomeComponent, - TablesDialogComponent + TablesDialogComponent, + VoidReasonComponent ], imports: [ CommonModule, @@ -72,7 +74,8 @@ import { TablesDialogComponent } from "./tables-dialog/tables-dialog.component"; ModifiersComponent, QuantityComponent, ReceivePaymentComponent, - TablesDialogComponent + TablesDialogComponent, + VoidReasonComponent ] }) 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 0bd1e4c..4159064 100644 --- a/bookie/src/app/sales/tables-dialog/tables-dialog.component.css +++ b/bookie/src/app/sales/tables-dialog/tables-dialog.component.css @@ -22,6 +22,7 @@ .center { text-align: center; } + .selected { background-color: #dddddd; } diff --git a/bookie/src/app/sales/void-reason/void-reason-datasource.ts b/bookie/src/app/sales/void-reason/void-reason-datasource.ts new file mode 100644 index 0000000..78c61fd --- /dev/null +++ b/bookie/src/app/sales/void-reason/void-reason-datasource.ts @@ -0,0 +1,16 @@ +import { DataSource } from '@angular/cdk/collections'; +import { Observable, of as observableOf } from 'rxjs'; + +export class VoidReasonDatasource extends DataSource { + + constructor(private data: string[]) { + super(); + } + + connect(): Observable { + return observableOf(this.data); + } + + disconnect() { + } +} diff --git a/bookie/src/app/sales/void-reason/void-reason.component.css b/bookie/src/app/sales/void-reason/void-reason.component.css new file mode 100644 index 0000000..30a6f6d --- /dev/null +++ b/bookie/src/app/sales/void-reason/void-reason.component.css @@ -0,0 +1,3 @@ +.selected { + background-color: #dddddd; +} diff --git a/bookie/src/app/sales/void-reason/void-reason.component.html b/bookie/src/app/sales/void-reason/void-reason.component.html new file mode 100644 index 0000000..98d1d4e --- /dev/null +++ b/bookie/src/app/sales/void-reason/void-reason.component.html @@ -0,0 +1,16 @@ +

Reason

+ + + + + + {{row}} + + + + + + + + + diff --git a/bookie/src/app/sales/void-reason/void-reason.component.spec.ts b/bookie/src/app/sales/void-reason/void-reason.component.spec.ts new file mode 100644 index 0000000..009c74e --- /dev/null +++ b/bookie/src/app/sales/void-reason/void-reason.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { VoidReasonComponent } from './void-reason.component'; + +describe('VoidReasonComponent', () => { + let component: VoidReasonComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ VoidReasonComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(VoidReasonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/bookie/src/app/sales/void-reason/void-reason.component.ts b/bookie/src/app/sales/void-reason/void-reason.component.ts new file mode 100644 index 0000000..9f1842d --- /dev/null +++ b/bookie/src/app/sales/void-reason/void-reason.component.ts @@ -0,0 +1,38 @@ +import { Component } from '@angular/core'; +import { MatDialogRef } from '@angular/material'; +import { VoidReasonDatasource } from "./void-reason-datasource"; + +@Component({ + selector: 'app-void-reason', + templateUrl: './void-reason.component.html', + styleUrls: ['./void-reason.component.css'] +}) +export class VoidReasonComponent { + dataSource: VoidReasonDatasource; + selected: string; + reasons = [ + "Discount", + "Printing fault", + "Item changed", + "Quantity reduced", + "Costing bill for party", + "Cashier mistake", + "Management free sale", + "Other" + ]; + displayedColumns = ['reason']; + + constructor( + public dialogRef: MatDialogRef + ) { + this.dataSource = new VoidReasonDatasource(this.reasons); + } + + select(reason: string) { + this.selected = reason; + } + + accept(): void { + this.dialogRef.close(this.selected); + } +}