323 lines
24 KiB
Clojure
323 lines
24 KiB
Clojure
(ns auto-ap.integration.graphql
|
|
(:require [auto-ap.graphql :as sut]
|
|
[venia.core :as v]
|
|
[clojure.test :as t :refer [deftest is testing use-fixtures]]
|
|
[datomic.client.api :as dc]
|
|
[auto-ap.integration.util :refer [wrap-setup admin-token user-token]]
|
|
[auto-ap.datomic :refer [conn]]))
|
|
|
|
|
|
(defn new-client [args]
|
|
(merge {:client/name "Test client"
|
|
:client/code (.toString (java.util.UUID/randomUUID))
|
|
:client/locations ["AB"]}
|
|
args))
|
|
|
|
(defn new-transaction [args]
|
|
(merge {:transaction/amount 100.0
|
|
:transaction/date #inst "2021-01-01"
|
|
:transaction/id (.toString (java.util.UUID/randomUUID))}
|
|
args))
|
|
|
|
(defn new-invoice [args]
|
|
(merge {:invoice/total 100.0
|
|
:invoice/date #inst "2021-01-01"
|
|
:invoice/invoice-number (.toString (java.util.UUID/randomUUID))}
|
|
args))
|
|
|
|
(use-fixtures :each wrap-setup)
|
|
(deftest transaction-page
|
|
(testing "transaction page"
|
|
(dc/transact conn
|
|
{:tx-data
|
|
[(new-client {:db/id "client"})
|
|
(new-transaction {:transaction/client "client"})]})
|
|
|
|
(testing "It should find all transactions"
|
|
(let [result (:transaction-page (:data (sut/query (admin-token) "{ transaction_page(filters: {client_id: null}) { count, start, data { id } }}")))]
|
|
(is (= 1 (:count result)))
|
|
(is (= 0 (:start result)))
|
|
(is (= 1 (count (:data result))))))
|
|
|
|
(testing "Users should not see transactions they don't own"
|
|
(let [result (:transaction-page (:data (sut/query (user-token) "{ transaction_page(filters: {client_id: null}) { count, start, data { id } }}")))]
|
|
(is (= 0 (:count result)))
|
|
(is (= 0 (:start result)))
|
|
(is (= 0 (count (:data result))))))))
|
|
|
|
|
|
(deftest invoice-page
|
|
(testing "invoice page"
|
|
(dc/transact conn
|
|
{:tx-data
|
|
[(new-client {:db/id "client"})
|
|
(new-invoice {:invoice/client "client"
|
|
:invoice/status :invoice-status/paid})]})
|
|
(testing "It should find all invoices"
|
|
(let [result (first (:invoice-page (:data (sut/query (admin-token) "{ invoice_page(filters: {client_id: null, status:paid}) { count, start, invoices { id } }}"))))]
|
|
(is (= 1 (:count result)))
|
|
(is (= 0 (:start result)))
|
|
(is (= 1 (count (:invoices result))))))
|
|
|
|
(testing "Users should not see transactions they don't own"
|
|
(let [result (first (:invoice-page (:data (sut/query (user-token) "{ invoice_page(filters: {client_id: null}) { count, start, invoices { id } }}"))))]
|
|
(is (= 0 (:count result)))
|
|
(is (= 0 (:start result)))
|
|
(is (= 0 (count (:data result))))))))
|
|
|
|
(deftest ledger-page
|
|
(testing "ledger"
|
|
(testing "it should find ledger entries"
|
|
(let [result (:ledger-page (:data (sut/query (admin-token) "{ ledger_page(filters: {client_id: null}) { count, start, journal_entries { id } }}")))]
|
|
(is (int? (:count result)))
|
|
(is (int? (:start result)))
|
|
(is (seqable? (:journal-entries result)))))))
|
|
|
|
|
|
(deftest vendors
|
|
(testing "vendors"
|
|
(testing "it should find vendors"
|
|
(let [result (:ledger-page (:data (sut/query (admin-token) "{ ledger_page(filters: {client_id: null}) { count, start, journal_entries { id } }}")))]
|
|
(is (int? (:count result)))
|
|
(is (int? (:start result)))
|
|
(is (seqable? (:journal-entries result)))))))
|
|
|
|
(deftest transaction-rule-page
|
|
(testing "it should find rules"
|
|
(let [result (-> (sut/query (admin-token) "{ transaction_rule_page(client_id: null) { count, start, transaction_rules { id } }}")
|
|
:data
|
|
:transaction-rule-page)]
|
|
(is (int? (:count result)))
|
|
(is (int? (:start result)))
|
|
(is (seqable? (:transaction-rules result))))))
|
|
|
|
(deftest upsert-transaction-rule
|
|
(let [{:strs [vendor-id account-id yodlee-merchant-id]} (->
|
|
(dc/transact
|
|
conn
|
|
{:tx-data
|
|
[{:vendor/name "Bryce's Meat Co"
|
|
:db/id "vendor-id"}
|
|
{:account/name "hello"
|
|
:db/id "account-id"}
|
|
{:yodlee-merchant/name "yodlee"
|
|
:db/id "yodlee-merchant-id"}]})
|
|
|
|
:tempids)]
|
|
(testing "it should reject rules that don't add up to 100%"
|
|
(let [q (v/graphql-query {:venia/operation {:operation/type :mutation
|
|
:operation/name "UpsertTransactionRule"}
|
|
:venia/queries [{:query/data (sut/->graphql [:upsert-transaction-rule
|
|
{:transaction-rule {:accounts [{:account-id account-id
|
|
:percentage "0.25"
|
|
:location "Shared"}]}}
|
|
[:id ]])}]})]
|
|
(is (thrown? clojure.lang.ExceptionInfo (sut/query (admin-token) q)))))
|
|
|
|
|
|
(testing "It should reject rules that are missing both description and merchant"
|
|
(let [q (v/graphql-query {:venia/operation {:operation/type :mutation
|
|
:operation/name "UpsertTransactionRule"}
|
|
:venia/queries [{:query/data (sut/->graphql [:upsert-transaction-rule
|
|
{:transaction-rule {:accounts [{:account-id account-id
|
|
:percentage "1.0"
|
|
:location "Shared"}]}}
|
|
[:id ]])}]})]
|
|
(is (thrown? clojure.lang.ExceptionInfo (sut/query (admin-token) q)))))
|
|
(testing "it should add rules"
|
|
(let [q (v/graphql-query {:venia/operation {:operation/type :mutation
|
|
:operation/name "UpsertTransactionRule"}
|
|
:venia/queries [{:query/data (sut/->graphql [:upsert-transaction-rule
|
|
{:transaction-rule {:description "123"
|
|
:yodlee-merchant-id yodlee-merchant-id
|
|
:vendor-id vendor-id
|
|
:transaction-approval-status :approved
|
|
:accounts [{:account-id account-id
|
|
:percentage "0.5"
|
|
:location "Shared"}
|
|
{:account-id account-id
|
|
:percentage "0.5"
|
|
:location "Shared"}]}}
|
|
[:id :description
|
|
:transaction-approval-status
|
|
[:vendor [:name]]
|
|
[:yodlee-merchant [:name]]
|
|
[:accounts [:id :percentage [:account [:name]]]]]])}]})
|
|
result (-> (sut/query (admin-token) q)
|
|
:data
|
|
:upsert-transaction-rule)]
|
|
|
|
(is (= "123" (:description result)))
|
|
(is (= "Bryce's Meat Co" (-> result :vendor :name)))
|
|
(is (= "yodlee" (-> result :yodlee-merchant :name)))
|
|
(is (= :approved (:transaction-approval-status result)))
|
|
(is (= "hello" (-> result :accounts (get 0) :account :name )))
|
|
(is (:id result))
|
|
|
|
(testing "it should unset removed fields"
|
|
(let [q (v/graphql-query {:venia/operation {:operation/type :mutation
|
|
:operation/name "UpsertTransactionRule"}
|
|
:venia/queries [{:query/data (sut/->graphql [:upsert-transaction-rule
|
|
{:transaction-rule {:id (:id result)
|
|
:description "123"
|
|
:vendor-id nil
|
|
:accounts [{:id (-> result :accounts (get 0) :id)
|
|
:account-id account-id
|
|
:percentage "1.0"
|
|
:location "Shared"}]}}
|
|
[[:vendor [:name]]]])}]})
|
|
result (-> (sut/query (admin-token) q)
|
|
:data
|
|
:upsert-transaction-rule)]
|
|
|
|
(is (nil? (:vendor result)))))
|
|
|
|
(testing "it should delete removed rules"
|
|
(let [q (v/graphql-query {:venia/operation {:operation/type :mutation
|
|
:operation/name "UpsertTransactionRule"}
|
|
:venia/queries [{:query/data (sut/->graphql [:upsert-transaction-rule
|
|
{:transaction-rule {:id (:id result)
|
|
:description "123"
|
|
:vendor-id vendor-id
|
|
:accounts [{:id (-> result :accounts (get 0) :id)
|
|
:account-id account-id
|
|
:percentage "1.0"
|
|
:location "Shared"}]}}
|
|
[[:accounts [:id :percentage [:account [:name]]]]]])}]})
|
|
result (-> (sut/query (admin-token) q)
|
|
:data
|
|
:upsert-transaction-rule)]
|
|
|
|
(is (= 1 (count (:accounts result))))))))))
|
|
|
|
|
|
(deftest test-transaction-rule
|
|
(testing "it should match rules"
|
|
(let [matching-transaction (dc/transact conn
|
|
{:tx-data
|
|
[{:transaction/description-original "matching-desc"
|
|
:transaction/date #inst "2019-01-05T00:00:00.000-08:00"
|
|
:transaction/client {:client/name "1"
|
|
:db/id "client-1"}
|
|
:transaction/bank-account {:db/id "bank-account-1"
|
|
:bank-account/name "1"}
|
|
|
|
:transaction/amount 1.00
|
|
:transaction/id "2019-01-05 matching-desc 1"
|
|
:db/id "a"}
|
|
|
|
{:transaction/description-original "nonmatching-desc"
|
|
:transaction/client {:client/name "2"
|
|
:db/id "client-2"}
|
|
:transaction/bank-account {:db/id "bank-account-2"
|
|
:bank-account/name "2"}
|
|
:transaction/date #inst "2019-01-15T23:23:00.000-08:00"
|
|
:transaction/amount 2.00
|
|
:transaction/id "2019-01-15 nonmatching-desc 2"
|
|
:db/id "b"}]})
|
|
{:strs [a b client-1 client-2 bank-account-1 bank-account-2]} (get-in matching-transaction [:tempids])
|
|
a (str a)
|
|
b (str b)
|
|
|
|
rule-test (fn [rule]
|
|
(-> (sut/query (admin-token) (v/graphql-query {:venia/operation {:operation/type :query
|
|
:operation/name "TestTransactionRule"}
|
|
:venia/queries [{:query/data (sut/->graphql [:test-transaction-rule
|
|
{:transaction-rule rule}
|
|
[:id]])}]}))
|
|
:data
|
|
:test-transaction-rule))]
|
|
(testing "based on date "
|
|
(is (= [{:id b}] (rule-test {:dom-gte 14 :dom-lte 16})))
|
|
(is (= [{:id b}] (rule-test {:dom-gte 14})))
|
|
(is (= (set [{:id a} {:id b}]) (set (rule-test {:dom-lte 15}))))
|
|
(is (= [{:id b}] (rule-test {:dom-gte 15})))
|
|
(is (= [{:id b}] (rule-test {:dom-gte 15 :dom-lte 15}))))
|
|
|
|
(testing "based on description"
|
|
(is (= [{:id a}] (rule-test {:description "^match"}))))
|
|
|
|
(testing "based on amount"
|
|
(is (= [{:id a}] (rule-test {:amount-gte 1.0 :amount-lte 1.0})))
|
|
(is (= (set [{:id a} {:id b}]) (set (rule-test {:amount-gte 1.0 }))) )
|
|
(is (= (set [{:id a} {:id b}]) (set (rule-test {:amount-lte 2.0 }))) ))
|
|
|
|
(testing "based on client"
|
|
(is (= [{:id a}] (rule-test {:client-id (str client-1)})))
|
|
(is (= [{:id b}] (rule-test {:client-id (str client-2)}))))
|
|
|
|
(testing "based on bank account"
|
|
(is (= [{:id a}] (rule-test {:bank-account-id (str bank-account-1)})))
|
|
(is (= [{:id b}] (rule-test {:bank-account-id (str bank-account-2)})))))))
|
|
|
|
(deftest test-match-transaction-rule
|
|
(testing "it should apply a rules"
|
|
(let [{:strs [transaction-id transaction-rule-id uneven-transaction-rule-id]} (-> (dc/transact conn
|
|
{:tx-data
|
|
[{:transaction/description-original "matching-desc"
|
|
:transaction/date #inst "2019-01-05T00:00:00.000-08:00"
|
|
:transaction/client {:client/name "1"
|
|
:db/id "client-1"}
|
|
:transaction/bank-account {:db/id "bank-account-1"
|
|
:bank-account/name "1"}
|
|
:transaction/amount 1.00
|
|
:db/id "transaction-id"}
|
|
|
|
{:db/id "transaction-rule-id"
|
|
:transaction-rule/note "transaction rule note"
|
|
:transaction-rule/description "matching-desc"
|
|
:transaction-rule/accounts [{:transaction-rule-account/location "A"
|
|
:transaction-rule-account/account {:account/numeric-code 123 :db/id "123"}
|
|
:transaction-rule-account/percentage 1.0}]}
|
|
{:db/id "uneven-transaction-rule-id"
|
|
:transaction-rule/note "transaction rule note"
|
|
:transaction-rule/description "matching-desc"
|
|
:transaction-rule/accounts [{:transaction-rule-account/location "A"
|
|
:transaction-rule-account/account {:account/numeric-code 123 :db/id "123"}
|
|
:transaction-rule-account/percentage 0.3333333}
|
|
{:transaction-rule-account/location "B"
|
|
:transaction-rule-account/account {:account/numeric-code 123 :db/id "123"}
|
|
:transaction-rule-account/percentage 0.33333333}
|
|
{:transaction-rule-account/location "c"
|
|
:transaction-rule-account/account {:account/numeric-code 123 :db/id "123"}
|
|
:transaction-rule-account/percentage 0.333333}]}]})
|
|
:tempids)
|
|
rule-test (-> (sut/query (admin-token) (v/graphql-query {:venia/operation {:operation/type :mutation
|
|
:operation/name "MatchTransactionRules"}
|
|
:venia/queries [{:query/data (sut/->graphql [:match-transaction-rules
|
|
{:transaction-rule-id transaction-rule-id
|
|
:transaction-ids [transaction-id]}
|
|
[[:matched-rule [:id :note]] [:accounts [:id]] ]])}]}))
|
|
:data
|
|
:match-transaction-rules)]
|
|
|
|
(is (= "transaction rule note" (-> rule-test first :matched-rule :note)))
|
|
(is (= 1 (-> rule-test first :accounts count)))
|
|
|
|
(testing "Should replace accounts when matching a second time"
|
|
(let [rule-test (-> (sut/query (admin-token) (v/graphql-query {:venia/operation {:operation/type :mutation
|
|
:operation/name "MatchTransactionRules"}
|
|
:venia/queries [{:query/data (sut/->graphql [:match-transaction-rules
|
|
{:transaction-rule-id transaction-rule-id
|
|
:transaction-ids [transaction-id]}
|
|
[[:matched-rule [:id :note]] [:accounts [:id]] ]])}]}))
|
|
:data
|
|
:match-transaction-rules)]
|
|
(is (= 1 (-> rule-test first :accounts count)))))
|
|
|
|
(testing "Should round when the transaction can't be divided eventy"
|
|
(let [rule-test (-> (sut/query (admin-token) (v/graphql-query {:venia/operation {:operation/type :mutation
|
|
:operation/name "MatchTransactionRules"}
|
|
:venia/queries [{:query/data (sut/->graphql [:match-transaction-rules
|
|
{:transaction-rule-id uneven-transaction-rule-id
|
|
:transaction-ids [transaction-id]}
|
|
[[:matched-rule [:id :note]] [:accounts [:id :amount]] ]])}]}))
|
|
:data
|
|
:match-transaction-rules)]
|
|
(is (= 3 (-> rule-test first :accounts count)))
|
|
(is (= "0.33" (-> rule-test first :accounts (nth 0) :amount)))
|
|
(is (= "0.33" (-> rule-test first :accounts (nth 1) :amount)))
|
|
(is (= "0.34" (-> rule-test first :accounts (nth 2) :amount))))))))
|
|
|
|
|