IAMTFRMZA commited on
Commit
6475632
Β·
verified Β·
1 Parent(s): 2e0be03

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -74
app.py CHANGED
@@ -6,30 +6,40 @@ from oauth2client.service_account import ServiceAccountCredentials
6
  from datetime import datetime, timedelta
7
 
8
  # -------------------- CONFIG --------------------
9
- SHEET_URL = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
10
- CREDS_JSON = "deep-mile-461309-t8-0e90103411e0.json"
11
 
12
  # -------------------- AUTH --------------------
13
  scope = ["https://spreadsheets.google.com/feeds","https://www.googleapis.com/auth/drive"]
14
  creds = ServiceAccountCredentials.from_json_keyfile_name(CREDS_JSON, scope)
15
  client = gspread.authorize(creds)
16
 
17
- # -------------------- SHEET LOAD / UTILS --------------------
18
  def normalize_columns(df):
19
  df.columns = df.columns.str.strip().str.title()
20
  return df
21
 
22
- def load_sheet_df(sheet_name):
 
23
  try:
24
- ws = client.open_by_url(SHEET_URL).worksheet(sheet_name)
25
  df = pd.DataFrame(ws.get_all_records())
26
  return normalize_columns(df)
27
  except Exception as e:
28
  return pd.DataFrame([{"Error": str(e)}])
29
 
30
- def rep_options(sheet_name, rep_col="Rep"):
31
- df = load_sheet_df(sheet_name)
32
- if rep_col in df.columns:
 
 
 
 
 
 
 
 
 
33
  return sorted(df[rep_col].dropna().unique().tolist())
34
  return []
35
 
@@ -39,9 +49,9 @@ def get_current_week_range():
39
  start = today - timedelta(days=today.weekday())
40
  return start.date(), (start + timedelta(days=6)).date()
41
 
42
- def filter_week(df, date_col, rep_col=None, rep=None):
43
  df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
44
- start,end = get_current_week_range()
45
  out = df[(df[date_col] >= start) & (df[date_col] <= end)]
46
  if rep and rep_col in out.columns:
47
  out = out[out[rep_col] == rep]
@@ -58,87 +68,97 @@ def filter_date(df, date_col, rep_col, y,m,d, rep):
58
  out = out[out[rep_col] == rep]
59
  return out
60
 
61
- # -------------------- REPORT FUNCTIONS --------------------
62
  def get_calls(rep=None):
63
  df = load_sheet_df("Calls")
64
  if "Call Date" not in df.columns:
65
  return pd.DataFrame([{"Error":"Missing 'Call Date'"}])
66
- return filter_week(df, "Call Date", "Rep", rep)
 
67
 
68
  def get_calls_summary(rep=None):
69
  df = get_calls(rep)
70
  if "Error" in df.columns or df.empty:
71
  return df
72
- return df.groupby("Rep").size().reset_index(name="Count")
 
73
 
74
  def search_calls_by_date(y,m,d,rep):
75
  df = load_sheet_df("Calls")
76
  if "Call Date" not in df.columns:
77
  return pd.DataFrame([{"Error":"Missing 'Call Date'"}])
78
- return filter_date(df, "Call Date", "Rep", y,m,d, rep)
 
79
 
 
80
  def get_appointments(rep=None):
81
  df = load_sheet_df("Appointments")
82
  if "Appointment Date" not in df.columns:
83
  return pd.DataFrame([{"Error":"Missing 'Appointment Date'"}])
84
- return filter_week(df, "Appointment Date", "Rep", rep)
 
85
 
86
  def get_appointments_summary(rep=None):
87
  df = get_appointments(rep)
88
  if "Error" in df.columns or df.empty:
89
  return df
90
- return df.groupby("Rep").size().reset_index(name="Count")
 
91
 
92
  def search_appointments_by_date(y,m,d,rep):
93
  df = load_sheet_df("Appointments")
94
  if "Appointment Date" not in df.columns:
95
  return pd.DataFrame([{"Error":"Missing 'Appointment Date'"}])
96
- return filter_date(df, "Appointment Date", "Rep", y,m,d, rep)
 
97
 
 
98
  def get_leads_detail():
99
  df = load_sheet_df("AllocatedLeads")
100
- if "Assigned Rep" not in df.columns:
101
- return pd.DataFrame([{"Error":"Missing 'Assigned Rep'"}])
102
  return df
103
 
104
  def get_leads_summary():
105
  df = get_leads_detail()
106
- if "Error" in df.columns:
107
- return df
108
- return df.groupby("Assigned Rep").size().reset_index(name="Leads Count")
 
109
 
110
  # -------------------- INSIGHTS --------------------
111
  def compute_insights():
112
- def top_rep(df, col):
113
- if "Error" in df.columns or df.empty:
114
- return "N/A"
115
- counts = df.groupby(col).size()
116
- return counts.idxmax() if not counts.empty else "N/A"
117
-
118
  calls = get_calls()
119
  appts = get_appointments()
120
- leads = get_leads_detail().rename(columns={"Assigned Rep":"Rep"})
 
 
 
 
 
 
 
 
 
121
 
122
  return pd.DataFrame([
123
- {"Metric":"Most Calls This Week", "Rep":top_rep(calls, "Rep")},
124
- {"Metric":"Most Appointments This Week", "Rep":top_rep(appts, "Rep")},
125
- {"Metric":"Most Leads Allocated", "Rep":top_rep(leads, "Rep")},
126
  ])
127
 
128
  # -------------------- USER MANAGEMENT --------------------
129
  def load_users():
130
- df = load_sheet_df("Users") # your sheet tab is named "Users"
131
  wanted = [
132
- "Id","Email","Name","Business","Role",
133
- "Daily Phone Call Target","Daily Phone Appointment Target",
134
- "Daily Quote Number Target","Daily Quote Revenue Target",
135
- "Weekly Phone Call Target","Weekly Phone Appointment Target",
136
- "Weekly Quote Number Target","Weekly Quote Revenue Target",
137
- "Monthly Phone Call Target","Monthly Phone Appointment Target",
138
- "Monthly Quote Number Target","Monthly Quote Revenue Target",
139
- "Monthly Sales Revenue Target"
140
  ]
141
- cols = [c for c in wanted if c in df.columns]
142
  return df[cols]
143
 
144
  def save_users(df):
@@ -147,72 +167,76 @@ def save_users(df):
147
  set_with_dataframe(ws, df)
148
  return "βœ… Users saved!"
149
 
150
- # -------------------- GRADIO UI --------------------
151
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
152
  gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
153
 
154
- # ─── Calls Report ───────────────────
155
  with gr.Tab("Calls Report"):
156
- rep_calls = gr.Dropdown("Optional Rep Filter", choices=rep_options("Calls"), allow_custom_value=True)
157
- calls_btn = gr.Button("Load Current Week Calls")
158
- calls_sum = gr.Dataframe(label="πŸ“Š Calls by Rep")
159
- calls_det = gr.Dataframe(label="πŸ”Ž Detailed Calls")
160
- calls_btn.click(fn=lambda r: (get_calls_summary(r), get_calls(r)),
 
161
  inputs=rep_calls, outputs=[calls_sum, calls_det])
162
 
163
- gr.Markdown("### πŸ” Search Calls by Date")
164
  y1,m1,d1 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
165
- rep1 = gr.Dropdown("Optional Rep Filter", choices=rep_options("Calls"), allow_custom_value=True)
166
- calls_dt_btn = gr.Button("Search")
 
167
  calls_dt_tbl = gr.Dataframe()
168
  calls_dt_btn.click(fn=search_calls_by_date,
169
- inputs=[y1,m1,d1,rep1],
170
- outputs=calls_dt_tbl)
171
 
172
- # ─── Appointments Report ────────────
173
  with gr.Tab("Appointments Report"):
174
- rep_appt = gr.Dropdown("Optional Rep Filter", choices=rep_options("Appointments"), allow_custom_value=True)
175
- appt_btn = gr.Button("Load Current Week Appts")
176
- appt_sum = gr.Dataframe(label="πŸ“Š Appts by Rep")
177
- appt_det = gr.Dataframe(label="πŸ”Ž Detailed Appts")
178
- appt_btn.click(fn=lambda r: (get_appointments_summary(r), get_appointments(r)),
 
179
  inputs=rep_appt, outputs=[appt_sum, appt_det])
180
 
181
- gr.Markdown("### πŸ” Search Appts by Date")
182
  y2,m2,d2 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
183
- rep2 = gr.Dropdown("Optional Rep Filter", choices=rep_options("Appointments"), allow_custom_value=True)
184
- appt_dt_btn = gr.Button("Search")
185
- appt_dt_sum = gr.Dataframe(label="πŸ“Š Appts Summary by Rep")
186
- appt_dt_det = gr.Dataframe(label="πŸ”Ž Detailed Appts")
 
187
  appt_dt_btn.click(
188
- fn=lambda y,m,d,r: (
189
- (lambda df: df.groupby("Rep").size().reset_index(name="Count"))(search_appointments_by_date(y,m,d,r)),
 
190
  search_appointments_by_date(y,m,d,r)
191
  ),
192
  inputs=[y2,m2,d2,rep2],
193
  outputs=[appt_dt_sum, appt_dt_det]
194
  )
195
 
196
- # ─── Appointed Leads ────────────────
197
  with gr.Tab("Appointed Leads"):
198
  leads_btn = gr.Button("View Appointed Leads")
199
  leads_sum = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
200
  leads_det = gr.Dataframe(label="πŸ”Ž Detailed Leads")
201
- leads_btn.click(fn=lambda: (get_leads_summary(), get_leads_detail()),
202
  outputs=[leads_sum, leads_det])
203
 
204
- # ─── Insights ───────────────────────
205
  with gr.Tab("Insights"):
206
  ins_btn = gr.Button("Generate Insights")
207
  ins_tbl = gr.Dataframe()
208
  ins_btn.click(fn=compute_insights, outputs=ins_tbl)
209
 
210
- # ─── User Management ────────────────
211
  with gr.Tab("User Management"):
212
  gr.Markdown("## πŸ‘€ Manage Users\nEdit/add/remove rows, then click **Save Users**.")
213
- users_df = gr.Dataframe(load_users(), interactive=True)
214
- save_btn = gr.Button("Save Users")
215
- save_stat = gr.Textbox()
216
  save_btn.click(fn=save_users, inputs=users_df, outputs=save_stat)
217
 
218
  app.launch()
 
6
  from datetime import datetime, timedelta
7
 
8
  # -------------------- CONFIG --------------------
9
+ SHEET_URL = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
10
+ CREDS_JSON = "deep-mile-461309-t8-0e90103411e0.json"
11
 
12
  # -------------------- AUTH --------------------
13
  scope = ["https://spreadsheets.google.com/feeds","https://www.googleapis.com/auth/drive"]
14
  creds = ServiceAccountCredentials.from_json_keyfile_name(CREDS_JSON, scope)
15
  client = gspread.authorize(creds)
16
 
17
+ # -------------------- SHEET LOADING --------------------
18
  def normalize_columns(df):
19
  df.columns = df.columns.str.strip().str.title()
20
  return df
21
 
22
+ def load_sheet_df(tab_name):
23
+ """Load a worksheet into a normalized DataFrame."""
24
  try:
25
+ ws = client.open_by_url(SHEET_URL).worksheet(tab_name)
26
  df = pd.DataFrame(ws.get_all_records())
27
  return normalize_columns(df)
28
  except Exception as e:
29
  return pd.DataFrame([{"Error": str(e)}])
30
 
31
+ def find_rep_column(df):
32
+ """Return the first column whose name contains 'rep' (case-insensitive)."""
33
+ for c in df.columns:
34
+ if "rep" in c.lower():
35
+ return c
36
+ return None
37
+
38
+ def rep_options(tab_name):
39
+ """Build a dropdown list of all reps in the given sheet."""
40
+ df = load_sheet_df(tab_name)
41
+ rep_col = find_rep_column(df)
42
+ if rep_col:
43
  return sorted(df[rep_col].dropna().unique().tolist())
44
  return []
45
 
 
49
  start = today - timedelta(days=today.weekday())
50
  return start.date(), (start + timedelta(days=6)).date()
51
 
52
+ def filter_week(df, date_col, rep_col, rep):
53
  df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
54
+ start, end = get_current_week_range()
55
  out = df[(df[date_col] >= start) & (df[date_col] <= end)]
56
  if rep and rep_col in out.columns:
57
  out = out[out[rep_col] == rep]
 
68
  out = out[out[rep_col] == rep]
69
  return out
70
 
71
+ # -------------------- CALLS REPORT --------------------
72
  def get_calls(rep=None):
73
  df = load_sheet_df("Calls")
74
  if "Call Date" not in df.columns:
75
  return pd.DataFrame([{"Error":"Missing 'Call Date'"}])
76
+ rep_col = find_rep_column(df)
77
+ return filter_week(df, "Call Date", rep_col, rep)
78
 
79
  def get_calls_summary(rep=None):
80
  df = get_calls(rep)
81
  if "Error" in df.columns or df.empty:
82
  return df
83
+ rep_col = find_rep_column(df)
84
+ return df.groupby(rep_col).size().reset_index(name="Count")
85
 
86
  def search_calls_by_date(y,m,d,rep):
87
  df = load_sheet_df("Calls")
88
  if "Call Date" not in df.columns:
89
  return pd.DataFrame([{"Error":"Missing 'Call Date'"}])
90
+ rep_col = find_rep_column(df)
91
+ return filter_date(df, "Call Date", rep_col, y,m,d, rep)
92
 
93
+ # -------------------- APPOINTMENTS REPORT --------------------
94
  def get_appointments(rep=None):
95
  df = load_sheet_df("Appointments")
96
  if "Appointment Date" not in df.columns:
97
  return pd.DataFrame([{"Error":"Missing 'Appointment Date'"}])
98
+ rep_col = find_rep_column(df)
99
+ return filter_week(df, "Appointment Date", rep_col, rep)
100
 
101
  def get_appointments_summary(rep=None):
102
  df = get_appointments(rep)
103
  if "Error" in df.columns or df.empty:
104
  return df
105
+ rep_col = find_rep_column(df)
106
+ return df.groupby(rep_col).size().reset_index(name="Count")
107
 
108
  def search_appointments_by_date(y,m,d,rep):
109
  df = load_sheet_df("Appointments")
110
  if "Appointment Date" not in df.columns:
111
  return pd.DataFrame([{"Error":"Missing 'Appointment Date'"}])
112
+ rep_col = find_rep_column(df)
113
+ return filter_date(df, "Appointment Date", rep_col, y,m,d, rep)
114
 
115
+ # -------------------- APPOINTED LEADS --------------------
116
  def get_leads_detail():
117
  df = load_sheet_df("AllocatedLeads")
 
 
118
  return df
119
 
120
  def get_leads_summary():
121
  df = get_leads_detail()
122
+ rep_col = find_rep_column(df) or "Assigned Rep"
123
+ if rep_col not in df.columns:
124
+ return pd.DataFrame([{"Error":"Missing rep column in leads"}])
125
+ return df.groupby(rep_col).size().reset_index(name="Leads Count")
126
 
127
  # -------------------- INSIGHTS --------------------
128
  def compute_insights():
 
 
 
 
 
 
129
  calls = get_calls()
130
  appts = get_appointments()
131
+ leads = get_leads_detail()
132
+ def top(df, col):
133
+ if "Error" in df.columns or df.empty or col not in df.columns:
134
+ return "N/A"
135
+ s = df.groupby(col).size()
136
+ return s.idxmax() if not s.empty else "N/A"
137
+
138
+ rep_calls = find_rep_column(calls)
139
+ rep_appts = find_rep_column(appts)
140
+ rep_leads = find_rep_column(leads)
141
 
142
  return pd.DataFrame([
143
+ {"Metric":"Most Calls This Week", "Rep": top(calls, rep_calls)},
144
+ {"Metric":"Most Appointments This Week", "Rep": top(appts, rep_appts)},
145
+ {"Metric":"Most Leads Allocated", "Rep": top(leads, rep_leads)},
146
  ])
147
 
148
  # -------------------- USER MANAGEMENT --------------------
149
  def load_users():
150
+ df = load_sheet_df("Users")
151
  wanted = [
152
+ "Id","Email","Name","Business","Role",
153
+ "Daily Phone Call Target","Daily Phone Appointment Target",
154
+ "Daily Quote Number Target","Daily Quote Revenue Target",
155
+ "Weekly Phone Call Target","Weekly Phone Appointment Target",
156
+ "Weekly Quote Number Target","Weekly Quote Revenue Target",
157
+ "Monthly Phone Call Target","Monthly Phone Appointment Target",
158
+ "Monthly Quote Number Target","Monthly Quote Revenue Target",
159
+ "Monthly Sales Revenue Target"
160
  ]
161
+ cols = [c for c in wanted if c in df.columns]
162
  return df[cols]
163
 
164
  def save_users(df):
 
167
  set_with_dataframe(ws, df)
168
  return "βœ… Users saved!"
169
 
170
+ # -------------------- GRADIO LAYOUT --------------------
171
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
172
  gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
173
 
174
+ # Calls Tab
175
  with gr.Tab("Calls Report"):
176
+ rep_calls = gr.Dropdown("Optional Rep Filter",
177
+ choices=rep_options("Calls"), allow_custom_value=True)
178
+ calls_btn = gr.Button("Load Current Week Calls")
179
+ calls_sum = gr.Dataframe(label="πŸ“Š Calls by Rep")
180
+ calls_det = gr.Dataframe(label="πŸ”Ž Detailed Calls")
181
+ calls_btn.click(lambda r: (get_calls_summary(r), get_calls(r)),
182
  inputs=rep_calls, outputs=[calls_sum, calls_det])
183
 
184
+ gr.Markdown("### πŸ” Search Calls by Specific Date")
185
  y1,m1,d1 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
186
+ rep1 = gr.Dropdown("Optional Rep Filter",
187
+ choices=rep_options("Calls"), allow_custom_value=True)
188
+ calls_dt_btn = gr.Button("Search Calls by Date")
189
  calls_dt_tbl = gr.Dataframe()
190
  calls_dt_btn.click(fn=search_calls_by_date,
191
+ inputs=[y1,m1,d1,rep1], outputs=calls_dt_tbl)
 
192
 
193
+ # Appointments Tab
194
  with gr.Tab("Appointments Report"):
195
+ rep_appt = gr.Dropdown("Optional Rep Filter",
196
+ choices=rep_options("Appointments"), allow_custom_value=True)
197
+ appt_btn = gr.Button("Load Current Week Appointments")
198
+ appt_sum = gr.Dataframe(label="πŸ“Š Appts by Rep")
199
+ appt_det = gr.Dataframe(label="πŸ”Ž Detailed Appts")
200
+ appt_btn.click(lambda r: (get_appointments_summary(r), get_appointments(r)),
201
  inputs=rep_appt, outputs=[appt_sum, appt_det])
202
 
203
+ gr.Markdown("### πŸ” Search Appts by Specific Date")
204
  y2,m2,d2 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
205
+ rep2 = gr.Dropdown("Optional Rep Filter",
206
+ choices=rep_options("Appointments"), allow_custom_value=True)
207
+ appt_dt_btn = gr.Button("Search Appointments by Date")
208
+ appt_dt_sum = gr.Dataframe(label="πŸ“Š Appts Summary by Rep")
209
+ appt_dt_det = gr.Dataframe(label="πŸ”Ž Detailed Appts")
210
  appt_dt_btn.click(
211
+ lambda y,m,d,r: (
212
+ (lambda df: df.groupby(find_rep_column(df)).size().reset_index(name="Count"))
213
+ (search_appointments_by_date(y,m,d,r)),
214
  search_appointments_by_date(y,m,d,r)
215
  ),
216
  inputs=[y2,m2,d2,rep2],
217
  outputs=[appt_dt_sum, appt_dt_det]
218
  )
219
 
220
+ # Appointed Leads Tab
221
  with gr.Tab("Appointed Leads"):
222
  leads_btn = gr.Button("View Appointed Leads")
223
  leads_sum = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
224
  leads_det = gr.Dataframe(label="πŸ”Ž Detailed Leads")
225
+ leads_btn.click(lambda: (get_leads_summary(), get_leads_detail()),
226
  outputs=[leads_sum, leads_det])
227
 
228
+ # Insights Tab
229
  with gr.Tab("Insights"):
230
  ins_btn = gr.Button("Generate Insights")
231
  ins_tbl = gr.Dataframe()
232
  ins_btn.click(fn=compute_insights, outputs=ins_tbl)
233
 
234
+ # User Management Tab
235
  with gr.Tab("User Management"):
236
  gr.Markdown("## πŸ‘€ Manage Users\nEdit/add/remove rows, then click **Save Users**.")
237
+ users_df = gr.Dataframe(load_users(), interactive=True)
238
+ save_btn = gr.Button("Save Users")
239
+ save_stat= gr.Textbox()
240
  save_btn.click(fn=save_users, inputs=users_df, outputs=save_stat)
241
 
242
  app.launch()