Add importer for employer taxes

This commit is contained in:
Ben Sturmfels 2024-02-20 18:26:45 +11:00
parent 76520640d1
commit c57b842c49
Signed by: bsturmfels
GPG key ID: 023C05E2C9C068F0
3 changed files with 148 additions and 139 deletions

View file

@ -19,7 +19,8 @@
(def data (import/read-grouped-csv "/home/ben/Downloads/2023-12-27_Pay-Item-Details_2023-12-2.csv")) (def data (import/read-grouped-csv "/home/ben/Downloads/2023-12-27_Pay-Item-Details_2023-12-2.csv"))
(def imported (def imported
(concat [(import/import-monthly-payroll data)] (concat [(import/import-monthly-payroll data)]
(import/import-individual-taxes data))) (import/import-individual-taxes data)
[(import/import-employer-taxes data)]))
(dd/pretty-print (dd/pretty-print
(dd/diff (dd/diff
@ -29,4 +30,9 @@
(doseq [i imported] (doseq [i imported]
(println (import/render-transaction i))) (println (import/render-transaction i)))
(dd/pretty-print
(dd/diff
(sort-postings (parse examples/employer-taxes))
(sort-postings [(import/import-employer-taxes data)])))
) )

View file

@ -36,16 +36,6 @@
bigdec-or-zero))))] bigdec-or-zero))))]
cleaned-records)) cleaned-records))
(defn monthly-payroll-trans [date desc receipt postings]
{:date date :desc desc
:meta {:program "Conservancy:Payroll"
:project "Conservancy"
:receipt receipt
:approval "Financial/Employment-Records/memo-re-board-approval-of-payroll.txt"
:tax-implication "W2"
:payroll-type "US:General"}
:postings postings})
(defn format-name [name] (defn format-name [name]
(case name (case name
"Sharp, Sage A" "Sharp-Sage-A" "Sharp, Sage A" "Sharp-Sage-A"
@ -81,144 +71,155 @@
"OR Disability PFL" "US:OR:Disability:PFL" "OR Disability PFL" "US:OR:Disability:PFL"
"NY Disability PFL" "US:NY:Disability:PFL" "NY Disability PFL" "US:NY:Disability:PFL"
"OR TRANS STT" "US:OR:Tax:STT" "OR TRANS STT" "US:OR:Tax:STT"
"Fed Unemploy" "US:Unemployment"
"IL Unemploy" "IL:Unemployment"
"NY Unemploy" "NY:Unemployment"
"OR Unemploy" "OR:Unemployment"
cat)) cat))
(defn indiv-payroll-trans [date desc name receipt postings]
{:date date :desc (format desc (format-name name))
:meta {:project (if (= (format-name name) "Sharp-Sage-A") "Outreachy" "Conservancy")
:program "Conservancy:Payroll"
:entity (format-name name)
:receipt receipt
:approval "Financial/Employment-Records/memo-re-board-approval-of-payroll.txt"}
:postings postings})
;; TODO: How do we know we used all the relevant data from the report? Didn't ;; TODO: How do we know we used all the relevant data from the report? Didn't
;; miss anything? ;; miss anything?
;; TODO: Split out the match amount into a separate transaction entry? ;; TODO: Split out the match amount into a separate transaction entry?
(defn import-monthly-payroll [groups] (defn import-monthly-payroll [groups]
(monthly-payroll-trans {:date "2023-12-29" :desc "Monthly Payroll - December 2023 - Net Pay"
"2023-12-29" :meta {:program "Conservancy:Payroll"
"Monthly Payroll - December 2023 - Net Pay" :project "Conservancy"
"rt:19462/674660" :receipt "rt:19462/674660"
(apply concat (for [[name records] groups] :approval "Financial/Employment-Records/memo-re-board-approval-of-payroll.txt"
(let [name (format-name name) :tax-implication "W2"
total-net-pay (->> records :payroll-type "US:General"}
(filter #(= (:type %) "Net Pay")) :postings
(map :t-net-pay) (apply concat (for [[name records] groups]
(apply +) (let [name (format-name name)
bigdec) total-net-pay (->> records
total-reimbursement (->> records (filter #(= (:type %) "Net Pay"))
(filter #(= (:type %) "Reimbursement")) (map :t-net-pay)
(map :t-reimbursement) (apply +)
(apply +) bigdec)
bigdec) total-reimbursement (->> records
total-net-pay-less-reimb (- total-net-pay total-reimbursement) (filter #(= (:type %) "Reimbursement"))
pay-exp-trans [{:account "Expenses:Payroll:Salary" (map :t-reimbursement)
:amount total-net-pay-less-reimb (apply +)
:currency "USD" bigdec)
:meta (if (= name "Sharp-Sage-A") total-net-pay-less-reimb (- total-net-pay total-reimbursement)
{:entity name pay-exp-trans [{:account "Expenses:Payroll:Salary"
:project "Outreachy"} :amount total-net-pay-less-reimb
{:entity name})} :currency "USD"
{:account "Assets:FR:Check2721" :meta (if (= name "Sharp-Sage-A")
:amount (- total-net-pay-less-reimb) {:entity name
:currency "USD" :project "Outreachy"}
:meta {:entity name}}] {:entity name})}
reimbursement-exp-trans [{:account "Expenses:Hosting" {:account "Assets:FR:Check2721"
:amount total-reimbursement :amount (- total-net-pay-less-reimb)
:currency "USD" :currency "USD"
:meta (if (= name "Sharp-Sage-A") :meta {:entity name}}]
{:entity name reimbursement-exp-trans [{:account "Expenses:Hosting"
:project "Outreachy" :amount total-reimbursement
:payroll-type "US:Reimbursement"} :currency "USD"
{:entity name :meta (if (= name "Sharp-Sage-A")
:payroll-type "US:Reimbursement"})} {:entity name
{:account "Assets:FR:Check2721" :project "Outreachy"
:amount (- total-reimbursement) :payroll-type "US:Reimbursement"}
:currency "USD" {:entity name
:meta (if (= name "Sharp-Sage-A") :payroll-type "US:Reimbursement"})}
{:entity name {:account "Assets:FR:Check2721"
:project "Outreachy" :amount (- total-reimbursement)
:tax-implication "Reimbursement"} :currency "USD"
{:entity name :meta (if (= name "Sharp-Sage-A")
:tax-implication "Reimbursement"})}]] {:entity name
(concat pay-exp-trans reimbursement-exp-trans)))) :project "Outreachy"
#_(apply concat (for [x data :when (or (and (= (:type x) "Net Pay") (> (:t-net-pay x) 0)) :tax-implication "Reimbursement"}
(and (= (:type x) "Reimbursement") (> (:t-reimbursement x) 0)))] {:entity name
(let [name (format-name (:name x))] :tax-implication "Reimbursement"})}]]
(case (:type x) (concat pay-exp-trans reimbursement-exp-trans))))})
"Net Pay"
"Reimbursement"
[{:account "Expenses:Hosting"
:amount (:t-reimbursement x)
:currency "USD"
:meta {:entity name
:payroll-type "US:Reimbursement"}}
{:account "Assets:FR:Check2721"
:amount (- (:t-reimbursement x))
:currency "USD"
:meta {:entity name
:tax-implication "Reimbursement"}}]))))))
(defn import-individual-taxes [groups] (defn import-individual-taxes [groups]
;; Print the individual taxes blocks ;; Print the individual taxes blocks
(for [[name records] groups] (for [[name records] groups]
(indiv-payroll-trans {:date "2023-12-29" :desc (format "Monthly Payroll - December 2023 - TAXES - %s" (format-name name))
"2023-12-29" :meta {:project (if (= (format-name name) "Sharp-Sage-A") "Outreachy" "Conservancy")
"Monthly Payroll - December 2023 - TAXES - %s" :program "Conservancy:Payroll"
name :entity (format-name name)
"rt:19462/674660" :receipt "rt:19462/674660"
(let [r-super-lines (filter #(str/starts-with? (:category %) "403b") records) :approval "Financial/Employment-Records/memo-re-board-approval-of-payroll.txt"}
;; TODO: Have I got the liability/witholding right? Which is used in which report. :postings
r-witholding-lines (filter #(= (:type %) "Withholding") records) (let [super-lines (filter #(str/starts-with? (:category %) "403b") records)
r-insurance-lines (filter #(and (= (:type %) "Withholding") ;; TODO: Have I got the liability/witholding right? Which is used in which report.
(str/includes? (:category %) "NY Disability")) records) witholding-lines (filter #(= (:type %) "Withholding") records)
total-super (->> r-super-lines insurance-lines (filter #(and (= (:type %) "Withholding")
(map :t-retirement) (str/includes? (:category %) "NY Disability")) records)
(apply +) total-super (->> super-lines
bigdec)] (map :t-retirement)
(concat (apply +)
(for [x r-super-lines] bigdec)]
(if (= (:category x) "403b ER match") (concat
{:account "Expenses:Payroll:Salary" (for [x super-lines]
:amount (:t-retirement x) (if (= (:category x) "403b ER match")
:currency "USD" {:account "Expenses:Payroll:Salary"
:meta {:payroll-type "US:403b:Match" :amount (:t-retirement x)
:invoice "rt:19403/675431"}} :currency "USD"
{:account "Expenses:Payroll:Salary" :meta {:payroll-type "US:403b:Match"
:amount (:t-retirement x) :invoice "rt:19403/675431"}}
:currency "USD" {:account "Expenses:Payroll:Salary"
:meta {:payroll-type "US:403b:Employee" :amount (:t-retirement x)
:invoice "rt:19403/675431"}})) :currency "USD"
[{:account "Liabilities:Payable:Accounts" :meta {:payroll-type "US:403b:Employee"
:amount (- total-super) :invoice "rt:19403/675431"}}))
:currency "USD" [{:account "Liabilities:Payable:Accounts"
:meta {:invoice "rt:19403/675431"}}] :amount (- total-super)
(conj :currency "USD"
(vec (for [x r-witholding-lines] :meta {:invoice "rt:19403/675431"}}]
{:account "Expenses:Payroll:Salary" (conj
:amount (:t-withholding x) (vec (for [x witholding-lines]
:currency "USD" {:account "Expenses:Payroll:Salary"
:meta {:payroll-type (cat->acct (:category x))}})) :amount (:t-withholding x)
{:account "Assets:FR:Check2721" :currency "USD"
:amount (- (reduce + (map :t-withholding r-witholding-lines))) :meta {:payroll-type (cat->acct (:category x))}}))
:currency "USD" {:account "Assets:FR:Check2721"
:meta {:tax-implication "W2"}}) :amount (- (reduce + (map :t-withholding witholding-lines)))
;; We seem to add these extra insurance lines for Karen (only). Confirm with Rosanne. :currency "USD"
(conj :meta {:tax-implication "W2"}})
(vec (for [x r-insurance-lines] ;; We seem to add these extra insurance lines for Karen (only). Confirm with Rosanne.
{:account "Expenses:Insurance" (conj
:amount (- (:t-withholding x)) (vec (for [x insurance-lines]
:currency "USD" {:account "Expenses:Insurance"
:meta {:payroll-type (cat->acct (:category x))}})) :amount (- (:t-withholding x))
{:account "Assets:FR:Check2721" :currency "USD"
:amount (bigdec (reduce + (map :t-withholding r-insurance-lines))) :meta {:payroll-type (cat->acct (:category x))}}))
:currency "USD" {:account "Assets:FR:Check2721"
:meta {}})))))) :amount (bigdec (reduce + (map :t-withholding insurance-lines)))
:currency "USD"})))}))
;; TODO: TAXES - Employer (defn import-employer-taxes [groups]
{:date "2023-12-29" :desc "Monthly Payroll - December 2023 - TAXES - Employer"
:meta {:program "Conservancy:Payroll"
:project "Conservancy"
:receipt "rt:19462/674660"
:approval "Financial/Employment-Records/memo-re-board-approval-of-payroll.txt"}
:postings
(let [total-emp-tax (reduce + (map :t-liability (apply concat (vals groups))))]
(conj (vec (apply concat (for [[name records] groups]
(let [name (format-name name)
liability-lines (filter #(= (:type %) "Liability") records)]
(for [x liability-lines]
{:account "Expenses:Payroll:Tax"
:amount (:t-liability x)
:currency "USD"
:meta (if (= name "Sharp-Sage-A")
{:entity name
:project "Outreachy"
;; TODO: Check lack of ":Tax:" with Rosanne.
:payroll-type (str/replace (cat->acct (:category x)) "Tax:" "")}
{:entity name
:payroll-type (str/replace (cat->acct (:category x)) "Tax:" "")})})))))
{:account "Assets:FR:Check2721"
:amount (- total-emp-tax)
:currency "USD"
:meta {:entity "Paychex"
:tax-implication "Tax-Payment"}
}))})
;; TODO: Fee ;; TODO: Fee

View file

@ -2,11 +2,13 @@
(:require [clojure.spec.alpha :as s] (:require [clojure.spec.alpha :as s]
[clojure.walk :as walk])) [clojure.walk :as walk]))
(s/def ::token (s/+ (set "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-:./"))) (s/def ::token (s/+ (set "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-:")))
(s/def ::number (s/+ (set "01234567890-.")))
(s/def ::quoted-token (s/cat (s/def ::quoted-token (s/cat
:_ #{\"} :_ #{\"}
:token (s/+ (set "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-:./ ")) :token (s/+ (set "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-:./% "))
:_ #{\"})) :_ #{\"}))
(s/def ::whitespace (s/+ #{\space})) (s/def ::whitespace (s/+ #{\space}))
@ -23,7 +25,7 @@
(s/cat :_ ::whitespace (s/cat :_ ::whitespace
:account ::token :account ::token
:_ ::whitespace :_ ::whitespace
:amount ::token :amount ::number
:_ ::whitespace :_ ::whitespace
:currency ::token :currency ::token
:_ #{\newline} :_ #{\newline}