Files changed (1) hide show
  1. app.py +100 -96
app.py CHANGED
@@ -1,13 +1,17 @@
 
 
 
1
  import gradio as gr
2
  import pandas as pd
3
  import os
4
- from datetime import datetime, timedelta
5
 
6
 
7
  # ---------------- CONFIG ---------------- #
8
 
9
  STAFF_FILE = "staff_details.xlsx"
10
  PERMISSION_FILE = "permissions.xlsx"
 
11
 
12
  ADMIN_USER = "admin"
13
  ADMIN_PASS = "admin123"
@@ -16,6 +20,7 @@ ADMIN_PASS = "admin123"
16
  # ---------------- INIT ---------------- #
17
 
18
  if not os.path.exists(PERMISSION_FILE):
 
19
  df = pd.DataFrame(columns=[
20
  "StaffID",
21
  "Name",
@@ -26,6 +31,7 @@ if not os.path.exists(PERMISSION_FILE):
26
  "Reason",
27
  "SubmittedOn"
28
  ])
 
29
  df.to_excel(PERMISSION_FILE, index=False)
30
 
31
 
@@ -41,49 +47,22 @@ def load_permissions():
41
 
42
  # ---------------- VALIDATORS ---------------- #
43
 
44
- # Date: Only Today / Tomorrow / Day after Tomorrow
45
- def validate_date_range(date_str):
46
 
47
  try:
48
- d = datetime.strptime(date_str, "%d/%m/%Y").date()
 
49
  except:
50
- return False, "❌ Date format must be DD/MM/YYYY"
51
-
52
- today = datetime.today().date()
53
- max_day = today + timedelta(days=2)
54
-
55
- if d < today:
56
- return False, "❌ Past date not allowed"
57
-
58
- if d > max_day:
59
- return False, "❌ Apply only within 2 days"
60
-
61
- return True, ""
62
 
63
 
64
- # Time: 08:45 - 17:20 and exactly 1 hour
65
- def validate_time_range(f, t):
66
 
67
  try:
68
- f_time = datetime.strptime(f, "%H:%M")
69
- t_time = datetime.strptime(t, "%H:%M")
70
  except:
71
- return False, "❌ Time format must be HH:MM (24-hour)"
72
-
73
- min_time = datetime.strptime("08:45", "%H:%M")
74
- max_time = datetime.strptime("17:20", "%H:%M")
75
-
76
- # Check range
77
- if f_time < min_time or t_time > max_time:
78
- return False, "❌ Time allowed: 08:45 to 17:20 only"
79
-
80
- # Check 1 hour duration
81
- diff = (t_time - f_time).total_seconds() / 3600
82
-
83
- if diff != 1:
84
- return False, "❌ Permission must be exactly 1 hour"
85
-
86
- return True, ""
87
 
88
 
89
  # ---------------- STAFF FUNCTIONS ---------------- #
@@ -91,6 +70,7 @@ def validate_time_range(f, t):
91
  def fetch_staff(staff_id):
92
 
93
  df = load_staff()
 
94
  row = df[df["StaffID"] == staff_id]
95
 
96
  if row.empty:
@@ -100,6 +80,7 @@ def fetch_staff(staff_id):
100
  dept = row.iloc[0]["Department"]
101
 
102
  perms = load_permissions()
 
103
  count = len(perms[perms["StaffID"] == staff_id])
104
 
105
  return name, dept, str(count)
@@ -107,70 +88,58 @@ def fetch_staff(staff_id):
107
 
108
  def submit_permission(staff_id, date, f, t, reason):
109
 
110
- # Basic validation
111
  if staff_id.strip() == "":
112
  return "❌ Staff ID Required"
113
 
114
- if date.strip() == "":
115
- return "❌ Date Required"
116
 
117
- if f.strip() == "" or t.strip() == "":
118
- return "❌ Time Required"
119
 
120
  if reason.strip() == "":
121
  return "❌ Reason Required"
122
 
123
-
124
- # Date validation
125
- ok, msg = validate_date_range(date)
126
- if not ok:
127
- return msg
128
-
129
-
130
- # Time validation
131
- ok, msg = validate_time_range(f, t)
132
- if not ok:
133
- return msg
134
-
135
-
136
- # Staff validation
137
  staff = load_staff()
 
138
  row = staff[staff["StaffID"] == staff_id]
139
 
140
  if row.empty:
141
  return "❌ Invalid Staff ID"
142
 
143
-
144
  perms = load_permissions()
145
 
146
 
147
- # Same day check (max 2)
 
148
  same_day = perms[
149
  (perms["StaffID"] == staff_id) &
150
  (perms["Date"] == date)
151
  ]
152
 
153
  if len(same_day) == 1:
154
- return "⚠️ Second permission today β†’ Apply Leave"
155
 
156
  if len(same_day) >= 2:
157
  return "❌ Daily limit reached"
158
 
159
 
160
- # Monthly limit (2 only)
161
- m = date.split("/")[1]
162
- y = date.split("/")[2]
 
163
 
164
  same_month = perms[
165
  (perms["StaffID"] == staff_id) &
166
- (perms["Date"].str.contains(f"/{m}/{y}", na=False))
167
  ]
168
 
169
  if len(same_month) >= 2:
170
- return "❌ Monthly limit reached (2 only)"
171
 
172
 
173
- # Save
 
174
  name = row.iloc[0]["Name"]
175
  dept = row.iloc[0]["Department"]
176
 
@@ -187,7 +156,11 @@ def submit_permission(staff_id, date, f, t, reason):
187
  "SubmittedOn": now
188
  }
189
 
190
- perms = pd.concat([perms, pd.DataFrame([new_row])], ignore_index=True)
 
 
 
 
191
  perms.to_excel(PERMISSION_FILE, index=False)
192
 
193
  return "βœ… Permission Submitted Successfully"
@@ -196,6 +169,7 @@ def submit_permission(staff_id, date, f, t, reason):
196
  def delete_permission(staff_id, date):
197
 
198
  perms = load_permissions()
 
199
  before = len(perms)
200
 
201
  perms = perms[
@@ -208,7 +182,7 @@ def delete_permission(staff_id, date):
208
  if len(perms) == before:
209
  return "❌ No Record Found"
210
  else:
211
- return "βœ… Deleted"
212
 
213
 
214
  def clear_form():
@@ -217,10 +191,10 @@ def clear_form():
217
 
218
  # ---------------- ADMIN ---------------- #
219
 
220
- def admin_login(user, pwd):
221
 
222
- if user == ADMIN_USER and pwd == ADMIN_PASS:
223
- return gr.update(visible=True), "βœ… Login Successful"
224
 
225
  return gr.update(visible=False), "❌ Invalid Login"
226
 
@@ -233,54 +207,72 @@ def download_excel():
233
  return PERMISSION_FILE
234
 
235
 
236
- def monthly_report(month, year):
237
 
238
  perms = load_permissions()
239
 
240
  return perms[
241
- perms["Date"].str.contains(f"/{month}/{year}", na=False)
242
  ]
243
 
244
 
245
- def dept_report(dept):
246
 
247
  perms = load_permissions()
248
 
249
- return perms[perms["Department"] == dept]
250
 
251
 
252
  def reset_data():
253
 
254
  df = pd.DataFrame(columns=[
255
- "StaffID",
256
- "Name",
257
- "Department",
258
- "Date",
259
- "FromTime",
260
- "ToTime",
261
- "Reason",
262
- "SubmittedOn"
263
  ])
264
 
265
  df.to_excel(PERMISSION_FILE, index=False)
266
 
267
- return "βœ… All Data Cleared"
268
 
269
 
270
  # ================= UI ================= #
271
 
272
  with gr.Blocks() as app:
273
 
 
 
 
274
  gr.HTML("""
275
- <center>
276
- <h2>SRC, SASTRA</h2>
277
- <h3>Staff Permission Management System</h3>
278
- <hr>
279
- </center>
280
  """)
281
 
282
 
283
- # ---------------- STAFF TAB ---------------- #
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
 
285
  with gr.Tab("Staff Panel"):
286
 
@@ -300,8 +292,8 @@ with gr.Blocks() as app:
300
  with gr.Column():
301
 
302
  date = gr.Textbox(label="Date (DD/MM/YYYY)")
303
- f = gr.Textbox(label="From (HH:MM 24-hr)")
304
- t = gr.Textbox(label="To (HH:MM 24-hr)")
305
 
306
  reason = gr.Textbox(label="Reason", lines=3)
307
 
@@ -313,7 +305,8 @@ with gr.Blocks() as app:
313
  status = gr.Textbox(label="Status", interactive=False)
314
 
315
 
316
- # ---------------- ADMIN TAB ---------------- #
 
317
 
318
  with gr.Tab("Admin Panel"):
319
 
@@ -326,13 +319,14 @@ with gr.Blocks() as app:
326
 
327
  admin_box = gr.Column(visible=False)
328
 
 
329
  with admin_box:
330
 
331
  gr.Markdown("### πŸ“Š All Records")
332
 
333
  table = gr.Dataframe(interactive=False)
334
 
335
- refresh = gr.Button("Refresh")
336
 
337
 
338
  gr.Markdown("### πŸ“… Monthly Report")
@@ -361,14 +355,15 @@ with gr.Blocks() as app:
361
  file = gr.File()
362
 
363
 
364
- gr.Markdown("### ⚠️ Reset")
365
 
366
  reset = gr.Button("Reset All", variant="stop")
367
 
368
  reset_msg = gr.Textbox(interactive=False)
369
 
370
 
371
- # ---------------- EVENTS ---------------- #
 
372
 
373
  fetch.click(fetch_staff, staff_id, [name, dept, count])
374
 
@@ -383,7 +378,11 @@ with gr.Blocks() as app:
383
  clear.click(clear_form, outputs=[date, f, t, reason, status])
384
 
385
 
386
- login.click(admin_login, [admin_user, admin_pwd], [admin_box, msg])
 
 
 
 
387
 
388
  refresh.click(get_all_data, outputs=table)
389
 
@@ -396,4 +395,9 @@ with gr.Blocks() as app:
396
  reset.click(reset_data, outputs=reset_msg)
397
 
398
 
399
- app.launch()
 
 
 
 
 
 
1
+ # app.py
2
+ # Staff Permission Management System (HF + Gradio Ready)
3
+
4
  import gradio as gr
5
  import pandas as pd
6
  import os
7
+ from datetime import datetime
8
 
9
 
10
  # ---------------- CONFIG ---------------- #
11
 
12
  STAFF_FILE = "staff_details.xlsx"
13
  PERMISSION_FILE = "permissions.xlsx"
14
+ LOGO_FILE = "logo.jpg"
15
 
16
  ADMIN_USER = "admin"
17
  ADMIN_PASS = "admin123"
 
20
  # ---------------- INIT ---------------- #
21
 
22
  if not os.path.exists(PERMISSION_FILE):
23
+
24
  df = pd.DataFrame(columns=[
25
  "StaffID",
26
  "Name",
 
31
  "Reason",
32
  "SubmittedOn"
33
  ])
34
+
35
  df.to_excel(PERMISSION_FILE, index=False)
36
 
37
 
 
47
 
48
  # ---------------- VALIDATORS ---------------- #
49
 
50
+ def validate_date(d):
 
51
 
52
  try:
53
+ datetime.strptime(d, "%d/%m/%Y")
54
+ return True
55
  except:
56
+ return False
 
 
 
 
 
 
 
 
 
 
 
57
 
58
 
59
+ def validate_time(t):
 
60
 
61
  try:
62
+ datetime.strptime(t, "%H:%M")
63
+ return True
64
  except:
65
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
 
68
  # ---------------- STAFF FUNCTIONS ---------------- #
 
70
  def fetch_staff(staff_id):
71
 
72
  df = load_staff()
73
+
74
  row = df[df["StaffID"] == staff_id]
75
 
76
  if row.empty:
 
80
  dept = row.iloc[0]["Department"]
81
 
82
  perms = load_permissions()
83
+
84
  count = len(perms[perms["StaffID"] == staff_id])
85
 
86
  return name, dept, str(count)
 
88
 
89
  def submit_permission(staff_id, date, f, t, reason):
90
 
 
91
  if staff_id.strip() == "":
92
  return "❌ Staff ID Required"
93
 
94
+ if not validate_date(date):
95
+ return "❌ Date format: DD/MM/YYYY"
96
 
97
+ if not validate_time(f) or not validate_time(t):
98
+ return "❌ Time format: HH:MM"
99
 
100
  if reason.strip() == "":
101
  return "❌ Reason Required"
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  staff = load_staff()
104
+
105
  row = staff[staff["StaffID"] == staff_id]
106
 
107
  if row.empty:
108
  return "❌ Invalid Staff ID"
109
 
 
110
  perms = load_permissions()
111
 
112
 
113
+ # ---------- RULE 1: SAME DAY ---------- #
114
+
115
  same_day = perms[
116
  (perms["StaffID"] == staff_id) &
117
  (perms["Date"] == date)
118
  ]
119
 
120
  if len(same_day) == 1:
121
+ return "⚠️ Apply Leave (Second permission same day)"
122
 
123
  if len(same_day) >= 2:
124
  return "❌ Daily limit reached"
125
 
126
 
127
+ # ---------- RULE 2: MONTHLY LIMIT ---------- #
128
+
129
+ month = date.split("/")[1]
130
+ year = date.split("/")[2]
131
 
132
  same_month = perms[
133
  (perms["StaffID"] == staff_id) &
134
+ (perms["Date"].str.contains(f"/{month}/{year}", na=False))
135
  ]
136
 
137
  if len(same_month) >= 2:
138
+ return "❌ Monthly limit (Only 2 allowed)"
139
 
140
 
141
+ # ---------- SAVE ---------- #
142
+
143
  name = row.iloc[0]["Name"]
144
  dept = row.iloc[0]["Department"]
145
 
 
156
  "SubmittedOn": now
157
  }
158
 
159
+ perms = pd.concat(
160
+ [perms, pd.DataFrame([new_row])],
161
+ ignore_index=True
162
+ )
163
+
164
  perms.to_excel(PERMISSION_FILE, index=False)
165
 
166
  return "βœ… Permission Submitted Successfully"
 
169
  def delete_permission(staff_id, date):
170
 
171
  perms = load_permissions()
172
+
173
  before = len(perms)
174
 
175
  perms = perms[
 
182
  if len(perms) == before:
183
  return "❌ No Record Found"
184
  else:
185
+ return "βœ… Deleted Successfully"
186
 
187
 
188
  def clear_form():
 
191
 
192
  # ---------------- ADMIN ---------------- #
193
 
194
+ def admin_login(u, p):
195
 
196
+ if u == ADMIN_USER and p == ADMIN_PASS:
197
+ return gr.update(visible=True), "βœ… Login Success"
198
 
199
  return gr.update(visible=False), "❌ Invalid Login"
200
 
 
207
  return PERMISSION_FILE
208
 
209
 
210
+ def monthly_report(m, y):
211
 
212
  perms = load_permissions()
213
 
214
  return perms[
215
+ perms["Date"].str.contains(f"/{m}/{y}", na=False)
216
  ]
217
 
218
 
219
+ def dept_report(d):
220
 
221
  perms = load_permissions()
222
 
223
+ return perms[perms["Department"] == d]
224
 
225
 
226
  def reset_data():
227
 
228
  df = pd.DataFrame(columns=[
229
+ "StaffID", "Name", "Department",
230
+ "Date", "FromTime", "ToTime",
231
+ "Reason", "SubmittedOn"
 
 
 
 
 
232
  ])
233
 
234
  df.to_excel(PERMISSION_FILE, index=False)
235
 
236
+ return "βœ… All Data Reset"
237
 
238
 
239
  # ================= UI ================= #
240
 
241
  with gr.Blocks() as app:
242
 
243
+
244
+ # ---------- CSS ---------- #
245
+
246
  gr.HTML("""
247
+ <style>
248
+ .center-text {
249
+ text-align: center;
250
+ }
251
+ </style>
252
  """)
253
 
254
 
255
+ # ---------- HEADER ---------- #
256
+
257
+ with gr.Column():
258
+
259
+ gr.Image(
260
+ LOGO_FILE,
261
+ show_label=False,
262
+ height=120,
263
+ container=True
264
+ )
265
+
266
+ gr.Markdown(
267
+ "## SRC, SASTRA\n"
268
+ "### Staff Permission Management System",
269
+ elem_classes=["center-text"]
270
+ )
271
+
272
+ gr.Markdown("---")
273
+
274
+
275
+ # ================= STAFF TAB ================= #
276
 
277
  with gr.Tab("Staff Panel"):
278
 
 
292
  with gr.Column():
293
 
294
  date = gr.Textbox(label="Date (DD/MM/YYYY)")
295
+ f = gr.Textbox(label="From Time (HH:MM)")
296
+ t = gr.Textbox(label="To Time (HH:MM)")
297
 
298
  reason = gr.Textbox(label="Reason", lines=3)
299
 
 
305
  status = gr.Textbox(label="Status", interactive=False)
306
 
307
 
308
+
309
+ # ================= ADMIN TAB ================= #
310
 
311
  with gr.Tab("Admin Panel"):
312
 
 
319
 
320
  admin_box = gr.Column(visible=False)
321
 
322
+
323
  with admin_box:
324
 
325
  gr.Markdown("### πŸ“Š All Records")
326
 
327
  table = gr.Dataframe(interactive=False)
328
 
329
+ refresh = gr.Button("Refresh Table")
330
 
331
 
332
  gr.Markdown("### πŸ“… Monthly Report")
 
355
  file = gr.File()
356
 
357
 
358
+ gr.Markdown("### ⚠️ Reset System")
359
 
360
  reset = gr.Button("Reset All", variant="stop")
361
 
362
  reset_msg = gr.Textbox(interactive=False)
363
 
364
 
365
+
366
+ # ================= EVENTS ================= #
367
 
368
  fetch.click(fetch_staff, staff_id, [name, dept, count])
369
 
 
378
  clear.click(clear_form, outputs=[date, f, t, reason, status])
379
 
380
 
381
+ login.click(
382
+ admin_login,
383
+ [admin_user, admin_pwd],
384
+ [admin_box, msg]
385
+ )
386
 
387
  refresh.click(get_all_data, outputs=table)
388
 
 
395
  reset.click(reset_data, outputs=reset_msg)
396
 
397
 
398
+
399
+ # ================= LAUNCH ================= #
400
+
401
+ if __name__ == "__main__":
402
+
403
+ app.launch()