File size: 7,987 Bytes
80feb1b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
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
    """
    # Convert single order to list and use the multi-order function
    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()
    # Use a narrower page size to mimic a receipt
    doc = SimpleDocTemplate(
        buffer,
        pagesize=(4*inch, 11*inch),  # Typical receipt width
        rightMargin=10,
        leftMargin=10,
        topMargin=10,
        bottomMargin=10
    )

    # Create styles
    styles = getSampleStyleSheet()
    styles.add(ParagraphStyle(
        name='HotelName',
        fontName='Helvetica-Bold',
        fontSize=14,
        alignment=1,  # Center alignment
        spaceAfter=2
    ))
    styles.add(ParagraphStyle(
        name='HotelTagline',
        fontName='Helvetica',
        fontSize=9,
        alignment=1,  # Center alignment
        spaceAfter=2
    ))
    styles.add(ParagraphStyle(
        name='HotelAddress',
        fontName='Helvetica',
        fontSize=8,
        alignment=1,  # Center alignment
        spaceAfter=1
    ))
    styles.add(ParagraphStyle(
        name='BillInfo',
        fontName='Helvetica',
        fontSize=8,
        alignment=0,  # Left alignment
        spaceAfter=1
    ))
    styles.add(ParagraphStyle(
        name='BillInfoRight',
        fontName='Helvetica',
        fontSize=8,
        alignment=2,  # Right alignment
        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  # Right alignment
    ))
    styles.add(ParagraphStyle(
        name='Total',
        fontName='Helvetica-Bold',
        fontSize=9,
        alignment=1  # Center alignment
    ))
    styles.add(ParagraphStyle(
        name='Footer',
        fontName='Helvetica',
        fontSize=7,
        alignment=1,  # Center alignment
        textColor=colors.black
    ))

    # Create content elements
    elements = []

    # We're not using the logo in this receipt-style bill
    # Add hotel name and info
    elements.append(Paragraph(settings.hotel_name.upper(), styles['HotelName']))

    # Add tagline (if any, otherwise use a default)
    tagline = "AN AUTHENTIC CUISINE SINCE 2000"
    elements.append(Paragraph(tagline, styles['HotelTagline']))

    # Add address with formatting similar to the image
    if settings.address:
        elements.append(Paragraph(settings.address, styles['HotelAddress']))

    # Add contact info
    if settings.contact_number:
        elements.append(Paragraph(f"Contact: {settings.contact_number}", styles['HotelAddress']))

    # Add tax ID (GSTIN)
    if settings.tax_id:
        elements.append(Paragraph(f"GSTIN: {settings.tax_id}", styles['HotelAddress']))

    # Add a separator line
    elements.append(Paragraph("_" * 50, styles['HotelAddress']))

    # Add bill details in a more receipt-like format
    # Use the first order for common details
    first_order = orders[0]

    # Create a table for the bill header info
    # Get customer name if available
    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']))

    # Create header for items table
    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)

    # Add all order items
    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}"
            ])

        # Create the table for this order's items
        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)

    # Add a separator line
    elements.append(Paragraph("_" * 50, styles['HotelAddress']))

    # Add totals section
    # Calculate tax (assuming 5% CGST and 5% SGST like in the image)
    tax_rate = 0.05  # 5%
    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)

    # Add grand total with emphasis
    elements.append(Paragraph("_" * 50, styles['HotelAddress']))
    elements.append(Paragraph(f"Grand Total    ₹{grand_total:.2f}", styles['Total']))
    elements.append(Paragraph("_" * 50, styles['HotelAddress']))

    # Add license info and thank you message
    elements.append(Spacer(1, 5))
    elements.append(Paragraph("FSSAI Lic No: 12018033000205", styles['Footer']))
    elements.append(Paragraph("!!! Thank You !!! Visit Again !!!", styles['Footer']))

    # Build the PDF
    doc.build(elements)
    buffer.seek(0)

    return buffer