Void Bill Working

This commit is contained in:
Amritanshu 2019-08-10 18:49:05 +05:30
parent 2fcff26e34
commit 40a958a935
17 changed files with 212 additions and 46 deletions

View File

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

View File

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

View File

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

View File

@ -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<Bill> {
receivePayment(id: string, amounts: { id: string; name: string; amount: number }[], updateTable: boolean): Observable<boolean> {
const options = {params: new HttpParams().set('r', "").set('u', updateTable.toString())};
return <Observable<Bill>>this.http.post<Bill>(`${url}/${id}`, amounts, options)
return <Observable<boolean>>this.http.post<boolean>(`${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<boolean> {
const options = {params: new HttpParams().set('v', reason).set('u', updateTable.toString())};
return <Observable<boolean>>this.http.post<boolean>(`${url}/${id}`, {}, options)
.pipe(
catchError(this.log.handleError(serviceName, 'voidBill'))
);
}
}

View File

@ -21,7 +21,7 @@
<mat-card fxLayout="column" class="square-button" matRipple (click)="moveTable()">
<h3 class="item-name">Move Table</h3>
</mat-card>
<mat-card fxLayout="column" class="square-button" matRipple [routerLink]="['../../tables']">
<mat-card fxLayout="column" class="square-button" matRipple (click)="voidBill()">
<h3 class="item-name">Void Bill</h3>
</mat-card>
<mat-card fxLayout="column" class="square-button" matRipple [routerLink]="['../../tables']">

View File

@ -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<boolean | string> {
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)
})
}
}

View File

@ -5,3 +5,7 @@
cursor: pointer;
margin: 20px;
}
.selected {
background-color: #dddddd;
}

View File

@ -7,11 +7,12 @@
<mat-chip *ngIf="!!item.maximum">{{item.minimum}} - {{item.maximum}}</mat-chip>
</mat-chip-list>
</ng-template>
<mat-button-toggle-group multiple>
<mat-button-toggle mat-raised-button class="square-button" *ngFor="let m of item.modifiers" (click)="select(m)" [checked]="selectedIds.indexOf(m.id) !== -1">
{{m.name}}
</mat-button-toggle>
</mat-button-toggle-group>
<div fxLayout="row wrap" fxLayoutGap="grid 20px">
<mat-card fxLayout="column" class="square-button" matRipple *ngFor="let m of item.modifiers" (click)="select(m)"
[class.selected]="selectedIds.indexOf(m.id) !== -1">
<h3 class="item-name">{{m.name}}</h3>
</mat-card>
</div>
</mat-tab>
</mat-tab-group>
<mat-dialog-actions align="end">

View File

@ -15,6 +15,11 @@
text-align: center;
}
.warn {
background-color: red;
.yellow300 {
background-color: #fff176;
}
.red700 {
background-color: #d32f2f;
color: #ffffff;
}

View File

@ -1,9 +1,9 @@
<mat-card>
<mat-card-content fxLayout="row wrap" fxLayoutGap="grid 20px">
<mat-card fxLayout="column" class="square-button" matRipple *ngFor="let item of list" (click)="addProduct(item)">
<mat-card fxLayout="column" class="square-button" matRipple *ngFor="let item of list" (click)="addProduct(item)" [class.yellow300]="item.hasHappyHour">
<h3 class="item-name">{{item.name}}</h3>
</mat-card>
<mat-card fxLayout="column" class="square-button warn" matRipple [routerLink]="['../../menu-categories']"
<mat-card fxLayout="column" class="square-button red700" matRipple [routerLink]="['../../menu-categories']"
queryParamsHandling="preserve">
<h3 class="item-name">Back</h3>
</mat-card>

View File

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

View File

@ -22,6 +22,7 @@
.center {
text-align: center;
}
.selected {
background-color: #dddddd;
}

View File

@ -0,0 +1,16 @@
import { DataSource } from '@angular/cdk/collections';
import { Observable, of as observableOf } from 'rxjs';
export class VoidReasonDatasource extends DataSource<string> {
constructor(private data: string[]) {
super();
}
connect(): Observable<string[]> {
return observableOf(this.data);
}
disconnect() {
}
}

View File

@ -0,0 +1,3 @@
.selected {
background-color: #dddddd;
}

View File

@ -0,0 +1,16 @@
<h2 mat-dialog-title>Reason</h2>
<mat-dialog-content>
<mat-table [dataSource]="dataSource">
<!-- Name Column -->
<ng-container matColumnDef="reason">
<mat-cell *matCellDef="let row" (click)="select(row)">{{row}}</mat-cell>
</ng-container>
<mat-row *matRowDef="let row; columns: displayedColumns;" [class.selected]="row === selected"></mat-row>
</mat-table>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button [mat-dialog-close]="false">Cancel</button>
<button mat-button (click)="accept()" color="primary" [disabled]="!selected">Ok</button>
</mat-dialog-actions>

View File

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

View File

@ -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<VoidReasonComponent>
) {
this.dataSource = new VoidReasonDatasource(this.reasons);
}
select(reason: string) {
this.selected = reason;
}
accept(): void {
this.dialogRef.close(this.selected);
}
}