Renamed void_reason to reason so that we can store the employee name in case of Staff and NC reason in case of NC bills.

Settling NC and Staff bills now asks for Staff name / NC reason
This commit is contained in:
Amritanshu 2019-08-25 23:22:50 +05:30
parent 6d0f30503a
commit a12f093828
18 changed files with 171 additions and 97 deletions

View File

@ -16,7 +16,7 @@ call:copyQuery m-Sections "SELECT 'INSERT INTO sections(id, name) VALUES (''' +
call:copyQuery n-Printers "SELECT 'INSERT INTO printers(id, name, address, cut_code) VALUES (''' + CAST(NewID() AS Nvarchar(36)) + ''', ''' + Printer + ''', ''' + Printer + ''', ''' + CutCode + ''');' FROM Test.dbo.PrintLocations GROUP BY Printer, CutCode;"
call:copyQuery o-SectionPrinters "SELECT 'INSERT INTO section_printers(id, menu_category_id, section_id, printer_id, copies) VALUES (''' + CAST(PrintLocationID AS Nvarchar(36)) + ''', ' + COALESCE('''' + CAST(ProductGroupID AS Nvarchar(36)) + '''','null') + ', ' + '(select id from sections where name = ''' + Location + ''')' + ', ' + '(select id from printers where name = ''' + Printer + ''')' + ', ' + CAST(Copies AS nvarchar(36)) + ');' FROM Test.dbo.PrintLocations;"
call:copyQuery p-Vouchers "SELECT 'INSERT INTO vouchers(id, date, pax, user_id, creation_date, last_edit_date, bill_id, food_table_id, customer_id, narration, void_reason, voucher_type, kot_id) VALUES (''' + CAST(VoucherID AS Nvarchar(36)) + ''', ' + '''' + CONVERT(Nvarchar(36), Date, 126) + ''', ' + COALESCE(CAST(Pax AS Nvarchar(36)), 'null') + ', ''' + CAST(UserID AS Nvarchar(36)) + ''', ' + '''' + CONVERT(Nvarchar(36), CreationDate, 126) + ''', ' + '''' + CONVERT(Nvarchar(36), LastEditDate, 126) + ''', ' + COALESCE(CAST(BillID AS Nvarchar(36)), 'null') + ', ' + '''' + CAST(TableID AS Nvarchar(36)) + ''', ' + '''' + CAST(CustomerID AS Nvarchar(36)) + ''', ' + COALESCE('''' + REPLACE(Narration, '''', '''''') + '''', 'null') + ', ' + COALESCE('''' + REPLACE(VoidReason, '''', '''''') + '''', 'null') + ', ' + CASE WHEN Printed = 0 THEN '0' WHEN Void = 1 THEN '5' ELSE CAST(VoucherType AS Nvarchar(36)) END + ', ' + CAST(KotID AS Nvarchar(36)) + ');' FROM Test.dbo.Vouchers;"
call:copyQuery p-Vouchers "SELECT 'INSERT INTO vouchers(id, date, pax, user_id, creation_date, last_edit_date, bill_id, food_table_id, customer_id, narration, reason, voucher_type, kot_id) VALUES (''' + CAST(VoucherID AS Nvarchar(36)) + ''', ' + '''' + CONVERT(Nvarchar(36), Date, 126) + ''', ' + COALESCE(CAST(Pax AS Nvarchar(36)), 'null') + ', ''' + CAST(UserID AS Nvarchar(36)) + ''', ' + '''' + CONVERT(Nvarchar(36), CreationDate, 126) + ''', ' + '''' + CONVERT(Nvarchar(36), LastEditDate, 126) + ''', ' + COALESCE(CAST(BillID AS Nvarchar(36)), 'null') + ', ' + '''' + CAST(TableID AS Nvarchar(36)) + ''', ' + '''' + CAST(CustomerID AS Nvarchar(36)) + ''', ' + COALESCE('''' + REPLACE(Narration, '''', '''''') + '''', 'null') + ', ' + COALESCE('''' + REPLACE(VoidReason, '''', '''''') + '''', 'null') + ', ' + CASE WHEN Printed = 0 THEN '0' WHEN Void = 1 THEN '5' ELSE CAST(VoucherType AS Nvarchar(36)) END + ', ' + CAST(KotID AS Nvarchar(36)) + ');' FROM Test.dbo.Vouchers;"
call:copyQuery q-Kots "SELECT 'INSERT INTO kots(id, voucher_id, code, food_table_id, date, user_id) VALUES (''' + CAST(KotID AS Nvarchar(36)) + ''', ' + '''' + CAST(VoucherID AS Nvarchar(36)) + '''' + ', ' + CAST(Code AS Nvarchar(36)) + ', ' + '''' + CAST(TableID AS Nvarchar(36)) + '''' + ', ' + '''' + CONVERT(Nvarchar(36), Date, 126) + ''', ''' + CAST(UserID AS Nvarchar(36)) + ''');' FROM Test.dbo.Kots;"
call:copyQuery r-Inventories "SELECT 'INSERT INTO inventories(id, kot_id, product_id, sort_order, quantity, price, is_happy_hour, tax_rate, tax_id, discount) VALUES (''' + CAST(InventoryID AS Nvarchar(36)) + ''', ' + '''' + CAST(KotID AS Nvarchar(36)) + '''' + ', ' + '''' + CAST(ProductID AS Nvarchar(36)) + '''' + ', ' + CAST(SortOrder AS Nvarchar(36)) + ', ' + CAST(Quantity AS Nvarchar(36)) + ', ' + CAST(Price AS Nvarchar(36)) + ', ' + CASE WHEN IsHappyHour = 1 THEN 'true' ELSE 'false' END + ', ' + CAST(VatRate AS Nvarchar(36)) + ', ' + '''' + CAST(VatID AS Nvarchar(36)) + '''' + ', ' + CAST(Discount AS Nvarchar(36)) + ');' FROM Test.dbo.Inventories;"
call:copyQuery s-InventoryModifiers "SELECT 'INSERT INTO inventory_modifiers(id, inventory_id, modifier_id, price) VALUES (''' + CAST(InventoryModifierID AS Nvarchar(36)) + ''', ' + '''' + CAST(InventoryID AS Nvarchar(36)) + '''' + ', ' + '''' + CAST(ModifierID AS Nvarchar(36)) + '''' + ', 0);' FROM Test.dbo.InventoryModifiers;"

View File

@ -114,7 +114,7 @@ class Voucher(Base):
)
customer_id = Column("customer_id", GUID(), ForeignKey("customers.id"))
narration = Column("narration", Unicode(1000), nullable=False)
void_reason = Column("void_reason", Unicode(255))
reason = Column("reason", Unicode(255))
_voucher_type = Column("voucher_type", Integer, nullable=False)
user_id = Column("user_id", GUID(), ForeignKey("users.id"), nullable=False)
@ -170,7 +170,6 @@ class Voucher(Base):
self.food_table_id = food_table_id
self.customer_id = customer_id
self.narration = ""
self.void_reason = None
self.voucher_type = voucher_type
self.user_id = user_id

View File

@ -60,7 +60,7 @@ def check_permissions(item, voucher_type, permissions):
if item.voucher_type == VoucherType.VOID:
raise ValidationFailure(
"This Bill is already void.\nReason: {0}".format(item.void_reason)
"This Bill is already void.\nReason: {0}".format(item.reason)
)

View File

@ -4,7 +4,7 @@ from decimal import Decimal
import transaction
from pyramid.view import view_config
from barker.models import SettleOption, Voucher, Settlement, Overview
from barker.models import SettleOption, Voucher, Settlement, Overview, VoucherType
from barker.models.validation_exception import ValidationError
@ -19,20 +19,30 @@ from barker.models.validation_exception import ValidationError
def receive_payment(request):
update_table = request.GET["u"]
json = request.json_body
for item in json:
amounts = [
j
for j in json["amounts"]
if j["amount"] != 0
and j["id"] not in [SettleOption.AMOUNT(), SettleOption.ROUND_OFF()]
]
for item in amounts:
item["amount"] = round(Decimal(item["amount"]), 0)
id_ = uuid.UUID(request.matchdict["id"])
item = request.dbsession.query(Voucher).filter(Voucher.id == id_).first()
if item.voucher_type in [VoucherType.NO_CHARGE, VoucherType.STAFF]:
item.reason = json["name"].strip().title()
total_amount = item.amount
json.append({"id": SettleOption.AMOUNT(), "amount": -total_amount})
amounts.append({"id": SettleOption.AMOUNT(), "amount": -total_amount})
round_off = round(total_amount) - total_amount
if round_off != 0:
json.append({"id": SettleOption.ROUND_OFF(), "amount": -round_off})
if sum([i["amount"] for i in json]) != 0:
amounts.append({"id": SettleOption.ROUND_OFF(), "amount": -round_off})
if sum([i["amount"] for i in amounts]) != 0:
raise ValidationError("Payment received is not equal to bill amount")
for i in (j for j in json if j["amount"] != 0):
for i in amounts:
amount = i["amount"]
settlement_type_id = i["id"]
old = [s for s in item.settlements if s.settled == settlement_type_id]
@ -43,7 +53,7 @@ def receive_payment(request):
item.settlements.append(s)
request.dbsession.add(s)
allowed = [a["id"] for a in json if a["amount"] != 0]
allowed = [a["id"] for a in amounts]
for i in (s for s in item.settlements if s.settled not in allowed):
item.settlements.remove(i)
request.dbsession.delete(i)
@ -54,5 +64,3 @@ def receive_payment(request):
).delete()
transaction.commit()
return True

View File

@ -98,7 +98,7 @@ def voucher_info(item):
"customer": {"id": item.customer_id, "name": item.customer.name} if item.customer is not None else {},
"settlements": [],
"narration": item.narration,
"voidReason": item.void_reason,
"reason": item.reason,
"voucherType": item.voucher_type.name,
"kotId": item.kot_id,
"kots": [

View File

@ -27,7 +27,7 @@ def split_voucher(request):
update_table = request.GET["u"] == "true"
item = request.dbsession.query(Voucher).filter(Voucher.id == id_).first()
item.void = True
item.void_reason = "Bill Split"
item.reason = "Bill Split"
do_void_settlements(item, request.dbsession)
if update_table:
request.dbsession.query(Overview).filter(

View File

@ -22,7 +22,7 @@ def void_voucher(request):
item = request.dbsession.query(Voucher).filter(Voucher.id == id_).first()
item.void = True
item.void_reason = reason
item.reason = reason
item.voucher_type = VoucherType.VOID
do_void_settlements(item, request.dbsession)

View File

@ -206,8 +206,8 @@ export class BillService {
return this.bill.voucherType;
}
receivePayment(amounts: { id: string; name: string; amount: number }[]): Observable<boolean> {
return this.ser.receivePayment(this.bill.id, amounts, true);
receivePayment(amounts: { id: number; name: string; amount: number }[], name: string): Observable<boolean> {
return this.ser.receivePayment(this.bill.id, amounts, name, true);
}
moveTable(table: Table): Observable<boolean> {

View File

@ -79,10 +79,10 @@ export class VoucherService {
}
}
receivePayment(id: string, amounts: { id: string; name: string; amount: number }[], updateTable: boolean): Observable<boolean> {
receivePayment(id: string, amounts: { id: number; name: string; amount: number }[], name: string, updateTable: boolean): Observable<boolean> {
const options = {params: new HttpParams().set('receive-payment', '').set('u', updateTable.toString())};
return <Observable<boolean>>this.http.post<boolean>(
`${url}/${id}`, amounts, options
`${url}/${id}`, {name: name, amounts: amounts}, options
).pipe(
catchError(this.log.handleError(serviceName, 'receivePayment'))
);

View File

@ -15,7 +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';
import { ReasonComponent } from '../reason/reason.component';
@Component({
selector: 'app-sales-home',
@ -184,28 +184,71 @@ export class SalesHomeComponent implements OnInit {
return true;
}
receivePaymentWithReason(type:string, amount: number): Observable<boolean> {
const types = {
NO_CHARGE: [
{
id: 4,
name: 'No Charge',
amount: amount
}
],
STAFF: [
{
id: 10,
name: 'Staff Account',
amount: amount
}
]
};
return this.dialog.open(ReasonComponent, {
// width: '750px'
data: {title: (type === "NO_CHARGE") ? "NC for whom" : "Staff name"}
}).afterClosed().pipe(
switchMap((value: boolean | string) => {
if (!!value) {
return this.bs.receivePayment(types[type], value as string)
} else {
return throwError("Cancelled");
}
})
);
}
receiveRegularPayment (type: string, amount: number): Observable<boolean> {
return this.dialog.open(ReceivePaymentComponent, {
// width: '750px',
data: {
type: type,
amount: amount
}
}).afterClosed().pipe(
switchMap((value: boolean | {id: number, name: string, amount: number}[]) => {
if (!!value) {
return this.bs.receivePayment(value as { id: number, name: string, amount: number }[], '')
} else {
return throwError("Cancelled");
}
})
);
}
receivePayment() {
if (!this.receivePaymentAllowed()) {
return;
}
const amount = this.bs.amountVal();
const type = this.bs.type();
const dialogRef = this.dialog.open(ReceivePaymentComponent, {
// width: '750px',
data: {
type: type,
amount: amount
}
});
dialogRef.afterClosed().subscribe((result: boolean | { id: string, name: string, amount: number }[]) => {
if (!!result) {
this.bs.receivePayment(result as { id: string, name: string, amount: number }[]).subscribe(() => {
let obs: any;
if (type === 'NO_CHARGE' || type === 'STAFF') {
obs = this.receivePaymentWithReason(type, amount);
} else {
obs = this.receiveRegularPayment(type, amount);
}
obs.subscribe(() => {
this.toaster.show('Success', '');
this.router.navigate(['/sales']);
});
}
});
}
moveTableAllowed(): boolean {
if (!this.auth.hasPermission('Move Table') && !this.auth.hasPermission('Merge Tables')) {
@ -269,8 +312,20 @@ export class SalesHomeComponent implements OnInit {
if (!this.voidBillAllowed()) {
return;
}
this.dialog.open(VoidReasonComponent, {
this.dialog.open(ReasonComponent, {
// width: '750px'
data: {
title: 'Void Reason',
reasons: [
'Discount',
'Printing fault',
'Item changed',
'Quantity reduced',
'Costing bill for party',
'Cashier mistake',
'Management free sale',
]
}
}).afterClosed().pipe(
switchMap((x: boolean | string) => {
if (!!x) {

View File

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

View File

@ -0,0 +1,25 @@
<h2 mat-dialog-title>{{ title }}</h2>
<mat-dialog-content>
<form [formGroup]="form">
<mat-table [dataSource]="dataSource">
<!-- Reason Column -->
<ng-container matColumnDef="reason">
<mat-cell *matCellDef="let row" (click)="select(row)">{{row}}</mat-cell>
<mat-footer-cell *matFooterCellDef>
<mat-form-field fxFlex>
<mat-label>Reason</mat-label>
<input type="text" matInput #son placeholder="Reason" formControlName="son" autocomplete="off"
(focus)="select($event.target.value) && son.select()" (input)="select($event.target.value)">
</mat-form-field>
</mat-footer-cell>
</ng-container>
<mat-row *matRowDef="let row; columns: displayedColumns;" [class.selected]="row === selected"></mat-row>
<mat-footer-row *matFooterRowDef="displayedColumns"></mat-footer-row>
</mat-table>
</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" [disabled]="!selected">Ok</button>
</mat-dialog-actions>

View File

@ -1,20 +1,20 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { VoidReasonComponent } from './void-reason.component';
import { ReasonComponent } from './reason.component';
describe('VoidReasonComponent', () => {
let component: VoidReasonComponent;
let fixture: ComponentFixture<VoidReasonComponent>;
let component: ReasonComponent;
let fixture: ComponentFixture<ReasonComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ VoidReasonComponent ]
declarations: [ ReasonComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(VoidReasonComponent);
fixture = TestBed.createComponent(ReasonComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

View File

@ -0,0 +1,41 @@
import { Component, ElementRef, Inject, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { ReasonDatasource } from './reason-datasource';
import { FormBuilder, FormGroup } from "@angular/forms";
@Component({
selector: 'app-reason',
templateUrl: './reason.component.html',
styleUrls: ['./reason.component.css']
})
export class ReasonComponent {
@ViewChild('son', { static: true }) son: ElementRef;
form: FormGroup;
dataSource: ReasonDatasource;
title: string;
selected: string;
reasons: string[];
displayedColumns = ['reason'];
constructor(
public dialogRef: MatDialogRef<ReasonComponent>,
@Inject(MAT_DIALOG_DATA) private data:{ title: string, reasons: string[]},
private fb: FormBuilder
) {
this.reasons = data.reasons || [];
this.title = data.title;
this.form = this.fb.group({
son: ''
});
this.dataSource = new ReasonDatasource(this.reasons);
}
select(reason: string) {
this.selected = reason.trim();
return true;
}
accept(): void {
this.dialogRef.close(this.selected);
}
}

View File

@ -30,7 +30,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';
import { ReasonComponent } from './reason/reason.component';
@NgModule({
providers: [
@ -48,7 +48,7 @@ import { VoidReasonComponent } from './void-reason/void-reason.component';
RunningTablesComponent,
SalesHomeComponent,
TablesDialogComponent,
VoidReasonComponent
ReasonComponent
],
imports: [
CommonModule,
@ -78,7 +78,7 @@ import { VoidReasonComponent } from './void-reason/void-reason.component';
QuantityComponent,
ReceivePaymentComponent,
TablesDialogComponent,
VoidReasonComponent
ReasonComponent
]
})
export class SalesModule { }

View File

@ -1,16 +0,0 @@
<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

@ -1,38 +0,0 @@
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);
}
}