import gradio as gr import pandas as pd import os class DeleteTab: def __init__(self, get_sheet_func, get_farmers_func, format_indian_currency_func, format_date_display_func): """ Initialize the Delete Tab Args: get_sheet_func: Function to get Google Sheet get_farmers_func: Function to get list of farmers format_indian_currency_func: Function to format currency in Indian style format_date_display_func: Function to format date display """ self.get_sheet = get_sheet_func self.get_farmers = get_farmers_func self.format_indian_currency = format_indian_currency_func self.format_date_display = format_date_display_func def refresh_farmers(self): """Refresh farmer dropdown""" return gr.Dropdown(choices=self.get_farmers()) def get_farmer_transactions_for_deletion(self, farmer_name): """Get all transactions for a farmer with row indices""" try: if not farmer_name or not farmer_name.strip(): return None, "❌ Please select a farmer" farmer_name = farmer_name.strip() spreadsheet = self.get_sheet() trans_sheet = spreadsheet.worksheet("Transactions") data = trans_sheet.get_all_values() if len(data) <= 1: return None, f"❌ No transactions found for farmer '{farmer_name}'" # Create DataFrame with row indices df = pd.DataFrame(data[1:], columns=data[0]) df['Sheet_Row'] = range(2, len(data) + 1) # Filter by farmer farmer_df = df[df['Farmer Name'] == farmer_name].copy() if farmer_df.empty: return None, f"❌ No transactions found for farmer '{farmer_name}'" # Convert amount and date farmer_df['Amount'] = pd.to_numeric(farmer_df['Amount'], errors='coerce') farmer_df['Date'] = pd.to_datetime(farmer_df['Date'], errors='coerce') farmer_df = farmer_df.sort_values('Date') # Create display dataframe display_df = farmer_df[['Sheet_Row', 'Date', 'Type', 'Bank Account', 'Amount']].copy() display_df.columns = ['Row #', 'Date', 'Description', 'Bank Account', 'Amount (₹)'] display_df['Date'] = display_df['Date'].apply(lambda x: self.format_date_display(str(x)[:10])) display_df['Amount (₹)'] = display_df['Amount (₹)'].apply(self.format_indian_currency) return display_df, f"✅ Found {len(farmer_df)} transaction(s) for {farmer_name}" except Exception as e: import traceback traceback.print_exc() return None, f"❌ Error loading transactions: {str(e)}" def delete_single_transaction(self, row_number): """Delete a single transaction by row number""" try: if not row_number: return "❌ Please select a row to delete" row_number = int(row_number) spreadsheet = self.get_sheet() trans_sheet = spreadsheet.worksheet("Transactions") # Delete the row trans_sheet.delete_rows(row_number) return f"✅ Successfully deleted transaction at row {row_number}" except Exception as e: return f"❌ Error deleting transaction: {str(e)}" def delete_all_farmer_data(self, farmer_name): """Delete all data for a farmer including transactions and farmer registration""" try: if not farmer_name or not farmer_name.strip(): return "❌ Please enter a farmer name" farmer_name = farmer_name.strip() spreadsheet = self.get_sheet() # 1. Delete all transactions for this farmer trans_sheet = spreadsheet.worksheet("Transactions") data = trans_sheet.get_all_values() if len(data) > 1: # Find rows to delete (from bottom to top to avoid index shifting) rows_to_delete = [] for idx, row in enumerate(data[1:], start=2): if len(row) > 1 and row[1] == farmer_name: # Column 1 is Farmer Name rows_to_delete.append(idx) # Delete rows from bottom to top for row_num in sorted(rows_to_delete, reverse=True): trans_sheet.delete_rows(row_num) transactions_deleted = len(rows_to_delete) else: transactions_deleted = 0 # 2. Remove farmer from metadata meta_sheet = spreadsheet.worksheet("Metadata") meta_data = meta_sheet.get_all_values() for idx, row in enumerate(meta_data): if len(row) >= 2 and row[0] == 'farmer': current_farmers = row[1] farmers_list = [f.strip() for f in current_farmers.split(',') if f.strip()] if farmer_name in farmers_list: farmers_list.remove(farmer_name) new_farmers = ','.join(farmers_list) meta_sheet.update_cell(idx + 1, 2, new_farmers) return f"✅ Successfully deleted farmer '{farmer_name}' from system.\n" \ f"Deleted {transactions_deleted} transaction(s).\n" \ f"Removed farmer from registration list." if transactions_deleted > 0: return f"⚠️ Deleted {transactions_deleted} transaction(s) but farmer was not found in registration list" else: return f"❌ Farmer '{farmer_name}' not found in system" except Exception as e: import traceback traceback.print_exc() return f"❌ Error deleting farmer data: {str(e)}" def get_banks(self): """Get list of registered bank accounts""" try: spreadsheet = self.get_sheet() meta_sheet = spreadsheet.worksheet("Metadata") data = meta_sheet.get_all_values() banks = [] for row in data: if len(row) >= 2 and row[0] == 'bank' and row[1]: banks.extend([b.strip() for b in row[1].split(',') if b.strip()]) return sorted(list(set(banks))) except Exception as e: print(f"Error getting banks: {str(e)}") return [] def refresh_banks(self): """Refresh bank dropdown""" return gr.Dropdown(choices=self.get_banks()) def delete_bank(self, bank_name): """Delete a bank from the registration list""" try: if not bank_name or not bank_name.strip(): return "❌ Please select a bank account" bank_name = bank_name.strip() spreadsheet = self.get_sheet() meta_sheet = spreadsheet.worksheet("Metadata") meta_data = meta_sheet.get_all_values() for idx, row in enumerate(meta_data): if len(row) >= 2 and row[0] == 'bank': current_banks = row[1] banks_list = [b.strip() for b in current_banks.split(',') if b.strip()] if bank_name in banks_list: banks_list.remove(bank_name) new_banks = ','.join(banks_list) meta_sheet.update_cell(idx + 1, 2, new_banks) return f"✅ Successfully deleted bank account '{bank_name}' from registration list" return f"❌ Bank account '{bank_name}' not found in registration list" except Exception as e: import traceback traceback.print_exc() return f"❌ Error deleting bank: {str(e)}" def clear_delete_bank(self): """Clear bank deletion interface""" return "" def clear_delete_single(self): """Clear single deletion interface""" return None, "", "" def clear_delete_all(self): """Clear complete deletion interface""" return "" def create_tab(self): """Create the Delete tab interface""" with gr.Tab("🗑️ Delete Records"): gr.Markdown("## Delete Transaction Records") gr.Markdown("⚠️ **Warning**: Deletion is permanent and cannot be undone!") # Section 1: Delete Single Transaction with gr.Accordion("🔍 Delete Individual Transaction", open=False): gr.Markdown("*Search for a farmer and delete specific transactions*") with gr.Row(): delete_single_farmer = gr.Dropdown( label="Select Farmer", choices=[], allow_custom_value=True, scale=9 ) refresh_delete_single_btn = gr.Button("🔄", scale=1, size="sm") load_delete_trans_btn = gr.Button("Load Transactions", variant="primary") delete_single_status = gr.Textbox(label="Status", interactive=False, show_label=False) delete_trans_df = gr.Dataframe( label="Transactions for Selected Farmer", interactive=False, wrap=True ) gr.Markdown("### Select Transaction to Delete") gr.Markdown("*Enter the Row # from the table above*") with gr.Row(): delete_row_input = gr.Textbox( label="Enter Row Number to Delete", placeholder="e.g., 15", scale=3 ) delete_single_btn = gr.Button("Delete Selected Row", variant="stop", size="lg", scale=1) delete_result = gr.Textbox(label="Deletion Result", interactive=False) gr.Markdown("---") # Section 2: Delete All Farmer Data with gr.Accordion("⚠️ Delete All Farmer Data", open=False): gr.Markdown("*Permanently delete ALL transactions and registration for a farmer*") gr.Markdown("**This will:**") gr.Markdown("- Delete all transaction records for this farmer") gr.Markdown("- Remove farmer from the registration list") gr.Markdown("- **Cannot be undone!**") with gr.Row(): delete_all_farmer = gr.Dropdown( label="Select Farmer to Delete Completely", choices=[], allow_custom_value=True, scale=9 ) refresh_delete_all_btn = gr.Button("🔄", scale=1, size="sm") delete_all_confirm = gr.Checkbox( label="I understand this action is permanent and cannot be undone", value=False ) delete_all_btn = gr.Button( "Delete All Data for This Farmer", variant="stop", size="lg" ) delete_all_result = gr.Textbox(label="Deletion Result", interactive=False) with gr.Accordion("🏦 Delete Bank Account", open=False): gr.Markdown("*Remove a bank account from the registration list*") gr.Markdown("⚠️ **Note**: This only removes the bank from the dropdown list. Existing transactions with this bank will remain.") with gr.Row(): delete_bank_dropdown = gr.Dropdown( label="Select Bank Account to Delete", choices=[], allow_custom_value=True, scale=9 ) refresh_delete_bank_btn = gr.Button("🔄", scale=1, size="sm") delete_bank_confirm = gr.Checkbox( label="I confirm I want to delete this bank account from the registration list", value=False ) delete_bank_btn = gr.Button( "Delete Bank Account", variant="stop", size="lg" ) delete_bank_result = gr.Textbox(label="Deletion Result", interactive=False) # Event handlers - Delete Single Transaction refresh_delete_single_btn.click( fn=self.refresh_farmers, outputs=[delete_single_farmer] ) load_delete_trans_btn.click( fn=self.get_farmer_transactions_for_deletion, inputs=[delete_single_farmer], outputs=[delete_trans_df, delete_single_status] ) # Replace the delete_single_btn.click handler: def delete_and_refresh(row_number, farmer_name): """Delete transaction and refresh the list""" if not row_number or not row_number.strip(): return "❌ Please enter a row number", None, "" result = self.delete_single_transaction(row_number.strip()) # Reload transactions after deletion if deletion was successful if "Successfully deleted" in result: new_df, new_status = self.get_farmer_transactions_for_deletion(farmer_name) return result, new_df, new_status else: return result, None, "" delete_single_btn.click( fn=delete_and_refresh, inputs=[delete_row_input, delete_single_farmer], outputs=[delete_result, delete_trans_df, delete_single_status] ) # Event handlers - Delete All Farmer Data refresh_delete_all_btn.click( fn=self.refresh_farmers, outputs=[delete_all_farmer] ) # Event handlers - Delete Bank Account refresh_delete_bank_btn.click( fn=self.refresh_banks, outputs=[delete_bank_dropdown] ) def delete_bank_with_confirmation(bank_name, confirmed): if not confirmed: return "❌ Please check the confirmation box to proceed with deletion" return self.delete_bank(bank_name) delete_bank_btn.click( fn=delete_bank_with_confirmation, inputs=[delete_bank_dropdown, delete_bank_confirm], outputs=[delete_bank_result] ).then( fn=lambda: False, # Uncheck the confirmation box outputs=[delete_bank_confirm] ) def delete_all_with_confirmation(farmer_name, confirmed): if not confirmed: return "❌ Please check the confirmation box to proceed with deletion" return self.delete_all_farmer_data(farmer_name) delete_all_btn.click( fn=delete_all_with_confirmation, inputs=[delete_all_farmer, delete_all_confirm], outputs=[delete_all_result] ).then( fn=lambda: False, # Uncheck the confirmation box outputs=[delete_all_confirm] )