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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -94
app.py CHANGED
@@ -6,37 +6,54 @@ 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 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:
@@ -57,7 +74,7 @@ def filter_week(df, date_col, rep_col, rep):
57
  out = out[out[rep_col] == rep]
58
  return out
59
 
60
- def filter_date(df, date_col, rep_col, y,m,d, rep):
61
  try:
62
  target = datetime(int(y), int(m), int(d)).date()
63
  except:
@@ -68,156 +85,147 @@ def filter_date(df, date_col, rep_col, y,m,d, 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):
165
- ws = client.open_by_url(SHEET_URL).worksheet("Users")
166
  ws.clear()
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")
@@ -225,18 +233,18 @@ with gr.Blocks(title="Graffiti Admin Dashboard") as app:
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()
 
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",
14
+ "https://www.googleapis.com/auth/drive"]
15
  creds = ServiceAccountCredentials.from_json_keyfile_name(CREDS_JSON, scope)
16
  client = gspread.authorize(creds)
17
 
18
+ # -------------------- WORKSHEET HELPERS --------------------
19
+ def open_ws(name_substr):
20
+ """
21
+ Try to open a worksheet:
22
+ 1. exact match on title
23
+ 2. first sheet whose title contains name_substr (case-insensitive)
24
+ """
25
+ sh = client.open_by_url(SHEET_URL)
26
+ # 1) exact
27
+ try:
28
+ return sh.worksheet(name_substr)
29
+ except gspread.WorksheetNotFound:
30
+ pass
31
+
32
+ # 2) contains substring
33
+ for ws in sh.worksheets():
34
+ if name_substr.lower() in ws.title.lower():
35
+ return ws
36
+ raise gspread.WorksheetNotFound(f"No tab matching '{name_substr}'")
37
 
38
  def load_sheet_df(tab_name):
39
+ """Load & normalize the sheet named by tab_name (substring)."""
40
  try:
41
+ ws = open_ws(tab_name)
42
  df = pd.DataFrame(ws.get_all_records())
43
+ df.columns = df.columns.str.strip().str.title()
44
+ return df
45
  except Exception as e:
46
  return pd.DataFrame([{"Error": str(e)}])
47
 
48
  def find_rep_column(df):
49
+ """Find the first column whose header contains 'rep' (case-insensitive)."""
50
  for c in df.columns:
51
  if "rep" in c.lower():
52
  return c
53
  return None
54
 
55
  def rep_options(tab_name):
56
+ """Return a list of all unique reps in the given tab (or empty list)."""
57
  df = load_sheet_df(tab_name)
58
  rep_col = find_rep_column(df)
59
  if rep_col:
 
74
  out = out[out[rep_col] == rep]
75
  return out
76
 
77
+ def filter_date(df, date_col, rep_col, y, m, d, rep):
78
  try:
79
  target = datetime(int(y), int(m), int(d)).date()
80
  except:
 
85
  out = out[out[rep_col] == rep]
86
  return out
87
 
88
+ # -------------------- CALLS --------------------
89
  def get_calls(rep=None):
90
  df = load_sheet_df("Calls")
91
  if "Call Date" not in df.columns:
92
+ return pd.DataFrame([{"Error":"Missing 'Call Date' column"}])
93
+ return filter_week(df, "Call Date", find_rep_column(df), rep)
 
94
 
95
  def get_calls_summary(rep=None):
96
  df = get_calls(rep)
97
  if "Error" in df.columns or df.empty:
98
  return df
99
+ col = find_rep_column(df)
100
+ return df.groupby(col).size().reset_index(name="Count")
101
 
102
  def search_calls_by_date(y,m,d,rep):
103
  df = load_sheet_df("Calls")
104
  if "Call Date" not in df.columns:
105
+ return pd.DataFrame([{"Error":"Missing 'Call Date' column"}])
106
+ return filter_date(df, "Call Date", find_rep_column(df), y,m,d, rep)
 
107
 
108
+ # -------------------- APPOINTMENTS --------------------
109
  def get_appointments(rep=None):
110
  df = load_sheet_df("Appointments")
111
  if "Appointment Date" not in df.columns:
112
+ return pd.DataFrame([{"Error":"Missing 'Appointment Date' column"}])
113
+ return filter_week(df, "Appointment Date", find_rep_column(df), rep)
 
114
 
115
  def get_appointments_summary(rep=None):
116
  df = get_appointments(rep)
117
  if "Error" in df.columns or df.empty:
118
  return df
119
+ col = find_rep_column(df)
120
+ return df.groupby(col).size().reset_index(name="Count")
121
 
122
  def search_appointments_by_date(y,m,d,rep):
123
  df = load_sheet_df("Appointments")
124
  if "Appointment Date" not in df.columns:
125
+ return pd.DataFrame([{"Error":"Missing 'Appointment Date' column"}])
126
+ return filter_date(df, "Appointment Date", find_rep_column(df), y,m,d, rep)
 
127
 
128
  # -------------------- APPOINTED LEADS --------------------
129
  def get_leads_detail():
130
+ return load_sheet_df("Leads")
 
131
 
132
  def get_leads_summary():
133
  df = get_leads_detail()
134
+ col = find_rep_column(df) or "Assigned Rep"
135
+ if col not in df.columns:
136
  return pd.DataFrame([{"Error":"Missing rep column in leads"}])
137
+ return df.groupby(col).size().reset_index(name="Leads Count")
138
 
139
  # -------------------- INSIGHTS --------------------
140
  def compute_insights():
141
  calls = get_calls()
142
  appts = get_appointments()
143
  leads = get_leads_detail()
144
+
145
+ def top(df):
146
+ col = find_rep_column(df)
147
+ if "Error" in df.columns or df.empty or not col:
148
  return "N/A"
149
  s = df.groupby(col).size()
150
  return s.idxmax() if not s.empty else "N/A"
151
 
 
 
 
 
152
  return pd.DataFrame([
153
+ {"Metric":"Most Calls This Week", "Rep": top(calls)},
154
+ {"Metric":"Most Appointments This Week", "Rep": top(appts)},
155
+ {"Metric":"Most Leads Allocated", "Rep": top(leads)},
156
  ])
157
 
158
  # -------------------- USER MANAGEMENT --------------------
159
  def load_users():
160
  df = load_sheet_df("Users")
161
+ want = [
162
+ "Id","Email","Name","Business","Role",
163
+ "Daily Phone Call Target","Daily Phone Appointment Target",
164
+ "Daily Quote Number Target","Daily Quote Revenue Target",
165
+ "Weekly Phone Call Target","Weekly Phone Appointment Target",
166
+ "Weekly Quote Number Target","Weekly Quote Revenue Target",
167
+ "Monthly Phone Call Target","Monthly Phone Appointment Target",
168
+ "Monthly Quote Number Target","Monthly Quote Revenue Target",
169
+ "Monthly Sales Revenue Target"
170
  ]
171
+ cols = [c for c in want if c in df.columns]
172
  return df[cols]
173
 
174
  def save_users(df):
175
+ ws = open_ws("Users")
176
  ws.clear()
177
  set_with_dataframe(ws, df)
178
  return "βœ… Users saved!"
179
 
180
+ # -------------------- GRADIO UI --------------------
181
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
182
  gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
183
 
184
+ # --- Calls ---
185
  with gr.Tab("Calls Report"):
186
+ rc = rep_options("Calls")
187
+ rep_calls = gr.Dropdown(rc or ["(no reps found)"],
188
+ label="Optional Rep Filter",
189
+ allow_custom_value=True)
190
+ calls_btn = gr.Button("Load Current Week Calls")
191
+ calls_sum = gr.Dataframe(label="πŸ“Š Calls by Rep")
192
+ calls_det = gr.Dataframe(label="πŸ”Ž Detailed Calls")
193
  calls_btn.click(lambda r: (get_calls_summary(r), get_calls(r)),
194
  inputs=rep_calls, outputs=[calls_sum, calls_det])
195
 
196
+ gr.Markdown("### πŸ” Search Calls by Date")
197
+ y1,m1,d1 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
198
+ rep1 = gr.Dropdown(rc or ["(no reps found)"],
199
+ label="Optional Rep Filter", allow_custom_value=True)
200
  calls_dt_btn = gr.Button("Search Calls by Date")
201
  calls_dt_tbl = gr.Dataframe()
202
+ calls_dt_btn.click(search_calls_by_date,
203
  inputs=[y1,m1,d1,rep1], outputs=calls_dt_tbl)
204
 
205
+ # --- Appointments ---
206
  with gr.Tab("Appointments Report"):
207
+ ra = rep_options("Appointments")
208
+ rep_appt = gr.Dropdown(ra or ["(no reps found)"],
209
+ label="Optional Rep Filter",
210
+ allow_custom_value=True)
211
  appt_btn = gr.Button("Load Current Week Appointments")
212
  appt_sum = gr.Dataframe(label="πŸ“Š Appts by Rep")
213
  appt_det = gr.Dataframe(label="πŸ”Ž Detailed Appts")
214
  appt_btn.click(lambda r: (get_appointments_summary(r), get_appointments(r)),
215
  inputs=rep_appt, outputs=[appt_sum, appt_det])
216
 
217
+ gr.Markdown("### πŸ” Search Appts by Date")
218
+ y2,m2,d2 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
219
+ rep2 = gr.Dropdown(ra or ["(no reps found)"],
220
+ label="Optional Rep Filter", allow_custom_value=True)
221
+ appt_dt_btn = gr.Button("Search Appts by Date")
222
+ appt_dt_sum = gr.Dataframe(label="πŸ“Š Appts by Rep")
223
  appt_dt_det = gr.Dataframe(label="πŸ”Ž Detailed Appts")
224
+ appt_dt_btn.click(search_appointments_by_date,
225
+ inputs=[y2,m2,d2,rep2],
226
+ outputs=appt_dt_det)
227
+
228
+ # --- Appointed Leads ---
 
 
 
 
 
 
229
  with gr.Tab("Appointed Leads"):
230
  leads_btn = gr.Button("View Appointed Leads")
231
  leads_sum = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
 
233
  leads_btn.click(lambda: (get_leads_summary(), get_leads_detail()),
234
  outputs=[leads_sum, leads_det])
235
 
236
+ # --- Insights ---
237
  with gr.Tab("Insights"):
238
  ins_btn = gr.Button("Generate Insights")
239
  ins_tbl = gr.Dataframe()
240
+ ins_btn.click(compute_insights, outputs=ins_tbl)
241
 
242
+ # --- User Management ---
243
  with gr.Tab("User Management"):
244
+ gr.Markdown("## πŸ‘€ Manage Users β€” edit/add/remove, then Save")
245
  users_df = gr.Dataframe(load_users(), interactive=True)
246
  save_btn = gr.Button("Save Users")
247
+ save_out = gr.Textbox()
248
+ save_btn.click(save_users, inputs=users_df, outputs=save_out)
249
 
250
  app.launch()