From 7f6abf8a88f9f6b46b06493cfe37c8b06d1a8897 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Wed, 5 Jun 2019 22:49:51 -0700 Subject: [PATCH] makes sure rounding happens. --- src/clj/auto_ap/rule_matching.clj | 52 +++++++++++++++++++------------ test/clj/auto_ap/graphql.clj | 52 +++++++++++++++++++++++-------- 2 files changed, 71 insertions(+), 33 deletions(-) diff --git a/src/clj/auto_ap/rule_matching.clj b/src/clj/auto_ap/rule_matching.clj index b15bad22..17022aff 100644 --- a/src/clj/auto_ap/rule_matching.clj +++ b/src/clj/auto_ap/rule_matching.clj @@ -95,28 +95,40 @@ (filter #(rule-applies? transaction %)))) (defn apply-rule [transaction rule valid-locations] - (assoc transaction - :transaction/matched-rule (:db/id rule) - :transaction/approval-status (:transaction-rule/transaction-approval-status rule) - :transaction/accounts (mapcat - (fn [tra] - (if (= "Shared" (:transaction-rule-account/location tra)) - (map - (fn [location] - {:transaction-account/account (:db/id (:transaction-rule-account/account tra)) - :transaction-account/amount (Math/abs (* (/ 1.0 (count valid-locations)) - (:transaction-rule-account/percentage tra) - (:transaction/amount transaction))) - :transaction-account/location location}) + (with-precision 2 + (let [accounts (vec (mapcat + (fn [tra] + (if (= "Shared" (:transaction-rule-account/location tra)) + (map + (fn [location] + {:transaction-account/account (:db/id (:transaction-rule-account/account tra)) + :transaction-account/amount (Math/abs (* (/ 1.0 (count valid-locations)) + (:transaction-rule-account/percentage tra) + (:transaction/amount transaction))) + :transaction-account/location location}) - valid-locations) - [{:transaction-account/account (:db/id (:transaction-rule-account/account tra)) - :transaction-account/amount (Math/abs (* (:transaction-rule-account/percentage tra) - (:transaction/amount transaction))) - :transaction-account/location (:transaction-rule-account/location tra)}])) - (:transaction-rule/accounts rule)) - :transaction/vendor (:db/id (:transaction-rule/vendor rule)))) + valid-locations) + [{:transaction-account/account (:db/id (:transaction-rule-account/account tra)) + :transaction-account/amount (Math/abs (* (:transaction-rule-account/percentage tra) + (:transaction/amount transaction))) + :transaction-account/location (:transaction-rule-account/location tra)}])) + (:transaction-rule/accounts rule))) + accounts (mapv + (fn [a] + (update a :transaction-account/amount + #(with-precision 2 + (double (.setScale (bigdec %) 2 java.math.RoundingMode/HALF_UP))))) + accounts) + leftover (with-precision 2 (.round (bigdec (- (Math/abs (:transaction/amount transaction)) + (Math/abs (reduce + 0.0 (map #(:transaction-account/amount %) accounts))))) + *math-context*)) + accounts (update-in accounts [(dec (count accounts)) :transaction-account/amount] #(+ % (double leftover)))] + (assoc transaction + :transaction/matched-rule (:db/id rule) + :transaction/approval-status (:transaction-rule/transaction-approval-status rule) + :transaction/accounts accounts + :transaction/vendor (:db/id (:transaction-rule/vendor rule)))))) (defn rule-applying-fn [rules] (let [rules-by-priority (group-rules-by-priority rules)] diff --git a/test/clj/auto_ap/graphql.clj b/test/clj/auto_ap/graphql.clj index 68a3622a..1d610093 100644 --- a/test/clj/auto_ap/graphql.clj +++ b/test/clj/auto_ap/graphql.clj @@ -211,7 +211,7 @@ (deftest test-match-transaction-rule (testing "it should apply a rules" - (let [{:strs [transaction-id transaction-rule-id]} (-> @(d/transact (d/connect uri) + (let [{:strs [transaction-id transaction-rule-id uneven-transaction-rule-id]} (-> @(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" @@ -226,29 +226,55 @@ :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}]}]) + :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 "MatchTransactionRule"} - :venia/queries [{:query/data (sut/->graphql [:match-transaction-rule + :operation/name "MatchTransactionRules"} + :venia/queries [{:query/data (sut/->graphql [:match-transaction-rules {:transaction-rule-id transaction-rule-id - :transaction-id transaction-id} + :transaction-ids [transaction-id]} [[:matched-rule [:id :note]] [:accounts [:id]] ]])}]})) :data - :match-transaction-rule)] + :match-transaction-rules)] - (is (= "transaction rule note" (-> rule-test :matched-rule :note))) - (is (= 1 (-> rule-test :accounts count))) + (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 "MatchTransactionRule"} - :venia/queries [{:query/data (sut/->graphql [:match-transaction-rule + :operation/name "MatchTransactionRules"} + :venia/queries [{:query/data (sut/->graphql [:match-transaction-rules {:transaction-rule-id transaction-rule-id - :transaction-id transaction-id} + :transaction-ids [transaction-id]} [[:matched-rule [:id :note]] [:accounts [:id]] ]])}]})) :data - :match-transaction-rule)] - (is (= 1 (-> rule-test :accounts count)))))))) + :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))))))))