You can now pay invoices with credits from the same vendor.

This commit is contained in:
2022-05-31 13:21:49 -07:00
parent abd79c4b41
commit 49a0684d63
4 changed files with 131 additions and 14 deletions

View File

@@ -508,6 +508,9 @@
:db/cardinality :db.cardinality/one}]]}
:auto-ap/add-payment-type-credit {:txes [[{:db/ident :payment-type/credit
:db/doc "Credit for negative invoices"}]]}
:auto-ap/add-payment-type-balance-credit {:txes [[{:db/ident :payment-type/balance-credit
:db/doc "Used for paying invoices from statement credits."}]]}
:auto-ap/fulltext-accounts {:txes [[{:db/ident :account/search-terms
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one

View File

@@ -10,7 +10,7 @@
[auto-ap.datomic.transactions :as d-transactions]
[auto-ap.datomic.vendors :as d-vendors]
[auto-ap.graphql.utils
:refer [->graphql <-graphql assert-admin assert-can-see-client enum->keyword assert-not-locked assert-none-locked]]
:refer [->graphql <-graphql assert-admin assert-failure assert-can-see-client enum->keyword assert-not-locked assert-none-locked]]
[auto-ap.numeric :refer [num->words]]
[auto-ap.time :refer [iso-date local-now parse]]
[auto-ap.utils :refer [by dollars-0?]]
@@ -212,7 +212,8 @@
type))
(defn invoice-payments [invoices invoice-amounts]
(->> (for [invoice invoices
:let [invoice-amount (invoice-amounts (:db/id invoice))]]
:let [invoice-amount (invoice-amounts (:db/id invoice))]
:when invoice-amount]
[{:invoice-payment/payment (-> invoice :invoice/vendor :db/id str)
:invoice-payment/amount invoice-amount
:invoice-payment/invoice (:db/id invoice)}
@@ -292,6 +293,16 @@
(conj payment)
(into (invoice-payments invoices invoice-amounts)))))
(defmethod invoices->entities :payment-type/balance-credit [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."})))
)
(defmethod invoices->entities :payment-type/credit [invoices vendor client bank-account type index invoice-amounts]
(when (>= (->> invoices
(map (comp invoice-amounts :db/id))
@@ -552,6 +563,76 @@
(:type args)
(:id context))))
(defn pay-invoices-from-balance [context {invoices :invoices
client-id :client_id} _]
(assert-can-see-client (:id context) client-id)
(let [invoices (d-invoices/get-multi invoices)
client (d-clients/get-by-id client-id)
_ (when (> (count (set (map :invoice/vendor invoices))) 1)
(assert-failure "Balance payments can only be done on one vendor at a time."))
_ (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)
credit-invoices (filter
(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)]))
(< (+ 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/invoices (map :db/id invoices)
:payment/type :payment-type/balance-credit
:payment/status :payment-status/cleared}]
(audit-transact (-> []
(conj payment)
(into (invoice-payments invoices invoice-amounts))) (:id context))
(->graphql {:invoices (d-invoices/get-multi (map :db/id invoices))})))
(def objects
{:payment {:fields {:id {:type :id}
:type {:type :payment_type}
@@ -601,6 +682,11 @@
:type {:type :payment_type}
:client_id {:type :id}}
:resolve :mutation/print-checks}
:pay_invoices_from_balance {:type :check_result
:args {:invoices {:type '(list :id)}
:client_id {:type :id}}
:resolve :mutation/pay-invoices-from-balance}
:add_handwritten_check {:type :check_result
:args {:invoice_payments {:type '(list :invoice_payment_amount)}
:date {:type 'String}
@@ -637,7 +723,8 @@
{:payment_type {:values [{:enum-value :check}
{:enum-value :cash}
{:enum-value :debit}
{:enum-value :credit}]}
{:enum-value :credit}
{:enum-value :balance_credit}]}
:payment_status {:values [{:enum-value :voided}
{:enum-value :pending}
{:enum-value :cleared}]}})
@@ -650,6 +737,7 @@
:mutation/void-payment void-payment
:mutation/void-payments void-payments
:mutation/print-checks print-checks
:mutation/pay-invoices-from-balance pay-invoices-from-balance
:mutation/add-handwritten-check add-handwritten-check
})

View File

@@ -689,13 +689,7 @@
})
(def enums
{:payment_type {:values [{:enum-value :check}
{:enum-value :cash}
{:enum-value :debit}
{:enum-value :credit}]}
:payment_status {:values [{:enum-value :voided}
{:enum-value :pending}
{:enum-value :cleared}]}})
{})
(def resolvers

View File

@@ -29,7 +29,8 @@
[goog.string :as gstring]
[re-frame.core :as re-frame]
[reagent.core :as r]
[vimsical.re-frame.fx.track :as track]))
[vimsical.re-frame.fx.track :as track]
[vimsical.re-frame.cofx.inject :as inject]))
(re-frame/reg-event-fx
::params-change
@@ -105,6 +106,30 @@
(:invoices (:print-checks result))
(:pdf-url (:print-checks result))])}}))
(re-frame/reg-event-fx
::pay-invoices-from-balance
[with-user (re-frame/inject-cofx ::inject/sub [::data-page/checked :invoices])]
(fn [{:keys [db user] ::data-page/keys [checked] :as cofx} _]
{:graphql
{:token user
:owns-state {:single ::print-checks}
:query-obj {:venia/operation {:operation/type :mutation
:operation/name "PayInvoicesFromBalance"}
:venia/queries [[:pay-invoices-from-balance
{:invoices (->> checked
(vals )
(filter (fn [{:keys [id outstanding-balance] }]
(and id outstanding-balance)))
(map :id))
:client_id (:client db)}
[[:invoices invoice-read]
:pdf_url]]]}
:on-success (fn [result]
[::checks-printed
(:invoices (:pay-invoices-from-balance result))
nil])}}))
(re-frame/reg-event-fx
::checks-printed
@@ -229,9 +254,16 @@
:disabled (status/disabled-for print-checks-status)} "Debit from " name])
(list
^{:key (str id "-credit")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::print-checks id :credit])
:disabled (status/disabled-for print-checks-status)} "Credit from " name]))))
(when (> balance 0.001)
^{:key "advanced-divider"} [:hr.dropdown-divider])
:disabled (status/disabled-for print-checks-status)} "Credit from " name]
))))
^{:key "advanced-divider"} [:hr.dropdown-divider]
(when (and (> (count checked-invoices) 1)
(= 1 (count (set (map (comp :id :vendor) (vals checked-invoices)))))
(< balance 0.001))
^{:key (str "balance-credit")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::pay-invoices-from-balance])
:disabled (status/disabled-for print-checks-status)} "Pay invoices using balance "])
(when (and (= 1 (count (set (map (comp :id :vendor) (vals checked-invoices)))))
(> balance 0.001))