Change (Reprint bill)

Chore:
  Refactored save voucher so that the save function can be reused in change voucher route

Fix:
  Show voucher sent modifiers in a wrong format
  Inventory schema used rate instead of price
This commit is contained in:
2020-09-29 10:50:55 +05:30
parent f8778fee74
commit 046504e097
8 changed files with 204 additions and 132 deletions

View File

@ -26,7 +26,7 @@ from .routers.reports import (
sale_report, sale_report,
tax_report tax_report
) )
from .routers.voucher import show, save, update, receive_payment, void, merge_move, split from .routers.voucher import show, save, update, receive_payment, void, merge_move, split, change
from .db.base_class import Base from .db.base_class import Base
from .core.config import settings from .core.config import settings
@ -76,6 +76,7 @@ app.include_router(receive_payment.router, prefix="/api/voucher", tags=["voucher
app.include_router(void.router, prefix="/api/voucher", tags=["voucher"]) app.include_router(void.router, prefix="/api/voucher", tags=["voucher"])
app.include_router(merge_move.router, prefix="/api", tags=["voucher"]) app.include_router(merge_move.router, prefix="/api", tags=["voucher"])
app.include_router(split.router, prefix="/api", tags=["voucher"]) app.include_router(split.router, prefix="/api", tags=["voucher"])
app.include_router(change.router, prefix="/api/voucher", tags=["voucher"])
# app.include_router(issue_grid.router, prefix="/api/issue-grid", tags=["vouchers"]) # app.include_router(issue_grid.router, prefix="/api/issue-grid", tags=["vouchers"])
# app.include_router(batch.router, prefix="/api/batch", tags=["vouchers"]) # app.include_router(batch.router, prefix="/api/batch", tags=["vouchers"])

View File

@ -194,8 +194,8 @@ class Settlement(Base):
settle_option = relationship("SettleOption") settle_option = relationship("SettleOption")
def __init__(self, voucher_id=None, settled=None, amount=None, id=None): def __init__(self, voucher_id=None, settled=None, amount=None, id_=None):
self.id = id self.id = id_
self.voucher_id = voucher_id self.voucher_id = voucher_id
self.settled = settled self.settled = settled
self.amount = amount self.amount = amount
@ -211,8 +211,8 @@ class Reprint(Base):
user = relationship("User", backref="reprints") user = relationship("User", backref="reprints")
def __init__(self, voucher_id=None, user_id=None, id=None): def __init__(self, voucher_id=None, user_id=None, id_=None):
self.id = id self.id = id_
self.date = datetime.now() self.date = datetime.now()
self.voucher_id = voucher_id self.voucher_id = voucher_id
self.user_id = user_id self.user_id = user_id

View File

@ -1,42 +1,91 @@
# import uuid import uuid
# from decimal import Decimal
# import transaction from typing import Optional
# from pyramid.view import view_config
# from fastapi import APIRouter, HTTPException, status, Depends, Security
# from barker.models import Voucher, Overview from sqlalchemy.exc import SQLAlchemyError
# from barker.views.voucher.save import save from sqlalchemy.orm import Session
# from barker.views.voucher.show import voucher_info
# from .save import do_save
# from ...schemas.auth import UserToken
# @view_config( import barker.schemas.voucher as schemas
# request_method="POST", from ...core.security import get_current_active_user as get_user
# route_name="voucher_reprint", from ...db.session import SessionLocal
# renderer="json", from ...models import Voucher, SettleOption, Overview, Reprint
# permission="Edit Printed Bill", from ...routers.voucher import (
# trans=True, do_update_settlements,
# ) # Permission error get_guest_book,
# def voucher_change(request): )
# json = request.json_body from barker.schemas.receive_payment import ReceivePaymentItem as SettleSchema
# id_ = uuid.UUID(request.matchdict["id"])
# item = save(json, request.dbsession) router = APIRouter()
# old = request.dbsession.query(Voucher).filter(Voucher.id == id_).first()
# old.void = True
# old.void_reason = "Bill Discounted / Changed. New Bill ID is {0}".format( # Dependency
# item.full_bill_id def get_db():
# ) try:
# # TODO: Set the Void Settlement db = SessionLocal()
# yield db
# if old.status is None: finally:
# item.status = Overview( db.close()
# voucher_id=None, food_table_id=item.food_table_id, status="printed"
# )
# request.dbsession.add(item.status) @router.put("/change/{id_}")
# else: def change(
# request.dbsession.query(Overview).filter(Overview.voucher_id == old.id).update( id_: uuid.UUID,
# {Overview.voucher_id: item.id} data: schemas.VoucherIn,
# ) u: bool, # Update table?
# transaction.commit() g: Optional[uuid.UUID] = None, # Guest book id
# item = request.dbsession.query(Voucher).filter(Voucher.id == item.id).first() db: Session = Depends(get_db),
# return voucher_info(item) user: UserToken = Security(get_user),
# ):
# try:
old: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
amount_changed: bool = old.amount != round(
sum(
Decimal((0 if i.is_happy_hour else i.price) * i.quantity * (1 - i.discount) * (1 + i.tax_rate))
for k in data.kots
for i in k.inventories
),
2,
)
items_changed: bool = len([i for k in old.kots for i in k.inventories]) != len(
[i for k in data.kots for i in k.inventories]
)
if amount_changed or items_changed:
void_and_issue_new_bill(data, u, g, old, db, user)
else:
reprint_bill(id_, user.id_, db)
db.commit()
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
raise
def reprint_bill(voucher_id: uuid.UUID, user_id: uuid.UUID, db: Session):
item = Reprint(voucher_id=voucher_id, user_id=user_id)
db.add(item)
def void_and_issue_new_bill(
data: schemas.VoucherIn, u: bool, g: Optional[uuid.UUID], old: Voucher, db: Session, user: UserToken
):
update_table = u
guest_book = get_guest_book(g, db)
item = do_save(data, old.voucher_type, guest_book, db, user)
db.flush()
old.void = True
old.void_reason = f"Bill Discounted / Changed. New Bill ID is {item.full_bill_id}"
do_update_settlements(old, [SettleSchema(id=SettleOption.VOID(), amount=round(old.amount))], db)
if update_table:
if old.status is None:
item.status = Overview(voucher_id=None, food_table_id=item.food_table_id, status="printed")
db.add(item.status)
else:
db.query(Overview).filter(Overview.voucher_id == old.id).update({Overview.voucher_id: item.id})

View File

@ -11,7 +11,7 @@ from ...schemas.auth import UserToken
import barker.schemas.voucher as schemas import barker.schemas.voucher as schemas
from ...core.security import get_current_active_user as get_user from ...core.security import get_current_active_user as get_user
from ...db.session import SessionLocal from ...db.session import SessionLocal
from ...models import Voucher, VoucherType, Kot, Product, Inventory, InventoryModifier from ...models import Voucher, VoucherType, Kot, Product, Inventory, InventoryModifier, GuestBook
from ...routers.voucher import ( from ...routers.voucher import (
get_tax, get_tax,
do_update_settlements, do_update_settlements,
@ -43,58 +43,10 @@ def save(
user: UserToken = Security(get_user), user: UserToken = Security(get_user),
): ):
try: try:
now = datetime.now()
update_table = u update_table = u
voucher_type = VoucherType[p] voucher_type = VoucherType[p]
guest_book = get_guest_book(g, db) guest_book = get_guest_book(g, db)
item: Voucher = do_save(data, voucher_type, guest_book, db, user)
check_permissions(None, voucher_type, user.permissions)
bill_id = get_bill_id(voucher_type, db)
kot_id = db.query(func.coalesce(func.max(Voucher.kot_id), 0) + 1).scalar()
item = Voucher(
now,
guest_book.pax if guest_book is not None else data.pax,
bill_id,
kot_id,
data.table.id_,
data.customer.id_ if data.customer is not None else None,
voucher_type,
user.id_,
)
db.add(item)
for k in data.kots:
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
kot = Kot(item.id, code, item.food_table_id, item.date, item.user_id)
item.kots.append(kot)
db.add(kot)
for index, i in enumerate(k.inventories):
product = db.query(Product).filter(Product.id == i.product.id_).first()
tax_rate = get_tax(product.sale_category.tax.rate, voucher_type)
inv = Inventory(
kot.id,
product.id,
round(i.quantity, 2),
product.price,
round(i.discount, 5),
i.is_happy_hour,
product.sale_category.tax_id,
tax_rate,
index,
)
kot.inventories.append(inv)
db.add(inv)
for m in i.modifiers:
mod = InventoryModifier(None, m.id_, 0)
inv.modifiers.append(mod)
db.add(mod)
do_update_settlements(item, [], db)
if len(item.kots) == 0 or len(item.kots[0].inventories) == 0:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Please add some products",
)
if update_table: if update_table:
do_update_table(item, guest_book, db) do_update_table(item, guest_book, db)
db.commit() db.commit()
@ -106,3 +58,64 @@ def save(
except Exception: except Exception:
db.rollback() db.rollback()
raise raise
def do_save(
data: schemas.VoucherIn,
voucher_type: VoucherType,
guest_book: GuestBook,
db: Session,
user: UserToken,
):
now = datetime.now()
check_permissions(None, voucher_type, user.permissions)
bill_id = get_bill_id(voucher_type, db)
kot_id = db.query(func.coalesce(func.max(Voucher.kot_id), 0) + 1).scalar()
item = Voucher(
now,
guest_book.pax if guest_book is not None else data.pax,
bill_id,
kot_id,
data.table.id_,
data.customer.id_ if data.customer is not None else None,
voucher_type,
user.id_,
)
db.add(item)
for k in data.kots:
if not len(k.inventories):
continue
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
kot = Kot(item.id, code, item.food_table_id, item.date, item.user_id)
item.kots.append(kot)
db.add(kot)
for index, i in enumerate(k.inventories):
product = db.query(Product).filter(Product.id == i.product.id_).first()
tax_rate = get_tax(product.sale_category.tax.rate, voucher_type)
inv = Inventory(
kot.id,
product.id,
round(i.quantity, 2),
product.price,
round(i.discount, 5),
i.is_happy_hour,
product.sale_category.tax_id,
tax_rate,
index,
)
kot.inventories.append(inv)
db.add(inv)
for m in i.modifiers:
mod = InventoryModifier(None, m.id_, 0)
inv.modifiers.append(mod)
db.add(mod)
db.flush()
do_update_settlements(item, [], db)
if len(item.kots) == 0 or len(item.kots[0].inventories) == 0:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Please add some products",
)
return item

View File

@ -49,9 +49,9 @@ def from_bill(
@router.get("/from-table/{id_}") @router.get("/from-table/{id_}")
def from_bill( def from_bill(
id_: str, # Table ID id_: str, # table id
v: Optional[uuid.UUID] = None, # Voucher ID v: Optional[uuid.UUID] = None, # voucher id
g: Optional[uuid.UUID] = None, # Guest ID g: Optional[uuid.UUID] = None, # guest id
db: Session = Depends(get_db), db: Session = Depends(get_db),
user: UserToken = Security(get_user), user: UserToken = Security(get_user),
): ):
@ -116,16 +116,8 @@ def voucher_info(item: Voucher):
"taxRate": i.tax_rate, "taxRate": i.tax_rate,
"tax": {"id": i.tax_id, "name": i.tax.name}, "tax": {"id": i.tax_id, "name": i.tax.name},
"discount": i.discount, "discount": i.discount,
"inventoryModifier": [ "modifiers": [
{ {"id": m.modifier.id, "name": m.modifier.name, "price": m.price,} for m in i.modifiers
"modifier": {
"id": m.modifier.id,
"name": m.modifier.name,
"showInBill": m.modifier.show_in_bill,
},
"price": m.price,
}
for m in i.modifiers
], ],
} }
for i in k.inventories for i in k.inventories
@ -137,7 +129,7 @@ def voucher_info(item: Voucher):
} }
def voucher_blank(table, guest): def voucher_blank(table: FoodTable, guest: Optional[GuestBook]):
return { return {
"pax": table.seats if guest is None else guest.pax, "pax": table.seats if guest is None else guest.pax,
"table": {"id": table.id, "name": table.name}, "table": {"id": table.id, "name": table.name},

View File

@ -16,9 +16,9 @@ class Inventory(BaseModel):
id_: Optional[uuid.UUID] id_: Optional[uuid.UUID]
product: ProductLink product: ProductLink
quantity: Decimal = Field(ge=0, multiple_of=0.01) quantity: Decimal = Field(ge=0, multiple_of=0.01)
rate: Optional[Decimal] price: Optional[Decimal]
tax: Optional[TaxLink] tax: Optional[TaxLink]
taxRate: Optional[Decimal] tax_rate: Optional[Decimal]
discount: Decimal = Field(ge=0, multiple_of=0.00001, le=1) discount: Decimal = Field(ge=0, multiple_of=0.00001, le=1)
is_happy_hour: bool is_happy_hour: bool
modifiers: Optional[List[ModifierLink]] modifiers: Optional[List[ModifierLink]]

View File

@ -69,11 +69,24 @@ export class VoucherService {
); );
} }
change(voucher: Bill, printType: PrintType, guest_book_id: string, updateTable: boolean): Observable<boolean> {
const options = {params: new HttpParams().set('u', updateTable.toString())};
if (guest_book_id !== null) {
options.params = options.params.set('g', guest_book_id);
}
return <Observable<boolean>>this.http.put<boolean>(`${url}/change/${voucher.id}`, voucher, options)
.pipe(
catchError(this.log.handleError(serviceName, 'change'))
);
}
saveOrUpdate(voucher: Bill, printType: PrintType, guest_book_id: string, updateTable: boolean): Observable<boolean> { saveOrUpdate(voucher: Bill, printType: PrintType, guest_book_id: string, updateTable: boolean): Observable<boolean> {
if (!voucher.id) { if (!voucher.id) {
return this.save(voucher, printType, guest_book_id, updateTable); return this.save(voucher, printType, guest_book_id, updateTable);
} else { } else if (voucher.voucherType === PrintType.Kot) {
return this.update(voucher, printType, guest_book_id, updateTable); return this.update(voucher, printType, guest_book_id, updateTable);
} else {
return this.change(voucher, printType, guest_book_id, updateTable);
} }
} }

View File

@ -73,17 +73,18 @@ export class SalesHomeComponent implements OnInit {
} }
showDiscount(): Observable<boolean | { id: string, name: string, discount: number }[]> { showDiscount(): Observable<boolean | { id: string, name: string, discount: number }[]> {
const dialogRef = this.dialog.open(DiscountComponent, { if (this.discountAllowed()) {
// width: '750px', const dialogRef = this.dialog.open(DiscountComponent, {
data: this.mcSer.listForDiscount() // width: '750px',
}); data: this.mcSer.listForDiscount()
return dialogRef.afterClosed(); });
return dialogRef.afterClosed();
} else {
return observableOf(false);
}
} }
discount(): void { discount(): void {
if (!this.discountAllowed()) {
return;
}
this.showDiscount().subscribe((result: boolean | { id: string, name: string, discount: number }[]) => { this.showDiscount().subscribe((result: boolean | { id: string, name: string, discount: number }[]) => {
if (!!result) { if (!!result) {
this.bs.discount(result as { id: string, name: string, discount: number }[]); this.bs.discount(result as { id: string, name: string, discount: number }[]);
@ -92,13 +93,18 @@ export class SalesHomeComponent implements OnInit {
} }
billTypeDialog() { billTypeDialog() {
return this.dialog.open(BillTypeComponent).afterClosed().pipe( if (this.bs.bill.voucherType !== PrintType.Kot) {
tap(x => { return observableOf(this.bs.bill.voucherType);
if (!x) { } else {
throwError ('No Bill Type Chosen'); return this.dialog.open(BillTypeComponent).afterClosed().pipe(
} tap(x => {
}) if (!x) {
); throwError('No Bill Type Chosen');
}
})
);
}
} }
confirmTableDialog(table: Table): Observable<{table: Table, confirmed: boolean}> { confirmTableDialog(table: Table): Observable<{table: Table, confirmed: boolean}> {
@ -143,9 +149,7 @@ export class SalesHomeComponent implements OnInit {
if (this.route.snapshot.queryParamMap.has('guest')) { if (this.route.snapshot.queryParamMap.has('guest')) {
guestBookId = this.route.snapshot.queryParamMap.get('guest'); guestBookId = this.route.snapshot.queryParamMap.get('guest');
} }
const discountObservable: Observable<any> = (this.discountAllowed()) ? this.showDiscount() : observableOf(''); this.showDiscount().pipe(
discountObservable.pipe(
tap((result: boolean | { id: string, name: string, discount: number }[]) => { tap((result: boolean | { id: string, name: string, discount: number }[]) => {
if (!!result) { if (!!result) {
this.bs.discount(result as { id: string, name: string, discount: number }[]); this.bs.discount(result as { id: string, name: string, discount: number }[]);