Bladeren bron

Initial Commit

mike 2 weken geleden
commit
a42be37390
11 gewijzigde bestanden met toevoegingen van 729 en 0 verwijderingen
  1. 1 0
      .gitignore
  2. 3 0
      .idea/.gitignore
  3. 10 0
      .idea/PaycheckExtractor.iml
  4. 12 0
      .idea/inspectionProfiles/Project_Default.xml
  5. 6 0
      .idea/inspectionProfiles/profiles_settings.xml
  6. 4 0
      .idea/misc.xml
  7. 8 0
      .idea/modules.xml
  8. 5 0
      README.MD
  9. 9 0
      csv_merge.py
  10. 339 0
      log.txt
  11. 332 0
      main.py

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+*.csv*

+ 3 - 0
.idea/.gitignore

@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml

+ 10 - 0
.idea/PaycheckExtractor.iml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/venv" />
+    </content>
+    <orderEntry type="jdk" jdkName="Python 3.10 (PaycheckExtractor)" jdkType="Python SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 12 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,12 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
+      <option name="ignoredErrors">
+        <list>
+          <option value="N802" />
+        </list>
+      </option>
+    </inspection_tool>
+  </profile>
+</component>

+ 6 - 0
.idea/inspectionProfiles/profiles_settings.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>

+ 4 - 0
.idea/misc.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (PaycheckExtractor)" project-jdk-type="Python SDK" />
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/PaycheckExtractor.iml" filepath="$PROJECT_DIR$/.idea/PaycheckExtractor.iml" />
+    </modules>
+  </component>
+</project>

+ 5 - 0
README.MD

@@ -0,0 +1,5 @@
+Script to Parse a paycheck or folder of paychecks and populate a csv file with aggregate data.
+
+Useful for analysing paychecks a year at a time.
+
+Currently, individual Paychecks fail, but folders work fine.

+ 9 - 0
csv_merge.py

@@ -0,0 +1,9 @@
+with open("result.csv", "ab") as fout:
+    with open("2018.csv", "rb") as f:
+        fout.writelines(f)
+
+    for num in range(2019,(2024+1)):
+        # print(num)
+        with open(str(num) + ".csv", "rb") as f:
+            next(f)
+            fout.writelines(f)

+ 339 - 0
log.txt

@@ -0,0 +1,339 @@
+07/21/25 12:00:55:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:00:55:DEBUG:Using Parser v2.
+07/21/25 12:00:55:DEBUG:ParsePDF Complete
+07/21/25 12:01:01:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:01:01:DEBUG:Using Parser v2.
+07/21/25 12:01:01:DEBUG:ParsePDF Complete
+07/21/25 12:02:15:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:02:15:DEBUG:Using Parser v2.
+07/21/25 12:02:15:DEBUG:ParsePDF Complete
+07/21/25 12:02:23:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:02:23:DEBUG:Using Parser v2.
+07/21/25 12:02:23:DEBUG:ParsePDF Complete
+07/21/25 12:03:08:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:03:08:DEBUG:Using Parser v2.
+07/21/25 12:03:08:DEBUG:ParsePDF Complete
+07/21/25 12:03:44:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:03:44:DEBUG:Using Parser v2.
+07/21/25 12:03:44:DEBUG:ParsePDF Complete
+07/21/25 12:03:58:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:03:58:DEBUG:Using Parser v2.
+07/21/25 12:03:58:DEBUG:ParsePDF Complete
+07/21/25 12:04:09:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:04:09:DEBUG:Using Parser v2.
+07/21/25 12:04:09:DEBUG:ParsePDF Complete
+07/21/25 12:04:27:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:04:27:DEBUG:Using Parser v2.
+07/21/25 12:04:27:DEBUG:ParsePDF Complete
+07/21/25 12:04:27:DEBUG:calculate_result:0
+07/21/25 12:06:02:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:06:02:DEBUG:checkargs complete with no errors
+07/21/25 12:06:02:DEBUG:Using Parser v2.
+07/21/25 12:06:02:DEBUG:ParsePDF Complete
+07/21/25 12:06:02:DEBUG:Length of calculate_result results:0
+07/21/25 12:06:49:WARNING:***Starting Application***
+07/21/25 12:06:49:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:06:49:DEBUG:checkargs complete with no errors
+07/21/25 12:06:49:DEBUG:Using Parser v2.
+07/21/25 12:06:49:DEBUG:ParsePDF Complete
+07/21/25 12:06:49:DEBUG:Length of calculate_result results:0
+07/21/25 12:07:35:WARNING:***Starting Application***
+07/21/25 12:07:35:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:07:35:DEBUG:checkargs complete with no errors
+07/21/25 12:07:35:DEBUG:Using Parser v2.
+07/21/25 12:07:35:DEBUG:ParsePDF Complete
+07/21/25 12:07:35:DEBUG:Length of calculate_result results:0
+07/21/25 12:07:42:WARNING:***Starting Application***
+07/21/25 12:07:42:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:07:42:DEBUG:checkargs complete with no errors
+07/21/25 12:07:42:DEBUG:Using Parser v2.
+07/21/25 12:07:42:DEBUG:ParsePDF Complete
+07/21/25 12:07:42:DEBUG:Length of calculate_result results:0
+07/21/25 12:08:28:WARNING:***Starting Application***
+07/21/25 12:08:28:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:08:28:DEBUG:checkargs complete with no errors
+07/21/25 12:08:28:DEBUG:Using Parser v2.
+07/21/25 12:08:28:DEBUG:ParsePDF Complete
+07/21/25 12:08:40:WARNING:***Starting Application***
+07/21/25 12:08:40:DEBUG:Loading file: Payslip-01_06_2025.pdf
+07/21/25 12:08:40:DEBUG:checkargs complete with no errors
+07/21/25 12:08:40:DEBUG:Using Parser v2.
+07/21/25 12:08:40:DEBUG:ParsePDF Complete
+07/21/25 12:08:40:DEBUG:results: 1
+07/21/25 12:08:40:DEBUG:Length of calculate_result results:0
+07/21/25 12:08:56:WARNING:***Starting Application***
+07/21/25 12:08:56:DEBUG:Loading folder: 
+07/21/25 12:08:56:DEBUG:checkargs complete with no errors
+07/21/25 12:08:56:DEBUG:Using Parser v2.
+07/21/25 12:08:56:DEBUG:ParsePDF Complete
+07/21/25 12:08:56:DEBUG:Using Parser v2.
+07/21/25 12:08:56:DEBUG:ParsePDF Complete
+07/21/25 12:08:56:DEBUG:Using Parser v2.
+07/21/25 12:08:56:DEBUG:ParsePDF Complete
+07/21/25 12:08:56:DEBUG:Using Parser v2.
+07/21/25 12:08:56:DEBUG:ParsePDF Complete
+07/21/25 12:08:56:DEBUG:Using Parser v2.
+07/21/25 12:08:56:DEBUG:ParsePDF Complete
+07/21/25 12:08:56:DEBUG:Using Parser v2.
+07/21/25 12:08:56:DEBUG:ParsePDF Complete
+07/21/25 12:08:57:DEBUG:Using Parser v2.
+07/21/25 12:08:57:DEBUG:ParsePDF Complete
+07/21/25 12:08:57:DEBUG:Using Parser v2.
+07/21/25 12:08:57:DEBUG:ParsePDF Complete
+07/21/25 12:08:57:DEBUG:Using Parser v2.
+07/21/25 12:08:57:DEBUG:ParsePDF Complete
+07/21/25 12:08:57:DEBUG:Using Parser v2.
+07/21/25 12:08:57:DEBUG:ParsePDF Complete
+07/21/25 12:08:57:DEBUG:Using Parser v2.
+07/21/25 12:08:57:DEBUG:ParsePDF Complete
+07/21/25 12:08:57:DEBUG:Using Parser v2.
+07/21/25 12:08:57:DEBUG:ParsePDF Complete
+07/21/25 12:08:57:DEBUG:Using Parser v2.
+07/21/25 12:08:57:DEBUG:ParsePDF Complete
+07/21/25 12:08:57:DEBUG:Using Parser v2.
+07/21/25 12:08:57:DEBUG:ParsePDF Complete
+07/21/25 12:08:57:DEBUG:results: 14
+07/21/25 12:08:57:DEBUG:Length of calculate_result results:0
+07/21/25 12:08:57:DEBUG:calculate_result complete
+07/21/25 12:12:06:WARNING:***Starting Application***
+07/21/25 12:12:06:DEBUG:Loading folder: 2024
+07/21/25 12:12:06:DEBUG:checkargs complete with no errors
+07/21/25 12:12:06:DEBUG:Using Parser v2.
+07/21/25 12:12:06:DEBUG:ParsePDF Complete
+07/21/25 12:12:06:DEBUG:Using Parser v2.
+07/21/25 12:12:06:DEBUG:ParsePDF Complete
+07/21/25 12:12:06:DEBUG:Using Parser v2.
+07/21/25 12:12:06:DEBUG:ParsePDF Complete
+07/21/25 12:12:06:DEBUG:Using Parser v2.
+07/21/25 12:12:06:DEBUG:ParsePDF Complete
+07/21/25 12:12:06:DEBUG:Using Parser v2.
+07/21/25 12:12:06:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:12:07:DEBUG:Using Parser v2.
+07/21/25 12:12:07:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:WARNING:***Starting Application***
+07/21/25 12:14:01:DEBUG:Loading folder: 2024
+07/21/25 12:14:01:DEBUG:checkargs complete with no errors
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:01:DEBUG:Using Parser v2.
+07/21/25 12:14:01:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:WARNING:***Starting Application***
+07/21/25 12:14:26:DEBUG:Loading folder: 2024
+07/21/25 12:14:26:DEBUG:checkargs complete with no errors
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:26:DEBUG:Using Parser v2.
+07/21/25 12:14:26:DEBUG:ParsePDF Complete
+07/21/25 12:14:27:DEBUG:Using Parser v2.
+07/21/25 12:14:27:DEBUG:ParsePDF Complete
+07/21/25 12:14:27:DEBUG:Using Parser v2.
+07/21/25 12:14:27:DEBUG:ParsePDF Complete
+07/21/25 12:14:27:DEBUG:Using Parser v2.
+07/21/25 12:14:27:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:WARNING:***Starting Application***
+07/21/25 12:16:36:DEBUG:Loading folder: 2024
+07/21/25 12:16:36:DEBUG:checkargs complete with no errors
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:16:36:DEBUG:Using Parser v2.
+07/21/25 12:16:36:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:WARNING:***Starting Application***
+07/21/25 12:17:53:DEBUG:Loading folder: 2024
+07/21/25 12:17:53:DEBUG:checkargs complete with no errors
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:53:DEBUG:Using Parser v2.
+07/21/25 12:17:53:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:Using Parser v2.
+07/21/25 12:17:54:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:Using Parser v2.
+07/21/25 12:17:54:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:Using Parser v2.
+07/21/25 12:17:54:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:Using Parser v2.
+07/21/25 12:17:54:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:Using Parser v2.
+07/21/25 12:17:54:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:Using Parser v2.
+07/21/25 12:17:54:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:Using Parser v2.
+07/21/25 12:17:54:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:Using Parser v2.
+07/21/25 12:17:54:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:Using Parser v2.
+07/21/25 12:17:54:DEBUG:ParsePDF Complete
+07/21/25 12:17:54:DEBUG:results: 25
+07/21/25 12:17:54:DEBUG:Length of calculate_result results:0
+07/21/25 12:17:54:DEBUG:calculate_result complete

+ 332 - 0
main.py

@@ -0,0 +1,332 @@
+import calendar
+import os.path
+from pypdf import PdfReader
+from pypdf.errors import PdfReadError
+import sys
+import logging
+from datetime import datetime
+import csv
+
+logger = logging.getLogger(__name__)
+ch = logging.StreamHandler()
+ch.setLevel(logging.DEBUG)
+stream_formatter = logging.Formatter('%(levelname)s - %(message)s')
+ch.setFormatter(stream_formatter)
+logger.addHandler(ch)
+logging.basicConfig(filename='log.txt', encoding='utf-8', format='%(asctime)s:%(levelname)s:%(message)s',
+                    datefmt='%m/%d/%y %H:%M:%S', level=logging.DEBUG)
+
+
+# class paycheck:
+#
+#     def __init__(self):
+#         # TODO - add variables to be returned or obtained in code
+#         pass
+#
+#     pass
+
+
+def loadfiles(pointer, folder):
+    # Take a file or a folder as an input and load all applicable filenames into a list
+    # return a list
+    list_files = []
+    if folder:  # input is a folder
+        logger.debug("Loading folder: %s", os.path.basename(pointer))
+        for file in os.listdir(pointer):
+            list_files.append(os.path.join(pointer, file))
+    elif not folder:  # input is a file
+        list_files.append(pointer)
+        logger.debug("Loading file: %s", os.path.basename(pointer))
+
+    return list_files
+
+
+def checkargs(args):
+    list_file = []
+    list_folder = []
+    for arg in args[1:]:
+        if os.path.isfile(arg):
+            list_file.append(arg)
+        elif os.path.isdir(arg):
+            list_folder.append(arg)
+        if arg == "-debug":
+            global debug
+            debug = True
+
+    # print(dict_file["folder"])
+    if not len(list_file) == 1 and not len(list_folder) == 1:
+        raise Exception("Error parsing filename or folder name.")
+    if len(list_file) == 1 and len(list_folder) == 1:
+        raise Exception("Both filename and folder provided.")
+
+    if list_file:
+        files = loadfiles(list_file[0], False)
+    elif list_folder:
+        files = loadfiles(list_folder[0], True)
+    else:
+        raise Exception("Error sending file or folder to loadfiles.")
+
+    logging.debug('checkargs complete with no errors')
+
+    return (files)
+
+
+def paycheckv2_parser(lines, filename):
+    ###  This will parse paychecks using the post Jul 2022 formar
+    keywords = ['Current', 'BANK OF AMERICA', 'Earnings', 'TFP']
+    dict_result = {}
+    dict_tfp = {}
+
+    dict_result['Filename'] = filename
+    dict_result["Check Date"] = datetime.strptime(lines[2].split()[8], "%m/%d/%Y")
+    dict_result["ParserVersion"] = "V2"
+
+    for line in lines:
+        # print(line)
+        dict_result["month"] = dict_result["Check Date"].strftime('%m')
+        if line.find(keywords[0]) == 0:
+            dict_result["Gross Pay"] = line.split()[1]
+        if line.find(keywords[1]) >= 0:
+            dict_result["BoA Deposit"] = line.split()[6]
+        if line.find(keywords[2]) == 0 and len(line.split()) > 1:
+            dict_result["Earnings"] = line.split()[1]
+        if line.find(keywords[3]) >= 0 and not line.find('TFP/Hrs') >= 0:
+            ## Only displays for second paycheck of the period
+            ## check if third from last entry is a number of some sort.  This shows it is a current pay item
+            tfp_line = line.split()
+            if len(tfp_line) >= 5:
+                if tfp_line[-3].find('.') >= 0 and not tfp_line[-1] == "Taxes":
+                    desc = ' '.join(tfp_line[:-3])
+                    amt = tfp_line[-3][:-6]
+                    dict_tfp[desc] = amt
+                    dict_result["TFP"] = dict_tfp
+            if tfp_line[-1] == "Taxes" and tfp_line[-4].find('.') >= 0:
+                desc = tfp_line[0]
+                amt = tfp_line[-4][:-6]
+                dict_tfp[desc] = amt
+                dict_result["TFP"] = dict_tfp
+
+    total_tfp = float(0)
+    for tfp in dict_tfp.items():
+        total_tfp += float(tfp[1])
+    dict_result["Total TFP"] = round(total_tfp, 2)
+
+    # print(dict_result)
+
+    return dict_result
+
+
+def paycheckv1_parser(lines, filename, linetwo):
+    # Check Date
+    # Gross Pay
+    # BoA Deposit
+    # earnings
+    # TFP
+
+    dict_result = {}
+    dict_tfp = {}
+
+    dateline_num = 2
+    grosspayline_num = 4
+
+    if linetwo == "45":
+        dateline_num += 1
+        grosspayline_num += 1
+
+    # print(lines[3])
+    dateline = datetime.strptime(list(filter(None, lines[dateline_num].split(' ')))[5], '%m/%d/%Y').month
+    # print(dateline)
+    earningsline = list(filter(None, lines[grosspayline_num].split(' ')))
+    # print(earningsline)
+
+    # print(filename, earningsline[earningsline.index('=')+1])
+    dict_result['Filename'] = filename
+    dict_result["Check Date"] = datetime.strptime(list(filter(None, lines[dateline_num].split(' ')))[5], "%m/%d/%Y")
+    dict_result['month'] = datetime.strptime(list(filter(None, lines[dateline_num].split(' ')))[5], "%m/%d/%Y").month
+    dict_result["ParserVersion"] = "V1"
+    dict_result["Gross Pay"] = list(filter(None, lines[grosspayline_num].split(' ')))[0]
+    dict_result["Earnings"] = earningsline[earningsline.index('=') + 1]
+    dict_result["BoA Deposit"] = float(0.0)
+
+    start = 0
+    end = 0
+
+    for i, line in enumerate(lines):
+        # print(line)
+        if line.find("BANK OF AMERICA") >= 0:
+            dict_result["BoA Deposit"] = list(filter(None, line.split(' ')))[-1]
+        if line.find("Gross") >= 0 and line.find("Hrs") >= 0:
+            # print("START")
+            start = i
+        if line.find('Total Gross Pay') >= 0:
+            # print("END")
+            end = i
+
+    for line in lines[start + 1:end - 1]:
+        split_line = line.split(' ')
+        desc = (line[:26].strip())
+        # print(desc)
+        dataline = line[26:].split(' ')
+        tfp = 0
+        if len(dataline[0]) > 0 and not desc == "Pilot Per Diem DAY":
+            tfp = float(dataline[0])
+
+        # print(desc, tfp)
+
+        if tfp > 0:
+            dict_tfp[desc] = tfp
+
+    dict_result["TFP"] = dict_tfp
+
+    total_tfp = float(0)
+    for tfp in dict_tfp.items():
+        total_tfp += float(tfp[1])
+    dict_result["Total TFP"] = round(total_tfp, 2)
+
+    # print(dict_result)
+
+    return dict_result
+
+
+def calculate_result(list_result):
+    if not type(list_result) is list:
+        raise Exception("calculate_result requires a list of dictionaries, even if one item.")
+
+    if len(list_result) > 1:
+        list_result = consolodateMonths(list_result)
+
+    result = []
+
+    logging.debug('Length of calculate_result results:' + str(len(result)))
+
+    for resulty in list_result:
+        # print(resulty)
+        if resulty['Total BoA'] > 0 and resulty['Total Earnings'] > 0:
+            try:
+                resulty['BoA to Earnings'] = resulty['Total BoA'] / resulty['Total Earnings']
+                resulty['BoA to TFP'] = resulty['Total BoA'] / resulty['Total TFP']
+                resulty['Total Deductions'] = resulty['Gross Pay'] - resulty['Total Earnings']
+            except ZeroDivisionError:
+                logging.warning("Zero Division Error")
+            except:
+                logging.warning('Unable to calculate totals.  Something went wrong.')
+        result.append(resulty)
+
+    logging.debug('calculate_result complete')
+
+    return(result)
+
+
+def consolodateMonths(list_results):
+    # Takes list with all data and builds a new list with all paychecks for each month combined and totaled
+    list_monthdata = []
+
+    # print(list_results)
+    # print(datetime.strftime(list_results[0]['Check Date'], '%Y'))
+
+    for month in range(1, 13):
+        monthdata = {}
+        monthdata['Gross Pay'] = 0
+        monthdata['Total TFP'] = 0
+        monthdata['Total BoA'] = 0
+        monthdata['Total Earnings'] = 0
+        monthdata['Month'] = int(month)
+        monthdata['Year'] = datetime.strftime(list_results[0]['Check Date'], '%Y')
+        for i, check in enumerate(list_results):
+            if int(check['Check Date'].strftime('%m').lstrip('0')) == month:
+                # print(check)
+                monthdata['Gross Pay'] += float(check['Gross Pay'].replace(',', ''))
+                monthdata['Total TFP'] += float(check['Total TFP'])
+                if check['BoA Deposit'] != float(0.0):
+                    monthdata['Total BoA'] += float(check['BoA Deposit'].replace(',', ''))
+                monthdata['Total Earnings'] += float(check['Earnings'].replace(',', ''))
+
+        list_monthdata.append(monthdata)
+
+    # print(list_monthdata)
+
+    return list_monthdata
+
+
+def parse_pdf(filename):  # Takes only one fielname, not a list!
+
+    if type(filename) == list:
+        raise Exception("parse_pdf accepts only one input, not a list")
+
+    list_result = []
+
+    # for file in filename:
+    templines = []
+    #print(file)
+    #Test if file is valid pdf file
+
+    try:
+        reader = PdfReader(filename)
+    except PdfReadError:
+        raise Exception(filename, "is not a valid PDF file.")
+
+    pages = reader.pages
+    # print(pages)
+
+    for i in range(len(pages)):
+        templines.append(pages[i].extract_text().split('\n'))
+    if len(pages) == 1:
+        lines = templines[0]
+    elif len(pages) == 2:
+        lines = templines[0] + templines[1]
+    else:
+        raise Exception('Paycheck', i, ' appears to be greater than 2 pages.  Unable to Parse')
+
+
+    # If lines[1] == 81, then its post July 2022 (new format)
+    # If lines[1] == about 121, then is pre July 2022 (old format)
+    # print(os.path.basename(filename))
+    # print(len(lines[1]), lines[1])
+    #
+    # Check for signs of paycheck versioning
+    if len(lines[1]) == 81:
+        result = paycheckv2_parser(lines, filename)
+        logging.debug('Using Parser v2.')
+    elif len(lines[1]) == 122:
+        result = paycheckv1_parser(lines, filename, "122")
+        logging.debug('Using Parser v1 with line 2 length 122.')
+    elif len(lines[1]) == 45:
+        result = paycheckv1_parser(lines, filename, "45")
+        logging.debug('Using Parser v1 with line 2 lenght 45')
+    else:
+        logger.warning("Unable to determine paycheck format for %s. Check logs for details.  Line 2 length: %s" % (os.path.basename(filename), str(len(lines[1]))))
+        raise Exception("Unable to determine paycheck format for %s. Check logs for details.  Line 2 length: %s" % (os.path.basename(filename), str(len(lines[1]))))
+
+    logging.debug('ParsePDF Complete')
+
+    return result
+
+
+# Begin Application
+
+logging.warning('***Starting Application***')	
+
+files = checkargs(sys.argv)  # Get Arguments from Command Line, check user's request, and return a list of files to
+
+result = []
+
+for i, file in enumerate(files):
+    if os.path.isfile(file):  # Ignore folders such as W2 or other statements
+      print(i, file)
+      result.append(parse_pdf(file))
+
+logging.debug('results: ' +str( len(result)))
+
+full_result = calculate_result(result)
+
+for i in full_result:
+    print(i)
+
+file_name = full_result[0]['Year']
+
+with open(f'{file_name}.csv', 'w',  newline='') as f:
+    w = csv.writer(f)
+    w.writerow(full_result[0].keys())
+    for row in full_result:
+        w.writerow(row.values())
+    f.close