(ns auto-ap.datomic.checks (:require [auto-ap.datomic :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query observable-query pull-many]] [auto-ap.graphql.utils :refer [extract-client-ids]] [clj-time.coerce :as c] [clojure.set :refer [rename-keys]] [datomic.api :as dc] [clj-time.coerce :as coerce])) (defn <-datomic [result] (-> result (update :payment/date c/from-date) (update :payment/status :db/ident) (update :payment/type :db/ident) (update :transaction/_payment (fn [transactions] (mapv (fn [transaction] (update transaction :transaction/date c/from-date)) transactions))) (rename-keys {:invoice-payment/_payment :payment/invoices}))) (def default-read '[* {:invoice-payment/_payment [* {:invoice-payment/invoice [*]}]} {:payment/client [:client/name :db/id :client/code]} {:payment/bank-account [*]} {:payment/vendor [:vendor/name {:vendor/default-account [:account/name :account/numeric-code :db/id]} :db/id {:vendor/primary-contact [*]} {:vendor/address [*]}]} {:payment/status [:db/ident]} {:payment/type [:db/ident]} {:transaction/_payment [:db/id :transaction/date]}]) (defn raw-graphql-ids ([args] (raw-graphql-ids (dc/db conn) args)) ([db args] (let [valid-clients (extract-client-ids (:clients args) (:client-id args) (when (:client-code args) [:client/code (:client-code args)])) check-number-like (try (Long/parseLong (:check-number-like args)) (catch Exception _ nil)) query (if (:exact-match-id args) {:query {:find '[?e] :in '[$ ?e [?c ...]] :where '[[?e :payment/client ?c]]} :args [db (:exact-match-id args) valid-clients]} (cond-> {:query {:find [] :in '[$ [?clients ?start ?end]] :where '[[(iol-ion.query/scan-payments $ ?clients ?start ?end) [[?e _ ?sort-default] ...]]]} :args [db [valid-clients (some-> (:start (:date-range args)) coerce/to-date) (some-> (:end (:date-range args)) coerce/to-date)]]} (:sort args) (add-sorter-fields {"client" ['[?e :payment/client ?c] '[?c :client/name ?sort-client]] "vendor" ['[?e :payment/vendor ?v] '[?v :vendor/name ?sort-vendor]] "bank-account" ['[?e :payment/bank-account ?ba] '[?ba :bank-account/name ?sort-bank-account]] "check-number" ['[(get-else $ ?e :payment/check-number 0) ?sort-check-number]] "date" ['[?e :payment/date ?sort-date]] "amount" ['[?e :payment/amount ?sort-amount]] "status" ['[?e :payment/status ?sort-status]]} args) (:exact-match-id args) (merge-query {:query {:in ['?e] :where []} :args [(:exact-match-id args)]}) (:vendor-id args) (merge-query {:query {:in ['?vendor-id] :where ['[?e :payment/vendor ?vendor-id]]} :args [(:vendor-id args)]}) (:original-id args) (merge-query {:query {:in ['?original-id] :where ['[?e :payment/client ?c] '[?c :client/original-id ?original-id]]} :args [(:original-id args)]}) (:check-number args) (merge-query {:query {:in ['?check-number] :where ['[?e :payment/check-number ?check-number]]} :args [(:check-number args)]}) (not-empty (:invoice-number args)) (merge-query {:query {:in ['?invoice-number] :where ['[?e :payment/invoices ?i] '[?i :invoice/invoice-number ?invoice-number]]} :args [(:invoice-number args)]}) (:bank-account-id args) (merge-query {:query {:in ['?bank-account-id] :where ['[?e :payment/bank-account ?bank-account-id]]} :args [(:bank-account-id args)]}) (:amount-gte args) (merge-query {:query {:in ['?amount-gte] :where ['[?e :payment/amount ?a] '[(>= ?a ?amount-gte)]]} :args [(:amount-gte args)]}) (:amount-lte args) (merge-query {:query {:in ['?amount-lte] :where ['[?e :payment/amount ?a] '[(<= ?a ?amount-lte)]]} :args [(:amount-lte args)]}) (:amount args) (merge-query {:query {:in ['?amount] :where ['[?e :payment/amount ?transaction-amount] '[(iol-ion.query/dollars= ?transaction-amount ?amount)]]} :args [(:amount args)]}) (:status args) (merge-query {:query {:in ['?status] :where ['[?e :payment/status ?status]]} :args [(:status args)]}) (:payment-type args) (merge-query {:query {:in '[?payment-type] :where ['[?e :payment/type ?payment-type]]} :args [(:payment-type args)]}) check-number-like (merge-query {:query {:in '[?check-number-like] :where ['[?e :payment/check-number ?check-number-like]]} :args [check-number-like]}) true (merge-query {:query {:find ['?sort-default '?e]}})))] (cond->> (observable-query query) true (apply-sort-3 (assoc args :default-asc? false)) true (apply-pagination args))))) (defn graphql-results [ids db _] (let [results (->> (pull-many db default-read ids) (group-by :db/id)) payments (->> ids (map results) (map first) (mapv <-datomic))] payments)) (defn get-graphql [args] (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])) (defn filter-ids [ids] (if ids (->> (dc/q {:find ['?e] :in ['$ '[?e ...]] :where ['[?e :payment/date]]} (dc/db conn) ids) (map first) vec) [])) (defn get-by-id [id] (->> (dc/pull (dc/db conn) default-read id) (<-datomic))) (defn pay [db e amount] (let [current-outstanding-balance (-> (dc/pull db [:invoice/outstanding-balance] e) :invoice/outstanding-balance) new-outstanding-balance (- current-outstanding-balance amount)] [[:db/add e :invoice/outstanding-balance new-outstanding-balance] [:db/add e :invoice/status (if (> new-outstanding-balance 0) :invoice-status/unpaid :invoice-status/paid)]]))