From cecf021929d8c9017a112b2151b02064e79ccd06 Mon Sep 17 00:00:00 2001 From: Bryce Date: Thu, 8 Feb 2024 21:13:43 -0800 Subject: [PATCH] payments should load again. --- src/clj/auto_ap/graphql/checks.clj | 329 +++++++++++++------------- src/clj/auto_ap/routes/exports.fiddle | 12 + 2 files changed, 173 insertions(+), 168 deletions(-) create mode 100644 src/clj/auto_ap/routes/exports.fiddle diff --git a/src/clj/auto_ap/graphql/checks.clj b/src/clj/auto_ap/graphql/checks.clj index acf1bff1..c3612b36 100644 --- a/src/clj/auto_ap/graphql/checks.clj +++ b/src/clj/auto_ap/graphql/checks.clj @@ -43,7 +43,7 @@ (java.util UUID))) (def parser (f/formatter "MM/dd/YYYY")) -(defn date->str [t] +(defn date->str [t] (f/unparse parser t)) (defn distribute [nums] @@ -56,7 +56,7 @@ (take 6 (concat (reduce - (fn [[line & rest ] word] + (fn [[line & rest] word] (let [line (or line "")] (if (> (+ (count line) (count word)) 50) (concat [word line] rest) @@ -71,24 +71,23 @@ (pdf/pdf [{:left-margin 25 :right-margin 0 :top-margin 0 :bottom-margin 0 :size :letter} (let [{:keys [bank-account paid-to client check date amount memo] {print-as :vendor/print-as vendor-name :vendor/name :as vendor} :vendor} check - df (DecimalFormat. "#,###.00") + df (DecimalFormat. "#,###.00") word-amount (num->words amount) amount (str "--" (.format df amount) "--")] [:table {:num-cols 12 :border false :leading 11 :widths (distribute [2 3 3 3 3 3 3 3 3 2 2 2])} [(let [{:keys [:client/name] {:keys [:address/street1 :address/city :address/state :address/zip]} :client/address} client] - [:cell {:colspan 5 } [:paragraph {:leading 14} name "\n" street1 "\n" (str city ", " state " " zip)] ]) - (let [{:keys [:bank-account/bank-name :bank-account/bank-code] } bank-account] + [:cell {:colspan 5} [:paragraph {:leading 14} name "\n" street1 "\n" (str city ", " state " " zip)]]) + (let [{:keys [:bank-account/bank-name :bank-account/bank-code]} bank-account] [:cell {:colspan 5 :align :center} [:paragraph {:style :bold} bank-name] [:paragraph {:size 8 :leading 8} bank-code]]) [:cell {:colspan 2 :size 13} check]] [[:cell {:colspan 9}] - [:cell {:colspan 3 :leading -10} date]] - [[:cell {:colspan 12 :size 14}] - ] + [:cell {:colspan 3 :leading -10} date]] + [[:cell {:colspan 12 :size 14}]] [[:cell {:size 13 :leading 13} "PAY"] - [:cell {:size 8 :leading 8 } "TO THE ORDER OF"] + [:cell {:size 8 :leading 8} "TO THE ORDER OF"] [:cell {:colspan 7} (if (seq print-as) print-as vendor-name)] @@ -96,26 +95,25 @@ [[:cell {}] [:cell {:colspan 8 :size 7} (str " -- " word-amount " " (str/join "" (take (max - 2 - (- 95 - (count word-amount))) - (repeat "-")))) + 2 + (- 95 + (count word-amount))) + (repeat "-")))) [:line {:line-width 0.15 :color [50 50 50]}]] [:cell {:colspan 3}]] - + [[:cell {:size 9 :leading 11.5} "\n\n\n\n\nMEMO"] - [:cell {:colspan 5 :leading 11.5} (split-memo memo) + [:cell {:colspan 5 :leading 11.5} (split-memo memo) [:line {:line-width 0.15 :color [50 50 50]}]] - [:cell {:colspan 6 } (if (:client/signature-file client) - [:image { :top-margin 90 :xscale 0.30 :yscale 0.30 :align :center} + [:cell {:colspan 6} (if (:client/signature-file client) + [:image {:top-margin 90 :xscale 0.30 :yscale 0.30 :align :center} - (:client/signature-file client)] - [:spacer])]] + (:client/signature-file client)] + [:spacer])]] - #_[ - #_[:cell {:colspan 5} #_memo ] - #_[:cell {:colspan 6}]] + #_[#_[:cell {:colspan 5} #_memo] + #_[:cell {:colspan 6}]] [[:cell {:colspan 2}] [:cell {:colspan 10 :leading 30} @@ -125,13 +123,13 @@ (into [:cell {:colspan 9}] (let [{:keys [:client/name] - {:keys [:address/street1 :address/street2 :address/city :address/state :address/zip ]} :client/address} client] + {:keys [:address/street1 :address/street2 :address/city :address/state :address/zip]} :client/address} client] (filter identity (list [:paragraph " " name] [:paragraph " " street1] - (when (not (str/blank? street2)) - [:paragraph " " street2]) + (when (not (str/blank? street2)) + [:paragraph " " street2]) [:paragraph " " city ", " state " " zip])))) [:cell {:colspan 2 :size 13} check]] @@ -139,12 +137,11 @@ [[:cell {:colspan 12 :leading 74} [:spacer]]] [[:cell] - [:cell {:colspan 5} [:paragraph + [:cell {:colspan 5} [:paragraph " " vendor-name "\n" " " (:address/street1 (:vendor/address vendor)) "\n" (when (not (str/blank? (:address/street2 (:vendor/address vendor)))) - (str " " (:address/street2 (:vendor/address vendor)) "\n") - ) + (str " " (:address/street2 (:vendor/address vendor)) "\n")) " " (:address/city (:vendor/address vendor)) ", " (:address/state (:vendor/address vendor)) " " (:address/zip (:vendor/address vendor))]] [:cell {:align :right} "Paid to:\n" @@ -164,7 +161,7 @@ [[:cell {:colspan 12} [:spacer]]] [[:cell {:colspan 12} [:spacer]]] - [[:cell {:colspan 3}] + [[:cell {:colspan 3}] [:cell {:align :right :colspan 2} "Check:\n" "Vendor:\n" @@ -183,8 +180,7 @@ [:paragraph amount] [:paragraph date]]] [[:cell {:colspan 3} "Memo:"] - [:cell {:colspan 9} memo]] - ])] + [:cell {:colspan 9} memo]]])] output-stream) (.toByteArray output-stream))) @@ -197,8 +193,7 @@ - make-check-pdf - )] + make-check-pdf)] (s3/put-object :bucket-name (:data-bucket env) :key (:payment/s3-key check) :input-stream (io/make-input-stream check-bytes {}) @@ -210,8 +205,8 @@ (let [merged-pdf-stream (java.io.ByteArrayOutputStream.) uuid (str (UUID/randomUUID))] (apply pdf/collate (concat [{:size :letter} merged-pdf-stream] (->> keys - (map #(s3/get-object (:data-bucket env) %)) - (map :input-stream)))) + (map #(s3/get-object (:data-bucket env) %)) + (map :input-stream)))) (s3/put-object :bucket-name (:data-bucket env) :key (str "merged-checks/" uuid ".pdf") :input-stream (io/make-input-stream (.toByteArray merged-pdf-stream) {}) @@ -227,10 +222,10 @@ :let [invoice-amount (invoice-amounts (:db/id invoice))] :when (and invoice-amount (not= :invoice-status/voided (:invoice/status invoice)))] - [{:invoice-payment/payment (-> invoice :invoice/vendor :db/id str) - :invoice-payment/amount invoice-amount - :invoice-payment/invoice (:db/id invoice)} - [:pay (:db/id invoice) invoice-amount]]) + [{:invoice-payment/payment (-> invoice :invoice/vendor :db/id str) + :invoice-payment/amount invoice-amount + :invoice-payment/invoice (:db/id invoice)} + [:pay (:db/id invoice) invoice-amount]]) (reduce into []))) (defn base-payment [invoices vendor client bank-account _ _ invoice-amounts] @@ -239,49 +234,49 @@ :payment/amount (reduce + 0 (map (comp invoice-amounts :db/id) invoices)) :payment/vendor (:db/id vendor) :payment/client (:db/id client) - :payment/date (c/to-date (time/now)) + :payment/date (c/to-date (time/now)) :payment/invoices (map :db/id invoices)}) (defmethod invoices->entities :payment-type/check [invoices vendor client bank-account type index invoice-amounts] (when (<= (->> invoices - (map (comp invoice-amounts :db/id)) - (reduce + 0.0)) - 0.001) - (throw (ex-info "The selected invoices do not have an outstanding balance." - {:validation-error "The selected invoices do not have an outstanding balance."}))) + (map (comp invoice-amounts :db/id)) + (reduce + 0.0)) + 0.001) + (throw (ex-info "The selected invoices do not have an outstanding balance." + {:validation-error "The selected invoices do not have an outstanding balance."}))) (let [uuid (str (UUID/randomUUID)) memo (str "Invoice #'s: " - (str/join ", " - (map (fn [i] - (str (:invoice/invoice-number i) "(" (invoice-amounts (:db/id i)) ")")) - invoices))) + (str/join ", " + (map (fn [i] + (str (:invoice/invoice-number i) "(" (invoice-amounts (:db/id i)) ")")) + invoices))) base-payment (base-payment invoices vendor client bank-account type index invoice-amounts) payment - (remove-nils - (assoc base-payment - :payment/s3-uuid (when (> (:payment/amount base-payment) 0) uuid) - :payment/s3-key (when (> (:payment/amount base-payment) 0) (str "checks/" uuid ".pdf")) - :payment/s3-url (when (> (:payment/amount base-payment) 0) (str "https://" (:data-bucket env) "/checks/" uuid ".pdf")) - :payment/check-number (+ index (:bank-account/check-number bank-account)) - :payment/type :payment-type/check - :payment/memo memo - :payment/status :payment-status/pending - :payment/pdf-data (pr-str {:vendor vendor - :paid-to (or (:vendor/paid-to vendor) (:vendor/name vendor)) - :amount (reduce + 0 (map (comp invoice-amounts :db/id) invoices)) - :check (str (+ index (:bank-account/check-number bank-account))) - :memo memo - :date (date->str (local-now)) - :client (dissoc client :client/bank-accounts :client/square-integration-status :client/ezcater-locations :client/locked-until :client/emails :client/square-auth-token :client/square-locations) - :bank-account (dissoc bank-account :bank-account/start-date :bank-account/integration-status) - #_#_:client {:name (:name client) - :address (:address client) - :signature-file (:signature-file client) - :bank {:name (:bank-account/bank-name bank-account) - :acct (:bank-account/bank-code bank-account) - :routing (:bank-account/routing bank-account) - :acct-number (:bank-account/number bank-account)}}})))] - + (remove-nils + (assoc base-payment + :payment/s3-uuid (when (> (:payment/amount base-payment) 0) uuid) + :payment/s3-key (when (> (:payment/amount base-payment) 0) (str "checks/" uuid ".pdf")) + :payment/s3-url (when (> (:payment/amount base-payment) 0) (str "https://" (:data-bucket env) "/checks/" uuid ".pdf")) + :payment/check-number (+ index (:bank-account/check-number bank-account)) + :payment/type :payment-type/check + :payment/memo memo + :payment/status :payment-status/pending + :payment/pdf-data (pr-str {:vendor vendor + :paid-to (or (:vendor/paid-to vendor) (:vendor/name vendor)) + :amount (reduce + 0 (map (comp invoice-amounts :db/id) invoices)) + :check (str (+ index (:bank-account/check-number bank-account))) + :memo memo + :date (date->str (local-now)) + :client (dissoc client :client/bank-accounts :client/square-integration-status :client/ezcater-locations :client/locked-until :client/emails :client/square-auth-token :client/square-locations) + :bank-account (dissoc bank-account :bank-account/start-date :bank-account/integration-status) + #_#_:client {:name (:name client) + :address (:address client) + :signature-file (:signature-file client) + :bank {:name (:bank-account/bank-name bank-account) + :acct (:bank-account/bank-code bank-account) + :routing (:bank-account/routing bank-account) + :acct-number (:bank-account/number bank-account)}}})))] + (-> [] (conj payment) (into (invoice-payments invoices invoice-amounts))))) @@ -313,8 +308,7 @@ (reduce + 0.0)) 0.001) (throw (ex-info "The selected invoices do not have an outstanding balance." - {:validation-error "The selected invoices do not have an outstanding balance."}))) - ) + {:validation-error "The selected invoices do not have an outstanding balance."})))) (defmethod invoices->entities :payment-type/credit [invoices vendor client bank-account type index invoice-amounts] (when (>= (->> invoices @@ -376,17 +370,16 @@ (into (invoice-payments invoices invoice-amounts))))) (defn validate-belonging [client-id invoices bank-account] - (when-not (apply = client-id (map (comp :db/id :invoice/client) invoices )) + (when-not (apply = client-id (map (comp :db/id :invoice/client) invoices)) (throw (ex-info "You can't pay for that invoice from this bank account." {:validation-error "You can't pay for that invoice from this bank account." :client-id client-id - :invoices (map :invoice/invoice-number invoices)})) - ) + :invoices (map :invoice/invoice-number invoices)}))) (when-not (= client-id (:db/id (:client/_bank-accounts bank-account))) - (throw (ex-info "The selected bank doesn't belong to this client" - {:validation-error "The selected bank doesn't belong to this client" - :client-id client-id - :invoices (map :invoice/invoice-number invoices)})))) + (throw (ex-info "The selected bank doesn't belong to this client" + {:validation-error "The selected bank doesn't belong to this client" + :client-id client-id + :invoices (map :invoice/invoice-number invoices)})))) (defn print-checks-internal [invoice-payments client-id bank-account-id type id] (let [type (keyword "payment-type" (name type)) @@ -418,10 +411,10 @@ checks)))) (let [result (audit-transact (map #(if (map? %) (dissoc % :payment/pdf-data) - %) checks ) id)] - + %) checks) id)] + (doseq [[_ i] (:tempids result)] - (solr/touch-with-ledger i))) + (solr/touch-with-ledger i))) {:invoices (d-invoices/get-multi (map :invoice-id invoice-payments)) :pdf-url (if (= type :payment-type/check) (mu/trace ::merge-pdfs @@ -437,7 +430,7 @@ (assoc :clients (:clients context)) (update :payment-type enum->keyword "payment-type") (update :status enum->keyword "payment-status")))] - + [{:payments (->> payments (map (fn [payment] (if (seq (:transaction/_payment payment)) @@ -445,25 +438,25 @@ (set/rename-keys {:transaction/_payment :transaction}) (update :transaction first)) payment))) - (map ->graphql )) + (map ->graphql)) :total checks-count :count (count payments) - :start (-> args :filters (:start 0) ) - :end (+ (-> args :filters (:start 0) ) (count payments))}])) + :start (-> args :filters (:start 0)) + :end (+ (-> args :filters (:start 0)) (count payments))}])) (defn get-potential-payments [context args _] (let [transaction (d-transactions/get-by-id (:transaction_id args)) _ (assert-can-see-client (:id context) (:transaction/client transaction)) [payments _] (d-checks/get-graphql {:client-id (:db/id (:transaction/client transaction)) :clients [{:db/id (:db/id (:transaction/client transaction))}] - :bank-account-id (:db/id (:transaction/bank-account transaction)) + :bank-account-id (:db/id (:transaction/bank-account transaction)) :amount (- (:transaction/amount transaction)) :status :payment-status/pending :date-range {:start (time/plus (:transaction/date transaction) (time/days -90))}})] (map ->graphql (reverse (sort-by :payment/date payments))))) (defn add-handwritten-check [context args _] - (let [invoices (d-invoices/get-multi (map :invoice_id (:invoice_payments args))) + (let [invoices (d-invoices/get-multi (map :invoice_id (:invoice_payments args))) bank-account-id (:bank_account_id args) bank-account (d-bank-accounts/get-by-id bank-account-id) _ (doseq [invoice invoices] @@ -475,19 +468,19 @@ base-payment (base-payment invoices (:invoice/vendor (first invoices)) (:invoice/client (first invoices)) - bank-account - :payment-type/check - 0 - invoice-payment-lookup)] - + bank-account + :payment-type/check + 0 + invoice-payment-lookup)] + (let [result (audit-transact - (into [(assoc base-payment - :payment/type :payment-type/check - :payment/status :payment-status/pending - :payment/check-number (:check_number args) - :payment/date (c/to-date (parse (:date args) iso-date)))] - (invoice-payments invoices invoice-payment-lookup)) - (:id context))] + (into [(assoc base-payment + :payment/type :payment-type/check + :payment/status :payment-status/pending + :payment/check-number (:check_number args) + :payment/date (c/to-date (parse (:date args) iso-date)))] + (invoice-payments invoices invoice-payment-lookup)) + (:id context))] (doseq [[_ i] (:tempids result)] (solr/touch-with-ledger i))) (->graphql @@ -505,14 +498,14 @@ (let [removing-payments (mapcat (fn [x] (let [invoice (:invoice-payment/invoice x) new-balance (+ (:invoice/outstanding-balance invoice) - (:invoice-payment/amount x))] + (:invoice-payment/amount x))] [[:db/retractEntity (:db/id x)] [:upsert-invoice {:db/id (:db/id invoice) :invoice/outstanding-balance new-balance :invoice/status (if (dollars-0? new-balance) (:invoice/status invoice) :invoice-status/unpaid)}]])) - (:payment/invoices check)) + (:payment/invoices check)) updated-payment {:db/id id :payment/amount 0.0 :payment/status :payment-status/voided}] @@ -534,26 +527,25 @@ [?p :payment/client ?c] [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] [?p :payment/date ?d] - [(>= ?d ?lu)] - ] + [(>= ?d ?lu)]] (dc/db conn)) (map first) (mapcat (fn [{:keys [:db/id] invoices :invoice-payment/_payment}] - (into - [{:db/id id - :payment/amount 0.0 - :payment/status :payment-status/voided}] - (->> invoices - (mapcat (fn [{:keys [:invoice-payment/invoice :db/id :invoice-payment/amount]}] - (let [new-balance (+ (:invoice/outstanding-balance invoice) - amount)] - [[:db.fn/retractEntity id] - [:upsert-invoice {:db/id (:db/id invoice) - :invoice/outstanding-balance new-balance - :invoice/status (if (dollars-0? new-balance) - (:invoice/status invoice) - :invoice-status/unpaid)}]])))))))) + (into + [{:db/id id + :payment/amount 0.0 + :payment/status :payment-status/voided}] + (->> invoices + (mapcat (fn [{:keys [:invoice-payment/invoice :db/id :invoice-payment/amount]}] + (let [new-balance (+ (:invoice/outstanding-balance invoice) + amount)] + [[:db.fn/retractEntity id] + [:upsert-invoice {:db/id (:db/id invoice) + :invoice/outstanding-balance new-balance + :invoice/status (if (dollars-0? new-balance) + (:invoice/status invoice) + :invoice-status/unpaid)}]])))))))) id)) @@ -561,14 +553,14 @@ (assert-admin (:id context)) (let [args (assoc args :clients (:clients context)) ids (some-> args - :filters - (assoc :clients (:clients context)) - (<-graphql) - (update :payment-type enum->keyword "payment-type") - (update :status enum->keyword "payment-status") - (assoc :per-page Integer/MAX_VALUE) - d-checks/raw-graphql-ids - :ids) + :filters + (assoc :clients (:clients context)) + (<-graphql) + (update :payment-type enum->keyword "payment-type") + (update :status enum->keyword "payment-status") + (assoc :per-page Integer/MAX_VALUE) + d-checks/raw-graphql-ids + :ids) specific-ids (d-checks/filter-ids (:ids args)) all-ids (into (set ids) specific-ids)] (alog/info ::voiding-payments :count (count all-ids)) @@ -579,19 +571,20 @@ (defn get-all-payments [context args _] (assert-admin (:id context)) (map - ->graphql - (first (d-checks/get-graphql (assoc (<-graphql args) :count Integer/MAX_VALUE))))) + ->graphql + (first (d-checks/get-graphql (assoc (<-graphql (assoc args :clients (:clients context))) :count Integer/MAX_VALUE))))) + (defn print-checks [context args _] (assert-can-see-client (:id context) (:client_id args)) (->graphql - (print-checks-internal (map (fn [i] {:invoice-id (:invoice_id i) - :amount (:amount i)}) - (:invoice_payments args)) - (:client_id args) - (:bank_account_id args) - (:type args) - (:id context)))) + (print-checks-internal (map (fn [i] {:invoice-id (:invoice_id i) + :amount (:amount i)}) + (:invoice_payments args)) + (:client_id args) + (:bank_account_id args) + (:type args) + (:id context)))) (defn pay-invoices-from-balance [context {invoices :invoices client-id :client_id} _] @@ -603,54 +596,54 @@ _ (when (> (reduce + 0 (map :invoice/outstanding-balance invoices)) 0.001) (assert-failure "There isn't a positive balance to pay from.")) invoices-to-be-paid (filter - (fn [i] - (> (:invoice/outstanding-balance i) - 0.001)) - invoices) + (fn [i] + (> (:invoice/outstanding-balance i) + 0.001)) + invoices) credit-invoices (filter - (fn [i] - (< (:invoice/outstanding-balance i) - 0.001)) - invoices) + (fn [i] + (< (:invoice/outstanding-balance i) + 0.001)) + invoices) total-to-pay (reduce + 0 (map :invoice/outstanding-balance invoices-to-be-paid)) _ (when (<= total-to-pay 0.001) (assert-failure "You must select invoices that need to be paid.")) - + invoice-amounts (->> invoices-to-be-paid (map (fn [i] [(:db/id i) (:invoice/outstanding-balance i)])) (concat (->> credit-invoices (reduce - (fn [[remaining-to-pay invoice-amounts] invoice] - - (cond (dollars-0? (+ remaining-to-pay (:invoice/outstanding-balance invoice))) - (reduced (conj invoice-amounts - [(:db/id invoice) - (:invoice/outstanding-balance invoice)])) + (fn [[remaining-to-pay invoice-amounts] invoice] - (< (+ remaining-to-pay (:invoice/outstanding-balance invoice)) 0.0) - (reduced (conj invoice-amounts - [(:db/id invoice) - (- remaining-to-pay)])) + (cond (dollars-0? (+ remaining-to-pay (:invoice/outstanding-balance invoice))) + (reduced (conj invoice-amounts + [(:db/id invoice) + (:invoice/outstanding-balance invoice)])) - :else - [(+ remaining-to-pay (:invoice/outstanding-balance invoice)) - (conj invoice-amounts [(:db/id invoice) - (:invoice/outstanding-balance invoice)])])) - [total-to-pay []]))) + (< (+ remaining-to-pay (:invoice/outstanding-balance invoice)) 0.0) + (reduced (conj invoice-amounts + [(:db/id invoice) + (- remaining-to-pay)])) + + :else + [(+ remaining-to-pay (:invoice/outstanding-balance invoice)) + (conj invoice-amounts [(:db/id invoice) + (:invoice/outstanding-balance invoice)])])) + [total-to-pay []]))) (into {})) - - - + + + vendor-id (:db/id (:invoice/vendor (first invoices))) payment {:db/id (str vendor-id) :payment/amount total-to-pay :payment/vendor vendor-id :payment/client (:db/id client) - :payment/date (c/to-date (time/now)) + :payment/date (c/to-date (time/now)) :payment/invoices (map :db/id invoices) :payment/type :payment-type/balance-credit :payment/status :payment-status/cleared}] @@ -698,7 +691,7 @@ :statuses {:type '(list String)}} :resolve :get-all-payments} :payment_page {:type '(list :payment_page) - :args {:filters {:type :payment_filters}} + :args {:filters {:type :payment_filters}} :resolve :get-payment-page} :potential_payment_matches {:type '(list :payment) :args {:transaction_id {:type :id}} diff --git a/src/clj/auto_ap/routes/exports.fiddle b/src/clj/auto_ap/routes/exports.fiddle new file mode 100644 index 00000000..4cc28e33 --- /dev/null +++ b/src/clj/auto_ap/routes/exports.fiddle @@ -0,0 +1,12 @@ + +(let [query [[:all_payments + {:client-code "VS" + :original-id nil} + [:id :check-number :amount :memo :date :status :type :original-id + [:invoices [[:invoice [:id :original-id]] :amount]] + [:bank-account [:number :code :bank-name :bank-code :id]] + [:vendor [:name :id [:primary-contact [:name :email :phone]] [:default-account [:name :numeric-code :id]] [:address [:street1 :city :state :zip]]]] + [:client [:id :name :code]]]]] + payments (auto-ap.graphql/query {:user/role "admin"} (venia/graphql-query {:venia/queries (->graphql query)}))] + {:body + (list (:all-payments (:data payments)))})