Deduplicated the settle options function for save/update/void/receive payment

Ported:
  Void
  Receive payment
This commit is contained in:
Amritanshu Agrawal 2020-09-24 08:47:09 +05:30
parent 6c06271315
commit 578385f866
11 changed files with 164 additions and 130 deletions

View File

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

View File

@ -1,4 +1,5 @@
import uuid
from typing import Optional, List
from fastapi import HTTPException
from sqlalchemy import func
@ -14,6 +15,8 @@ from barker.models import (
GuestBook,
)
from barker.schemas.receive_payment import ReceivePaymentItem as SettleSchema
def get_tax(tax, voucher_type):
if voucher_type in [VoucherType.STAFF, VoucherType.NO_CHARGE]:
@ -39,7 +42,7 @@ def get_bill_id(voucher_type, db):
return bill_id
def do_update_table(item, guest_book, db):
def do_update_table(item: Voucher, guest_book: Optional[GuestBook], db: Session):
status_ = "running" if item.voucher_type == VoucherType.KOT else "printed"
if item.status is None:
item.status = Overview(
@ -53,7 +56,7 @@ def do_update_table(item, guest_book, db):
item.status.status = status_
def check_permissions(item, voucher_type, permissions):
def check_permissions(item: Optional[Voucher], voucher_type: VoucherType, permissions: List[str]):
if voucher_type == VoucherType.KOT and "print-kot" not in permissions:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail="You are not allowed to print a kot",
@ -87,26 +90,31 @@ def get_guest_book(id_: uuid.UUID, db: Session):
return db.query(GuestBook).filter(GuestBook.id == id_).first()
def do_update_settlements(voucher, db: Session):
settlements = []
def do_update_settlements(voucher: Voucher, others: List[SettleSchema], db: Session):
settlements: List[SettleSchema] = []
settlements += others
total_amount = voucher.amount
settlements.append({"id": SettleOption.AMOUNT(), "amount": -total_amount})
settlements.append(SettleSchema(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.UNSETTLED(), "amount": round(total_amount)})
settlements.append(SettleSchema(id=SettleOption.ROUND_OFF(), amount=-round_off))
unsettled = sum(x.amount for x in settlements)
if len(others) and unsettled != 0: # This should not be allowed
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Payment received is not equal to bill amount",
)
if unsettled != 0:
settlements.append(SettleSchema(id=SettleOption.UNSETTLED(), amount=unsettled))
for i in settlements:
amount = i["amount"]
settlement_type_id = i["id"]
old = [s for s in voucher.settlements if s.settled == settlement_type_id]
old = [s for s in voucher.settlements if s.settled == i.id_]
if len(old) == 1:
old[0].amount = amount
old[0].amount = i.amount
else:
s = Settlement(voucher.id, settlement_type_id, amount)
s = Settlement(voucher.id, i.id_, i.amount)
voucher.settlements.append(s)
db.add(s)
for i in (i for i in voucher.settlements if i.settled not in [x["id"] for x in settlements]):
for i in (i for i in voucher.settlements if i.settled not in [x.id_ for x in settlements]):
voucher.settlements.remove(i)
db.delete(i)

View File

@ -1,63 +1,59 @@
import uuid
from decimal import Decimal
import transaction
from pyramid.view import view_config
from fastapi import APIRouter, HTTPException, status, Depends, Security
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from barker.models import SettleOption, Voucher, Settlement, Overview, VoucherType
from barker.models.validation_exception import ValidationError
from . import do_update_settlements
from ...schemas.auth import UserToken
import barker.schemas.receive_payment as schemas
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionLocal
from ...models import Voucher, VoucherType, SettleOption, Settlement, Overview
router = APIRouter()
@view_config(
request_method="POST",
route_name="v1_vouchers_id",
renderer="json",
request_param="receive-payment",
permission="Settle Bill",
trans=False,
)
def receive_payment(request):
update_table = request.GET["u"]
json = request.json_body
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()
# Dependency
def get_db():
try:
db = SessionLocal()
yield db
finally:
db.close()
if item.voucher_type in [VoucherType.NO_CHARGE, VoucherType.STAFF]:
item.reason = json["name"].strip().title()
total_amount = item.amount
amounts.append({"id": SettleOption.AMOUNT(), "amount": -total_amount})
round_off = round(total_amount) - total_amount
if round_off != 0:
amounts.append({"id": SettleOption.ROUND_OFF(), "amount": -round_off})
@router.post("/receive-payment/{id_}")
def update(
id_: uuid.UUID,
data: schemas.ReceivePayment,
u: bool, # Update table?
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["settle-bill"]),
):
try:
update_table = u
amounts = [
j for j in data.amounts if j.amount != 0 and j.id_ not in [SettleOption.AMOUNT(), SettleOption.ROUND_OFF()]
]
for i in amounts:
i.amount = round(i.amount, 0)
item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
if sum([i["amount"] for i in amounts]) != 0:
raise ValidationError("Payment received is not equal to bill amount")
if item.voucher_type in [VoucherType.NO_CHARGE, VoucherType.STAFF]:
item.reason = data.name.title()
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]
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)
do_update_settlements(item, amounts, db)
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)
if update_table:
request.dbsession.query(Overview).filter(Overview.voucher_id == item.id).delete()
transaction.commit()
return True
if update_table:
db.query(Overview).filter(Overview.voucher_id == item.id).delete()
db.commit()
return True
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
raise

View File

@ -1,6 +1,5 @@
import uuid
from datetime import datetime
from decimal import Decimal
from typing import Optional
from fastapi import APIRouter, HTTPException, status, Depends, Security
@ -90,7 +89,7 @@ def save(
mod = InventoryModifier(None, m.id_, 0)
inv.modifiers.append(mod)
db.add(mod)
do_update_settlements(item, db)
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",

View File

@ -142,6 +142,6 @@ def voucher_blank(table, guest):
"pax": table.seats if guest is None else guest.pax,
"table": {"id": table.id, "name": table.name},
"voucherType": VoucherType.KOT.name,
"customer": {"id": guest.customer_id, "name": guest.customer.name} if guest is not None else {},
"customer": {"id": guest.customer_id, "name": guest.customer.name} if guest is not None else None,
"kots": [],
}

View File

@ -1,6 +1,5 @@
import uuid
from datetime import datetime
from decimal import Decimal
from typing import Optional
from fastapi import APIRouter, HTTPException, status, Depends, Security
@ -96,7 +95,7 @@ def update(
mod = InventoryModifier(None, m.id_, 0)
inv.modifiers.append(mod)
db.add(mod)
do_update_settlements(item, db)
do_update_settlements(item, [], db)
if update_table:
do_update_table(item, guest_book, db)
db.commit()

View File

@ -1,58 +1,54 @@
import uuid
import transaction
from pyramid.view import view_config
from fastapi import APIRouter, HTTPException, status, Depends, Security
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from barker.models import Voucher, SettleOption, Settlement, Overview, VoucherType
from . import do_update_settlements
from ...schemas.auth import UserToken
from ...core.security import get_current_active_user as get_user
from ...db.session import SessionLocal
from ...models import Voucher, VoucherType, SettleOption, Overview
from barker.schemas.receive_payment import ReceivePaymentItem as SettleSchema
router = APIRouter()
@view_config(
request_method="POST",
route_name="v1_vouchers_id",
renderer="json",
request_param="void-bill",
permission="Void Bill",
trans=True,
)
def void_voucher(request):
id_ = uuid.UUID(request.matchdict["id"])
reason = request.json_body["reason"]
update_table = request.GET["u"] == "true"
item = request.dbsession.query(Voucher).filter(Voucher.id == id_).first()
item.void = True
item.reason = reason
item.voucher_type = VoucherType.VOID
do_void_settlements(item, request.dbsession)
if update_table:
request.dbsession.query(Overview).filter(Overview.voucher_id == item.id).delete()
transaction.commit()
return True
# Dependency
def get_db():
try:
db = SessionLocal()
yield db
finally:
db.close()
def do_void_settlements(item, dbsession):
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)})
@router.post("/void-bill/{id_}")
def update(
id_: uuid.UUID,
u: bool, # Update table?
reason: str,
db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["void-bill"]),
):
try:
item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
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)
dbsession.add(s)
item.void = True
item.reason = reason
item.voucher_type = VoucherType.VOID
for i in (i for i in item.settlements if i.settled not in [x["id"] for x in settlements]):
item.settlements.remove(i)
dbsession.delete(i)
do_update_settlements(item, [SettleSchema(id=SettleOption.VOID(), amount=round(item.amount))], db)
if u: # Update table
db.query(Overview).filter(Overview.voucher_id == item.id).delete()
db.commit()
return True
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
raise

View File

@ -0,0 +1,29 @@
import uuid
from typing import Optional, List
from decimal import Decimal
from pydantic import BaseModel, Field
from barker.schemas import to_camel
from barker.schemas.customer import CustomerLink
from barker.schemas.modifier import ModifierLink
from barker.schemas.product import ProductLink
from barker.schemas.table import TableLink
from barker.schemas.tax import TaxLink
class ReceivePaymentItem(BaseModel):
id_: int
amount: Decimal
class Config:
fields = {"id_": "id"}
class ReceivePayment(BaseModel):
name: str
amounts: List[ReceivePaymentItem]
class Config:
alias_generator = to_camel
anystr_strip_whitespace = True

View File

@ -26,7 +26,7 @@
</ng-container>
<ng-container matColumnDef="table-details">
<mat-header-cell *matHeaderCellDef class="deep-purple-50 bold right-align">{{ bs.bill.table.name }}
/ {{ bs.bill.pax }} / {{ bs.bill.customer.name }}</mat-header-cell>
/ {{ bs.bill.pax }} / {{ bs.bill.customer?.name }}</mat-header-cell>
</ng-container>
<!-- Checkbox Column -->

View File

@ -13,7 +13,7 @@ import { TablesDialogComponent } from '../tables-dialog/tables-dialog.component'
import { TableService } from '../../tables/table.service';
import { ToasterService } from '../../core/toaster.service';
import { AuthService } from '../../auth/auth.service';
import { PaxComponent } from "../pax/pax.component";
import { PaxComponent } from '../pax/pax.component';
@Component({
selector: 'app-bills',
@ -46,8 +46,8 @@ export class BillsComponent implements OnInit {
}
getPax(): void {
if (this.bs.bill.id || this.bs.bill.customer.id) {
return
if (this.bs.bill.id || this.bs.bill.customer) {
return;
}
const dialogRef = this.dialog.open(PaxComponent, {
// width: '750px',

View File

@ -76,19 +76,24 @@ export class VoucherService {
}
}
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())};
receivePayment(
id: string,
amounts: { id: number; name: string; amount: number }[],
name: string,
updateTable: boolean
): Observable<boolean> {
const options = {params: new HttpParams().set('u', updateTable.toString())};
return <Observable<boolean>>this.http.post<boolean>(
`${url}/${id}`, {name: name, amounts: amounts}, options
`${url}/receive-payment/${id}`, {name: name, amounts: amounts}, options
).pipe(
catchError(this.log.handleError(serviceName, 'receivePayment'))
);
}
voidBill(id: string, reason: string, updateTable: boolean): Observable<boolean> {
const options = {params: new HttpParams().set('void-bill', '').set('u', updateTable.toString())};
const options = {params: new HttpParams().set('reason', reason).set('u', updateTable.toString())};
return <Observable<boolean>>this.http.post<boolean>(
`${url}/${id}`, {reason: reason}, options
`${url}/void-bill/${id}`, {}, options
).pipe(
catchError(this.log.handleError(serviceName, 'voidBill'))
);