diff --git a/iol_ion/src/iol_ion/tx.clj b/iol_ion/src/iol_ion/tx.clj index 5738fea4..a0b26120 100644 --- a/iol_ion/src/iol_ion/tx.clj +++ b/iol_ion/src/iol_ion/tx.clj @@ -220,6 +220,82 @@ result nil))) + + + +(defn invoice->journal-entry + ([db invoice-id] + (invoice->journal-entry db invoice-id invoice-id)) + ;; the 3-arity version allows you to pass a potential tempid in instead of the invoice-id, + ;; which would be a temporary value after the transaction + ([db invoice-id raw-invoice-id] + (let [entity (dc/pull db + '[:invoice/total + :invoice/exclude-from-ledger + :invoice/outstanding-balance + :invoice/date + {:invoice/vendor [:db/id :vendor/name] + :invoice/client [:db/id :client/code] + :invoice/payment [:db/id {:payment/status [:db/ident]}] + :invoice/status [:db/ident] + :invoice/import-status [:db/ident] + :invoice/expense-accounts [:invoice-expense-account/account + :invoice-expense-account/amount + :invoice-expense-account/location]}] + invoice-id) + credit-invoice? (< (:invoice/total entity 0.0) 0.0)] + (when-not (or + (not (:invoice/total entity)) + (= true (:invoice/exclude-from-ledger entity)) + (= :import-status/pending (:db/ident (:invoice/import-status entity))) + (= :invoice-status/voided (:db/ident (:invoice/status entity))) + (< -0.001 (:invoice/total entity) 0.001)) + + (remove-nils + {:journal-entry/source "invoice" + :journal-entry/client (:db/id (:invoice/client entity)) + :journal-entry/date (:invoice/date entity) + :journal-entry/original-entity raw-invoice-id + :journal-entry/vendor (:db/id (:invoice/vendor entity)) + :journal-entry/amount (Math/abs (:invoice/total entity)) + + :journal-entry/line-items (into [(cond-> {:db/id (str (:db/id entity) "-" 0) + :journal-entry-line/account :account/accounts-payable + :journal-entry-line/location "A" + } + credit-invoice? (assoc :journal-entry-line/debit (Math/abs (:invoice/total entity))) + (not credit-invoice?) (assoc :journal-entry-line/credit (Math/abs (:invoice/total entity))))] + (map-indexed (fn [i ea] + (cond-> + {:db/id (str (:db/id entity) "-" (inc i)) + :journal-entry-line/account (:db/id (:invoice-expense-account/account ea)) + :journal-entry-line/location (or (:invoice-expense-account/location ea) "HQ") + } + credit-invoice? (assoc :journal-entry-line/credit (Math/abs (:invoice-expense-account/amount ea))) + (not credit-invoice?) (assoc :journal-entry-line/debit (Math/abs (:invoice-expense-account/amount ea))))) + (:invoice/expense-accounts entity))) + :journal-entry/cleared (and (< (:invoice/outstanding-balance entity) 0.01) + (every? #(= :payment-status/cleared (:payment/status %)) (:invoice/payments entity)) + )}))))) + +(defn upsert-invoice [db invoice] + (let [ + upserted-entity (upsert-entity db invoice) + with-invoice (try (dc/with db {:tx-data upserted-entity}) + (catch ClassCastException e + (println "Dev local does not support with in tx functions. :(") + (dc/with (dc/with-db @(resolve 'auto-ap.datomic/conn)) {:tx-data upserted-entity}) + )) + invoice-id (or (-> with-invoice :tempids (get (:db/id invoice))) + (:db/id invoice)) + journal-entry (invoice->journal-entry (:db-after with-invoice) + invoice-id + (:db/id invoice))] + (into upserted-entity + (if journal-entry + (upsert-ledger db journal-entry) + [[:db/retractEntity [:journal-entry/original-entity (:db/id invoice)]]])))) + (defn propose-invoice [db invoice] (let [existing? (boolean (seq (dc/q '[:find ?i :in $ ?invoice-number ?client ?vendor @@ -228,10 +304,10 @@ [?i :invoice/client ?client] [?i :invoice/vendor ?vendor] (not [?i :invoice/status :invoice-status/voided])] - db - (:invoice/invoice-number invoice) - (:invoice/client invoice) - (:invoice/vendor invoice))))] + db + (:invoice/invoice-number invoice) + (:invoice/client invoice) + (:invoice/vendor invoice))))] (if existing? [] - [(remove-nils invoice)]))) + (upsert-invoice db invoice)))) diff --git a/resources/datomic/ion-config.edn b/resources/datomic/ion-config.edn index 8064bdeb..e40a703e 100644 --- a/resources/datomic/ion-config.edn +++ b/resources/datomic/ion-config.edn @@ -4,6 +4,7 @@ iol-ion.tx/upsert-ledger iol-ion.tx/min-by iol-ion.tx/propose-invoice + iol-ion.tx/upsert-invoice iol-ion.query/dollars= iol-ion.query/dollars-0?] diff --git a/src/clj/auto_ap/graphql/checks.clj b/src/clj/auto_ap/graphql/checks.clj index 12bff35a..a4df6324 100644 --- a/src/clj/auto_ap/graphql/checks.clj +++ b/src/clj/auto_ap/graphql/checks.clj @@ -1,8 +1,9 @@ (ns auto-ap.graphql.checks (:require [amazonica.aws.s3 :as s3] - [auto-ap.datomic :refer [conn remove-nils plus pull-many]] + [auto-ap.datomic :refer [conn remove-nils plus pull-many audit-transact]] [auto-ap.datomic.accounts :as a] + [iol-ion.tx :refer [upsert-invoice]] [auto-ap.datomic.bank-accounts :as d-bank-accounts] [auto-ap.datomic.checks :as d-checks] [auto-ap.datomic.clients :as d-clients] @@ -18,7 +19,6 @@ assert-failure assert-not-locked enum->keyword]] - [auto-ap.ledger :refer [transact-with-ledger]] [auto-ap.numeric :refer [num->words]] [auto-ap.time :refer [iso-date local-now parse]] [auto-ap.utils :refer [by dollars-0?]] @@ -415,7 +415,7 @@ (make-pdfs (filter #(and (= :payment-type/check (:payment/type %)) (> (:payment/amount %) 0.0)) checks)))) - (transact-with-ledger (map #(if (map? %) + (audit-transact (map #(if (map? %) (dissoc % :payment/pdf-data) %) checks ) id) @@ -476,7 +476,7 @@ 0 invoice-payment-lookup)] - (transact-with-ledger + (audit-transact (into [(assoc base-payment :payment/type :payment-type/check :payment/status :payment-status/pending @@ -501,60 +501,60 @@ new-balance (+ (:invoice/outstanding-balance invoice) (:invoice-payment/amount x))] [[:db.fn/retractEntity (:db/id x)] - {:db/id (:db/id invoice) - :invoice/outstanding-balance new-balance - :invoice/status (if (dollars-0? new-balance) - (:invoice/status invoice) - :invoice-status/unpaid)}])) + `(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)) updated-payment {:db/id id :payment/amount 0.0 :payment/status :payment-status/voided}] - (transact-with-ledger (conj removing-payments updated-payment) + (audit-transact (conj removing-payments updated-payment) (:id context))) (-> (d-checks/get-by-id id) (->graphql)))) (defn void-payments-internal [all-ids id] - (transact-with-ledger (->> all-ids - (dc/q '[:find (pull ?p [:db/id - {:invoice-payment/_payment [:invoice-payment/amount - :db/id - {:invoice-payment/invoice [:db/id :invoice/outstanding-balance]}]}]) - :in $ [?p ...] - :where - (not [_ :transaction/payment ?p]) - (not [?p :payment/status :payment-status/voided]) - [?p :payment/client ?c] - [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] - [?p :payment/date ?d] - [(>= ?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] - {:db/id (:db/id invoice) - :invoice/outstanding-balance new-balance - :invoice/status (if (dollars-0? new-balance) - (:invoice/status invoice) - :invoice-status/unpaid)}])))))))) - id)) + (audit-transact (->> all-ids + (dc/q '[:find (pull ?p [:db/id + {:invoice-payment/_payment [:invoice-payment/amount + :db/id + {:invoice-payment/invoice [:db/id :invoice/outstanding-balance]}]}]) + :in $ [?p ...] + :where + (not [_ :transaction/payment ?p]) + (not [?p :payment/status :payment-status/voided]) + [?p :payment/client ?c] + [(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu] + [?p :payment/date ?d] + [(>= ?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)})])))))))) + id)) (defn void-payments [context args _] (assert-admin (:id context)) - (let [args (assoc args :id (:id context)) - ids (some-> args + (let [args (assoc args :id (:id context)) + ids (some-> args :filters (assoc :id (:id context)) (<-graphql) @@ -649,10 +649,7 @@ :payment/type :payment-type/balance-credit :payment/status :payment-status/cleared}] - - - - (transact-with-ledger (-> [] + (audit-transact (-> [] (conj payment) (into (invoice-payments invoices invoice-amounts))) (:id context)) (->graphql {:invoices (d-invoices/get-multi (map :db/id invoices))}))) diff --git a/src/clj/auto_ap/graphql/invoices.clj b/src/clj/auto_ap/graphql/invoices.clj index 8d9f11fc..52c456f5 100644 --- a/src/clj/auto_ap/graphql/invoices.clj +++ b/src/clj/auto_ap/graphql/invoices.clj @@ -1,8 +1,8 @@ (ns auto-ap.graphql.invoices (:require [auto-ap.datomic - :refer [conn pull-attr pull-many pull-ref random-tempid ]] - [iol-ion.tx :refer [upsert-entity]] + :refer [conn pull-attr pull-many pull-ref random-tempid audit-transact audit-transact-batch]] +[iol-ion.tx :refer [upsert-entity upsert-invoice]] [auto-ap.datomic.clients :as d-clients] [auto-ap.datomic.invoices :as d-invoices] [auto-ap.datomic.vendors :as d-vendors] @@ -18,7 +18,7 @@ attach-tracing-resolvers enum->keyword]] [auto-ap.ledger - :refer [transact-batch-with-ledger transact-with-ledger]] + :refer [transact-batch-with-ledger]] [auto-ap.rule-matching :as rm] [auto-ap.utils :refer [dollars=]] [clj-time.coerce :as coerce] @@ -62,8 +62,10 @@ (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 (map (fn [i] [:db/retractEntity i]) invoices)] - (transact-with-ledger transactions (:id context)) + (let [transactions (mapcat (fn [i] [[:db/retractEntity i] + [:db/retractEntity [:journal-entry/original-invoice i]]]) + invoices)] + (audit-transact transactions (:id context)) invoices)) (defn approve-invoices [context {:keys [invoices]} _] @@ -74,8 +76,8 @@ 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] {:db/id i :invoice/import-status :import-status/imported}) invoices)] - (transact-with-ledger transactions (:id context)) + (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]}] @@ -109,19 +111,19 @@ _ (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-entity ~{:db/id "invoice" - :invoice/invoice-number invoice_number - :invoice/client client_id - :invoice/vendor vendor_id - :invoice/import-status :import-status/imported - :invoice/total total - :invoice/outstanding-balance total - :invoice/status :invoice-status/unpaid - :invoice/date (coerce/to-date date) - :invoice/expense-accounts (map expense-account->entity - expense_accounts) - :invoice/due (coerce/to-date due) - :invoice/scheduled-payment (coerce/to-date scheduled_payment)}))) + `(upsert-invoice ~{:db/id "invoice" + :invoice/invoice-number invoice_number + :invoice/client client_id + :invoice/vendor vendor_id + :invoice/import-status :import-status/imported + :invoice/total total + :invoice/outstanding-balance total + :invoice/status :invoice-status/unpaid + :invoice/date (coerce/to-date date) + :invoice/expense-accounts (map expense-account->entity + expense_accounts) + :invoice/due (coerce/to-date due) + :invoice/scheduled-payment (coerce/to-date scheduled_payment)}))) (defn assert-valid-expense-accounts [expense_accounts vendor_id] (doseq [expense-account expense_accounts @@ -176,7 +178,7 @@ (assert-valid-expense-accounts expense_accounts vendor_id) (assert-invoice-amounts-add-up in) - (let [transaction-result (transact-with-ledger [(add-invoice-transaction in)] (:id context))] + (let [transaction-result (audit-transact [(add-invoice-transaction in)] (:id context))] (-> (d-invoices/get-by-id (get-in transaction-result [:tempids "invoice"])) (->graphql (:id context))))) @@ -195,7 +197,7 @@ (assert-not-locked client_id (:date in)) (assert-valid-expense-accounts (:expense_accounts in) vendor_id) (assert-invoice-amounts-add-up in))) - (let [transaction-result (transact-with-ledger [(add-invoice-transaction in)] (:id context))] + (let [transaction-result (audit-transact [(add-invoice-transaction in)] (:id context))] (mu/trace ::printing-checks [] (-> (gq-checks/print-checks-internal [{:invoice-id (get-in transaction-result [:tempids "invoice"]) @@ -230,7 +232,7 @@ expense_accounts) :invoice/due (coerce/to-date due) :invoice/scheduled-payment (coerce/to-date scheduled_payment)}] - (transact-with-ledger [`(upsert-entity ~updated-invoice)] + (audit-transact [`(upsert-invoice ~updated-invoice)] (:id context)) (-> (d-invoices/get-by-id id) (->graphql (:id context))))) @@ -239,13 +241,13 @@ (let [invoice (d-invoices/get-by-id id)] (assert-can-see-client (:id context) (:db/id (:invoice/client invoice))) (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice)) - (transact-with-ledger [{: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))}] + (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))})] (:id context)) (-> (d-invoices/get-by-id id) (->graphql (:id context))))) @@ -296,7 +298,7 @@ (gq-checks/void-payments-internal voidable-cash-payments (:id context)) (log/info "Voiding " (count all-ids) args) - (transact-with-ledger + (audit-transact (->> all-ids (dc/q '[:find (pull ?i [:db/id :invoice/date {:invoice/expense-accounts [:db/id]}]) :in $ [?i ...] @@ -306,20 +308,17 @@ [?i :invoice/date ?d] [(>= ?d ?lu)]] (dc/db conn)) - (map first) - (mapcat - (fn [i] - (into - [{:db/id (:db/id i) - :invoice/total 0.0 - :invoice/outstanding-balance 0.0 - :invoice/status :invoice-status/voided - }] - (map - (fn [iea] - {:db/id (:db/id iea) - :invoice-expense-account/amount 0.0}) - (:invoice/expense-accounts i)))))) + (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 (map + (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))})) @@ -337,17 +336,17 @@ :in ['$ '?e]} :args [history id]}) [last-transaction] (->> txs (sort-by first) (last))] - (mu/log ::here - :txes txs) - (transact-with-ledger [(->> txs - (filter (fn [[tx]] (= tx last-transaction))) - (reduce (fn [new-transaction [_ entity original-status original-outstanding total expense-account expense-account-amount]] - (-> new-transaction - (assoc :db/id entity - :invoice/total total - :invoice/status original-status - :invoice/outstanding-balance original-outstanding) - (update :invoice/expense-accounts conj {:db/id expense-account :invoice-expense-account/amount expense-account-amount}))) {}))] + (audit-transact [`(upsert-invoice + ~(->> txs + (filter (fn [[tx]] (= tx last-transaction))) + (reduce (fn [new-transaction [_ entity original-status original-outstanding total expense-account expense-account-amount]] + (-> new-transaction + (assoc :db/id entity + :invoice/total total + :invoice/status original-status + :invoice/outstanding-balance original-outstanding) + (update :invoice/expense-accounts conj {:db/id expense-account :invoice-expense-account/amount expense-account-amount}))) + {})))] (:id context)) (-> (d-invoices/get-by-id id) @@ -363,9 +362,11 @@ (assert-can-see-client (:id context) (:db/id (:invoice/client invoice))) (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice)) (assert (not (seq (:invoice-payment/_invoice invoice)))) - (transact-with-ledger [[:db/add id :invoice/status :invoice-status/unpaid] - [:db/add id :invoice/outstanding-balance (:invoice/total invoice)] - [:db/retract id :invoice/scheduled-payment (:invoice/scheduled-payment invoice)]] + (audit-transact [`(upsert-invoice + ~{:db/id id + :invoice/status :invoice-status/unpaid + :invoice/outstanding-balance (:invoice/total invoice) + :invoice/scheduled-payment nil})] (:id context)) (-> (d-invoices/get-by-id id) @@ -378,11 +379,11 @@ _ (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice)) _ (assert-valid-expense-accounts (:expense_accounts args) (:db/id (:invoice/vendor invoice )))] - (transact-with-ledger [`(upsert-entity ~{:db/id invoice-id - :invoice/expense-accounts (map - expense-account->entity - (:expense_accounts args))})] - (:id context)) + (audit-transact [`(upsert-invoice ~{:db/id invoice-id + :invoice/expense-accounts (map + expense-account->entity + (:expense_accounts args))})] + (:id context)) (->graphql (d-invoices/get-by-id (:invoice_id args)) (:id context)))) @@ -468,9 +469,9 @@ (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 + (audit-transact-batch (map (fn [i] - `(upsert-entity ~{:db/id (:db/id i) + `(upsert-invoice ~{:db/id (:db/id i) :invoice/expense-accounts (maybe-code-accounts i (:accounts args) locations)})) invoices) (:id context)) diff --git a/src/clj/auto_ap/jobs/register_invoice_import.clj b/src/clj/auto_ap/jobs/register_invoice_import.clj index fb05d5c3..50c29b91 100644 --- a/src/clj/auto_ap/jobs/register_invoice_import.clj +++ b/src/clj/auto_ap/jobs/register_invoice_import.clj @@ -2,9 +2,8 @@ (:gen-class) (:require [amazonica.aws.s3 :as s3] - [auto-ap.datomic :refer [conn pull-attr]] + [auto-ap.datomic :refer [audit-transact conn pull-attr]] [auto-ap.jobs.core :refer [execute]] - [auto-ap.ledger :refer [transact-with-ledger]] [auto-ap.time :as atime] [auto-ap.utils :refer [dollars=]] [clj-time.coerce :as coerce] @@ -14,7 +13,8 @@ [clojure.tools.logging :as log] [config.core :refer [env]] [datomic.client.api :as dc]) - (:import [java.util UUID])) + (:import + (java.util UUID))) (def bucket (:data-bucket env)) @@ -141,8 +141,8 @@ (log/info "contains " (count data) " rows") (doseq [n (partition-all 50 (register-invoice-import* data))] (log/info "transacting" n) - (transact-with-ledger n {:user/name "register-invoice-import" - :user/role "admin"})))) + (audit-transact n {:user/name "register-invoice-import" + :user/role "admin"})))) (defn -main [& _] (execute "register-invoice-import" #(register-invoice-import (:args env)))) diff --git a/src/clj/auto_ap/routes/invoices.clj b/src/clj/auto_ap/routes/invoices.clj index 7d599c9a..6cc2892c 100644 --- a/src/clj/auto_ap/routes/invoices.clj +++ b/src/clj/auto_ap/routes/invoices.clj @@ -1,8 +1,7 @@ (ns auto-ap.routes.invoices (:require [amazonica.aws.s3 :as s3] - [auto-ap.datomic :refer [conn remove-nils uri]] - [iol-ion.tx :refer [propose-invoice]] + [auto-ap.datomic :refer [audit-transact conn remove-nils]] [auto-ap.datomic.accounts :as a] [auto-ap.datomic.clients :as d-clients] [auto-ap.datomic.invoices :as d-invoices] @@ -10,7 +9,6 @@ [auto-ap.graphql.utils :refer [assert-admin assert-can-see-client]] [auto-ap.import.manual :as manual] [auto-ap.import.manual.common :as c] - [auto-ap.ledger :refer [transact-with-ledger]] [auto-ap.parse :as parse] [auto-ap.routes.utils :refer [wrap-secure]] [auto-ap.utils :refer [by]] @@ -22,6 +20,7 @@ [config.core :refer [env]] [datomic.client.api :as dc] [digest] + [iol-ion.tx :refer [propose-invoice]] [ring.middleware.json :refer [wrap-json-response]] [unilog.context :as lc]) (:import @@ -278,7 +277,7 @@ (mapv (fn [i] `(propose-invoice ~i))))] (log/info "creating invoice" potential-invoices) - (let [tx (transact-with-ledger potential-invoices user)] + (let [tx (audit-transact potential-invoices user)] (when-not (seq (dc/q '[:find ?i :in $ [?i ...] :where [?i :invoice/invoice-number]] @@ -395,7 +394,7 @@ conj [] rows)] - (transact-with-ledger txes nil))) + (audit-transact txes nil))) (defn batch-upload-transactions [{{:keys [data]} :edn-params user :identity}] (assert-admin user) @@ -479,7 +478,7 @@ (not= "Cash" (:check %)))) (map :vendor-name) set) - _ (transact-with-ledger (invoice-rows->transaction (:new grouped-rows) + _ (audit-transact (invoice-rows->transaction (:new grouped-rows) user) user)] {:status 200 diff --git a/test/clj/auto_ap/integration/graphql/transactions.clj b/test/clj/auto_ap/integration/graphql/transactions.clj index d89e116b..8685201a 100644 --- a/test/clj/auto_ap/integration/graphql/transactions.clj +++ b/test/clj/auto_ap/integration/graphql/transactions.clj @@ -146,13 +146,13 @@ (is (= #:transaction{:vendor {:db/id test-vendor-id} :approval-status {:db/ident :transaction-approval-status/approved} :payment {:db/id payment-id} - :accounts [#:transaction-account{:account {:db/id accounts-payable-id} + :accounts [#:transaction-account{:account {:account/name "Accounts Payable"} :location "A" :amount 50.0}]} (dc/pull (dc/db conn) '[:transaction/vendor :transaction/payment {:transaction/approval-status [:db/ident] - :transaction/accounts [:transaction-account/account + :transaction/accounts [{:transaction-account/account [:account/name]} :transaction-account/location :transaction-account/amount]}] transaction-id))))) diff --git a/test/clj/auto_ap/integration/util.clj b/test/clj/auto_ap/integration/util.clj index 2cab005f..607a7409 100644 --- a/test/clj/auto_ap/integration/util.clj +++ b/test/clj/auto_ap/integration/util.clj @@ -108,5 +108,10 @@ :client/bank-accounts [(test-bank-account :db/id "test-bank-account-id")]) (test-vendor :db/id "test-vendor-id") {:db/id "accounts-payable-id" + :account/name "Accounts Payable" + :db/ident :account/accounts-payable :account/numeric-code 21000 :account/account-set "default"}])}))) + +(defn apply-tx [data] + (:db-after (dc/transact conn {:tx-data data}))) diff --git a/test/clj/iol_ion/integration/tx.clj b/test/clj/iol_ion/integration/tx.clj new file mode 100644 index 00000000..5db4cb79 --- /dev/null +++ b/test/clj/iol_ion/integration/tx.clj @@ -0,0 +1,84 @@ +(ns iol-ion.integration.tx + (:require + [auto-ap.datomic :refer [conn]] + [auto-ap.integration.util + :refer [setup-test-data test-invoice wrap-setup apply-tx]] + [clojure.test :as t :refer [deftest is use-fixtures testing]] + [datomic.client.api :as dc] + [iol-ion.tx :as sut])) + +(use-fixtures :each wrap-setup) + +(def journal-pull [:journal-entry/date + :journal-entry/original-entity + :journal-entry/client + :journal-entry/source + :journal-entry/cleared + :journal-entry/amount + :journal-entry/vendor + {:journal-entry/line-items [{:journal-entry-line/account '[:account/name]} + :journal-entry-line/location + :journal-entry-line/credit + :journal-entry-line/dirty + :journal-entry-line/debit]}]) + + +(deftest upsert-invoice + (testing "Importing should create a journal entry" + (let [{:strs [invoice-id + test-client-id + test-vendor-id + ]} (setup-test-data + [(test-invoice :db/id "invoice-id" + :invoice/import-status :import-status/pending + :invoice/total 200.0 + )])] + + (is (nil? (:db/id (dc/pull (dc/db conn) journal-pull + [:journal-entry/original-entity invoice-id])))) + (let [db-after (apply-tx (sut/upsert-invoice + (dc/with-db conn) + {:db/id invoice-id + :invoice/import-status :import-status/imported}))] + + (is (= #:journal-entry{:date #inst "2022-01-01T00:00:00.000-00:00", + :original-entity #:db{:id invoice-id}, + :client #:db{:id test-client-id}, + :line-items + [#:journal-entry-line{:account + #:account{:name + "Accounts Payable"}, + :credit 200.0, + :location "A", + :dirty true} + #:journal-entry-line{:account + #:account{:name "Account"}, + :location "DT", + :dirty true, + :debit 100.0}], + :source "invoice", + :cleared false, + :amount 200.0, + :vendor #:db{:id test-vendor-id}} + (dc/pull db-after journal-pull + [:journal-entry/original-entity invoice-id]))) + + (testing "voiding an invoice should remove the journal entry" + (let [db-after (apply-tx (sut/upsert-invoice + (dc/with-db conn) + {:db/id invoice-id + :invoice/status :invoice-status/voided}))] + + (is (= nil + (dc/pull db-after journal-pull + [:journal-entry/original-entity invoice-id]))))) + (testing "invoice should remove the journal entry" + (let [db-after (apply-tx (sut/upsert-invoice + (dc/db conn) + {:db/id invoice-id + :invoice/status :invoice-status/unpaid + :invoice/import-status :import-status/pending}))] + + (is (= nil + (dc/pull db-after journal-pull + [:journal-entry/original-entity invoice-id]))))))))) diff --git a/things-to-search-for.txt b/things-to-search-for.txt index 6ee1fa6a..59c77777 100644 --- a/things-to-search-for.txt +++ b/things-to-search-for.txt @@ -1,8 +1,13 @@ +* try again to see if we can get upsert-ledger into the same transaction, making it all or nothing +* look for all usages of transact-with-ledger +* propose-invoice should use upsert invoice as well + it looks like there are a bbunch of orrphaned customizations for accounts, breaking indexes upsertledger - matching transaction rule might not assign an account. Other things might not assign accounts. This is an assertion that is commented out. Determine consequence of disabling Double check each job still functions in the new system Make reports just be based on running-balances Test exports +Move pay into iol-ion.tx, make sure to use upsert-invoice Some jobs just aren't so big they need to be jobs anymore: Refreshing running balance for journal entry lines @@ -12,7 +17,6 @@ Closing auto invoices Running Balance Cache * Add tests for upsert-ledger -* try again to see if we can get upsert-ledger into the same transaction, making it all or nothing * Make a new way to reset the entire cache for a client Address memory