Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from reportlab.lib.pagesizes import A4 | |
| from reportlab.platypus import ( | |
| SimpleDocTemplate, Table, TableStyle, | |
| Paragraph, Spacer, Image | |
| ) | |
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle | |
| from reportlab.lib import colors | |
| from datetime import datetime | |
| import pandas as pd | |
| import os | |
| LOGO_PATH = "assets/logo.png" | |
| # ================= PDF ================= | |
| def generate_pdf(shetkari, sauda_date, entries, entity_type): | |
| # Change 1: Dynamic PDF filename based on shetkari name | |
| pdf_filename = f"{shetkari.replace(' ', '_')}_auction_confirmation_slip.pdf" | |
| doc = SimpleDocTemplate(pdf_filename, pagesize=A4) | |
| styles = getSampleStyleSheet() | |
| elements = [] | |
| title_style = ParagraphStyle( | |
| "title", | |
| fontSize=16, | |
| alignment=1, | |
| fontName="Helvetica-Bold" | |
| ) | |
| center_style = ParagraphStyle( | |
| "center", | |
| alignment=1 | |
| ) | |
| # ----- HEADER ----- | |
| logo = Image(LOGO_PATH, width=80, height=55) if os.path.exists(LOGO_PATH) else "" | |
| header_text = Paragraph( | |
| "<b>Shree Gajanan Cold Storage Pvt. Ltd.</b><br/><br/>" | |
| "<b>Ashirvad Trading Company</b><br/><br/>" | |
| "Tasgaon-Sangli Road, Kavthe Ekand, Sangli<br/><br/>" | |
| "Prasad Vijay Patil - [Contact : 9359533780]", | |
| ParagraphStyle("header", fontSize=16, alignment=1) | |
| ) | |
| header = Table([[logo, header_text]], colWidths=[90, 420]) | |
| header.setStyle(TableStyle([ | |
| ("VALIGN", (0, 0), (-1, -1), "MIDDLE") | |
| ])) | |
| elements.extend([header, Spacer(1, 12)]) | |
| elements.append(Paragraph("Auction Confirmation Slip", title_style)) | |
| elements.append(Spacer(1, 12)) | |
| # ----- SHETKARI/VENDOR ----- | |
| # Change 5: Dynamic label based on entity_type | |
| # Change 6: Increased font size to 14 (similar to Prasad Vijay Patil which is 16) | |
| entity_label = "Shetkari" if entity_type == "Shetkari" else "Vendor" | |
| shetkari_info = Paragraph( | |
| f"<b>{entity_label}:</b> <b>{shetkari}</b> " | |
| f"<b>Sauda Date:</b> {sauda_date}", | |
| ParagraphStyle("shetkari_style", fontSize=14) | |
| ) | |
| # Wrap in table to align with main table | |
| info_table = Table([[shetkari_info]], colWidths=[545]) | |
| elements.append(info_table) | |
| elements.append(Spacer(1, 10)) | |
| # ----- TABLE ----- | |
| table_data = [ | |
| ["Sr.", "Storage Name", "Lot No", "Quantity", "Rate", "Details"] | |
| ] | |
| total_qty = 0 | |
| for i, e in enumerate(entries, 1): | |
| total_qty += e["quantity"] | |
| table_data.append([ | |
| i, | |
| e["storage"], | |
| e["lot"].upper(), | |
| e["quantity"], | |
| Paragraph(f"<b>{e['rate']}</b>", center_style), | |
| e["details"] | |
| ]) | |
| table_data.append([ | |
| "", | |
| "", | |
| Paragraph("<b>Total</b>", center_style), | |
| Paragraph(f"<b>{total_qty}</b>", center_style), | |
| "", | |
| "" | |
| ]) | |
| table = Table( | |
| table_data, | |
| colWidths=[35, 120, 80, 60, 60, 190] | |
| ) | |
| table.setStyle(TableStyle([ | |
| ("GRID", (0, 0), (-1, -1), 1, colors.black), | |
| ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey), | |
| ("ALIGN", (0, 0), (-1, -1), "CENTER"), | |
| ("FONT", (0, 0), (-1, 0), "Helvetica-Bold"), | |
| ("TOPPADDING", (0, 0), (-1, -1), 6), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 6), | |
| ])) | |
| elements.append(table) | |
| doc.build(elements) | |
| return pdf_filename | |
| # ================= UX LOGIC ================= | |
| def add_entry(storage, lot, qty, rate, details, entries, prev_storage, prev_lot, prev_qty, prev_rate): | |
| # Change 2: Use previous storage if empty | |
| if not storage and prev_storage: | |
| storage = prev_storage | |
| # Change 2: Use previous values if empty for lot, qty, rate | |
| if not lot and prev_lot: | |
| lot = prev_lot | |
| if qty is None and prev_qty is not None: | |
| qty = prev_qty | |
| if rate is None and prev_rate is not None: | |
| rate = prev_rate | |
| entries.append({ | |
| "storage": storage, | |
| "lot": lot, | |
| "quantity": int(qty), | |
| "details": details, | |
| "rate": float(rate) | |
| }) | |
| df = create_display_dataframe(entries) | |
| # Change 2: Return empty/None values for lot, qty, rate to reset them | |
| # Return current values to be stored as "previous" | |
| return entries, storage, lot, qty, rate, df, "", None, None, "" | |
| def create_display_dataframe(entries): | |
| """Create dataframe with index column for selection""" | |
| if not entries: | |
| return pd.DataFrame(columns=["Select", "Storage", "Lot", "Quantity", "Rate", "Details"]) | |
| display_data = [] | |
| for i, e in enumerate(entries): | |
| display_data.append({ | |
| "Select": i, | |
| "Storage": e["storage"], | |
| "Lot": e["lot"], | |
| "Quantity": e["quantity"], | |
| "Rate": e["rate"], | |
| "Details": e["details"] | |
| }) | |
| return pd.DataFrame(display_data) | |
| def delete_entry(row_to_delete, entries): | |
| """Delete entry by row index""" | |
| if row_to_delete is None or row_to_delete < 0: | |
| return entries, create_display_dataframe(entries), None | |
| if row_to_delete < len(entries): | |
| entries.pop(row_to_delete) | |
| return entries, create_display_dataframe(entries), None | |
| def generate(shetkari, sauda_date, entries, entity_type): | |
| return generate_pdf(shetkari, sauda_date, entries, entity_type) | |
| # ================= UI ================= | |
| with gr.Blocks(title="Auction Confirmation Slip") as demo: | |
| gr.Markdown("## 🧾 Create New Auction Confirmation Slip") | |
| with gr.Row(): | |
| # Change 5: Added dropdown for entity type selection | |
| entity_type = gr.Dropdown( | |
| choices=["Shetkari", "Vendor"], | |
| value="Shetkari", | |
| label="Entity Type" | |
| ) | |
| shetkari = gr.Textbox(label="Shetkari/Vendor Name") | |
| sauda_date = gr.Textbox( | |
| label="Sauda Date", | |
| value=datetime.today().strftime("%d/%m/%Y") | |
| ) | |
| entries_state = gr.State([]) | |
| prev_storage = gr.State("") | |
| # Change 2: Added state variables for previous lot, qty, rate | |
| prev_lot = gr.State("") | |
| prev_qty = gr.State(None) | |
| prev_rate = gr.State(None) | |
| gr.Markdown("### ➕ Add Entry") | |
| with gr.Row(): | |
| storage = gr.Textbox(label="Storage Name (leave empty to reuse)") | |
| # Change 3: Added elem_id for JavaScript to enable caps lock | |
| lot = gr.Textbox(label="Lot Number", elem_id="lot_number_input") | |
| with gr.Row(): | |
| qty = gr.Number(label="Quantity", precision=0) | |
| rate = gr.Number(label="Rate") | |
| details = gr.Textbox( | |
| label="Details", | |
| lines=3, | |
| placeholder="Enter detailed description" | |
| ) | |
| add_btn = gr.Button("Add Entry") | |
| preview = gr.Dataframe( | |
| headers=["Select", "Storage", "Lot", "Quantity", "Rate", "Details"], | |
| interactive=False, | |
| row_count="dynamic", | |
| label="Entries Preview (Note the 'Select' index number)" | |
| ) | |
| gr.Markdown("### 🗑️ Delete Entry") | |
| with gr.Row(): | |
| delete_index = gr.Number( | |
| label="Enter row number to delete (from 'Select' column)", | |
| precision=0, | |
| minimum=0 | |
| ) | |
| delete_btn = gr.Button("Delete Entry") | |
| generate_btn = gr.Button("Confirm & Generate PDF") | |
| pdf_output = gr.File(label="Download PDF") | |
| # Change 2 & 3: Updated add_entry click handler | |
| add_btn.click( | |
| add_entry, | |
| inputs=[storage, lot, qty, rate, details, entries_state, prev_storage, prev_lot, prev_qty, prev_rate], | |
| outputs=[entries_state, prev_storage, prev_lot, prev_qty, prev_rate, preview, lot, qty, rate, details] | |
| ) | |
| delete_btn.click( | |
| delete_entry, | |
| inputs=[delete_index, entries_state], | |
| outputs=[entries_state, preview, delete_index] | |
| ) | |
| generate_btn.click( | |
| generate, | |
| inputs=[shetkari, sauda_date, entries_state, entity_type], | |
| outputs=pdf_output | |
| ) | |
| # Change 3: JavaScript to auto-capitalize lot number input | |
| demo.load(js=""" | |
| function() { | |
| const lotInput = document.getElementById('lot_number_input'); | |
| if (lotInput) { | |
| lotInput.addEventListener('input', function(e) { | |
| this.value = this.value.toUpperCase(); | |
| }); | |
| } | |
| } | |
| """) | |
| demo.launch() |