Makes editing work correctly for non-admins
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
[auto-ap.datomic.invoices :as d-invoices]
|
||||
[auto-ap.graphql.utils :refer [assert-can-see-client
|
||||
assert-not-locked exception->4xx]]
|
||||
[auto-ap.logging :as alog]
|
||||
[auto-ap.routes.invoice :as route]
|
||||
[auto-ap.routes.utils
|
||||
:refer [wrap-client-redirect-unauthenticated]]
|
||||
@@ -69,8 +70,6 @@
|
||||
(defn check-vendor-default-account [vendor-id]
|
||||
(some? (:vendor/default-account (get-vendor vendor-id))))
|
||||
|
||||
;; TODO negative expense accounts for negative invoices?
|
||||
|
||||
(def new-form-schema
|
||||
[:map
|
||||
[:db/id {:optional true} [:maybe entity-id]]
|
||||
@@ -97,7 +96,7 @@
|
||||
[:fn {:error/message "Not an allowed account."}
|
||||
check-allowance]]]
|
||||
[:invoice-expense-account/location :string]
|
||||
[:invoice-expense-account/amount [:double {:min 0}]]]
|
||||
[:invoice-expense-account/amount :double]]
|
||||
[:fn {:error/fn (fn [r x] (:type r))
|
||||
:error/path [:invoice-expense-account/location]} check-invoice-expense-account-location]]]]])
|
||||
|
||||
@@ -557,36 +556,67 @@
|
||||
(when-not (dollars= total expense-account-total)
|
||||
(form-validation-error (str "Expense account total (" expense-account-total ") does not equal invoice total (" total ")")))))
|
||||
|
||||
(defn maybe-spread-locations [invoice]
|
||||
(let [valid-locations (pull-attr (dc/db conn) :client/locations (:invoice/client invoice))]
|
||||
(with-precision 2
|
||||
(let [expense-accounts (vec (mapcat
|
||||
(fn [ea]
|
||||
(let [cents-to-distribute (int (Math/round (Math/abs (* (:invoice-expense-account/amount ea) 100))))]
|
||||
(if (= "Shared" (:invoice-expense-account/location ea))
|
||||
(->> valid-locations
|
||||
(map
|
||||
(fn [cents location]
|
||||
(assoc ea
|
||||
:db/id (random-tempid)
|
||||
:invoice-expense-account/amount (* 0.01 cents)
|
||||
:invoice-expense-account/location location))
|
||||
(rm/spread-cents cents-to-distribute (count valid-locations))))
|
||||
[ea])))
|
||||
(:invoice/expense-accounts invoice)))
|
||||
expense-accounts (mapv
|
||||
(fn [a]
|
||||
(update a :invoice-expense-account/amount
|
||||
#(with-precision 2
|
||||
(double (.setScale (bigdec %) 2 java.math.RoundingMode/HALF_UP)))))
|
||||
expense-accounts)
|
||||
leftover (with-precision 2 (.round (bigdec (- (Math/abs (:invoice/total invoice))
|
||||
(Math/abs (reduce + 0.0 (map #(:invoice-expense-account/amount %) expense-accounts)))))
|
||||
*math-context*))
|
||||
accounts (if (seq expense-accounts)
|
||||
(update-in expense-accounts [(dec (count expense-accounts)) :invoice-expense-account/amount] #(+ % (double leftover)))
|
||||
[])]
|
||||
(assoc invoice :invoice/expense-accounts (into [] accounts))))))
|
||||
|
||||
(defn- calculate-spread
|
||||
"Helper function to calculate the amount to be assigned to each location"
|
||||
[shared-amount total-locations]
|
||||
(let [base-amount (int (/ shared-amount total-locations))
|
||||
remainder (- shared-amount (* base-amount total-locations))]
|
||||
{:base-amount base-amount
|
||||
:remainder remainder}))
|
||||
|
||||
|
||||
(defn- spread-expense-account
|
||||
"Spreads the expense account amount across the given locations"
|
||||
[locations expense-account]
|
||||
(if (= "Shared" (:invoice-expense-account/location expense-account))
|
||||
(let [{:keys [base-amount remainder]} (calculate-spread (:invoice-expense-account/amount expense-account) (count locations))]
|
||||
(map-indexed (fn [idx _]
|
||||
(assoc expense-account
|
||||
:invoice-expense-account/amount (+ base-amount (if (< idx remainder) 1 0))
|
||||
:invoice-expense-account/location (nth locations idx)))
|
||||
locations))
|
||||
[expense-account]))
|
||||
|
||||
(defn $->cents [x]
|
||||
(int
|
||||
(let [result (* 100M (bigdec x))]
|
||||
(.setScale result 0 java.math.BigDecimal/ROUND_HALF_UP))))
|
||||
|
||||
(defn cents->$ [x]
|
||||
(double
|
||||
(let [result (* 0.01M (bigdec x))]
|
||||
(.setScale result 2 java.math.BigDecimal/ROUND_HALF_UP))))
|
||||
|
||||
(defn- apply-total-delta-to-account [invoice-total eas]
|
||||
(when (seq eas)
|
||||
(let [leftover (- invoice-total (reduce + 0 (map :invoice-expense-account/amount eas)))
|
||||
leftover-beyond-a-single-cent? (or (< leftover -1)
|
||||
(> leftover 1))
|
||||
leftover (if leftover-beyond-a-single-cent?
|
||||
0
|
||||
leftover)
|
||||
[first-eas & rest] eas]
|
||||
(cons
|
||||
(update first-eas :invoice-expense-account/amount #(+ % leftover))
|
||||
rest))))
|
||||
|
||||
|
||||
(defn maybe-spread-locations
|
||||
"Converts any expense account for a \"Shared\" location into a separate expense account for all valid locations for that client"
|
||||
([invoice]
|
||||
(maybe-spread-locations invoice (pull-attr (dc/db conn) :client/locations (:invoice/client invoice))))
|
||||
([invoice locations]
|
||||
(update-in invoice
|
||||
[:invoice/expense-accounts]
|
||||
(fn [expense-accounts]
|
||||
(->> expense-accounts
|
||||
(map (fn [ea] (update ea :invoice-expense-account/amount $->cents)))
|
||||
(mapcat (partial spread-expense-account locations))
|
||||
(apply-total-delta-to-account ($->cents (:invoice/total invoice)))
|
||||
(map (fn [ea] (update ea :invoice-expense-account/amount cents->$))))))))
|
||||
|
||||
|
||||
|
||||
(defrecord NewWizard2 [_ current-step]
|
||||
mm/LinearModalWizard
|
||||
@@ -622,9 +652,27 @@
|
||||
new-form-schema)
|
||||
(submit [this {:keys [multi-form-state request-method identity] :as request}]
|
||||
(let [invoice (:snapshot multi-form-state)
|
||||
|
||||
_ (alog/peek invoice)
|
||||
extant? (:db/id invoice)
|
||||
client-id (->db-id (:invoice/client invoice))
|
||||
vendor-id (->db-id (:invoice/vendor invoice))
|
||||
paid-amount (if-let [outstanding-balance
|
||||
(and extant?
|
||||
(-
|
||||
(pull-attr (dc/db conn)
|
||||
:invoice/total
|
||||
(:db/id invoice))
|
||||
(pull-attr (dc/db conn)
|
||||
:invoice/outstanding-balance
|
||||
(:db/id invoice))))]
|
||||
outstanding-balance
|
||||
0.0)
|
||||
outstanding-balance (- (or
|
||||
(:invoice/total (:step-params multi-form-state))
|
||||
(:invoice/total (:snapshot multi-form-state)))
|
||||
paid-amount)
|
||||
|
||||
transaction [:upsert-invoice (-> multi-form-state
|
||||
:snapshot
|
||||
(assoc :db/id (or (:db/id invoice) "invoice"))
|
||||
@@ -638,11 +686,11 @@
|
||||
:invoice-expense-account/amount (or (:invoice/total (:step-params multi-form-state))
|
||||
(:invoice/total (:snapshot multi-form-state)))}]))
|
||||
(assoc
|
||||
:invoice/outstanding-balance (or
|
||||
(:invoice/total (:step-params multi-form-state))
|
||||
(:invoice/total (:snapshot multi-form-state)))
|
||||
:invoice/outstanding-balance outstanding-balance
|
||||
:invoice/import-status :import-status/imported
|
||||
:invoice/status :invoice-status/unpaid)
|
||||
:invoice/status (if (dollars= 0.0 outstanding-balance)
|
||||
:invoice-status/paid
|
||||
:invoice-status/unpaid))
|
||||
(maybe-spread-locations)
|
||||
(update :invoice/date coerce/to-date)
|
||||
(update :invoice/due coerce/to-date)
|
||||
|
||||
Reference in New Issue
Block a user