Fully working app. Interface needs work. Could use config to remember last opened location. Debug option not configured

master
Griffiths Lott 3 years ago
parent 6b375ecb72
commit 3aff9e4474
  1. 233
      ILParser.py
  2. 2
      getcol.py
  3. 254
      main.py
  4. 124
      ui.py

@ -0,0 +1,233 @@
from pandas import DataFrame
import re
from logging import debug, DEBUG, basicConfig, warn
from typing import Optional, Union
logConfig = basicConfig(filename='ILFormatter.log', encoding='utf-8', level=DEBUG, filemode='w')
CONTRACT_NO_REGEX = "\d{3}-\d{7}-\d{3}"
class Column:
def __init__(self, columnName: str, startIndex: int,
length: Optional[int] = None, endIndex: Optional[int] = None, valueRegex: Optional[str] = None) -> None:
assert length != None or endIndex != None, "You must specify either the length or endIndex of this column"
self.name = columnName
self.start = startIndex
self.end = endIndex if endIndex != None else startIndex + length
self.valueRegex = valueRegex
def __regex_check(self, value: str) -> bool:
if self.valueRegex == None: return True
return False if re.search(self.valueRegex, value) == None else True
def extract_column(self, line: str) -> tuple[str, Union[str, float]]:
debug(line)
end = self.end if self.end != -1 else len(line)
try:
dataValue: str = line[self.start : end].replace(',', '').strip()
except:
warn(f"NO DATA VALUE PRESENT ({self.name} | {self.start}-{self.end}): {line}")
if not self.__regex_check(dataValue):
warn(f"Invalid column value: Column: {self.name} value: {dataValue} regex: {self.valueRegex}")
try:
dataValue = float(dataValue)
except: pass
return self.name, dataValue
FIN_COLUMNS: list[Column] = [
Column("CUST.ID", startIndex= 0 ,endIndex = 21, valueRegex = "\d{8}"),
Column("CONTRACT.NO", startIndex= 21 ,endIndex = 37, valueRegex = "CONTRACT_NO_REGEX"),
Column("BUSINESS.TYPE", startIndex= 37 ,endIndex = 51, valueRegex = "\d{2}"),
Column("FED.ID", startIndex= 51 ,endIndex = 72, valueRegex = "\d{9}"),
Column("CUST.CREDIT.ACCT", startIndex= 72 ,endIndex = 89, valueRegex = "\d+"),
Column("CUSTOMER", startIndex= 89 ,endIndex = 120, valueRegex = None),
Column("LEASE.TYPE", startIndex= 120 ,endIndex = 131, valueRegex = None),
Column("EQUIPMENT.COST", startIndex= 131 ,endIndex = 146, valueRegex = None),
Column("CBR.", startIndex= 146 ,endIndex = 161, valueRegex = None),
Column("NET.INVESTMENT", startIndex= 161 ,endIndex = 176, valueRegex = None),
Column("ANNUAL.COMBINED.IRR", startIndex= 176 ,endIndex = 185, valueRegex = None),
Column("CONTRACT.TERM", startIndex= 185 ,endIndex = 199, valueRegex = None),
Column("INCOME.START.DATE", startIndex= 199 ,endIndex = 217, valueRegex = None),
Column("FIRST.PYMT.DATE", startIndex= 217 ,endIndex = 233, valueRegex = None),
Column("FIRST.PYMT.AMT", startIndex= 233 ,endIndex = 248, valueRegex = None),
Column("CONTRACT.PYMT.", startIndex= 248 ,endIndex = 263, valueRegex = None),
Column("INVOICE.CODE", startIndex= 263 ,endIndex = 276, valueRegex = None),
Column("INV.DAYS", startIndex= 276 ,endIndex = 285, valueRegex = None),
Column("INV.DUE.DAY", startIndex= 285 ,endIndex = 297, valueRegex = None),
Column("SEC.DEPOSIT.", startIndex= 297 ,endIndex = 312, valueRegex = None),
Column("IDC.AMOUNTS.", startIndex= 312 ,endIndex = 327, valueRegex = None),
Column("IDC.DATES.", startIndex= 327 ,endIndex = 338, valueRegex = None),
Column("RESIDUAL", startIndex= 338 ,endIndex = 353, valueRegex = None),
Column("MANAGERS.RESIDUAL", startIndex= 353 ,endIndex = 371, valueRegex = None),
Column("PROMOTION", startIndex= 371 ,endIndex = 381, valueRegex = None),
Column("PRODUCT.LINE", startIndex= 381 ,endIndex = 394, valueRegex = None),
Column("REGION", startIndex= 394 ,endIndex = 401, valueRegex = None),
Column("REGION.DESC.", startIndex= 401 ,endIndex = 432, valueRegex = None),
Column("BRANCH", startIndex= 432 ,endIndex = 439, valueRegex = None),
Column("BUSINESS.SEGMENT", startIndex= 439 ,endIndex = 456, valueRegex = None),
Column("LEAD.BANK", startIndex= 456 ,endIndex = 466, valueRegex = None),
Column("MRKTNG.REP", startIndex= 466 ,endIndex = 477, valueRegex = None),
Column("MRKTNG.REGION", startIndex= 477 ,endIndex = 491, valueRegex = None),
Column("REMIT.TO", startIndex= 491 ,endIndex = 500, valueRegex = None),
Column("PYMT.OPTION", startIndex= 500 ,endIndex = 512, valueRegex = None),
Column("BANK.CODE", startIndex= 512 ,endIndex = 522, valueRegex = None),
Column("TAPE.BANK.NUM", startIndex= 522 ,endIndex = 536, valueRegex = None),
Column("TAPE.ACCOUNT.NUM", startIndex= 536 ,endIndex = 557, valueRegex = None),
Column("TAPE.ACCT.TYPE", startIndex= 557 ,endIndex = 572, valueRegex = None),
Column("DEALER", startIndex= 572 ,endIndex = 583, valueRegex = None),
Column("PRIVATE.LABEL", startIndex= 583 ,endIndex = 597, valueRegex = None),
Column("RESID.METHOD", startIndex= 597 ,endIndex = 610, valueRegex = None),
Column("LATE.CHRG.EXMPT", startIndex= 610 ,endIndex = 626, valueRegex = None),
Column("INSURANCE.CODE", startIndex= 626 ,endIndex = 641, valueRegex = None),
Column("VARIABLE.DATE", startIndex= 641 ,endIndex = 655, valueRegex = None),
Column("VARIABLE.RATE", startIndex= 655 ,endIndex = 671, valueRegex = None),
Column("BILLING.CYCLE", startIndex= 671 ,endIndex = 685, valueRegex = None),
Column("UM.USER.DATE2", startIndex= 685 ,endIndex = 699, valueRegex = None),
Column("CR.ATTG.PHONE", startIndex= 699 ,endIndex = 715, valueRegex = None),
Column("GROSS.CONTRACT", startIndex= 715 ,endIndex = 730, valueRegex = None),
Column("ADV", startIndex= 730 ,endIndex = 734, valueRegex = None),
Column("PD.AMT.FINANCED ", startIndex= 735 ,endIndex = 751, valueRegex = None),
Column("PD.INCOME.START.DATE ", startIndex= 751 ,endIndex = 772, valueRegex = None),
Column("INVOICE.DESC", startIndex= 772 ,endIndex = 792, valueRegex = None),
Column("VARIABLE.PYMT.CODE ", startIndex= 792 ,endIndex = 811, valueRegex = None),
Column("PD.PAYMENT.AMT ", startIndex= 811 ,endIndex = 826, valueRegex = None),
Column("QUOTE.BUYOUT ", startIndex= 826 ,endIndex = 839, valueRegex = None),
Column("LATE.CHARGE.CODE ", startIndex= 839 ,endIndex = 856, valueRegex = None),
Column("LATE.CHRG.RATE ", startIndex= 856 ,endIndex = 871, valueRegex = None),
Column("M.DEF.COLLECTOR ", startIndex= 871 ,endIndex = 887, valueRegex = None),
Column("AM.ACH.LEAD.DAYS ", startIndex= 887 ,endIndex = 904, valueRegex = None),
Column("UNL POOL", startIndex= 904 ,endIndex = 915, valueRegex = None),
Column("PD RISK", startIndex= 915 ,endIndex = 926, valueRegex = None),
Column("PD RISK DATE.", startIndex= 926 ,endIndex = 940, valueRegex = None),
Column("LGD RISK", startIndex= 940 ,endIndex = 949, valueRegex = None),
Column("LGD DATE", startIndex= 949 ,endIndex = 960, valueRegex = None),
Column("Service By Others", startIndex= 960 ,endIndex = -1, valueRegex = None)
]
ASSET_COLS: list[Column] = [
Column("ASSET.#. ", startIndex= 0 ,endIndex = 9, valueRegex = None),
Column("CUST.ID. ", startIndex= 9 ,endIndex = 30, valueRegex = None),
Column("CONTRACT.NO ", startIndex= 30 ,endIndex = 46, valueRegex = None),
Column("CUST.CREDIT.ACCT ", startIndex= 46 ,endIndex = 63, valueRegex = None),
Column("CUST.NAME. ", startIndex= 63 ,endIndex = 84, valueRegex = None),
Column("EQUIP.DESC ", startIndex= 84 ,endIndex = 125, valueRegex = None),
Column("QUANTITY ", startIndex= 125 ,endIndex = 134, valueRegex = None),
Column("NEW.USED ", startIndex= 134 ,endIndex = 143, valueRegex = None),
Column("MODEL. ", startIndex= 143 ,endIndex = 164, valueRegex = None),
Column("A.MANUFACTURER.YEAR ", startIndex= 164 ,endIndex = 184, valueRegex = None),
Column("SERIAL.NUMBER. ", startIndex= 184 ,endIndex = 205, valueRegex = None),
Column("EQUIP.CODE ", startIndex= 205 ,endIndex = 216, valueRegex = None),
Column("EQUIP.CODE.DESC. ", startIndex= 216 ,endIndex = 247, valueRegex = None),
Column("ASSET.VENDOR ", startIndex= 247 ,endIndex = 260, valueRegex = None),
Column("ASSET.VENDOR.NAME. ", startIndex= 260 ,endIndex = 291, valueRegex = None),
Column("MANUFACTURER ", startIndex= 291 ,endIndex = 304, valueRegex = None),
Column("MANUFACT.NAME. ", startIndex= 304 ,endIndex = 335, valueRegex = None),
Column("UATB.EQUIP.ADDR1.45 ", startIndex= 335 ,endIndex = 381, valueRegex = None),
Column("UATB.EQUIP.ADDR2.45 ", startIndex= 381 ,endIndex = 427, valueRegex = None),
Column("EQUIP.CITY. ", startIndex= 427 ,endIndex = 453, valueRegex = None),
Column("EQUIP.STATE ", startIndex= 453 ,endIndex = 465, valueRegex = None),
Column("EQUIP.ZIP. ", startIndex= 465 ,endIndex = 476, valueRegex = None),
Column("STATE.TAX.CODE ", startIndex= 476 ,endIndex = 491, valueRegex = None),
Column("CNTY.TAX.CODE ", startIndex= 491 ,endIndex = 505, valueRegex = None),
Column("CITY.TAX.CODE ", startIndex= 505 ,endIndex = 519, valueRegex = None),
Column("PROP.STATUS ", startIndex= 519 ,endIndex = 531, valueRegex = None),
Column("EQUIP.COST ", startIndex= 531 ,endIndex = 546, valueRegex = None),
Column("EQUIP.COST.PCT ", startIndex= 546 ,endIndex = 561, valueRegex = None),
Column("PUR.OPTION ", startIndex= 561 ,endIndex = 572, valueRegex = None),
Column("PUR.OPTION. ", startIndex= 572 ,endIndex = 588, valueRegex = None),
Column("AS.RECOURSE.CODE ", startIndex= 588 ,endIndex = 605, valueRegex = None),
Column("RESID.AMT. ", startIndex= 605 ,endIndex = 620, valueRegex = None),
Column("BEG.DEPR.DATE ", startIndex= 620 ,endIndex = 634, valueRegex = None),
Column("OPER.LS.BEGIN.DATE ", startIndex= 634 ,endIndex = 653, valueRegex = None),
Column("OPER.LS.LIM ", startIndex= 653 ,endIndex = 665, valueRegex = None),
Column("OPER.LS.SALVAGE ", startIndex= 665 ,endIndex = -1, valueRegex = None)
]
CUST_COLS: list[Column] = [
Column("CONTRACT.NO ", startIndex= 0 ,endIndex = 16, valueRegex = None),
Column("CUST.CREDIT.ACCT ", startIndex= 16 ,endIndex = 33, valueRegex = None),
Column("CUST.ID. ", startIndex= 33 ,endIndex = 54, valueRegex = None),
Column("CUST.NAME. ", startIndex= 54 ,endIndex = 105, valueRegex = None),
Column("UATB.CUST.DBA. ", startIndex= 105 ,endIndex = 136, valueRegex = None),
Column("UATB.CUST.ADDRESS1.45 ", startIndex= 136 ,endIndex = 182, valueRegex = None),
Column("UATB.CUST.ADDRESS2.45 ", startIndex= 182 ,endIndex = 228, valueRegex = None),
Column("UATB.CUST.ADDRESS3.45 ", startIndex= 228 ,endIndex = 274, valueRegex = None),
Column("CUST.CITY. ", startIndex= 274 ,endIndex = 295, valueRegex = None),
Column("CUST.STATE ", startIndex= 295 ,endIndex = 306, valueRegex = None),
Column("CUST.ZIP ", startIndex= 306 ,endIndex = 317, valueRegex = None),
Column("GUAR.CODE.1 ", startIndex= 317 ,endIndex = 329, valueRegex = None),
Column("PRIN1/GUAR.NAME.1. ", startIndex= 329 ,endIndex = 365, valueRegex = None),
Column("PRIN1.ADD1. ", startIndex= 365 ,endIndex = 396, valueRegex = None),
Column("PRIN1.ADD2. ", startIndex= 396 ,endIndex = 427, valueRegex = None),
Column("PRIN1.CITY1. ", startIndex= 427 ,endIndex = 453, valueRegex = None),
Column("PRIN1.ST.1. ", startIndex= 453 ,endIndex = 464, valueRegex = None),
Column("ZIP.1. ", startIndex= 464 ,endIndex = 477, valueRegex = None),
Column("FED.ID/SS#1 ", startIndex= 477 ,endIndex = 503, valueRegex = None),
Column("GUAR.CODE.2.PRIN/GUAR.NAME.2. ", startIndex= 503 ,endIndex = 541, valueRegex = None),
Column("PRIN2.ADD2. ", startIndex= 541 ,endIndex = 572, valueRegex = None),
Column("PRIN2.ADDR2 ", startIndex= 572 ,endIndex = 603, valueRegex = None),
Column("PRIN2.CITY2. ", startIndex= 603 ,endIndex = 629, valueRegex = None),
Column("PRIN2.ST.2ZIP.2. ", startIndex= 629 ,endIndex = 653, valueRegex = None),
Column("FED.ID/SS#2 ", startIndex= 653 ,endIndex = 679, valueRegex = None),
Column("BILLING.NAME ", startIndex= 679 ,endIndex = 720, valueRegex = None),
Column("UATB.AR.ADDRESS1.45 ", startIndex= 720 ,endIndex = 766, valueRegex = None),
Column("UATB.AR.ADDRESS2.45 ", startIndex= 766 ,endIndex = 812, valueRegex = None),
Column("UATB.AR.ADDRESS3.45 ", startIndex= 812 ,endIndex = 858, valueRegex = None),
Column("AR.CITY. ", startIndex= 858 ,endIndex = 879, valueRegex = None),
Column("AR.STATE ", startIndex= 879 ,endIndex = 888, valueRegex = None),
Column("AR.ZIP ", startIndex= 888 ,endIndex = 899, valueRegex = None),
Column("AR.ATTN. ", startIndex= 899 ,endIndex = 920, valueRegex = None),
Column("UATB.CR.ATTG.NAME40. ", startIndex= 920 ,endIndex = 961, valueRegex = None),
Column("CR.SCORING ", startIndex= 961 ,endIndex = 972, valueRegex = None),
Column("FACILITY.SCORE ", startIndex= 972 ,endIndex = 988, valueRegex = None),
Column("SIC.CODE ", startIndex= 988 ,endIndex = -1, valueRegex = None),
]
DOB_COL: list[Column] = [
Column("CONTRACT.NO ", startIndex= 0 ,endIndex = 16, valueRegex = None),
Column("CUST.CREDIT.ACCT ", startIndex= 16 ,endIndex = 33, valueRegex = None),
Column("CUST.ID. ", startIndex= 33 ,endIndex = 54, valueRegex = None),
Column("GUAR.CODE.1 ", startIndex= 54 ,endIndex = 66, valueRegex = None),
Column("PRIN/GUAR.NAME.1. ", startIndex= 66 ,endIndex = 102, valueRegex = None),
Column("FED.ID/SS#1 ", startIndex= 102 ,endIndex = 128, valueRegex = None),
Column("DOB1 ", startIndex= 128 ,endIndex = 139, valueRegex = None),
Column("GUAR.CODE.2 ", startIndex= 139 ,endIndex = 151, valueRegex = None),
Column("PRIN/GUAR.NAME.2. ", startIndex= 151 ,endIndex = 177, valueRegex = None),
Column("FED.ID/SS#2 ", startIndex= 177 ,endIndex = -1, valueRegex = None)
]
def parse(ILOutput: str, columns: list[Column], dataColumnRegex: str = CONTRACT_NO_REGEX) -> DataFrame :
debug(ILOutput)
lines = ILOutput.splitlines()
dataDict = {}
for index, line in enumerate(lines):
debug(f"Index: {index} | {line}")
debug(re.search(dataColumnRegex, line))
if re.search(dataColumnRegex, line) == None: continue
for col in columns:
name, value = col.extract_column(line)
debug(f"name: {name} | value: {value}")
try:
dataDict[name].append(value)
except:
dataDict[name] = [value]
debug(dataDict)
try:
dataframe = DataFrame(dataDict)
except ValueError as ve:
debug({c: len(dataDict[c]) for c in dataDict.keys()})
debug(ve)
return dataframe
# extracts = [("FIN", FIN_COLUMNS), ("ASSET", ASSET_COLS), ("CUST", CUST_COLS), ("DOB", DOB_COL)]
# for file, columns in extracts:
# with open(f"Inputs/{file}", errors="replace") as reportFile:
# report: str = reportFile.read()
# # Removes characters that cause errors
# report: str = report.replace("^"," ")
# dataframe: DataFrame = parse(ILOutput=report, columns=columns)
# print(f"{file} dataframe: {dataframe}")

@ -10,7 +10,7 @@ for input in ["ASSET", "CUST", "DOB"]:
for line in report.splitlines(): for line in report.splitlines():
print(line.strip()) print(line.strip())
if len(line.strip()) > 50: if len(line.strip()) > 50:
matches = re.finditer('(\w|\.)+\s', line) matches = re.finditer('(\w|\.|/|#)+\s', line)
for match in matches: for match in matches:
print(match) print(match)
colDict["ColName"].append(match.group()) colDict["ColName"].append(match.group())

@ -1,141 +1,115 @@
from pandas import DataFrame from ui import Ui_MainWindow
import re import ILParser
from PyQt5 import QtWidgets
from logging import debug, DEBUG, basicConfig, warn from logging import debug, DEBUG, basicConfig, warn
from typing import Optional, Union from sys import argv
from typing import Literal, Optional
from pandas import DataFrame, ExcelWriter
from datetime import datetime as dt
logConfig = basicConfig(filename='ILFormatter.log', encoding='utf-8', level=DEBUG)
logConfig = basicConfig(filename='ILFormatter.log', encoding='utf-8', level=DEBUG, filemode='w')
TEST_FIN_LOCATION = r"Inputs/FIN"
TEST_ASSET_LOCATION = R"Inputs\ASSET" class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, obj=None, **kwargs):
CONTRACT_NO_REGEX = "\d{3}-\d{7}-\d{3}" debug("MainWindow class init..")
super(MainWindow, self).__init__(*args, **kwargs)
class Column: self.setupUi(self)
def __init__(self, columnName: str, startIndex: int, self.processButton.setEnabled(False)
length: Optional[int] = None, endIndex: Optional[int] = None, valueRegex: Optional[str] = None) -> None:
# File Locations
assert length != None or endIndex != None, "You must specify either the length or endIndex of this column" self.assetFile = None
self.name = columnName self.custFile = None
self.start = startIndex self.dobFile = None
self.end = endIndex if endIndex != None else startIndex + length self.finFile = None
self.valueRegex = valueRegex self.outputLocation = None
def __regex_check(self, value: str) -> bool: # Button Hooks
if self.valueRegex == None: return True self.assetButton.clicked.connect(lambda: self._set_file(lineEdit= self.assetLE, selfFile="ASSET"))
return False if re.search(self.valueRegex, value) == None else True self.custButton.clicked.connect(lambda: self._set_file(lineEdit= self.custLe, selfFile="CUST"))
self.dobButton.clicked.connect(lambda: self._set_file(lineEdit= self.dobLE, selfFile="DOB"))
def extract_column(self, line: str) -> tuple[str, Union[str, float]]: self.finButton.clicked.connect(lambda: self._set_file(lineEdit= self.finLE, selfFile="FIN"))
debug(line) self.outputButton.clicked.connect(lambda: self._set_output())
if self.end == -1: self.processButton.clicked.connect(lambda: self._process())
end = len(line)
else: def _check_files(self):
assert len(line) >= self.end, f"Line is to short to extract value: len: {len(line)} > end : {self.end}" debug(self.assetFile)
end = self.end debug(self.custFile)
dataValue: str = line[self.start : end].replace(',', '').strip() debug(self.dobFile)
if not self.__regex_check(dataValue): debug(self.finFile)
warn(f"Invalid column value: Column: {self.name} value: {dataValue} regex: {self.valueRegex}") ready = (
try: self.assetFile != None and
dataValue = float(dataValue) self.custFile != None and
except: pass self.dobFile != None and
return self.name, dataValue self.finFile != None and
self.outputLocation != None
)
FIN_COLUMNS: list[Column] = [ self.processButton.setEnabled(ready)
Column("CUST.ID", startIndex= 0 ,endIndex = 21, valueRegex = "\d{8}"),
Column("CONTRACT.NO", startIndex= 21 ,endIndex = 37, valueRegex = "CONTRACT_NO_REGEX"), def _set_file(self, lineEdit: QtWidgets.QLineEdit, selfFile: Literal["ASSET", "CUST", "DOB", "FIN"]) -> str :
Column("BUSINESS.TYPE", startIndex= 37 ,endIndex = 51, valueRegex = "\d{2}"), selectedFile: list[str] = QtWidgets.QFileDialog.getOpenFileName(self, "OpenFile")
Column("FED.ID", startIndex= 51 ,endIndex = 72, valueRegex = "\d{9}"), debug(f"Selected file: {selectedFile}")
Column("CUST.CREDIT.ACCT", startIndex= 72 ,endIndex = 89, valueRegex = "\d+"), lineEdit.setText(selectedFile[0])
Column("CUSTOMER", startIndex= 89 ,endIndex = 120, valueRegex = None), file = selectedFile[0] if selectedFile[0] != '' else None
Column("LEASE.TYPE", startIndex= 120 ,endIndex = 131, valueRegex = None), if file != None and self.outputLocation == None:
Column("EQUIPMENT.COST", startIndex= 131 ,endIndex = 146, valueRegex = None), self._auto_output_set(fileRoot='/'.join(file.split('/')[:-1]))
Column("CBR.", startIndex= 146 ,endIndex = 161, valueRegex = None), if selfFile == "ASSET":
Column("NET.INVESTMENT", startIndex= 161 ,endIndex = 176, valueRegex = None), self.assetFile = file
Column("ANNUAL.COMBINED.IRR", startIndex= 176 ,endIndex = 185, valueRegex = None), elif selfFile == "CUST":
Column("CONTRACT.TERM", startIndex= 185 ,endIndex = 199, valueRegex = None), self.custFile = file
Column("INCOME.START.DATE", startIndex= 199 ,endIndex = 217, valueRegex = None), elif selfFile == "DOB":
Column("FIRST.PYMT.DATE", startIndex= 217 ,endIndex = 233, valueRegex = None), self.dobFile = file
Column("FIRST.PYMT.AMT", startIndex= 233 ,endIndex = 248, valueRegex = None), elif selfFile == "FIN":
Column("CONTRACT.PYMT.", startIndex= 248 ,endIndex = 263, valueRegex = None), self.finFile = file
Column("INVOICE.CODE", startIndex= 263 ,endIndex = 276, valueRegex = None), self._check_files()
Column("INV.DAYS", startIndex= 276 ,endIndex = 285, valueRegex = None),
Column("INV.DUE.DAY", startIndex= 285 ,endIndex = 297, valueRegex = None), def _set_output(self):
Column("SEC.DEPOSIT.", startIndex= 297 ,endIndex = 312, valueRegex = None), self.outputLocation = QtWidgets.QFileDialog.getSaveFileName(self, "Output file name") if QtWidgets.QFileDialog.getSaveFileName(self, "Output file name") != '' else None
Column("IDC.AMOUNTS.", startIndex= 312 ,endIndex = 327, valueRegex = None), self.outputLE.setText(self.outputLocation if self.outputLocation != None else '')
Column("IDC.DATES.", startIndex= 327 ,endIndex = 338, valueRegex = None), debug(f"Output Location: {self.outputLocation}")
Column("RESIDUAL", startIndex= 338 ,endIndex = 353, valueRegex = None),
Column("MANAGERS.RESIDUAL", startIndex= 353 ,endIndex = 371, valueRegex = None), def _auto_output_set(self, fileRoot):
Column("PROMOTION", startIndex= 371 ,endIndex = 381, valueRegex = None), self.outputLocation = fileRoot + f"/Portfolio Contracts - {dt.now().strftime('%Y-%m-%d')}.xlsx"
Column("PRODUCT.LINE", startIndex= 381 ,endIndex = 394, valueRegex = None), self.outputLE.setText(self.outputLocation if self.outputLocation != None else '')
Column("REGION", startIndex= 394 ,endIndex = 401, valueRegex = None), debug(f"Auto set output: {self.outputLocation}")
Column("REGION.DESC.", startIndex= 401 ,endIndex = 432, valueRegex = None),
Column("BRANCH", startIndex= 432 ,endIndex = 439, valueRegex = None), def _setAssetFile(self):
Column("BUSINESS.SEGMENT", startIndex= 439 ,endIndex = 456, valueRegex = None), self.assetFile = self._set_file(self.assetLE)
Column("LEAD.BANK", startIndex= 456 ,endIndex = 466, valueRegex = None),
Column("MRKTNG.REP", startIndex= 466 ,endIndex = 477, valueRegex = None), def _parse_file(self, filePath: str, parseColumns: list[ILParser.Column]) -> Optional[DataFrame]:
Column("MRKTNG.REGION", startIndex= 477 ,endIndex = 491, valueRegex = None), with open(filePath) as file:
Column("REMIT.TO", startIndex= 491 ,endIndex = 500, valueRegex = None), report = file.read()
Column("PYMT.OPTION", startIndex= 500 ,endIndex = 512, valueRegex = None), debug(f"Report: {report}")
Column("BANK.CODE", startIndex= 512 ,endIndex = 522, valueRegex = None), data: DataFrame = ILParser.parse(report, parseColumns)
Column("TAPE.BANK.NUM", startIndex= 522 ,endIndex = 536, valueRegex = None), debug(f"Data: {data}")
Column("TAPE.ACCOUNT.NUM", startIndex= 536 ,endIndex = 557, valueRegex = None), if data.empty:
Column("TAPE.ACCT.TYPE", startIndex= 557 ,endIndex = 572, valueRegex = None), return None
Column("DEALER", startIndex= 572 ,endIndex = 583, valueRegex = None), else: return data
Column("PRIVATE.LABEL", startIndex= 583 ,endIndex = 597, valueRegex = None),
Column("RESID.METHOD", startIndex= 597 ,endIndex = 610, valueRegex = None), def _process(self):
Column("LATE.CHRG.EXMPT", startIndex= 610 ,endIndex = 626, valueRegex = None), assetDf: DataFrame = self._parse_file(self.assetFile, ILParser.ASSET_COLS)
Column("INSURANCE.CODE", startIndex= 626 ,endIndex = 641, valueRegex = None), debug(assetDf)
Column("VARIABLE.DATE", startIndex= 641 ,endIndex = 655, valueRegex = None), custDf: DataFrame = self._parse_file(self.custFile, ILParser.CUST_COLS)
Column("VARIABLE.RATE", startIndex= 655 ,endIndex = 671, valueRegex = None), debug(custDf)
Column("BILLING.CYCLE", startIndex= 671 ,endIndex = 685, valueRegex = None), dobDf: DataFrame = self._parse_file(self.dobFile, ILParser.DOB_COL)
Column("UM.USER.DATE2", startIndex= 685 ,endIndex = 699, valueRegex = None), debug(dobDf)
Column("CR.ATTG.PHONE", startIndex= 699 ,endIndex = 715, valueRegex = None), finDf: DataFrame = self._parse_file(self.finFile, ILParser.FIN_COLUMNS)
Column("GROSS.CONTRACT", startIndex= 715 ,endIndex = 730, valueRegex = None), debug(finDf)
Column("ADV", startIndex= 730 ,endIndex = 734, valueRegex = None), with ExcelWriter(self.outputLocation) as writer:
Column("PD.AMT.FINANCED ", startIndex= 735 ,endIndex = 751, valueRegex = None), assetDf.to_excel(writer, sheet_name="ASSET")
Column("PD.INCOME.START.DATE ", startIndex= 751 ,endIndex = 772, valueRegex = None), custDf.to_excel(writer, sheet_name="CUST")
Column("INVOICE.DESC", startIndex= 772 ,endIndex = 792, valueRegex = None), dobDf.to_excel(writer, sheet_name="DOB")
Column("VARIABLE.PYMT.CODE ", startIndex= 792 ,endIndex = 811, valueRegex = None), finDf.to_excel(writer, sheet_name="FIN")
Column("PD.PAYMENT.AMT ", startIndex= 811 ,endIndex = 826, valueRegex = None), debug("Finished writing to excel.")
Column("QUOTE.BUYOUT ", startIndex= 826 ,endIndex = 839, valueRegex = None),
Column("LATE.CHARGE.CODE ", startIndex= 839 ,endIndex = 856, valueRegex = None),
Column("LATE.CHRG.RATE ", startIndex= 856 ,endIndex = 871, valueRegex = None), # Defines the app
Column("M.DEF.COLLECTOR ", startIndex= 871 ,endIndex = 887, valueRegex = None), app = QtWidgets.QApplication(argv)
Column("AM.ACH.LEAD.DAYS ", startIndex= 887 ,endIndex = 904, valueRegex = None), # Sets the style
Column("UNL POOL", startIndex= 904 ,endIndex = 915, valueRegex = None), app.setStyle("Fusion")
Column("PD RISK", startIndex= 915 ,endIndex = 926, valueRegex = None), # Builds the main window
Column("PD RISK DATE.", startIndex= 926 ,endIndex = 940, valueRegex = None), window = MainWindow()
Column("LGD RISK", startIndex= 940 ,endIndex = 949, valueRegex = None), window.setWindowTitle("IL Extract")
Column("LGD DATE", startIndex= 949 ,endIndex = 960, valueRegex = None), window.show()
Column("Service By Others", startIndex= 960 ,endIndex = -1, valueRegex = None) # Starts the app
] app.exec()
def parse(ILOutput: str, columns: list[Column], dataColumnRegex: str = CONTRACT_NO_REGEX) -> DataFrame :
debug(ILOutput)
lines = ILOutput.splitlines()
dataDict = {}
for index, line in enumerate(lines):
debug(f"Index: {index} | {line}")
debug(re.search(dataColumnRegex, line))
if re.search(dataColumnRegex, line) == None: continue
for col in columns:
name, value = col.extract_column(line)
try:
dataDict[name].append(value)
except:
dataDict[name] = [value]
dataframe = DataFrame(dataDict)
return dataframe
with open(TEST_FIN_LOCATION, errors="replace") as reportFile:
report: str = reportFile.read()
# Removes characters that cause errors
report: str = report.replace("^"," ")
finDataframe: DataFrame = parse(ILOutput=report, columns=FIN_COLUMNS)
print(f"FIN dataframe: {finDataframe}")

124
ui.py

@ -0,0 +1,124 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'PortfolioILFormatter.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(520, 314)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.widget = QtWidgets.QWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(10, 10, 491, 251))
self.widget.setObjectName("widget")
self.mainVbox = QtWidgets.QVBoxLayout(self.widget)
self.mainVbox.setContentsMargins(0, 0, 0, 0)
self.mainVbox.setObjectName("mainVbox")
self.assetHbox = QtWidgets.QHBoxLayout()
self.assetHbox.setObjectName("assetHbox")
self.assetButton = QtWidgets.QPushButton(self.widget)
self.assetButton.setMinimumSize(QtCore.QSize(99, 27))
self.assetButton.setMaximumSize(QtCore.QSize(99, 27))
self.assetButton.setObjectName("assetButton")
self.assetHbox.addWidget(self.assetButton)
self.assetLE = QtWidgets.QLineEdit(self.widget)
self.assetLE.setObjectName("assetLE")
self.assetHbox.addWidget(self.assetLE)
self.mainVbox.addLayout(self.assetHbox)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.custButton = QtWidgets.QPushButton(self.widget)
self.custButton.setMinimumSize(QtCore.QSize(99, 27))
self.custButton.setMaximumSize(QtCore.QSize(99, 27))
self.custButton.setObjectName("custButton")
self.horizontalLayout_2.addWidget(self.custButton)
self.custLe = QtWidgets.QLineEdit(self.widget)
self.custLe.setObjectName("custLe")
self.horizontalLayout_2.addWidget(self.custLe)
self.mainVbox.addLayout(self.horizontalLayout_2)
self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.dobButton = QtWidgets.QPushButton(self.widget)
self.dobButton.setMinimumSize(QtCore.QSize(99, 27))
self.dobButton.setMaximumSize(QtCore.QSize(99, 27))
self.dobButton.setObjectName("dobButton")
self.horizontalLayout_6.addWidget(self.dobButton)
self.dobLE = QtWidgets.QLineEdit(self.widget)
self.dobLE.setObjectName("dobLE")
self.horizontalLayout_6.addWidget(self.dobLE)
self.mainVbox.addLayout(self.horizontalLayout_6)
self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.finButton = QtWidgets.QPushButton(self.widget)
self.finButton.setMinimumSize(QtCore.QSize(99, 27))
self.finButton.setMaximumSize(QtCore.QSize(99, 27))
self.finButton.setObjectName("finButton")
self.horizontalLayout_7.addWidget(self.finButton)
self.finLE = QtWidgets.QLineEdit(self.widget)
self.finLE.setObjectName("finLE")
self.horizontalLayout_7.addWidget(self.finLE)
self.mainVbox.addLayout(self.horizontalLayout_7)
self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.outputButton = QtWidgets.QPushButton(self.widget)
self.outputButton.setMinimumSize(QtCore.QSize(99, 27))
self.outputButton.setMaximumSize(QtCore.QSize(99, 27))
self.outputButton.setObjectName("outputButton")
self.horizontalLayout_8.addWidget(self.outputButton)
self.outputLE = QtWidgets.QLineEdit(self.widget)
self.outputLE.setObjectName("outputLE")
self.horizontalLayout_8.addWidget(self.outputLE)
self.mainVbox.addLayout(self.horizontalLayout_8)
self.processButton = QtWidgets.QPushButton(self.widget)
self.processButton.setObjectName("processButton")
self.mainVbox.addWidget(self.processButton)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 520, 24))
self.menubar.setObjectName("menubar")
self.menuSettings = QtWidgets.QMenu(self.menubar)
self.menuSettings.setObjectName("menuSettings")
self.menuLog_Level = QtWidgets.QMenu(self.menuSettings)
self.menuLog_Level.setObjectName("menuLog_Level")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionDebug_2 = QtWidgets.QAction(MainWindow)
self.actionDebug_2.setObjectName("actionDebug_2")
self.actionInfo = QtWidgets.QAction(MainWindow)
self.actionInfo.setObjectName("actionInfo")
self.actionInfo_2 = QtWidgets.QAction(MainWindow)
self.actionInfo_2.setObjectName("actionInfo_2")
self.menuLog_Level.addAction(self.actionInfo)
self.menuLog_Level.addAction(self.actionInfo_2)
self.menuLog_Level.addAction(self.actionDebug_2)
self.menuSettings.addAction(self.menuLog_Level.menuAction())
self.menubar.addAction(self.menuSettings.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Portfolio IL Output Formatter"))
self.assetButton.setText(_translate("MainWindow", "Select ASSET:"))
self.custButton.setText(_translate("MainWindow", "Select CUST:"))
self.dobButton.setText(_translate("MainWindow", "Select DOB:"))
self.finButton.setText(_translate("MainWindow", "Select FIN:"))
self.outputButton.setText(_translate("MainWindow", "Select Output"))
self.processButton.setText(_translate("MainWindow", "Process Files"))
self.menuSettings.setTitle(_translate("MainWindow", "Settings"))
self.menuLog_Level.setTitle(_translate("MainWindow", "Log Level"))
self.actionDebug_2.setText(_translate("MainWindow", "Debug"))
self.actionInfo.setText(_translate("MainWindow", "Warn"))
self.actionInfo_2.setText(_translate("MainWindow", "Info"))
Loading…
Cancel
Save