Compare commits

...

2 Commits
v3.1 ... master

  1. 19
      ILE_MainWindow.py
  2. 11
      ILExtract.py
  3. 118
      ile_installer.py
  4. 40
      main.py
  5. 2
      settings.json

@ -127,6 +127,7 @@ class Ui_MainWindow(object):
self.gridLayout.addWidget(self.inputFilePreview, 3, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 889, 24))
self.menubar.setObjectName("menubar")
@ -136,20 +137,16 @@ class Ui_MainWindow(object):
self.menu_Settings.setIcon(icon5)
self.menu_Settings.setObjectName("menu_Settings")
self.menuStart_Maximized = QtWidgets.QMenu(self.menu_Settings)
icon6 = QtGui.QIcon()
icon6.addPixmap(QtGui.QPixmap("assets/maximize.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.menuStart_Maximized.setIcon(icon6)
self.menuStart_Maximized.setObjectName("menuStart_Maximized")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.action_Default_Locations = QtWidgets.QAction(MainWindow)
icon7 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap("assets/fileSearch.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.action_Default_Locations.setIcon(icon7)
self.action_Default_Locations.setObjectName("action_Default_Locations")
self.menu_Settings.addAction(self.action_Default_Locations)
# self.action_Debug_Mode = QtWidgets.QAction(MainWindow)
# icon7 = QtGui.QIcon()
# icon7.addPixmap(QtGui.QPixmap("assets/fileSearch.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
# self.action_Debug_Mode.setIcon(icon7)
# self.action_Debug_Mode.setObjectName("action_Debug_Mode")
#self.menu_Settings.addAction(self.action_Debug_Mode)
self.menubar.addAction(self.menu_Settings.menuAction())
self.reportTypeL.setBuddy(self.reportTypeCB)
@ -190,5 +187,5 @@ class Ui_MainWindow(object):
self.openFolderButton.setText(_translate("MainWindow", "&Open Folder"))
self.openExcelButton.setText(_translate("MainWindow", "&Open File"))
self.menu_Settings.setTitle(_translate("MainWindow", "&Settings"))
self.action_Default_Locations.setText(_translate("MainWindow", "&Default Locations"))
#self.action_Debug_Mode.setText(_translate("MainWindow", "&Debug Mode"))

@ -6,7 +6,7 @@ import re
from pathlib import Path
import numpy as np
from glob import glob
from logging import debug, DEBUG, basicConfig, warn
from logging import debug, DEBUG, basicConfig, warn, error
# V3.1 | 01/19/23
@ -53,7 +53,7 @@ class ILReport:
dataframe: DataFrame = self.x_method(report, self.output_location)
if dataframe.empty:
warn(f"ILReport: resulting dataframe was empty! Exiting with None.")
return None
return dataframe
self._append_to_consolidated_report(dataframe, settings["consolidatedBasePath"])
return dataframe
@ -91,9 +91,13 @@ class ILReport:
debug(f"Consolidated Report | No monthly summary file!\n\tCreating: {save_path}")
# No file exists yet
# Create it and add the current month
try:
with pd.ExcelWriter(save_path) as writer:
debug(f"Consolidated Report | {sheet_name}: Saving data as: {report_name}")
dataframe_to_append.to_excel(writer, index=False, sheet_name=sheet_name)
except Exception as e:
error(f"[E] Failed to create consolidated report! {sheet_name}:\n{e}")
else:
# We need to read the dataframe in the current monthly report
# Check that we are not adding matching data
@ -106,9 +110,12 @@ class ILReport:
debug(f"Consolidated Report | Data is same as previous! Skipping!")
return None
# We need to find the start cols (where the new data should go)
try:
with pd.ExcelWriter(save_path, engine='openpyxl', mode='a',if_sheet_exists="overlay") as writer:
debug(f"Consolidated Report | {sheet_name}: Saving data as: {report_name}")
dataframe_to_append.to_excel(writer, index=False, sheet_name=sheet_name,startrow=len(current_data),header=False)
except Exception as e:
error(f"[E] Failed to append to consolidated report! {sheet_name}:\n{e}")
def create_line_divider(breakage_list: list):

@ -0,0 +1,118 @@
from os import system, getlogin
import os
from sys import exit
from zipfile import ZipFile
import win32com.client
from glob import glob
import re
from itertools import cycle
from shutil import get_terminal_size
from threading import Thread
from time import sleep
def error_exit(exception_info: str):
print(exception_info)
input("\nPress enter/return to exit")
exit(1)
class NoMatchingFile(Exception):
def __init__(self, search_file: str, found: list) -> None:
super().__init__(f"File: {search_file} was not found: {found}")
class Loader:
def __init__(self, desc="Loading...", end="Done!", timeout=0.1):
"""
A loader-like context manager
Args:
desc (str, optional): The loader's description. Defaults to "Loading...".
end (str, optional): Final print. Defaults to "Done!".
timeout (float, optional): Sleep time between prints. Defaults to 0.1.
"""
self.desc = desc
self.end = end
self.timeout = timeout
self._thread = Thread(target=self._animate, daemon=True)
self.steps = ["|", "/", "-", "\\",]
self.done = False
def start(self):
self._thread.start()
return self
def _animate(self):
for c in cycle(self.steps):
if self.done:
break
print(f"\r{self.desc} {c}", flush=True, end="")
sleep(self.timeout)
def __enter__(self):
self.start()
def stop(self):
self.done = True
cols = get_terminal_size((80, 20)).columns
print("\r" + " " * cols, end="", flush=True)
print(f"\r{self.end}", flush=True)
def __exit__(self, exc_type, exc_value, tb):
# handle exceptions with those variables ^
self.stop()
ZIP_LOCATION = r"\\leafnow.com\public\Accounting Shared\ILE Apps"
APP_FOLDER = r"InfoLeaseExtract"
try:
user = getlogin()
install_folder = f"C:\\Users\\{user}\\AppData\\Local"
backup_install_folder = f"C:\\Users\\{user}\\Documents\\"
print(f"Initalizing InfoLease Extract Installer\n#######################################")
# Find the newest version:
latest_version = glob(f"{ZIP_LOCATION}\\LATEST*")
if len(latest_version) == 0:
# Create Custom exception
raise NoMatchingFile(f"{ZIP_LOCATION}\\LATEST*", latest_version)
latest_version: str = latest_version[0]
version = re.search("\d+\.\d+", latest_version).group()
print(f"Installing verion {version}...")
with ZipFile(latest_version, 'r') as zipObj:
try:
with Loader("Setting up program files..."):
zipObj.extractall(install_folder)
except Exception as e:
error_exit(f"Failed to extract file ({latest_version}) to '{install_folder}' :\n{e}")
print("Creating Desktop shortcut...")
try:
desktop = f"C:\\Users\\{user}\\OneDrive - LEAF Commercial Capital\\Desktop"
shell = win32com.client.Dispatch("WScript.Shell")
shortcut = shell.CreateShortCut(os.path.join(desktop, "IL Extract v3.10.lnk"),)
shortcut.Targetpath = f"{install_folder}\\IL Extract\\IL Extract.exe"
shortcut.IconLocation = f"{install_folder}\\IL Extract\\assets\\extract.ico"
shortcut.WorkingDirectory = f"{install_folder}\\IL Extract"
shortcut.save()
except:
try:
desktop = f"C:\\Users\\{user}\\Desktop"
shell = win32com.client.Dispatch("WScript.Shell")
shortcut = shell.CreateShortCut(os.path.join(desktop, "IL Extract v3.10.lnk"),)
shortcut.Targetpath = f"{install_folder}\\IL Extract\\IL Extract.exe"
shortcut.IconLocation = f"{install_folder}\\IL Extract\\assets\\extract.ico"
shortcut.WorkingDirectory = f"{install_folder}\\IL Extract"
shortcut.save()
except Exception as e:
error_exit(f"Failed to create shortcut. The application is still installed at:\n{install_folder}\\IL Extract.\nYou can manually create a shortcut if you would like.\n{e}")
print(f"\nInstallation Completed Successfully!")
input("\nPress Enter/Return to exit.")
except Exception as e:
error_exit(f"High level exception:\n{e}")

@ -14,6 +14,7 @@ with open("settings.json") as s:
if settings["debug"]:
basicConfig(filename='debug.log', encoding='utf-8', level=DEBUG)
debug("\n\n\n########################### VERSION = 3.10 ###########################\n\n\n")
debug("Running main.py...")
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
"""
@ -104,7 +105,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
Launches the file selection dialog then inits the set_input function
"""
debug("Launching getfile.")
inFile = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file')
inFile = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file',directory=self.settings["defaultLocations"][self.curReportType])
# If the user does not select a file we just exit and do not change anything
if inFile[0] == '':
debug(f"User did not select an input file! {inFile}")
@ -178,6 +179,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
debug(f"Process Selction | dataframe:\n{dataframe}")
# The text preview box can have trouble loading the larger dataframes so
# they are trimmed to 500 so that the users can see if anything got messed up
if dataframe.empty:
self.inputFilePreview.setText("Failed to create dataframe!")
return None
smallDF = dataframe.iloc[0:500,:]
self.inputFilePreview.setText(smallDF.to_html(index=False))
# Enable the excel button so users can open the file
@ -213,9 +217,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
Checks if a report type already has a default location
If the default location is blank, the current inputFileLocation will be saved
"""
if self.settings["defaultLocations"][self.curReportType]["dir"] == '':
self.settings["defaultLocations"][self.curReportType]["dir"] = ('/').join(self.inputFile.split('/')[:-1])
debug(f"checked_for_saved: saved new deafult location | {self.curReportType} | {self.settings['defaultLocations'][self.curReportType]['dir']}")
if self.settings["defaultLocations"][self.curReportType] == '':
self.settings["defaultLocations"][self.curReportType] = ('/').join(self.inputFile.split('/')[:-1])
debug(f"checked_for_saved: saved new deafult location | {self.curReportType} | {self.settings['defaultLocations'][self.curReportType]}")
with open('settings.json', 'w') as s:
# Save changes to the setting
json.dump(self.settings, s)
@ -226,6 +230,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# This will be used in settings the the extract function and determining file locations
# Disable the process report button since the input and output fields are now blank
self.processReportButton.setEnabled(False)
self.openExcelButton.setEnabled(False)
self.copyButton.setEnabled(False)
self.openFolderButton.setEnabled(False)
if self.reportTypeCB.currentText() == "ACH":
self.curReportType = "ach"
self.extract_function = ilx.ach
@ -269,32 +277,16 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.curReportType = "pymt"
self.extract_function = ilx.payment_transactions
# Replace the hard-coded dates in the default locations with the current date
inputRoot = self.settings["defaultLocations"][self.curReportType]["dir"]\
.replace("{dd}",dt.now().strftime('%d'))\
.replace("{mm}",dt.now().strftime('%m'))\
.replace("{yyyy}",dt.now().strftime('%Y')).replace("{yy}",dt.now().strftime('%y'))
inputFile = self.settings["defaultLocations"][self.curReportType]["fn"]\
.replace("{dd}",dt.now().strftime('%d'))\
.replace("{mm}",dt.now().strftime('%m'))\
.replace("{yyyy}",dt.now().strftime('%Y')).replace("{yy}",dt.now().strftime('%y'))
# If inputfile is blank, just leave the input root from settings
self.inputFile = f"{inputRoot}/{inputFile}" if (inputFile != '') else inputRoot
self.inputFile = ""
self.inputFileLE.setText(self.inputFile)
# Automatically sets output to be in the same file as input, with a naming scheme
# The report type selected in the combo box will dictate the naming
if self.inputFile == "":
outputroot = ('/').join(self.inputFileLE.text().split('/')[:-1])
else:
outputroot = inputRoot + '/'
if self.curReportType == "minv":
self.outputFile = f"{outputroot}{self.reportTypeCB.currentText()}_{dt.now().strftime('%Y%m%d_%H%M')}.txt"
self.outputFile = f"{self.reportTypeCB.currentText()}_{dt.now().strftime('%Y%m%d_%H%M')}.txt"
else:
self.outputFile = f"{outputroot}{self.reportTypeCB.currentText().replace('/','')}_{dt.now().strftime('%Y%m%d_%H%M')}.xlsx"
self.outputFile = f"{self.reportTypeCB.currentText().replace('/','')}_{dt.now().strftime('%Y%m%d_%H%M')}.xlsx"
self.outputFileLE.setText(self.outputFile)
self.openExcelButton.setEnabled(False)
self.copyButton.setEnabled(False)
self.openFolderButton.setEnabled(True)
debug(f"report_type_change | inputFile: {self.inputFile}")
debug(f"report_type_change | outputFile: {self.outputFile}")
self.check_ready_to_process()

@ -1 +1 @@
{"debug": false, "consolidatedBasePath": "", "defaultLocations": {"ach": {"dir": "", "fn": "", "custom": false}, "minv": {"dir": "", "fn": "", "custom": false}, "niv": {"dir": "", "fn": "", "custom": false}, "ren": {"dir": "", "fn": "", "custom": false}, "pymt": {"dir": "", "fn": "", "custom": false}, "uap": {"dir": "", "fn": "", "custom": false}, "pastdue": {"dir": "", "fn": "", "custom": false}}}
{"debug": false, "consolidatedBasePath": "leafnow.com/shared/cashapps", "defaultLocations": {"ach": "", "disp": "", "gl": "", "lb": "", "minv": "", "niv": "", "ren": "", "pymt": "", "uap": "", "pastdue": ""}}
Loading…
Cancel
Save