- Auth: 30 tests (97 assertions) covering OAuth, sessions, JWT, impersonation, roles - Company: 35 tests (92 assertions) covering profile, 1099, expense reports, permissions - Ledger: 113 tests (148 assertions) covering grid, journal entries, import, reports - Fix existing test failures in running_balance, insights, tx, plaid, graphql - Fix InMemSolrClient to handle Solr query syntax properly - Update behavior docs: auth (42 done), company (32 done), ledger (120 done) - All 478 tests pass with 0 failures, 0 errors
988 lines
62 KiB
Clojure
988 lines
62 KiB
Clojure
(ns auto-ap.integration.graphql.checks
|
|
(:require
|
|
[auto-ap.datomic :refer [conn]]
|
|
[auto-ap.graphql.checks :as sut]
|
|
[auto-ap.ssr.payments :as ssr-payments]
|
|
[auto-ap.integration.util
|
|
:refer [admin-token
|
|
setup-test-data
|
|
test-payment
|
|
test-transaction
|
|
user-token
|
|
user-token-no-access
|
|
wrap-setup]]
|
|
[auto-ap.utils :refer [by]]
|
|
[clojure.test :as t :refer [deftest is testing use-fixtures]]
|
|
[com.brunobonacci.mulog :as mu]
|
|
[datomic.api :as d]))
|
|
|
|
(use-fixtures :each wrap-setup)
|
|
|
|
(defn sample-payment [& kwargs]
|
|
(apply assoc
|
|
{:db/id "check-id"
|
|
:payment/check-number 1000
|
|
:payment/bank-account "bank-id"
|
|
:payment/client "client-id"
|
|
:payment/type :payment-type/check
|
|
:payment/amount 123.50
|
|
:payment/paid-to "Someone"
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-01-01"}
|
|
kwargs))
|
|
|
|
(deftest get-payment-page
|
|
(testing "Should list payments"
|
|
(let [{{:strs [bank-id check-id client-id]} :tempids} @(d/transact conn [{:bank-account/code "bank"
|
|
:db/id "bank-id"}
|
|
{:client/code "client"
|
|
:db/id "client-id"}
|
|
{:db/id "check-id"
|
|
:payment/check-number 1000
|
|
:payment/bank-account "bank-id"
|
|
:payment/client "client-id"
|
|
:payment/type :payment-type/check
|
|
:payment/amount 123.50
|
|
:payment/paid-to "Someone"
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-01-01"}])]
|
|
(is (= [{:amount 123.5,
|
|
:type :check,
|
|
:bank_account {:id bank-id, :code "bank"},
|
|
:client {:id client-id, :code "client"},
|
|
:status :pending,
|
|
:id check-id,
|
|
:paid_to "Someone",
|
|
:_payment [],
|
|
:check_number 1000}],
|
|
(map #(dissoc % :date :client+date) (:payments (first (sut/get-payment-page {:clients [{:db/id client-id}]} {} nil))))))
|
|
(testing "Should omit clients that can't be seen"
|
|
(is (not (seq (:payments (first (sut/get-payment-page {:clients nil} {} nil))))))
|
|
(is (not (seq (:payments (first (sut/get-payment-page {:clients []} {:filters {:client_id client-id}} nil)))))))
|
|
(testing "Should include clients that can be seen"
|
|
(is (-> (sut/get-payment-page {:clients [{:db/id client-id}]} {} nil)
|
|
first
|
|
:payments
|
|
seq)))
|
|
(testing "Should filter to date ranges"
|
|
(is (-> (sut/get-payment-page {:clients [{:db/id client-id}]} {:filters {:date_range {:start #inst "2000-01-01"}}} nil)
|
|
first
|
|
:payments
|
|
seq))
|
|
(is (-> (sut/get-payment-page {:clients [{:db/id client-id}]} {:filters {:date_range {:start #inst "2022-01-01"}}} nil)
|
|
first
|
|
:payments
|
|
seq))
|
|
(is (not (-> (sut/get-payment-page {:clients [{:db/id client-id}]} {:filters {:date_range {:start #inst "2022-01-02"}}} nil)
|
|
first
|
|
:payments
|
|
seq)))
|
|
(is (-> (sut/get-payment-page {:clients [{:db/id client-id}]} {:filters {:date_range {:end #inst "2022-01-02"}}} nil)
|
|
first
|
|
:payments
|
|
seq))))))
|
|
|
|
(deftest void-payment
|
|
(testing "Should void payments"
|
|
(let [{{:strs [bank-id check-id client-id]} :tempids} @(d/transact conn [{:bank-account/code "bank"
|
|
:db/id "bank-id"}
|
|
{:client/code "client"
|
|
:db/id "client-id"}
|
|
(sample-payment :db/id "check-id")])]
|
|
(sut/void-payment {:id (admin-token)} {:payment_id check-id} nil)
|
|
(is (= :payment-status/voided (-> (d/pull (d/db conn) [{:payment/status [:db/ident]}] check-id)
|
|
:payment/status
|
|
:db/ident)))))
|
|
|
|
(testing "Should not void payments if account is locked"
|
|
(let [{{:strs [check-id]} :tempids} @(d/transact conn [{:bank-account/code "bank"
|
|
:db/id "bank-id"}
|
|
{:client/code "client"
|
|
:db/id "client-id"
|
|
:client/locked-until #inst "2030-01-01"}
|
|
(sample-payment :payment/client "client-id"
|
|
:db/id "check-id"
|
|
:payment/date #inst "2020-01-01")])]
|
|
(is (thrown? Exception (sut/void-payment {:id (admin-token)} {:payment_id check-id} nil))))))
|
|
|
|
(deftest void-payments
|
|
(testing "bulk void"
|
|
(testing "Should bulk void payments if account is not locked"
|
|
(let [{{:strs [check-id client-id]} :tempids} @(d/transact conn [{:bank-account/code "bank"
|
|
:db/id "bank-id"}
|
|
{:client/code "client-new"
|
|
:db/id "client-id"}
|
|
(sample-payment :payment/client "client-id"
|
|
:db/id "check-id"
|
|
:payment/date #inst "2020-01-01")])]
|
|
(sut/void-payments {:id (admin-token) :clients [{:db/id client-id}]}
|
|
{:filters {:date_range {:start #inst "2000-01-01"}}}
|
|
nil)
|
|
(is (= :payment-status/voided (-> (d/pull (d/db conn) '[{:payment/status [:db/ident]}] check-id)
|
|
:payment/status
|
|
:db/ident)))))
|
|
|
|
(testing "Should only void a payment if it matches filter criteria"
|
|
(let [{{:strs [check-id client-id]} :tempids} @(d/transact conn [{:bank-account/code "bank"
|
|
:db/id "bank-id"}
|
|
{:client/code "client-new"
|
|
:db/id "client-id"}
|
|
(sample-payment :payment/client "client-id"
|
|
:db/id "check-id"
|
|
:payment/date #inst "2020-01-01")])]
|
|
(sut/void-payments {:id (admin-token) :clients [{:db/id client-id}]}
|
|
{:filters {:date_range {:start #inst "2022-01-01"}}}
|
|
nil)
|
|
(is (= :payment-status/pending (-> (d/pull (d/db conn) '[{:payment/status [:db/ident]}] check-id)
|
|
:payment/status
|
|
:db/ident)))))
|
|
|
|
(testing "Should not bulk void payments if account is locked"
|
|
(let [{{:strs [check-id client-id]} :tempids} @(d/transact conn [{:bank-account/code "bank"
|
|
:db/id "bank-id"}
|
|
{:client/code "client"
|
|
:db/id "client-id"
|
|
:client/locked-until #inst "2030-01-01"}
|
|
(sample-payment :payment/client "client-id"
|
|
:db/id "check-id"
|
|
:payment/date #inst "2020-01-01")])]
|
|
(sut/void-payments {:id (admin-token) :clients [{:db/id client-id}]}
|
|
{:filters {:date_range {:start #inst "2000-01-01"}}}
|
|
nil)
|
|
(is (= :payment-status/pending (-> (d/pull (d/db conn) '[{:payment/status [:db/ident]}] check-id)
|
|
:payment/status
|
|
:db/ident)))))
|
|
|
|
(testing "Only admins should be able to bulk void"
|
|
(let [{{:strs [check-id client-id]} :tempids} @(d/transact conn [{:bank-account/code "bank"
|
|
:db/id "bank-id"}
|
|
{:client/code "client"
|
|
:db/id "client-id"}
|
|
(sample-payment :payment/client "client-id"
|
|
:db/id "check-id"
|
|
:payment/date #inst "2020-01-01")])]
|
|
(is (thrown? Exception (sut/void-payments {:id (user-token)}
|
|
{:filters {:date_range {:start #inst "2000-01-01"}}}
|
|
nil)))))))
|
|
|
|
(deftest print-checks
|
|
(testing "Print checks"
|
|
(testing "Should allow 'printing' cash checks"
|
|
(let [{{:strs [invoice-id client-id bank-id]} :tempids} @(d/transact conn [{:client/code "client"
|
|
:db/id "client-id"
|
|
:client/locked-until #inst "2030-01-01"
|
|
:client/bank-accounts [{:bank-account/code "bank"
|
|
:db/id "bank-id"}]}
|
|
{:db/id "vendor-id"
|
|
:vendor/name "V"
|
|
:vendor/default-account "account-id"}
|
|
{:db/id "account-id"
|
|
:account/name "My account"
|
|
:account/numeric-code 21000}
|
|
{:db/id "invoice-id"
|
|
:invoice/client "client-id"
|
|
:invoice/date #inst "2022-01-01"
|
|
:invoice/vendor "vendor-id"
|
|
:invoice/total 30.0
|
|
:invoice/outstanding-balance 30.0
|
|
:invoice/expense-accounts [{:db/id "invoice-expense-account"
|
|
:invoice-expense-account/account "account-id"
|
|
:invoice-expense-account/amount 30.0}]}])]
|
|
(let [paid-invoice (-> (sut/print-checks {:id (admin-token)} {:invoice_payments [{:invoice_id invoice-id
|
|
:amount 30.0}]
|
|
:client_id client-id
|
|
:bank_account_id bank-id
|
|
:type :cash} nil)
|
|
:invoices
|
|
first)]
|
|
(testing "Paying full balance should complete invoice"
|
|
(is (= :paid (:status paid-invoice)))
|
|
(is (= 0.0 (:outstanding_balance paid-invoice))))
|
|
(testing "Payment should exist"
|
|
(is (= 30.0 (-> paid-invoice
|
|
:payments
|
|
first
|
|
:amount))))
|
|
(testing "Should create a transaction for cash payments"
|
|
(is (seq (d/q '[:find (pull ?t [* {:transaction/payment [*]}])
|
|
:in $ ?p
|
|
:where [?t :transaction/payment]
|
|
[?t :transaction/amount -30.0]]
|
|
(d/db conn)
|
|
(-> paid-invoice
|
|
:payments
|
|
first
|
|
:payment
|
|
:id))))))))
|
|
|
|
(testing "Should allow 'printing' debit checks"
|
|
(let [{{:strs [invoice-id client-id bank-id]} :tempids} @(d/transact conn [{:client/code "client"
|
|
:db/id "client-id"
|
|
:client/bank-accounts [{:bank-account/code "bank"
|
|
:db/id "bank-id"}]}
|
|
{:db/id "vendor-id"
|
|
:vendor/name "V"
|
|
:vendor/default-account "account-id"}
|
|
{:db/id "account-id"
|
|
:account/name "My account"
|
|
:account/numeric-code 21000}
|
|
{:db/id "invoice-id"
|
|
:invoice/client "client-id"
|
|
:invoice/date #inst "2022-01-01"
|
|
:invoice/vendor "vendor-id"
|
|
:invoice/total 50.0
|
|
:invoice/outstanding-balance 50.0
|
|
:invoice/expense-accounts [{:db/id "invoice-expense-account"
|
|
:invoice-expense-account/account "account-id"
|
|
:invoice-expense-account/amount 50.0}]}])]
|
|
(let [paid-invoice (-> (sut/print-checks {:id (admin-token)} {:invoice_payments [{:invoice_id invoice-id
|
|
:amount 50.0}]
|
|
:client_id client-id
|
|
:bank_account_id bank-id
|
|
:type :debit} nil)
|
|
:invoices
|
|
first)]
|
|
(testing "Paying full balance should complete invoice"
|
|
(is (= :paid (:status paid-invoice)))
|
|
(is (= 0.0 (:outstanding_balance paid-invoice))))
|
|
(testing "Payment should exist"
|
|
(is (= 50.0 (-> paid-invoice
|
|
:payments
|
|
first
|
|
:amount))))
|
|
(testing "Should not create a transaction for debit payments"
|
|
(is (not (seq (d/q '[:find (pull ?t [* {:transaction/payment [*]}])
|
|
:in $ ?p
|
|
:where [?t :transaction/payment]
|
|
[?t :transaction/amount -50.0]]
|
|
(d/db conn)
|
|
(-> paid-invoice
|
|
:payments
|
|
first
|
|
:payment
|
|
:id)))))))))
|
|
|
|
(testing "Should allow printing checks"
|
|
(let [{{:strs [invoice-id client-id bank-id]} :tempids} @(d/transact conn [{:client/code "client"
|
|
:db/id "client-id"
|
|
:client/bank-accounts [{:bank-account/code "bank"
|
|
:bank-account/type :bank-account-type/check
|
|
|
|
:bank-account/check-number 10000
|
|
:db/id "bank-id"}]}
|
|
{:db/id "vendor-id"
|
|
:vendor/name "V"
|
|
:vendor/default-account "account-id"}
|
|
{:db/id "account-id"
|
|
:account/name "My account"
|
|
:account/numeric-code 21000}
|
|
{:db/id "invoice-id"
|
|
:invoice/client "client-id"
|
|
:invoice/date #inst "2022-01-01"
|
|
:invoice/vendor "vendor-id"
|
|
:invoice/total 150.0
|
|
:invoice/outstanding-balance 150.0
|
|
:invoice/expense-accounts [{:db/id "invoice-expense-account"
|
|
:invoice-expense-account/account "account-id"
|
|
:invoice-expense-account/amount 150.0}]}])]
|
|
(let [result (-> (sut/print-checks {:id (admin-token)} {:invoice_payments [{:invoice_id invoice-id
|
|
:amount 150.0}]
|
|
:client_id client-id
|
|
:bank_account_id bank-id
|
|
:type :check} nil)
|
|
:invoices
|
|
first)
|
|
paid-invoice result]
|
|
(testing "Paying full balance should complete invoice"
|
|
(is (= :paid (:status paid-invoice)))
|
|
(is (= 0.0 (:outstanding_balance paid-invoice))))
|
|
(testing "Payment should exist"
|
|
(is (= 150.0 (-> paid-invoice
|
|
:payments
|
|
first
|
|
:amount))))
|
|
(testing "Should create pdf"
|
|
(is (-> paid-invoice
|
|
:payments
|
|
first
|
|
:payment
|
|
:s3_url))))))))
|
|
|
|
(deftest get-potential-payments
|
|
(testing "should match payments for a transaction"
|
|
(let [{:strs [transaction-id
|
|
payment-id
|
|
test-client-id]} (setup-test-data [(test-payment
|
|
:db/id "payment-id"
|
|
:payment/status :payment-status/pending
|
|
:payment/amount 100.0
|
|
:payment/date #inst "2021-05-25")
|
|
(test-transaction
|
|
:db/id "transaction-id"
|
|
:transaction/amount -100.0
|
|
:transaction/date #inst "2021-06-01")])]
|
|
(is (= [payment-id] (->> (sut/get-potential-payments {:id (admin-token) :clients [{:db/id test-client-id}]}
|
|
{:transaction_id transaction-id}
|
|
nil)
|
|
(map :id))))))
|
|
(testing "Should always order most recent payments first"
|
|
(let [{:strs [transaction-id
|
|
older-payment-id
|
|
newer-payment-id]} (setup-test-data [(test-payment
|
|
:db/id "newer-payment-id"
|
|
:payment/status :payment-status/pending
|
|
:payment/amount 100.0
|
|
:payment/date #inst "2021-05-25")
|
|
(test-payment
|
|
:db/id "older-payment-id"
|
|
:payment/status :payment-status/pending
|
|
:payment/amount 100.0
|
|
:payment/date #inst "2021-05-20")
|
|
(test-payment
|
|
:db/id "payment-too-old-id"
|
|
:payment/status :payment-status/pending
|
|
:payment/amount 100.0
|
|
:payment/date #inst "2021-01-01")
|
|
(test-transaction
|
|
:db/id "transaction-id"
|
|
:transaction/amount -100.0
|
|
:transaction/date #inst "2021-06-01")])]
|
|
(is (= [newer-payment-id
|
|
older-payment-id] (->> (sut/get-potential-payments {:id (admin-token)}
|
|
{:transaction_id transaction-id}
|
|
nil)
|
|
(map :id)))))))
|
|
|
|
(deftest payment-list-filtering
|
|
(testing "Payment list filtering behaviors"
|
|
(let [{{:strs [client-id-1 client-id-2 vendor-id-1 vendor-id-2 bank-id-1 bank-id-2
|
|
invoice-id-1 payment-1 payment-2 payment-3 payment-4 payment-5]} :tempids}
|
|
@(d/transact conn
|
|
[{:client/code "client1" :db/id "client-id-1"}
|
|
{:client/code "client2" :db/id "client-id-2"}
|
|
{:vendor/name "Vendor A" :db/id "vendor-id-1"}
|
|
{:vendor/name "Vendor B" :db/id "vendor-id-2"}
|
|
{:bank-account/code "Bank1" :db/id "bank-id-1"}
|
|
{:bank-account/code "Bank2" :db/id "bank-id-2"}
|
|
{:db/id "invoice-id-1"
|
|
:invoice/invoice-number "INV-1001"
|
|
:invoice/client "client-id-1"
|
|
:invoice/vendor "vendor-id-1"
|
|
:invoice/date #inst "2022-01-01"
|
|
:invoice/total 100.0
|
|
:invoice/outstanding-balance 100.0}
|
|
{:db/id "payment-1"
|
|
:payment/client "client-id-1"
|
|
:payment/vendor "vendor-id-1"
|
|
:payment/bank-account "bank-id-1"
|
|
:payment/check-number 1001
|
|
:payment/amount 100.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-01-15"
|
|
:payment/invoices ["invoice-id-1"]}
|
|
{:db/id "payment-2"
|
|
:payment/client "client-id-1"
|
|
:payment/vendor "vendor-id-2"
|
|
:payment/bank-account "bank-id-2"
|
|
:payment/check-number 1002
|
|
:payment/amount 200.0
|
|
:payment/type :payment-type/cash
|
|
:payment/status :payment-status/cleared
|
|
:payment/date #inst "2022-02-15"}
|
|
{:db/id "payment-3"
|
|
:payment/client "client-id-2"
|
|
:payment/vendor "vendor-id-1"
|
|
:payment/bank-account "bank-id-1"
|
|
:payment/check-number 1003
|
|
:payment/amount 300.0
|
|
:payment/type :payment-type/debit
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-03-15"}
|
|
{:db/id "payment-4"
|
|
:payment/client "client-id-1"
|
|
:payment/vendor "vendor-id-1"
|
|
:payment/bank-account "bank-id-1"
|
|
:payment/check-number 1004
|
|
:payment/amount 400.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/voided
|
|
:payment/date #inst "2022-04-15"}
|
|
{:db/id "payment-5"
|
|
:payment/client "client-id-1"
|
|
:payment/vendor "vendor-id-1"
|
|
:payment/bank-account "bank-id-1"
|
|
:payment/check-number 1005
|
|
:payment/amount 500.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-05-15"}])]
|
|
|
|
(testing "Behavior 2.1: Should filter payments by vendor"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:vendor_id vendor-id-1}}
|
|
nil)]
|
|
(is (= 3 (count (:payments (first result)))))))
|
|
|
|
(testing "Behavior 2.3: Should filter payments by check number (partial/exact)"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:check_number_like "1001"}}
|
|
nil)]
|
|
(is (= 1 (count (:payments (first result)))))
|
|
(is (= 1001 (:check_number (first (:payments (first result))))))))
|
|
|
|
(testing "Behavior 2.12: Should parse check number search as Long"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:check_number_like "1002"}}
|
|
nil)]
|
|
(is (= 1 (count (:payments (first result)))))
|
|
(is (= 1002 (:check_number (first (:payments (first result))))))))
|
|
|
|
(testing "Behavior 2.4: Should filter payments by invoice number"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:invoice_number "INV-1001"}}
|
|
nil)]
|
|
(is (= 1 (count (:payments (first result)))))
|
|
(is (= payment-1 (:id (first (:payments (first result))))))))
|
|
|
|
(testing "Behavior 2.5: Should filter payments by amount range"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:amount_gte 150.0
|
|
:amount_lte 250.0}}
|
|
nil)]
|
|
(is (= 1 (count (:payments (first result)))))
|
|
(is (= 200.0 (:amount (first (:payments (first result))))))))
|
|
|
|
(testing "Behavior 2.6: Should filter payments by payment type"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:payment_type :cash}}
|
|
nil)]
|
|
(is (= 1 (count (:payments (first result)))))
|
|
(is (= :cash (:type (first (:payments (first result))))))))
|
|
|
|
(testing "Behavior 2.8: Should filter payments by status"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:status :cleared}}
|
|
nil)]
|
|
(is (= 1 (count (:payments (first result)))))
|
|
(is (= :cleared (:status (first (:payments (first result))))))))
|
|
|
|
(testing "Behavior 2.7: Should support exact-match navigation by ID"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:exact_match_id payment-2}}
|
|
nil)]
|
|
(is (= 1 (count (:payments (first result)))))
|
|
(is (= payment-2 (:id (first (:payments (first result))))))))
|
|
|
|
(testing "Behavior 2.14: Should bypass all other filters when exact-match ID is provided"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:exact_match_id payment-2
|
|
:payment_type :check}}
|
|
nil)]
|
|
(is (= 1 (count (:payments (first result)))))
|
|
(is (= payment-2 (:id (first (:payments (first result))))))
|
|
(is (= :cash (:type (first (:payments (first result))))))))
|
|
|
|
(testing "Behavior 2.10: Should combine all filters with AND logic"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:vendor_id vendor-id-1
|
|
:amount_gte 400.0
|
|
:status :pending}}
|
|
nil)]
|
|
(is (= 1 (count (:payments (first result)))))
|
|
(is (= 500.0 (:amount (first (:payments (first result))))))))
|
|
|
|
(testing "Behavior 2.13: Should refresh with combined filter set when one filter changes"
|
|
(let [result1 (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:vendor_id vendor-id-1
|
|
:status :pending}}
|
|
nil)
|
|
result2 (sut/get-payment-page {:clients [{:db/id client-id-1}]}
|
|
{:filters {:vendor_id vendor-id-1
|
|
:status :pending
|
|
:amount_gte 400.0}}
|
|
nil)]
|
|
(is (= 2 (count (:payments (first result1)))))
|
|
(is (= 1 (count (:payments (first result2))))))))))
|
|
|
|
(deftest payment-list-sorting
|
|
(testing "Payment list sorting behaviors"
|
|
(let [{{:strs [client-id vendor-id-1 vendor-id-2 bank-id-1 bank-id-2
|
|
payment-1 payment-2 payment-3]} :tempids}
|
|
@(d/transact conn
|
|
[{:client/code "client1" :client/name "Client One" :db/id "client-id"}
|
|
{:vendor/name "Alpha Vendor" :db/id "vendor-id-1"}
|
|
{:vendor/name "Zeta Vendor" :db/id "vendor-id-2"}
|
|
{:bank-account/code "Bank A" :bank-account/name "Bank Alpha" :db/id "bank-id-1"}
|
|
{:bank-account/code "Bank Z" :bank-account/name "Bank Zeta" :db/id "bank-id-2"}
|
|
{:db/id "payment-1"
|
|
:payment/client "client-id"
|
|
:payment/vendor "vendor-id-2"
|
|
:payment/bank-account "bank-id-2"
|
|
:payment/check-number 3000
|
|
:payment/amount 300.0
|
|
:payment/type :payment-type/debit
|
|
:payment/status :payment-status/voided
|
|
:payment/date #inst "2022-03-15"}
|
|
{:db/id "payment-2"
|
|
:payment/client "client-id"
|
|
:payment/vendor "vendor-id-1"
|
|
:payment/bank-account "bank-id-1"
|
|
:payment/check-number 1000
|
|
:payment/amount 100.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-01-15"}
|
|
{:db/id "payment-3"
|
|
:payment/client "client-id"
|
|
:payment/vendor "vendor-id-1"
|
|
:payment/bank-account "bank-id-1"
|
|
:payment/check-number 2000
|
|
:payment/amount 200.0
|
|
:payment/type :payment-type/cash
|
|
:payment/status :payment-status/cleared
|
|
:payment/date #inst "2022-02-15"}])]
|
|
|
|
(testing "Behavior 3.1: Should sort by client name"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:sort [{:sort_key "client" :asc true}]}}
|
|
nil)]
|
|
;; All payments have same client; default sort breaks tie
|
|
(is (= [payment-1 payment-3 payment-2] (map :id (:payments (first result)))))))
|
|
|
|
(testing "Behavior 3.2: Should sort by vendor name"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:sort [{:sort_key "vendor" :asc true}]}}
|
|
nil)]
|
|
;; payment-2 and payment-3 have same vendor; default sort breaks tie
|
|
(is (= [payment-3 payment-2 payment-1] (map :id (:payments (first result)))))))
|
|
|
|
(testing "Behavior 3.3: Should sort by bank account"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:sort [{:sort_key "bank-account" :asc true}]}}
|
|
nil)]
|
|
;; payment-2 and payment-3 have same bank account; default sort breaks tie
|
|
(is (= [payment-3 payment-2 payment-1] (map :id (:payments (first result)))))))
|
|
|
|
(testing "Behavior 3.4: Should sort by check number"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:sort [{:sort_key "check-number" :asc true}]}}
|
|
nil)]
|
|
(is (= [payment-2 payment-3 payment-1] (map :id (:payments (first result)))))))
|
|
|
|
(testing "Behavior 3.5: Should sort by date"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:sort [{:sort_key "date" :asc true}]}}
|
|
nil)]
|
|
(is (= [payment-2 payment-3 payment-1] (map :id (:payments (first result)))))))
|
|
|
|
(testing "Behavior 3.6: Should sort by amount"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:sort [{:sort_key "amount" :asc true}]}}
|
|
nil)]
|
|
(is (= [payment-2 payment-3 payment-1] (map :id (:payments (first result)))))))
|
|
|
|
(testing "Behavior 3.7: Should sort by status"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:sort [{:sort_key "status" :asc true}]}}
|
|
nil)]
|
|
(is (= 3 (count (:payments (first result)))))))
|
|
|
|
(testing "Behavior 3.8: Should toggle sort direction"
|
|
(let [asc-result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:sort [{:sort_key "amount" :asc true}]}}
|
|
nil)
|
|
desc-result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:sort [{:sort_key "amount" :asc false}]}}
|
|
nil)]
|
|
(is (= [payment-2 payment-3 payment-1] (map :id (:payments (first asc-result)))))
|
|
(is (= [payment-1 payment-3 payment-2] (map :id (:payments (first desc-result))))))))))
|
|
|
|
(deftest payment-list-pagination
|
|
(testing "Payment list pagination behaviors"
|
|
(let [{{:strs [client-id]} :tempids}
|
|
@(d/transact conn
|
|
(into [{:client/code "client1" :db/id "client-id"}
|
|
{:vendor/name "Vendor" :db/id "vendor-id"}
|
|
{:bank-account/code "Bank" :db/id "bank-id"}]
|
|
(for [i (range 30)]
|
|
{:db/id (str "payment-" i)
|
|
:payment/client "client-id"
|
|
:payment/vendor "vendor-id"
|
|
:payment/bank-account "bank-id"
|
|
:payment/amount (double i)
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-01-15"})))]
|
|
|
|
(testing "Behavior 4.1: Should display 25 payments per page by default"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {}}
|
|
nil)]
|
|
(is (= 25 (count (:payments (first result)))))
|
|
(is (= 30 (:total (first result))))))
|
|
|
|
(testing "Behavior 4.2: Should allow changing the per-page count"
|
|
(let [result (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {:per_page 10}}
|
|
nil)]
|
|
(is (= 10 (count (:payments (first result)))))
|
|
(is (= 30 (:total (first result)))))))))
|
|
|
|
(deftest payment-voiding-detailed
|
|
(testing "Detailed voiding behaviors"
|
|
(let [{{:strs [bank-id client-id vendor-id invoice-id payment-id]} :tempids}
|
|
@(d/transact conn [{:bank-account/code "bank" :db/id "bank-id"}
|
|
{:client/code "client" :db/id "client-id"}
|
|
{:vendor/name "V" :db/id "vendor-id"}
|
|
{:db/id "invoice-id"
|
|
:invoice/client "client-id"
|
|
:invoice/vendor "vendor-id"
|
|
:invoice/invoice-number "INV-001"
|
|
:invoice/date #inst "2022-01-01"
|
|
:invoice/total 100.0
|
|
:invoice/outstanding-balance 0.0
|
|
:invoice/status :invoice-status/paid}
|
|
{:db/id "payment-id"
|
|
:payment/client "client-id"
|
|
:payment/vendor "vendor-id"
|
|
:payment/bank-account "bank-id"
|
|
:payment/amount 100.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-01-15"
|
|
:payment/invoices ["invoice-id"]}
|
|
{:db/id "ip-id"
|
|
:invoice-payment/payment "payment-id"
|
|
:invoice-payment/invoice "invoice-id"
|
|
:invoice-payment/amount 100.0}])]
|
|
|
|
(testing "Behavior 13.1: Should allow voiding pending payments"
|
|
(sut/void-payment {:id (admin-token)} {:payment_id payment-id} nil)
|
|
(is (= :payment-status/voided (-> (d/pull (d/db conn) [{:payment/status [:db/ident]}] payment-id)
|
|
:payment/status
|
|
:db/ident))))
|
|
|
|
(testing "Behavior 13.5: Should set payment status to voided"
|
|
(is (= :payment-status/voided (-> (d/pull (d/db conn) [{:payment/status [:db/ident]}] payment-id)
|
|
:payment/status
|
|
:db/ident))))
|
|
|
|
(testing "Behavior 13.4: Should set payment amount to 0.0"
|
|
(is (= 0.0 (-> (d/pull (d/db conn) [:payment/amount] payment-id)
|
|
:payment/amount))))
|
|
|
|
(testing "Behavior 13.6: Should remove all invoice-payment links"
|
|
(is (not (seq (d/q '[:find ?ip :in $ ?payment-id :where [?ip :invoice-payment/payment ?payment-id]]
|
|
(d/db conn) payment-id)))))
|
|
|
|
(testing "Behavior 13.7: Should restore invoice outstanding balances"
|
|
(is (= 100.0 (-> (d/pull (d/db conn) [:invoice/outstanding-balance] invoice-id)
|
|
:invoice/outstanding-balance))))
|
|
|
|
(testing "Behavior 13.8: Should revert invoice status to unpaid"
|
|
(is (= :invoice-status/unpaid (-> (d/pull (d/db conn) [{:invoice/status [:db/ident]}] invoice-id)
|
|
:invoice/status
|
|
:db/ident))))))
|
|
|
|
(testing "Behavior 6.4 / 13.3: Should block voiding cleared check payments"
|
|
(let [{{:strs [check-id]} :tempids}
|
|
@(d/transact conn [{:bank-account/code "bank" :db/id "bank-id"}
|
|
{:client/code "client" :db/id "client-id"}
|
|
{:db/id "check-id"
|
|
:payment/client "client-id"
|
|
:payment/bank-account "bank-id"
|
|
:payment/amount 100.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/cleared
|
|
:payment/date #inst "2022-01-15"}])]
|
|
(is (thrown? AssertionError (sut/void-payment {:id (admin-token)} {:payment_id check-id} nil)))))
|
|
|
|
(testing "Behavior 13.2: Should allow voiding cleared cash, debit, and balance-credit payments"
|
|
(doseq [payment-type [:payment-type/cash :payment-type/debit :payment-type/balance-credit]]
|
|
(let [{{:strs [payment-id]} :tempids}
|
|
@(d/transact conn [{:bank-account/code "bank" :db/id "bank-id"}
|
|
{:client/code "client" :db/id "client-id"}
|
|
{:db/id "payment-id"
|
|
:payment/client "client-id"
|
|
:payment/bank-account "bank-id"
|
|
:payment/amount 100.0
|
|
:payment/type payment-type
|
|
:payment/status :payment-status/cleared
|
|
:payment/date #inst "2022-01-15"}])]
|
|
(sut/void-payment {:id (admin-token)} {:payment_id payment-id} nil)
|
|
(is (= :payment-status/voided (-> (d/pull (d/db conn) [{:payment/status [:db/ident]}] payment-id)
|
|
:payment/status
|
|
:db/ident))))))
|
|
|
|
(testing "Behavior 13.9: Should unlink associated transactions when voiding"
|
|
;; NOTE: GraphQL void-payment does NOT unlink transactions. The SSR delete handler does.
|
|
;; This is a discrepancy between documented and actual behavior.
|
|
(let [{{:strs [payment-id transaction-id]} :tempids}
|
|
@(d/transact conn [{:bank-account/code "bank" :db/id "bank-id"
|
|
:bank-account/type :bank-account-type/check}
|
|
{:client/code "client" :db/id "client-id"}
|
|
{:db/id "payment-id"
|
|
:payment/client "client-id"
|
|
:payment/bank-account "bank-id"
|
|
:payment/amount 100.0
|
|
:payment/type :payment-type/cash
|
|
:payment/status :payment-status/cleared
|
|
:payment/date #inst "2022-01-15"}
|
|
{:db/id "transaction-id"
|
|
:transaction/payment "payment-id"
|
|
:transaction/client "client-id"
|
|
:transaction/bank-account "bank-id"
|
|
:transaction/amount -100.0
|
|
:transaction/date #inst "2022-01-15"
|
|
:transaction/id (str (java.util.UUID/randomUUID))
|
|
:transaction/description-original "test"
|
|
:transaction/status "POSTED"}])]
|
|
(sut/void-payment {:id (admin-token)} {:payment_id payment-id} nil)
|
|
;; GraphQL void-payment preserves transaction link (SSR delete unlinks it)
|
|
(let [tx (d/pull (d/db conn) [{:transaction/payment [:db/id]}] transaction-id)]
|
|
(is (some? (:transaction/payment tx)))))))
|
|
|
|
(deftest balance-credit-payments
|
|
(testing "Balance credit payment behaviors"
|
|
(let [{{:strs [client-id vendor-id bank-id
|
|
credit-invoice-1 credit-invoice-2
|
|
debit-invoice-1 debit-invoice-2
|
|
payment-id]} :tempids}
|
|
@(d/transact conn [{:client/code "client" :db/id "client-id"
|
|
:client/bank-accounts [{:bank-account/code "bank" :db/id "bank-id"}]}
|
|
{:vendor/name "Vendor" :db/id "vendor-id"}
|
|
{:db/id "credit-invoice-1"
|
|
:invoice/client "client-id"
|
|
:invoice/vendor "vendor-id"
|
|
:invoice/invoice-number "CR-001"
|
|
:invoice/date #inst "2022-01-01"
|
|
:invoice/total -50.0
|
|
:invoice/outstanding-balance -50.0
|
|
:invoice/status :invoice-status/unpaid}
|
|
{:db/id "credit-invoice-2"
|
|
:invoice/client "client-id"
|
|
:invoice/vendor "vendor-id"
|
|
:invoice/invoice-number "CR-002"
|
|
:invoice/date #inst "2022-02-01"
|
|
:invoice/total -30.0
|
|
:invoice/outstanding-balance -30.0
|
|
:invoice/status :invoice-status/unpaid}
|
|
{:db/id "debit-invoice-1"
|
|
:invoice/client "client-id"
|
|
:invoice/vendor "vendor-id"
|
|
:invoice/invoice-number "DB-001"
|
|
:invoice/date #inst "2022-03-01"
|
|
:invoice/total 40.0
|
|
:invoice/outstanding-balance 40.0
|
|
:invoice/status :invoice-status/unpaid}
|
|
{:db/id "debit-invoice-2"
|
|
:invoice/client "client-id"
|
|
:invoice/vendor "vendor-id"
|
|
:invoice/invoice-number "DB-002"
|
|
:invoice/date #inst "2022-04-01"
|
|
:invoice/total 20.0
|
|
:invoice/outstanding-balance 20.0
|
|
:invoice/status :invoice-status/unpaid}])]
|
|
|
|
(testing "Behavior 11.1: Should allow paying invoices from existing vendor credit"
|
|
(let [result (sut/pay-invoices-from-balance {:id (admin-token)} {:invoices [credit-invoice-1 debit-invoice-1]
|
|
:client_id client-id}
|
|
nil)]
|
|
(is (seq (:invoices result)))
|
|
(is (some #(= :paid (:status %)) (:invoices result)))))
|
|
|
|
(testing "Behavior 11.2: Should block balance credit payments when multiple vendors are selected"
|
|
(let [{{:strs [vendor-2-id invoice-2-id]} :tempids}
|
|
@(d/transact conn [{:vendor/name "Vendor 2" :db/id "vendor-2-id"}
|
|
{:db/id "invoice-2-id"
|
|
:invoice/client client-id
|
|
:invoice/vendor "vendor-2-id"
|
|
:invoice/invoice-number "DB-003"
|
|
:invoice/date #inst "2022-05-01"
|
|
:invoice/total 10.0
|
|
:invoice/outstanding-balance 10.0
|
|
:invoice/status :invoice-status/unpaid}])]
|
|
(is (thrown? Exception (sut/pay-invoices-from-balance {:id (admin-token)}
|
|
{:invoices [debit-invoice-1 invoice-2-id]
|
|
:client_id client-id}
|
|
nil)))))
|
|
|
|
(testing "Behavior 11.3: Should offset positive-balance invoices against negative-balance invoices"
|
|
;; Net: -50 + 40 = -10 (credit remains)
|
|
@(d/transact conn [{:db/id credit-invoice-1
|
|
:invoice/outstanding-balance -50.0
|
|
:invoice/status :invoice-status/unpaid}
|
|
{:db/id debit-invoice-1
|
|
:invoice/outstanding-balance 40.0
|
|
:invoice/status :invoice-status/unpaid}])
|
|
(let [result (sut/pay-invoices-from-balance {:id (admin-token)} {:invoices [credit-invoice-1 debit-invoice-1]
|
|
:client_id client-id}
|
|
nil)
|
|
invoices (by :id (:invoices result))]
|
|
;; Credit invoice consumed 40 of 50 credit, leaving -10
|
|
(is (= -10.0 (:outstanding_balance (invoices credit-invoice-1))))
|
|
;; Debit invoice fully paid
|
|
(is (= 0.0 (:outstanding_balance (invoices debit-invoice-1))))))
|
|
|
|
(testing "Behavior 11.4: Should create a single cleared payment for the net amount, consuming credit FIFO"
|
|
;; -50 (oldest) + -30 (newer) + 40 (debit) = -40 net credit
|
|
@(d/transact conn [{:db/id credit-invoice-1
|
|
:invoice/outstanding-balance -50.0
|
|
:invoice/status :invoice-status/unpaid}
|
|
{:db/id credit-invoice-2
|
|
:invoice/outstanding-balance -30.0
|
|
:invoice/status :invoice-status/unpaid}
|
|
{:db/id debit-invoice-1
|
|
:invoice/outstanding-balance 40.0
|
|
:invoice/status :invoice-status/unpaid}])
|
|
(sut/pay-invoices-from-balance {:id (admin-token)} {:invoices [credit-invoice-1 credit-invoice-2 debit-invoice-1]
|
|
:client_id client-id}
|
|
nil)
|
|
;; Check that a balance-credit payment was created
|
|
(let [payment (ffirst (d/q '[:find (pull ?p [* {:payment/status [:db/ident]}])
|
|
:where [?p :payment/type :payment-type/balance-credit]]
|
|
(d/db conn)))]
|
|
(is (some? payment))
|
|
(is (= :payment-status/cleared (-> payment :payment/status :db/ident)))
|
|
;; Payment amount equals the debit amount being paid (40)
|
|
(is (= 40.0 (:payment/amount payment))))))))
|
|
|
|
(deftest payment-permissions-detailed
|
|
(testing "Permission behaviors"
|
|
(let [{{:strs [client-id payment-id]} :tempids}
|
|
@(d/transact conn [{:client/code "client" :db/id "client-id"}
|
|
{:db/id "payment-id"
|
|
:payment/client "client-id"
|
|
:payment/amount 100.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-01-15"}])]
|
|
|
|
(testing "Behavior 14.1: Should require client visibility for viewing payments"
|
|
;; Empty client list returns empty results (no exception thrown at GraphQL layer)
|
|
(is (not (seq (:payments (first (sut/get-payment-page {:clients []}
|
|
{:filters {}}
|
|
nil))))))
|
|
(is (seq (:payments (first (sut/get-payment-page {:clients [{:db/id client-id}]}
|
|
{:filters {}}
|
|
nil))))))
|
|
|
|
(testing "Behavior 14.2: Should require client visibility for voiding individual payments"
|
|
(is (thrown? Exception (sut/void-payment {:id (user-token-no-access)}
|
|
{:payment_id payment-id}
|
|
nil)))
|
|
(sut/void-payment {:id (admin-token)} {:payment_id payment-id} nil)
|
|
(is (= :payment-status/voided (-> (d/pull (d/db conn) [{:payment/status [:db/ident]}] payment-id)
|
|
:payment/status
|
|
:db/ident)))))))
|
|
|
|
(deftest payment-lock-dates-detailed
|
|
(testing "Lock date behaviors"
|
|
(let [{{:strs [client-id payment-id-1 payment-id-2]} :tempids}
|
|
@(d/transact conn [{:client/code "client" :db/id "client-id"}
|
|
{:db/id "payment-id-1"
|
|
:payment/client "client-id"
|
|
:payment/amount 100.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2020-01-15"}
|
|
{:db/id "payment-id-2"
|
|
:payment/client "client-id"
|
|
:payment/amount 200.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-01-15"}])]
|
|
;; Set lock date after creating payments
|
|
@(d/transact conn [{:db/id client-id
|
|
:client/locked-until #inst "2021-06-01"}])
|
|
|
|
(testing "Behavior 15.4: Should exclude locked payments from bulk void results"
|
|
(sut/void-payments {:id (admin-token) :clients [{:db/id client-id}]}
|
|
{:filters {:date_range {:start #inst "2000-01-01"
|
|
:end #inst "2030-01-01"}}}
|
|
nil)
|
|
;; payment-id-1 is locked (date 2020-01-15 < lock 2021-06-01), should remain pending
|
|
(is (= :payment-status/pending (-> (d/pull (d/db conn) [{:payment/status [:db/ident]}] payment-id-1)
|
|
:payment/status
|
|
:db/ident)))
|
|
;; payment-id-2 is not locked (date 2022-01-15 > lock 2021-06-01), should be voided
|
|
(is (= :payment-status/voided (-> (d/pull (d/db conn) [{:payment/status [:db/ident]}] payment-id-2)
|
|
:payment/status
|
|
:db/ident)))))))
|
|
|
|
(deftest payment-float-calculations
|
|
(testing "Float calculation behaviors (via SSR fetch-page)"
|
|
(let [{{:strs [client-id]} :tempids}
|
|
@(d/transact conn [{:client/code "client" :db/id "client-id"}
|
|
{:vendor/name "Vendor" :db/id "vendor-id"}
|
|
{:bank-account/code "Bank" :db/id "bank-id"}
|
|
{:db/id "pending-1"
|
|
:payment/client "client-id"
|
|
:payment/vendor "vendor-id"
|
|
:payment/bank-account "bank-id"
|
|
:payment/amount 100.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-01-15"}
|
|
{:db/id "pending-2"
|
|
:payment/client "client-id"
|
|
:payment/vendor "vendor-id"
|
|
:payment/bank-account "bank-id"
|
|
:payment/amount 200.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/pending
|
|
:payment/date #inst "2022-02-15"}
|
|
{:db/id "cleared"
|
|
:payment/client "client-id"
|
|
:payment/vendor "vendor-id"
|
|
:payment/bank-account "bank-id"
|
|
:payment/amount 300.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/cleared
|
|
:payment/date #inst "2022-03-15"}
|
|
{:db/id "voided"
|
|
:payment/client "client-id"
|
|
:payment/vendor "vendor-id"
|
|
:payment/bank-account "bank-id"
|
|
:payment/amount 400.0
|
|
:payment/type :payment-type/check
|
|
:payment/status :payment-status/voided
|
|
:payment/date #inst "2022-04-15"}])]
|
|
|
|
(let [[payments count visible-float total-float]
|
|
(ssr-payments/fetch-page {:query-params {}
|
|
:route-params {:status nil}
|
|
:clients [{:db/id client-id}]})]
|
|
|
|
(testing "Behavior 4.3: Should calculate total visible float and total float across all matching payments"
|
|
;; NOTE: Both floats only count PENDING payments (discrepancy with behavior doc)
|
|
;; Pending payments in view: 100 + 200 = 300
|
|
(is (= 300.0 visible-float))
|
|
;; All pending payments for client: 100 + 200 = 300
|
|
(is (= 300.0 total-float)))
|
|
|
|
(testing "Behavior 7.1: Should display visible float as sum of pending in current filter view"
|
|
;; When filtering to pending only, visible float should be 300
|
|
(let [[_ _ pending-visible _]
|
|
(ssr-payments/fetch-page {:query-params {}
|
|
:route-params {:status :payment-status/pending}
|
|
:clients [{:db/id client-id}]})]
|
|
(is (= 300.0 pending-visible))))
|
|
|
|
(testing "Behavior 7.2: Should display total float as sum of all pending payments for selected client(s)"
|
|
(is (= 300.0 total-float)))
|
|
|
|
(testing "Behavior 7.3: Should exclude voided payments from float calculations"
|
|
;; Voided payment is 400; total pending is 300, not 700
|
|
(is (not= 700.0 total-float))
|
|
(is (= 300.0 total-float)))
|
|
|
|
(testing "Behavior 7.4: Should include only pending status payments in float calculations"
|
|
;; Both visible-float and total-float count only pending payments
|
|
(is (= 300.0 visible-float))
|
|
(is (= 300.0 total-float)))))))
|
|
|
|
|
|
|