(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
report_data = None
# Figure out the paths:
# Figure out the paths,
# and read the records:
proj_dir = files.get_parent_directory(
files.get_file_directory(include_filename = False),
depth = 4
@@ -201,6 +202,16 @@ async def muster_roll_report_generate(
# Note down the status of success or failure:
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,
)
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)
# Finally, compute the work status.
# 'A' --> Absent
# 'H' --> Half Day
# 'P' --> Present (Full Day)
# 'OT' -> Overtime
# 'A' ----> Absent
# 'H' ----> Holiday
# 'HD1' --> Half Day (1st Half)
# 'HD2' --> Half Day (2nd Half)
# 'P' ----> Present (Full Day)
# 'OT' ---> Overtime
work_hours = work_seconds / (60 * 60)
if work_hours > 10.0: work_status = "OT"
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"
# Save the data:
+1 -1
View File
@@ -351,7 +351,7 @@ if __name__ == "__main__":
import argparse
ap = argparse.ArgumentParser()
ap.add_argument(
"--test",
"--test", "--test-mode",
action = "store_true",
default = False,
)
+13 -7
View File
@@ -604,7 +604,7 @@ class AsyncTheCAOffice:
async def attendance_mark(
self,
user_id: int,
status: Literal["P", "H", "A", "OT"],
status: Literal["A", "H", "HD1", "HD2", "P", "OT"],
over_time: int | float,
attendance_date: datetime.datetime | None = None,
json_notes: dict = None,
@@ -615,10 +615,12 @@ class AsyncTheCAOffice:
Add a new department.
:param user_id: The id of the user whose attendance is being marked.
:param status: The status of the attendance.
1. "P" for present,
2. "H" for half-day,
3. "A" for absent,
4. "OT" for over-time.
1. "A" for absent,
2. "H" for holiday,
3. "HD1" for half-day (1st half),
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 attendance_date: The date of the attendance. If not given, today's date will be used.
:param json_notes: Optional notes about the attendance.
@@ -683,6 +685,7 @@ class AsyncTheCAOffice:
async def attendance_register(
self,
target_month: datetime.datetime,
mode: Literal["month", "date"] = "month",
raise_exception: bool = False,
) -> 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.
:param target_month: The datetime which indicates the year and month in which the attendance needs to be
checked.
:param mode: The mode of the attendance filtering.
:param raise_exception: Whether to raise any exceptions, or to suppress them.
:return: The attendance register records if successful, else None.
"""
@@ -700,11 +704,13 @@ class AsyncTheCAOffice:
try:
# Make the API call:
json_payload = {"month": target_month.strftime("%Y-%m-%d")}
response = await self._http_client.post(
url = self.ATTENDANCE_REGISTER_URL,
headers = {"X-Session-Token": self.__session_token},
json = json_payload,
json = {
"month": target_month.strftime("%Y-%m-%d"),
"mode": mode
},
)
# If the call succeeded: