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"):
|