264 lines
14 KiB
Clojure
264 lines
14 KiB
Clojure
(ns auto-ap.datomic.transactions
|
|
(:require [datomic.api :as d]
|
|
[auto-ap.datomic :refer [uri merge-query apply-sort-3 apply-pagination add-sorter-fields conn]]
|
|
[auto-ap.graphql.utils :refer [limited-clients]]
|
|
[clj-time.coerce :as c]
|
|
[clj-time.coerce :as coerce]
|
|
[clojure.tools.logging :as log]
|
|
[clojure.string :as str]
|
|
[auto-ap.datomic.accounts :as d-accounts]))
|
|
|
|
(defn sort-fn [sort-by]
|
|
(cond
|
|
(= "client" sort-by)
|
|
#(-> % :transaction/client :client/name)
|
|
|
|
(= "account" sort-by)
|
|
#(vector (-> % :transaction/account :account/name) (-> % :db/id))
|
|
|
|
:else
|
|
(keyword "transaction" sort-by)))
|
|
|
|
(defn potential-duplicate-ids [db args]
|
|
(if (and (:potential-duplicates args)
|
|
(:bank-account-id args))
|
|
(->> (d/q '[:find ?tx ?amount ?date
|
|
:in $ ?ba
|
|
:where
|
|
[?tx :transaction/bank-account ?ba]
|
|
[?tx :transaction/amount ?amount]
|
|
[?tx :transaction/date ?date]
|
|
(not [?tx :transaction/approval-status :transaction-approval-status/suppressed])]
|
|
db
|
|
(:bank-account-id args))
|
|
(group-by (fn [[tx amount date]]
|
|
[amount date]))
|
|
(filter (fn [[g txes]]
|
|
(> (count txes) 1)))
|
|
|
|
(vals)
|
|
(mapcat identity)
|
|
(map first)
|
|
set)))
|
|
|
|
|
|
(defn raw-graphql-ids
|
|
([args] (raw-graphql-ids (d/db conn) args))
|
|
([db args]
|
|
(let [potential-duplicates (potential-duplicate-ids db args)
|
|
query (cond-> {:query {:find []
|
|
:in ['$ ]
|
|
:where []}
|
|
:args [db]}
|
|
|
|
(:potential-duplicates args)
|
|
(merge-query {:query {:in '[[?e ...]]}
|
|
:args [potential-duplicates]})
|
|
|
|
(:exact-match-id args)
|
|
(merge-query {:query {:in ['?e]
|
|
:where []}
|
|
:args [(:exact-match-id args)]})
|
|
|
|
(limited-clients (:id args))
|
|
(merge-query {:query {:in ['[?xx ...]]
|
|
:where ['[?e :transaction/client ?xx]]}
|
|
:args [(set (map :db/id (limited-clients (:id args))))]})
|
|
|
|
(:bank-account-id args)
|
|
(merge-query {:query {:in ['?bank-account-id]
|
|
:where ['[?e :transaction/bank-account ?bank-account-id]]}
|
|
:args [(:bank-account-id args)]})
|
|
|
|
(:import-batch-id args)
|
|
(merge-query {:query {:in ['?import-batch-id]
|
|
:where ['[?import-batch-id :import-batch/entry ?e]]}
|
|
:args [(:import-batch-id args)]})
|
|
|
|
(:account-id args)
|
|
(merge-query {:query {:in ['?account-id]
|
|
:where ['[?e :transaction/accounts ?accounts]
|
|
'[?accounts :transaction-account/account ?account-id]]}
|
|
:args [(:account-id args)]})
|
|
|
|
(:client-id args)
|
|
(merge-query {:query {:in ['?client-id]
|
|
:where ['[?e :transaction/client ?client-id]]}
|
|
:args [(:client-id args)]})
|
|
|
|
(:vendor-id args)
|
|
(merge-query {:query {:in ['?vendor-id]
|
|
:where ['[?e :transaction/vendor ?vendor-id]]}
|
|
:args [(:vendor-id args)]})
|
|
|
|
|
|
(:amount-gte args)
|
|
(merge-query {:query {:in ['?amount-gte]
|
|
:where ['[?e :transaction/amount ?a]
|
|
'[(>= ?a ?amount-gte)]]}
|
|
:args [(:amount-gte args)]})
|
|
|
|
(:amount-lte args)
|
|
(merge-query {:query {:in ['?amount-lte]
|
|
:where ['[?e :transaction/amount ?a]
|
|
'[(<= ?a ?amount-lte)]]}
|
|
:args [(:amount-lte args)]})
|
|
|
|
(:start (:date-range args))
|
|
(merge-query {:query {:in ['?start-date]
|
|
:where ['[?e :transaction/date ?date]
|
|
'[(>= ?date ?start-date)]]}
|
|
:args [(coerce/to-date (:start (:date-range args)))]})
|
|
|
|
(:end (:date-range args))
|
|
(merge-query {:query {:in ['?end-date]
|
|
:where ['[?e :transaction/date ?date]
|
|
'[(<= ?date ?end-date)]]}
|
|
:args [(coerce/to-date (:end (:date-range args)))]})
|
|
|
|
(:approval-status args)
|
|
(merge-query {:query {:in ['?approval-status]
|
|
:where ['[?e :transaction/approval-status ?approval-status]]}
|
|
:args [(:approval-status args)]})
|
|
|
|
(:client-code args)
|
|
(merge-query {:query {:in ['?client-code]
|
|
:where ['[?e :transaction/client ?client-id]
|
|
'[?client-id :client/code ?client-code]]}
|
|
:args [(:client-code args)]})
|
|
|
|
(:original-id args)
|
|
(merge-query {:query {:in ['?original-id]
|
|
:where ['[?e :transaction/client ?c]
|
|
'[?c :client/original-id ?original-id]]}
|
|
:args [(:original-id args)]})
|
|
|
|
(seq (:location args))
|
|
(merge-query {:query {:in ['?location]
|
|
:where ['[?e :transaction/accounts ?tas]
|
|
'[?tas :transaction-account/location ?location]]}
|
|
:args [(:location args)]})
|
|
|
|
(:unresolved args)
|
|
(merge-query {:query {:where ['[?e :transaction/date]
|
|
'(or-join [?e]
|
|
(not [?e :transaction/accounts])
|
|
(and [?e :transaction/accounts ?tas]
|
|
(not [?tas :transaction-account/account])))]}})
|
|
|
|
(:description args)
|
|
(merge-query {:query {:in ['?description]
|
|
:where ['[?e :transaction/description-original ?do]
|
|
'[(clojure.string/lower-case ?do) ?do2]
|
|
'[(.contains ?do2 ?description)]]}
|
|
:args [(clojure.string/lower-case (:description args))]})
|
|
|
|
(:sort args) (add-sorter-fields {"client" ['[?e :transaction/client ?c]
|
|
'[?c :client/name ?sort-client]]
|
|
"account" ['[?e :transaction/date]
|
|
'(or-join [?e ?sort-account]
|
|
(and [?e :transaction/bank-account ?c]
|
|
[?c :bank-account/name ?sort-account])
|
|
(and
|
|
(not [?e :transaction/bank-account])
|
|
[(ground "") ?sort-account]))]
|
|
"description-original" ['[?e :transaction/description-original ?sort-description-original]]
|
|
"date" ['[?e :transaction/date ?sort-date]]
|
|
"vendor" ['(or-join [?e ?sort-vendor]
|
|
(and [(missing? $ ?e :transaction/vendor)]
|
|
[?e :transaction/description-original ?sort-vendor])
|
|
(and [?e :transaction/vendor ?v]
|
|
[?v :vendor/name ?sort-vendor]))]
|
|
"amount" ['[?e :transaction/amount ?sort-amount]]
|
|
"status" ['[?e :transaction/status ?sort-status]]}
|
|
args)
|
|
true
|
|
(merge-query {:query {:find ['?sort-default '?e]
|
|
:where ['[?e :transaction/id]
|
|
'[?e :transaction/date ?sort-default]
|
|
'(not [?e :transaction/approval-status :transaction-approval-status/suppressed])]}}))]
|
|
(log/info "query is" query)
|
|
(cond->> query
|
|
true (d/query)
|
|
true (apply-sort-3 (assoc args :default-asc? false))
|
|
true (apply-pagination args)))))
|
|
|
|
(defn graphql-results [ids db args]
|
|
(let [results (->> (d/pull-many db '[* {:transaction/client [:client/name :db/id :client/code]
|
|
:transaction/approval-status [:db/ident :db/id]
|
|
:transaction/bank-account [:bank-account/name :bank-account/code :bank-account/yodlee-account-id :db/id :bank-account/locations :bank-account/current-balance]
|
|
:transaction/forecast-match [:db/id :forecasted-transaction/identifier]
|
|
:transaction/vendor [:db/id :vendor/name]
|
|
:transaction/matched-rule [:db/id :transaction-rule/note]
|
|
:transaction/payment [:db/id :payment/date]
|
|
:transaction/expected-deposit [:db/id :expected-deposit/date]
|
|
:transaction/accounts [:transaction-account/amount
|
|
:db/id
|
|
:transaction-account/location
|
|
{:transaction-account/account [:account/name :db/id
|
|
:account/location
|
|
{:account/client-overrides [:account-client-override/name
|
|
{:account-client-override/client [:db/id]}]}]}]
|
|
:transaction/yodlee-merchant [:db/id :yodlee-merchant/yodlee-id :yodlee-merchant/name]}]
|
|
ids)
|
|
(map #(update % :transaction/date c/from-date))
|
|
(map #(update % :transaction/post-date c/from-date))
|
|
(map #(update % :transaction/accounts
|
|
(fn [tas]
|
|
(map
|
|
(fn [ta]
|
|
(update ta :transaction-account/account d-accounts/clientize (:db/id (:transaction/client %))))
|
|
tas))))
|
|
(map (fn [transaction]
|
|
(cond-> transaction
|
|
(:transaction/payment transaction) (update-in [:transaction/payment :payment/date] c/from-date)
|
|
(:transaction/expected-deposit transaction) (update-in [:transaction/expected-deposit :expected-deposit/date] c/from-date))
|
|
))
|
|
(map #(dissoc % :transaction/id))
|
|
(group-by :db/id))]
|
|
|
|
(->> ids
|
|
(map results)
|
|
(map first))))
|
|
|
|
(defn get-graphql [args]
|
|
(let [db (d/db (d/connect uri))
|
|
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
|
|
|
[(->> (graphql-results ids-to-retrieve db args))
|
|
matching-count]))
|
|
|
|
(defn filter-ids [ids]
|
|
(if ids
|
|
(->> {:query {:find ['?e]
|
|
:in ['$ '[?e ...]]
|
|
:where ['[?e :transaction/date]]}
|
|
:args [(d/db conn) ids]}
|
|
(d/query)
|
|
(map first)
|
|
vec)
|
|
[]))
|
|
|
|
(defn get-by-id [id]
|
|
(->
|
|
(d/pull (d/db (d/connect uri))
|
|
'[* {:transaction/client [:client/name :db/id :client/code :client/locations]
|
|
:transaction/approval-status [:db/ident :db/id]
|
|
:transaction/bank-account [:bank-account/name :bank-account/code :bank-account/yodlee-account-id :db/id :bank-account/locations :bank-account/current-balance]
|
|
:transaction/vendor [:db/id :vendor/name]
|
|
:transaction/matched-rule [:db/id :transaction-rule/note]
|
|
:transaction/forecast-match [:db/id :forecasted-transaction/identifier]
|
|
:transaction/accounts [:transaction-account/amount
|
|
:db/id
|
|
:transaction-account/location
|
|
{ :transaction-account/account [:account/name :db/id
|
|
:account/location
|
|
{:account/client-overrides [:account-client-override/name
|
|
{:account-client-override/client [:db/id]}]}]}]
|
|
:transaction/yodlee-merchant [:db/id :yodlee-merchant/yodlee-id :yodlee-merchant/name]}]
|
|
id)
|
|
(update :transaction/date c/from-date)
|
|
(update :transaction/post-date c/from-date)
|
|
(dissoc :transaction/id)))
|
|
|