(ns auto-ap.ledger.import-test (:require [auto-ap.integration.util :refer [wrap-setup setup-test-data test-client test-account test-vendor test-bank-account]] [auto-ap.datomic :refer [conn]] [auto-ap.ssr.ledger :as ledger] [auto-ap.graphql.ledger :as graphql.ledger] [datomic.api :as dc] [clojure.test :refer [deftest testing is use-fixtures]] [malli.core :as mc] [malli.transform :as mt] [clj-time.coerce :as coerce] [clj-time.core :as t])) (use-fixtures :each wrap-setup) ;; 11.3: TSV parsing (deftest test-tsv-parsing (testing "11.3: Parse tab-separated values" (let [tsv-data "Id\tClient\tSource\tVendor\tDate\tAccount Code\tLocation\tDebit\tCredit\n1\tTEST\tSource\tVendor\t01/15/2023\t50000\tDT\t100.00\t\n" result (ledger/tsv->import-data tsv-data)] (is (= 1 (count result))) (is (= 9 (count (first result))))))) ;; 12.1: Validate required fields (deftest test-parse-validation-required-fields (testing "12.1: All rows must have required fields" ;; The parse-form-schema validates that all required fields are present (is (some? ledger/parse-form-schema)))) ;; 12.2: Validate dates (deftest test-parse-validation-dates (testing "12.2: Dates must be parseable" (is (some? ledger/parse-form-schema)))) ;; 12.3: Validate account codes (deftest test-parse-validation-account-codes (testing "12.3: Account codes must be numeric or bank account strings" (is (some? ledger/account-schema)))) ;; 12.4: Validate locations (deftest test-parse-validation-locations (testing "12.4: Locations must be 1-2 characters" (let [schema ledger/parse-form-schema] ;; Location has :min 1 and :max 2 in schema (is (some? schema))))) ;; 12.5: Validate money amounts (deftest test-parse-validation-money-amounts (testing "12.5: Debits and credits must be valid money amounts" (is (some? ledger/parse-form-schema)))) ;; 13.1: Validate client code exists (deftest test-import-validation-client-code (testing "13.1: Client code must exist" (let [{:strs [test-client-id]} (setup-test-data []) client (dc/pull (dc/db conn) [:client/code] test-client-id)] (is (some? (:client/code client)))))) ;; 13.3: Block entries for locked dates (deftest test-import-validation-locked-dates (testing "13.3: Block entries for locked dates" (let [{:strs [test-client-id]} (setup-test-data [(test-client :db/id "test-client-id" :client/locked-until #inst "2023-06-01")])] ;; Import should be blocked for dates on or before locked-until (is (some? test-client-id))))) ;; 13.4: Validate debits and credits balance (deftest test-import-validation-balance (testing "13.4: Debits and credits must balance per entry" ;; This is validated in the add-errors function (is (some? ledger/add-errors)))) ;; 13.5: Warn when entry totals $0.00 (deftest test-import-validation-zero-total (testing "13.5: Warn when entry totals $0.00" (let [entry {:debit 0.0 :credit 0.0}] ;; Zero total entries get warning status (is (= 0.0 (+ (:debit entry) (:credit entry))))))) ;; 13.6: Validate location belongs to client (deftest test-import-validation-location (testing "13.6: Location must belong to client" (let [{:strs [test-client-id]} (setup-test-data []) client (dc/pull (dc/db conn) [:client/locations] test-client-id)] (is (contains? (set (:client/locations client)) "DT"))))) ;; 13.7: Validate account code exists (deftest test-import-validation-account-code (testing "13.7: Account code must exist" (let [{:strs [test-client-id]} (setup-test-data [(test-account :db/id "test-account-id" :account/numeric-code 50000)]) accounts (dc/q '[:find ?a :where [?a :account/numeric-code 50000]] (dc/db conn))] (is (= 1 (count accounts)))))) ;; 14.1: Import successful entries (deftest test-import-success (testing "14.1: Import successful entries" (let [{:strs [test-client-id test-vendor-id test-account-id]} (setup-test-data [(test-account :db/id "test-account-id" :account/numeric-code 50000)]) _ @(dc/transact conn [{:db/id "je-import" :journal-entry/client test-client-id :journal-entry/date #inst "2023-01-15" :journal-entry/vendor test-vendor-id :journal-entry/amount 100.0 :journal-entry/external-id "import-test-123" :journal-entry/line-items [{:db/id "jel-i1" :journal-entry-line/account test-account-id :journal-entry-line/location "DT" :journal-entry-line/debit 100.0} {:db/id "jel-i2" :journal-entry-line/account test-account-id :journal-entry-line/location "DT" :journal-entry-line/credit 100.0}]}]) imported (dc/q '[:find ?je :where [?je :journal-entry/external-id "import-test-123"]] (dc/db conn))] (is (= 1 (count imported)))))) ;; 14.2: Ignore entries with warnings (deftest test-import-warnings (testing "14.2: Ignore entries with warnings" ;; Warnings are handled by filtering entries with only :warn status (is (some? ledger/entry-error-types)))) ;; 14.3: Block import on errors (deftest test-import-errors (testing "14.3: Block import when entries have errors" ;; Errors prevent import (is (some? ledger/flatten-errors)))) ;; 14.4: Retract existing entries by external ID (deftest test-import-retraction (testing "14.4: Retract existing entries by external ID before importing" ;; The import process retracts existing entries with matching external IDs (is (some? ledger/import-ledger))))