A client's bank account and the financial account it posts to carry the same numeric code. Reports keyed their detail rows on [code, name], so the pair rendered as two rows — one labelled for the bank account, one for the financial account. The amount was duplicated too, not just the label: the row's figure is filtered by code alone, so both rows printed the whole code's total. The group subtotal counts the code once, so a section's visible rows stopped footing to their own subtotal. Penelope's Coffee and Tea overshot the 2000 Accounts Payable subtotal by $251,751.80 this way. Resolve it in two places: - build-account-lookup now maps every account at a shared code down to the bank account's name, per client. Where a client has two bank accounts on one code, lowest :bank-account/sort-order wins, then lowest :db/id, so the label is stable across runs. - used-accounts now keys rows on the code alone. Across a multi-client report the clients can still disagree, since only some of them have a bank account at the code; a bank-sourced name wins there, which the new :bank_account_name? flag carries through from the lookup. Rows are code-keyed now, so detail-rows decides whether to print a figure by asking whether the client has data at the code rather than under the winning name — otherwise a client reaching a code under a name another client won would blank out. Balance sheet, profit and loss and cash flows all route through used-accounts and are all fixed. The GraphQL and cljs balance sheets pick up the unified name through build-account-lookup. A sweep of all 146 clients with bank accounts finds duplicate rows on 8 of them before this change and none after, with every section total unchanged.
130 lines
7.8 KiB
Clojure
130 lines
7.8 KiB
Clojure
(ns auto-ap.ledger-test
|
|
(:require
|
|
[auto-ap.datomic :refer [conn]]
|
|
[auto-ap.integration.util :refer [test-account test-bank-account test-client
|
|
wrap-setup]]
|
|
[auto-ap.ledger :refer [build-account-lookup]]
|
|
[clojure.test :as t]
|
|
[datomic.api :as dc]))
|
|
|
|
(t/use-fixtures :each wrap-setup)
|
|
|
|
(t/deftest build-account-lookup-prefers-the-bank-account-name
|
|
(t/testing "a bank account and the financial account sharing its code resolve to one name"
|
|
(let [{:strs [client bank financial]}
|
|
(:tempids @(dc/transact conn
|
|
[(test-account :db/id "financial"
|
|
:account/name "Accounts Payable 10"
|
|
:account/numeric-code 21010
|
|
:account/type :account-type/liability)
|
|
(test-client :db/id "client"
|
|
:client/bank-accounts
|
|
[(test-bank-account :db/id "bank"
|
|
:bank-account/name "Capital One CC - 3196"
|
|
:bank-account/numeric-code 21010
|
|
:bank-account/type :bank-account-type/credit)])]))
|
|
lookup (build-account-lookup client)]
|
|
|
|
(t/is (= "Capital One CC - 3196" (:name (lookup bank))))
|
|
(t/is (= "Capital One CC - 3196" (:name (lookup financial)))
|
|
"the financial account takes the bank account's name, so reports render one row")
|
|
|
|
(t/testing "and both are flagged as bank-named for downstream report labelling"
|
|
(t/is (true? (:bank_account_name? (lookup bank))))
|
|
(t/is (true? (:bank_account_name? (lookup financial)))))
|
|
|
|
(t/testing "without changing the code or the account type"
|
|
(t/is (= 21010 (:numeric_code (lookup bank))))
|
|
(t/is (= 21010 (:numeric_code (lookup financial))))
|
|
(t/is (= :account-type/liability (:account_type (lookup financial))))))))
|
|
|
|
(t/deftest build-account-lookup-leaves-unshared-codes-alone
|
|
(t/testing "an account with no bank account at its code keeps its own name"
|
|
(let [{:strs [client financial]}
|
|
(:tempids @(dc/transact conn
|
|
[(test-account :db/id "financial"
|
|
:account/name "Sales Taxes Payable"
|
|
:account/numeric-code 23000
|
|
:account/type :account-type/liability)
|
|
(test-client :db/id "client"
|
|
:client/bank-accounts
|
|
[(test-bank-account :db/id "bank"
|
|
:bank-account/name "Capital One CC - 3196"
|
|
:bank-account/numeric-code 21010
|
|
:bank-account/type :bank-account-type/credit)])]))
|
|
lookup (build-account-lookup client)]
|
|
(t/is (= "Sales Taxes Payable" (:name (lookup financial))))
|
|
(t/is (false? (:bank_account_name? (lookup financial))))))
|
|
|
|
(t/testing "another client's bank account never renames this client's accounts"
|
|
(let [{:strs [mine financial]}
|
|
(:tempids @(dc/transact conn
|
|
[(test-account :db/id "financial"
|
|
:account/name "Accounts Payable 10"
|
|
:account/numeric-code 21010
|
|
:account/type :account-type/liability)
|
|
(test-client :db/id "mine")
|
|
(test-client :db/id "theirs"
|
|
:client/bank-accounts
|
|
[(test-bank-account :db/id "bank"
|
|
:bank-account/name "Capital One CC - 3196"
|
|
:bank-account/numeric-code 21010
|
|
:bank-account/type :bank-account-type/credit)])]))
|
|
lookup (build-account-lookup mine)]
|
|
(t/is (= "Accounts Payable 10" (:name (lookup financial))))
|
|
(t/is (false? (:bank_account_name? (lookup financial)))))))
|
|
|
|
(t/deftest build-account-lookup-breaks-ties-between-bank-accounts
|
|
(t/testing "two bank accounts on one code resolve deterministically by sort-order"
|
|
(let [{:strs [client first-bank second-bank]}
|
|
(:tempids @(dc/transact conn
|
|
[(test-client :db/id "client"
|
|
:client/bank-accounts
|
|
[(test-bank-account :db/id "second-bank"
|
|
:bank-account/name "US Bank 2974"
|
|
:bank-account/numeric-code 13101
|
|
:bank-account/sort-order 3)
|
|
(test-bank-account :db/id "first-bank"
|
|
:bank-account/name "Fremont Gyro HB Main 8576"
|
|
:bank-account/numeric-code 13101
|
|
:bank-account/sort-order 0)])]))
|
|
lookup (build-account-lookup client)]
|
|
(t/is (= "Fremont Gyro HB Main 8576"
|
|
(:name (lookup first-bank))
|
|
(:name (lookup second-bank)))))))
|
|
|
|
(t/deftest entity-change->ledger
|
|
#_(t/testing "Should code an expected deposit"
|
|
(let [{:strs [ed ccp receipts-split client]}
|
|
(:tempids @(d/transact conn [#:expected-deposit {:status :expected-deposit-status/pending
|
|
:client {:db/id "client"
|
|
:client/code "BRYCE"
|
|
:client/locations ["M"]}
|
|
:total 4.0
|
|
:fee 1.0
|
|
:date #inst "2021-01-01T00:00:00-08:00"
|
|
:location "M"
|
|
:db/id "ed"}]))
|
|
result (sut/entity-change->ledger (d/db conn) [:expected-deposit ed])]
|
|
(t/is (= #:journal-entry
|
|
{:source "expected-deposit"
|
|
:client {:db/id client}
|
|
:date #inst "2021-01-01T00:00:00-08:00"
|
|
:original-entity ed
|
|
:vendor :vendor/ccp-square
|
|
:amount 4.0}
|
|
(dissoc result :journal-entry/line-items)))
|
|
|
|
(t/testing "should debit ccp"
|
|
(t/is (= [#:journal-entry-line
|
|
{:debit 4.0
|
|
:location "A"
|
|
:account :account/ccp}]
|
|
(filter :journal-entry-line/debit (:journal-entry/line-items result)))))
|
|
(t/testing "should credit receipts split ccp"
|
|
(t/is (= [#:journal-entry-line
|
|
{:credit 4.0
|
|
:location "A"
|
|
:account :account/receipts-split}]
|
|
(filter :journal-entry-line/credit (:journal-entry/line-items result))))))))
|