test: add missing AC tests and fix AC numbering
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
[auto-ap.ssr.transaction.edit :refer [clientize-vendor
|
||||
edit-vendor-changed-handler
|
||||
edit-wizard-toggle-mode-handler
|
||||
location-select*
|
||||
manual-coding-section*
|
||||
vendor-default-account]]
|
||||
[clojure.test :refer [deftest is testing use-fixtures]]
|
||||
@@ -18,6 +19,10 @@
|
||||
(def ^:private save-handler
|
||||
#'auto-ap.ssr.transaction.edit/save-handler)
|
||||
|
||||
;; Private simple-mode-fields* accessible via var reference
|
||||
(def ^:private simple-mode-fields*-fn
|
||||
#'auto-ap.ssr.transaction.edit/simple-mode-fields*)
|
||||
|
||||
(use-fixtures :each wrap-setup)
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
@@ -30,7 +35,7 @@
|
||||
(get (:tempids result) temp-id))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC 1-3: manual-mode-initial — mode selection on open
|
||||
;;; AC1-3: manual-mode-initial — mode selection on open
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
;; manual-mode-initial is private; access via var reference
|
||||
@@ -38,17 +43,17 @@
|
||||
#'auto-ap.ssr.transaction.edit/manual-mode-initial)
|
||||
|
||||
(deftest manual-mode-initial-test
|
||||
(testing "AC1: no accounts → simple mode"
|
||||
(testing "AC1: uncoded transaction (no accounts) opens in simple mode"
|
||||
(is (= :simple (manual-mode-initial {:db/id 123})))
|
||||
(is (= :simple (manual-mode-initial {:db/id 123 :transaction/accounts []}))))
|
||||
|
||||
(testing "AC2: exactly one account → simple mode"
|
||||
(testing "AC2: single-account transaction opens in simple mode"
|
||||
(is (= :simple (manual-mode-initial {:db/id 123
|
||||
:transaction/accounts [{:transaction-account/account 456
|
||||
:transaction-account/location "Shared"
|
||||
:transaction-account/amount 100.0}]}))))
|
||||
|
||||
(testing "AC3: two or more accounts → advanced mode"
|
||||
(testing "AC3: multi-account (2+) transaction opens in advanced mode"
|
||||
(is (= :advanced (manual-mode-initial {:db/id 123
|
||||
:transaction/accounts [{:transaction-account/account 1}
|
||||
{:transaction-account/account 2}]})))
|
||||
@@ -56,11 +61,11 @@
|
||||
:transaction/accounts [{} {} {}]})))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC 4-5: edit-vendor-changed-handler — vendor selection in simple mode
|
||||
;;; AC4-5: edit-vendor-changed-handler — vendor selection in simple mode
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest edit-vendor-changed-simple-mode-test
|
||||
(testing "AC4: selecting vendor with no existing account populates account/location from vendor default"
|
||||
(testing "AC4: vendor selection in simple mode populates account/location from vendor default"
|
||||
;; Set up vendor with a default account
|
||||
(let [result @(dc/transact conn [{:db/id "vendor-id"
|
||||
:vendor/name "Test Vendor"}
|
||||
@@ -105,7 +110,7 @@
|
||||
(is (re-find #"Test Account" body)
|
||||
"Response should contain the vendor's default account name")))
|
||||
|
||||
(testing "AC5: selecting vendor when account already set does NOT overwrite existing account"
|
||||
(testing "AC5: vendor selection in simple mode does NOT overwrite already-set account"
|
||||
(let [result @(dc/transact conn [{:db/id "vendor-id"
|
||||
:vendor/name "Test Vendor"}
|
||||
{:db/id "account-id"
|
||||
@@ -158,11 +163,11 @@
|
||||
"Response should NOT contain the vendor's default account ID when existing account is set"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC 6: save round-trip — manual mode saves vendor + account to DB
|
||||
;;; AC6: save round-trip — manual mode saves vendor + account to DB
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest save-manual-round-trip-test
|
||||
(testing "AC6: submitting simple-mode form saves vendor and single account/location to DB"
|
||||
(testing "AC6: save in simple mode persists vendor/account/location — re-opening shows same values"
|
||||
(let [result @(dc/transact conn [{:db/id "vendor-id"
|
||||
:vendor/name "Save Vendor"}
|
||||
{:db/id "account-id"
|
||||
@@ -218,11 +223,86 @@
|
||||
"The amount should be saved")))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC 7-9: edit-wizard-toggle-mode-handler — mode toggling
|
||||
;;; AC7: simple mode account typeahead respects :account/default-allowance rules
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest toggle-mode-test
|
||||
(testing "AC7: simple → advanced toggle re-renders in advanced mode with accounts preserved"
|
||||
(deftest simple-mode-account-typeahead-allowance-test
|
||||
(testing "AC7: simple mode account typeahead URL includes purpose=transaction"
|
||||
;; The account-typeahead* always passes purpose=transaction to the search URL,
|
||||
;; and the schema validates accounts using check-allowance with :account/default-allowance.
|
||||
;; We test the rendering side: the typeahead URL in simple-mode-fields* must contain purpose=transaction.
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "ALLOWCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "account-id"
|
||||
:account/name "Allowed Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
account-id (tempid->id result "account-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
one-account [{:db/id "row-1"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]
|
||||
request {:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts one-account}
|
||||
[]
|
||||
{:mode "simple"
|
||||
:transaction/accounts one-account})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
html (hiccup/html
|
||||
(fc/start-form (:multi-form-state request) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :simple request))))]
|
||||
(is (re-find #"purpose=transaction" html)
|
||||
"Simple mode account typeahead URL must include purpose=transaction to enforce allowance rules"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC8: location dropdown — fixed location vs full client list
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest location-select-options-test
|
||||
(testing "AC8: when account has a fixed location, dropdown shows only that location"
|
||||
(let [html (hiccup/html
|
||||
(location-select* {:name "location"
|
||||
:account-location "HQ"
|
||||
:client-locations ["DT" "NY"]
|
||||
:value "HQ"}))]
|
||||
(is (re-find #"HQ" html)
|
||||
"Fixed account location 'HQ' should appear in dropdown")
|
||||
(is (not (re-find #"DT" html))
|
||||
"Client location 'DT' should NOT appear when account has fixed location")
|
||||
(is (not (re-find #"Shared" html))
|
||||
"'Shared' option should not appear when account has fixed location")))
|
||||
|
||||
(testing "AC8: when account has no fixed location, dropdown shows full client location list"
|
||||
(let [html (hiccup/html
|
||||
(location-select* {:name "location"
|
||||
:account-location nil
|
||||
:client-locations ["DT" "NY"]
|
||||
:value "Shared"}))]
|
||||
(is (re-find #"Shared" html)
|
||||
"'Shared' option should appear when no fixed account location")
|
||||
(is (re-find #"DT" html)
|
||||
"Client location 'DT' should appear when no fixed account location")
|
||||
(is (re-find #"NY" html)
|
||||
"Client location 'NY' should appear when no fixed account location"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC9: simple → advanced toggle with pre-populated row
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest toggle-simple-to-advanced-test
|
||||
(testing "AC9: clicking 'Switch to advanced mode' from simple mode re-renders in advanced with one row pre-populated"
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "TOGGLECL"
|
||||
:client/locations ["DT"]}
|
||||
@@ -267,14 +347,58 @@
|
||||
"Advanced mode response should contain the account ID from the simple-mode row")
|
||||
;; The account name should appear in the advanced table HTML
|
||||
(is (re-find #"Toggle Account" body)
|
||||
"Advanced mode response should contain the account name from the simple-mode row")))
|
||||
"Advanced mode response should contain the account name from the simple-mode row"))))
|
||||
|
||||
(testing "AC8: advanced → simple (1 row) re-renders in simple mode"
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC10: blank simple → advanced gives empty table
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest toggle-blank-simple-to-advanced-test
|
||||
(testing "AC10: 'Switch to advanced mode' from blank simple mode gives advanced with empty table"
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "TOGSIMCL"
|
||||
:client/code "BLNKTOGLCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
request {:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts []}
|
||||
[]
|
||||
{:mode "simple"
|
||||
:transaction/accounts []})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
response (edit-wizard-toggle-mode-handler request)
|
||||
body (:body response)]
|
||||
(is (string? body))
|
||||
;; Should render in advanced mode
|
||||
(is (re-find #"account-grid-body" body)
|
||||
"Blank simple → advanced should produce account-grid-body")
|
||||
;; Should NOT have any account-row elements (empty grid)
|
||||
(is (not (re-find #"account-row" body))
|
||||
"Blank simple → advanced should have NO account rows")
|
||||
;; Should show 'Switch to simple mode' because 0 rows <= 1
|
||||
(is (re-find #"Switch to simple mode" body)
|
||||
"Advanced mode with 0 rows should show 'Switch to simple mode' link"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC11-12: "Switch to simple mode" visibility based on row count
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest advanced-mode-switch-link-visibility-test
|
||||
(testing "AC11: 'Switch to simple mode' link is visible in advanced mode with 0 or 1 rows"
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "VISLINKCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "account-id"
|
||||
:account/name "Toggle Account"
|
||||
:account/name "Visibility Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
@@ -284,28 +408,36 @@
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
account-id (tempid->id result "account-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
zero-rows []
|
||||
one-row [{:db/id "row-1"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]
|
||||
request {:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts one-row}
|
||||
[]
|
||||
{:mode "advanced"
|
||||
:transaction/accounts one-row})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
response (edit-wizard-toggle-mode-handler request)
|
||||
body (:body response)]
|
||||
(is (string? body))
|
||||
;; After toggling from advanced to simple, show "Switch to advanced mode" link
|
||||
(is (re-find #"Switch to advanced mode" body)
|
||||
"After toggling to simple mode, 'Switch to advanced mode' should be visible")))
|
||||
make-req (fn [accounts]
|
||||
{:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts accounts}
|
||||
[]
|
||||
{:mode "advanced"
|
||||
:transaction/accounts accounts})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}})
|
||||
html-zero-rows (hiccup/html
|
||||
(fc/start-form (:multi-form-state (make-req zero-rows)) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :advanced (make-req zero-rows)))))
|
||||
html-one-row (hiccup/html
|
||||
(fc/start-form (:multi-form-state (make-req one-row)) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :advanced (make-req one-row)))))]
|
||||
(is (re-find #"Switch to simple mode" html-zero-rows)
|
||||
"In advanced mode with 0 rows, 'Switch to simple mode' should be visible")
|
||||
(is (re-find #"Switch to simple mode" html-one-row)
|
||||
"In advanced mode with 1 row, 'Switch to simple mode' should be visible")))
|
||||
|
||||
(testing "AC9: In advanced mode with 2+ rows, 'Switch to simple mode' should be absent"
|
||||
(testing "AC12: 'Switch to simple mode' link is absent in advanced mode with 2+ rows"
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "TWOROWCL"
|
||||
:client/locations ["DT"]}
|
||||
@@ -342,7 +474,6 @@
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
;; Render advanced mode directly with 2 rows using manual-coding-section*
|
||||
html (hiccup/html
|
||||
(fc/start-form (:multi-form-state request) nil
|
||||
(fc/with-field :step-params
|
||||
@@ -351,175 +482,16 @@
|
||||
"In advanced mode with 2+ rows, 'Switch to simple mode' link should be absent"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC 9 (direct): "Switch to simple mode" hidden/visible based on row count
|
||||
;;; AC13: advanced → simple (1 row) re-renders in simple mode
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest advanced-mode-switch-link-visibility-test
|
||||
(testing "AC9a: 'Switch to simple mode' link visible when 1 row in advanced mode"
|
||||
(deftest toggle-advanced-to-simple-test
|
||||
(testing "AC13: 'Switch to simple mode' from advanced (1 row) gives simple mode with that row's values"
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "VISLINKCL"
|
||||
:client/code "TOGSIMCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "account-id"
|
||||
:account/name "Visibility Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
account-id (tempid->id result "account-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
one-row [{:db/id "row-1"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]
|
||||
two-rows [{:db/id "row-1"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 50.0}
|
||||
{:db/id "row-2"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 50.0}]
|
||||
make-req (fn [accounts]
|
||||
{:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts accounts}
|
||||
[]
|
||||
{:mode "advanced"
|
||||
:transaction/accounts accounts})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}})
|
||||
;; Render advanced mode with 1 row
|
||||
html-one-row (hiccup/html
|
||||
(fc/start-form (:multi-form-state (make-req one-row)) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :advanced (make-req one-row)))))
|
||||
;; Render advanced mode with 2 rows
|
||||
html-two-rows (hiccup/html
|
||||
(fc/start-form (:multi-form-state (make-req two-rows)) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :advanced (make-req two-rows)))))]
|
||||
(is (re-find #"Switch to simple mode" html-one-row)
|
||||
"In advanced mode with 1 row, 'Switch to simple mode' should be visible")
|
||||
(is (not (re-find #"Switch to simple mode" html-two-rows))
|
||||
"In advanced mode with 2+ rows, 'Switch to simple mode' should be absent"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC 10: vendor-default-account uses clientized vendor logic
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest vendor-default-account-clientize-test
|
||||
(testing "AC10: client-specific account override takes precedence over global vendor default"
|
||||
(let [result @(dc/transact conn [{:db/id "global-account-id"
|
||||
:account/name "Global Default Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "client-specific-account-id"
|
||||
:account/name "Client Specific Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "client-id"
|
||||
:client/code "CLACCTEST"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "vendor-id"
|
||||
:vendor/name "Clientized Vendor"
|
||||
:vendor/default-account "global-account-id"
|
||||
:vendor/account-overrides [{:vendor-account-override/client "client-id"
|
||||
:vendor-account-override/account "client-specific-account-id"}]}])
|
||||
vendor-id (tempid->id result "vendor-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
client-specific-account-id (tempid->id result "client-specific-account-id")
|
||||
result-account (vendor-default-account vendor-id client-id)]
|
||||
(is (some? result-account)
|
||||
"Should return a default account")
|
||||
(is (= client-specific-account-id (:db/id result-account))
|
||||
"Client-specific account override should take precedence over global vendor default")))
|
||||
|
||||
(testing "AC10: falls back to global vendor default when no client override"
|
||||
(let [result @(dc/transact conn [{:db/id "global-account-id"
|
||||
:account/name "Global Default Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "vendor-id"
|
||||
:vendor/name "Vendor No Override"
|
||||
:vendor/default-account "global-account-id"}
|
||||
{:db/id "client-id"
|
||||
:client/code "NOOVCL"
|
||||
:client/locations ["DT"]}])
|
||||
vendor-id (tempid->id result "vendor-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
global-account-id (tempid->id result "global-account-id")
|
||||
result-account (vendor-default-account vendor-id client-id)]
|
||||
(is (= global-account-id (:db/id result-account))
|
||||
"Should use global vendor default when no client-specific override exists")))
|
||||
|
||||
(testing "AC10: clientize-vendor applies both terms and account overrides"
|
||||
(let [vendor {:db/id "vendor-id"
|
||||
:vendor/name "Test Vendor"
|
||||
:vendor/default-account {:db/id "global-account-id"}
|
||||
:vendor/terms "NET30"
|
||||
:vendor/automatically-paid-when-due []
|
||||
:vendor/terms-overrides [{:vendor-terms-override/client {:db/id "client-id"}
|
||||
:vendor-terms-override/terms "NET60"}]
|
||||
:vendor/account-overrides [{:vendor-account-override/client {:db/id "client-id"}
|
||||
:vendor-account-override/account {:db/id "client-specific-account-id"}}]}
|
||||
clientized (clientize-vendor vendor "client-id")]
|
||||
(is (= "NET60" (:vendor/terms clientized))
|
||||
"Terms override should be applied")
|
||||
(is (= "client-specific-account-id" (-> clientized :vendor/default-account :db/id))
|
||||
"Account override should be applied"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC 1-2 (rendering): manual-coding-section* renders correct mode
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest manual-coding-section-renders-correct-mode-test
|
||||
(testing "AC1/AC2: simple mode renders with 'Switch to advanced mode' link (with one account present)"
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "SIMMODECL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "account-id"
|
||||
:account/name "Simple Mode Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
account-id (tempid->id result "account-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
;; Simple mode: one account (renders correctly with one row cursor available)
|
||||
one-account [{:db/id "row-1"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]
|
||||
request {:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts one-account}
|
||||
[]
|
||||
{:mode "simple"
|
||||
:transaction/accounts one-account})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
html (hiccup/html
|
||||
(fc/start-form (:multi-form-state request) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :simple request))))]
|
||||
(is (re-find #"Switch to advanced mode" html)
|
||||
"Simple mode should show 'Switch to advanced mode' link")
|
||||
(is (not (re-find #"Switch to simple mode" html))
|
||||
"Simple mode should NOT show 'Switch to simple mode' link")))
|
||||
|
||||
(testing "AC3: advanced mode renders with 'Switch to simple mode' link when 1 row"
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "ADVMODECL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "account-id"
|
||||
:account/name "Advanced Mode Account"
|
||||
:account/name "Toggle Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
@@ -543,11 +515,425 @@
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
response (edit-wizard-toggle-mode-handler request)
|
||||
body (:body response)]
|
||||
(is (string? body))
|
||||
;; After toggling from advanced to simple, show "Switch to advanced mode" link
|
||||
(is (re-find #"Switch to advanced mode" body)
|
||||
"After toggling to simple mode, 'Switch to advanced mode' should be visible")
|
||||
;; The row's account ID should appear in the simple mode form
|
||||
(is (re-find (re-pattern (str account-id)) body)
|
||||
"Simple mode should display the account from the advanced mode row"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC14: vendor change in advanced mode with no rows creates one row
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest edit-vendor-changed-advanced-mode-no-rows-test
|
||||
(testing "AC14: vendor change in advanced mode with no rows creates one row with vendor's default account"
|
||||
(let [result @(dc/transact conn [{:db/id "vendor-id"
|
||||
:vendor/name "Advanced Vendor"}
|
||||
{:db/id "account-id"
|
||||
:account/name "Vendor Default Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "vendor-id"
|
||||
:vendor/default-account "account-id"}
|
||||
{:db/id "client-id"
|
||||
:client/code "ADVVCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 200.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
vendor-id (tempid->id result "vendor-id")
|
||||
account-id (tempid->id result "account-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
;; Advanced mode with no accounts
|
||||
request {:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts []}
|
||||
[]
|
||||
{:mode "advanced"
|
||||
:transaction/vendor vendor-id
|
||||
:transaction/accounts []})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 200.0}}
|
||||
response (edit-vendor-changed-handler request)
|
||||
body (:body response)]
|
||||
(is (string? body))
|
||||
(is (re-find #"manual-coding-section" body))
|
||||
;; Should have account-grid-body (advanced mode)
|
||||
(is (re-find #"account-grid-body" body)
|
||||
"Advanced mode vendor change should show account-grid-body")
|
||||
;; The vendor's default account ID should appear in the new row
|
||||
(is (re-find (re-pattern (str account-id)) body)
|
||||
"Advanced mode: vendor default account should appear in the newly created row")
|
||||
(is (re-find #"Vendor Default Account" body)
|
||||
"Advanced mode: vendor default account name should appear in the new row"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC15: vendor change in advanced mode with existing rows does NOT modify them
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest edit-vendor-changed-advanced-mode-existing-rows-test
|
||||
(testing "AC15: vendor change in advanced mode with existing rows does NOT modify existing rows"
|
||||
(let [result @(dc/transact conn [{:db/id "vendor-id"
|
||||
:vendor/name "New Vendor"}
|
||||
{:db/id "vendor-account-id"
|
||||
:account/name "Vendor Default Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "vendor-id"
|
||||
:vendor/default-account "vendor-account-id"}
|
||||
{:db/id "existing-account-id"
|
||||
:account/name "Existing Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "client-id"
|
||||
:client/code "ADVEXCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
vendor-id (tempid->id result "vendor-id")
|
||||
vendor-account-id (tempid->id result "vendor-account-id")
|
||||
existing-account-id (tempid->id result "existing-account-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
existing-rows [{:db/id "row-1"
|
||||
:transaction-account/account existing-account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]
|
||||
;; Advanced mode with existing accounts — vendor change should NOT touch them
|
||||
request {:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts existing-rows}
|
||||
[]
|
||||
{:mode "advanced"
|
||||
:transaction/vendor vendor-id
|
||||
:transaction/accounts existing-rows})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
response (edit-vendor-changed-handler request)
|
||||
body (:body response)]
|
||||
(is (string? body))
|
||||
;; The original (existing) account should still be shown
|
||||
(is (re-find (re-pattern (str existing-account-id)) body)
|
||||
"Existing row account should remain unchanged when vendor changes in advanced mode")
|
||||
;; The vendor's default account should NOT appear — existing rows are untouched
|
||||
(is (not (re-find (re-pattern (str vendor-account-id)) body))
|
||||
"Vendor default account should NOT replace existing rows in advanced mode"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC16: vendor-default-account uses clientized vendor logic
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest vendor-default-account-clientize-test
|
||||
(testing "AC16: client-specific account override takes precedence over global vendor default"
|
||||
(let [result @(dc/transact conn [{:db/id "global-account-id"
|
||||
:account/name "Global Default Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "client-specific-account-id"
|
||||
:account/name "Client Specific Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "client-id"
|
||||
:client/code "CLACCTEST"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "vendor-id"
|
||||
:vendor/name "Clientized Vendor"
|
||||
:vendor/default-account "global-account-id"
|
||||
:vendor/account-overrides [{:vendor-account-override/client "client-id"
|
||||
:vendor-account-override/account "client-specific-account-id"}]}])
|
||||
vendor-id (tempid->id result "vendor-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
client-specific-account-id (tempid->id result "client-specific-account-id")
|
||||
result-account (vendor-default-account vendor-id client-id)]
|
||||
(is (some? result-account)
|
||||
"Should return a default account")
|
||||
(is (= client-specific-account-id (:db/id result-account))
|
||||
"Client-specific account override should take precedence over global vendor default")))
|
||||
|
||||
(testing "AC16: falls back to global vendor default when no client override"
|
||||
(let [result @(dc/transact conn [{:db/id "global-account-id"
|
||||
:account/name "Global Default Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "vendor-id"
|
||||
:vendor/name "Vendor No Override"
|
||||
:vendor/default-account "global-account-id"}
|
||||
{:db/id "client-id"
|
||||
:client/code "NOOVCL"
|
||||
:client/locations ["DT"]}])
|
||||
vendor-id (tempid->id result "vendor-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
global-account-id (tempid->id result "global-account-id")
|
||||
result-account (vendor-default-account vendor-id client-id)]
|
||||
(is (= global-account-id (:db/id result-account))
|
||||
"Should use global vendor default when no client-specific override exists")))
|
||||
|
||||
(testing "AC16: clientize-vendor applies both terms and account overrides"
|
||||
(let [vendor {:db/id "vendor-id"
|
||||
:vendor/name "Test Vendor"
|
||||
:vendor/default-account {:db/id "global-account-id"}
|
||||
:vendor/terms "NET30"
|
||||
:vendor/automatically-paid-when-due []
|
||||
:vendor/terms-overrides [{:vendor-terms-override/client {:db/id "client-id"}
|
||||
:vendor-terms-override/terms "NET60"}]
|
||||
:vendor/account-overrides [{:vendor-account-override/client {:db/id "client-id"}
|
||||
:vendor-account-override/account {:db/id "client-specific-account-id"}}]}
|
||||
clientized (clientize-vendor vendor "client-id")]
|
||||
(is (= "NET60" (:vendor/terms clientized))
|
||||
"Terms override should be applied")
|
||||
(is (= "client-specific-account-id" (-> clientized :vendor/default-account :db/id))
|
||||
"Account override should be applied"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC17: approval status, memo, vendor fields present in both modes
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest fields-present-in-both-modes-test
|
||||
(testing "AC17: vendor field is present in simple mode"
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "FLDTESTCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "account-id"
|
||||
:account/name "Fields Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
account-id (tempid->id result "account-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
one-account [{:db/id "row-1"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]
|
||||
make-req (fn [mode accounts]
|
||||
{:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts accounts}
|
||||
[]
|
||||
{:mode (name mode)
|
||||
:transaction/accounts accounts})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}})
|
||||
html-simple (hiccup/html
|
||||
(fc/start-form (:multi-form-state (make-req :simple one-account)) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :simple (make-req :simple one-account)))))
|
||||
html-advanced (hiccup/html
|
||||
(fc/start-form (:multi-form-state (make-req :advanced one-account)) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :advanced (make-req :advanced one-account)))))]
|
||||
(is (re-find #"Vendor" html-simple)
|
||||
"AC17: Vendor field label must appear in simple mode")
|
||||
(is (re-find #"vendor/search" html-simple)
|
||||
"AC17: Vendor typeahead/search URL must appear in simple mode")
|
||||
(is (re-find #"transaction/vendor" html-simple)
|
||||
"AC17: Vendor field name must appear in simple mode")
|
||||
(is (re-find #"Vendor" html-advanced)
|
||||
"AC17: Vendor field label must appear in advanced mode")
|
||||
(is (re-find #"vendor/search" html-advanced)
|
||||
"AC17: Vendor typeahead/search URL must appear in advanced mode")
|
||||
(is (re-find #"transaction/vendor" html-advanced)
|
||||
"AC17: Vendor field name must appear in advanced mode"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC18: switching modes mid-edit then saving produces a valid transaction
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest switch-modes-then-save-test
|
||||
(testing "AC18: switching simple→advanced→save produces a single valid transaction row in DB"
|
||||
(let [result @(dc/transact conn [{:db/id "vendor-id"
|
||||
:vendor/name "Switch Vendor"}
|
||||
{:db/id "account-id"
|
||||
:account/name "Switch Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "client-id"
|
||||
:client/code "SWITCHCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
vendor-id (tempid->id result "vendor-id")
|
||||
account-id (tempid->id result "account-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
simple-row [{:db/id "row-1"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]
|
||||
;; Step 1: Start in simple mode
|
||||
simple-request {:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts simple-row}
|
||||
[]
|
||||
{:mode "simple"
|
||||
:transaction/accounts simple-row})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
;; Step 2: Toggle to advanced mode
|
||||
toggle-response (edit-wizard-toggle-mode-handler simple-request)
|
||||
;; After toggle, build a save request in advanced mode with one row
|
||||
advanced-snapshot {:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:action :manual
|
||||
:transaction/vendor vendor-id
|
||||
:transaction/amount 100.0
|
||||
:transaction/accounts [{:db/id "row-1"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]}
|
||||
save-request {:multi-form-state (mm/->MultiStepFormState advanced-snapshot [] advanced-snapshot)
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}
|
||||
:identity {:user/role "admin"}}]
|
||||
;; Verify the toggle worked
|
||||
(is (string? (:body toggle-response)))
|
||||
(is (re-find #"account-grid-body" (:body toggle-response))
|
||||
"After toggle, response should be in advanced mode")
|
||||
;; Now save
|
||||
(with-redefs [auto-ap.solr/impl (auto-ap.solr/->InMemSolrClient (atom {}))]
|
||||
(save-handler save-request))
|
||||
;; Verify exactly one account row was saved (no orphaned rows)
|
||||
(let [saved (dc/pull (dc/db conn)
|
||||
'[:db/id
|
||||
{:transaction/accounts [{:transaction-account/account [:db/id]}
|
||||
:transaction-account/location
|
||||
:transaction-account/amount]}]
|
||||
tx-id)]
|
||||
(is (= 1 (count (:transaction/accounts saved)))
|
||||
"AC18: Exactly one account row should be saved after mode-switch + save (no orphaned rows)")
|
||||
(is (= account-id (-> saved :transaction/accounts first :transaction-account/account :db/id))
|
||||
"AC18: The correct account should be saved")))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC19: split transaction re-opens in advanced mode with all splits
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest split-transaction-reopens-advanced-test
|
||||
(testing "AC19: split transaction (2+ accounts) re-opens in advanced mode with all splits intact"
|
||||
;; Test manual-mode-initial with 2-row snapshot
|
||||
(is (= :advanced (manual-mode-initial {:db/id 123
|
||||
:transaction/accounts [{:transaction-account/account 1
|
||||
:transaction-account/amount 50.0}
|
||||
{:transaction-account/account 2
|
||||
:transaction-account/amount 50.0}]}))
|
||||
"AC19: 2-account snapshot should return :advanced mode")
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "SPLITCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "account-id-1"
|
||||
:account/name "Split Account 1"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "account-id-2"
|
||||
:account/name "Split Account 2"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
account-id-1 (tempid->id result "account-id-1")
|
||||
account-id-2 (tempid->id result "account-id-2")
|
||||
client-id (tempid->id result "client-id")
|
||||
two-rows [{:db/id "row-1"
|
||||
:transaction-account/account account-id-1
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 50.0}
|
||||
{:db/id "row-2"
|
||||
:transaction-account/account account-id-2
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 50.0}]
|
||||
request {:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts two-rows}
|
||||
[]
|
||||
{:mode "advanced"
|
||||
:transaction/accounts two-rows})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
html (hiccup/html
|
||||
(fc/start-form (:multi-form-state request) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :advanced request))))]
|
||||
(is (re-find #"Switch to simple mode" html)
|
||||
"Advanced mode with 1 row should show 'Switch to simple mode' link")
|
||||
(is (not (re-find #"Switch to advanced mode" html))
|
||||
"Advanced mode should NOT show 'Switch to advanced mode' link"))))
|
||||
;; Should show both account IDs
|
||||
(is (re-find (re-pattern (str account-id-1)) html)
|
||||
"AC19: First split account should appear in advanced mode rendering")
|
||||
(is (re-find (re-pattern (str account-id-2)) html)
|
||||
"AC19: Second split account should appear in advanced mode rendering")
|
||||
;; Should NOT show 'Switch to simple mode' with 2 rows
|
||||
(is (not (re-find #"Switch to simple mode" html))
|
||||
"AC19: Split transaction (2 rows) in advanced mode should NOT show 'Switch to simple mode'"))))
|
||||
|
||||
;;; ---------------------------------------------------------------------------
|
||||
;;; AC20: single-account transaction re-opens in simple mode
|
||||
;;; ---------------------------------------------------------------------------
|
||||
|
||||
(deftest single-account-reopens-simple-test
|
||||
(testing "AC20: single-account transaction re-opens in simple mode with account/location pre-populated"
|
||||
;; Test manual-mode-initial returns :simple for single-account snapshot
|
||||
(is (= :simple (manual-mode-initial {:db/id 123
|
||||
:transaction/accounts [{:transaction-account/account 456
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]}))
|
||||
"AC20: Single-account snapshot should return :simple mode")
|
||||
(let [result @(dc/transact conn [{:db/id "client-id"
|
||||
:client/code "SINGCL"
|
||||
:client/locations ["DT"]}
|
||||
{:db/id "account-id"
|
||||
:account/name "Single Account"
|
||||
:account/type :account-type/expense}
|
||||
{:db/id "transaction-id"
|
||||
:transaction/amount 100.0
|
||||
:transaction/date #inst "2023-01-01"
|
||||
:transaction/id (str (java.util.UUID/randomUUID))
|
||||
:transaction/client "client-id"}])
|
||||
tx-id (tempid->id result "transaction-id")
|
||||
account-id (tempid->id result "account-id")
|
||||
client-id (tempid->id result "client-id")
|
||||
one-account [{:db/id "row-1"
|
||||
:transaction-account/account account-id
|
||||
:transaction-account/location "DT"
|
||||
:transaction-account/amount 100.0}]
|
||||
request {:multi-form-state (mm/->MultiStepFormState
|
||||
{:db/id tx-id
|
||||
:transaction/client client-id
|
||||
:transaction/accounts one-account}
|
||||
[]
|
||||
{:mode "simple"
|
||||
:transaction/accounts one-account})
|
||||
:entity {:db/id tx-id
|
||||
:transaction/client {:db/id client-id}
|
||||
:transaction/amount 100.0}}
|
||||
html (hiccup/html
|
||||
(fc/start-form (:multi-form-state request) nil
|
||||
(fc/with-field :step-params
|
||||
(manual-coding-section* :simple request))))]
|
||||
;; Simple mode should show the account typeahead pre-populated with the account
|
||||
(is (re-find (re-pattern (str account-id)) html)
|
||||
"AC20: Simple mode should show the account pre-populated")
|
||||
;; Should show 'Switch to advanced mode' (confirming it's in simple mode)
|
||||
(is (re-find #"Switch to advanced mode" html)
|
||||
"AC20: Simple mode should show 'Switch to advanced mode' link")
|
||||
;; Should NOT show 'Switch to simple mode'
|
||||
(is (not (re-find #"Switch to simple mode" html))
|
||||
"AC20: Simple mode should NOT show 'Switch to simple mode' link"))))
|
||||
|
||||
Reference in New Issue
Block a user