Feature:
Print kot and print bill are working now using celery Now also need to install RabbitMQ for clery to work
This commit is contained in:
parent
aaac5efea2
commit
3f2a06c2cf
@ -205,7 +205,7 @@ def upgrade():
|
|||||||
sa.Column("menu_category_id", postgresql.UUID(), nullable=True),
|
sa.Column("menu_category_id", postgresql.UUID(), nullable=True),
|
||||||
sa.Column("section_id", postgresql.UUID(), nullable=False),
|
sa.Column("section_id", postgresql.UUID(), nullable=False),
|
||||||
sa.Column("printer_id", postgresql.UUID(), nullable=False),
|
sa.Column("printer_id", postgresql.UUID(), nullable=False),
|
||||||
sa.Column("copies", sa.Numeric(), nullable=False),
|
sa.Column("copies", sa.Integer(), nullable=False),
|
||||||
sa.ForeignKeyConstraint(
|
sa.ForeignKeyConstraint(
|
||||||
["menu_category_id"],
|
["menu_category_id"],
|
||||||
["menu_categories.id"],
|
["menu_categories.id"],
|
||||||
|
@ -1,78 +1,3 @@
|
|||||||
import re
|
from barker.printing.bill import print_bill # noqa: F401
|
||||||
import socket
|
from barker.printing.kot import print_kot # noqa: F401
|
||||||
import sys
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from sqlalchemy import or_
|
|
||||||
from sqlalchemy.orm import Session
|
|
||||||
|
|
||||||
from barker.models import SectionPrinter, Printer, Voucher
|
|
||||||
|
|
||||||
|
|
||||||
def sent_to_printer(data, address, cut_code):
|
|
||||||
print(data, address, cut_code)
|
|
||||||
try:
|
|
||||||
regex = re.compile(r'pdl://(?P<host>[\w\d.-]+):(?P<port>[\d]+)')
|
|
||||||
match = regex.match(address)
|
|
||||||
s = socket.socket()
|
|
||||||
s.connect((match.group("host"), int(match.group("port"))))
|
|
||||||
s.send(bytearray(data + cut_code, "ascii"))
|
|
||||||
except LookupError as e:
|
|
||||||
print("Lookup error:", e)
|
|
||||||
except:
|
|
||||||
print("Unexpected error:", sys.exc_info()[0])
|
|
||||||
finally:
|
|
||||||
s.close()
|
|
||||||
|
|
||||||
|
|
||||||
def design_kot(voucher, kot, items, copy_number):
|
|
||||||
s = (
|
|
||||||
f"KOT / BOT".center(42)
|
|
||||||
+ "\n\r" + f"Copy No. {copy_number}:".center(42)
|
|
||||||
+ "\n\r" + "".ljust(42, "-")
|
|
||||||
+ "\n\r" + f"KOT ID : K-{voucher.kot_id:>5}/S-{kot.code:>5} {kot.date:%d-%b-%Y %H:%M}"
|
|
||||||
+ "\n\r" + f"Table No.: {voucher.food_table.name}"
|
|
||||||
+ "\n\r" + "".ljust(42, "-")
|
|
||||||
+ "\n\r" + " Qty. x Name "
|
|
||||||
+ "\n\r" + "".ljust(42, "-")
|
|
||||||
)
|
|
||||||
for item in items:
|
|
||||||
name = (
|
|
||||||
"H H " + item.product.full_name
|
|
||||||
if item.is_happy_hour
|
|
||||||
else item.product.full_name
|
|
||||||
)
|
|
||||||
s += "\n\r" + f"{item.quantity:6.2} x {name:>33}"
|
|
||||||
for m in item.modifiers:
|
|
||||||
s += "\n\r" + f" --- {m.name:>32}"
|
|
||||||
s += "\n\r" + "".ljust(42, "-")
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
def print_kot(voucher_id: uuid.UUID, db: Session):
|
|
||||||
voucher: Voucher = db.query(Voucher).filter(Voucher.id == voucher_id).first()
|
|
||||||
my_hash = {}
|
|
||||||
kot = voucher.kots[-1]
|
|
||||||
for item in kot.inventories:
|
|
||||||
printer, copies = (
|
|
||||||
db.query(Printer, SectionPrinter.copies)
|
|
||||||
.join(SectionPrinter.printer)
|
|
||||||
.filter(SectionPrinter.section_id == voucher.food_table.section_id)
|
|
||||||
.filter(
|
|
||||||
or_(
|
|
||||||
SectionPrinter.menu_category_id == item.product.menu_category_id,
|
|
||||||
SectionPrinter.menu_category_id == None,
|
|
||||||
)
|
|
||||||
).order_by(SectionPrinter.menu_category_id)
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
key = (printer.id, copies)
|
|
||||||
if key not in my_hash:
|
|
||||||
my_hash[key] = (printer, [])
|
|
||||||
my_hash[key][1].append(item)
|
|
||||||
for key, value in my_hash.items():
|
|
||||||
printer_id, copies = key
|
|
||||||
printer, items = value
|
|
||||||
for c in range(int(copies)):
|
|
||||||
data = design_kot(voucher, kot, items, c)
|
|
||||||
sent_to_printer(data, printer.address, printer.cut_code)
|
|
||||||
|
97
barker/printing/bill.py
Normal file
97
barker/printing/bill.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import uuid
|
||||||
|
from decimal import Decimal
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from barker.models import SectionPrinter, Printer, Voucher, Inventory, DbSetting, VoucherType
|
||||||
|
from barker.worker import sent_to_printer
|
||||||
|
|
||||||
|
|
||||||
|
def print_bill(voucher_id: uuid.UUID, db: Session):
|
||||||
|
voucher: Voucher = db.query(Voucher).filter(Voucher.id == voucher_id).first()
|
||||||
|
|
||||||
|
printer = (
|
||||||
|
db.query(Printer)
|
||||||
|
.join(SectionPrinter.printer)
|
||||||
|
.filter(SectionPrinter.section_id == voucher.food_table.section_id)
|
||||||
|
.filter(SectionPrinter.menu_category_id == None)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
items_dict = {}
|
||||||
|
tax = {}
|
||||||
|
for i in [i for k in voucher.kots for i in k.inventories]:
|
||||||
|
key = (i.product_id, i.is_happy_hour, tuple(m.modifier_id for m in i.modifiers if m.modifier.show_in_bill))
|
||||||
|
if key in items_dict:
|
||||||
|
items_dict[key].quantity += i.quantity
|
||||||
|
else:
|
||||||
|
items_dict[key] = i
|
||||||
|
if i.tax_id in tax:
|
||||||
|
tax[i.tax_id] = (i.tax.name, tax[i.tax_id][1] + i.tax_amount)
|
||||||
|
else:
|
||||||
|
tax[i.tax_id] = (i.tax.name, i.tax_amount)
|
||||||
|
data = design_bill(voucher, items_dict.values(), tax.values(), db)
|
||||||
|
sent_to_printer.delay(data, printer.address, printer.cut_code)
|
||||||
|
|
||||||
|
|
||||||
|
def design_bill(voucher: Voucher, items: List[Tuple[Inventory, Decimal]], tax: List[Tuple[str, Decimal]], db: Session):
|
||||||
|
# Header
|
||||||
|
s = "\n\r" + db.query(DbSetting).filter(DbSetting.name == "Header").first().data['Text']
|
||||||
|
if voucher.voucher_type == VoucherType.REGULAR_BILL:
|
||||||
|
s += "\n\r" + "Retail Invoice".center(42)
|
||||||
|
s += "\n\r"
|
||||||
|
elif voucher.voucher_type == VoucherType.NO_CHARGE:
|
||||||
|
s += "\n\r" + "NO CHARGE - THIS IS NOT A BILL - DON'T PAY".center(42)
|
||||||
|
s += "\n\r"
|
||||||
|
elif voucher.voucher_type == VoucherType.STAFF:
|
||||||
|
s += "\n\r" + "STAFF CONSUMPTION -- THIS IS NOT A BILL".center(42)
|
||||||
|
s += "\n\r"
|
||||||
|
|
||||||
|
# Products
|
||||||
|
s += "\n\r" + f"Bill No: {voucher.full_bill_id:>12} {voucher.date:%d-%b-%Y %H:%M}"
|
||||||
|
s += "\n\r" + "Table No.: " + voucher.food_table.name
|
||||||
|
s += "\n\r" + "-" * 42
|
||||||
|
s += "\n\r" + "Qty. Particulars Price Amount"
|
||||||
|
s += "\n\r" + "-" * 42
|
||||||
|
for item in [i for i in items if i.quantity != 0]:
|
||||||
|
name = "H H " + item.product.full_name if item.is_happy_hour else item.product.full_name
|
||||||
|
s += "\n\r" + f"{item.quantity: >5.2f} {name:<22.22} {item.price: >6.2f} {item.price * item.quantity: >6.2f}"
|
||||||
|
for m in [m for m in item.modifiers if m.modifier.show_in_bill]:
|
||||||
|
s += f"\n\r -- {m.modifier.name: <38.38}"
|
||||||
|
s += "\n\r" + "------------------------------------------"
|
||||||
|
|
||||||
|
# Totals
|
||||||
|
amount = sum(i.quantity * i.price for i in items)
|
||||||
|
s += f"\n\r{'Subtotal :': >32} {amount: >9.2f}"
|
||||||
|
|
||||||
|
amount = sum(i.quantity * i.price for i in items if i.is_happy_hour)
|
||||||
|
if amount != 0:
|
||||||
|
s += f"\n\r{'Happy Hour Discount :': >32} {amount: >9.2f}"
|
||||||
|
|
||||||
|
amount = sum(i.quantity * i.effective_price * i.discount for i in items)
|
||||||
|
if amount != 0:
|
||||||
|
s += f"\n\r{'Discount :': >32} {amount: >9.2f}"
|
||||||
|
|
||||||
|
for t in tax:
|
||||||
|
if t[1] != 0:
|
||||||
|
s += f"\n\r{t[0]: >30} : {t[1]: >9.2f}"
|
||||||
|
|
||||||
|
s += f"\n\r{'Total Amount :',32} {round(voucher.amount): >9.2f}"
|
||||||
|
s += "\n\r" + "-" * 42
|
||||||
|
|
||||||
|
if voucher.voucher_type != VoucherType.REGULAR_BILL:
|
||||||
|
s += "\n\r" + "THIS IS NOT A BILL - DON'T PAY".center(42)
|
||||||
|
s += "\n\r" + "-" * 42
|
||||||
|
|
||||||
|
if voucher.narration:
|
||||||
|
s += f"\n\r{voucher.narration: ^42}"
|
||||||
|
s += "\n\r" + "-" * 42
|
||||||
|
|
||||||
|
if voucher.customer:
|
||||||
|
s += f"\n\r{voucher.customer.name}\n\r{voucher.customer.phone}\n\r{voucher.customer.address}"
|
||||||
|
s += "\n\r" + "-" * 42
|
||||||
|
|
||||||
|
s += "\n\r" + "Cashier : " + voucher.user.name
|
||||||
|
s += "\n\r" + db.query(DbSetting).filter(DbSetting.name == "Footer").first().data['Text']
|
||||||
|
return s
|
61
barker/printing/kot.py
Normal file
61
barker/printing/kot.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import uuid
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from sqlalchemy import or_
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from barker.models import SectionPrinter, Printer, Voucher, Kot, Inventory
|
||||||
|
from barker.worker import sent_to_printer
|
||||||
|
|
||||||
|
|
||||||
|
def design_kot(voucher: Voucher, kot: Kot, items: List[Inventory], copy_number: int) -> str:
|
||||||
|
s = (
|
||||||
|
f"KOT / BOT".center(42)
|
||||||
|
+ "\n\r" + f"Copy No. {copy_number}:".center(42)
|
||||||
|
+ "\n\r" + "".ljust(42, "-")
|
||||||
|
+ "\n\r" + f"KOT ID : K-{voucher.kot_id:>5}/S-{kot.code:>5} {kot.date:%d-%b-%Y %H:%M}"
|
||||||
|
+ "\n\r" + f"Table No.: {voucher.food_table.name}"
|
||||||
|
+ "\n\r" + "".ljust(42, "-")
|
||||||
|
+ "\n\r" + " Qty. x Name "
|
||||||
|
+ "\n\r" + "".ljust(42, "-")
|
||||||
|
)
|
||||||
|
for item in items:
|
||||||
|
name = (
|
||||||
|
"H H " + item.product.full_name
|
||||||
|
if item.is_happy_hour
|
||||||
|
else item.product.full_name
|
||||||
|
)
|
||||||
|
s += "\n\r" + f"{item.quantity:6.2} x {name:>33}"
|
||||||
|
for m in item.modifiers:
|
||||||
|
s += "\n\r" + f" --- {m.name:>32}"
|
||||||
|
s += "\n\r" + "".ljust(42, "-")
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def print_kot(voucher_id: uuid.UUID, db: Session):
|
||||||
|
voucher: Voucher = db.query(Voucher).filter(Voucher.id == voucher_id).first()
|
||||||
|
my_hash = {}
|
||||||
|
kot: Kot = voucher.kots[-1]
|
||||||
|
for item in kot.inventories:
|
||||||
|
printer, copies = (
|
||||||
|
db.query(Printer, SectionPrinter.copies)
|
||||||
|
.join(SectionPrinter.printer)
|
||||||
|
.filter(SectionPrinter.section_id == voucher.food_table.section_id)
|
||||||
|
.filter(
|
||||||
|
or_(
|
||||||
|
SectionPrinter.menu_category_id == item.product.menu_category_id,
|
||||||
|
SectionPrinter.menu_category_id == None,
|
||||||
|
)
|
||||||
|
).order_by(SectionPrinter.menu_category_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
key = (printer.id, copies)
|
||||||
|
if key not in my_hash:
|
||||||
|
my_hash[key] = (printer, [])
|
||||||
|
my_hash[key][1].append(item)
|
||||||
|
for key, value in my_hash.items():
|
||||||
|
printer_id, copies = key
|
||||||
|
printer, items = value
|
||||||
|
for c in range(int(copies)):
|
||||||
|
data = design_kot(voucher, kot, items, c)
|
||||||
|
sent_to_printer.delay(data, printer.address, printer.cut_code)
|
@ -59,6 +59,7 @@ def save(
|
|||||||
SectionPrinter.__table__.delete(
|
SectionPrinter.__table__.delete(
|
||||||
and_(
|
and_(
|
||||||
SectionPrinter.section_id == id_,
|
SectionPrinter.section_id == id_,
|
||||||
|
SectionPrinter.menu_category_id != None,
|
||||||
~SectionPrinter.menu_category_id.in_([x for x in current if x is not None]),
|
~SectionPrinter.menu_category_id.in_([x for x in current if x is not None]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -20,7 +20,7 @@ from ...routers.voucher import (
|
|||||||
check_permissions,
|
check_permissions,
|
||||||
get_guest_book,
|
get_guest_book,
|
||||||
)
|
)
|
||||||
from barker.printing import print_kot
|
from barker.printing import print_kot, print_bill
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@ -51,8 +51,9 @@ def save(
|
|||||||
if update_table:
|
if update_table:
|
||||||
do_update_table(item, guest_book, db)
|
do_update_table(item, guest_book, db)
|
||||||
db.commit()
|
db.commit()
|
||||||
# print_kot(item.id, db)
|
print_kot(item.id, db)
|
||||||
|
if item.voucher_type != VoucherType.KOT:
|
||||||
|
print_bill(item.id, db)
|
||||||
except SQLAlchemyError as e:
|
except SQLAlchemyError as e:
|
||||||
db.rollback()
|
db.rollback()
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
@ -7,6 +7,7 @@ from sqlalchemy import func
|
|||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from ...printing import print_kot, print_bill
|
||||||
from ...schemas.auth import UserToken
|
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
|
||||||
@ -48,6 +49,7 @@ def update(
|
|||||||
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)
|
||||||
|
need_to_print_kot = False
|
||||||
|
|
||||||
item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
|
item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
|
||||||
|
|
||||||
@ -76,6 +78,7 @@ def update(
|
|||||||
round(inv.discount, 5) for ko in data.kots for inv in ko.inventories if inv.id_ == i.id
|
round(inv.discount, 5) for ko in data.kots for inv in ko.inventories if inv.id_ == i.id
|
||||||
)
|
)
|
||||||
for k in (k for k in data.kots if k.id_ is None and len(k.inventories) > 0):
|
for k in (k for k in data.kots if k.id_ is None and len(k.inventories) > 0):
|
||||||
|
need_to_print_kot = True
|
||||||
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
|
code = db.query(func.coalesce(func.max(Kot.code), 0) + 1).scalar()
|
||||||
kot = Kot(item.id, code, item.food_table_id, now, item.user_id)
|
kot = Kot(item.id, code, item.food_table_id, now, item.user_id)
|
||||||
item.kots.append(kot)
|
item.kots.append(kot)
|
||||||
@ -104,6 +107,10 @@ def update(
|
|||||||
if update_table:
|
if update_table:
|
||||||
do_update_table(item, guest_book, db)
|
do_update_table(item, guest_book, db)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
if need_to_print_kot:
|
||||||
|
print_kot(item.id, db)
|
||||||
|
if item.voucher_type != VoucherType.KOT:
|
||||||
|
print_bill(item.id, db)
|
||||||
except SQLAlchemyError as e:
|
except SQLAlchemyError as e:
|
||||||
db.rollback()
|
db.rollback()
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
28
barker/worker.py
Normal file
28
barker/worker.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import re
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
from celery import Celery
|
||||||
|
from celery.utils.log import get_task_logger
|
||||||
|
|
||||||
|
# Create the celery app and get the logger
|
||||||
|
celery_app = Celery('tasks', broker='pyamqp://guest@localhost//')
|
||||||
|
logger = get_task_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@celery_app.task
|
||||||
|
def sent_to_printer(data: str, address: str, cut_code: str):
|
||||||
|
print(data, address, cut_code)
|
||||||
|
# try:
|
||||||
|
# regex = re.compile(r'pdl://(?P<host>[\w\d.-]+):(?P<port>[\d]+)')
|
||||||
|
# match = regex.match(address)
|
||||||
|
# s = socket.socket()
|
||||||
|
# s.connect((match.group("host"), int(match.group("port"))))
|
||||||
|
# s.send(bytearray(data + cut_code, "ascii"))
|
||||||
|
# except LookupError as e:
|
||||||
|
# print("Lookup error:", e)
|
||||||
|
# except:
|
||||||
|
# print("Unexpected error:", sys.exc_info()[0])
|
||||||
|
# finally:
|
||||||
|
# s.close()
|
||||||
|
|
||||||
|
# celery --app=barker.worker.celery_app worker -c 2 --loglevel=INFO
|
@ -7,7 +7,8 @@
|
|||||||
"build": "ng build",
|
"build": "ng build",
|
||||||
"test": "ng test",
|
"test": "ng test",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "ng e2e"
|
"e2e": "ng e2e",
|
||||||
|
"postinstall": "ngcc"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user