""" AUTHOR: Khushal P Soonderji DATE: CREATED: Wed, 25th Feb, 2026 UPDATED: Wed, 25th Feb, 2026 OBJECTIVE: To use fuzzy similarity scores to get the `User ID` of the `Reporting To` field for employees. The problem is simple - we need to figure out hierarchy. In Cosec, we have `"User ID": "VIS07085"` with `"User Name": "Vibhor Iyer"` Under him, we have `"User ID": "VIS07024"` with `"User Name": "Punish Kumar"` and `"Direct Reporting": "Vibhor"` For a computer "Vibor" and "Vibhor Iyer" are very distinct strings, so the next best thing to do is fuzzy matching. The danger is for cases where names overlap. For instance, an employee under "Dr. Nagaraj H" may get assigned to "Nagaraj Patel". This is a risk, BUT THERE IS NO COHERENCE IN THE INPUTS SO NO BETTER SOLUTION EXISTS AS OF THE TIME OF THE DEVELOPMENT. REFERENCES: N/A DOWNLOADS: N/A """ # ***************************************************************************************************************** # ***** **** # *** IMPORT *** # ***** **** # ***************************************************************************************************************** # To make sibling directories accessible for imports: import sys sys.path.append(".") sys.path.append("..") # For system-level activities: import os import copy from pathlib import Path # To work with date and time: import time import datetime # To work with tabulate data: import pandas as pd # Cosec-related: from cosec_web.cosec_web import CosecWeb # TCAOFF-related: from tcaoff.async_tcaoff import AsyncTheCAOffice # My utils: from utils_v2.system import files from utils_v2.string import json from utils_v2.string import regex from utils_v2.string import fuzzy from utils_v2.date_time import date_time # To work with datatypes: from typing import List, Dict, Any from collections import defaultdict # To run a cron-like scheduler: from apscheduler.schedulers.asyncio import AsyncIOScheduler # For async activities: import asyncio # For debugging: from icecream import IceCreamDebugger # Common and Shared: from scripts import common # ***************************************************************************************************************** # ***** **** # *** MACROS / ONE-TIME INIT *** # ***** **** # ***************************************************************************************************************** # Debugging: printer = IceCreamDebugger(prefix = "Fuzzy Hierarchy | ", includeContext = True) err_printer = IceCreamDebugger(prefix = "[ERR] Fuzzy Hierarchy | ", includeContext = True) # ***************************************************************************************************************** # ***** **** # *** VARIABLES *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** CLASSES *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** FUNCTIONS *** # ***** **** # ***************************************************************************************************************** def get_hierarchy( cosec_muster_roll: str | Path, velankani_master_excel: str | Path, ): # Read the files: printer("Reading files.") print("\n\n") # Read the Muster Roll from Cosec: cosec_muster_roll_df = CosecWeb.read_muster_roll_xls(str(cosec_muster_roll)) cosec_muster_roll_df["Direct Reporting ID"] = None cosec_muster_roll_df["Level-1 ID"] = None cosec_muster_roll_df = cosec_muster_roll_df[[ "User ID", "User Name", "Category Name", "Grade Name", "Branch Name", "Department Name", "Direct Reporting", "Direct Reporting ID", "Level-1", "Level-1 ID", ]] printer("Cosec Muster Roll:") print(cosec_muster_roll_df[:25].to_string()) print("\n\n") # Read the Master file maintained by Velankani: velankani_master_df = pd.read_excel(velankani_master_excel) velankani_master_df = velankani_master_df.rename( columns = { "New Emp ID": "New Emp ID", "Emp ID": "Emp ID", "User Name": "User Name", "Personal Email": "Personal Email", "Moblie Number": "Mobile No.", "Birth Date": "DoB", "Gender": "Gender", "Joining Date": "Joining Date", "Shift Group": "Shift Group", "Shift ID": "Shift ID" } ) printer("Velankani Master Excel:") print(velankani_master_df[:25].to_string()) print("\n\n") # Perform a left join to directly copy easily matchable data: # Merge selected columns from lookup_df into main_df printer("Performing left join.") cosec_muster_roll_df = cosec_muster_roll_df.merge( velankani_master_df[[ "Emp ID", "Personal Email", "Mobile No.", "DoB", "Gender", "Joining Date", "Shift Group", "Shift ID" ]], how = "left", left_on = "User ID", right_on = "Emp ID" ) # Now we start preparing the combined data. # Since the master file is just a reference, and we are focussing on automating Cosec, # we iterate over Cosec's records: printer("Performing fuzzy match.") time.sleep(1.0) print(f"| {'TARGET': <30} | {'BEST CHOICE': <30} | {'%': <4} |") print(f"| {'-' * 30} | {'-' * 30} | {'-' * 4} |") for i, target_row in cosec_muster_roll_df.iterrows(): # Loop through all the options in the lookup Master Excel and find the best match: direct_reporting_fuzzy_str = target_row["Direct Reporting"] best_match_score = 0.0 best_match_entry = None for j, choice_row in cosec_muster_roll_df.iterrows(): # Make the key and check for the best match: score = fuzzy.get_match_score( target = direct_reporting_fuzzy_str, choice = choice_row["User Name"], partial = False ) if score > best_match_score: best_match_score = score best_match_entry = choice_row.to_dict() print(f"| {target_row['Direct Reporting']: <30} | {best_match_entry['User Name']: <30} | {best_match_score: <.2f} |") # ***************************************************************************************************************** # ***** **** # *** MAIN PROGRAM *** # ***** **** # ***************************************************************************************************************** if __name__ == "__main__": # Request the required files: print("Please paste the paths to the required files.") # muster_roll = input("COSEC MUSTER ROLL FILE: ") # master_excel = input("VEL. MASTER EXCEL FILE: ") muster_roll = r"D:\kps\PycharmProjects\cosec\cosec_web\sample_files\muster_roll.xls" master_excel = r"C:\Users\Khushal P Soonderji\Downloads\Master Data-25.02.2026.xlsx" # Now we run the matching algo: get_hierarchy( cosec_muster_roll = muster_roll, velankani_master_excel = master_excel )