|
from reportlab.lib import colors |
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle |
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle |
|
from reportlab.lib.units import inch |
|
from io import BytesIO |
|
from datetime import datetime |
|
from typing import List |
|
|
|
def generate_bill_pdf(order, settings): |
|
""" |
|
Generate a PDF bill for a single order |
|
|
|
Args: |
|
order: The order object with all details |
|
settings: The hotel settings object |
|
|
|
Returns: |
|
BytesIO: A buffer containing the PDF data |
|
""" |
|
|
|
return generate_multi_order_bill_pdf([order], settings) |
|
|
|
def generate_multi_order_bill_pdf(orders: List, settings): |
|
""" |
|
Generate a PDF bill for multiple orders in a receipt-like format |
|
|
|
Args: |
|
orders: List of order objects with all details |
|
settings: The hotel settings object |
|
|
|
Returns: |
|
BytesIO: A buffer containing the PDF data |
|
""" |
|
buffer = BytesIO() |
|
|
|
doc = SimpleDocTemplate( |
|
buffer, |
|
pagesize=(4*inch, 11*inch), |
|
rightMargin=10, |
|
leftMargin=10, |
|
topMargin=10, |
|
bottomMargin=10 |
|
) |
|
|
|
|
|
styles = getSampleStyleSheet() |
|
styles.add(ParagraphStyle( |
|
name='HotelName', |
|
fontName='Helvetica-Bold', |
|
fontSize=14, |
|
alignment=1, |
|
spaceAfter=2 |
|
)) |
|
styles.add(ParagraphStyle( |
|
name='HotelTagline', |
|
fontName='Helvetica', |
|
fontSize=9, |
|
alignment=1, |
|
spaceAfter=2 |
|
)) |
|
styles.add(ParagraphStyle( |
|
name='HotelAddress', |
|
fontName='Helvetica', |
|
fontSize=8, |
|
alignment=1, |
|
spaceAfter=1 |
|
)) |
|
styles.add(ParagraphStyle( |
|
name='BillInfo', |
|
fontName='Helvetica', |
|
fontSize=8, |
|
alignment=0, |
|
spaceAfter=1 |
|
)) |
|
styles.add(ParagraphStyle( |
|
name='BillInfoRight', |
|
fontName='Helvetica', |
|
fontSize=8, |
|
alignment=2, |
|
spaceAfter=1 |
|
)) |
|
styles.add(ParagraphStyle( |
|
name='TableHeader', |
|
fontName='Helvetica-Bold', |
|
fontSize=8, |
|
alignment=0 |
|
)) |
|
styles.add(ParagraphStyle( |
|
name='ItemName', |
|
fontName='Helvetica', |
|
fontSize=8, |
|
alignment=0 |
|
)) |
|
styles.add(ParagraphStyle( |
|
name='ItemValue', |
|
fontName='Helvetica', |
|
fontSize=8, |
|
alignment=2 |
|
)) |
|
styles.add(ParagraphStyle( |
|
name='Total', |
|
fontName='Helvetica-Bold', |
|
fontSize=9, |
|
alignment=1 |
|
)) |
|
styles.add(ParagraphStyle( |
|
name='Footer', |
|
fontName='Helvetica', |
|
fontSize=7, |
|
alignment=1, |
|
textColor=colors.black |
|
)) |
|
|
|
|
|
elements = [] |
|
|
|
|
|
|
|
elements.append(Paragraph(settings.hotel_name.upper(), styles['HotelName'])) |
|
|
|
|
|
tagline = "AN AUTHENTIC CUISINE SINCE 2000" |
|
elements.append(Paragraph(tagline, styles['HotelTagline'])) |
|
|
|
|
|
if settings.address: |
|
elements.append(Paragraph(settings.address, styles['HotelAddress'])) |
|
|
|
|
|
if settings.contact_number: |
|
elements.append(Paragraph(f"Contact: {settings.contact_number}", styles['HotelAddress'])) |
|
|
|
|
|
if settings.tax_id: |
|
elements.append(Paragraph(f"GSTIN: {settings.tax_id}", styles['HotelAddress'])) |
|
|
|
|
|
elements.append(Paragraph("_" * 50, styles['HotelAddress'])) |
|
|
|
|
|
|
|
first_order = orders[0] |
|
|
|
|
|
|
|
customer_name = "" |
|
if hasattr(first_order, 'person_name') and first_order.person_name: |
|
customer_name = first_order.person_name |
|
|
|
bill_info_data = [ |
|
["Name:", customer_name], |
|
[f"Date: {datetime.now().strftime('%d/%m/%y')}", f"Dine In: {first_order.table_number}"], |
|
[f"{datetime.now().strftime('%H:%M')}", f"Bill No.: {first_order.id}"] |
|
] |
|
|
|
bill_info_table = Table(bill_info_data, colWidths=[doc.width/2-20, doc.width/2-20]) |
|
bill_info_table.setStyle(TableStyle([ |
|
('FONT', (0, 0), (-1, -1), 'Helvetica', 8), |
|
('ALIGN', (0, 0), (0, -1), 'LEFT'), |
|
('ALIGN', (1, 0), (1, -1), 'RIGHT'), |
|
('LINEBELOW', (0, 0), (1, 0), 0.5, colors.black), |
|
])) |
|
|
|
elements.append(bill_info_table) |
|
elements.append(Paragraph("_" * 50, styles['HotelAddress'])) |
|
|
|
|
|
items_header = [["Item", "Qty.", "Price", "Amount"]] |
|
items_header_table = Table(items_header, colWidths=[doc.width*0.4, doc.width*0.15, doc.width*0.2, doc.width*0.25]) |
|
items_header_table.setStyle(TableStyle([ |
|
('FONT', (0, 0), (-1, -1), 'Helvetica-Bold', 8), |
|
('ALIGN', (0, 0), (0, -1), 'LEFT'), |
|
('ALIGN', (1, 0), (-1, -1), 'RIGHT'), |
|
('LINEBELOW', (0, 0), (-1, 0), 0.5, colors.black), |
|
])) |
|
|
|
elements.append(items_header_table) |
|
|
|
|
|
total_items = 0 |
|
grand_total = 0 |
|
|
|
for order in orders: |
|
order_data = [] |
|
|
|
for item in order.items: |
|
dish_name = item.dish.name if item.dish else "Unknown Dish" |
|
price = item.dish.price if item.dish else 0 |
|
quantity = item.quantity |
|
total = price * quantity |
|
grand_total += total |
|
total_items += quantity |
|
|
|
order_data.append([ |
|
dish_name, |
|
str(quantity), |
|
f"{price:.2f}", |
|
f"{total:.2f}" |
|
]) |
|
|
|
|
|
if order_data: |
|
items_table = Table(order_data, colWidths=[doc.width*0.4, doc.width*0.15, doc.width*0.2, doc.width*0.25]) |
|
items_table.setStyle(TableStyle([ |
|
('FONT', (0, 0), (-1, -1), 'Helvetica', 8), |
|
('ALIGN', (0, 0), (0, -1), 'LEFT'), |
|
('ALIGN', (1, 0), (-1, -1), 'RIGHT'), |
|
])) |
|
|
|
elements.append(items_table) |
|
|
|
|
|
elements.append(Paragraph("_" * 50, styles['HotelAddress'])) |
|
|
|
|
|
|
|
tax_rate = 0.05 |
|
cgst = grand_total * tax_rate |
|
sgst = grand_total * tax_rate |
|
subtotal = grand_total - cgst - sgst |
|
|
|
totals_data = [ |
|
[f"Total Qty: {total_items}", f"Sub Total", f"{subtotal:.2f}"], |
|
["", f"CGST", f"{cgst:.2f}"], |
|
["", f"SGST", f"{sgst:.2f}"], |
|
] |
|
|
|
totals_table = Table(totals_data, colWidths=[doc.width*0.4, doc.width*0.35, doc.width*0.25]) |
|
totals_table.setStyle(TableStyle([ |
|
('FONT', (0, 0), (-1, -1), 'Helvetica', 8), |
|
('ALIGN', (0, 0), (0, -1), 'LEFT'), |
|
('ALIGN', (1, 0), (1, -1), 'RIGHT'), |
|
('ALIGN', (2, 0), (2, -1), 'RIGHT'), |
|
])) |
|
|
|
elements.append(totals_table) |
|
|
|
|
|
elements.append(Paragraph("_" * 50, styles['HotelAddress'])) |
|
elements.append(Paragraph(f"Grand Total ₹{grand_total:.2f}", styles['Total'])) |
|
elements.append(Paragraph("_" * 50, styles['HotelAddress'])) |
|
|
|
|
|
elements.append(Spacer(1, 5)) |
|
elements.append(Paragraph("FSSAI Lic No: 12018033000205", styles['Footer'])) |
|
elements.append(Paragraph("!!! Thank You !!! Visit Again !!!", styles['Footer'])) |
|
|
|
|
|
doc.build(elements) |
|
buffer.seek(0) |
|
|
|
return buffer |
|
|