Makes integreat run on datomic cloud
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
(ns auto-ap.graphql.accounts
|
||||
(:require
|
||||
[auto-ap.datomic :refer [audit-transact conn remove-nils]]
|
||||
[auto-ap.datomic :refer [audit-transact conn upsert-entity]]
|
||||
[auto-ap.datomic.accounts :as d-accounts]
|
||||
[auto-ap.graphql.utils
|
||||
:refer [->graphql
|
||||
@@ -11,7 +11,12 @@
|
||||
enum->keyword
|
||||
is-admin?
|
||||
result->page]]
|
||||
[datomic.api :as d]))
|
||||
[auto-ap.search :as search]
|
||||
[datomic.client.api :as dc]
|
||||
[clojure.string :as str])
|
||||
(:import
|
||||
(org.apache.lucene.search TermInSetQuery)
|
||||
(org.apache.lucene.util BytesRef)))
|
||||
|
||||
(defn get-graphql [context args _]
|
||||
(assert-admin (:id context))
|
||||
@@ -33,48 +38,38 @@
|
||||
(defn upsert-account [context args _]
|
||||
(let [{{:keys [id client-overrides numeric-code location applicability account-set name invoice-allowance vendor-allowance type]} :account} (<-graphql args)]
|
||||
(when-not id
|
||||
(when (seq (d/query {:query {:find ['?e]
|
||||
:in '[$ ?account-set ?numeric-code]
|
||||
:where ['[?e :account/account-set ?account-set]
|
||||
'[?e :account/numeric-code ?numeric-code]]}
|
||||
:args [(d/db conn) account-set numeric-code]}))
|
||||
(when (seq (dc/q {:query {:find ['?e]
|
||||
:in '[$ ?account-set ?numeric-code]
|
||||
:where ['[?e :account/account-set ?account-set]
|
||||
'[?e :account/numeric-code ?numeric-code]]}
|
||||
:args [(dc/db conn) account-set numeric-code]}))
|
||||
|
||||
(throw (ex-info (str "Account set " account-set " already has an account for code " numeric-code)
|
||||
{} ))))
|
||||
|
||||
(let [original (when id
|
||||
(d/entity (d/db conn) id))
|
||||
result (audit-transact (cond->
|
||||
[(remove-nils
|
||||
{:db/id (or id "new-account")
|
||||
:account/name name
|
||||
:account/search-terms name
|
||||
:account/type (keyword "account-type" (clojure.core/name type))
|
||||
:account/applicability (or (enum->keyword applicability "account-applicability")
|
||||
:account-applicability/global)
|
||||
|
||||
:account/invoice-allowance (some-> invoice-allowance (enum->keyword "allowance"))
|
||||
:account/vendor-allowance (some-> vendor-allowance (enum->keyword "allowance"))
|
||||
:account/default-allowance :allowance/allowed
|
||||
:account/account-set account-set
|
||||
:account/location location
|
||||
:account/numeric-code (when-not id
|
||||
numeric-code)
|
||||
:account/code (when-not id
|
||||
(str numeric-code))})
|
||||
[:reset (or id "new-account") :account/client-overrides
|
||||
(mapv
|
||||
(fn [client-override]
|
||||
(remove-nils
|
||||
{:db/id (:id client-override)
|
||||
:account-client-override/client (:client-id client-override)
|
||||
:account-client-override/name (:name client-override)
|
||||
:account-client-override/search-terms (:name client-override)}))
|
||||
client-overrides)]]
|
||||
(and (not location) (:account/location original)) (conj [:db/retract (or id "new-account") :account/location (:account/location original)]))
|
||||
(let [result (audit-transact [`(upsert-entity
|
||||
~{:db/id (or id "new-account")
|
||||
:account/name name
|
||||
:account/search-terms name
|
||||
:account/type (keyword "account-type" (clojure.core/name type))
|
||||
:account/applicability (or (enum->keyword applicability "account-applicability")
|
||||
:account-applicability/global)
|
||||
:account/invoice-allowance (some-> invoice-allowance (enum->keyword "allowance"))
|
||||
:account/vendor-allowance (some-> vendor-allowance (enum->keyword "allowance"))
|
||||
:account/default-allowance :allowance/allowed
|
||||
:account/account-set account-set
|
||||
:account/location location
|
||||
:account/numeric-code numeric-code
|
||||
:account/code (str numeric-code)
|
||||
:account/client-overrides (mapv
|
||||
(fn [client-override]
|
||||
{:db/id (:id client-override)
|
||||
:account-client-override/client (:client-id client-override)
|
||||
:account-client-override/name (:name client-override)
|
||||
:account-client-override/search-terms (:name client-override)})
|
||||
client-overrides)})]
|
||||
(:id context))]
|
||||
(->graphql
|
||||
(d-accounts/get-by-id (or id (get-in result [:tempids "new-account"])))))))
|
||||
(d-accounts/get-by-id (or id (get-in result [:tempids "new-account"])))))))
|
||||
|
||||
(def search-pattern [:db/id
|
||||
:account/numeric-code
|
||||
@@ -86,6 +81,7 @@
|
||||
(when client
|
||||
(assert-can-see-client (:id context) client))
|
||||
(let [query (cleanse-query query)
|
||||
_ (println query)
|
||||
num (some-> (re-find #"([0-9]+)" query)
|
||||
second
|
||||
(not-empty )
|
||||
@@ -160,3 +156,35 @@
|
||||
(sequence xform)))
|
||||
[])))
|
||||
|
||||
(defn rebuild-search-index []
|
||||
(search/full-index-query
|
||||
(for [result (map first (dc/qseq '[:find (pull ?aco [:account-client-override/search-terms :account-client-override/client :db/id {:account/_client-overrides [:account/numeric-code :account/location :db/id]}])
|
||||
:in $
|
||||
:where [?aco :account-client-override/client ]
|
||||
[?aco :account-client-override/search-terms ]]
|
||||
(dc/db conn)))
|
||||
:when (:account/numeric-code (:account/_client-overrides result))]
|
||||
{:id (:db/id (:account/_client-overrides result))
|
||||
:text (:account-client-override/search-terms result)
|
||||
:client (str (:db/id (:account-client-override/client result)))
|
||||
:numeric-code (:account/numeric-code (:account/_client-overrides result))
|
||||
:location (:account/location (:account/_client-overrides result))})
|
||||
"account-client-override")
|
||||
|
||||
(search/full-index-query
|
||||
(for [result (map first (dc/qseq '[:find (pull ?a [:account/numeric-code
|
||||
:account/search-terms
|
||||
{:account/applicability [:db/ident]}
|
||||
:db/id
|
||||
:account/location])
|
||||
:in $
|
||||
:where [?a :account/search-terms ]]
|
||||
(dc/db conn)))
|
||||
:when (:account/search-terms result)
|
||||
]
|
||||
{:id (:db/id result)
|
||||
:text (:account/search-terms result)
|
||||
:numeric-code (:account/numeric-code result)
|
||||
:location (:account/location result)
|
||||
:applicability (name (:db/ident (:account/applicability result)))})
|
||||
"account"))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns auto-ap.graphql.checks
|
||||
(:require
|
||||
[amazonica.aws.s3 :as s3]
|
||||
[auto-ap.datomic :refer [conn remove-nils]]
|
||||
[auto-ap.datomic :refer [conn remove-nils plus]]
|
||||
[auto-ap.datomic.accounts :as a]
|
||||
[auto-ap.datomic.bank-accounts :as d-bank-accounts]
|
||||
[auto-ap.datomic.checks :as d-checks]
|
||||
@@ -34,9 +34,9 @@
|
||||
[com.brunobonacci.mulog :as mu]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[config.core :refer [env]]
|
||||
[datomic.api :as d]
|
||||
[digest]
|
||||
[clj-time.coerce :as coerce])
|
||||
[clj-time.coerce :as coerce]
|
||||
[datomic.client.api :as dc]
|
||||
[digest])
|
||||
(:import
|
||||
(java.io ByteArrayOutputStream)
|
||||
(java.text DecimalFormat)
|
||||
@@ -230,7 +230,7 @@
|
||||
[{:invoice-payment/payment (-> invoice :invoice/vendor :db/id str)
|
||||
:invoice-payment/amount invoice-amount
|
||||
:invoice-payment/invoice (:db/id invoice)}
|
||||
[:pay (:db/id invoice) invoice-amount]])
|
||||
`(d-checks/pay ~(:db/id invoice) ~invoice-amount)])
|
||||
(reduce into [])))
|
||||
|
||||
(defn base-payment [invoices vendor client bank-account _ _ invoice-amounts]
|
||||
@@ -391,7 +391,6 @@
|
||||
(let [type (keyword "payment-type" (name type))
|
||||
invoices (d-invoices/get-multi (map :invoice-id invoice-payments))
|
||||
client (d-clients/get-by-id client-id)
|
||||
|
||||
invoice-amounts (by :invoice-id :amount invoice-payments)
|
||||
invoices-grouped-by-vendor (group-by (comp :db/id :invoice/vendor) invoices)
|
||||
vendors (->> (d/pull-many (d/db conn) d-vendors/default-read (keys invoices-grouped-by-vendor))
|
||||
@@ -409,14 +408,16 @@
|
||||
(reduce into [])
|
||||
doall))
|
||||
checks (if (= type :payment-type/check)
|
||||
(conj checks [:inc (:db/id bank-account) :bank-account/check-number (count invoices-grouped-by-vendor)])
|
||||
(conj checks `(plus ~(:db/id bank-account) ~:bank-account/check-number ~(count invoices-grouped-by-vendor)))
|
||||
checks)]
|
||||
(when (= type :payment-type/check)
|
||||
(mu/trace ::making-pdfs [:checks checks]
|
||||
(make-pdfs (filter #(and (= :payment-type/check (:payment/type %))
|
||||
(> (:payment/amount %) 0.0))
|
||||
checks))))
|
||||
(transact-with-ledger checks id)
|
||||
(transact-with-ledger (map #(if (map? %)
|
||||
(dissoc % :payment/pdf-data)
|
||||
%) checks ) id)
|
||||
|
||||
|
||||
{:invoices (d-invoices/get-multi (map :invoice-id invoice-payments))
|
||||
@@ -565,7 +566,6 @@
|
||||
(log/info "Voiding " (count all-ids) args)
|
||||
|
||||
(void-payments-internal all-ids (:id context))
|
||||
|
||||
{:message (str "Succesfully voided " (count all-ids))}))
|
||||
|
||||
(defn get-all-payments [context args _]
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
(ns auto-ap.graphql.clients
|
||||
(:require
|
||||
[amazonica.aws.s3 :as s3]
|
||||
[auto-ap.datomic :refer [audit-transact conn remove-nils]]
|
||||
[auto-ap.datomic :refer [audit-transact conn upsert-entity random-tempid]]
|
||||
[auto-ap.datomic.clients :as d-clients]
|
||||
[auto-ap.square.core :as square]
|
||||
[auto-ap.graphql.utils
|
||||
:refer [->graphql assert-admin can-see-client? is-admin?]]
|
||||
[auto-ap.routes.queries :as q]
|
||||
[auto-ap.square.core :as square]
|
||||
[clj-time.coerce :as coerce]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
[clojure.tools.logging :as log]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[datomic.api :as d]
|
||||
[datomic.client.api :as dc]
|
||||
[unilog.context :as lc]
|
||||
[auto-ap.graphql.utils :refer [attach-tracing-resolvers]]
|
||||
[com.brunobonacci.mulog :as mu])
|
||||
@@ -22,10 +22,10 @@
|
||||
(org.apache.commons.codec.binary Base64)))
|
||||
|
||||
(defn assert-client-code-is-unique [code]
|
||||
(when (seq (d/query {:query {:find '[?id]
|
||||
:in ['$ '?code]
|
||||
:where ['[?id :client/code ?code]]}
|
||||
:args [(d/db conn) code]}))
|
||||
(when (seq (dc/q {:query {:find '[?id]
|
||||
:in ['$ '?code]
|
||||
:where ['[?id :client/code ?code]]}
|
||||
:args [(dc/db conn) code]}))
|
||||
(throw (ex-info "Client is not unique" {:validation-error (str "Client code '" code "' is not unique.")}))))
|
||||
|
||||
(defn upload-signature-data [signature-data]
|
||||
@@ -44,9 +44,9 @@
|
||||
(str "https://integreat-signature-images.s3.amazonaws.com/" signature-id ".jpg")))))
|
||||
|
||||
(defn assert-no-shared-transaction-sources [client-code txes]
|
||||
(let [new-db (:db-after (d/with (d/db conn)
|
||||
txes))]
|
||||
(when (seq (->> (d/q '[:find ?src (count ?ba)
|
||||
(let [new-db (:db-after (dc/with (dc/with-db conn)
|
||||
{:tx-data txes}))]
|
||||
(when (seq (->> (dc/q '[:find ?src (count ?ba)
|
||||
:in $ ?c
|
||||
:where [?c :client/bank-accounts ?ba]
|
||||
(or
|
||||
@@ -66,116 +66,84 @@
|
||||
(let [client (when (:id edit_client) (d-clients/get-by-id (:id edit_client)))
|
||||
id (or (:db/id client) "new-client")
|
||||
signature-file (upload-signature-data (:signature_data edit_client))
|
||||
_ (when client
|
||||
(audit-transact (-> []
|
||||
(into (mapv (fn [lm] [:db/retractEntity (:db/id lm)]) (:client/location-matches client)))
|
||||
(into (mapv (fn [m] [:db/retract (:db/id client) :client/matches m]) (:client/matches client)))
|
||||
(into (mapv (fn [m] [:db/retract (:db/id client) :client/feature-flags m]) (:client/feature-flags client))))
|
||||
(:id context)))
|
||||
reverts (-> []
|
||||
(into (->> (:bank_accounts edit_client)
|
||||
(filter #(nil? (:yodlee_account_id %)))
|
||||
(filter #(:bank-account/yodlee-account-id (d/entity (d/db conn) (:id %))))
|
||||
(map (fn [ba] [:db/retract (:id ba) :bank-account/yodlee-account-id (:bank-account/yodlee-account-id (d/entity (d/db conn) (:id ba)))]))))
|
||||
(into (->> (:bank_accounts edit_client)
|
||||
(filter #(nil? (:yodlee_account %)))
|
||||
(filter #(:bank-account/yodlee-account (d/entity (d/db conn) (:id %))))
|
||||
(map (fn [ba] [:db/retract (:id ba) :bank-account/yodlee-account (:db/id (:bank-account/yodlee-account (d/entity (d/db conn) (:id ba))))]))))
|
||||
(into (->> (:bank_accounts edit_client)
|
||||
(filter #(nil? (:intuit_bank_account %)))
|
||||
(filter #(:bank-account/intuit-bank-account (d/entity (d/db conn) (:id %))))
|
||||
(map (fn [ba] [:db/retract (:id ba) :bank-account/intuit-bank-account (:db/id (:bank-account/intuit-bank-account (d/entity (d/db conn) (:id ba))))]))))
|
||||
(into (->> (:bank_accounts edit_client)
|
||||
(filter #(nil? (:plaid_account %)))
|
||||
(filter #(:bank-account/plaid-account (d/entity (d/db conn) (:id %))))
|
||||
(map (fn [ba] [:db/retract (:id ba) :bank-account/plaid-account (:db/id (:bank-account/plaid-account (d/entity (d/db conn) (:id ba))))])))))
|
||||
|
||||
|
||||
client-code (if (str/blank? (:client/code client))
|
||||
(:code edit_client)
|
||||
(:client/code client))
|
||||
transactions (into [(remove-nils {:db/id id
|
||||
:client/code client-code
|
||||
:client/name (:name edit_client)
|
||||
:client/matches (:matches edit_client)
|
||||
:client/signature-file signature-file
|
||||
:client/email (:email edit_client)
|
||||
:client/locked-until (some-> (:locked_until edit_client) (coerce/to-date))
|
||||
:client/locations (filter identity (:locations edit_client))
|
||||
:client/week-a-debits (:week_a_debits edit_client)
|
||||
:client/week-a-credits (:week_a_credits edit_client)
|
||||
:client/week-b-debits (:week_b_debits edit_client)
|
||||
:client/square-auth-token (:square_auth_token edit_client)
|
||||
:client/square-locations (map
|
||||
(fn [sl]
|
||||
(remove-nils
|
||||
{:db/id (:id sl)
|
||||
:square-location/client-location (:client_location sl)}))
|
||||
(:square_locations edit_client))
|
||||
updated-entity {:db/id id
|
||||
:client/code client-code
|
||||
:client/name (:name edit_client)
|
||||
:client/matches (:matches edit_client)
|
||||
:client/signature-file signature-file
|
||||
:client/email (:email edit_client)
|
||||
:client/locked-until (some-> (:locked_until edit_client) (coerce/to-date))
|
||||
:client/locations (filter identity (:locations edit_client))
|
||||
:client/week-a-debits (:week_a_debits edit_client)
|
||||
:client/week-a-credits (:week_a_credits edit_client)
|
||||
:client/week-b-debits (:week_b_debits edit_client)
|
||||
:client/square-auth-token (:square_auth_token edit_client)
|
||||
:client/square-locations (map
|
||||
(fn [sl]
|
||||
{:db/id (or (:id sl) (random-tempid))
|
||||
:square-location/client-location (:client_location sl)})
|
||||
(:square_locations edit_client))
|
||||
|
||||
:client/ezcater-locations (map
|
||||
(fn [el]
|
||||
(remove-nils
|
||||
{:db/id (:id el)
|
||||
:ezcater-location/location (:location el)
|
||||
:ezcater-location/caterer (:caterer el)}))
|
||||
(:ezcater_locations edit_client))
|
||||
:client/week-b-credits (:week_b_credits edit_client)
|
||||
:client/location-matches (->> (:location_matches edit_client)
|
||||
(filter (fn [lm] (and (:location lm) (:match lm))))
|
||||
(map (fn [lm] {:location-match/location (:location lm)
|
||||
:location-match/matches [(:match lm)]})))
|
||||
:client/address (remove-nils {
|
||||
:address/street1 (:street1 (:address edit_client))
|
||||
:address/street2 (:street2 (:address edit_client))
|
||||
:address/city (:city (:address edit_client))
|
||||
:address/state (:state (:address edit_client))
|
||||
:address/zip (:zip (:address edit_client))})
|
||||
:client/feature-flags (:feature_flags edit_client)
|
||||
:client/bank-accounts (map #(remove-nils
|
||||
(cond-> {:db/id (:id %)
|
||||
:bank-account/code (:code %)
|
||||
:bank-account/bank-name (:bank_name %)
|
||||
:bank-account/bank-code (:bank_code %)
|
||||
:bank-account/start-date (-> (:start_date %) (coerce/to-date))
|
||||
:bank-account/routing (:routing %)
|
||||
:bank-account/include-in-reports (:include_in_reports %)
|
||||
:client/emails (map (fn [e]
|
||||
{:db/id (or (:id e)
|
||||
(random-tempid))
|
||||
:email-contact/email (:email e)
|
||||
:email-contact/description (:description e)})
|
||||
(:emails edit_client))
|
||||
|
||||
:bank-account/name (:name %)
|
||||
:bank-account/visible (:visible %)
|
||||
:bank-account/number (:number %)
|
||||
:bank-account/check-number (:check_number %)
|
||||
:bank-account/numeric-code (:numeric_code %)
|
||||
:bank-account/sort-order (:sort_order %)
|
||||
:bank-account/locations (:locations %)
|
||||
:bank-account/use-date-instead-of-post-date? (boolean (:use_date_instead_of_post_date %))
|
||||
:client/feature-flags (:feature_flags edit_client)
|
||||
:client/ezcater-locations (map
|
||||
(fn [el]
|
||||
{:db/id (or (:id el) (random-tempid))
|
||||
:ezcater-location/location (:location el)
|
||||
:ezcater-location/caterer (:caterer el)})
|
||||
(:ezcater_locations edit_client))
|
||||
:client/week-b-credits (:week_b_credits edit_client)
|
||||
:client/location-matches (->> (:location_matches edit_client)
|
||||
(filter (fn [lm] (and (:location lm) (:match lm))))
|
||||
(map (fn [lm] {:db/id (or (:id lm ) (random-tempid))
|
||||
:location-match/location (:location lm)
|
||||
:location-match/matches [(:match lm)]})))
|
||||
:client/address {:db/id (or (:id (:address edit_client)) (random-tempid))
|
||||
:address/street1 (:street1 (:address edit_client))
|
||||
:address/street2 (:street2 (:address edit_client))
|
||||
:address/city (:city (:address edit_client))
|
||||
:address/state (:state (:address edit_client))
|
||||
:address/zip (:zip (:address edit_client))}
|
||||
:client/bank-accounts (map (fn [ba]
|
||||
{:db/id (:id ba)
|
||||
:bank-account/code (:code ba)
|
||||
:bank-account/bank-name (:bank_name ba)
|
||||
:bank-account/bank-code (:bank_code ba)
|
||||
:bank-account/start-date (-> (:start_date ba) (coerce/to-date))
|
||||
:bank-account/routing (:routing ba)
|
||||
:bank-account/include-in-reports (:include_in_reports ba)
|
||||
|
||||
:bank-account/yodlee-account-id (:yodlee_account_id %)
|
||||
:bank-account/type (keyword "bank-account-type" (name (:type %)))}
|
||||
(:yodlee_account %) (assoc :bank-account/yodlee-account [:yodlee-account/id (:yodlee_account %)])
|
||||
(:plaid_account %) (assoc :bank-account/plaid-account (:plaid_account %))
|
||||
(:intuit_bank_account %) (assoc :bank-account/intuit-bank-account (:intuit_bank_account %))))
|
||||
(:bank_accounts edit_client))
|
||||
:bank-account/name (:name ba)
|
||||
:bank-account/visible (:visible ba)
|
||||
:bank-account/number (:number ba)
|
||||
:bank-account/check-number (:check_number ba)
|
||||
:bank-account/numeric-code (:numeric_code ba)
|
||||
:bank-account/sort-order (:sort_order ba)
|
||||
:bank-account/locations (:locations ba)
|
||||
:bank-account/use-date-instead-of-post-date? (boolean (:use_date_instead_of_post_date ba))
|
||||
|
||||
})
|
||||
|
||||
[:reset id :client/emails (map #(remove-nils
|
||||
{:db/id (or (:id %)
|
||||
(str (UUID/randomUUID)))
|
||||
:email-contact/email (:email %)
|
||||
:email-contact/description (:description %)})
|
||||
(:emails edit_client))]
|
||||
[:reset id :client/forecasted-transactions (map #(remove-nils
|
||||
{:db/id (:id %)
|
||||
:forecasted-transaction/day-of-month (:day_of_month %)
|
||||
:forecasted-transaction/identifier (:identifier %)
|
||||
:forecasted-transaction/amount (:amount %)}
|
||||
)
|
||||
(:forecasted_transactions edit_client))]]
|
||||
reverts)
|
||||
_ (assert-no-shared-transaction-sources client-code transactions)
|
||||
_ (log/info "upserting client" transactions)
|
||||
result (audit-transact transactions (:id context))]
|
||||
:bank-account/yodlee-account-id (:yodlee_account_id ba)
|
||||
:bank-account/type (keyword "bank-account-type" (name (:type ba)))
|
||||
:bank-account/yodlee-account (when (:yodlee_account ba)
|
||||
[:yodlee-account/id (:yodlee_account ba)])
|
||||
:bank-account/plaid-account (:plaid_account ba)
|
||||
:bank-account/intuit-bank-account (:intuit_bank_account ba)})
|
||||
(:bank_accounts edit_client))
|
||||
|
||||
}
|
||||
_ (assert-no-shared-transaction-sources client-code [`(upsert-entity ~updated-entity)])
|
||||
_ (log/info "upserting client" updated-entity)
|
||||
|
||||
result (audit-transact [`(upsert-entity ~updated-entity)] (:id context))]
|
||||
(when (:square_auth_token edit_client)
|
||||
(square/upsert-locations (-> result :tempids (get id) (or id) d-clients/get-by-id)))
|
||||
(-> (-> result :tempids (get id) (or id) d-clients/get-by-id)
|
||||
@@ -194,13 +162,13 @@
|
||||
->graphql)))
|
||||
|
||||
(defn refresh-bank-account-current-balance [bank-account-id]
|
||||
(let [all-transactions (d/query
|
||||
(let [all-transactions (dc/q
|
||||
{:query {:find ['?e '?debit '?credit]
|
||||
:in ['$ '?bank-account-id]
|
||||
:where '[[?e :journal-entry-line/account ?bank-account-id]
|
||||
[(get-else $ ?e :journal-entry-line/debit 0.0) ?debit]
|
||||
[(get-else $ ?e :journal-entry-line/credit 0.0) ?credit]]}
|
||||
:args [(d/db conn) bank-account-id]})
|
||||
:args [(dc/db conn) bank-account-id]})
|
||||
debits (->> all-transactions
|
||||
(map (fn [[_ debit _]]
|
||||
debit))
|
||||
@@ -209,46 +177,45 @@
|
||||
(map (fn [[_ _ credit]]
|
||||
credit))
|
||||
(reduce + 0.0))
|
||||
current-balance (if (= :bank-account-type/check (:bank-account/type (d/entity (d/db conn) bank-account-id)))
|
||||
current-balance (if (= :bank-account-type/check (:db/ident (:bank-account/type (dc/pull (dc/db conn) [:bank-account/type] bank-account-id))))
|
||||
(- debits credits)
|
||||
(- credits debits))]
|
||||
@(d/transact conn [{:db/id bank-account-id
|
||||
:bank-account/current-balance current-balance}])))
|
||||
(dc/transact conn {:tx-data [{:db/id bank-account-id
|
||||
:bank-account/current-balance current-balance}]})))
|
||||
|
||||
(defn bank-accounts-needing-refresh []
|
||||
(let [last-refreshed (->> (d/query
|
||||
{:query {:find ['?ba '?tx]
|
||||
(let [last-refreshed (->> (dc/q {:query {:find ['?ba '?tx]
|
||||
:in ['$ ]
|
||||
:where ['[?ba :bank-account/current-balance _ ?tx true]]}
|
||||
:args [(d/history (d/db conn))]})
|
||||
:args [(dc/history (dc/db conn))]})
|
||||
(group-by first)
|
||||
(map (fn [[ba balance-txes]]
|
||||
[ba (->> balance-txes
|
||||
(map second)
|
||||
(sort-by #(- %))
|
||||
first)])))
|
||||
has-newer-transaction (->> (d/query
|
||||
has-newer-transaction (->> (dc/q
|
||||
{:query {:find ['?ba]
|
||||
:in '[$ [[?ba ?last-refreshed] ...] ]
|
||||
:where ['[_ :journal-entry-line/account ?ba ?tx]
|
||||
'[(>= ?tx ?last-refreshed)]]}
|
||||
:args [(d/history (d/db conn))
|
||||
:args [(dc/history (dc/db conn))
|
||||
last-refreshed]})
|
||||
(map first)
|
||||
(set))
|
||||
|
||||
no-current-balance (->> (d/query {:query {:find ['?ba]
|
||||
no-current-balance (->> (dc/q {:query {:find ['?ba]
|
||||
:in '[$]
|
||||
:where ['[?ba :bank-account/code]
|
||||
'(not [?ba :bank-account/current-balance])
|
||||
]}
|
||||
:args [(d/db conn)]})
|
||||
:args [(dc/db conn)]})
|
||||
(map first))]
|
||||
(into has-newer-transaction no-current-balance)))
|
||||
|
||||
(defn build-current-balance [bank-accounts]
|
||||
(doseq [bank-account bank-accounts]
|
||||
(log/info "Refreshing bank account" (-> (d/db conn) (d/entity bank-account) :bank-account/code))
|
||||
(log/info "Refreshing bank account" (-> (dc/db conn) (dc/pull [:bank-account/code] bank-account)))
|
||||
(try
|
||||
(refresh-bank-account-current-balance bank-account)
|
||||
(catch Exception e
|
||||
@@ -257,10 +224,10 @@
|
||||
#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
|
||||
(defn refresh-all-current-balance []
|
||||
(lc/with-context {:source "current-balance-cache"}
|
||||
(build-current-balance (->> (d/query {:query {:find ['?ba]
|
||||
:in '[$]
|
||||
:where ['[?ba :bank-account/code]]}
|
||||
:args [(d/db conn)]})
|
||||
(build-current-balance (->> (dc/q {:query {:find ['?ba]
|
||||
:in '[$]
|
||||
:where ['[?ba :bank-account/code]]}
|
||||
:args [(dc/db conn)]})
|
||||
(map first)))))
|
||||
|
||||
(defn refresh-current-balance []
|
||||
@@ -410,8 +377,8 @@
|
||||
|
||||
(defn setup-sales-queries [context args _]
|
||||
(assert-admin (:id context))
|
||||
(let [{client-code :client/code feature-flags :client/feature-flags} (d/pull (d/db conn) '[:client/code :client/feature-flags] (:client_id args))
|
||||
is-new-square? ((set feature-flags) "new-square")]
|
||||
(let [{client-code :client/code feature-flags :client/feature-flags} (dc/pull (dc/db conn) '[:client/code :client/feature-flags] (:client_id args))
|
||||
is-new-square? ((set feature-flags) "new-square")]
|
||||
(q/put-query (str (UUID/randomUUID))
|
||||
(format sales-summary-query client-code)
|
||||
(str "sales query for " client-code)
|
||||
@@ -442,12 +409,11 @@
|
||||
(str "refunds query for " client-code)
|
||||
(str client-code "-refund")
|
||||
[:client/code client-code])
|
||||
|
||||
(let [sales-summary-id (:saved-query/guid (d/pull (d/db auto-ap.datomic/conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-sales-summary")]))
|
||||
sales-category-id (:saved-query/guid (d/pull (d/db auto-ap.datomic/conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-sales-category")]))
|
||||
expected-deposit-id (:saved-query/guid (d/pull (d/db auto-ap.datomic/conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-expected-deposit")]))
|
||||
tender-id (:saved-query/guid (d/pull (d/db auto-ap.datomic/conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-tender")]))
|
||||
refund-id (:saved-query/guid (d/pull (d/db auto-ap.datomic/conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-refund")]))]
|
||||
(let [sales-summary-id (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-sales-summary")]))
|
||||
sales-category-id (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-sales-category")]))
|
||||
expected-deposit-id (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-expected-deposit")]))
|
||||
tender-id (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-tender")]))
|
||||
refund-id (:saved-query/guid (dc/pull (dc/db conn) [:saved-query/guid] [:saved-query/lookup-key (str client-code "-refund")]))]
|
||||
{:message (str/join "\n"
|
||||
[
|
||||
(str "For " client-code ":")
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
(ns auto-ap.graphql.import-batch
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
:refer
|
||||
[add-sorter-fields apply-pagination apply-sort-3 conn merge-query]]
|
||||
[auto-ap.datomic :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query pull-many-by-id]]
|
||||
[auto-ap.graphql.utils
|
||||
:refer
|
||||
[<-graphql assert-admin ident->enum-f result->page]]
|
||||
[clj-time.coerce :as coerce]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[datomic.api :as d]
|
||||
[datomic.client.api :as dc]
|
||||
[auto-ap.graphql.utils :refer [attach-tracing-resolvers]]))
|
||||
|
||||
(def default-read '[:db/id
|
||||
@@ -36,19 +35,17 @@
|
||||
|
||||
|
||||
(cond->> query
|
||||
true (d/query)
|
||||
true (dc/q)
|
||||
true (apply-sort-3 args)
|
||||
true (apply-pagination args))))
|
||||
|
||||
(defn graphql-results [ids db _]
|
||||
(let [results (->> (d/pull-many db default-read ids)
|
||||
(group-by :db/id))]
|
||||
(let [results (pull-many-by-id db default-read ids)]
|
||||
(->> ids
|
||||
(map results)
|
||||
(map first))))
|
||||
(map results))))
|
||||
|
||||
(defn get-graphql [args]
|
||||
(let [db (d/db conn)
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
[(graphql-results ids-to-retrieve db args)
|
||||
matching-count]))
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
(:require
|
||||
[auto-ap.datomic :refer [conn]]
|
||||
[auto-ap.graphql.utils :refer [->graphql assert-admin]]
|
||||
[datomic.api :as d]))
|
||||
[datomic.client.api :as dc]))
|
||||
|
||||
(defn get-intuit-bank-accounts [context _ _]
|
||||
(assert-admin (:id context))
|
||||
(->graphql (map first (d/q '[:find (pull ?e [*])
|
||||
(->graphql (map first (dc/q '[:find (pull ?e [*])
|
||||
:in $
|
||||
:where [?e :intuit-bank-account/external-id]]
|
||||
(d/db conn)))))
|
||||
(dc/db conn)))))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
(ns auto-ap.graphql.invoices
|
||||
(:require
|
||||
[auto-ap.datomic :refer [conn remove-nils uri]]
|
||||
[auto-ap.datomic
|
||||
:refer [conn remove-nils upsert-entity]]
|
||||
[auto-ap.ledger :refer [transact-with-ledger]]
|
||||
[auto-ap.datomic.clients :as d-clients]
|
||||
[auto-ap.datomic.invoices :as d-invoices]
|
||||
[auto-ap.datomic.vendors :as d-vendors]
|
||||
@@ -21,11 +23,12 @@
|
||||
[auto-ap.utils :refer [dollars=]]
|
||||
[clj-time.coerce :as coerce]
|
||||
[clj-time.core :as time]
|
||||
[clojure.set :as set]
|
||||
[clojure.tools.logging :as log]
|
||||
[datomic.api :as d]
|
||||
[manifold.deferred :as de]
|
||||
[com.brunobonacci.mulog :as mu]))
|
||||
[com.brunobonacci.mulog :as mu]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[datomic.client.api :as dc]))
|
||||
|
||||
(defn ->graphql [invoice user ]
|
||||
(if (= "admin" (:user/role user))
|
||||
@@ -61,7 +64,7 @@
|
||||
(defn reject-invoices [context {:keys [invoices]} _]
|
||||
(assert-power-user (:id context))
|
||||
(doseq [i invoices]
|
||||
(assert-can-see-client (:id context) (:db/id (:invoice/client (d/entity (d/db conn) i)))))
|
||||
(assert-can-see-client (:id context) (:db/id (:invoice/client (dc/pull (dc/db conn) [{:invoice/client [:db/id]}] i)))))
|
||||
(let [transactions (map (fn [i] [:db/retractEntity i]) invoices)]
|
||||
(transact-with-ledger transactions (:id context))
|
||||
invoices))
|
||||
@@ -69,7 +72,9 @@
|
||||
(defn approve-invoices [context {:keys [invoices]} _]
|
||||
(assert-power-user (:id context))
|
||||
(doseq [i invoices
|
||||
:let [invoice (d/entity (d/db conn) i)]]
|
||||
:let [invoice (dc/pull (dc/db conn) [{:invoice/client [:db/id]}
|
||||
:invoice/date]
|
||||
i)]]
|
||||
(assert-can-see-client (:id context) (-> invoice :invoice/client :db/id))
|
||||
(assert-not-locked (-> invoice :invoice/client :db/id) (-> invoice :invoice/date)))
|
||||
(let [transactions (map (fn [i] {:db/id i :invoice/import-status :import-status/imported}) invoices)]
|
||||
@@ -104,34 +109,25 @@
|
||||
due))
|
||||
_ (when-not (:db/id account)
|
||||
(throw (ex-info (str "Vendor '" (:vendor/name vendor) "' does not have a default expense acount.") {:vendor-id vendor_id})))]
|
||||
(cond->
|
||||
{:db/id "invoice"
|
||||
:invoice/invoice-number invoice_number
|
||||
:invoice/client client_id
|
||||
:invoice/vendor vendor_id
|
||||
:invoice/import-status :import-status/imported
|
||||
:invoice/total total
|
||||
:invoice/outstanding-balance total
|
||||
:invoice/status :invoice-status/unpaid
|
||||
:invoice/date (coerce/to-date date)
|
||||
:invoice/expense-accounts (map expense-account->entity
|
||||
expense_accounts)}
|
||||
due (assoc :invoice/due (coerce/to-date due))
|
||||
scheduled_payment (assoc :invoice/scheduled-payment (coerce/to-date scheduled_payment)))))
|
||||
|
||||
(defn deleted-expense-accounts [invoice expense-accounts]
|
||||
(let [current-expense-accounts (:invoice/expense-accounts invoice)
|
||||
specified-ids (->> expense-accounts
|
||||
(map :id)
|
||||
set)
|
||||
existing-ids (->> current-expense-accounts
|
||||
(map :db/id)
|
||||
set)]
|
||||
(set/difference existing-ids specified-ids)))
|
||||
`(upsert-entity ~{:db/id "invoice"
|
||||
:invoice/invoice-number invoice_number
|
||||
:invoice/client client_id
|
||||
:invoice/vendor vendor_id
|
||||
:invoice/import-status :import-status/imported
|
||||
:invoice/total total
|
||||
:invoice/outstanding-balance total
|
||||
:invoice/status :invoice-status/unpaid
|
||||
:invoice/date (coerce/to-date date)
|
||||
:invoice/expense-accounts (map expense-account->entity
|
||||
expense_accounts)
|
||||
:invoice/due (coerce/to-date due)
|
||||
:invoice/scheduled-payment (coerce/to-date scheduled_payment)})))
|
||||
|
||||
(defn assert-valid-expense-accounts [expense_accounts vendor_id]
|
||||
(doseq [expense-account expense_accounts
|
||||
:let [account (d/entity (d/db conn) (:account_id expense-account))]]
|
||||
:let [account (dc/pull (dc/db conn)
|
||||
[:account/location]
|
||||
(:account_id expense-account))]]
|
||||
(when (empty? (:location expense-account))
|
||||
(throw (ex-info "Expense account is missing location" {:validation-error "Expense account is missing location"})))
|
||||
|
||||
@@ -178,7 +174,7 @@
|
||||
(assert-valid-expense-accounts expense_accounts vendor_id)
|
||||
(assert-invoice-amounts-add-up in)
|
||||
|
||||
(let [transaction-result (transact-with-ledger [(add-invoice-transaction in)] (:id context))]
|
||||
(let [transaction-result (transact-with-ledger (add-invoice-transaction in) (:id context))]
|
||||
(-> (d-invoices/get-by-id (get-in transaction-result [:tempids "invoice"]))
|
||||
(->graphql (:id context)))))
|
||||
|
||||
@@ -218,23 +214,21 @@
|
||||
|
||||
paid-amount (- (:invoice/total invoice) (:invoice/outstanding-balance invoice))
|
||||
_ (assert-can-see-client (:id context) (:db/id (:invoice/client invoice)))
|
||||
deleted (deleted-expense-accounts invoice expense_accounts)
|
||||
_ (assert-not-locked (:db/id (:invoice/client invoice)) (:date in))
|
||||
_ (assert-valid-expense-accounts expense_accounts vendor_id)
|
||||
_ (assert-invoice-amounts-add-up in)
|
||||
|
||||
updated-invoice (cond-> {:db/id id
|
||||
:invoice/invoice-number invoice_number
|
||||
:invoice/date (coerce/to-date date)
|
||||
updated-invoice {:db/id id
|
||||
:invoice/invoice-number invoice_number
|
||||
:invoice/date (coerce/to-date date)
|
||||
|
||||
:invoice/total total
|
||||
:invoice/outstanding-balance (- total paid-amount)
|
||||
:invoice/expense-accounts (map expense-account->entity
|
||||
expense_accounts)}
|
||||
due (assoc :invoice/due (coerce/to-date due))
|
||||
scheduled_payment (assoc :invoice/scheduled-payment (coerce/to-date scheduled_payment)))]
|
||||
(transact-with-ledger (concat [updated-invoice]
|
||||
(map (fn [d] [:db/retract id :invoice/expense-accounts d]) deleted))
|
||||
:invoice/total total
|
||||
:invoice/outstanding-balance (- total paid-amount)
|
||||
:invoice/expense-accounts (map expense-account->entity
|
||||
expense_accounts)
|
||||
:invoice/due (coerce/to-date due)
|
||||
:invoice/scheduled-payment (coerce/to-date scheduled_payment)}]
|
||||
(transact-with-ledger [`(upsert-entity ~updated-invoice)]
|
||||
(:id context))
|
||||
(-> (d-invoices/get-by-id id)
|
||||
(->graphql (:id context)))))
|
||||
@@ -300,15 +294,15 @@
|
||||
(log/info "Voiding " (count all-ids) args)
|
||||
(transact-with-ledger
|
||||
(->> all-ids
|
||||
(d/q '[:find [(pull ?i [:db/id :invoice/date {:invoice/expense-accounts [:db/id]}
|
||||
]) ...]
|
||||
(dc/q '[:find (pull ?i [:db/id :invoice/date {:invoice/expense-accounts [:db/id]}])
|
||||
:in $ [?i ...]
|
||||
:where (not [_ :invoice-payment/invoice ?i])
|
||||
[?i :invoice/client ?c]
|
||||
[(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu]
|
||||
[?i :invoice/date ?d]
|
||||
[(>= ?d ?lu)]]
|
||||
(d/db conn))
|
||||
(dc/db conn))
|
||||
(map first)
|
||||
(mapcat
|
||||
(fn [i]
|
||||
(into
|
||||
@@ -328,16 +322,15 @@
|
||||
(let [invoice (d-invoices/get-by-id id)
|
||||
_ (assert-can-see-client (:id context) (:db/id (:invoice/client invoice)))
|
||||
_ (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice))
|
||||
conn (d/connect uri)
|
||||
history (d/history (d/db conn))
|
||||
txs (d/query {:query {:find ['?tx '?e '?original-status '?original-outstanding '?total '?ea '?ea-amount]
|
||||
:where ['[?e :invoice/status :invoice-status/voided ?tx true]
|
||||
'[?e :invoice/status ?original-status ?tx false]
|
||||
'[?e :invoice/outstanding-balance ?original-outstanding ?tx false]
|
||||
'[?e :invoice/total ?total ?tx false]
|
||||
'[?ea :invoice-expense-account/amount ?ea-amount ?tx false]]
|
||||
:in ['$ '?e]}
|
||||
:args [history id]})
|
||||
history (dc/history (dc/db conn))
|
||||
txs (dc/q {:query {:find ['?tx '?e '?original-status '?original-outstanding '?total '?ea '?ea-amount]
|
||||
:where ['[?e :invoice/status :invoice-status/voided ?tx true]
|
||||
'[?e :invoice/status ?original-status ?tx false]
|
||||
'[?e :invoice/outstanding-balance ?original-outstanding ?tx false]
|
||||
'[?e :invoice/total ?total ?tx false]
|
||||
'[?ea :invoice-expense-account/amount ?ea-amount ?tx false]]
|
||||
:in ['$ '?e]}
|
||||
:args [history id]})
|
||||
[last-transaction] (->> txs (sort-by first) (last))]
|
||||
(transact-with-ledger [(->> txs
|
||||
(filter (fn [[tx]] (= tx last-transaction)))
|
||||
@@ -354,7 +347,11 @@
|
||||
(->graphql (:id context)))))
|
||||
|
||||
(defn unautopay-invoice [context {id :invoice_id} _]
|
||||
(let [invoice (d/entity (d/db conn) id)]
|
||||
(let [invoice (dc/pull (dc/db conn) [{:invoice/client [:db/id]}
|
||||
:invoice-payment/_invoice
|
||||
:invoice/total
|
||||
:invoice/scheduled-payment
|
||||
:invoice/date] id)]
|
||||
(assert (:invoice/client invoice))
|
||||
(assert-can-see-client (:id context) (:db/id (:invoice/client invoice)))
|
||||
(assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice))
|
||||
@@ -370,18 +367,15 @@
|
||||
(defn edit-expense-accounts [context args _]
|
||||
(assert-can-see-client (:id context) (:db/id (:invoice/client (d-invoices/get-by-id (:invoice_id args)))))
|
||||
(let [invoice-id (:invoice_id args)
|
||||
invoice (d-invoices/get-by-id invoice-id)
|
||||
_ (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice))
|
||||
_ (assert-valid-expense-accounts (:expense_accounts args) (:db/id (:invoice/vendor invoice )))
|
||||
deleted (deleted-expense-accounts invoice (:expense_accounts args))
|
||||
updated {:db/id invoice-id
|
||||
:invoice/expense-accounts (map
|
||||
expense-account->entity
|
||||
(:expense_accounts args))}]
|
||||
invoice (d-invoices/get-by-id invoice-id)
|
||||
_ (assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice))
|
||||
_ (assert-valid-expense-accounts (:expense_accounts args) (:db/id (:invoice/vendor invoice )))]
|
||||
|
||||
(transact-with-ledger (concat [updated]
|
||||
(map (fn [d] [:db/retract invoice-id :invoice/expense-accounts d]) deleted))
|
||||
(:id context))
|
||||
(transact-with-ledger [`(upsert-entity ~{:db/id invoice-id
|
||||
:invoice/expense-accounts (map
|
||||
expense-account->entity
|
||||
(:expense_accounts args))})]
|
||||
(:id context))
|
||||
(->graphql
|
||||
(d-invoices/get-by-id (:invoice_id args))
|
||||
(:id context))))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns auto-ap.graphql.ledger
|
||||
(:require
|
||||
[auto-ap.datomic :refer [audit-transact-batch conn remove-nils uri]]
|
||||
[auto-ap.datomic
|
||||
:refer [audit-transact-batch conn pull-attr pull-many remove-nils]]
|
||||
[auto-ap.datomic.accounts :as a]
|
||||
[auto-ap.datomic.clients :as d-clients]
|
||||
[auto-ap.datomic.ledger :as l]
|
||||
@@ -17,7 +18,7 @@
|
||||
[clojure.tools.logging :as log]
|
||||
[clojure.data.csv :as csv]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[datomic.api :as d]
|
||||
[datomic.client.api :as dc]
|
||||
[mount.core :as mount]
|
||||
[com.brunobonacci.mulog :as mu]
|
||||
[unilog.context :as lc]
|
||||
@@ -135,19 +136,19 @@
|
||||
[]))))
|
||||
|
||||
(defn build-account-lookup [client-id]
|
||||
(let [accounts (by :db/id (map first (d/query {:query {:find ['(pull ?e [:db/id :account/name
|
||||
(let [accounts (by :db/id (map first (dc/q {:query {:find ['(pull ?e [:db/id :account/name
|
||||
:account/numeric-code
|
||||
{:account/type [:db/ident]
|
||||
:account/client-overrides [:account-client-override/client :account-client-override/name]}
|
||||
])]
|
||||
:in ['$]
|
||||
:where ['[?e :account/name]]}
|
||||
:args [(d/db (d/connect uri) )]})))
|
||||
:args [(dc/db conn )]})))
|
||||
|
||||
bank-accounts (by :db/id (map first (d/query {:query {:find ['(pull ?e [:db/id :bank-account/name :bank-account/numeric-code {:bank-account/type [:db/ident]}])]
|
||||
bank-accounts (by :db/id (map first (dc/q {:query {:find ['(pull ?e [:db/id :bank-account/name :bank-account/numeric-code {:bank-account/type [:db/ident]}])]
|
||||
:in ['$]
|
||||
:where ['[?e :bank-account/name]]}
|
||||
:args [(d/db (d/connect uri))]})))
|
||||
:args [(dc/db conn)]})))
|
||||
overrides-by-client (->> accounts
|
||||
vals
|
||||
(mapcat (fn [a]
|
||||
@@ -171,7 +172,7 @@
|
||||
:client_id client-id})))
|
||||
|
||||
(defn full-ledger-for-client [client-id]
|
||||
(->> (d/query
|
||||
(->> (dc/q
|
||||
{:query {:find ['?d '?jel '?account '?location '?debit '?credit]
|
||||
:in ['$ '?client-id]
|
||||
:where '[[?e :journal-entry/client ?client-id]
|
||||
@@ -191,7 +192,7 @@
|
||||
[(get-else $ ?jel :journal-entry-line/credit 0.0) ?credit]
|
||||
[(get-else $ ?jel :journal-entry-line/location "") ?location]]
|
||||
}
|
||||
:args [(d/db (d/connect uri)) client-id]})
|
||||
:args [(dc/db conn) client-id]})
|
||||
(sort-by first)))
|
||||
|
||||
(defn get-balance-sheet [context args _]
|
||||
@@ -259,14 +260,15 @@
|
||||
|
||||
(defn all-ids-not-locked [all-ids]
|
||||
(->> all-ids
|
||||
(d/q '[:find [?t ...]
|
||||
(dc/q '[:find ?t
|
||||
:in $ [?t ...]
|
||||
:where
|
||||
[?t :journal-entry/client ?c]
|
||||
[(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu]
|
||||
[?t :journal-entry/date ?d]
|
||||
[(>= ?d ?lu)]]
|
||||
(d/db conn))))
|
||||
(dc/db conn))
|
||||
(map first)))
|
||||
|
||||
(defn delete-external-ledger [context args _]
|
||||
(let [_ (assert-admin (:id context))
|
||||
@@ -275,7 +277,7 @@
|
||||
(assoc :only-external true)
|
||||
(<-graphql)
|
||||
(assoc :per-page Integer/MAX_VALUE)
|
||||
(#(l/raw-graphql-ids (d/db conn) %))
|
||||
(#(l/raw-graphql-ids (dc/db conn) %))
|
||||
:ids)
|
||||
specific-ids (l/filter-ids (:ids args))
|
||||
all-ids (all-ids-not-locked (into (set ids) specific-ids))]
|
||||
@@ -426,7 +428,6 @@
|
||||
(:location ea)
|
||||
"'")
|
||||
{:status :error})))
|
||||
|
||||
(when (and matching-account
|
||||
(not (:account/location matching-account))
|
||||
(= "A" (:location ea)))
|
||||
@@ -513,7 +514,7 @@
|
||||
|
||||
(defn running-balance-for [client-id]
|
||||
(let [lookup-account (build-account-lookup client-id)]
|
||||
(->> (d/query
|
||||
(->> (dc/q
|
||||
{:query {:find ['?d '?e '?jel '?account '?location '?debit '?credit]
|
||||
:in ['$ '?client-id]
|
||||
:where '[[?e :journal-entry/client ?client-id]
|
||||
@@ -533,7 +534,7 @@
|
||||
[(get-else $ ?jel :journal-entry-line/credit 0.0) ?credit]
|
||||
[(get-else $ ?jel :journal-entry-line/location "") ?location]]
|
||||
}
|
||||
:args [(d/db conn) client-id]})
|
||||
:args [(dc/db conn) client-id]})
|
||||
(sort-by (juxt first second))
|
||||
(build-running-balance lookup-account))))
|
||||
|
||||
@@ -541,25 +542,23 @@
|
||||
|
||||
(defn build-running-balance-cache []
|
||||
(let [clients-needing-refresh (if-let [last-run @last-run-running-balance]
|
||||
(->> (d/query
|
||||
(->> (dc/q
|
||||
{:query {:find ['?v]
|
||||
:in ['$ '?log '?since '?till]
|
||||
:where ['[(tx-ids ?log ?since ?till) [?tx ...]]
|
||||
'[$ _ :journal-entry/client ?v ?tx]]}
|
||||
:args [(d/history (d/db conn))
|
||||
(d/log conn)
|
||||
last-run
|
||||
(java.util.Date.)]})
|
||||
:in ['$ '[?tx ...]]
|
||||
:where ['[$ _ :journal-entry/client ?v ?tx]]}
|
||||
:args [(dc/history (dc/db conn))
|
||||
(map :t (mapcat :data (dc/tx-range conn {:start last-run
|
||||
:end (java.util.Date.)})))]})
|
||||
(map first)
|
||||
(into #{}))
|
||||
(into #{} (map :db/id (d-clients/get-all))))
|
||||
(into #{}))
|
||||
(into #{} (map :db/id (d-clients/get-all))))
|
||||
starting (java.util.Date.)]
|
||||
(log/info (count clients-needing-refresh) "Clients need their balance cache refreshed.")
|
||||
(swap! running-balance-cache
|
||||
merge
|
||||
(reduce
|
||||
(fn [acc client]
|
||||
(log/info "Computing running balance cache for " (:client/code (d/entity (d/db conn) client)))
|
||||
(log/info "Computing running balance cache for " (pull-attr (dc/db conn) :client/code client ))
|
||||
(assoc acc client (running-balance-for client)))
|
||||
{}
|
||||
clients-needing-refresh))
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
(ns auto-ap.graphql.plaid
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
:refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query]]
|
||||
:refer [add-sorter-fields
|
||||
apply-pagination
|
||||
apply-sort-3
|
||||
conn
|
||||
merge-query
|
||||
pull-attr
|
||||
pull-many-by-id]]
|
||||
[auto-ap.graphql.utils
|
||||
:refer [->graphql
|
||||
<-graphql
|
||||
@@ -14,13 +20,15 @@
|
||||
[clj-time.coerce :as coerce]
|
||||
[clj-time.core :as time]
|
||||
[clojure.tools.logging :as log]
|
||||
[datomic.client.api :as dc]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[datomic.api :as d]))
|
||||
|
||||
(defn plaid-link-token [context value _]
|
||||
(when-not (:client_id value)
|
||||
(throw (ex-info "Client ID is required" {:validation-error "Client ID is required"})))
|
||||
(assert-can-see-client (:id context) (:client_id value))
|
||||
(let [client-code (:client/code (d/pull (d/db conn) [:client/code] (:client_id value)))]
|
||||
(let [client-code (pull-attr (dc/db conn) :client/code (:client_id value))]
|
||||
{:token (p/get-link-token client-code)}))
|
||||
|
||||
(defn link-plaid [context value _]
|
||||
@@ -28,8 +36,8 @@
|
||||
(throw (ex-info "Client not provided" {:validation-error "Client not provided."})))
|
||||
(when-not (:public_token value)
|
||||
(throw (ex-info "Public token not provided" {:validation-error "public token not provided"})))
|
||||
(log/info (:id context) (:db/id (d/pull (d/db conn) [:db/id] [:client/code (:client_code value)])))
|
||||
(assert-can-see-client (:id context) (:db/id (d/pull (d/db conn) [:db/id] [:client/code (:client_code value)])))
|
||||
(log/info (:id context) (pull-attr (dc/db conn) :db/id [:client/code (:client_code value)]))
|
||||
(assert-can-see-client (:id context) (pull-attr (dc/db conn) :db/id [:client/code (:client_code value)]))
|
||||
(let [access-token (:access_token (p/exchange-public-token (:public_token value) (:client_code value)))
|
||||
account-result (p/get-accounts access-token )
|
||||
item {:plaid-item/client [:client/code (:client_code value)]
|
||||
@@ -40,15 +48,16 @@
|
||||
:plaid-item/last-updated (coerce/to-date (time/now))
|
||||
:db/id "plaid-item"}]
|
||||
|
||||
@(d/transact conn (->> (:accounts account-result)
|
||||
(map (fn [a]
|
||||
(let [balance (some-> a :balances :current (* 0.01))]
|
||||
(cond-> {:plaid-account/external-id (:account_id a)
|
||||
:plaid-account/number (:mask a)
|
||||
:plaid-account/name (str (:name a) " " (:mask a))
|
||||
:plaid-item/_accounts "plaid-item"}
|
||||
balance (assoc :plaid-account/balance balance)))))
|
||||
(into [item])))
|
||||
(dc/transact conn {:tx-data
|
||||
(->> (:accounts account-result)
|
||||
(map (fn [a]
|
||||
(let [balance (some-> a :balances :current (* 0.01))]
|
||||
(cond-> {:plaid-account/external-id (:account_id a)
|
||||
:plaid-account/number (:mask a)
|
||||
:plaid-account/name (str (:name a) " " (:mask a))
|
||||
:plaid-item/_accounts "plaid-item"}
|
||||
balance (assoc :plaid-account/balance balance)))))
|
||||
(into [item]))})
|
||||
(log/info "Access token was " access-token)
|
||||
{:message (str "Plaid linked successfully.")}))
|
||||
|
||||
@@ -87,19 +96,17 @@
|
||||
:where ['[?e :plaid-item/external-id]]}}))]
|
||||
|
||||
(cond->> query
|
||||
true (d/query)
|
||||
true (dc/q)
|
||||
true (apply-sort-3 args)
|
||||
true (apply-pagination args))))
|
||||
|
||||
(defn graphql-results [ids db _]
|
||||
(let [results (->> (d/pull-many db default-read ids)
|
||||
(group-by :db/id))]
|
||||
(let [results (pull-many-by-id db default-read ids)]
|
||||
(->> ids
|
||||
(map results)
|
||||
(map first))))
|
||||
(map results))))
|
||||
|
||||
(defn get-graphql [args]
|
||||
(let [db (d/db conn)
|
||||
(let [db (dc/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
[(graphql-results ids-to-retrieve db args)
|
||||
matching-count]))
|
||||
@@ -121,7 +128,7 @@
|
||||
(defn delete-plaid-item [context args _]
|
||||
(assert-admin (:id context))
|
||||
(assert-present args :id)
|
||||
@(d/transact conn [[:db/retractEntity (:id args)]])
|
||||
(dc/transact conn {:tx-data [[:db/retractEntity (:id args)]]})
|
||||
{:message "Item deleted."})
|
||||
|
||||
(defn attach [schema]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[auto-ap.graphql.utils
|
||||
:refer [<-graphql assert-admin attach-tracing-resolvers result->page]]
|
||||
[config.core :refer [env]]
|
||||
[datomic.api :as d]))
|
||||
[datomic.client.api :as dc]))
|
||||
|
||||
(defn get-report-page [context args _]
|
||||
(let [args (assoc args :id (:id context))
|
||||
@@ -17,15 +17,15 @@
|
||||
|
||||
(defn delete-report [context args _]
|
||||
(assert-admin (:id context))
|
||||
(let [[id-to-delete key] (first (d/q '[:find ?i ?k
|
||||
(let [[id-to-delete key] (first (dc/q '[:find ?i ?k
|
||||
:in $ ?i
|
||||
:where [?i :report/key ?k]]
|
||||
(d/db conn)
|
||||
(dc/db conn)
|
||||
(:id args)))]
|
||||
(when id-to-delete
|
||||
(s3/delete-object :bucket-name (:data-bucket env)
|
||||
:key key)
|
||||
@(d/transact conn [[:db/retractEntity id-to-delete]]))
|
||||
(dc/transact conn {:tx-data [[:db/retractEntity id-to-delete]]}))
|
||||
{:message (format "deleted %s successfully" key)}))
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
(ns auto-ap.graphql.transaction-rules
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
:refer [audit-transact
|
||||
conn
|
||||
merge-query
|
||||
remove-nils
|
||||
replace-nils-with-retract]]
|
||||
[auto-ap.datomic :refer [audit-transact conn merge-query upsert-entity]]
|
||||
[auto-ap.datomic.transaction-rules :as tr]
|
||||
[auto-ap.datomic.transactions :as d-transactions]
|
||||
[auto-ap.graphql.utils
|
||||
@@ -20,7 +15,7 @@
|
||||
[auto-ap.utils :refer [dollars=]]
|
||||
[clj-time.coerce :as c]
|
||||
[clojure.string :as str]
|
||||
[datomic.api :as d]))
|
||||
[datomic.client.api :as dc]))
|
||||
|
||||
(defn get-transaction-rule-page [context args _]
|
||||
(let [args (assoc args :id (:id context))
|
||||
@@ -37,10 +32,10 @@
|
||||
nil))
|
||||
|
||||
(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}))
|
||||
#:transaction-rule-account {:percentage percentage
|
||||
:db/id id
|
||||
:account account_id
|
||||
:location location})
|
||||
|
||||
(defn delete-transaction-rule [context {:keys [transaction_rule_id ]} _]
|
||||
(assert-admin (:id context))
|
||||
@@ -53,8 +48,7 @@
|
||||
|
||||
(defn upsert-transaction-rule [context {{:keys [id description yodlee_merchant_id note client_id bank_account_id amount_lte amount_gte vendor_id accounts transaction_approval_status dom_gte dom_lte]} :transaction_rule} _]
|
||||
(assert-admin (:id context))
|
||||
(let [existing-transaction (tr/get-by-id id)
|
||||
account-total (reduce + 0 (map (fn [x] (:percentage x)) accounts))
|
||||
(let [account-total (reduce + 0 (map (fn [x] (:percentage x)) accounts))
|
||||
_ (try
|
||||
(. java.util.regex.Pattern (compile description java.util.regex.Pattern/CASE_INSENSITIVE))
|
||||
(catch Exception e
|
||||
@@ -67,8 +61,8 @@
|
||||
(let [error (str "You must provide a description or a yodlee merchant")]
|
||||
(throw (ex-info error {:validation-error error}))))
|
||||
_ (doseq [a accounts
|
||||
:let [{:keys [:account/location :account/name]} (d/entity (d/db conn) (:account_id a))
|
||||
client (d/entity (d/db conn) client_id)
|
||||
:let [{:keys [:account/location :account/name]} (dc/pull (dc/db conn) [:account/location :account/name] (:account_id a))
|
||||
client (dc/pull (dc/db conn) [:client/locations] client_id)
|
||||
]]
|
||||
(when (and location (not= location (:location a)))
|
||||
(let [err (str "Account " name " uses location " (:location a) ", but is supposed to be " location)]
|
||||
@@ -82,27 +76,25 @@
|
||||
rule-id (if id
|
||||
id
|
||||
"transaction-rule")
|
||||
transaction (replace-nils-with-retract #:transaction-rule {:db/id rule-id
|
||||
:description description
|
||||
:note note
|
||||
:client client_id
|
||||
:bank-account bank_account_id
|
||||
:yodlee-merchant yodlee_merchant_id
|
||||
:dom-lte dom_lte
|
||||
:dom-gte dom_gte
|
||||
:amount-lte amount_lte
|
||||
:amount-gte amount_gte
|
||||
:vendor vendor_id
|
||||
:transaction-approval-status
|
||||
(some->> transaction_approval_status
|
||||
name
|
||||
snake->kebab
|
||||
(keyword "transaction-approval-status"))}
|
||||
existing-transaction)
|
||||
transaction [`(upsert-entity ~#:transaction-rule {:db/id rule-id
|
||||
:description description
|
||||
:note note
|
||||
:client client_id
|
||||
:bank-account bank_account_id
|
||||
:yodlee-merchant yodlee_merchant_id
|
||||
:dom-lte dom_lte
|
||||
:dom-gte dom_gte
|
||||
:amount-lte amount_lte
|
||||
:amount-gte amount_gte
|
||||
:vendor vendor_id
|
||||
:transaction-approval-status
|
||||
(some->> transaction_approval_status
|
||||
name
|
||||
snake->kebab
|
||||
(keyword "transaction-approval-status"))
|
||||
:transaction-rule/accounts (map transaction-rule-account->entity accounts)})]
|
||||
|
||||
|
||||
transaction (conj transaction
|
||||
[:reset rule-id :transaction-rule/accounts (map transaction-rule-account->entity accounts)])
|
||||
transaction-result (audit-transact transaction (:id context))]
|
||||
(-> (tr/get-by-id (or (-> transaction-result :tempids (get "transaction-rule"))
|
||||
id))
|
||||
@@ -111,14 +103,14 @@
|
||||
|
||||
(defn -test-transaction-rule [id {:keys [:transaction-rule/description :transaction-rule/client :transaction-rule/bank-account :transaction-rule/amount-lte :transaction-rule/amount-gte :transaction-rule/dom-lte :transaction-rule/dom-gte :transaction-rule/yodlee-merchant]} include-coded? count]
|
||||
(->>
|
||||
(d/query
|
||||
(dc/q
|
||||
(cond-> {:query {:find ['(pull ?e [* {:transaction/client [:client/name]
|
||||
:transaction/bank-account [:bank-account/name]
|
||||
:transaction/payment [:db/id]}
|
||||
])]
|
||||
:in ['$ ]
|
||||
:where []}
|
||||
:args [(d/db conn)]}
|
||||
:args [(dc/db conn)]}
|
||||
|
||||
(limited-clients id)
|
||||
(merge-query {:query {:in ['[?xx ...]]
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
(ns auto-ap.graphql.transactions
|
||||
(:require
|
||||
[auto-ap.datomic :refer [conn remove-nils]]
|
||||
[auto-ap.datomic
|
||||
:refer [audit-transact
|
||||
audit-transact-batch
|
||||
conn
|
||||
pull-attr
|
||||
pull-many
|
||||
pull-ref
|
||||
remove-nils
|
||||
upsert-entity]]
|
||||
[auto-ap.datomic.accounts :as a]
|
||||
[auto-ap.datomic.checks :as d-checks]
|
||||
[auto-ap.datomic.invoices :as d-invoices]
|
||||
@@ -27,6 +35,7 @@
|
||||
[clojure.string :as str]
|
||||
[clojure.tools.logging :as log]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[datomic.client.api :as dc]
|
||||
[datomic.api :as d]
|
||||
[auto-ap.graphql.utils :refer [attach-tracing-resolvers]]))
|
||||
|
||||
@@ -74,14 +83,15 @@
|
||||
|
||||
(defn all-ids-not-locked [all-ids]
|
||||
(->> all-ids
|
||||
(d/q '[:find [?t ...]
|
||||
(dc/q '[:find ?t
|
||||
:in $ [?t ...]
|
||||
:where
|
||||
[?t :transaction/client ?c]
|
||||
[(get-else $ ?c :client/locked-until #inst "2000-01-01") ?lu]
|
||||
[?t :transaction/date ?d]
|
||||
[(>= ?d ?lu)]]
|
||||
(d/db conn))))
|
||||
(dc/db conn))
|
||||
(map first)))
|
||||
(defn bulk-change-status [context args _]
|
||||
(let [_ (assert-admin (:id context))
|
||||
args (assoc args :id (:id context))
|
||||
@@ -140,11 +150,11 @@
|
||||
(throw (ex-info "Client is required"
|
||||
{:validation-error "client is required"})))
|
||||
(let [args (assoc args :id (:id context))
|
||||
locations (:client/locations (d/pull (d/db conn)
|
||||
[:client/locations]
|
||||
(:client_id args)))
|
||||
locations (pull-attr (dc/db conn)
|
||||
:client/locations
|
||||
(:client_id args))
|
||||
all-ids (all-ids-not-locked (get-ids-matching-filters args))
|
||||
transactions (d/pull-many (d/db conn) '[:db/id :transaction/amount] (vec all-ids))
|
||||
transactions (pull-many (dc/db conn) [:db/id :transaction/amount] (vec all-ids))
|
||||
account-total (reduce + 0 (map (fn [x] (:percentage x)) (:accounts args)))]
|
||||
(log/info "client is" locations)
|
||||
|
||||
@@ -156,7 +166,9 @@
|
||||
(throw (ex-info error {:validation-error error}))))
|
||||
|
||||
(doseq [a (:accounts args)
|
||||
:let [{:keys [:account/location :account/name]} (d/entity (d/db conn) (:account_id a))]]
|
||||
:let [{:keys [:account/location :account/name]} (dc/pull (dc/db conn)
|
||||
[:account/location :account/name]
|
||||
(:account_id a))]]
|
||||
(when (and location (not= location (:location a)))
|
||||
(let [err (str "Account " name " uses location " (:location a) ", but is supposed to be " location)]
|
||||
(throw (ex-info err {:validation-error err}) )))
|
||||
@@ -184,12 +196,14 @@
|
||||
(let [_ (assert-admin (:id context))
|
||||
args (assoc args :id (:id context))
|
||||
all-ids (all-ids-not-locked (get-ids-matching-filters args))
|
||||
db (d/db conn)]
|
||||
db (dc/db conn)]
|
||||
|
||||
(log/info "Deleting " (count all-ids) args)
|
||||
(transact-batch-with-ledger
|
||||
(mapcat (fn [i]
|
||||
(let [transaction (d/entity db i)
|
||||
(let [transaction (dc/pull db [:transaction/payment
|
||||
:transaction/expected-deposit
|
||||
:db/id] i)
|
||||
payment-id (-> transaction :transaction/payment :db/id)
|
||||
expected-deposit-id (-> transaction :transaction/expected-deposit :db/id)
|
||||
transaction-tx (if (:suppress args)
|
||||
@@ -233,7 +247,7 @@
|
||||
(let [_ (assert-power-user (:id context))
|
||||
args (assoc args :id (:id context))
|
||||
transaction-id (:transaction_id args)
|
||||
transaction (d/pull (d/db conn)
|
||||
transaction (dc/pull (dc/db conn)
|
||||
[:transaction/approval-status
|
||||
:transaction/status
|
||||
:transaction/date
|
||||
@@ -249,12 +263,12 @@
|
||||
(assert-not-locked (:db/id (:transaction/client transaction)) (-> transaction :transaction/payment :payment/date)))
|
||||
_ (log/info "Unlinking" transaction)
|
||||
payment (-> transaction :transaction/payment )
|
||||
is-autopay-payment? (some->> (doto (d/query {:query {:find ['?sp]
|
||||
is-autopay-payment? (some->> (doto (dc/q {:query {:find ['?sp]
|
||||
:in ['$ '?payment]
|
||||
:where ['[?ip :invoice-payment/payment ?payment]
|
||||
'[?ip :invoice-payment/invoice ?i]
|
||||
'[(get-else $ ?i :invoice/scheduled-payment "N/A") ?sp]]}
|
||||
:args [(d/db conn) (:db/id payment)]})
|
||||
:args [(dc/db conn) (:db/id payment)]})
|
||||
log/info)
|
||||
seq
|
||||
(map first)
|
||||
@@ -288,10 +302,10 @@
|
||||
true
|
||||
(into (map (fn [[invoice-payment]]
|
||||
[:db/retractEntity invoice-payment])
|
||||
(d/query {:query {:find ['?ip]
|
||||
:in ['$ '?p]
|
||||
:where ['[?ip :invoice-payment/payment ?p]]}
|
||||
:args [(d/db conn) (:db/id payment)]} ))))
|
||||
(dc/q {:query {:find ['?ip]
|
||||
:in ['$ '?p]
|
||||
:where ['[?ip :invoice-payment/payment ?p]]}
|
||||
:args [(dc/db conn) (:db/id payment)]} ))))
|
||||
(:id context))
|
||||
(transact-with-ledger
|
||||
(into (cond-> [{:db/id (:db/id payment)
|
||||
@@ -314,25 +328,17 @@
|
||||
|
||||
|
||||
(defn transaction-account->entity [{:keys [id account_id amount location]}]
|
||||
(remove-nils #:transaction-account {:amount amount
|
||||
:db/id id
|
||||
:account account_id
|
||||
:location location}))
|
||||
#:transaction-account {:amount amount
|
||||
:db/id id
|
||||
:account account_id
|
||||
:location location})
|
||||
|
||||
|
||||
(defn deleted-accounts [transaction accounts]
|
||||
(let [current-accounts (:transaction/accounts transaction)
|
||||
specified-ids (->> accounts
|
||||
(map :id)
|
||||
set)
|
||||
existing-ids (->> current-accounts
|
||||
(map :db/id)
|
||||
set)]
|
||||
(set/difference existing-ids specified-ids)))
|
||||
|
||||
(defn assert-valid-expense-accounts [accounts]
|
||||
(doseq [trans-account accounts
|
||||
:let [account (d/entity (d/db conn) (:account_id trans-account))]]
|
||||
:let [account (dc/pull (dc/db conn)
|
||||
[:account/location]
|
||||
(:account_id trans-account))]]
|
||||
(when (empty? (:location trans-account))
|
||||
(throw (ex-info "Account is missing location" {:validation-error "Account is missing location"})))
|
||||
|
||||
@@ -358,7 +364,6 @@
|
||||
_ (assert-can-see-client (:id context) (:transaction/client existing-transaction) )
|
||||
_ (assert-valid-expense-accounts accounts)
|
||||
_ (assert-not-locked (:db/id (:transaction/client existing-transaction)) (:transaction/date existing-transaction))
|
||||
deleted (deleted-accounts existing-transaction accounts)
|
||||
account-total (reduce + 0 (map (fn [x] (:amount x)) accounts))
|
||||
missing-locations (seq (set/difference
|
||||
(->> accounts
|
||||
@@ -376,27 +381,14 @@
|
||||
(when missing-locations
|
||||
(throw (ex-info (str "Location '" (str/join ", " missing-locations) "' not found on client.") {})) )
|
||||
|
||||
(transact-with-ledger (concat [(remove-nils {:db/id id
|
||||
:transaction/vendor vendor_id
|
||||
:transaction/approval-status (some->> approval_status
|
||||
name
|
||||
snake->kebab
|
||||
(keyword "transaction-approval-status"))
|
||||
:transaction/accounts (map transaction-account->entity accounts)
|
||||
})
|
||||
]
|
||||
(cond forecast_match
|
||||
[[:db/add id :transaction/forecast-match forecast_match]]
|
||||
|
||||
(:db/id (:transaction/forecast-match existing-transaction))
|
||||
[[:db/retract id :transaction/forecast-match (:db/id (:transaction/forecast-match existing-transaction))]]
|
||||
|
||||
:else
|
||||
[])
|
||||
|
||||
(map (fn [d]
|
||||
[:db/retract id :transaction/accounts d])
|
||||
deleted))
|
||||
(transact-with-ledger [`(upsert-entity ~{:db/id id
|
||||
:transaction/vendor vendor_id
|
||||
:transaction/approval-status (some->> approval_status
|
||||
name
|
||||
snake->kebab
|
||||
(keyword "transaction-approval-status"))
|
||||
:transaction/accounts (map transaction-account->entity accounts)
|
||||
:transaction/forecast-match forecast_match})]
|
||||
(:id context))
|
||||
(-> (d-transactions/get-by-id id)
|
||||
approval-status->graphql
|
||||
@@ -440,9 +432,9 @@
|
||||
(let [_ (assert-power-user (:id context))
|
||||
transaction (d-transactions/get-by-id transaction_id)
|
||||
_ (assert-can-see-client (:id context) (:transaction/client transaction) )
|
||||
db (d/db conn)
|
||||
invoice-clients (set (map (comp :db/id :invoice/client #(d/entity db %)) autopay_invoice_ids))
|
||||
invoice-amount (reduce + 0.0 (map (comp :invoice/total #(d/entity db %)) autopay_invoice_ids))
|
||||
db (dc/db conn)
|
||||
invoice-clients (set (map #(pull-ref db :invoice/client %) autopay_invoice_ids))
|
||||
invoice-amount (reduce + 0.0 (map #(pull-attr db :invoice/total %) autopay_invoice_ids))
|
||||
_ (assert-not-locked (:db/id (:transaction/client transaction)) (:transaction/date transaction))]
|
||||
(when (:transaction/payment transaction)
|
||||
(throw (ex-info "Transaction already linked" {:validation-error "Transaction already linked"})))
|
||||
@@ -454,22 +446,15 @@
|
||||
(when-not (dollars= (- (:transaction/amount transaction))
|
||||
invoice-amount)
|
||||
(throw (ex-info "Amounts don't match" {:validation-error "Amounts don't match"})))
|
||||
#_(log/info [#_(select-keys (d/entity db transaction_id) #{:transaction/amount :db/id})]
|
||||
(->> autopay_invoice_ids
|
||||
(map (fn [id]
|
||||
(let [entity (d/entity db id)]
|
||||
[(-> entity :invoice/vendor :db/id)
|
||||
(-> entity :db/id)
|
||||
(-> entity :invoice/total)])))))
|
||||
(let [payment-tx (i-transactions/add-new-payment [(select-keys (d/entity db transaction_id) #{:transaction/amount :transaction/date :db/id})]
|
||||
(map (fn [id]
|
||||
(let [entity (d/entity db id)]
|
||||
[(-> entity :invoice/vendor :db/id)
|
||||
(-> entity :db/id)
|
||||
(-> entity :invoice/total)]))
|
||||
autopay_invoice_ids)
|
||||
(:db/id (:transaction/bank-account transaction))
|
||||
(:db/id (:transaction/client transaction)))]
|
||||
(let [payment-tx (i-transactions/add-new-payment [(dc/pull db [:transaction/amount :transaction/date :db/id] transaction_id)]
|
||||
(map (fn [id]
|
||||
(let [entity (dc/pull db [:invoice/vendor :db/id :invoice/total] id)]
|
||||
[(-> entity :invoice/vendor :db/id)
|
||||
(-> entity :db/id)
|
||||
(-> entity :invoice/total)]))
|
||||
autopay_invoice_ids)
|
||||
(:db/id (:transaction/bank-account transaction))
|
||||
(:db/id (:transaction/client transaction)))]
|
||||
(log/info "Adding a new payment" payment-tx)
|
||||
(transact-with-ledger payment-tx (:id context)))
|
||||
|
||||
@@ -483,9 +468,9 @@
|
||||
|
||||
_ (assert-can-see-client (:id context) (:transaction/client transaction) )
|
||||
_ (assert-not-locked (:db/id (:transaction/client transaction)) (:transaction/date transaction))
|
||||
db (d/db conn)
|
||||
invoice-clients (set (map (comp :db/id :invoice/client #(d/entity db %)) unpaid_invoice_ids))
|
||||
invoice-amount (reduce + 0.0 (map (comp :invoice/outstanding-balance #(d/entity db %)) unpaid_invoice_ids))]
|
||||
db (dc/db conn)
|
||||
invoice-clients (set (map #(pull-ref db :invoice/client %) unpaid_invoice_ids))
|
||||
invoice-amount (reduce + 0.0 (map #(pull-attr db :invoice/outstanding-balance %) unpaid_invoice_ids))]
|
||||
(when (or (> (count invoice-clients) 1)
|
||||
(not= (:db/id (:transaction/client transaction))
|
||||
(first invoice-clients)))
|
||||
@@ -498,9 +483,9 @@
|
||||
(when (:transaction/payment transaction)
|
||||
(throw (ex-info "Transaction already linked" {:validation-error "Transaction already linked"})))
|
||||
|
||||
(let [payment-tx (i-transactions/add-new-payment [(select-keys (d/entity db transaction_id) #{:transaction/amount :transaction/date :db/id})]
|
||||
(let [payment-tx (i-transactions/add-new-payment [(dc/pull db [:transaction/amount :transaction/date :db/id] transaction_id)]
|
||||
(map (fn [id]
|
||||
(let [entity (d/entity db id)]
|
||||
(let [entity (dc/pull db [:invoice/vendor :db/id :invoice/total] id)]
|
||||
[(-> entity :invoice/vendor :db/id)
|
||||
(-> entity :db/id)
|
||||
(-> entity :invoice/total)]))
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[clj-time.coerce :as coerce]
|
||||
[auto-ap.time :as atime]
|
||||
[buddy.auth :refer [throw-unauthorized]]
|
||||
[datomic.api :as d]
|
||||
[datomic.client.api :as dc]
|
||||
[clojure.walk :as walk]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[clojure.tools.logging :as log]
|
||||
@@ -113,7 +113,7 @@
|
||||
(some->> e name snake->kebab (keyword namespace)))
|
||||
|
||||
(defn get-locked-until [client-id]
|
||||
(:client/locked-until (d/pull (d/db conn) [:client/locked-until] client-id)))
|
||||
(:client/locked-until (dc/pull (dc/db conn) [:client/locked-until] client-id)))
|
||||
|
||||
(defn assert-not-locked [client-id date]
|
||||
(let [locked-until (get-locked-until client-id)]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns auto-ap.graphql.vendors
|
||||
(:require
|
||||
[auto-ap.datomic :refer [audit-transact conn remove-nils]]
|
||||
[auto-ap.datomic :refer [audit-transact conn pull-attr remove-nils]]
|
||||
[auto-ap.datomic.vendors :as d-vendors]
|
||||
[auto-ap.graphql.utils
|
||||
:refer [->graphql
|
||||
@@ -14,20 +14,22 @@
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
[clojure.tools.logging :as log]
|
||||
[datomic.api :as d]))
|
||||
[datomic.client.api :as dc]
|
||||
[auto-ap.search :as search]))
|
||||
|
||||
(defn can-user-edit-vendor? [vendor-id id]
|
||||
(if (is-admin? id)
|
||||
true
|
||||
(empty?
|
||||
(set/difference (set (d/q '[:find [?c ...]
|
||||
:in $ ?v
|
||||
:where [?vu :vendor-usage/vendor ?v]
|
||||
[?vu :vendor-usage/client ?c]
|
||||
[?vu :vendor-usage/count ?d]
|
||||
[(>= ?d 0)]]
|
||||
(d/db conn)
|
||||
vendor-id))
|
||||
(set/difference (set (->> (dc/q '[:find ?c
|
||||
:in $ ?v
|
||||
:where [?vu :vendor-usage/vendor ?v]
|
||||
[?vu :vendor-usage/client ?c]
|
||||
[?vu :vendor-usage/count ?d]
|
||||
[(>= ?d 0)]]
|
||||
(dc/db conn)
|
||||
vendor-id)
|
||||
(map first)))
|
||||
(set (map :db/id (:user/clients id)))))))
|
||||
|
||||
(defn upsert-vendor [context {{:keys [id name hidden terms code print_as primary_contact secondary_contact address default_account_id invoice_reminder_schedule schedule_payment_dom terms_overrides account_overrides] :as in} :vendor} _]
|
||||
@@ -59,8 +61,7 @@
|
||||
hidden (if (is-admin? (:id context))
|
||||
hidden
|
||||
false)
|
||||
existing (when id
|
||||
(d/pull (d/db conn) '[:vendor/name] id))
|
||||
existing (pull-attr (dc/db conn) :vendor/name id)
|
||||
terms-overrides (mapv
|
||||
(fn [to]
|
||||
(cond->
|
||||
@@ -145,11 +146,11 @@
|
||||
(->graphql))))
|
||||
|
||||
(defn merge-vendors [context {:keys [from to]} _]
|
||||
(let [transaction (->> (d/query {:query {:find '[?x ?a2]
|
||||
(let [transaction (->> (dc/q {:query {:find '[?x ?a2]
|
||||
:in '[$ ?vendor-from ]
|
||||
:where ['[?x ?a ?vendor-from]
|
||||
'[?a :db/ident ?a2]]}
|
||||
:args [(d/db conn) from]})
|
||||
:args [(dc/db conn) from]})
|
||||
(mapcat (fn [[src attr]]
|
||||
|
||||
[[:db/retract src attr from]
|
||||
@@ -182,6 +183,13 @@
|
||||
matches))
|
||||
|
||||
(defn search [context args _]
|
||||
(comment (let [search-query (cleanse-query (:query args))]
|
||||
(for [[id name] (search/search (cond-> {:q search-query}
|
||||
(not (is-admin? (:id context))) (assoc :hidden false))
|
||||
"vendors")]
|
||||
{:name name
|
||||
:id (Long/parseLong id)})
|
||||
))
|
||||
(if-let [search-query (cleanse-query (:query args))]
|
||||
(let [data (if (is-admin? (:id context))
|
||||
(d/q '[:find ?n ?i ?s
|
||||
|
||||
Reference in New Issue
Block a user