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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -89
app.py CHANGED
@@ -27,111 +27,181 @@ def load_tab(sheet_name):
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()
 
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()
207