(20260309) Added new 'mode' for formatting the muster roll'.

This commit is contained in:
2026-03-09 17:25:35 +05:30
parent c3ab2e4d9a
commit 4350435a01
8 changed files with 94 additions and 16 deletions
+12 -1
View File
@@ -187,7 +187,8 @@ async def muster_roll_report_generate(
success = False success = False
report_data = None report_data = None
# Figure out the paths: # Figure out the paths,
# and read the records:
proj_dir = files.get_parent_directory( proj_dir = files.get_parent_directory(
files.get_file_directory(include_filename = False), files.get_file_directory(include_filename = False),
depth = 4 depth = 4
@@ -201,6 +202,16 @@ async def muster_roll_report_generate(
# Note down the status of success or failure: # Note down the status of success or failure:
success = True if report_data else False success = True if report_data else False
# format the report as required:
if success:
if inbound_data.mode == "array":
pass # ... already an array
elif inbound_data.mode == "map":
report_data["report"] = {
r["UserID"]: {k: v for k,v in r.items if k != "User ID"}
for r in report_data["report"]
}
# ┳┓ # ┳┓
# ┣┫┏┓┏┏┓┏┓┏┓┏┏┓ # ┣┫┏┓┏┏┓┏┓┏┓┏┏┓
# ┛┗┗ ┛┣┛┗┛┛┗┛┗ # ┛┗┗ ┛┣┛┗┛┛┗┛┗
@@ -84,6 +84,11 @@ class CosecMusterRollReportRequestData(BaseModel):
frozen = True, frozen = True,
) )
mode: Literal["array", "map"] = Field(
description = "The format in which the response is desired.",
frozen = True,
)
# ┏┓ ┏• # ┏┓ ┏•
# ┃ ┏┓┏┓╋┓┏┓ # ┃ ┏┓┏┓╋┓┏┓
# ┗┛┗┛┛┗┛┗┗┫ # ┗┛┗┛┛┗┛┗┗┫
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,54 @@
from utils_v2.string import json
from scripts import common
from tcaoff.async_tcaoff import AsyncTheCAOffice
import asyncio
import datetime
# Explicitly mention the expected file paths for other devs to maintain:
print("PROJ. DIR. :", common.PROJ_DIR)
print("COSEC CREDS :", common.COSEC_CREDS_FILE)
print("TCAOFF CREDS:", common.TCAOFF_CREDS_FILE)
# Read required credentials:
cosec_creds = json.from_file(common.COSEC_CREDS_FILE)
tcaoff_creds = json.from_file(common.TCAOFF_CREDS_FILE)
# Create the clients:
tcaoff_client = AsyncTheCAOffice(
username = tcaoff_creds["creds"]["username"],
password = tcaoff_creds["creds"]["password"],
debug = True,
debug_only_errors = False,
)
async def main():
# Ensure login:
if not await tcaoff_client.login():
return
# Get the data:
raw_records = await tcaoff_client.attendance_register(
target_month = datetime.datetime.now(),
raise_exception = True
)
# Format the data for preview:
formatted_records = []
for r in raw_records:
cosec_data = json.from_string(r.get("json_notes", "{}")).get("cosec", {})
if cosec_data:
cosec_data.update({
"cosecId": r["pseudonym"],
"tcaoffId": r["user_id"],
})
formatted_records.append(cosec_data)
# Show the formatted data for debugging:
print(f"RECORDS ({len(formatted_records)}):", json.to_string(formatted_records))
print(f"Found {len(formatted_records)} record(s).")
# Log out:
await tcaoff_client.logout()
asyncio.run(main())
+7 -5
View File
@@ -620,14 +620,16 @@ def compute_work_done(
work_ot_seconds = max(0.0, work_seconds - min_work_seconds) work_ot_seconds = max(0.0, work_seconds - min_work_seconds)
# Finally, compute the work status. # Finally, compute the work status.
# 'A' --> Absent # 'A' ----> Absent
# 'H' --> Half Day # 'H' ----> Holiday
# 'P' --> Present (Full Day) # 'HD1' --> Half Day (1st Half)
# 'OT' -> Overtime # 'HD2' --> Half Day (2nd Half)
# 'P' ----> Present (Full Day)
# 'OT' ---> Overtime
work_hours = work_seconds / (60 * 60) work_hours = work_seconds / (60 * 60)
if work_hours > 10.0: work_status = "OT" if work_hours > 10.0: work_status = "OT"
elif 7.5 < work_hours <= 10.0: work_status = "P" elif 7.5 < work_hours <= 10.0: work_status = "P"
elif 4.5 < work_hours <= 7.5: work_status = "H" elif 4.5 < work_hours <= 7.5: work_status = "HD1"
else: work_status = "A" else: work_status = "A"
# Save the data: # Save the data:
+1 -1
View File
@@ -351,7 +351,7 @@ if __name__ == "__main__":
import argparse import argparse
ap = argparse.ArgumentParser() ap = argparse.ArgumentParser()
ap.add_argument( ap.add_argument(
"--test", "--test", "--test-mode",
action = "store_true", action = "store_true",
default = False, default = False,
) )
+13 -7
View File
@@ -604,7 +604,7 @@ class AsyncTheCAOffice:
async def attendance_mark( async def attendance_mark(
self, self,
user_id: int, user_id: int,
status: Literal["P", "H", "A", "OT"], status: Literal["A", "H", "HD1", "HD2", "P", "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, json_notes: dict = None,
@@ -615,10 +615,12 @@ class AsyncTheCAOffice:
Add a new department. Add a new department.
:param user_id: The id of the user whose attendance is being marked. :param user_id: The id of the user whose attendance is being marked.
:param status: The status of the attendance. :param status: The status of the attendance.
1. "P" for present, 1. "A" for absent,
2. "H" for half-day, 2. "H" for holiday,
3. "A" for absent, 3. "HD1" for half-day (1st half),
4. "OT" for over-time. 4. "HD2" for half-day (2nd half),
5. "P" for present,
6. "OT" for over-time.
:param over_time: The amount of over-time work in hours. :param over_time: The amount of over-time work in hours.
:param attendance_date: The date of the attendance. If not given, today's date will be used. :param attendance_date: The date of the attendance. If not given, today's date will be used.
:param json_notes: Optional notes about the attendance. :param json_notes: Optional notes about the attendance.
@@ -683,6 +685,7 @@ class AsyncTheCAOffice:
async def attendance_register( async def attendance_register(
self, self,
target_month: datetime.datetime, target_month: datetime.datetime,
mode: Literal["month", "date"] = "month",
raise_exception: bool = False, raise_exception: bool = False,
) -> List[dict] | None: ) -> List[dict] | None:
@@ -690,6 +693,7 @@ class AsyncTheCAOffice:
To get the whole attendance register for a month for all the employees of an entity. To get the whole attendance register for a month for all the employees of an entity.
:param target_month: The datetime which indicates the year and month in which the attendance needs to be :param target_month: The datetime which indicates the year and month in which the attendance needs to be
checked. checked.
:param mode: The mode of the attendance filtering.
:param raise_exception: Whether to raise any exceptions, or to suppress them. :param raise_exception: Whether to raise any exceptions, or to suppress them.
:return: The attendance register records if successful, else None. :return: The attendance register records if successful, else None.
""" """
@@ -700,11 +704,13 @@ class AsyncTheCAOffice:
try: try:
# Make the API call: # Make the API call:
json_payload = {"month": target_month.strftime("%Y-%m-%d")}
response = await self._http_client.post( response = await self._http_client.post(
url = self.ATTENDANCE_REGISTER_URL, url = self.ATTENDANCE_REGISTER_URL,
headers = {"X-Session-Token": self.__session_token}, headers = {"X-Session-Token": self.__session_token},
json = json_payload, json = {
"month": target_month.strftime("%Y-%m-%d"),
"mode": mode
},
) )
# If the call succeeded: # If the call succeeded: