Spaces:
Sleeping
Sleeping
File size: 6,775 Bytes
88ff990 4e6e288 88ff990 12477af 88ff990 de7d48b 4e6e288 1f48402 4e6e288 de7d48b 4e6e288 1f48402 de7d48b 12477af de7d48b 12477af 6259813 12477af de7d48b 581bd58 12477af 4e6e288 12477af de7d48b 12477af 6259813 12477af de7d48b 6259813 de7d48b 12477af de7d48b 12477af de7d48b 12477af de7d48b 12477af de7d48b 12477af de7d48b 12477af de7d48b 12477af de7d48b 12477af de7d48b 268f142 de7d48b 12477af 6259813 de7d48b 50acac4 6259813 |
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 |
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):
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 6371 * c
# ------------------ FIELD SALES ------------------
def load_field_sales():
df = load_tab("Field Sales")
if df.empty or "Date" not in df.columns:
return pd.DataFrame()
df['Date'] = pd.to_datetime(df['Date'], errors='coerce')
df = df.dropna(subset=["Date"])
df['DateStr'] = df['Date'].dt.date.astype(str)
if "Order Value" not in df.columns:
df["Order Value"] = 0
else:
df["Order Value"] = pd.to_numeric(df["Order Value"], errors="coerce").fillna(0)
# Distance calc
distances = [0]
for i in range(1, len(df)):
try:
prev = df.loc[i-1, 'Location']
curr = df.loc[i, 'Location']
if pd.notna(prev) and pd.notna(curr):
distances.append(round(haversine(prev, curr), 2))
else:
distances.append(0)
except:
distances.append(0)
df["Distance Travelled (km)"] = distances
return df
# ------------------ TELESALES ------------------
def load_telesales():
df = load_tab("TeleSales")
if df.empty or "Rep Email" not in df.columns:
return pd.DataFrame()
df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
df["DateStr"] = df["Date"].dt.date.astype(str)
return df
# ------------------ OEM ------------------
def load_oem():
df = load_tab("OEM Visit")
if df.empty or "Rep" not in df.columns:
return pd.DataFrame()
df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
df["DateStr"] = df["Date"].dt.date.astype(str)
return df
# ------------------ SUMMARY ------------------
def generate_summary(date_str):
df = load_field_sales()
if df.empty:
return pd.DataFrame([["No Field Sales data"]], columns=["Message"])*5
df_day = df[df['DateStr'] == date_str.strip()]
all_reps = sorted(df['Rep'].dropna().unique())
col = "Current/Prospect Customer"
# --- Visits Breakdown
total_visits = df_day.groupby("Rep").size().reset_index(name="Total Visits")
current = df_day[df_day[col] == "Current"]
prospect = df_day[df_day[col] == "Prospect"]
breakdown = pd.DataFrame({
"Rep": all_reps,
"Current": [len(current[current["Rep"] == rep]) for rep in all_reps],
"Prospect": [len(prospect[prospect["Rep"] == rep]) for rep in all_reps]
})
inactive = pd.DataFrame({'Inactive Reps': [rep for rep in all_reps if rep not in total_visits["Rep"].tolist()]})
# --- Field Summary per Rep
rep_summary = df_day.groupby("Rep").agg({
"Order Value": "sum",
"Order Received": lambda x: (x == "Yes").sum(),
"Current/Prospect Customer": lambda x: (x == "Current").sum(),
"Distance Travelled (km)": "sum"
}).rename(columns={
"Order Value": "Total Order Value",
"Order Received": "Orders Received",
"Current/Prospect Customer": "Current Customers",
"Distance Travelled (km)": "Total Distance (km)"
}).reset_index()
# --- TeleSales Summary
df_ts = load_telesales()
df_ts_day = df_ts[df_ts['DateStr'] == date_str.strip()]
ts_summary = df_ts_day.groupby("Rep Email").size().reset_index(name="Total Calls Made") if not df_ts_day.empty else pd.DataFrame([["No Telesales"]], columns=["Info"])
# --- OEM Summary
df_oem = load_oem()
df_oem_day = df_oem[df_oem['DateStr'] == date_str.strip()]
oem_summary = df_oem_day.groupby("Rep").size().reset_index(name="Total OEM Visits") if not df_oem_day.empty else pd.DataFrame([["No OEM Visits"]], columns=["Info"])
return total_visits, breakdown, inactive, rep_summary, ts_summary, oem_summary
# ------------------ 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")
df_initial = load_field_sales()
unique_dates = sorted(df_initial["DateStr"].unique(), reverse=True) if not df_initial.empty else []
# --- Summary Tab ---
with gr.Tab("π Summary"):
date_summary = gr.Dropdown(label="Select Date", choices=unique_dates)
visits = gr.Dataframe(label="β
Total Visits")
breakdown = gr.Dataframe(label="π·οΈ Current vs. Prospect")
inactive = gr.Dataframe(label="β οΈ Inactive Reps")
field_summary = gr.Dataframe(label="π Field Sales Summary")
ts_summary = gr.Dataframe(label="π Telesales Summary")
oem_summary = gr.Dataframe(label="π OEM Visit Summary")
date_summary.change(fn=generate_summary, inputs=date_summary,
outputs=[visits, breakdown, inactive, field_summary, ts_summary, oem_summary])
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()
|