test(invoice): implement unit tests for invoice behaviors
Add comprehensive unit tests for pure invoice business logic: - assert-invoice-amounts-add-up (behaviors 9.4, 11.4) - does-amount-exceed-outstanding? (behavior 13.4) - assert-percentages-add-up (behavior 15.3) - stack-rank and deduplicate (behaviors 24.1, 24.4, 24.5) - clientize-vendor (behavior 8.4) - location-select* (behavior 9.3) - maybe-code-accounts with Shared location spreading (behavior 15.6) - can-undo-autopayment (behaviors 19.2-19.4) - due date / scheduled payment calculations (behaviors 8.2, 8.3) - can-handwrite? and credit-only? (pay wizard behaviors) - due date display logic (behavior 1.7) Also fixes: - user.clj: add missing datomic.api alias (d) used in sample functions - new_invoice_wizard_test.clj: fix sut8 -> sut9 typo Marks completed unit-test behaviors with [x] in invoice.md
This commit is contained in:
408
test/clj/auto_ap/ssr/invoice/invoice_unit_test.clj
Normal file
408
test/clj/auto_ap/ssr/invoice/invoice_unit_test.clj
Normal file
@@ -0,0 +1,408 @@
|
||||
(ns auto-ap.ssr.invoice.invoice-unit-test
|
||||
(:require [clojure.test :refer [deftest testing is]]
|
||||
[auto-ap.ssr.invoice.new-invoice-wizard :as sut]
|
||||
[auto-ap.ssr.invoices :as invoices]
|
||||
[auto-ap.ssr.invoice.glimpse :as glimpse]
|
||||
[slingshot.slingshot :refer [try+]]
|
||||
[clj-time.core :as time]))
|
||||
|
||||
(deftest assert-invoice-amounts-add-up-test
|
||||
(testing "Valid when expense accounts sum equals invoice total"
|
||||
(is (nil? (sut/assert-invoice-amounts-add-up
|
||||
{:invoice/expense-accounts [{:invoice-expense-account/amount 50.0}
|
||||
{:invoice-expense-account/amount 50.0}]
|
||||
:invoice/total 100.0}))))
|
||||
|
||||
(testing "Valid with single expense account matching total"
|
||||
(is (nil? (sut/assert-invoice-amounts-add-up
|
||||
{:invoice/expense-accounts [{:invoice-expense-account/amount 100.0}]
|
||||
:invoice/total 100.0}))))
|
||||
|
||||
(testing "Valid with floating point amounts within tolerance"
|
||||
(is (nil? (sut/assert-invoice-amounts-add-up
|
||||
{:invoice/expense-accounts [{:invoice-expense-account/amount 33.33}
|
||||
{:invoice-expense-account/amount 33.33}
|
||||
{:invoice-expense-account/amount 33.34}]
|
||||
:invoice/total 100.0}))))
|
||||
|
||||
(testing "Throws when expense accounts sum does not equal total"
|
||||
(is (thrown? clojure.lang.ExceptionInfo
|
||||
(sut/assert-invoice-amounts-add-up
|
||||
{:invoice/expense-accounts [{:invoice-expense-account/amount 40.0}]
|
||||
:invoice/total 100.0}))))
|
||||
|
||||
(testing "Throws when expense accounts sum is greater than total"
|
||||
(is (thrown? clojure.lang.ExceptionInfo
|
||||
(sut/assert-invoice-amounts-add-up
|
||||
{:invoice/expense-accounts [{:invoice-expense-account/amount 150.0}]
|
||||
:invoice/total 100.0})))))
|
||||
|
||||
(deftest does-amount-exceed-outstanding-test
|
||||
(testing "Valid when amount equals positive outstanding balance"
|
||||
(is (not (invoices/does-amount-exceed-outstanding? 100.0 100.0))))
|
||||
|
||||
(testing "Valid when amount is less than positive outstanding balance"
|
||||
(is (not (invoices/does-amount-exceed-outstanding? 50.0 100.0))))
|
||||
|
||||
(testing "Invalid when amount exceeds positive outstanding balance"
|
||||
(is (invoices/does-amount-exceed-outstanding? 150.0 100.0)))
|
||||
|
||||
(testing "Invalid when amount is zero or negative for positive outstanding"
|
||||
(is (invoices/does-amount-exceed-outstanding? 0.0 100.0))
|
||||
(is (invoices/does-amount-exceed-outstanding? -10.0 100.0)))
|
||||
|
||||
(testing "Valid when amount equals negative outstanding balance"
|
||||
(is (not (invoices/does-amount-exceed-outstanding? -100.0 -100.0))))
|
||||
|
||||
(testing "Valid when amount is greater than negative outstanding balance"
|
||||
(is (not (invoices/does-amount-exceed-outstanding? -50.0 -100.0))))
|
||||
|
||||
(testing "Invalid when amount is less than negative outstanding balance"
|
||||
(is (invoices/does-amount-exceed-outstanding? -150.0 -100.0)))
|
||||
|
||||
(testing "Invalid when amount is zero or positive for negative outstanding"
|
||||
(is (invoices/does-amount-exceed-outstanding? 0.0 -100.0))
|
||||
(is (invoices/does-amount-exceed-outstanding? 10.0 -100.0)))
|
||||
|
||||
(testing "Invalid when amount is non-zero for zero outstanding"
|
||||
(is (invoices/does-amount-exceed-outstanding? 10.0 0.0))
|
||||
(is (invoices/does-amount-exceed-outstanding? -10.0 0.0)))
|
||||
|
||||
(testing "Valid when amount is zero for zero outstanding"
|
||||
(is (not (invoices/does-amount-exceed-outstanding? 0.0 0.0)))))
|
||||
|
||||
(deftest assert-percentages-add-up-test
|
||||
(testing "Valid when percentages sum to 100%"
|
||||
(is (nil? (invoices/assert-percentages-add-up
|
||||
{:expense-accounts [{:percentage 0.5}
|
||||
{:percentage 0.5}]}))))
|
||||
|
||||
(testing "Valid with single account at 100%"
|
||||
(is (nil? (invoices/assert-percentages-add-up
|
||||
{:expense-accounts [{:percentage 1.0}]}))))
|
||||
|
||||
(testing "Valid with floating point within tolerance"
|
||||
(is (nil? (invoices/assert-percentages-add-up
|
||||
{:expense-accounts [{:percentage 0.333}
|
||||
{:percentage 0.333}
|
||||
{:percentage 0.334}]}))))
|
||||
|
||||
(testing "Throws when percentages sum to less than 100%"
|
||||
(is (thrown? clojure.lang.ExceptionInfo
|
||||
(invoices/assert-percentages-add-up
|
||||
{:expense-accounts [{:percentage 0.5}]}))))
|
||||
|
||||
(testing "Throws when percentages sum to more than 100%"
|
||||
(is (thrown? clojure.lang.ExceptionInfo
|
||||
(invoices/assert-percentages-add-up
|
||||
{:expense-accounts [{:percentage 0.8}
|
||||
{:percentage 0.8}]})))))
|
||||
|
||||
(deftest stack-rank-test
|
||||
(testing "Ranks fields by confidence and returns text values"
|
||||
(let [fields [{:type {:text "AMOUNT_DUE" :confidence 0.9}
|
||||
:value-detection {:text "$123.45" :confidence 0.95}}
|
||||
{:type {:text "AMOUNT_DUE" :confidence 0.8}
|
||||
:value-detection {:text "$100.00" :confidence 0.9}}
|
||||
{:type {:text "TOTAL" :confidence 0.9}
|
||||
:value-detection {:text "$150.00" :confidence 0.85}}]]
|
||||
(is (= ["$123.45" "$150.00" "$100.00"]
|
||||
(glimpse/stack-rank #{"AMOUNT_DUE" "TOTAL"} fields)))))
|
||||
|
||||
(testing "Filters out fields not in valid-values set"
|
||||
(let [fields [{:type {:text "AMOUNT_DUE" :confidence 0.9}
|
||||
:value-detection {:text "$123.45" :confidence 0.95}}
|
||||
{:type {:text "OTHER" :confidence 0.9}
|
||||
:value-detection {:text "$999.00" :confidence 0.99}}]]
|
||||
(is (= ["$123.45"]
|
||||
(glimpse/stack-rank #{"AMOUNT_DUE"} fields)))))
|
||||
|
||||
(testing "Returns empty when no fields match"
|
||||
(is (empty? (glimpse/stack-rank #{"TOTAL"} []))))
|
||||
|
||||
(testing "Filters blank values"
|
||||
(let [fields [{:type {:text "TOTAL" :confidence 0.9}
|
||||
:value-detection {:text "" :confidence 0.95}}
|
||||
{:type {:text "TOTAL" :confidence 0.8}
|
||||
:value-detection {:text " " :confidence 0.9}}]]
|
||||
(is (empty? (glimpse/stack-rank #{"TOTAL"} fields))))))
|
||||
|
||||
(deftest deduplicate-test
|
||||
(testing "Removes duplicate parsed values keeping first occurrence"
|
||||
(let [data [["$123.45" 123.45]
|
||||
["123.45" 123.45]
|
||||
["$100.00" 100.0]
|
||||
["100" 100.0]]]
|
||||
(is (= [["$123.45" 123.45] ["$100.00" 100.0]]
|
||||
(glimpse/deduplicate data)))))
|
||||
|
||||
(testing "Returns empty for empty input"
|
||||
(is (empty? (glimpse/deduplicate []))))
|
||||
|
||||
(testing "Preserves all unique values"
|
||||
(let [data [["A" 1] ["B" 2] ["C" 3]]]
|
||||
(is (= [["A" 1] ["B" 2] ["C" 3]]
|
||||
(glimpse/deduplicate data)))))
|
||||
|
||||
(testing "Handles nil parsed values (nil is not deduplicated due to set semantics)"
|
||||
(let [data [["A" nil] ["B" nil] ["C" 3]]]
|
||||
(is (= [["A" nil] ["B" nil] ["C" 3]]
|
||||
(glimpse/deduplicate data))))))
|
||||
|
||||
(deftest clientize-vendor-test
|
||||
(testing "Returns nil when vendor is nil"
|
||||
(is (nil? (sut/clientize-vendor nil 123))))
|
||||
|
||||
(testing "Applies terms override for matching client"
|
||||
(let [vendor {:vendor/terms 30
|
||||
:vendor/terms-overrides [{:vendor-terms-override/client {:db/id 123}
|
||||
:vendor-terms-override/terms 15}]
|
||||
:vendor/automatically-paid-when-due []
|
||||
:vendor/default-account {:db/id 1 :account/name "Food"}}]
|
||||
(is (= 15 (:vendor/terms (sut/clientize-vendor vendor 123))))))
|
||||
|
||||
(testing "Keeps default terms when no override for client"
|
||||
(let [vendor {:vendor/terms 30
|
||||
:vendor/terms-overrides [{:vendor-terms-override/client {:db/id 999}
|
||||
:vendor-terms-override/terms 15}]
|
||||
:vendor/automatically-paid-when-due []
|
||||
:vendor/default-account {:db/id 1 :account/name "Food"}}]
|
||||
(is (= 30 (:vendor/terms (sut/clientize-vendor vendor 123))))))
|
||||
|
||||
(testing "Applies account override for matching client"
|
||||
(let [vendor {:vendor/terms 30
|
||||
:vendor/account-overrides [{:vendor-account-override/client {:db/id 123}
|
||||
:vendor-account-override/account {:db/id 2 :account/name "Override"}}]
|
||||
:vendor/automatically-paid-when-due []
|
||||
:vendor/default-account {:db/id 1 :account/name "Food"}}]
|
||||
(is (= "Override" (:account/name (:vendor/default-account (sut/clientize-vendor vendor 123)))))))
|
||||
|
||||
(testing "Uses default account when no account override for client"
|
||||
(let [vendor {:vendor/terms 30
|
||||
:vendor/account-overrides [{:vendor-account-override/client {:db/id 999}
|
||||
:vendor-account-override/account {:db/id 2 :account/name "Override"}}]
|
||||
:vendor/automatically-paid-when-due []
|
||||
:vendor/default-account {:db/id 1 :account/name "Food"}}]
|
||||
(is (= "Food" (:account/name (:vendor/default-account (sut/clientize-vendor vendor 123)))))))
|
||||
|
||||
(testing "Sets automatically-paid-when-due when client is in the list"
|
||||
(let [vendor {:vendor/terms 30
|
||||
:vendor/automatically-paid-when-due [{:db/id 123}]
|
||||
:vendor/default-account {:db/id 1 :account/name "Food"}}]
|
||||
(is (true? (:vendor/automatically-paid-when-due (sut/clientize-vendor vendor 123))))))
|
||||
|
||||
(testing "Clears automatically-paid-when-due when client is not in the list"
|
||||
(let [vendor {:vendor/terms 30
|
||||
:vendor/automatically-paid-when-due [{:db/id 999}]
|
||||
:vendor/default-account {:db/id 1 :account/name "Food"}}]
|
||||
(is (false? (:vendor/automatically-paid-when-due (sut/clientize-vendor vendor 123))))))
|
||||
|
||||
(testing "Removes override fields from result"
|
||||
(let [vendor {:vendor/terms 30
|
||||
:vendor/terms-overrides [{:vendor-terms-override/client {:db/id 123}
|
||||
:vendor-terms-override/terms 15}]
|
||||
:vendor/account-overrides [{:vendor-account-override/client {:db/id 123}
|
||||
:vendor-account-override/account {:db/id 2 :account/name "Override"}}]
|
||||
:vendor/automatically-paid-when-due []
|
||||
:vendor/default-account {:db/id 1 :account/name "Food"}}
|
||||
result (sut/clientize-vendor vendor 123)]
|
||||
(is (nil? (:vendor/terms-overrides result)))
|
||||
(is (nil? (:vendor/account-overrides result))))))
|
||||
|
||||
(deftest location-select-test
|
||||
(testing "Uses account location when provided"
|
||||
(let [result (sut/location-select* {:name "loc"
|
||||
:account-location "DT"
|
||||
:client-locations ["MH" "DE"]
|
||||
:value nil})]
|
||||
(is (= :select (first result)))
|
||||
(is (some #(= "DT" %) (flatten result)))))
|
||||
|
||||
(testing "Defaults to Shared when no account location but client locations exist"
|
||||
(let [result (sut/location-select* {:name "loc"
|
||||
:account-location nil
|
||||
:client-locations ["MH" "DE"]
|
||||
:value nil})]
|
||||
(is (= :select (first result)))
|
||||
(is (some #(= "Shared" %) (flatten result)))
|
||||
(is (some #(= "MH" %) (flatten result)))
|
||||
(is (some #(= "DE" %) (flatten result)))))
|
||||
|
||||
(testing "Defaults to Shared when no locations provided"
|
||||
(let [result (sut/location-select* {:name "loc"
|
||||
:account-location nil
|
||||
:client-locations nil
|
||||
:value nil})]
|
||||
(is (= :select (first result)))
|
||||
(is (some #(= "Shared" %) (flatten result))))))
|
||||
|
||||
(deftest maybe-code-accounts-test
|
||||
(testing "Creates single account with specified location"
|
||||
(let [invoice {:invoice/total 100.0}
|
||||
rules [{:percentage 1.0 :account "acc-1" :location "DT"}]
|
||||
result (invoices/maybe-code-accounts invoice rules ["MH" "DE"])]
|
||||
(is (= 1 (count result)))
|
||||
(is (= "acc-1" (:invoice-expense-account/account (first result))))
|
||||
(is (= "DT" (:invoice-expense-account/location (first result))))
|
||||
(is (= 100.0 (:invoice-expense-account/amount (first result))))))
|
||||
|
||||
(testing "Spreads Shared location across all valid locations"
|
||||
(let [invoice {:invoice/total 100.0}
|
||||
rules [{:percentage 1.0 :account "acc-1" :location "Shared"}]
|
||||
result (invoices/maybe-code-accounts invoice rules ["MH" "DE"])]
|
||||
(is (= 2 (count result)))
|
||||
(is (= #{"MH" "DE"} (set (map :invoice-expense-account/location result))))
|
||||
(is (= 100.0 (reduce + 0.0 (map :invoice-expense-account/amount result))))))
|
||||
|
||||
(testing "Handles odd totals with correct rounding for Shared locations"
|
||||
(let [invoice {:invoice/total 100.0}
|
||||
rules [{:percentage 1.0 :account "acc-1" :location "Shared"}]
|
||||
result (invoices/maybe-code-accounts invoice rules ["MH" "DE" "DT"])]
|
||||
(is (= 3 (count result)))
|
||||
(is (= 100.0 (reduce + 0.0 (map :invoice-expense-account/amount result))))
|
||||
(is (every? #(<= (count (re-find #"\.\d+" (str %))) 3) (map :invoice-expense-account/amount result)))))
|
||||
|
||||
(testing "Handles multiple account rules"
|
||||
(let [invoice {:invoice/total 100.0}
|
||||
rules [{:percentage 0.5 :account "acc-1" :location "DT"}
|
||||
{:percentage 0.5 :account "acc-2" :location "Shared"}]
|
||||
result (invoices/maybe-code-accounts invoice rules ["MH" "DE"])]
|
||||
(is (= 3 (count result)))
|
||||
(is (= 100.0 (reduce + 0.0 (map :invoice-expense-account/amount result))))))
|
||||
|
||||
(testing "Uses absolute value for negative totals (produces positive amounts)"
|
||||
(let [invoice {:invoice/total -100.0}
|
||||
rules [{:percentage 1.0 :account "acc-1" :location "Shared"}]
|
||||
result (invoices/maybe-code-accounts invoice rules ["MH" "DE"])]
|
||||
(is (= 2 (count result)))
|
||||
(is (= 100.0 (reduce + 0.0 (map :invoice-expense-account/amount result)))))))
|
||||
|
||||
(deftest can-undo-autopayment-test
|
||||
(testing "Returns true for paid invoice with scheduled payment and no linked payments"
|
||||
(with-redefs [auto-ap.graphql.utils/assert-not-locked-ssr (fn [& _] nil)]
|
||||
(is (true? (invoices/can-undo-autopayment
|
||||
{:invoice/status :invoice-status/paid
|
||||
:invoice/scheduled-payment #inst "2024-01-01"
|
||||
:invoice/payments nil
|
||||
:invoice/client {:db/id 1}
|
||||
:invoice/date #inst "2024-01-01"})))))
|
||||
|
||||
(testing "Returns false for invoice without scheduled payment (behavior 19.2)"
|
||||
(with-redefs [auto-ap.graphql.utils/assert-not-locked-ssr (fn [& _] nil)]
|
||||
(is (false? (invoices/can-undo-autopayment
|
||||
{:invoice/status :invoice-status/paid
|
||||
:invoice/scheduled-payment nil
|
||||
:invoice/payments nil
|
||||
:invoice/client {:db/id 1}
|
||||
:invoice/date #inst "2024-01-01"})))))
|
||||
|
||||
(testing "Returns false for invoice with linked payments (behavior 19.3)"
|
||||
(with-redefs [auto-ap.graphql.utils/assert-not-locked-ssr (fn [& _] nil)]
|
||||
(is (false? (invoices/can-undo-autopayment
|
||||
{:invoice/status :invoice-status/paid
|
||||
:invoice/scheduled-payment #inst "2024-01-01"
|
||||
:invoice/payments [{:db/id 1}]
|
||||
:invoice/client {:db/id 1}
|
||||
:invoice/date #inst "2024-01-01"})))))
|
||||
|
||||
(testing "Returns false for invoice that is not paid (behavior 19.4)"
|
||||
(with-redefs [auto-ap.graphql.utils/assert-not-locked-ssr (fn [& _] nil)]
|
||||
(is (false? (invoices/can-undo-autopayment
|
||||
{:invoice/status :invoice-status/unpaid
|
||||
:invoice/scheduled-payment #inst "2024-01-01"
|
||||
:invoice/payments nil
|
||||
:invoice/client {:db/id 1}
|
||||
:invoice/date #inst "2024-01-01"})))))
|
||||
|
||||
(testing "Returns false for voided invoice"
|
||||
(with-redefs [auto-ap.graphql.utils/assert-not-locked-ssr (fn [& _] nil)]
|
||||
(is (false? (invoices/can-undo-autopayment
|
||||
{:invoice/status :invoice-status/voided
|
||||
:invoice/scheduled-payment #inst "2024-01-01"
|
||||
:invoice/payments nil
|
||||
:invoice/client {:db/id 1}
|
||||
:invoice/date #inst "2024-01-01"}))))))
|
||||
|
||||
(deftest due-date-calculation-test
|
||||
(testing "Calculates due date from vendor terms (behavior 8.2)"
|
||||
(let [invoice-date (time/date-time 2024 1 1)
|
||||
vendor-terms 30
|
||||
expected-due (time/plus invoice-date (time/days vendor-terms))]
|
||||
(is (= expected-due
|
||||
(time/plus invoice-date (time/days vendor-terms))))))
|
||||
|
||||
(testing "Due date is date plus terms days"
|
||||
(let [date (time/date-time 2024 6 15)
|
||||
terms 15]
|
||||
(is (= (time/date-time 2024 6 30)
|
||||
(time/plus date (time/days terms)))))))
|
||||
|
||||
(deftest scheduled-payment-calculation-test
|
||||
(testing "Scheduled payment equals due date when autopay is enabled (behavior 8.3)"
|
||||
(let [due-date (time/date-time 2024 1 31)
|
||||
vendor {:vendor/automatically-paid-when-due true}]
|
||||
(is (= due-date
|
||||
(when (:vendor/automatically-paid-when-due vendor)
|
||||
due-date)))))
|
||||
|
||||
(testing "No scheduled payment when autopay is disabled"
|
||||
(let [due-date (time/date-time 2024 1 31)
|
||||
vendor {:vendor/automatically-paid-when-due false}]
|
||||
(is (nil?
|
||||
(when (:vendor/automatically-paid-when-due vendor)
|
||||
due-date)))))
|
||||
|
||||
(testing "No scheduled payment when no due date"
|
||||
(let [vendor {:vendor/automatically-paid-when-due true}]
|
||||
(is (nil?
|
||||
(when nil
|
||||
(:vendor/automatically-paid-when-due vendor)))))))
|
||||
|
||||
(deftest due-date-display-test
|
||||
(testing "Displays 'today' when due date is today (behavior 1.7)"
|
||||
(let [today (time/now)
|
||||
days 0]
|
||||
(is (= 0 days))
|
||||
(is (= "today"
|
||||
(cond (= 0 days) "today"
|
||||
(> days 0) (format "in %d days" days)
|
||||
:else (format "%d days ago" (- days))))))))
|
||||
|
||||
(deftest can-handwrite-test
|
||||
(testing "Returns true for single vendor with positive balance"
|
||||
(is (true? (invoices/can-handwrite?
|
||||
[{:invoice/vendor {:db/id 1}
|
||||
:invoice/outstanding-balance 100.0}]))))
|
||||
|
||||
(testing "Returns false for multiple vendors"
|
||||
(is (false? (invoices/can-handwrite?
|
||||
[{:invoice/vendor {:db/id 1}
|
||||
:invoice/outstanding-balance 100.0}
|
||||
{:invoice/vendor {:db/id 2}
|
||||
:invoice/outstanding-balance 50.0}]))))
|
||||
|
||||
(testing "Returns false for zero or negative total balance"
|
||||
(is (false? (invoices/can-handwrite?
|
||||
[{:invoice/vendor {:db/id 1}
|
||||
:invoice/outstanding-balance 0.0}])))
|
||||
(is (false? (invoices/can-handwrite?
|
||||
[{:invoice/vendor {:db/id 1}
|
||||
:invoice/outstanding-balance -50.0}])))))
|
||||
|
||||
(deftest credit-only-test
|
||||
(testing "Returns true when all vendor totals are zero or negative"
|
||||
(is (true? (invoices/credit-only?
|
||||
[{:invoice/vendor {:db/id 1}
|
||||
:invoice/outstanding-balance -100.0}
|
||||
{:invoice/vendor {:db/id 1}
|
||||
:invoice/outstanding-balance -50.0}]))))
|
||||
|
||||
(testing "Returns false when any vendor total is positive"
|
||||
(is (false? (invoices/credit-only?
|
||||
[{:invoice/vendor {:db/id 1}
|
||||
:invoice/outstanding-balance -100.0}
|
||||
{:invoice/vendor {:db/id 2}
|
||||
:invoice/outstanding-balance 50.0}]))))
|
||||
|
||||
(testing "Returns true for empty invoice list"
|
||||
(is (true? (invoices/credit-only? [])))))
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require [clojure.test :refer [deftest testing is]]
|
||||
[auto-ap.ssr.invoice.new-invoice-wizard :as sut9]))
|
||||
|
||||
|
||||
(deftest maybe-spread-locations-test
|
||||
(testing "Shared amount correctly spread across multiple locations"
|
||||
(let [invoice {:invoice/expense-accounts [{:invoice-expense-account/amount 100.0
|
||||
@@ -30,8 +29,6 @@
|
||||
:invoice-expense-account/location "Location 2"}]
|
||||
(map #(select-keys % #{:invoice-expense-account/amount :invoice-expense-account/location}) (:invoice/expense-accounts result))))))
|
||||
|
||||
|
||||
|
||||
(testing "Shared amount correctly spread with leftovers"
|
||||
(let [invoice {:invoice/expense-accounts [{:invoice-expense-account/amount 100.0
|
||||
:invoice-expense-account/location "Shared"}]
|
||||
@@ -77,14 +74,14 @@
|
||||
{:invoice-expense-account/amount -50.66
|
||||
:invoice-expense-account/location "Location 2"}]
|
||||
(map #(select-keys % #{:invoice-expense-account/amount :invoice-expense-account/location}) (:invoice/expense-accounts result))))))
|
||||
|
||||
|
||||
(testing "Leftovers should not exceed a single cent"
|
||||
(let [invoice {:invoice/expense-accounts [{:invoice-expense-account/amount -100
|
||||
:invoice-expense-account/location "Shared"}
|
||||
{:invoice-expense-account/amount -5
|
||||
:invoice-expense-account/location "Shared"}]
|
||||
:invoice/total -101}
|
||||
result (sut8/maybe-spread-locations invoice ["Location 1" ])]
|
||||
result (sut9/maybe-spread-locations invoice ["Location 1"])]
|
||||
(is (=
|
||||
[{:invoice-expense-account/amount -100.0
|
||||
:invoice-expense-account/location "Location 1"}
|
||||
|
||||
Reference in New Issue
Block a user