supports adding conclusions.
This commit is contained in:
@@ -350,6 +350,32 @@
|
|||||||
:db/valueType :db.type/long
|
:db/valueType :db.type/long
|
||||||
:db/cardinality :db.cardinality/one
|
:db/cardinality :db.cardinality/one
|
||||||
:db/doc "Day of month has to be greater than or equal to this"}
|
:db/doc "Day of month has to be greater than or equal to this"}
|
||||||
|
|
||||||
|
{:db/ident :transaction-rule/vendor
|
||||||
|
:db/valueType :db.type/ref
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/doc "The vendor to assign"}
|
||||||
|
|
||||||
|
{:db/ident :transaction-rule-account/percentage
|
||||||
|
:db/valueType :db.type/double
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/doc "How much should go to this account"}
|
||||||
|
|
||||||
|
{:db/ident :transaction-rule-account/location
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/doc "The location this split is for"}
|
||||||
|
|
||||||
|
{:db/ident :transaction-rule-account/account
|
||||||
|
:db/valueType :db.type/ref
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/doc "The account of this split"}
|
||||||
|
|
||||||
|
{:db/ident :transaction-rule/accounts
|
||||||
|
:db/valueType :db.type/ref
|
||||||
|
:db/cardinality :db.cardinality/many
|
||||||
|
:db/isComponent true
|
||||||
|
:db/doc "The outcome split"}
|
||||||
]])
|
]])
|
||||||
|
|
||||||
(def add-credit-bank-account
|
(def add-credit-bank-account
|
||||||
|
|||||||
@@ -11,7 +11,12 @@
|
|||||||
(def default-read '[*
|
(def default-read '[*
|
||||||
{:transaction-rule/client [:client/name :db/id :client/code]}
|
{:transaction-rule/client [:client/name :db/id :client/code]}
|
||||||
{:transaction-rule/bank-account [*]}
|
{:transaction-rule/bank-account [*]}
|
||||||
{:transaction-rule/yodlee-merchant [*]}])
|
{:transaction-rule/yodlee-merchant [*]}
|
||||||
|
{:transaction-rule/vendor [:vendor/name :db/id :vendor/default-account]}
|
||||||
|
{:transaction-rule/accounts [:transaction-rule-account/percentage
|
||||||
|
:transaction-rule-account/location
|
||||||
|
{:transaction-rule-account/account [*]}
|
||||||
|
:db/id]}])
|
||||||
|
|
||||||
(defn raw-graphql-ids [db args]
|
(defn raw-graphql-ids [db args]
|
||||||
(let [query (cond-> {:query {:find []
|
(let [query (cond-> {:query {:find []
|
||||||
|
|||||||
@@ -47,7 +47,14 @@
|
|||||||
:serialize (schema/as-conformer #(if (double? %)
|
:serialize (schema/as-conformer #(if (double? %)
|
||||||
(str %)
|
(str %)
|
||||||
%))
|
%))
|
||||||
}}
|
}
|
||||||
|
:percentage {:parse (schema/as-conformer #(if (and (string? %)
|
||||||
|
(not (str/blank? %)))
|
||||||
|
(Double/parseDouble %)
|
||||||
|
%))
|
||||||
|
:serialize (schema/as-conformer #(if (double? %)
|
||||||
|
(str %)
|
||||||
|
%))}}
|
||||||
:objects
|
:objects
|
||||||
{
|
{
|
||||||
:client
|
:client
|
||||||
@@ -193,7 +200,8 @@
|
|||||||
:amount_gte {:type 'String}
|
:amount_gte {:type 'String}
|
||||||
:dom_lte {:type 'Int}
|
:dom_lte {:type 'Int}
|
||||||
:dom_gte {:type 'Int}
|
:dom_gte {:type 'Int}
|
||||||
:vendor {:type :vendor}}}
|
:vendor {:type :vendor}
|
||||||
|
:accounts {:type '(list :percentage_account)}}}
|
||||||
|
|
||||||
:invoice_payment
|
:invoice_payment
|
||||||
{:fields {:id {:type :id}
|
{:fields {:id {:type :id}
|
||||||
@@ -226,6 +234,11 @@
|
|||||||
|
|
||||||
:amount {:type 'String}}}
|
:amount {:type 'String}}}
|
||||||
|
|
||||||
|
:percentage_account
|
||||||
|
{:fields {:id {:type :id}
|
||||||
|
:account {:type :account}
|
||||||
|
:location {:type 'String}
|
||||||
|
:percentage {:type :percentage}}}
|
||||||
:invoice
|
:invoice
|
||||||
{:fields {:id {:type :id}
|
{:fields {:id {:type :id}
|
||||||
:original_id {:type 'Int}
|
:original_id {:type 'Int}
|
||||||
@@ -507,6 +520,12 @@
|
|||||||
:vendor_id {:type :id}
|
:vendor_id {:type :id}
|
||||||
:accounts {:type '(list :edit_expense_account)}}}
|
:accounts {:type '(list :edit_expense_account)}}}
|
||||||
|
|
||||||
|
:edit_percentage_account
|
||||||
|
{:fields {:id {:type :id}
|
||||||
|
:account_id {:type :id}
|
||||||
|
:location {:type 'String}
|
||||||
|
:percentage {:type :percentage}}}
|
||||||
|
|
||||||
:edit_transaction_rule
|
:edit_transaction_rule
|
||||||
{:fields {:id {:type :id}
|
{:fields {:id {:type :id}
|
||||||
:description {:type 'String}
|
:description {:type 'String}
|
||||||
@@ -516,7 +535,9 @@
|
|||||||
:amount_lte {:type :money}
|
:amount_lte {:type :money}
|
||||||
:amount_gte {:type :money}
|
:amount_gte {:type :money}
|
||||||
:dom_lte {:type 'Int}
|
:dom_lte {:type 'Int}
|
||||||
:dom_gte {:type 'Int}}}
|
:dom_gte {:type 'Int}
|
||||||
|
:vendor_id {:type :id}
|
||||||
|
:accounts {:type '(list :edit_percentage_account)}}}
|
||||||
|
|
||||||
:edit_account
|
:edit_account
|
||||||
{:fields {:id {:type :id}
|
{:fields {:id {:type :id}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
[datomic.api :as d]
|
[datomic.api :as d]
|
||||||
[auto-ap.datomic :refer [remove-nils uri merge-query]]
|
[auto-ap.datomic :refer [remove-nils uri merge-query]]
|
||||||
[auto-ap.graphql.utils :refer [->graphql <-graphql limited-clients assert-admin result->page]]
|
[auto-ap.graphql.utils :refer [->graphql <-graphql limited-clients assert-admin result->page]]
|
||||||
[clj-time.coerce :as c])
|
[clj-time.coerce :as c]
|
||||||
|
[clojure.set :as set])
|
||||||
(:import [java.time.temporal ChronoField]))
|
(:import [java.time.temporal ChronoField]))
|
||||||
|
|
||||||
(defn get-transaction-rule-page [context args value]
|
(defn get-transaction-rule-page [context args value]
|
||||||
@@ -12,9 +13,27 @@
|
|||||||
[journal-entries journal-entries-count] (tr/get-graphql (<-graphql args))]
|
[journal-entries journal-entries-count] (tr/get-graphql (<-graphql args))]
|
||||||
(result->page journal-entries journal-entries-count :transaction_rules args)))
|
(result->page journal-entries journal-entries-count :transaction_rules args)))
|
||||||
|
|
||||||
|
(defn deleted-accounts [transaction accounts]
|
||||||
|
(let [current-accounts (:transaction-rule/accounts transaction)
|
||||||
|
specified-ids (->> accounts
|
||||||
|
(map :id)
|
||||||
|
set)
|
||||||
|
existing-ids (->> current-accounts
|
||||||
|
(map :db/id)
|
||||||
|
set)]
|
||||||
|
(set/difference existing-ids specified-ids)))
|
||||||
|
|
||||||
|
(defn transaction-rule-account->entity [{:keys [id account_id percentage location]}]
|
||||||
|
(remove-nils #:transaction-rule-account {:percentage percentage
|
||||||
|
:db/id id
|
||||||
|
:account account_id
|
||||||
|
:location location}))
|
||||||
;; TODO ASSERT ADMIN
|
;; TODO ASSERT ADMIN
|
||||||
(defn upsert-transaction-rule [context {{:keys [id description note client_id bank_account_id amount_lte amount_gte ]} :transaction_rule :as z} value]
|
(defn upsert-transaction-rule [context {{:keys [id description note client_id bank_account_id amount_lte amount_gte vendor_id accounts ]} :transaction_rule :as z} value]
|
||||||
(let [transaction [(remove-nils #:transaction-rule {:db/id (if id
|
#_(assert-admin (:id context))
|
||||||
|
(let [existing-transaction (tr/get-by-id id)
|
||||||
|
deleted (deleted-accounts existing-transaction accounts)
|
||||||
|
transaction [(remove-nils #:transaction-rule {:db/id (if id
|
||||||
id
|
id
|
||||||
"transaction-rule")
|
"transaction-rule")
|
||||||
:description description
|
:description description
|
||||||
@@ -22,8 +41,14 @@
|
|||||||
:client client_id
|
:client client_id
|
||||||
:bank-account bank_account_id
|
:bank-account bank_account_id
|
||||||
:amount-lte amount_lte
|
:amount-lte amount_lte
|
||||||
:amount-gte amount_gte})]
|
:amount-gte amount_gte
|
||||||
_ (println transaction)
|
:vendor vendor_id
|
||||||
|
:accounts (map transaction-rule-account->entity accounts)})]
|
||||||
|
|
||||||
|
transaction (into transaction
|
||||||
|
(map (fn [d]
|
||||||
|
[:db/retract id :transaction-rule/accounts d])
|
||||||
|
deleted))
|
||||||
transaction-result @(d/transact (d/connect uri) transaction)]
|
transaction-result @(d/transact (d/connect uri) transaction)]
|
||||||
(-> (tr/get-by-id (or (-> transaction-result :tempids (get "transaction-rule"))
|
(-> (tr/get-by-id (or (-> transaction-result :tempids (get "transaction-rule"))
|
||||||
id))
|
id))
|
||||||
@@ -33,7 +58,6 @@
|
|||||||
(re-find (re-pattern z) x))
|
(re-find (re-pattern z) x))
|
||||||
|
|
||||||
(defn test-transaction-rule [{:keys [id]} {{:keys [description note client_id bank_account_id amount_lte amount_gte dom_lte dom_gte]} :transaction_rule :as z} value]
|
(defn test-transaction-rule [{:keys [id]} {{:keys [description note client_id bank_account_id amount_lte amount_gte dom_lte dom_gte]} :transaction_rule :as z} value]
|
||||||
(prn z)
|
|
||||||
(->>
|
(->>
|
||||||
(d/query
|
(d/query
|
||||||
(cond-> {:query {:find ['(pull ?e [* {:transaction/client [:client/name]
|
(cond-> {:query {:find ['(pull ?e [* {:transaction/client [:client/name]
|
||||||
@@ -95,6 +119,7 @@
|
|||||||
:args [client_id]})
|
:args [client_id]})
|
||||||
true
|
true
|
||||||
(merge-query {:query {:where ['[?e :transaction/id]]}})))
|
(merge-query {:query {:where ['[?e :transaction/id]]}})))
|
||||||
|
|
||||||
(transduce (comp
|
(transduce (comp
|
||||||
(take 15)
|
(take 15)
|
||||||
(map first)
|
(map first)
|
||||||
|
|||||||
@@ -14,85 +14,124 @@
|
|||||||
(d/delete-database uri))
|
(d/delete-database uri))
|
||||||
|
|
||||||
(use-fixtures :each wrap-setup)
|
(use-fixtures :each wrap-setup)
|
||||||
(deftest query
|
(deftest ledger-page
|
||||||
(testing "ledger"
|
(testing "ledger"
|
||||||
(testing "it should find ledger entries"
|
(testing "it should find ledger entries"
|
||||||
(let [result (:ledger-page (:data (sut/query nil "{ ledger_page(client_id: null) { count, start, journal_entries { id } }}")))]
|
(let [result (:ledger-page (:data (sut/query nil "{ ledger_page(client_id: null) { count, start, journal_entries { id } }}")))]
|
||||||
(is (int? (:count result)))
|
(is (int? (:count result)))
|
||||||
(is (int? (:start result)))
|
(is (int? (:start result)))
|
||||||
(is (seqable? (:journal-entries result))))))
|
(is (seqable? (:journal-entries result)))))))
|
||||||
|
|
||||||
(testing "transaction-rules"
|
(deftest transaction-rule-page
|
||||||
(testing "it should find rules"
|
(testing "it should find rules"
|
||||||
(let [result (-> (sut/query nil "{ transaction_rule_page(client_id: null) { count, start, transaction_rules { id } }}")
|
(let [result (-> (sut/query nil "{ transaction_rule_page(client_id: null) { count, start, transaction_rules { id } }}")
|
||||||
:data
|
:data
|
||||||
:transaction-rule-page)]
|
:transaction-rule-page)]
|
||||||
(is (int? (:count result)))
|
(is (int? (:count result)))
|
||||||
(is (int? (:start result)))
|
(is (int? (:start result)))
|
||||||
(is (seqable? (:transaction-rules result)))))
|
(is (seqable? (:transaction-rules result))))))
|
||||||
|
|
||||||
(testing "it should add rules"
|
(deftest upsert-transaction-rule
|
||||||
(let [q (v/graphql-query {:venia/operation {:operation/type :mutation
|
(testing "it should add rules"
|
||||||
:operation/name "UpsertTransactionRule"}
|
(let [{:strs [vendor-id account-id]} (-> (d/connect uri)
|
||||||
:venia/queries [{:query/data (sut/->graphql [:upsert-transaction-rule
|
(d/transact
|
||||||
{:transaction-rule {:description "123"}}
|
[{:vendor/name "Bryce's Meat Co"
|
||||||
[:id :description]])}]})
|
:db/id "vendor-id"}
|
||||||
result (-> (sut/query nil q)
|
{:account/name "hello"
|
||||||
:data
|
:db/id "account-id"}])
|
||||||
:upsert-transaction-rule)]
|
deref
|
||||||
(is (= "123" (:description result)))
|
:tempids)
|
||||||
(is (:id result))))
|
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"
|
||||||
|
:vendor-id vendor-id
|
||||||
|
:accounts [{:account-id account-id
|
||||||
|
:percentage "0.5"
|
||||||
|
:location "B"}
|
||||||
|
{:account-id account-id
|
||||||
|
:percentage "0.5"
|
||||||
|
:location "A"}]}}
|
||||||
|
[:id :description
|
||||||
|
[:vendor [:name]]
|
||||||
|
[:accounts [:id :percentage [:account [:name]]]]]])}]})
|
||||||
|
result (-> (sut/query nil q)
|
||||||
|
:data
|
||||||
|
:upsert-transaction-rule)]
|
||||||
|
|
||||||
|
(is (= "123" (:description result)))
|
||||||
|
(is (= "Bryce's Meat Co" (-> result :vendor :name)))
|
||||||
|
(is (= "hello" (-> result :accounts (get 0) :account :name )))
|
||||||
|
(is (:id 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 "B"}]}}
|
||||||
|
[[:accounts [:id :percentage [:account [:name]]]]]])}]})
|
||||||
|
result (-> (sut/query nil q)
|
||||||
|
:data
|
||||||
|
:upsert-transaction-rule)]
|
||||||
|
|
||||||
(testing "it should match rules based on description regex"
|
(is (= 1 (count (:accounts result)))))))))
|
||||||
(let [matching-transaction @(d/transact (d/connect uri)
|
|
||||||
[{: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
|
(deftest test-transaction-rule
|
||||||
:transaction/id "2019-01-05 matching-desc 1"}
|
(testing "it should match rules"
|
||||||
|
(let [matching-transaction @(d/transact (d/connect uri)
|
||||||
|
[{: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/description-original "nonmatching-desc"
|
:transaction/amount 1.00
|
||||||
:transaction/client {:client/name "2"
|
:transaction/id "2019-01-05 matching-desc 1"}
|
||||||
: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"}])
|
|
||||||
{:strs [client-1 client-2 bank-account-1 bank-account-2]} (get-in matching-transaction [:tempids])
|
|
||||||
|
|
||||||
rule-test (fn [rule]
|
{:transaction/description-original "nonmatching-desc"
|
||||||
(-> (sut/query nil (v/graphql-query {:venia/operation {:operation/type :query
|
:transaction/client {:client/name "2"
|
||||||
:operation/name "TestTransactionRule"}
|
:db/id "client-2"}
|
||||||
:venia/queries [{:query/data (sut/->graphql [:test-transaction-rule
|
:transaction/bank-account {:db/id "bank-account-2"
|
||||||
{:transaction-rule rule}
|
:bank-account/name "2"}
|
||||||
[:id]])}]}))
|
:transaction/date #inst "2019-01-15T23:23:00.000-08:00"
|
||||||
:data
|
:transaction/amount 2.00
|
||||||
:test-transaction-rule))]
|
:transaction/id "2019-01-15 nonmatching-desc 2"}])
|
||||||
(testing "based on date "
|
{:strs [client-1 client-2 bank-account-1 bank-account-2]} (get-in matching-transaction [:tempids])
|
||||||
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-gte 14 :dom-lte 16})))
|
|
||||||
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-gte 14})))
|
|
||||||
(is (= [{:id "2019-01-05 matching-desc 1"} {:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-lte 15})))
|
|
||||||
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-gte 15})))
|
|
||||||
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-gte 15 :dom-lte 15}))))
|
|
||||||
|
|
||||||
(testing "based on description"
|
rule-test (fn [rule]
|
||||||
(is (= [{:id "2019-01-05 matching-desc 1"}] (rule-test {:description "^match"}))))
|
(-> (sut/query nil (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 "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-gte 14 :dom-lte 16})))
|
||||||
|
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-gte 14})))
|
||||||
|
(is (= [{:id "2019-01-05 matching-desc 1"} {:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-lte 15})))
|
||||||
|
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-gte 15})))
|
||||||
|
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:dom-gte 15 :dom-lte 15}))))
|
||||||
|
|
||||||
(testing "based on amount"
|
(testing "based on description"
|
||||||
(is (= [{:id "2019-01-05 matching-desc 1"}] (rule-test {:amount-gte 1.0 :amount-lte 1.0})))
|
(is (= [{:id "2019-01-05 matching-desc 1"}] (rule-test {:description "^match"}))))
|
||||||
(is (= [{:id "2019-01-05 matching-desc 1"} {:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:amount-gte 1.0 })) )
|
|
||||||
(is (= [{:id "2019-01-05 matching-desc 1"} {:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:amount-lte 2.0 })) ))
|
|
||||||
|
|
||||||
(testing "based on client"
|
(testing "based on amount"
|
||||||
(is (= [{:id "2019-01-05 matching-desc 1"}] (rule-test {:client-id client-1})))
|
(is (= [{:id "2019-01-05 matching-desc 1"}] (rule-test {:amount-gte 1.0 :amount-lte 1.0})))
|
||||||
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:client-id client-2}))))
|
(is (= [{:id "2019-01-05 matching-desc 1"} {:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:amount-gte 1.0 })) )
|
||||||
|
(is (= [{:id "2019-01-05 matching-desc 1"} {:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:amount-lte 2.0 })) ))
|
||||||
|
|
||||||
(testing "based on bank account"
|
(testing "based on client"
|
||||||
(is (= [{:id "2019-01-05 matching-desc 1"}] (rule-test {:bank-account-id bank-account-1})))
|
(is (= [{:id "2019-01-05 matching-desc 1"}] (rule-test {:client-id client-1})))
|
||||||
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:bank-account-id bank-account-2}))))))))
|
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:client-id client-2}))))
|
||||||
|
|
||||||
|
(testing "based on bank account"
|
||||||
|
(is (= [{:id "2019-01-05 matching-desc 1"}] (rule-test {:bank-account-id bank-account-1})))
|
||||||
|
(is (= [{:id "2019-01-15 nonmatching-desc 2"}] (rule-test {:bank-account-id bank-account-2})))))))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user