girishwangikar commited on
Commit
c951ca9
Β·
verified Β·
1 Parent(s): 586c913

Create analytics_tab.py

Browse files
Files changed (1) hide show
  1. analytics_tab.py +352 -0
analytics_tab.py ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import plotly.graph_objects as go
4
+ from datetime import datetime
5
+
6
+ class AnalyticsTab:
7
+ def __init__(self, get_sheet_func):
8
+ """
9
+ Initialize the Analytics Tab
10
+
11
+ Args:
12
+ get_sheet_func: Function to get Google Sheet
13
+ """
14
+ self.get_sheet = get_sheet_func
15
+
16
+ def get_all_transactions(self):
17
+ """Get all transactions without interest calculations"""
18
+ try:
19
+ spreadsheet = self.get_sheet()
20
+ trans_sheet = spreadsheet.worksheet("Transactions")
21
+ data = trans_sheet.get_all_values()
22
+
23
+ if len(data) <= 1:
24
+ return pd.DataFrame()
25
+
26
+ df = pd.DataFrame(data[1:], columns=data[0])
27
+ df['Amount'] = pd.to_numeric(df['Amount'], errors='coerce')
28
+ df['Date'] = pd.to_datetime(df['Date'], errors='coerce')
29
+ df = df.sort_values('Date')
30
+
31
+ # Calculate running balance without interest
32
+ df['Balance'] = df['Amount'].cumsum()
33
+
34
+ return df
35
+ except Exception as e:
36
+ print(f"Error getting transactions: {str(e)}")
37
+ return pd.DataFrame()
38
+
39
+ def get_transactions_display(self):
40
+ """Get transactions formatted for display"""
41
+ try:
42
+ df = self.get_all_transactions()
43
+
44
+ if df.empty:
45
+ return None, "❌ No transactions found"
46
+
47
+ # Format for display
48
+ display_df = df[['Date', 'Type', 'Bank Account', 'Amount', 'Balance']].copy()
49
+ display_df.columns = ['Date', 'Description', 'Bank Account', 'Amount (β‚Ή)', 'Balance (β‚Ή)']
50
+ display_df['Date'] = display_df['Date'].dt.strftime('%Y-%m-%d')
51
+
52
+ return display_df, f"βœ… Showing {len(display_df)} transactions"
53
+ except Exception as e:
54
+ return None, f"❌ Error loading transactions: {str(e)}"
55
+
56
+ def get_bank_analytics(self, month=None, year=None):
57
+ """Get bank-wise analytics with optional month/year filter"""
58
+ try:
59
+ df = self.get_all_transactions()
60
+
61
+ if df.empty:
62
+ return None, None, "❌ No transactions found"
63
+
64
+ # Apply filters if provided
65
+ if month and year:
66
+ df = df[(df['Date'].dt.month == int(month)) & (df['Date'].dt.year == int(year))]
67
+ elif year:
68
+ df = df[df['Date'].dt.year == int(year)]
69
+
70
+ if df.empty:
71
+ return None, None, "❌ No transactions found for the selected period"
72
+
73
+ # Calculate bank-wise statistics
74
+ bank_stats = []
75
+ banks = df['Bank Account'].unique()
76
+
77
+ for bank in banks:
78
+ bank_df = df[df['Bank Account'] == bank]
79
+ outgoing = abs(bank_df[bank_df['Amount'] < 0]['Amount'].sum())
80
+ incoming = bank_df[bank_df['Amount'] > 0]['Amount'].sum()
81
+ net = incoming - outgoing
82
+
83
+ bank_stats.append({
84
+ 'Bank Account': bank,
85
+ 'Outgoing': outgoing,
86
+ 'Incoming': incoming,
87
+ 'Net': net
88
+ })
89
+
90
+ stats_df = pd.DataFrame(bank_stats)
91
+
92
+ # Create horizontal bar chart
93
+ fig = go.Figure()
94
+
95
+ fig.add_trace(go.Bar(
96
+ name='Outgoing',
97
+ y=stats_df['Bank Account'],
98
+ x=stats_df['Outgoing'],
99
+ orientation='h',
100
+ marker_color='#e74c3c',
101
+ text=stats_df['Outgoing'].apply(lambda x: f'β‚Ή{x:,.2f}'),
102
+ textposition='auto'
103
+ ))
104
+
105
+ fig.add_trace(go.Bar(
106
+ name='Incoming',
107
+ y=stats_df['Bank Account'],
108
+ x=stats_df['Incoming'],
109
+ orientation='h',
110
+ marker_color='#27ae60',
111
+ text=stats_df['Incoming'].apply(lambda x: f'β‚Ή{x:,.2f}'),
112
+ textposition='auto'
113
+ ))
114
+
115
+ filter_text = ""
116
+ if month and year:
117
+ filter_text = f" ({datetime(int(year), int(month), 1).strftime('%B %Y')})"
118
+ elif year:
119
+ filter_text = f" ({year})"
120
+
121
+ fig.update_layout(
122
+ title=f"Bank-wise Transaction Analytics{filter_text}",
123
+ xaxis_title="Amount (β‚Ή)",
124
+ yaxis_title="Bank Account",
125
+ barmode='group',
126
+ height=400,
127
+ font=dict(size=12),
128
+ showlegend=True
129
+ )
130
+
131
+ # Create summary HTML
132
+ summary_html = f"""
133
+ <div style="background: linear-gradient(135deg, #3498db 0%, #2c3e50 100%); padding: 30px; border-radius: 15px; margin: 20px 0;">
134
+ <h2 style="color: white; text-align: center; margin-bottom: 25px;">πŸ“Š Bank-wise Analytics{filter_text}</h2>
135
+ """
136
+
137
+ for _, row in stats_df.iterrows():
138
+ summary_html += f"""
139
+ <div style="background-color: rgba(255,255,255,0.95); border-radius: 10px; padding: 20px; margin-bottom: 15px;">
140
+ <h3 style="color: #2c3e50; margin-bottom: 15px;">🏦 {row['Bank Account']}</h3>
141
+ <table style="width: 100%; border-collapse: collapse;">
142
+ <tr>
143
+ <td style="padding: 10px; font-size: 16px; color: #e74c3c; font-weight: bold;">Outgoing:</td>
144
+ <td style="padding: 10px; font-size: 18px; text-align: right; color: #e74c3c; font-weight: bold;">β‚Ή{row['Outgoing']:,.2f}</td>
145
+ </tr>
146
+ <tr>
147
+ <td style="padding: 10px; font-size: 16px; color: #27ae60; font-weight: bold;">Incoming:</td>
148
+ <td style="padding: 10px; font-size: 18px; text-align: right; color: #27ae60; font-weight: bold;">β‚Ή{row['Incoming']:,.2f}</td>
149
+ </tr>
150
+ <tr style="border-top: 2px solid #34495e;">
151
+ <td style="padding: 10px; font-size: 16px; color: #34495e; font-weight: bold;">Net:</td>
152
+ <td style="padding: 10px; font-size: 18px; text-align: right; color: {'#27ae60' if row['Net'] >= 0 else '#e74c3c'}; font-weight: bold;">β‚Ή{abs(row['Net']):,.2f} {'(Surplus)' if row['Net'] >= 0 else '(Deficit)'}</td>
153
+ </tr>
154
+ </table>
155
+ </div>
156
+ """
157
+
158
+ summary_html += "</div>"
159
+
160
+ return fig, summary_html, "βœ… Analytics generated successfully"
161
+
162
+ except Exception as e:
163
+ return None, None, f"❌ Error generating analytics: {str(e)}"
164
+
165
+ def get_daily_transactions(self, selected_date):
166
+ """Get day-wise transaction details"""
167
+ try:
168
+ if not selected_date:
169
+ return None, "❌ Please select a date"
170
+
171
+ df = self.get_all_transactions()
172
+
173
+ if df.empty:
174
+ return None, "❌ No transactions found"
175
+
176
+ # Convert selected date to datetime
177
+ selected_dt = pd.to_datetime(selected_date)
178
+
179
+ # Filter for selected date
180
+ daily_df = df[df['Date'].dt.date == selected_dt.date()]
181
+
182
+ if daily_df.empty:
183
+ return None, f"❌ No transactions found for {selected_date}"
184
+
185
+ # Create summary table
186
+ outgoing_total = abs(daily_df[daily_df['Amount'] < 0]['Amount'].sum())
187
+ incoming_total = daily_df[daily_df['Amount'] > 0]['Amount'].sum()
188
+
189
+ # Get outgoing details
190
+ outgoing_details = []
191
+ outgoing_df = daily_df[daily_df['Amount'] < 0]
192
+ for _, row in outgoing_df.iterrows():
193
+ outgoing_details.append({
194
+ 'Farmer': row['Farmer Name'],
195
+ 'Bank Account': row['Bank Account'],
196
+ 'Amount': abs(row['Amount'])
197
+ })
198
+
199
+ # Get incoming details
200
+ incoming_details = []
201
+ incoming_df = daily_df[daily_df['Amount'] > 0]
202
+ for _, row in incoming_df.iterrows():
203
+ incoming_details.append({
204
+ 'Farmer': row['Farmer Name'],
205
+ 'Bank Account': row['Bank Account'],
206
+ 'Amount': row['Amount']
207
+ })
208
+
209
+ # Create HTML summary
210
+ summary_html = f"""
211
+ <div style="background: linear-gradient(135deg, #ff6b6b 0%, #feca57 100%); padding: 30px; border-radius: 15px; margin: 20px 0;">
212
+ <h2 style="color: white; text-align: center; margin-bottom: 25px;">πŸ“… Daily Transaction Summary: {selected_date}</h2>
213
+
214
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px;">
215
+ <div style="background-color: rgba(255,255,255,0.95); border-radius: 10px; padding: 20px;">
216
+ <h3 style="color: #e74c3c; text-align: center; margin-bottom: 15px;">πŸ’Έ Outgoing</h3>
217
+ <p style="font-size: 28px; font-weight: bold; text-align: center; color: #e74c3c; margin: 0;">β‚Ή{outgoing_total:,.2f}</p>
218
+ <p style="text-align: center; color: #666; margin-top: 5px;">{len(outgoing_details)} transaction(s)</p>
219
+ </div>
220
+
221
+ <div style="background-color: rgba(255,255,255,0.95); border-radius: 10px; padding: 20px;">
222
+ <h3 style="color: #27ae60; text-align: center; margin-bottom: 15px;">πŸ’° Incoming</h3>
223
+ <p style="font-size: 28px; font-weight: bold; text-align: center; color: #27ae60; margin: 0;">β‚Ή{incoming_total:,.2f}</p>
224
+ <p style="text-align: center; color: #666; margin-top: 5px;">{len(incoming_details)} transaction(s)</p>
225
+ </div>
226
+ </div>
227
+ """
228
+
229
+ # Add outgoing details
230
+ if outgoing_details:
231
+ summary_html += """
232
+ <div style="background-color: rgba(255,255,255,0.95); border-radius: 10px; padding: 20px; margin-bottom: 15px;">
233
+ <h3 style="color: #e74c3c; margin-bottom: 15px;">πŸ“€ Outgoing Transactions:</h3>
234
+ <table style="width: 100%; border-collapse: collapse;">
235
+ <tr style="background-color: #f8f9fa; font-weight: bold;">
236
+ <td style="padding: 10px; border-bottom: 2px solid #dee2e6;">Farmer</td>
237
+ <td style="padding: 10px; border-bottom: 2px solid #dee2e6;">Bank Account</td>
238
+ <td style="padding: 10px; border-bottom: 2px solid #dee2e6; text-align: right;">Amount</td>
239
+ </tr>
240
+ """
241
+ for detail in outgoing_details:
242
+ summary_html += f"""
243
+ <tr>
244
+ <td style="padding: 10px; border-bottom: 1px solid #dee2e6;">{detail['Farmer']}</td>
245
+ <td style="padding: 10px; border-bottom: 1px solid #dee2e6;">{detail['Bank Account']}</td>
246
+ <td style="padding: 10px; border-bottom: 1px solid #dee2e6; text-align: right; color: #e74c3c; font-weight: bold;">β‚Ή{detail['Amount']:,.2f}</td>
247
+ </tr>
248
+ """
249
+ summary_html += "</table></div>"
250
+
251
+ # Add incoming details
252
+ if incoming_details:
253
+ summary_html += """
254
+ <div style="background-color: rgba(255,255,255,0.95); border-radius: 10px; padding: 20px;">
255
+ <h3 style="color: #27ae60; margin-bottom: 15px;">πŸ“₯ Incoming Transactions:</h3>
256
+ <table style="width: 100%; border-collapse: collapse;">
257
+ <tr style="background-color: #f8f9fa; font-weight: bold;">
258
+ <td style="padding: 10px; border-bottom: 2px solid #dee2e6;">Farmer</td>
259
+ <td style="padding: 10px; border-bottom: 2px solid #dee2e6;">Bank Account</td>
260
+ <td style="padding: 10px; border-bottom: 2px solid #dee2e6; text-align: right;">Amount</td>
261
+ </tr>
262
+ """
263
+ for detail in incoming_details:
264
+ summary_html += f"""
265
+ <tr>
266
+ <td style="padding: 10px; border-bottom: 1px solid #dee2e6;">{detail['Farmer']}</td>
267
+ <td style="padding: 10px; border-bottom: 1px solid #dee2e6;">{detail['Bank Account']}</td>
268
+ <td style="padding: 10px; border-bottom: 1px solid #dee2e6; text-align: right; color: #27ae60; font-weight: bold;">β‚Ή{detail['Amount']:,.2f}</td>
269
+ </tr>
270
+ """
271
+ summary_html += "</table></div>"
272
+
273
+ summary_html += "</div>"
274
+
275
+ return summary_html, f"βœ… Found {len(daily_df)} transaction(s) for {selected_date}"
276
+
277
+ except Exception as e:
278
+ return None, f"❌ Error getting daily transactions: {str(e)}"
279
+
280
+ def create_tab(self):
281
+ """Create the Analytics tab interface"""
282
+ with gr.Tab("πŸ“ˆ Analytics & Insights"):
283
+ gr.Markdown("## Transaction Analytics Dashboard")
284
+ gr.Markdown("View all transactions and analyze bank-wise performance")
285
+
286
+ # Section 1: All Transactions
287
+ with gr.Accordion("πŸ“‹ All Transactions (Without Interest)", open=True):
288
+ load_trans_btn = gr.Button("Load All Transactions", variant="primary", size="lg")
289
+ trans_status = gr.Textbox(label="Status", interactive=False)
290
+ all_trans_df = gr.Dataframe(
291
+ label="All Transactions",
292
+ interactive=False,
293
+ wrap=True
294
+ )
295
+
296
+ gr.Markdown("---")
297
+
298
+ # Section 2: Bank-wise Analytics
299
+ with gr.Accordion("🏦 Bank-wise Analytics", open=True):
300
+ gr.Markdown("### Filter Transactions")
301
+ with gr.Row():
302
+ month_filter = gr.Dropdown(
303
+ label="Month (Optional)",
304
+ choices=[""] + [str(i) for i in range(1, 13)],
305
+ value="",
306
+ allow_custom_value=False
307
+ )
308
+ year_filter = gr.Dropdown(
309
+ label="Year (Optional)",
310
+ choices=[""] + [str(year) for year in range(2020, 2031)],
311
+ value="",
312
+ allow_custom_value=False
313
+ )
314
+
315
+ generate_analytics_btn = gr.Button("Generate Analytics", variant="primary", size="lg")
316
+
317
+ analytics_status = gr.Textbox(label="Status", interactive=False)
318
+ analytics_summary = gr.HTML()
319
+ analytics_chart = gr.Plot(label="Bank-wise Transaction Comparison")
320
+
321
+ gr.Markdown("---")
322
+
323
+ # Section 3: Daily Transaction Details
324
+ with gr.Accordion("πŸ“… Daily Transaction Details", open=True):
325
+ gr.Markdown("### Select a Date to View Daily Transactions")
326
+ daily_date = gr.Textbox(
327
+ label="Date (YYYY-MM-DD)",
328
+ placeholder="2024-01-15"
329
+ )
330
+ get_daily_btn = gr.Button("Get Daily Details", variant="primary", size="lg")
331
+
332
+ daily_status = gr.Textbox(label="Status", interactive=False)
333
+ daily_summary = gr.HTML()
334
+
335
+ # Event handlers
336
+ load_trans_btn.click(
337
+ fn=self.get_transactions_display,
338
+ inputs=[],
339
+ outputs=[all_trans_df, trans_status]
340
+ )
341
+
342
+ generate_analytics_btn.click(
343
+ fn=lambda m, y: self.get_bank_analytics(m if m else None, y if y else None),
344
+ inputs=[month_filter, year_filter],
345
+ outputs=[analytics_chart, analytics_summary, analytics_status]
346
+ )
347
+
348
+ get_daily_btn.click(
349
+ fn=self.get_daily_transactions,
350
+ inputs=[daily_date],
351
+ outputs=[daily_summary, daily_status]
352
+ )