Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -15,20 +15,25 @@ VALID_USERS = {
|
|
15 |
scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
|
16 |
creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
|
17 |
client = gspread.authorize(creds)
|
18 |
-
sheet_file = client.open("userAccess")
|
19 |
|
20 |
# ------------------ HELPERS ------------------
|
21 |
def load_tab(sheet_name):
|
22 |
-
|
|
|
|
|
|
|
|
|
23 |
|
24 |
# ------------------ FIELD SALES ------------------
|
25 |
def load_field_sales():
|
26 |
df = load_tab("Field Sales")
|
|
|
|
|
27 |
df['Date'] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
|
28 |
df = df.dropna(subset=["Date"])
|
29 |
df['DateStr'] = df['Date'].dt.date.astype(str)
|
30 |
|
31 |
-
# β
Fix: ensure column exists before numeric conversion
|
32 |
if "Order Value" not in df.columns:
|
33 |
df["Order Value"] = 0
|
34 |
else:
|
@@ -38,17 +43,19 @@ def load_field_sales():
|
|
38 |
|
39 |
def generate_summary(date_str):
|
40 |
df = load_field_sales()
|
|
|
|
|
|
|
41 |
all_reps = sorted(df['Rep'].dropna().unique())
|
42 |
day_df = df[df['DateStr'] == date_str]
|
43 |
-
|
44 |
total_visits = day_df.groupby("Rep").size().reset_index(name="Total Visits")
|
45 |
|
46 |
-
|
47 |
-
if
|
48 |
-
df[
|
49 |
|
50 |
-
current = day_df[day_df[
|
51 |
-
prospect = day_df[day_df[
|
52 |
breakdown = pd.DataFrame({
|
53 |
"Rep": all_reps,
|
54 |
"Current": [len(current[current["Rep"] == rep]) for rep in all_reps],
|
@@ -62,8 +69,10 @@ def generate_summary(date_str):
|
|
62 |
|
63 |
def get_order_summary(date_str):
|
64 |
df = load_field_sales()
|
65 |
-
|
|
|
66 |
|
|
|
67 |
if "Order Received" not in df.columns:
|
68 |
df["Order Received"] = ""
|
69 |
|
@@ -78,38 +87,52 @@ def get_order_summary(date_str):
|
|
78 |
|
79 |
def get_escalations():
|
80 |
df = load_field_sales()
|
|
|
|
|
|
|
81 |
col = "Customer Type & Status"
|
82 |
if col in df.columns:
|
83 |
flagged = df[df[col].str.contains("Second", na=False)]
|
84 |
-
return flagged if not flagged.empty else pd.DataFrame([["No second-hand dealerships flagged."]], columns=["
|
85 |
else:
|
86 |
-
return pd.DataFrame([["β οΈ Column 'Customer Type & Status' not found."]], columns=["
|
87 |
|
88 |
# ------------------ TELESALeS ------------------
|
89 |
def get_telesales_summary():
|
90 |
df = load_tab("TeleSales")
|
|
|
|
|
|
|
91 |
df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
|
92 |
df["DateStr"] = df["Date"].dt.date.astype(str)
|
93 |
-
|
|
|
|
|
94 |
|
95 |
# ------------------ OEM VISITS ------------------
|
96 |
def get_oem_summary():
|
97 |
df = load_tab("OEM Visit")
|
|
|
|
|
|
|
98 |
df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
|
99 |
df["DateStr"] = df["Date"].dt.date.astype(str)
|
100 |
return df.groupby(["Rep", "DateStr"]).size().reset_index(name="OEM Visits")
|
101 |
|
102 |
# ------------------ CUSTOMER REQUESTS ------------------
|
103 |
def get_requests():
|
104 |
-
|
|
|
105 |
|
106 |
# ------------------ CUSTOMER LISTINGS ------------------
|
107 |
def get_listings():
|
108 |
-
|
|
|
109 |
|
110 |
# ------------------ USERS ------------------
|
111 |
def get_users():
|
112 |
-
|
|
|
113 |
|
114 |
# ------------------ GRADIO APP ------------------
|
115 |
with gr.Blocks() as app:
|
@@ -125,7 +148,7 @@ with gr.Blocks() as app:
|
|
125 |
gr.Markdown("## ποΈ CarMat Dashboard")
|
126 |
|
127 |
df_initial = load_field_sales()
|
128 |
-
unique_dates = sorted(df_initial["DateStr"].unique(), reverse=True)
|
129 |
|
130 |
# --- Summary Tab ---
|
131 |
with gr.Tab("π Summary"):
|
|
|
15 |
scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
|
16 |
creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
|
17 |
client = gspread.authorize(creds)
|
18 |
+
sheet_file = client.open("userAccess")
|
19 |
|
20 |
# ------------------ HELPERS ------------------
|
21 |
def load_tab(sheet_name):
|
22 |
+
try:
|
23 |
+
df = pd.DataFrame(sheet_file.worksheet(sheet_name).get_all_records())
|
24 |
+
return df
|
25 |
+
except:
|
26 |
+
return pd.DataFrame([["β οΈ Could not load sheet."]], columns=["Error"])
|
27 |
|
28 |
# ------------------ FIELD SALES ------------------
|
29 |
def load_field_sales():
|
30 |
df = load_tab("Field Sales")
|
31 |
+
if df.empty:
|
32 |
+
return pd.DataFrame(columns=["Date", "Rep", "Order Value", "Order Received", "Current/Prospect Custor", "Customer Type & Status", "DateStr"])
|
33 |
df['Date'] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
|
34 |
df = df.dropna(subset=["Date"])
|
35 |
df['DateStr'] = df['Date'].dt.date.astype(str)
|
36 |
|
|
|
37 |
if "Order Value" not in df.columns:
|
38 |
df["Order Value"] = 0
|
39 |
else:
|
|
|
43 |
|
44 |
def generate_summary(date_str):
|
45 |
df = load_field_sales()
|
46 |
+
if df.empty:
|
47 |
+
return pd.DataFrame([["No data"]], columns=["Message"]), pd.DataFrame(), pd.DataFrame()
|
48 |
+
|
49 |
all_reps = sorted(df['Rep'].dropna().unique())
|
50 |
day_df = df[df['DateStr'] == date_str]
|
|
|
51 |
total_visits = day_df.groupby("Rep").size().reset_index(name="Total Visits")
|
52 |
|
53 |
+
col = "Current/Prospect Custor"
|
54 |
+
if col not in df.columns:
|
55 |
+
df[col] = ""
|
56 |
|
57 |
+
current = day_df[day_df[col] == "Current"]
|
58 |
+
prospect = day_df[day_df[col] == "Prospect"]
|
59 |
breakdown = pd.DataFrame({
|
60 |
"Rep": all_reps,
|
61 |
"Current": [len(current[current["Rep"] == rep]) for rep in all_reps],
|
|
|
69 |
|
70 |
def get_order_summary(date_str):
|
71 |
df = load_field_sales()
|
72 |
+
if df.empty:
|
73 |
+
return pd.DataFrame([["No data"]], columns=["Message"])
|
74 |
|
75 |
+
day_df = df[df['DateStr'] == date_str]
|
76 |
if "Order Received" not in df.columns:
|
77 |
df["Order Received"] = ""
|
78 |
|
|
|
87 |
|
88 |
def get_escalations():
|
89 |
df = load_field_sales()
|
90 |
+
if df.empty:
|
91 |
+
return pd.DataFrame([["No data in Field Sales"]], columns=["Message"])
|
92 |
+
|
93 |
col = "Customer Type & Status"
|
94 |
if col in df.columns:
|
95 |
flagged = df[df[col].str.contains("Second", na=False)]
|
96 |
+
return flagged if not flagged.empty else pd.DataFrame([["No second-hand dealerships flagged."]], columns=["Message"])
|
97 |
else:
|
98 |
+
return pd.DataFrame([["β οΈ Column 'Customer Type & Status' not found."]], columns=["Message"])
|
99 |
|
100 |
# ------------------ TELESALeS ------------------
|
101 |
def get_telesales_summary():
|
102 |
df = load_tab("TeleSales")
|
103 |
+
if df.empty or "Rep Email" not in df.columns:
|
104 |
+
return pd.DataFrame([["No data available"]], columns=["Message"])
|
105 |
+
|
106 |
df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
|
107 |
df["DateStr"] = df["Date"].dt.date.astype(str)
|
108 |
+
|
109 |
+
grouped = df.groupby(["Rep Email", "DateStr"]).size().reset_index(name="Calls Made")
|
110 |
+
return grouped.rename(columns={"Rep Email": "Rep"})
|
111 |
|
112 |
# ------------------ OEM VISITS ------------------
|
113 |
def get_oem_summary():
|
114 |
df = load_tab("OEM Visit")
|
115 |
+
if df.empty or "Rep" not in df.columns:
|
116 |
+
return pd.DataFrame([["No data available"]], columns=["Message"])
|
117 |
+
|
118 |
df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
|
119 |
df["DateStr"] = df["Date"].dt.date.astype(str)
|
120 |
return df.groupby(["Rep", "DateStr"]).size().reset_index(name="OEM Visits")
|
121 |
|
122 |
# ------------------ CUSTOMER REQUESTS ------------------
|
123 |
def get_requests():
|
124 |
+
df = load_tab("Customer Requests")
|
125 |
+
return df if not df.empty else pd.DataFrame([["No requests yet."]], columns=["Message"])
|
126 |
|
127 |
# ------------------ CUSTOMER LISTINGS ------------------
|
128 |
def get_listings():
|
129 |
+
df = load_tab("CustomerListings")
|
130 |
+
return df if not df.empty else pd.DataFrame([["No listings found."]], columns=["Message"])
|
131 |
|
132 |
# ------------------ USERS ------------------
|
133 |
def get_users():
|
134 |
+
df = load_tab("Users")
|
135 |
+
return df if not df.empty else pd.DataFrame([["No users configured."]], columns=["Message"])
|
136 |
|
137 |
# ------------------ GRADIO APP ------------------
|
138 |
with gr.Blocks() as app:
|
|
|
148 |
gr.Markdown("## ποΈ CarMat Dashboard")
|
149 |
|
150 |
df_initial = load_field_sales()
|
151 |
+
unique_dates = sorted(df_initial["DateStr"].unique(), reverse=True) if not df_initial.empty else []
|
152 |
|
153 |
# --- Summary Tab ---
|
154 |
with gr.Tab("π Summary"):
|