diff --git a/project.clj b/project.clj index 3cc85652..723284a3 100644 --- a/project.clj +++ b/project.clj @@ -149,6 +149,7 @@ :uberjar {:java-cmd "/usr/lib/jvm/java-11-openjdk/bin/java" :prep-tasks ["fig:min" ] + :aot [auto-ap.server auto-ap.time clj-time.core clj-time.coerce clj-time.format clojure.tools.logging.impl ] :dependencies [[com.bhauman/figwheel-main "0.2.18" :exclusions [org.clojure/clojurescript ring ring/ring-core @@ -180,9 +181,6 @@ } :main auto-ap.server - - #_#_:aot [auto-ap.server auto-ap.time clj-time.core clj-time.coerce clj-time.format clojure.tools.logging.impl] - :uberjar-name "auto-ap.jar" :test-paths ["test/clj"] :test-selectors {:integration (fn [m] diff --git a/src/clj/auto_ap/graphql/invoices.clj b/src/clj/auto_ap/graphql/invoices.clj index 2842a2c4..ea305baa 100644 --- a/src/clj/auto_ap/graphql/invoices.clj +++ b/src/clj/auto_ap/graphql/invoices.clj @@ -25,7 +25,7 @@ [datomic.api :as dc] [auto-ap.solr :as solr])) -(defn ->graphql [invoice user ] +(defn ->graphql [invoice user] (if (= "admin" (:user/role user)) (u/->graphql invoice) (u/->graphql (if (:invoice/source-url-admin-only invoice) @@ -56,26 +56,35 @@ (first (d-invoices/get-graphql (assoc (<-graphql args) :count Integer/MAX_VALUE))))) +(defn pending-invoices [invoices] + (->> (dc/q '[:find ?i + :in $ [?i ...] + :where [?i :invoice/import-status :import-status/pending]] + (dc/db conn) + invoices) + (map first))) + (defn reject-invoices [context {:keys [invoices]} _] (assert-power-user (:id context)) - (doseq [i invoices] - (assert-can-see-client (:id context) (:db/id (:invoice/client (dc/pull (dc/db conn) [{:invoice/client [:db/id]}] i))))) - (let [transactions (mapcat (fn [i] [[:db/retractEntity i]]) - invoices)] - (audit-transact transactions (:id context)) - invoices)) + (let [invoices (pending-invoices invoices)] + (doseq [i invoices] + (assert-can-see-client (:id context) (:db/id (:invoice/client (dc/pull (dc/db conn) [{:invoice/client [:db/id]}] i))))) + (let [transactions (mapcat (fn [i] [[:db/retractEntity i]]) + invoices)] + (audit-transact transactions (:id context)) + invoices))) (defn approve-invoices [context {:keys [invoices]} _] (assert-power-user (:id context)) - (doseq [i invoices - :let [invoice (dc/pull (dc/db conn) [{:invoice/client [:db/id]} - :invoice/date] - i)]] - (assert-can-see-client (:id context) (-> invoice :invoice/client :db/id)) - (assert-not-locked (-> invoice :invoice/client :db/id) (-> invoice :invoice/date))) - (let [transactions (map (fn [i] [:upsert-invoice {:db/id i :invoice/import-status :import-status/imported}]) invoices)] - (audit-transact transactions (:id context)) - invoices)) + (let [invoices (pending-invoices invoices)] + (doseq [i invoices + :let [invoice (dc/pull (dc/db conn) '[{:invoice/client [:db/id]} + :invoice/date] i)]] + (assert-can-see-client (:id context) (-> invoice :invoice/client :db/id)) + (assert-not-locked (-> invoice :invoice/client :db/id) (-> invoice :invoice/date))) + (let [transactions (map (fn [i] [:upsert-invoice {:db/id i :invoice/import-status :import-status/imported}]) invoices)] + (audit-transact transactions (:id context)) + invoices))) (defn assert-no-conflicting [{:keys [invoice_number client_id vendor_id]}] (when-not vendor_id @@ -107,7 +116,7 @@ nil) _ (when-not (:db/id account) (throw (ex-info (str "Vendor '" (:vendor/name vendor) "' does not have a default expense acount.") {:vendor-id vendor_id})))] - + [:upsert-invoice {:db/id "invoice" :invoice/invoice-number invoice_number :invoice/client client_id @@ -141,7 +150,7 @@ (when (and (= :allowance/denied (:db/ident (:account/invoice-allowance account))) - (not= (pull-ref (dc/db conn) :vendor/default-account vendor_id ) + (not= (pull-ref (dc/db conn) :vendor/default-account vendor_id) (:db/id account))) (let [err (str "Account isn't allowed for invoice use.")] (throw (ex-info err @@ -188,7 +197,7 @@ (defn add-and-print-invoice [context {{:keys [total client_id vendor_id] :as in} :invoice bank-account-id :bank_account_id type :type} _] (mu/trace ::validating-invoice [:invoice in] - (do + (do (assert-no-conflicting in) (assert-can-see-client (:id context) client_id) (assert-bank-account-belongs client_id bank-account-id) @@ -227,7 +236,7 @@ :invoice/total total :invoice/outstanding-balance (- total paid-amount) :invoice/expense-accounts (map expense-account->entity - expense_accounts) + expense_accounts) :invoice/due (coerce/to-date due) :invoice/scheduled-payment (coerce/to-date scheduled_payment)}] (audit-transact [[:upsert-invoice updated-invoice]] @@ -241,12 +250,12 @@ (assert-can-see-client (:id context) (:db/id (:invoice/client invoice))) (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice)) (audit-transact [[:upsert-invoice {:db/id id - :invoice/total 0.0 - :invoice/outstanding-balance 0.0 - :invoice/status :invoice-status/voided - :invoice/expense-accounts (map (fn [ea] {:db/id (:db/id ea) - :invoice-expense-account/amount 0.0}) - (:invoice/expense-accounts invoice))}]] + :invoice/total 0.0 + :invoice/outstanding-balance 0.0 + :invoice/status :invoice-status/voided + :invoice/expense-accounts (map (fn [ea] {:db/id (:db/id ea) + :invoice-expense-account/amount 0.0}) + (:invoice/expense-accounts invoice))}]] (:id context)) (-> (d-invoices/get-by-id id) (->graphql (:id context))))) @@ -267,13 +276,13 @@ (defn all-ids-not-locked [all-ids] (->> all-ids (dc/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)]] - (dc/db conn)) + :in $ [?i ...] + :where + [?i :invoice/client ?c] + [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] + [?i :invoice/date ?d] + [(>= ?d ?lu)]] + (dc/db conn)) (map first))) (defn void-invoices [context args _] @@ -291,15 +300,14 @@ [(>= ?d ?lu)]] (dc/db conn) all-ids) - (map first)) - ] + (map first))] (alog/info ::void-payments :count (count voidable-cash-payments)) (gq-checks/void-payments-internal voidable-cash-payments (:id context)) (alog/info ::voiding-invoices :count (count all-ids)) (audit-transact - (->> all-ids - (dc/q '[:find (pull ?i [:db/id :invoice/date {:invoice/expense-accounts [:db/id]}]) + (->> all-ids + (dc/q '[:find (pull ?i [:db/id :invoice/date {:invoice/expense-accounts [:db/id]}]) :in $ [?i ...] :where (not [_ :invoice-payment/invoice ?i]) [?i :invoice/client ?c] @@ -307,18 +315,18 @@ [?i :invoice/date ?d] [(>= ?d ?lu)]] (dc/db conn)) - (map - (fn [[i]] - [:upsert-invoice {:db/id (:db/id i) - :invoice/total 0.0 - :invoice/outstanding-balance 0.0 - :invoice/status :invoice-status/voided - :invoice/expense-accounts (mapv - (fn [iea] - {:db/id (:db/id iea) - :invoice-expense-account/amount 0.0}) - (:invoice/expense-accounts i))}]))) - (:id context)) + (map + (fn [[i]] + [:upsert-invoice {:db/id (:db/id i) + :invoice/total 0.0 + :invoice/outstanding-balance 0.0 + :invoice/status :invoice-status/voided + :invoice/expense-accounts (mapv + (fn [iea] + {:db/id (:db/id iea) + :invoice-expense-account/amount 0.0}) + (:invoice/expense-accounts i))}]))) + (:id context)) {:message (str "Succesfully voided " (count all-ids))})) (defn unvoid-invoice [context {id :invoice_id} _] @@ -363,10 +371,10 @@ (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice)) (assert (not (seq (:invoice-payment/_invoice invoice)))) (audit-transact [[:upsert-invoice - {:db/id id + {:db/id id :invoice/status :invoice-status/unpaid :invoice/outstanding-balance (:invoice/total invoice) - :invoice/scheduled-payment nil}]] + :invoice/scheduled-payment nil}]] (:id context)) (-> (d-invoices/get-by-id id) @@ -377,16 +385,16 @@ (let [invoice-id (:invoice_id args) invoice (d-invoices/get-by-id invoice-id) _ (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice)) - _ (assert-valid-expense-accounts (:expense_accounts args) (:db/id (:invoice/vendor invoice )))] + _ (assert-valid-expense-accounts (:expense_accounts args) (:db/id (:invoice/vendor invoice)))] (audit-transact [[:upsert-invoice {:db/id invoice-id :invoice/expense-accounts (map - expense-account->entity - (:expense_accounts args))}]] + expense-account->entity + (:expense_accounts args))}]] (:id context)) (->graphql - (d-invoices/get-by-id (:invoice_id args)) - (:id context)))) + (d-invoices/get-by-id (:invoice_id args)) + (:id context)))) ;; TODO - multiple versions of this now exist. fix in datomic migration? ;; Approach could be something like this: (thanks chatgpt) @@ -406,31 +414,31 @@ (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] - {:db/id (random-tempid) - :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-> {:db/id (random-tempid) - :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)) + (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] + {:db/id (random-tempid) + :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-> {:db/id (random-tempid) + :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) + (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*)) @@ -446,7 +454,7 @@ (when-not (:client_id args) (throw (ex-info "Client is required" {:validation-error "client is required"}))) - (let [args (assoc args :clients [{:db/id (:client_id args)}]) + (let [args (assoc args :clients [{:db/id (:client_id args)}]) locations (pull-attr (dc/db conn) :client/locations (:client_id args)) @@ -454,26 +462,26 @@ invoices (pull-many (dc/db conn) '[:db/id :invoice/total] (vec all-ids)) account-total (reduce + 0 (map (fn [x] (:percentage x)) (:accounts args)))] (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})))) + (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]} (dc/pull (dc/db conn) [:account/location :account/name] (: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}) ))) + (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}) )))) + (throw (ex-info err {:validation-error err}))))) (alog/info ::bulk-code :count (count all-ids)) (audit-transact-batch - (map (fn [i] - [:upsert-invoice {:db/id (:db/id i) - :invoice/expense-accounts (maybe-code-accounts i (:accounts args) locations)}]) - invoices) - (:id context)) + (map (fn [i] + [:upsert-invoice {:db/id (:db/id i) + :invoice/expense-accounts (maybe-code-accounts i (:accounts args) locations)}]) + invoices) + (:id context)) {:message (str "Successfully coded " (count all-ids) " invoices.")})) (def objects