Spaces:
Sleeping
Sleeping
File size: 8,422 Bytes
88ff990 4e6e288 88ff990 f97e304 88ff990 d5ae19a 4e6e288 1f48402 4e6e288 d5ae19a 593765d d5ae19a f97e304 ede4167 f97e304 ede4167 f97e304 ede4167 f97e304 ede4167 f97e304 ede4167 f97e304 ede4167 f97e304 ede4167 f97e304 ede4167 d5ae19a ede4167 5c20576 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
import pandas as pd
import gspread
import gradio as gr
from oauth2client.service_account import ServiceAccountCredentials
from datetime import datetime
from math import radians, cos, sin, asin, sqrt
# ------------------ AUTH ------------------
VALID_USERS = {
"[email protected]": "Pass.123",
"[email protected]": "Pass.123",
"[email protected]": "Pass.123"
}
# ------------------ GOOGLE SHEET SETUP ------------------
scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
client = gspread.authorize(creds)
sheet_file = client.open("userAccess")
# ------------------ HELPERS ------------------
def load_tab(sheet_name):
try:
df = pd.DataFrame(sheet_file.worksheet(sheet_name).get_all_records())
return df
except:
return pd.DataFrame([["β οΈ Could not load sheet."]], columns=["Error"])
def haversine(coord1, coord2):
try:
lon1, lat1 = map(radians, map(float, coord1.split(',')[::-1]))
lon2, lat2 = map(radians, map(float, coord2.split(',')[::-1]))
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
return round(6371 * c, 2)
except:
return 0.0
# ------------------ FIELD SALES ------------------
def load_field_sales():
df = load_tab("Field Sales")
if df.empty:
return pd.DataFrame(columns=["Date", "Rep", "Order Value", "Order Received", "Location", "DateStr", "KM Travelled"])
df['Date'] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
df = df.dropna(subset=["Date"])
df['DateStr'] = df['Date'].dt.date.astype(str)
df["Order Value"] = pd.to_numeric(df.get("Order Value", 0), errors="coerce").fillna(0)
df["KM Travelled"] = 0.0
for rep in df["Rep"].unique():
rep_df = df[df["Rep"] == rep].sort_values(by="Date")
prev_coord = None
for idx, row in rep_df.iterrows():
curr_coord = row.get("Location", "")
if prev_coord:
df.at[idx, "KM Travelled"] = haversine(prev_coord, curr_coord)
prev_coord = curr_coord
return df
def get_field_summary():
df = load_field_sales()
if df.empty:
return pd.DataFrame([["No data available"]], columns=["Message"])
summary = df.groupby("Rep").agg({
"Order Value": "sum",
"Order Received": lambda x: (x == "Yes").sum(),
"KM Travelled": "sum"
}).reset_index().rename(columns={
"Order Value": "Total Order Value",
"Order Received": "Orders Received"
})
return summary
# ------------------ TELESALES ------------------
def get_telesales_summary():
df = load_tab("TeleSales")
if df.empty or "Rep" not in df.columns:
return pd.DataFrame([["No data available"]], columns=["Message"])
df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
df["DateStr"] = df["Date"].dt.date.astype(str)
df["Order Value"] = pd.to_numeric(df.get("Order Value", 0), errors="coerce").fillna(0)
summary = df.groupby("Rep").agg({
"Order Value": "sum",
"Order Received": lambda x: (x == "Yes").sum()
}).reset_index().rename(columns={
"Order Value": "Total Order Value",
"Order Received": "Orders Received"
})
return summary
# ------------------ COMBINED ORDERS ------------------
def get_combined_orders():
fs = get_field_summary()
ts = get_telesales_summary()
fs["Source"] = "Field Sales"
ts["Source"] = "TeleSales"
combined = pd.concat([fs, ts], ignore_index=True)
return combined[["Rep", "Orders Received", "Total Order Value", "Source"]].sort_values(by="Total Order Value", ascending=False)
# ------------------ OEM VISITS ------------------
def get_oem_summary():
df = load_tab("OEM Visit")
if df.empty or "Rep" not in df.columns:
return pd.DataFrame([["No data available"]], columns=["Message"])
df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
df["DateStr"] = df["Date"].dt.date.astype(str)
return df.groupby(["Rep", "DateStr"]).size().reset_index(name="OEM Visits")
# ------------------ OTHER TABS ------------------
def get_requests():
df = load_tab("Customer Requests")
return df if not df.empty else pd.DataFrame([["No requests yet."]], columns=["Message"])
def get_listings():
df = load_tab("CustomerListings")
return df if not df.empty else pd.DataFrame([["No listings found."]], columns=["Message"])
def get_users():
df = load_tab("Users")
return df if not df.empty else pd.DataFrame([["No users configured."]], columns=["Message"])
def get_escalations():
df = load_field_sales()
col = "Customer Type & Status"
if col in df.columns:
flagged = df[df[col].str.contains("Second", na=False)]
return flagged if not flagged.empty else pd.DataFrame([["No second-hand dealerships flagged."]], columns=["Message"])
else:
return pd.DataFrame([["β οΈ Column 'Customer Type & Status' not found."]], columns=["Message"])
# ------------------ GRADIO APP ------------------
with gr.Blocks() as app:
with gr.Row():
with gr.Column(visible=True) as login_ui:
gr.Markdown("## π Login Required")
email = gr.Textbox(label="Email")
password = gr.Textbox(label="Password", type="password")
login_btn = gr.Button("Login")
login_msg = gr.Markdown("")
with gr.Column(visible=False) as main_ui:
gr.Markdown("## ποΈ CarMat Dashboard")
# --- Summary Tab ---
with gr.Tab("π Summary"):
summary_table = gr.Dataframe(label="Combined Orders", value=get_combined_orders)
# --- Field Sales Tab ---
with gr.Tab("π£οΈ Field Sales"):
fs_table = gr.Dataframe(label="Field Sales Summary", value=get_field_summary)
fs_raw = gr.Dataframe(label="Raw Field Sales", value=load_field_sales)
# --- Telesales Tab ---
with gr.Tab("π TeleSales"):
ts_table = gr.Dataframe(label="TeleSales Summary", value=get_telesales_summary)
# --- Orders Tab ---
with gr.Tab("π¦ Orders"):
order_table = gr.Dataframe(label="All Orders Combined", value=get_combined_orders)
# --- Escalations ---
with gr.Tab("π¨ Escalations"):
esc_table = gr.Dataframe(value=get_escalations, label="Second-hand Dealerships")
esc_btn = gr.Button("π Refresh")
esc_btn.click(fn=get_escalations, outputs=esc_table)
# --- OEM Visits ---
with gr.Tab("π OEM Visits"):
oem_table = gr.Dataframe(value=get_oem_summary, label="OEM Visit Summary")
oem_refresh = gr.Button("π Refresh OEM")
oem_refresh.click(fn=get_oem_summary, outputs=oem_table)
# --- Requests ---
with gr.Tab("π¬ Customer Requests"):
req_table = gr.Dataframe(value=get_requests, label="Customer Requests", interactive=False)
req_refresh = gr.Button("π Refresh Requests")
req_refresh.click(fn=get_requests, outputs=req_table)
# --- Dealership Listings ---
with gr.Tab("π Dealership Directory"):
listings_table = gr.Dataframe(value=get_listings, label="Customer Listings")
listings_refresh = gr.Button("π Refresh Listings")
listings_refresh.click(fn=get_listings, outputs=listings_table)
# --- Users ---
with gr.Tab("π€ Users"):
users_table = gr.Dataframe(value=get_users, label="Users")
users_refresh = gr.Button("π Refresh Users")
users_refresh.click(fn=get_users, outputs=users_table)
def do_login(user, pw):
if VALID_USERS.get(user) == pw:
return gr.update(visible=False), gr.update(visible=True), ""
else:
return gr.update(visible=True), gr.update(visible=False), "β Invalid login."
login_btn.click(fn=do_login, inputs=[email, password], outputs=[login_ui, main_ui, login_msg])
app.launch()
|