Makes it possible to bulk change invoices
This commit is contained in:
@@ -2,10 +2,11 @@
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
:refer [conn remove-nils uri]]
|
||||
[auto-ap.ledger :refer [transact-with-ledger]]
|
||||
[auto-ap.ledger :refer [transact-with-ledger transact-batch-with-ledger]]
|
||||
[auto-ap.datomic.clients :as d-clients]
|
||||
[auto-ap.datomic.invoices :as d-invoices]
|
||||
[auto-ap.datomic.vendors :as d-vendors]
|
||||
[auto-ap.rule-matching :as rm]
|
||||
[auto-ap.graphql.checks :as gq-checks]
|
||||
[auto-ap.graphql.utils
|
||||
:as u
|
||||
@@ -239,19 +240,23 @@
|
||||
|
||||
(-> (d-invoices/get-by-id id) (->graphql (:id context)))))
|
||||
|
||||
(defn void-invoices [context args _]
|
||||
(let [_ (assert-admin (:id context))
|
||||
args (assoc args :id (:id context))
|
||||
ids (some-> args
|
||||
|
||||
(defn get-ids-matching-filters [args]
|
||||
(let [ids (some-> args
|
||||
:filters
|
||||
(assoc :id (:id context))
|
||||
(assoc :id (:id args))
|
||||
(<-graphql)
|
||||
(update :status enum->keyword "invoice-status")
|
||||
(assoc :per-page Integer/MAX_VALUE)
|
||||
d-invoices/raw-graphql-ids
|
||||
:ids)
|
||||
specific-ids (d-invoices/filter-ids (:ids args))
|
||||
all-ids (into (set ids) specific-ids)]
|
||||
specific-ids (d-invoices/filter-ids (:ids args))]
|
||||
(into (set ids) specific-ids)))
|
||||
|
||||
(defn void-invoices [context args _]
|
||||
(let [_ (assert-admin (:id context))
|
||||
args (assoc args :id (:id context))
|
||||
all-ids (all-ids-not-locked (get-ids-matching-filters args))]
|
||||
|
||||
(log/info "Voiding " (count all-ids) args)
|
||||
(transact-with-ledger
|
||||
@@ -341,6 +346,87 @@
|
||||
(d-invoices/get-by-id (:invoice_id args))
|
||||
(:id context))))
|
||||
|
||||
;; TODO - multiple versions of this now exist. fix in datomic migration?
|
||||
(defn maybe-code-accounts [invoice account-rules valid-locations]
|
||||
(with-precision 2
|
||||
(let [accounts (vec (mapcat
|
||||
(fn [ar]
|
||||
(let [cents-to-distribute (int (Math/round (Math/abs (* (:percentage ar)
|
||||
(:invoice/total invoice)
|
||||
100))))]
|
||||
(if (= "Shared" (:location ar))
|
||||
(do
|
||||
(->> valid-locations
|
||||
(map
|
||||
(fn [cents location]
|
||||
{:invoice-expense-account/account (:account_id ar)
|
||||
:invoice-expense-account/amount (* 0.01 cents)
|
||||
:invoice-expense-account/location location})
|
||||
(rm/spread-cents cents-to-distribute (count valid-locations)))))
|
||||
[(cond-> {:invoice-expense-account/account (:account_id ar)
|
||||
:invoice-expense-account/amount (* 0.01 cents-to-distribute)}
|
||||
(:location ar) (assoc :invoice-expense-account/location (:location ar)))])))
|
||||
account-rules))
|
||||
accounts (mapv
|
||||
(fn [a]
|
||||
(update a :invoice-expense-account/amount
|
||||
#(with-precision 2
|
||||
(double (.setScale (bigdec %) 2 java.math.RoundingMode/HALF_UP)))))
|
||||
accounts)
|
||||
leftover (with-precision 2 (.round (bigdec (- (Math/abs (:invoice/total invoice))
|
||||
(Math/abs (reduce + 0.0 (map #(:invoice-expense-account/amount %) accounts)))))
|
||||
*math-context*))
|
||||
accounts (if (seq accounts)
|
||||
(update-in accounts [(dec (count accounts)) :invoice-expense-account/amount] #(+ % (double leftover)))
|
||||
[])]
|
||||
[:reset (:db/id invoice) :invoice/expense-accounts accounts])))
|
||||
|
||||
(defn all-ids-not-locked [all-ids]
|
||||
(->> all-ids
|
||||
(d/q '[:find [?i ...]
|
||||
:in $ [?i ...]
|
||||
:where
|
||||
[?i :invoice/client ?c]
|
||||
[(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu]
|
||||
[?i :invoice/date ?d]
|
||||
[(>= ?d ?lu)]]
|
||||
(d/db conn))))
|
||||
|
||||
(defn bulk-change-invoices [context args _]
|
||||
(assert-admin (:id context))
|
||||
(when-not (:client_id args)
|
||||
(throw (ex-info "Client is required"
|
||||
{:validation-error "client is required"})))
|
||||
(let [args (assoc args :id (:id context))
|
||||
locations (:client/locations (d/pull (d/db conn)
|
||||
[:client/locations]
|
||||
(:client_id args)))
|
||||
all-ids (all-ids-not-locked (get-ids-matching-filters args))
|
||||
invoices (d/pull-many (d/db conn) '[:db/id :invoice/total] (vec all-ids))
|
||||
account-total (reduce + 0 (map (fn [x] (:percentage x)) (:accounts args)))]
|
||||
(log/info "client is" locations)
|
||||
(when
|
||||
(not (dollars= 1.0 account-total))
|
||||
(let [error (str "Account total (" account-total ") does not reach 100%")]
|
||||
(throw (ex-info error {:validation-error error}))))
|
||||
(doseq [a (:accounts args)
|
||||
:let [{:keys [:account/location :account/name]} (d/entity (d/db conn) (:account_id a))]]
|
||||
(when (and location (not= location (:location a)))
|
||||
(let [err (str "Account " name " uses location " (:location a) ", but is supposed to be " location)]
|
||||
(throw (ex-info err {:validation-error err}) )))
|
||||
(when (and (not location)
|
||||
(not (get (into #{"Shared"} locations)
|
||||
(:location a))))
|
||||
(let [err (str "Account " name " uses location " (:location a) ", but doesn't belong to the client.")]
|
||||
(throw (ex-info err {:validation-error err}) ))))
|
||||
(log/info "Bulk coding " (count all-ids) args)
|
||||
(transact-batch-with-ledger
|
||||
(map (fn [i]
|
||||
(maybe-code-accounts i (:accounts args) locations))
|
||||
invoices)
|
||||
(:id context))
|
||||
{:message (str "Successfully coded " (count all-ids) " invoices.")}))
|
||||
|
||||
(def objects
|
||||
{:invoice
|
||||
{:fields {:id {:type :id}
|
||||
@@ -423,7 +509,14 @@
|
||||
:edit_expense_accounts {:type :invoice
|
||||
:args {:invoice_id {:type :id}
|
||||
:expense_accounts {:type '(list :edit_expense_account)}}
|
||||
:resolve :mutation/edit-expense-accounts}})
|
||||
:resolve :mutation/edit-expense-accounts}
|
||||
|
||||
:bulk_change_invoices {:type :message
|
||||
:args {:filters {:type :invoice_filters}
|
||||
:client_id {:type :id}
|
||||
:accounts {:type '(list :edit_percentage_account)}
|
||||
:ids {:type '(list :id)}}
|
||||
:resolve :mutation/bulk-change-invoices}})
|
||||
|
||||
(def input-objects
|
||||
{:add_invoice
|
||||
@@ -462,6 +555,7 @@
|
||||
:scheduled_payments {:type 'Boolean}
|
||||
:client_id {:type :id}
|
||||
:vendor_id {:type :id}
|
||||
:account_id {:type :id}
|
||||
:amount_lte {:type :money}
|
||||
:amount_gte {:type :money}
|
||||
:invoice_number_like {:type 'String}
|
||||
@@ -485,6 +579,7 @@
|
||||
:mutation/edit-invoice edit-invoice
|
||||
:mutation/void-invoice void-invoice
|
||||
:mutation/void-invoices void-invoices
|
||||
:mutation/bulk-change-invoices bulk-change-invoices
|
||||
:mutation/unvoid-invoice unvoid-invoice
|
||||
:mutation/unautopay-invoice unautopay-invoice
|
||||
:mutation/edit-expense-accounts edit-expense-accounts})
|
||||
|
||||
Reference in New Issue
Block a user