Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import pandas as pd | |
| import tempfile | |
| from fpdf import FPDF | |
| from datetime import datetime | |
| # In-memory database (dictionary) | |
| products_db = {} | |
| bill_items_db = [] | |
| def add_product(name, qty, price): | |
| if not name: | |
| return gr.update(), gr.update(choices=[]) | |
| try: | |
| qty = float(qty) if qty else 1.0 | |
| price = float(price) if price else 0.0 | |
| except Exception: | |
| qty = 1.0 | |
| price = 0.0 | |
| products_db[name] = {"qty": qty, "price": price} | |
| df = [[name, products_db[name]["qty"], products_db[name]["price"]] | |
| for name in products_db.keys()] | |
| choices = list(products_db.keys()) | |
| return gr.update(value=df), gr.update(choices=choices) | |
| def delete_product(name): | |
| if name and name in products_db: | |
| del products_db[name] | |
| df = [[name, products_db[name]["qty"], products_db[name]["price"]] | |
| for name in products_db.keys()] | |
| choices = list(products_db.keys()) | |
| return gr.update(value=df), gr.update(choices=choices, value=None) | |
| def add_to_bill(product_name, quantity): | |
| if not product_name or product_name not in products_db: | |
| # Return current bill items and empty preview | |
| df = [[item["name"], item["quantity"], item["unit_price"], item["total"]] | |
| for item in bill_items_db] | |
| return gr.update(value=df), "" | |
| try: | |
| quantity = float(quantity) if quantity else 0.0 | |
| except Exception: | |
| quantity = 0.0 | |
| if quantity <= 0: | |
| df = [[item["name"], item["quantity"], item["unit_price"], item["total"]] | |
| for item in bill_items_db] | |
| return gr.update(value=df), "" | |
| product = products_db[product_name] | |
| unit_price = product["price"] | |
| total = unit_price * quantity | |
| bill_items_db.append({ | |
| "name": product_name, | |
| "quantity": quantity, | |
| "unit_price": unit_price, | |
| "total": total | |
| }) | |
| df = [[item["name"], item["quantity"], item["unit_price"], item["total"]] | |
| for item in bill_items_db] | |
| preview = generate_bill_preview() | |
| return gr.update(value=df), preview | |
| def clear_bill(): | |
| bill_items_db.clear() | |
| return gr.update(value=[]), "" | |
| def generate_bill_preview(): | |
| if not bill_items_db: | |
| return "No items in bill" | |
| preview = "=" * 60 + "\n" | |
| preview += "BILL PREVIEW\n" | |
| preview += f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" | |
| preview += "=" * 60 + "\n\n" | |
| preview += f"{'Product':<20} {'Qty':>8} {'Unit Price':>12} {'Total':>12}\n" | |
| preview += "-" * 60 + "\n" | |
| grand_total = 0.0 | |
| for item in bill_items_db: | |
| preview += f"{item['name']:<20} {item['quantity']:>8.2f} {item['unit_price']:>12.2f} {item['total']:>12.2f}\n" | |
| grand_total += item['total'] | |
| preview += "-" * 60 + "\n" | |
| preview += f"{'GRAND TOTAL':<20} {' ':>8} {' ':>12} {grand_total:>12.2f}\n" | |
| preview += "=" * 60 + "\n" | |
| return preview | |
| def generate_bill_pdf(): | |
| """Generate PDF bill and return file path""" | |
| if not bill_items_db: | |
| return None | |
| pdf = FPDF() | |
| pdf.add_page() | |
| pdf.set_font("Arial", "B", 16) | |
| pdf.cell(0, 10, "INVOICE", ln=1, align='C') | |
| pdf.ln(5) | |
| pdf.set_font("Arial", "", 10) | |
| pdf.cell(0, 10, f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", ln=1) | |
| pdf.ln(5) | |
| pdf.set_font("Arial", "B", 11) | |
| pdf.cell(70, 10, "Product", 1, 0, 'L') | |
| pdf.cell(30, 10, "Qty", 1, 0, 'C') | |
| pdf.cell(40, 10, "Unit Price", 1, 0, 'R') | |
| pdf.cell(40, 10, "Total", 1, 1, 'R') | |
| pdf.set_font("Arial", "", 10) | |
| grand_total = 0.0 | |
| for item in bill_items_db: | |
| pdf.cell(70, 10, item['name'], 1, 0, 'L') | |
| pdf.cell(30, 10, f"{item['quantity']:.2f}", 1, 0, 'C') | |
| pdf.cell(40, 10, f"{item['unit_price']:.2f}", 1, 0, 'R') | |
| pdf.cell(40, 10, f"{item['total']:.2f}", 1, 1, 'R') | |
| grand_total += item['total'] | |
| pdf.set_font("Arial", "B", 11) | |
| pdf.cell(140, 10, "GRAND TOTAL", 1, 0, 'R') | |
| pdf.cell(40, 10, f"{grand_total:.2f}", 1, 1, 'R') | |
| tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") | |
| pdf.output(tmp.name) | |
| tmp.close() | |
| return tmp.name | |
| with gr.Blocks(title="Billing System - A Likitha") as demo: | |
| gr.Markdown("# π§Ύ Billing System - by A Likitha") | |
| gr.Markdown("Manage products and generate bills with ease autocalculated with pdf exports!") | |
| with gr.Tab("π¦ Products"): | |
| gr.Markdown("### Add/Update Products") | |
| gr.Markdown("Enter product details below. Quantity represents the base unit (e.g., 1 kg, 1 piece, etc.)") | |
| with gr.Row(): | |
| product_name = gr.Textbox(label="Product Name", placeholder="e.g., Idly, Sugar") | |
| product_qty = gr.Number(label="Quantity (Base Unit)", value=1, precision=0) | |
| product_price = gr.Number(label="Price per Unit", value=0, precision=2) | |
| add_product_btn = gr.Button("β Add/Update Product", variant="primary") | |
| gr.Markdown("### Product List") | |
| product_table = gr.Dataframe( | |
| headers=["Name", "Qty", "Price"], | |
| datatype=["str", "number", "number"], | |
| row_count=0, | |
| interactive=False, | |
| label="Current Products" | |
| ) | |
| gr.Markdown("### Delete Product") | |
| with gr.Row(): | |
| delete_dropdown = gr.Dropdown(choices=[], label="Select Product to Delete") | |
| delete_product_btn = gr.Button("ποΈ Delete Product", variant="stop") | |
| add_product_btn.click( | |
| fn=add_product, | |
| inputs=[product_name, product_qty, product_price], | |
| outputs=[product_table, delete_dropdown] | |
| ) | |
| delete_product_btn.click( | |
| fn=delete_product, | |
| inputs=[delete_dropdown], | |
| outputs=[product_table, delete_dropdown] | |
| ) | |
| with gr.Tab("π° Bills"): | |
| gr.Markdown("### Create New Bill") | |
| gr.Markdown("Select a product and enter the quantity to add to the bill") | |
| with gr.Row(): | |
| bill_product_dropdown = gr.Dropdown( | |
| choices=list(products_db.keys()), | |
| label="Select Product" | |
| ) | |
| bill_quantity = gr.Number(label="Quantity", value=1, precision=2) | |
| add_to_bill_btn = gr.Button("β Add to Bill", variant="primary") | |
| clear_bill_btn = gr.Button("ποΈ Clear Bill", variant="secondary") | |
| gr.Markdown("### Current Bill Items") | |
| bill_table = gr.Dataframe( | |
| headers=["Product", "Quantity", "Unit Price", "Total"], | |
| datatype=["str", "number", "number", "number"], | |
| row_count=0, | |
| interactive=False, | |
| label="Bill Items" | |
| ) | |
| gr.Markdown("### Bill Preview") | |
| bill_preview = gr.Textbox( | |
| label="Preview", | |
| lines=15, | |
| interactive=False, | |
| placeholder="Add items to see bill preview..." | |
| ) | |
| generate_pdf_btn = gr.Button("π Generate & Download PDF", variant="primary", size="lg") | |
| pdf_output = gr.File(label="Download Bill PDF") | |
| add_to_bill_btn.click( | |
| fn=add_to_bill, | |
| inputs=[bill_product_dropdown, bill_quantity], | |
| outputs=[bill_table, bill_preview] | |
| ) | |
| clear_bill_btn.click( | |
| fn=clear_bill, | |
| inputs=[], | |
| outputs=[bill_table, bill_preview] | |
| ) | |
| generate_pdf_btn.click( | |
| fn=generate_bill_pdf, | |
| inputs=[], | |
| outputs=[pdf_output] | |
| ) | |
| add_product_btn.click( | |
| fn=lambda: gr.update(choices=list(products_db.keys())), | |
| inputs=[], | |
| outputs=[bill_product_dropdown] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |