(20260119) Attendance now captures total hours, over-time hours, first in time, and last out time.
This commit is contained in:
+12
-2
@@ -276,7 +276,7 @@ def sync_teams_to_tcaoff(
|
|||||||
role = (cosec_team.get("Grade Name") or "Unknown").strip(),
|
role = (cosec_team.get("Grade Name") or "Unknown").strip(),
|
||||||
username = tcaoff_username,
|
username = tcaoff_username,
|
||||||
password = "Vispl@123",
|
password = "Vispl@123",
|
||||||
application_notes = {"cosec": cosec_team}
|
applicant_notes = {"cosec": cosec_team}
|
||||||
)
|
)
|
||||||
# response["total"] += 1
|
# response["total"] += 1
|
||||||
if success: response["success"] += 1
|
if success: response["success"] += 1
|
||||||
@@ -397,6 +397,10 @@ def sync_attendance_to_tcaoff(
|
|||||||
"work_date": last_dt
|
"work_date": last_dt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add fixed known details:
|
||||||
|
user_id_to_time[user_id]["first_in"] = first_in
|
||||||
|
user_id_to_time[user_id]["last_out"] = last_out
|
||||||
|
|
||||||
print("\n")
|
print("\n")
|
||||||
print("Result:")
|
print("Result:")
|
||||||
print("------")
|
print("------")
|
||||||
@@ -448,7 +452,7 @@ def sync_attendance_to_tcaoff(
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Update the attendance on TCAOFF:
|
# Update the attendance on TCAOFF:
|
||||||
hours_worked = work["work_seconds"] / (60 * 60)
|
hours_worked = work["work_seconds"] // (60 * 60)
|
||||||
if hours_worked > 10.0: status = "OT"
|
if hours_worked > 10.0: status = "OT"
|
||||||
elif 7.5 < hours_worked <= 10.0: status = "P"
|
elif 7.5 < hours_worked <= 10.0: status = "P"
|
||||||
elif 2.5 < hours_worked <= 5.0: status = "H"
|
elif 2.5 < hours_worked <= 5.0: status = "H"
|
||||||
@@ -460,6 +464,11 @@ def sync_attendance_to_tcaoff(
|
|||||||
status = status,
|
status = status,
|
||||||
over_time = max(0.0, hours_worked - 10.0),
|
over_time = max(0.0, hours_worked - 10.0),
|
||||||
attendance_date = work["work_date"],
|
attendance_date = work["work_date"],
|
||||||
|
json_notes = {
|
||||||
|
"totHours": hours_worked,
|
||||||
|
"firstIn": work["first_in"],
|
||||||
|
"lastOut": work["last_out"],
|
||||||
|
}
|
||||||
)
|
)
|
||||||
if success: response["success"] += 1
|
if success: response["success"] += 1
|
||||||
else: response["fail"] += 1
|
else: response["fail"] += 1
|
||||||
@@ -935,6 +944,7 @@ if __name__ == "__main__":
|
|||||||
"deptAdd": "https://api.thecaoffice.com/commons/departments/add",
|
"deptAdd": "https://api.thecaoffice.com/commons/departments/add",
|
||||||
"teamList": "https://api.thecaoffice.com/team/list",
|
"teamList": "https://api.thecaoffice.com/team/list",
|
||||||
"teamAdd": "https://api.thecaoffice.com/team/add",
|
"teamAdd": "https://api.thecaoffice.com/team/add",
|
||||||
|
"teamUpdate": "https://api.thecaoffice.com/team/update",
|
||||||
"attendanceList": "https://api.thecaoffice.com/user/attendance/register",
|
"attendanceList": "https://api.thecaoffice.com/user/attendance/register",
|
||||||
"attendanceMark": "https://api.thecaoffice.com/user/attendance/mark"
|
"attendanceMark": "https://api.thecaoffice.com/user/attendance/mark"
|
||||||
}
|
}
|
||||||
|
|||||||
+77
-6
@@ -376,7 +376,7 @@ def team_add(
|
|||||||
role: str,
|
role: str,
|
||||||
username: str,
|
username: str,
|
||||||
password: str,
|
password: str,
|
||||||
application_notes: dict | list | str = None
|
applicant_notes: dict | list | str = None
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -391,13 +391,13 @@ def team_add(
|
|||||||
:param role: The role of the team member in the organization.
|
:param role: The role of the team member in the organization.
|
||||||
:param username: The unique username of the team member. Cannot be the same as anyone else.
|
:param username: The unique username of the team member. Cannot be the same as anyone else.
|
||||||
:param password: The password for this team member's login.
|
:param password: The password for this team member's login.
|
||||||
:param application_notes: Optional notes about the team member.
|
:param applicant_notes: Optional notes about the team member.
|
||||||
:return: True if successful, else False.
|
:return: True if successful, else False.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Ensure that JSON notes are converted to string:
|
# # Ensure that JSON notes are converted to string:
|
||||||
if isinstance(application_notes, (list, dict)):
|
# if isinstance(applicant_notes, (list, dict)):
|
||||||
application_notes = json.to_string(application_notes, no_space = True)
|
# applicant_notes = json.to_string(applicant_notes, no_space = True)
|
||||||
|
|
||||||
# Make the API call:
|
# Make the API call:
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
@@ -414,7 +414,7 @@ def team_add(
|
|||||||
"username": username,
|
"username": username,
|
||||||
"password": password,
|
"password": password,
|
||||||
"hierarchy": 1,
|
"hierarchy": 1,
|
||||||
"applicantNotes": application_notes
|
"applicantNotes": applicant_notes
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -437,12 +437,79 @@ def team_add(
|
|||||||
# ---------------------------------------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def team_update(
|
||||||
|
tcaoff_creds: dict,
|
||||||
|
user_id: int,
|
||||||
|
branch_id: int,
|
||||||
|
dept_id: int,
|
||||||
|
reporting_to: int | None,
|
||||||
|
team_name: str,
|
||||||
|
email: str,
|
||||||
|
phone_no: str,
|
||||||
|
role: str,
|
||||||
|
applicant_notes: dict | list | str = None
|
||||||
|
) -> bool:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Add a new team member.
|
||||||
|
:param tcaoff_creds: The set of credentials to use with the API call.
|
||||||
|
:param dept_id: The id of the department that this team member is working in.
|
||||||
|
:param branch_id: The id of the branch that this team member is working in.
|
||||||
|
:param reporting_to: The id of the senior to whom this team member will report.
|
||||||
|
:param team_name: The name of the team member. This is the full display name. Can be the same as others.
|
||||||
|
:param email: The email id of the team member.
|
||||||
|
:param phone_no: The phone no. of the team member.
|
||||||
|
:param role: The role of the team member in the organization.
|
||||||
|
:param applicant_notes: Optional notes about the team member.
|
||||||
|
:return: True if successful, else False.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# # Ensure that JSON notes are converted to string:
|
||||||
|
# if isinstance(applicant_notes, (list, dict)):
|
||||||
|
# applicant_notes = json.to_string(applicant_notes, no_space = True)
|
||||||
|
|
||||||
|
# Make the API call:
|
||||||
|
response = requests.post(
|
||||||
|
url = tcaoff_creds["urls"]["teamUpdate"],
|
||||||
|
headers = {"X-Session-Token": tcaoff_creds["creds"]["sessionToken"]},
|
||||||
|
json = {
|
||||||
|
"branchId": branch_id,
|
||||||
|
"idDepartment": dept_id,
|
||||||
|
"reportingTo": reporting_to,
|
||||||
|
"name": team_name,
|
||||||
|
"email": email,
|
||||||
|
"phoneNo": phone_no,
|
||||||
|
"role": role,
|
||||||
|
"applicantNotes": applicant_notes
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Debugging:
|
||||||
|
if response.status_code not in [200]:
|
||||||
|
response_json = response.json()
|
||||||
|
print("TCAOFF Team-Update:", json.to_string(response_json))
|
||||||
|
|
||||||
|
# If the call succeeded:
|
||||||
|
if response.status_code in [200]:
|
||||||
|
print(f"TCAOFF: team '{user_id}' updated")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# If the call failed:
|
||||||
|
else:
|
||||||
|
print(f"TCAOFF: team '{user_id}' NOT updated")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def attendance_mark(
|
def attendance_mark(
|
||||||
tcaoff_creds: dict,
|
tcaoff_creds: dict,
|
||||||
user_id: int,
|
user_id: int,
|
||||||
status: Literal["P", "H", "A", "OT"],
|
status: Literal["P", "H", "A", "OT"],
|
||||||
over_time: int | float,
|
over_time: int | float,
|
||||||
attendance_date: datetime.datetime | None = None,
|
attendance_date: datetime.datetime | None = None,
|
||||||
|
json_notes: dict = None
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -470,6 +537,10 @@ def attendance_mark(
|
|||||||
"ot": over_time,
|
"ot": over_time,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add JSON notes is needed:
|
||||||
|
if json_notes:
|
||||||
|
json_payload["jsonNotes"] = json_notes
|
||||||
|
|
||||||
# Make the API call:
|
# Make the API call:
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
url = tcaoff_creds["urls"]["attendanceMark"],
|
url = tcaoff_creds["urls"]["attendanceMark"],
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,49 @@
|
|||||||
|
"""
|
||||||
|
This is a one-time fix script where we need to fix some content of the accounts created.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Imports:
|
||||||
|
import os
|
||||||
|
import pandas as pd
|
||||||
|
from helpers import tcaoff
|
||||||
|
from utils_v2.string import json
|
||||||
|
from utils_v2.system import files
|
||||||
|
|
||||||
|
# File paths:
|
||||||
|
file_dir = files.get_file_directory(include_filename = False)
|
||||||
|
proj_dir = files.get_parent_directory(file_dir, depth = 1)
|
||||||
|
tcaoff_creds_file = os.path.join(proj_dir, "creds", "tcaoff.json")
|
||||||
|
|
||||||
|
# Load the creds:
|
||||||
|
tcaoff_creds = json.from_file(tcaoff_creds_file)
|
||||||
|
|
||||||
|
# Log in:
|
||||||
|
tcaoff.login(tcaoff_creds)
|
||||||
|
|
||||||
|
# Load the team list:
|
||||||
|
team_list = tcaoff.team_list(tcaoff_creds)
|
||||||
|
|
||||||
|
# Loop through the list,
|
||||||
|
# check if `applicantNotes` in `json_notes` is a string,
|
||||||
|
# if it is a string, convert it to a dict/list and update the user:
|
||||||
|
for team in team_list:
|
||||||
|
|
||||||
|
# Extract info:
|
||||||
|
json_notes = json.from_string(team.get("json_notes", {}))
|
||||||
|
app_notes = json_notes.get("applicantNotes")
|
||||||
|
|
||||||
|
# If the app notes are a string, update them:
|
||||||
|
if isinstance(app_notes, str):
|
||||||
|
app_notes = json.from_string(app_notes)
|
||||||
|
json_notes["applicantNotes"] = app_notes
|
||||||
|
team["json_notes"] = json.to_string(json_notes, no_space = True)
|
||||||
|
|
||||||
|
# Make a pandas DataFrame:
|
||||||
|
team_df = pd.DataFrame(team_list)
|
||||||
|
|
||||||
|
# Log out:
|
||||||
|
tcaoff.logout(tcaoff_creds)
|
||||||
|
|
||||||
|
# Show and save the DF:
|
||||||
|
print(team_df[:10].to_string())
|
||||||
|
team_df[["user_id", "json_notes"]].to_csv(r"C:\Users\Khushal P Soonderji\Downloads\20260116_cosec_team_fix.csv", index = False)
|
||||||
Reference in New Issue
Block a user