IAMTFRMZA commited on
Commit
5c20576
Β·
verified Β·
1 Parent(s): f97e304

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -159
app.py CHANGED
@@ -27,180 +27,111 @@ def load_tab(sheet_name):
27
  return pd.DataFrame([["⚠️ Could not load sheet."]], columns=["Error"])
28
 
29
  def haversine(coord1, coord2):
30
- try:
31
- lon1, lat1 = map(radians, map(float, coord1.split(',')[::-1]))
32
- lon2, lat2 = map(radians, map(float, coord2.split(',')[::-1]))
33
- dlon = lon2 - lon1
34
- dlat = lat2 - lat1
35
- a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
36
- c = 2 * asin(sqrt(a))
37
- return round(6371 * c, 2)
38
- except:
39
- return 0.0
40
-
41
- # ------------------ FIELD SALES ------------------
42
  def load_field_sales():
43
  df = load_tab("Field Sales")
44
  if df.empty:
45
- return pd.DataFrame(columns=["Date", "Rep", "Order Value", "Order Received", "Location", "DateStr", "KM Travelled"])
46
-
47
  df['Date'] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
48
  df = df.dropna(subset=["Date"])
49
- df['DateStr'] = df['Date'].dt.date.astype(str)
50
  df["Order Value"] = pd.to_numeric(df.get("Order Value", 0), errors="coerce").fillna(0)
51
-
52
  df["KM Travelled"] = 0.0
53
  for rep in df["Rep"].unique():
54
  rep_df = df[df["Rep"] == rep].sort_values(by="Date")
55
  prev_coord = None
56
  for idx, row in rep_df.iterrows():
57
  curr_coord = row.get("Location", "")
58
- if prev_coord:
59
- df.at[idx, "KM Travelled"] = haversine(prev_coord, curr_coord)
 
 
 
 
60
  prev_coord = curr_coord
61
-
62
  return df
63
 
64
- def get_field_summary():
65
- df = load_field_sales()
66
- if df.empty:
67
- return pd.DataFrame([["No data available"]], columns=["Message"])
68
- summary = df.groupby("Rep").agg({
69
- "Order Value": "sum",
70
- "Order Received": lambda x: (x == "Yes").sum(),
71
- "KM Travelled": "sum"
72
- }).reset_index().rename(columns={
73
- "Order Value": "Total Order Value",
74
- "Order Received": "Orders Received"
75
- })
76
- return summary
77
-
78
- # ------------------ TELESALES ------------------
79
- def get_telesales_summary():
80
- df = load_tab("TeleSales")
81
- if df.empty or "Rep" not in df.columns:
82
- return pd.DataFrame([["No data available"]], columns=["Message"])
83
- df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
84
- df["DateStr"] = df["Date"].dt.date.astype(str)
85
  df["Order Value"] = pd.to_numeric(df.get("Order Value", 0), errors="coerce").fillna(0)
 
86
 
87
- summary = df.groupby("Rep").agg({
88
- "Order Value": "sum",
89
- "Order Received": lambda x: (x == "Yes").sum()
90
- }).reset_index().rename(columns={
91
- "Order Value": "Total Order Value",
92
- "Order Received": "Orders Received"
93
- })
94
- return summary
95
-
96
- # ------------------ COMBINED ORDERS ------------------
97
- def get_combined_orders():
98
- fs = get_field_summary()
99
- ts = get_telesales_summary()
100
-
101
- fs["Source"] = "Field Sales"
102
- ts["Source"] = "TeleSales"
103
-
104
- combined = pd.concat([fs, ts], ignore_index=True)
105
- return combined[["Rep", "Orders Received", "Total Order Value", "Source"]].sort_values(by="Total Order Value", ascending=False)
106
-
107
- # ------------------ OEM VISITS ------------------
108
- def get_oem_summary():
109
- df = load_tab("OEM Visit")
110
- if df.empty or "Rep" not in df.columns:
111
- return pd.DataFrame([["No data available"]], columns=["Message"])
112
- df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
113
- df["DateStr"] = df["Date"].dt.date.astype(str)
114
- return df.groupby(["Rep", "DateStr"]).size().reset_index(name="OEM Visits")
115
-
116
- # ------------------ OTHER TABS ------------------
117
- def get_requests():
118
- df = load_tab("Customer Requests")
119
- return df if not df.empty else pd.DataFrame([["No requests yet."]], columns=["Message"])
120
-
121
- def get_listings():
122
- df = load_tab("CustomerListings")
123
- return df if not df.empty else pd.DataFrame([["No listings found."]], columns=["Message"])
124
-
125
- def get_users():
126
- df = load_tab("Users")
127
- return df if not df.empty else pd.DataFrame([["No users configured."]], columns=["Message"])
128
-
129
- def get_escalations():
130
- df = load_field_sales()
131
- col = "Customer Type & Status"
132
- if col in df.columns:
133
- flagged = df[df[col].str.contains("Second", na=False)]
134
- return flagged if not flagged.empty else pd.DataFrame([["No second-hand dealerships flagged."]], columns=["Message"])
 
 
 
 
 
 
135
  else:
136
- return pd.DataFrame([["⚠️ Column 'Customer Type & Status' not found."]], columns=["Message"])
137
-
138
- # ------------------ GRADIO APP ------------------
139
- with gr.Blocks() as app:
140
- with gr.Row():
141
- with gr.Column(visible=True) as login_ui:
142
- gr.Markdown("## πŸ” Login Required")
143
- email = gr.Textbox(label="Email")
144
- password = gr.Textbox(label="Password", type="password")
145
- login_btn = gr.Button("Login")
146
- login_msg = gr.Markdown("")
147
-
148
- with gr.Column(visible=False) as main_ui:
149
- gr.Markdown("## πŸ—‚οΈ CarMat Dashboard")
150
-
151
- # --- Summary Tab ---
152
- with gr.Tab("πŸ“Š Summary"):
153
- summary_table = gr.Dataframe(label="Combined Orders", value=get_combined_orders)
154
-
155
- # --- Field Sales Tab ---
156
- with gr.Tab("πŸ›£οΈ Field Sales"):
157
- fs_table = gr.Dataframe(label="Field Sales Summary", value=get_field_summary)
158
- fs_raw = gr.Dataframe(label="Raw Field Sales", value=load_field_sales)
159
-
160
- # --- Telesales Tab ---
161
- with gr.Tab("πŸ“ž TeleSales"):
162
- ts_table = gr.Dataframe(label="TeleSales Summary", value=get_telesales_summary)
163
-
164
- # --- Orders Tab ---
165
- with gr.Tab("πŸ“¦ Orders"):
166
- order_table = gr.Dataframe(label="All Orders Combined", value=get_combined_orders)
167
-
168
- # --- Escalations ---
169
- with gr.Tab("🚨 Escalations"):
170
- esc_table = gr.Dataframe(value=get_escalations, label="Second-hand Dealerships")
171
- esc_btn = gr.Button("πŸ”„ Refresh")
172
- esc_btn.click(fn=get_escalations, outputs=esc_table)
173
-
174
- # --- OEM Visits ---
175
- with gr.Tab("🏭 OEM Visits"):
176
- oem_table = gr.Dataframe(value=get_oem_summary, label="OEM Visit Summary")
177
- oem_refresh = gr.Button("πŸ”„ Refresh OEM")
178
- oem_refresh.click(fn=get_oem_summary, outputs=oem_table)
179
-
180
- # --- Requests ---
181
- with gr.Tab("πŸ“¬ Customer Requests"):
182
- req_table = gr.Dataframe(value=get_requests, label="Customer Requests", interactive=False)
183
- req_refresh = gr.Button("πŸ”„ Refresh Requests")
184
- req_refresh.click(fn=get_requests, outputs=req_table)
185
-
186
- # --- Dealership Listings ---
187
- with gr.Tab("πŸ“‹ Dealership Directory"):
188
- listings_table = gr.Dataframe(value=get_listings, label="Customer Listings")
189
- listings_refresh = gr.Button("πŸ”„ Refresh Listings")
190
- listings_refresh.click(fn=get_listings, outputs=listings_table)
191
-
192
- # --- Users ---
193
- with gr.Tab("πŸ‘€ Users"):
194
- users_table = gr.Dataframe(value=get_users, label="Users")
195
- users_refresh = gr.Button("πŸ”„ Refresh Users")
196
- users_refresh.click(fn=get_users, outputs=users_table)
197
-
198
- def do_login(user, pw):
199
- if VALID_USERS.get(user) == pw:
200
- return gr.update(visible=False), gr.update(visible=True), ""
201
- else:
202
- return gr.update(visible=True), gr.update(visible=False), "❌ Invalid login."
203
-
204
- login_btn.click(fn=do_login, inputs=[email, password], outputs=[login_ui, main_ui, login_msg])
205
-
206
- app.launch()
 
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 # in km
37
+
38
+ # ------------------ LOAD SHEETS ------------------
 
 
 
39
  def load_field_sales():
40
  df = load_tab("Field Sales")
41
  if df.empty:
42
+ return pd.DataFrame(columns=["Date", "Rep", "Order Value", "Order Received", "Location", "KM Travelled"])
 
43
  df['Date'] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
44
  df = df.dropna(subset=["Date"])
 
45
  df["Order Value"] = pd.to_numeric(df.get("Order Value", 0), errors="coerce").fillna(0)
 
46
  df["KM Travelled"] = 0.0
47
  for rep in df["Rep"].unique():
48
  rep_df = df[df["Rep"] == rep].sort_values(by="Date")
49
  prev_coord = None
50
  for idx, row in rep_df.iterrows():
51
  curr_coord = row.get("Location", "")
52
+ if prev_coord and curr_coord:
53
+ try:
54
+ km = haversine(prev_coord, curr_coord)
55
+ df.at[idx, "KM Travelled"] = km
56
+ except:
57
+ df.at[idx, "KM Travelled"] = 0
58
  prev_coord = curr_coord
59
+ df["KM Travelled"] = df["KM Travelled"].round(2)
60
  return df
61
 
62
+ def load_telesales():
63
+ df = load_tab("Telesales")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  df["Order Value"] = pd.to_numeric(df.get("Order Value", 0), errors="coerce").fillna(0)
65
+ return df
66
 
67
+ def load_summary(field_df, telesales_df):
68
+ summary = []
69
+ reps = pd.concat([field_df["Rep"], telesales_df["Rep"]]).dropna().unique()
70
+ for rep in reps:
71
+ field_orders = field_df[(field_df["Rep"] == rep) & (field_df["Order Received"].str.lower() == "yes")]
72
+ telesales_orders = telesales_df[(telesales_df["Rep"] == rep) & (telesales_df["Order Received"].str.lower() == "yes")]
73
+ total_value = field_orders["Order Value"].sum() + telesales_orders["Order Value"].sum()
74
+ total_orders = len(field_orders) + len(telesales_orders)
75
+ total_km = field_df[field_df["Rep"] == rep]["KM Travelled"].sum()
76
+ summary.append([rep, total_value, total_orders, round(total_km, 2)])
77
+ return pd.DataFrame(summary, columns=["Rep", "Total Order Value", "Orders Received", "KM Travelled"])
78
+
79
+ # ------------------ MAIN INTERFACE ------------------
80
+ def login(email, password):
81
+ if VALID_USERS.get(email) == password:
82
+ field_df = load_field_sales()
83
+ telesales_df = load_telesales()
84
+ summary_df = load_summary(field_df, telesales_df)
85
+ orders_df = load_tab("Orders")
86
+ escalation_df = load_tab("Escalations")
87
+ oem_df = load_tab("OEM Visits")
88
+ cust_req_df = load_tab("Customer Requests")
89
+ dealer_df = load_tab("Dealership Directory")
90
+ users_df = load_tab("Users")
91
+
92
+ with gr.Tab("Summary"):
93
+ gr.Dataframe(summary_df, label="πŸ“Š Rep Summary")
94
+
95
+ with gr.Tab("Field Sales"):
96
+ gr.Dataframe(field_df[["Rep", "Order Value", "Order Received", "KM Travelled"]], label="Field Sales Summary")
97
+ gr.Dataframe(field_df, label="Raw Field Sales")
98
+
99
+ with gr.Tab("TeleSales"):
100
+ gr.Dataframe(telesales_df, label="TeleSales Data")
101
+
102
+ with gr.Tab("Orders"):
103
+ gr.Dataframe(orders_df, label="Orders")
104
+
105
+ with gr.Tab("Escalations"):
106
+ gr.Dataframe(escalation_df, label="Escalations")
107
+
108
+ with gr.Tab("OEM Visits"):
109
+ gr.Dataframe(oem_df, label="OEM Visits")
110
+
111
+ with gr.Tab("Customer Requests"):
112
+ gr.Dataframe(cust_req_df, label="Customer Requests")
113
+
114
+ with gr.Tab("Dealership Directory"):
115
+ gr.Dataframe(dealer_df, label="Dealership Directory")
116
+
117
+ with gr.Tab("Users"):
118
+ gr.Dataframe(users_df, label="Users")
119
+
120
+ return gr.update(visible=False), gr.update(visible=True)
121
  else:
122
+ return "Invalid credentials", gr.update(visible=False)
123
+
124
+ with gr.Blocks(theme=gr.themes.Monochrome(), css="footer {visibility: hidden}") as demo:
125
+ with gr.Column(visible=True) as login_col:
126
+ gr.Markdown("### πŸ” CarMat Dashboard Login")
127
+ email = gr.Textbox(label="Email")
128
+ password = gr.Textbox(label="Password", type="password")
129
+ login_btn = gr.Button("Login")
130
+ login_msg = gr.Text()
131
+
132
+ with gr.Column(visible=False) as dashboard_col:
133
+ gr.Markdown("## πŸ“‚ CarMat Dashboard")
134
+
135
+ login_btn.click(fn=login, inputs=[email, password], outputs=[login_msg, dashboard_col])
136
+
137
+ demo.launch()