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( "Shree Gajanan Cold Storage Pvt. Ltd.

" "Ashirvad Trading Company

" "Tasgaon-Sangli Road, Kavthe Ekand, Sangli

" "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"{entity_label}: {shetkari}    " f"Sauda Date: {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"{e['rate']}", center_style), e["details"] ]) table_data.append([ "", "", Paragraph("Total", center_style), Paragraph(f"{total_qty}", 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()