makes all invoice operations work again
This commit is contained in:
@@ -317,7 +317,8 @@
|
||||
}]
|
||||
(map
|
||||
(fn [iea]
|
||||
[:db/retract (:db/id i) :invoice/expense-accounts (:db/id 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))}))
|
||||
@@ -336,6 +337,8 @@
|
||||
: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]]
|
||||
@@ -385,6 +388,20 @@
|
||||
(:id context))))
|
||||
|
||||
;; TODO - multiple versions of this now exist. fix in datomic migration?
|
||||
;; Approach could be something like this: (thanks chatgpt)
|
||||
;; (defn distribute-cents [amount categories]
|
||||
;; (let [dollars (quot amount 1)
|
||||
;; cents (rem amount 1)
|
||||
;; cents-per-category (quot cents (count categories))
|
||||
;; extra-cents (rem cents (count categories))]
|
||||
;; (zipmap categories (repeat cents-per-category))
|
||||
;; (reduce-kv (fn [acc i category]
|
||||
;; (update acc category + (if (< i extra-cents) 1 0)))
|
||||
;; acc
|
||||
;; categories)))
|
||||
;; convert to/from decimal first
|
||||
;; for categories, pass in the accounts, and return a tuple of [account amount]
|
||||
;; after return, just use (assoc account :invoice-expnese-account/amount amount)
|
||||
(defn maybe-code-accounts [invoice account-rules valid-locations]
|
||||
(with-precision 2
|
||||
(let [accounts (vec (mapcat
|
||||
@@ -397,11 +414,13 @@
|
||||
(->> valid-locations
|
||||
(map
|
||||
(fn [cents location]
|
||||
{:invoice-expense-account/account (:account_id ar)
|
||||
{: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-> {:invoice-expense-account/account (:account_id ar)
|
||||
[(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))
|
||||
@@ -417,7 +436,7 @@
|
||||
accounts (if (seq accounts)
|
||||
(update-in accounts [(dec (count accounts)) :invoice-expense-account/amount] #(+ % (double leftover)))
|
||||
[])]
|
||||
[:reset (:db/id invoice) :invoice/expense-accounts accounts])))
|
||||
accounts)))
|
||||
|
||||
|
||||
|
||||
@@ -451,7 +470,8 @@
|
||||
(log/info "Bulk coding " (count all-ids) args)
|
||||
(transact-batch-with-ledger
|
||||
(map (fn [i]
|
||||
(maybe-code-accounts i (:accounts args) locations))
|
||||
`(upsert-entity ~{: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.")}))
|
||||
|
||||
@@ -1,73 +1,210 @@
|
||||
(ns auto-ap.integration.graphql.invoices
|
||||
(:require
|
||||
[auto-ap.time-reader]
|
||||
[auto-ap.datomic :refer [conn]]
|
||||
[auto-ap.graphql.invoices :as sut]
|
||||
[auto-ap.integration.util :refer [admin-token wrap-setup]]
|
||||
[datomic.client.api :as dc]
|
||||
[clojure.test :as t :refer [deftest is testing use-fixtures]]))
|
||||
|
||||
[clojure.test :as t :refer [deftest is testing use-fixtures]]
|
||||
[auto-ap.integration.util
|
||||
:refer [admin-token
|
||||
setup-test-data
|
||||
test-account
|
||||
test-invoice
|
||||
test-vendor
|
||||
wrap-setup]]
|
||||
[datomic.client.api :as d]))
|
||||
(use-fixtures :each wrap-setup)
|
||||
|
||||
(deftest test-add-invoice
|
||||
(testing "It should Add an invoice"
|
||||
(let [{:strs [vendor-id client-id account-id]}
|
||||
(:tempids (dc/transact conn
|
||||
{:tx-data [{:client/code "ABC"
|
||||
:db/id "client-id"
|
||||
:client/locations ["DT"]}
|
||||
{:vendor/name "Vendy"
|
||||
:db/id "vendor-id"
|
||||
:vendor/default-account "account-id"}
|
||||
{:account/name "Account"
|
||||
:account/numeric-code 123
|
||||
:account/invoice-allowance :allowance/allowed
|
||||
:db/id "account-id"}]}))]
|
||||
(let [{:strs [test-vendor-id test-client-id test-account-id
|
||||
denied-account-id vendor-account-id vendor-with-special-account]}
|
||||
(setup-test-data [(test-account :db/id "denied-account-id"
|
||||
:account/invoice-allowance :allowance/denied)
|
||||
(test-account :db/id "vendor-account-id"
|
||||
:account/invoice-allowance :allowance/denied
|
||||
:account/vendor-allowance :allowance/allowed)
|
||||
(test-vendor :db/id "vendor-with-special-account"
|
||||
:vendor/default-account "vendor-account-id")])]
|
||||
(is (some? (sut/add-invoice {:id (admin-token)}
|
||||
{:invoice {:client_id client-id
|
||||
:vendor_id vendor-id
|
||||
{:invoice {:client_id test-client-id
|
||||
:vendor_id test-vendor-id
|
||||
:invoice_number "123"
|
||||
:date #clj-time/date-time "2022-01-01"
|
||||
:total 10.00
|
||||
:expense_accounts [{:amount 10.0
|
||||
:location "DT"
|
||||
:account_id account-id}]}}
|
||||
:account_id test-account-id}]}}
|
||||
nil)))
|
||||
(testing "It should prevent an expense account that isn't allowed"
|
||||
(let [{:strs [denied-account-id]}
|
||||
(:tempids (dc/transact conn
|
||||
{:tx-data [{:account/name "Account"
|
||||
:account/numeric-code 123
|
||||
:account/invoice-allowance :allowance/denied
|
||||
:db/id "denied-account-id"}]}))]
|
||||
(is (thrown? Exception (sut/add-invoice {:id (admin-token)}
|
||||
{:invoice {:client_id client-id
|
||||
:vendor_id vendor-id
|
||||
:invoice_number "789"
|
||||
:date #clj-time/date-time "2022-01-01"
|
||||
:total 10.00
|
||||
:expense_accounts [{:amount 10.0
|
||||
:location "DT"
|
||||
:account_id denied-account-id}]}}
|
||||
nil)))))
|
||||
(is (thrown? Exception (sut/add-invoice {:id (admin-token)}
|
||||
{:invoice {:client_id test-client-id
|
||||
:vendor_id test-vendor-id
|
||||
:invoice_number "789"
|
||||
:date #clj-time/date-time "2022-01-01"
|
||||
:total 10.00
|
||||
:expense_accounts [{:amount 10.0
|
||||
:location "DT"
|
||||
:account_id denied-account-id}]}}
|
||||
nil))))
|
||||
|
||||
(testing "It should allow an expense account that is valid for the vendor"
|
||||
(let [{:strs [vendor-account-id vendor-2]}
|
||||
(:tempids (dc/transact conn {:tx-data [
|
||||
{:account/name "Account"
|
||||
:account/numeric-code 123
|
||||
:account/invoice-allowance :allowance/denied
|
||||
:account/vendor-allowance :allowance/allowed
|
||||
:db/id "vendor-account-id"}
|
||||
{:vendor/name "Testy"
|
||||
:vendor/default-account "vendor-account-id"
|
||||
:db/id "vendor-2"}]}))]
|
||||
(is (some? (sut/add-invoice {:id (admin-token)}
|
||||
{:invoice {:client_id client-id
|
||||
:vendor_id vendor-2
|
||||
:invoice_number "456"
|
||||
:date #clj-time/date-time "2022-01-01"
|
||||
:total 10.00
|
||||
:expense_accounts [{:amount 10.0
|
||||
:location "DT"
|
||||
:account_id vendor-account-id}]}}
|
||||
nil))))))))
|
||||
(is (some? (sut/add-invoice {:id (admin-token)}
|
||||
{:invoice {:client_id test-client-id
|
||||
:vendor_id vendor-with-special-account
|
||||
:invoice_number "456"
|
||||
:date #clj-time/date-time "2022-01-01"
|
||||
:total 10.00
|
||||
:expense_accounts [{:amount 10.0
|
||||
:location "DT"
|
||||
:account_id vendor-account-id}]}}
|
||||
nil)))))))
|
||||
|
||||
(deftest edit-invoice
|
||||
(testing "It should edit invoices"
|
||||
(let [{:strs [invoice-id
|
||||
new-vendor-id
|
||||
new-account-id]}
|
||||
(setup-test-data [(test-invoice :db/id "invoice-id")
|
||||
(test-vendor :db/id "new-vendor-id")
|
||||
(test-account :db/id "new-account-id")])]
|
||||
(is (some? (sut/edit-invoice {:id (admin-token)}
|
||||
{:invoice {:id invoice-id
|
||||
:vendor_id new-vendor-id
|
||||
:invoice_number "890213"
|
||||
:date #clj-time/date-time "2023-01-01"
|
||||
:total 100.00
|
||||
:outstanding_balance 100.00
|
||||
:expense_accounts [{:amount 100.0
|
||||
:location "DT"
|
||||
:account_id new-account-id}]}}
|
||||
nil)))
|
||||
(is (= #:invoice{:invoice-number "890213"
|
||||
:date #inst "2023-01-01T00:00:00.000-00:00"
|
||||
:total 100.0
|
||||
:expense-accounts
|
||||
[#:invoice-expense-account{:amount 100.0
|
||||
:location "DT"
|
||||
:account {:db/id new-account-id}}]}
|
||||
(d/pull (d/db conn) [:invoice/invoice-number
|
||||
:invoice/date
|
||||
:invoice/total
|
||||
{:invoice/expense-accounts [:invoice-expense-account/amount
|
||||
:invoice-expense-account/location
|
||||
:invoice-expense-account/account]}]
|
||||
invoice-id)))
|
||||
|
||||
(testing "Should not be able to change vendor"
|
||||
(is (not= new-vendor-id (:db/id (:invoice/vendor (d/pull (d/db conn) [:invoice/vendor] invoice-id))))))))
|
||||
|
||||
(testing "Should disallow adding a conflicting invoice"
|
||||
(let [{:strs [invoice-id]}
|
||||
(setup-test-data [(test-invoice :db/id "invoice-id"
|
||||
:invoice/invoice-number "original-invoice"
|
||||
:invoice/vendor "test-vendor-id"
|
||||
:invoice/client "test-client-id")
|
||||
(test-invoice :db/id "extant-invoice-id"
|
||||
:invoice/invoice-number "already taken"
|
||||
:invoice/vendor "test-vendor-id"
|
||||
:invoice/client "test-client-id")])]
|
||||
(is (thrown? Exception (sut/edit-invoice {:id (admin-token)}
|
||||
{:invoice {:id invoice-id
|
||||
:invoice_number "already taken"}}
|
||||
nil))))))
|
||||
|
||||
(deftest edit-expense-accounts
|
||||
(testing "It should edit expense accounts"
|
||||
(let [{:strs [invoice-id
|
||||
new-account-id]}
|
||||
(setup-test-data [(test-invoice :db/id "invoice-id")
|
||||
(test-account :db/id "new-account-id")])]
|
||||
(is (some? (sut/edit-expense-accounts {:id (admin-token)}
|
||||
{:invoice_id invoice-id
|
||||
:expense_accounts [{:amount 100.0
|
||||
:account_id new-account-id
|
||||
:location "DT"}]}
|
||||
nil)))
|
||||
(is (= [#:invoice-expense-account{:amount 100.0
|
||||
:location "DT"
|
||||
:account {:db/id new-account-id}}]
|
||||
(-> (d/pull (d/db conn) [{:invoice/expense-accounts [:invoice-expense-account/amount
|
||||
:invoice-expense-account/location
|
||||
:invoice-expense-account/account]}]
|
||||
invoice-id)
|
||||
:invoice/expense-accounts))))))
|
||||
|
||||
(deftest bulk-change-invoices
|
||||
(testing "It should change expense accounts in bulk"
|
||||
(let [{:strs [invoice-id
|
||||
new-account-id
|
||||
test-client-id]}
|
||||
(setup-test-data [(test-invoice :db/id "invoice-id")
|
||||
(test-account :db/id "new-account-id")])]
|
||||
(is (some? (sut/bulk-change-invoices {:id (admin-token)}
|
||||
{:client_id test-client-id
|
||||
:filters {:client_id test-client-id}
|
||||
:accounts [{:percentage 1.0
|
||||
:account_id new-account-id
|
||||
:location "Shared"}]}
|
||||
nil)))
|
||||
(is (= [#:invoice-expense-account{:amount 100.0
|
||||
:location "DT"
|
||||
:account {:db/id new-account-id}}]
|
||||
(-> (d/pull (d/db conn) [{:invoice/expense-accounts [:invoice-expense-account/amount
|
||||
:invoice-expense-account/location
|
||||
:invoice-expense-account/account]}]
|
||||
invoice-id)
|
||||
:invoice/expense-accounts))))))
|
||||
|
||||
(deftest void-invoices
|
||||
(testing "It should voide invoices in bulk"
|
||||
(let [{:strs [invoice-id test-client-id]}
|
||||
(setup-test-data [(test-invoice :db/id "invoice-id"
|
||||
:invoice/status :invoice-status/unpaid)
|
||||
(test-account :db/id "new-account-id")])]
|
||||
|
||||
(is (some? (sut/void-invoices {:id (admin-token)}
|
||||
{:filters {:client_id test-client-id}}
|
||||
nil)))
|
||||
(is (= :invoice-status/voided
|
||||
(-> (d/pull (d/db conn) [{:invoice/status [:db/ident]}]
|
||||
invoice-id)
|
||||
:invoice/status
|
||||
:db/ident)))
|
||||
|
||||
(testing "Should unvoid invoice"
|
||||
(is (some? (sut/unvoid-invoice {:id (admin-token)}
|
||||
{:invoice_id invoice-id}
|
||||
nil)))
|
||||
(is (= :invoice-status/unpaid
|
||||
(-> (d/pull (d/db conn) [{:invoice/status [:db/ident]}]
|
||||
invoice-id)
|
||||
:invoice/status
|
||||
:db/ident)))))))
|
||||
|
||||
|
||||
(deftest void-invoice
|
||||
(testing "It should voide invoices in bulk"
|
||||
(let [{:strs [invoice-id]}
|
||||
(setup-test-data [(test-invoice :db/id "invoice-id"
|
||||
:invoice/status :invoice-status/unpaid)
|
||||
(test-account :db/id "new-account-id")])]
|
||||
|
||||
|
||||
(is (some? (sut/void-invoice {:id (admin-token)}
|
||||
{:invoice_id invoice-id}
|
||||
nil)))
|
||||
(is (= :invoice-status/voided
|
||||
(-> (d/pull (d/db conn) [{:invoice/status [:db/ident]}]
|
||||
invoice-id)
|
||||
:invoice/status
|
||||
:db/ident)))
|
||||
|
||||
(testing "Should unvoid invoice"
|
||||
(is (some? (sut/unvoid-invoice {:id (admin-token)}
|
||||
{:invoice_id invoice-id}
|
||||
nil)))
|
||||
(is (= :invoice-status/unpaid
|
||||
(-> (d/pull (d/db conn) [{:invoice/status [:db/ident]}]
|
||||
invoice-id)
|
||||
:invoice/status
|
||||
:db/ident)))))))
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
|
||||
(defn test-vendor [& kwargs]
|
||||
(apply assoc {:db/id "vendor-id"
|
||||
:vendor/name "Vendorson"}
|
||||
:vendor/name "Vendorson"
|
||||
:vendor/default-account "test-account-id"}
|
||||
kwargs))
|
||||
|
||||
(defn test-bank-account [& kwargs]
|
||||
@@ -73,7 +74,10 @@
|
||||
(apply assoc {:db/id "test-invoice-id"
|
||||
:invoice/date #inst "2022-01-01"
|
||||
:invoice/client "test-client-id"
|
||||
:invoice/status :invoice-status/unpaid
|
||||
:invoice/import-status :import-status/imported
|
||||
:invoice/total 100.0
|
||||
:invoice/outstanding-balance 100.00
|
||||
:invoice/vendor "test-vendor-id"
|
||||
:invoice/invoice-number (str "INVOICE " (rand-int 1000000))
|
||||
:invoice/expense-accounts [{:invoice-expense-account/account "test-account-id"
|
||||
|
||||
Reference in New Issue
Block a user