IAMTFRMZA commited on
Commit
16ba360
Β·
verified Β·
1 Parent(s): 12477af

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -104
app.py CHANGED
@@ -3,7 +3,6 @@ import gspread
3
  import gradio as gr
4
  from oauth2client.service_account import ServiceAccountCredentials
5
  from datetime import datetime
6
- from math import radians, cos, sin, asin, sqrt
7
 
8
  # ------------------ AUTH ------------------
9
  VALID_USERS = {
@@ -26,111 +25,90 @@ def load_tab(sheet_name):
26
  except:
27
  return pd.DataFrame([["⚠️ Could not load sheet."]], columns=["Error"])
28
 
29
- def haversine(coord1, coord2):
30
- lon1, lat1 = map(radians, map(float, coord1.split(',')[::-1]))
31
- lon2, lat2 = map(radians, map(float, coord2.split(',')[::-1]))
32
- dlon = lon2 - lon1
33
- dlat = lat2 - lat1
34
- a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
35
- c = 2 * asin(sqrt(a))
36
- return 6371 * c
37
-
38
- # ------------------ FIELD SALES ------------------
39
- def load_field_sales():
40
- df = load_tab("Field Sales")
41
- if df.empty or "Date" not in df.columns:
42
- return pd.DataFrame()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
- df['Date'] = pd.to_datetime(df['Date'], errors='coerce')
45
- df = df.dropna(subset=["Date"])
46
- df['DateStr'] = df['Date'].dt.date.astype(str)
47
 
48
- if "Order Value" not in df.columns:
49
- df["Order Value"] = 0
50
- else:
51
- df["Order Value"] = pd.to_numeric(df["Order Value"], errors="coerce").fillna(0)
52
-
53
- # Distance calc
54
- distances = [0]
55
- for i in range(1, len(df)):
56
- try:
57
- prev = df.loc[i-1, 'Location']
58
- curr = df.loc[i, 'Location']
59
- if pd.notna(prev) and pd.notna(curr):
60
- distances.append(round(haversine(prev, curr), 2))
61
- else:
62
- distances.append(0)
63
- except:
64
- distances.append(0)
65
- df["Distance Travelled (km)"] = distances
66
 
67
- return df
 
 
68
 
69
- # ------------------ TELESALES ------------------
70
- def load_telesales():
71
  df = load_tab("TeleSales")
72
- if df.empty or "Rep Email" not in df.columns:
73
- return pd.DataFrame()
74
-
75
- df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
76
- df["DateStr"] = df["Date"].dt.date.astype(str)
77
- return df
78
 
79
- # ------------------ OEM ------------------
80
- def load_oem():
81
  df = load_tab("OEM Visit")
82
  if df.empty or "Rep" not in df.columns:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  return pd.DataFrame()
84
  df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
85
  df["DateStr"] = df["Date"].dt.date.astype(str)
86
  return df
87
 
88
- # ------------------ SUMMARY ------------------
89
- def generate_summary(date_str):
90
- df = load_field_sales()
91
- if df.empty:
92
- return pd.DataFrame([["No Field Sales data"]], columns=["Message"])*5
93
-
94
- df_day = df[df['DateStr'] == date_str.strip()]
95
- all_reps = sorted(df['Rep'].dropna().unique())
96
- col = "Current/Prospect Customer"
97
-
98
- # --- Visits Breakdown
99
- total_visits = df_day.groupby("Rep").size().reset_index(name="Total Visits")
100
- current = df_day[df_day[col] == "Current"]
101
- prospect = df_day[df_day[col] == "Prospect"]
102
- breakdown = pd.DataFrame({
103
- "Rep": all_reps,
104
- "Current": [len(current[current["Rep"] == rep]) for rep in all_reps],
105
- "Prospect": [len(prospect[prospect["Rep"] == rep]) for rep in all_reps]
106
- })
107
- inactive = pd.DataFrame({'Inactive Reps': [rep for rep in all_reps if rep not in total_visits["Rep"].tolist()]})
108
-
109
- # --- Field Summary per Rep
110
- rep_summary = df_day.groupby("Rep").agg({
111
- "Order Value": "sum",
112
- "Order Received": lambda x: (x == "Yes").sum(),
113
- "Current/Prospect Customer": lambda x: (x == "Current").sum(),
114
- "Distance Travelled (km)": "sum"
115
- }).rename(columns={
116
- "Order Value": "Total Order Value",
117
- "Order Received": "Orders Received",
118
- "Current/Prospect Customer": "Current Customers",
119
- "Distance Travelled (km)": "Total Distance (km)"
120
- }).reset_index()
121
-
122
- # --- TeleSales Summary
123
- df_ts = load_telesales()
124
- df_ts_day = df_ts[df_ts['DateStr'] == date_str.strip()]
125
- ts_summary = df_ts_day.groupby("Rep Email").size().reset_index(name="Total Calls Made") if not df_ts_day.empty else pd.DataFrame([["No Telesales"]], columns=["Info"])
126
-
127
- # --- OEM Summary
128
- df_oem = load_oem()
129
- df_oem_day = df_oem[df_oem['DateStr'] == date_str.strip()]
130
- oem_summary = df_oem_day.groupby("Rep").size().reset_index(name="Total OEM Visits") if not df_oem_day.empty else pd.DataFrame([["No OEM Visits"]], columns=["Info"])
131
-
132
- return total_visits, breakdown, inactive, rep_summary, ts_summary, oem_summary
133
-
134
  # ------------------ GRADIO APP ------------------
135
  with gr.Blocks() as app:
136
  with gr.Row():
@@ -147,18 +125,49 @@ with gr.Blocks() as app:
147
  df_initial = load_field_sales()
148
  unique_dates = sorted(df_initial["DateStr"].unique(), reverse=True) if not df_initial.empty else []
149
 
150
- # --- Summary Tab ---
151
  with gr.Tab("πŸ“Š Summary"):
152
- date_summary = gr.Dropdown(label="Select Date", choices=unique_dates)
153
- visits = gr.Dataframe(label="βœ… Total Visits")
154
- breakdown = gr.Dataframe(label="🏷️ Current vs. Prospect")
155
- inactive = gr.Dataframe(label="⚠️ Inactive Reps")
156
- field_summary = gr.Dataframe(label="πŸš— Field Sales Summary")
157
- ts_summary = gr.Dataframe(label="πŸ“ž Telesales Summary")
158
- oem_summary = gr.Dataframe(label="🏭 OEM Visit Summary")
159
-
160
- date_summary.change(fn=generate_summary, inputs=date_summary,
161
- outputs=[visits, breakdown, inactive, field_summary, ts_summary, oem_summary])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
  def do_login(user, pw):
164
  if VALID_USERS.get(user) == pw:
 
3
  import gradio as gr
4
  from oauth2client.service_account import ServiceAccountCredentials
5
  from datetime import datetime
 
6
 
7
  # ------------------ AUTH ------------------
8
  VALID_USERS = {
 
25
  except:
26
  return pd.DataFrame([["⚠️ Could not load sheet."]], columns=["Error"])
27
 
28
+ def get_combined_orders(date_str):
29
+ df_field = load_tab("Field Sales")
30
+ df_ts = load_tab("TeleSales")
31
+
32
+ combined = []
33
+
34
+ if not df_field.empty:
35
+ df_field['Date'] = pd.to_datetime(df_field['Date'], errors='coerce')
36
+ df_field['DateStr'] = df_field['Date'].dt.date.astype(str)
37
+ df_field = df_field[df_field['DateStr'] == date_str.strip()]
38
+ df_field['Order Value'] = pd.to_numeric(df_field['Order Value'], errors='coerce').fillna(0)
39
+ df_field_orders = df_field.groupby("Rep").agg({
40
+ "Order Received": lambda x: (x == "Yes").sum(),
41
+ "Order Value": "sum"
42
+ }).reset_index().rename(columns={
43
+ "Order Received": "Orders Received",
44
+ "Order Value": "Total Order Value"
45
+ })
46
+ df_field_orders["Source"] = "Field Sales"
47
+ combined.append(df_field_orders)
48
+
49
+ if not df_ts.empty:
50
+ df_ts['Date'] = pd.to_datetime(df_ts['Date'], errors='coerce')
51
+ df_ts['DateStr'] = df_ts['Date'].dt.date.astype(str)
52
+ df_ts = df_ts[df_ts['DateStr'] == date_str.strip()]
53
+ df_ts['Order Value'] = pd.to_numeric(df_ts['Order Value'], errors='coerce').fillna(0)
54
+ df_ts_orders = df_ts.groupby("Rep").agg({
55
+ "Order Received": lambda x: (x == "Yes").sum(),
56
+ "Order Value": "sum"
57
+ }).reset_index().rename(columns={
58
+ "Order Received": "Orders Received",
59
+ "Order Value": "Total Order Value"
60
+ })
61
+ df_ts_orders["Source"] = "TeleSales"
62
+ combined.append(df_ts_orders)
63
+
64
+ if combined:
65
+ return pd.concat(combined, ignore_index=True)
66
+ else:
67
+ return pd.DataFrame([["No orders on this date"]], columns=["Message"])
68
 
69
+ def get_requests():
70
+ df = load_tab("Customer Requests")
71
+ return df if not df.empty else pd.DataFrame([["No requests yet."]], columns=["Message"])
72
 
73
+ def get_listings():
74
+ df = load_tab("CustomerListings")
75
+ return df if not df.empty else pd.DataFrame([["No listings found."]], columns=["Message"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
+ def get_users():
78
+ df = load_tab("Users")
79
+ return df if not df.empty else pd.DataFrame([["No users configured."]], columns=["Message"])
80
 
81
+ def get_telesales_summary():
 
82
  df = load_tab("TeleSales")
83
+ if df.empty or "Rep" not in df.columns:
84
+ return pd.DataFrame([["No Telesales data available"]], columns=["Message"])
85
+ return df.groupby("Rep").size().reset_index(name="Total Calls Made")
 
 
 
86
 
87
+ def get_oem_summary():
 
88
  df = load_tab("OEM Visit")
89
  if df.empty or "Rep" not in df.columns:
90
+ return pd.DataFrame([["No OEM data available"]], columns=["Message"])
91
+ return df.groupby("Rep").size().reset_index(name="Total OEM Visits")
92
+
93
+ def get_escalations():
94
+ df = load_tab("Field Sales")
95
+ if df.empty:
96
+ return pd.DataFrame([["No data in Field Sales"]], columns=["Message"])
97
+ col = "Customer Type & Status"
98
+ if col in df.columns:
99
+ flagged = df[df[col].str.contains("Second", na=False)]
100
+ return flagged if not flagged.empty else pd.DataFrame([["No second-hand dealerships flagged."]], columns=["Message"])
101
+ else:
102
+ return pd.DataFrame([["⚠️ Column 'Customer Type & Status' not found."]], columns=["Message"])
103
+
104
+ def load_field_sales():
105
+ df = load_tab("Field Sales")
106
+ if df.empty:
107
  return pd.DataFrame()
108
  df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
109
  df["DateStr"] = df["Date"].dt.date.astype(str)
110
  return df
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  # ------------------ GRADIO APP ------------------
113
  with gr.Blocks() as app:
114
  with gr.Row():
 
125
  df_initial = load_field_sales()
126
  unique_dates = sorted(df_initial["DateStr"].unique(), reverse=True) if not df_initial.empty else []
127
 
128
+ # --- Tabs ---
129
  with gr.Tab("πŸ“Š Summary"):
130
+ gr.Markdown("Summary content coming soon...")
131
+
132
+ with gr.Tab("πŸ“‚ Field Sales"):
133
+ field_df = gr.Dataframe(value=load_field_sales, label="πŸ“‚ Field Sales Records", interactive=False)
134
+ field_btn = gr.Button("πŸ”„ Refresh Field Sales")
135
+ field_btn.click(fn=load_field_sales, outputs=field_df)
136
+
137
+ with gr.Tab("πŸ“ž TeleSales"):
138
+ ts_table = gr.Dataframe(value=get_telesales_summary, label="πŸ“ž TeleSales Summary")
139
+ ts_refresh = gr.Button("πŸ”„ Refresh")
140
+ ts_refresh.click(fn=get_telesales_summary, outputs=ts_table)
141
+
142
+ with gr.Tab("πŸ“¦ Orders Summary"):
143
+ order_date = gr.Dropdown(label="Select Date", choices=unique_dates, interactive=True)
144
+ order_table = gr.Dataframe(label="🧾 Combined Order Summary")
145
+ order_date.change(fn=get_combined_orders, inputs=order_date, outputs=order_table)
146
+
147
+ with gr.Tab("🚨 Escalations"):
148
+ esc_table = gr.Dataframe(value=get_escalations, label="🚨 Used Dealership Escalations")
149
+ esc_btn = gr.Button("πŸ”„ Refresh Escalations")
150
+ esc_btn.click(fn=get_escalations, outputs=esc_table)
151
+
152
+ with gr.Tab("🏭 OEM Visits"):
153
+ oem_table = gr.Dataframe(value=get_oem_summary, label="🏭 OEM Visit Summary")
154
+ oem_refresh = gr.Button("πŸ”„ Refresh")
155
+ oem_refresh.click(fn=get_oem_summary, outputs=oem_table)
156
+
157
+ with gr.Tab("πŸ“¬ Customer Requests"):
158
+ req_table = gr.Dataframe(value=get_requests, label="πŸ“¬ Customer Requests", interactive=False)
159
+ req_refresh = gr.Button("πŸ”„ Refresh Requests")
160
+ req_refresh.click(fn=get_requests, outputs=req_table)
161
+
162
+ with gr.Tab("πŸ“‹ Dealership Directory"):
163
+ listings_table = gr.Dataframe(value=get_listings, label="πŸ“‹ Customer Listings")
164
+ listings_refresh = gr.Button("πŸ”„ Refresh Listings")
165
+ listings_refresh.click(fn=get_listings, outputs=listings_table)
166
+
167
+ with gr.Tab("πŸ‘€ Users"):
168
+ users_table = gr.Dataframe(value=get_users, label="πŸ‘₯ Users")
169
+ users_refresh = gr.Button("πŸ”„ Refresh Users")
170
+ users_refresh.click(fn=get_users, outputs=users_table)
171
 
172
  def do_login(user, pw):
173
  if VALID_USERS.get(user) == pw: