You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
OnHoldReconciler/memory.py

123 lines
3.9 KiB

"""
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])