;; Copyright 2024 Ben Sturmfels ;; License: GPLv3-or-later (ns core "Beancount importer for Paychex Pay Item Details report." (:require [clojure.tools.cli :refer [parse-opts]] [import :as import]) (:gen-class)) (def cli-options [[nil "--csv FILE" "Pay Item Details CSV report"] [nil "--date DATE" "Date used for the transactions (YYYY-MM-DD)" :validate [#(re-matches #"\d{4}-\d{2}-\d{2}" %) "Must be of format YYYY-MM-DD"] :default "TODO-DATE"] [nil "--period PERIOD" "Month/year covered by the pay run eg. \"December 2023\"" :default "TODO-PERIOD"] [nil "--total-fees NUM" "Total fee charged by Paychex, eg. \"206.50\"" :parse-fn bigdec :default 0M] [nil "--pay-receipt-no REFERENCE" "Payroll receipt number, eg. \"rt:111/222\"" :default "TODO-PAY-RECEIPT"] [nil "--fees-receipt-no REFERENCE" "Paychex fees receipt number, eg. \"rt:111/222\"" :default "TODO-FEES-RECEIPT"] [nil "--fees-invoice-no REFERENCE" "Paychex fees invoice number, eg. \"rt:111/222\"" :default "TODO-FEES-INVOICE"] [nil "--retirement-receipt-no REFERENCE" "Retirement receipt number, eg. \"rt:111/222\"" :default "TODO-RETIREMENT-RECEIPT"] [nil "--retirement-invoice-no REFERENCE" "Retirement receipt number, eg. \"rt:111/222\"" :default "TODO-RETIREMENT-INVOICE"] ["-h" "--help"]]) (defn -main [& args] (let [{:keys [options _arguments _errors summary]} (parse-opts args cli-options) {:keys [date period pay-receipt-no total-fees fees-receipt-no fees-invoice-no retirement-receipt-no retirement-invoice-no]} options] (when (:help options) (println summary) (System/exit 0)) (let [data (import/read-csv (:csv options)) imported (concat (import/payroll date period pay-receipt-no data) (import/individual-taxes date period pay-receipt-no retirement-invoice-no data) (import/employer-taxes date period pay-receipt-no data) (import/payroll-fees date period fees-receipt-no fees-invoice-no total-fees data) (import/retirement date period retirement-receipt-no retirement-invoice-no data))] (doseq [i imported] (println (import/render-transaction i)))))) (comment ;; Examples to exercise the importer during development. (require '[parse :refer [parse sort-postings]] '[lambdaisland.deep-diff2 :as dd]) ;; These examples are not included with the code for privacy reasons. (require '[examples]) (def data (import/read-csv "/home/ben/Downloads/2023-12-27_Pay-Item-Details_2023-12-2.csv")) (def imported (concat (import/payroll "2023-12-29" "December 2023" "rt:19462/674660" data) (import/individual-taxes "2023-12-29" "December 2023" "rt:19462/674660" "rt:19403/675431" data) (import/employer-taxes "2023-12-29" "December 2023" "rt:19462/674660" data) (import/payroll-fees "2023-12-29" "December 2023" "rt:19459/675387" "rt:19459/674887" 206.50M data) (import/retirement "2024-01-02" "December 2023" "rt:19403/676724" "rt:19403/675431" data))) (dd/pretty-print (dd/diff (sort-postings (parse examples/dec-2023)) (sort-postings imported))) (def data (import/read-csv "/home/ben/Downloads/2024-01-29_Pay-Item-Details_2024-01.csv")) (def imported (concat (import/payroll "2024-01-31" "January 2024" "rt:19462/685751" data) (import/individual-taxes "2024-01-31" "January 2024" "rt:19462/685751" "rt:19403/685602" data) (import/employer-taxes "2024-01-31" "January 2024" "rt:19462/685751" data) (import/payroll-fees "2024-01-31" "January 2024" "rt:19459/675387" "rt:19459/674887" 206.50M data) (import/retirement "2024-01-31" "January 2024" "rt:19403/685929" "rt:19403/685602" data))) ;; Compare hand-written transactions with imported (ignoring ordering). (dd/pretty-print (dd/diff (sort-postings (parse examples/jan-2024)) (sort-postings imported))) ;; Print out text transactions (doseq [i imported] (println (import/render-transaction i))) )