""" Classes and functions to parse completed reconciliation reports and remember the resolutions of contracts. Also provides a way for the reconciler to check hold against previously resolved holds. *Last Updated: version 1.3 """ from helpers import drop_unnamed, setup_logging from ghlib.database.database_manager import SQLiteManager from pandas import DataFrame, Series, read_sql_query, read_excel, concat from logging import getLogger from dataclasses import dataclass from hashlib import md5 setup_logging() logger = getLogger(__name__) def hash_cols(row: Series, cols_to_hash: list[str]) -> str: md5_hash = md5() md5_hash.update((''.join(row[col] for col in cols_to_hash)).encode('utf-8')) return md5_hash.hexdigest() def save_rec(resolved_dataframes: list[DataFrame]): """ #TODO Actually handle this... """ #raise NotImplementedError("You were too lazy to fix this after the rewrite. FIX PLZ!") sqlManager: SQLiteManager = SQLiteManager("OnHold.db") with sqlManager.get_session() as session: conn = session.connection() rdf: DataFrame for rdf in resolved_dataframes: cols: list[str] = rdf.columns.to_list() if "onhold_amount" in cols: logger.debug(f"Found 'onhold_amount' in rdf: no_match dataframe") # Split the on_hold col to normalize with amount mismatch rdf["onhold_amount_GP"] = rdf.apply(lambda row: row.onhold_amount if row.Source == "GP" else None ) rdf["onhold_amount_OB"] = rdf.apply(lambda row: row.onhold_amount if row.Source == "OB" else None ) else: logger.debug(f"No 'onhold_amount' col found in rdf: amount_mismatch dataframe") # Create a unified column for index rdf["Indentifier"] = rdf.apply(lambda row: hash_cols(row, ["ID_OB","ID_GP"]), axis=1 ) rec_cols: list[str] = [ "Indentifier", "ID_GP", "ID_OB", "Hide Next Month", "Resolution" ] def get_prev_reconciled(contracts: list[str]) -> DataFrame: """ Get a DataFrame of previously reconciled contracts from an SQLite database. Args: contracts (list[str]): A list of contract numbers to check for previously reconciled contracts. Returns: DataFrame: A DataFrame of previously reconciled contracts, or an empty DataFrame if none are found. """ # Create a DB manager sqlManager: SQLiteManager = SQLiteManager("OnHold.db") # Create a temp table to hold this batches contract numbers # this table will be cleared when sqlManager goes out of scope temp_table_statement = """ CREATE TEMPORARY TABLE CUR_CONTRACTS (contract_number VARCHAR(11)); """ sqlManager.execute(temp_table_statement) # Insert the current contracts into the temp table insert_contracts = f""" INSERT INTO CUR_CONTRACTS (contract_number) VALUES {', '.join([f"('{cn}')" for cn in contracts])}; """ sqlManager.execute(insert_contracts) # Select previously resolved contracts res_query = """ SELECT r.* FROM Resolutions r JOIN CUR_CONTRACTS t ON r.contract_number = t.contract_number; """ resolved: DataFrame = sqlManager.execute(res_query, as_dataframe=True) return resolved if __name__ == "__main__": import argparse from logging import DEBUG logger.setLevel(DEBUG) parser = argparse.ArgumentParser( prog="HoldReconcilerRecord", ) parser.add_argument("-i", "--input") args = parser.parse_args() # No Match no_match: DataFrame = read_excel(args.input, sheet_name="No Match") # Amount Mismatch amt_mm: DataFrame = read_excel(args.input, sheet_name="Amount Mismatch") save_rec(resolved_dataframes=[no_match, amt_mm])