From 2a0f736af78dc6823fd5a067d9c96eed091acbc1 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Wed, 5 Apr 2023 22:50:38 -0700 Subject: [PATCH] makes POS page much less likely to break everything --- iol_ion/src/iol_ion/query.clj | 7 +- src/clj/auto_ap/backup.clj | 710 ++++++++++++----------- src/clj/auto_ap/datomic.clj | 18 + src/clj/auto_ap/datomic/sales_orders.clj | 191 ++---- src/clj/auto_ap/graphql/utils.clj | 2 + src/clj/auto_ap/pdf/ledger.clj | 14 +- 6 files changed, 441 insertions(+), 501 deletions(-) diff --git a/iol_ion/src/iol_ion/query.clj b/iol_ion/src/iol_ion/query.clj index 1bef212d..60945ce8 100644 --- a/iol_ion/src/iol_ion/query.clj +++ b/iol_ion/src/iol_ion/query.clj @@ -19,8 +19,11 @@ (localize (time/now))) -(defn recent-date [] - (coerce/to-date (time/minus (local-now) (time/days 90)))) +(defn recent-date + ([] + (recent-date 90)) + ([n] + (coerce/to-date (time/minus (local-now) (time/days n))))) (def excel-formatter (f/with-zone (f/formatter "MM/dd/yyyy") (time/time-zone-for-id "America/Los_Angeles"))) (defn excel-date [d] diff --git a/src/clj/auto_ap/backup.clj b/src/clj/auto_ap/backup.clj index 731bb0fc..5ca21b60 100644 --- a/src/clj/auto_ap/backup.clj +++ b/src/clj/auto_ap/backup.clj @@ -4,380 +4,381 @@ ;; You can also press C-u C-j to evaluate the expression and pretty-print its result. -(ns auto-ap.backup - (:require [datomic.api :as d] - [manifold.deferred :as de] - [manifold.executor :as ex] - [manifold.stream :as s] - [manifold.time :as mt] - [auto-ap.jobs.core :refer [execute]] - [clojure.java.io :as io] - [amazonica.aws.s3 :as s3] - [config.core :refer [env]] - [clojure.core.async :as a] - [lambdaisland.edn-lines :as ednl] - [clojure.set :as set] - [com.brunobonacci.mulog :as mu])) +(comment + (ns auto-ap.backup + (:require [datomic.api :as d] + [manifold.deferred :as de] + [manifold.executor :as ex] + [manifold.stream :as s] + [manifold.time :as mt] + [auto-ap.jobs.core :refer [execute]] + [clojure.java.io :as io] + [amazonica.aws.s3 :as s3] + [config.core :refer [env]] + [clojure.core.async :as a] + [lambdaisland.edn-lines :as ednl] + [clojure.set :as set] + [com.brunobonacci.mulog :as mu])) -(def request-pool (ex/fixed-thread-executor 30)) + (def request-pool (ex/fixed-thread-executor 30)) -(def buffered (ex/fixed-thread-executor 30)) + (def buffered (ex/fixed-thread-executor 30)) -(defn get-schema [remote-db] - (let [everything (->> (d/q '[:find [(pull ?e [:db/ident - {:db/valueType [:db/ident]} - {:db/cardinality [:db/ident]} - :db.attr/preds - {:db/unique [:db/ident]} - :db/isComponent - :db/id - :db/noHistory - :db/tupleAttrs - :db.entity/attrs - :db.entity/preds - :db/doc]) ...] - :where [?e :db/ident]] - remote-db)) - schema-attrs (->> everything - (filter :db/ident) - (filter (fn [{:db/keys [ident]}] - (if (namespace ident) - (re-matches #"^(?!cartographer)(?!db)(?!fressian).+" (namespace ident)) - true - )))) - meta-schema-schema (filter #(-> % :db/ident not) everything)] - schema-attrs)) + (defn get-schema [remote-db] + (let [everything (->> (d/q '[:find [(pull ?e [:db/ident + {:db/valueType [:db/ident]} + {:db/cardinality [:db/ident]} + :db.attr/preds + {:db/unique [:db/ident]} + :db/isComponent + :db/id + :db/noHistory + :db/tupleAttrs + :db.entity/attrs + :db.entity/preds + :db/doc]) ...] + :where [?e :db/ident]] + remote-db)) + schema-attrs (->> everything + (filter :db/ident) + (filter (fn [{:db/keys [ident]}] + (if (namespace ident) + (re-matches #"^(?!cartographer)(?!db)(?!fressian).+" (namespace ident)) + true + )))) + meta-schema-schema (filter #(-> % :db/ident not) everything)] + schema-attrs)) -(def entity->best-key - {"transaction-rule" - [:transaction-rule/description, :transaction-rule/note :transaction-rule/vendor] - "square-location" - :square-location/square-id, - "expected-deposit" - :expected-deposit/date, - "journal-entry-line" - [:journal-entry-line/account, :journal-entry-line/debit :journal-entry-line/credit] - "vendor" - [:vendor/name, :vendor/default-account, :vendor/hidden] - "transaction" - :transaction/amount, - "yodlee-provider-account" - :yodlee-provider-account/id, - "journal-entry" - :journal-entry/source, - "yodlee-merchant" :yodlee-merchant/yodlee-id, - "invoice" - :invoice/invoice-number, - "vendor-terms-override" - :vendor-terms-override/client, - "integration-status" - :integration-status/state, - "conformity" :conformity/conformed-norms-index, - "user" - :user/provider-id, - "sales-refund" - :sales-refund/total, - "plaid-account" - :plaid-account/name, - "charge" - [:charge/total, :charge/external-id] - "location-match" :location-match/location, - "vendor-schedule-payment-dom" - :vendor-schedule-payment-dom/dom, - "account-client-override" - :account-client-override/client, - "plaid-item" - :plaid-item/client, - "transaction-account" - :transaction-account/account, - "address" - [:address/street1, :address/city :address/state :address/zip] - "order-line-item" - :order-line-item/total, - "ezcater-location" [:ezcater-location/location, :ezcater-location/caterer] - "account" - [:account/numeric-code, :account/code :account/name :account/type] - "intuit-bank-account" - :intuit-bank-account/name, - "saved-query" - :saved-query/guid, - "ezcater-caterer" - :ezcater-caterer/uuid, - "forecasted-transaction" - :forecasted-transaction/day-of-month, - "audit" :audit/user, - "yodlee-account" - :yodlee-account/id, - "transaction-rule-account" - [:transaction-rule-account/account, :transaction-rule-account/location] - "ezcater-integration" - :ezcater-integration/subscriber-uuid, - "report" - :report/created, - "bank-account" - :bank-account/code, - "vendor-usage" - :vendor-usage/key, - "invoice-expense-account" - [:invoice-expense-account/expense-account-id, :invoice-expense-account/account :invoice-expense-account/location :invoice-expense-account/amount] - "sales-order" - :sales-order/date, - "client" - :client/code, - "email-contact" :email-contact/email, - "invoice-payment" - :invoice-payment/amount, - "contact" - [:contact/name, :contact/phone :contact/email] - "import-batch" - :import-batch/date, - "payment" - [:payment/date, :payment/bank-account] - "vendor-account-override" - :vendor-account-override/client}) + (def entity->best-key + {"transaction-rule" + [:transaction-rule/description, :transaction-rule/note :transaction-rule/vendor] + "square-location" + :square-location/square-id, + "expected-deposit" + :expected-deposit/date, + "journal-entry-line" + [:journal-entry-line/account, :journal-entry-line/debit :journal-entry-line/credit] + "vendor" + [:vendor/name, :vendor/default-account, :vendor/hidden] + "transaction" + :transaction/amount, + "yodlee-provider-account" + :yodlee-provider-account/id, + "journal-entry" + :journal-entry/source, + "yodlee-merchant" :yodlee-merchant/yodlee-id, + "invoice" + :invoice/invoice-number, + "vendor-terms-override" + :vendor-terms-override/client, + "integration-status" + :integration-status/state, + "conformity" :conformity/conformed-norms-index, + "user" + :user/provider-id, + "sales-refund" + :sales-refund/total, + "plaid-account" + :plaid-account/name, + "charge" + [:charge/total, :charge/external-id] + "location-match" :location-match/location, + "vendor-schedule-payment-dom" + :vendor-schedule-payment-dom/dom, + "account-client-override" + :account-client-override/client, + "plaid-item" + :plaid-item/client, + "transaction-account" + :transaction-account/account, + "address" + [:address/street1, :address/city :address/state :address/zip] + "order-line-item" + :order-line-item/total, + "ezcater-location" [:ezcater-location/location, :ezcater-location/caterer] + "account" + [:account/numeric-code, :account/code :account/name :account/type] + "intuit-bank-account" + :intuit-bank-account/name, + "saved-query" + :saved-query/guid, + "ezcater-caterer" + :ezcater-caterer/uuid, + "forecasted-transaction" + :forecasted-transaction/day-of-month, + "audit" :audit/user, + "yodlee-account" + :yodlee-account/id, + "transaction-rule-account" + [:transaction-rule-account/account, :transaction-rule-account/location] + "ezcater-integration" + :ezcater-integration/subscriber-uuid, + "report" + :report/created, + "bank-account" + :bank-account/code, + "vendor-usage" + :vendor-usage/key, + "invoice-expense-account" + [:invoice-expense-account/expense-account-id, :invoice-expense-account/account :invoice-expense-account/location :invoice-expense-account/amount] + "sales-order" + :sales-order/date, + "client" + :client/code, + "email-contact" :email-contact/email, + "invoice-payment" + :invoice-payment/amount, + "contact" + [:contact/name, :contact/phone :contact/email] + "import-batch" + :import-batch/date, + "payment" + [:payment/date, :payment/bank-account] + "vendor-account-override" + :vendor-account-override/client}) -#_(defn references [schema] - (filter (comp #{:db.type/ref} :db/ident :db/valueType) schema )) + #_(defn references [schema] + (filter (comp #{:db.type/ref} :db/ident :db/valueType) schema )) -#_(defn reference->entity [remote-db] - (->> (d/q '[:find ?a ?v3 - :in $ $$ [?a ...] - :where [$$ _ ?a ?e] - [$ ?e ?v _ _] - [$ ?v :db/ident ?v2 _ _] - [(namespace ?v2) ?v3] - [(namespace ?v2) ?v3]] - remote-db - (d/since remote-db #inst "2022-06-01") - (map :db/ident references) - ) - (group-by first) - (map (fn [[k v]] - [k (disj (set (map second v)) "db")])) - (into {}))) + #_(defn reference->entity [remote-db] + (->> (d/q '[:find ?a ?v3 + :in $ $$ [?a ...] + :where [$$ _ ?a ?e] + [$ ?e ?v _ _] + [$ ?v :db/ident ?v2 _ _] + [(namespace ?v2) ?v3] + [(namespace ?v2) ?v3]] + remote-db + (d/since remote-db #inst "2022-06-01") + (map :db/ident references) + ) + (group-by first) + (map (fn [[k v]] + [k (disj (set (map second v)) "db")])) + (into {}))) -#_(def manual-dependencies - {:client/location-matches #{"location-match"} - :transaction/yodlee-merchant #{"yodlee-merchant"} - :vendor-account-override/account #{"account"} - :vendor-account-override/client #{"client"} - :vendor/secondary-contact #{"contact"} - :vendor/account-overrides #{"vendor-account-override"} - :client/bank-accounts #{"bank-account"} - :transaction-rule/yodlee-merchant #{"yodlee-merchant"} - :client/forecasted-transactions #{"forecasted-transaction"} - :transaction/forecast-match #{"forecasted-transaction"} - :vendor/automatically-paid-when-due #{"client"} - :vendor/schedule-payment-dom #{"vendor-schedule-payment-dom"} - :vendor/terms-overrides #{"vendor-terms-override"} - :vendor-schedule-payment-dom/client #{"client"}}) + #_(def manual-dependencies + {:client/location-matches #{"location-match"} + :transaction/yodlee-merchant #{"yodlee-merchant"} + :vendor-account-override/account #{"account"} + :vendor-account-override/client #{"client"} + :vendor/secondary-contact #{"contact"} + :vendor/account-overrides #{"vendor-account-override"} + :client/bank-accounts #{"bank-account"} + :transaction-rule/yodlee-merchant #{"yodlee-merchant"} + :client/forecasted-transactions #{"forecasted-transaction"} + :transaction/forecast-match #{"forecasted-transaction"} + :vendor/automatically-paid-when-due #{"client"} + :vendor/schedule-payment-dom #{"vendor-schedule-payment-dom"} + :vendor/terms-overrides #{"vendor-terms-override"} + :vendor-schedule-payment-dom/client #{"client"}}) -#_(defn full-dependencies [remote-db] - (update (merge-with into (reference->entity remote-db) manual-dependencies) - :journal-entry/original-entity - #(disj % "journal-entry"))) + #_(defn full-dependencies [remote-db] + (update (merge-with into (reference->entity remote-db) manual-dependencies) + :journal-entry/original-entity + #(disj % "journal-entry"))) -#_(defn entity-dependencies [schema] - (let [base-dependencies - (into - {} - (map (fn [i] - [i #{}]) - (set (map (comp namespace :db/ident) - (filter :db/valueType - schema)))) - ) - ] - (into base-dependencies (reduce - (fn [acc [ref deps]] - (update acc (namespace ref) (fnil #(into % deps) #{}))) - {} - (full-dependencies remote-db))))) + #_(defn entity-dependencies [schema] + (let [base-dependencies + (into + {} + (map (fn [i] + [i #{}]) + (set (map (comp namespace :db/ident) + (filter :db/valueType + schema)))) + ) + ] + (into base-dependencies (reduce + (fn [acc [ref deps]] + (update acc (namespace ref) (fnil #(into % deps) #{}))) + {} + (full-dependencies remote-db))))) -(def full-dependencies - {:invoice/client #{"client"}, - :sales-order/client #{"client"}, - :transaction-rule/transaction-approval-status #{}, - :transaction/forecast-match #{"forecasted-transaction"}, - :user/role #{}, - :vendor-schedule-payment-dom/client #{"client"}, - :invoice-payment/payment #{"payment"}, - :transaction-rule/client #{"client"}, - :invoice/status #{}, - :payment/type #{}, - :expected-deposit/client #{"client"}, - :transaction/bank-account #{"bank-account"}, - :transaction-rule-account/account #{"account"}, - :import-batch/status #{}, - :user/clients #{"client"}, - :payment/client #{"client"}, - :expected-deposit/charges #{"charge"}, - :vendor/automatically-paid-when-due #{"client"}, - :payment/invoices #{"invoice"}, - :client/forecasted-transactions #{"forecasted-transaction"}, - :transaction/matched-rule #{"transaction-rule"}, - :invoice/import-status #{}, - :charge/processor #{}, - :expected-deposit/vendor #{"vendor"}, - :client/square-locations #{"square-location"}, - :payment/status #{}, - :client/location-matches #{"location-match"}, - :saved-query/client #{"client"}, - :transaction/payment #{"payment"}, - :transaction-rule/vendor #{"vendor"}, - :plaid-item/client #{"client"}, - :account/applicability #{}, - :journal-entry-line/account #{"account" "bank-account"}, - :client/bank-accounts #{"bank-account"}, - :yodlee-provider-account/client #{"client"}, - :account/vendor-allowance #{}, - :payment/bank-account #{"bank-account"}, - :account/default-allowance #{}, - :transaction-rule/yodlee-merchant #{"yodlee-merchant"}, - :vendor/account-overrides #{"vendor-account-override"}, - :transaction/client #{"client"}, - :invoice/vendor #{"vendor"}, - :sales-order/vendor #{"vendor"}, - :expected-deposit/status #{}, - :journal-entry/original-entity #{"transaction" "invoice"}, - :vendor-usage/client #{"client"}, - :transaction/expected-deposit #{"expected-deposit"}, - :client/ezcater-locations #{"ezcater-location"}, - :journal-entry/client #{"client"}, - :vendor/secondary-contact #{"contact"}, - :journal-entry/line-items #{"journal-entry-line"}, - :vendor/legal-entity-1099-type #{}, - :transaction-rule/bank-account #{"bank-account"}, - :transaction-account/account #{"account"}, - :vendor/terms-overrides #{"vendor-terms-override"}, - :vendor/default-account #{"account"}, - :transaction/yodlee-merchant #{"yodlee-merchant"}, - :sales-refund/client #{"client"}, - :client/emails #{"email-contact"}, - :payment/vendor #{"vendor"}, - :invoice-payment/invoice #{"invoice"}, - :report/client #{"client"}, - :transaction-rule/accounts #{"transaction-rule-account"}, - :charge/client #{"client"}, - :bank-account/type #{}, - :invoice-expense-account/account #{"account"}, - :vendor/legal-entity-tin-type #{}, - :transaction/approval-status #{}, - :import-batch/entry #{"transaction"}, - :bank-account/intuit-bank-account #{"intuit-bank-account"}, - :account/type #{}, - :sales-refund/vendor #{"vendor"}, - :bank-account/yodlee-account #{"yodlee-account"}, - :vendor/address #{"address"}, - :integration-status/state #{}, - :transaction/accounts #{"transaction-account"}, - :sales-order/charges #{"charge"}, - :client/address #{"address"}, - :ezcater-location/caterer #{"ezcater-caterer"}, - :vendor-account-override/client #{"client"}, - :bank-account/integration-status #{"integration-status"}, - :yodlee-provider-account/accounts #{"yodlee-account"}, - :account/invoice-allowance #{}, - :journal-entry/vendor #{"vendor"}, - :plaid-item/accounts #{"plaid-account"}, - :vendor-usage/vendor #{"vendor"}, - :sales-order/line-items #{"order-line-item"}, - :invoice/expense-accounts #{"invoice-expense-account"}, - :account-client-override/client #{"client"}, - :vendor/primary-contact #{"contact"}, - :vendor/schedule-payment-dom #{"vendor-schedule-payment-dom"}, - :account/client-overrides #{"account-client-override"}, - :transaction/vendor #{"vendor"}, - :client/square-integration-status #{"integration-status"}, - :ezcater-integration/caterers #{"ezcater-caterer"}, - :ezcater-integration/integration-status #{"integration-status"} - :vendor-account-override/account #{"account"}, - :import-batch/source #{}}) + (def full-dependencies + {:invoice/client #{"client"}, + :sales-order/client #{"client"}, + :transaction-rule/transaction-approval-status #{}, + :transaction/forecast-match #{"forecasted-transaction"}, + :user/role #{}, + :vendor-schedule-payment-dom/client #{"client"}, + :invoice-payment/payment #{"payment"}, + :transaction-rule/client #{"client"}, + :invoice/status #{}, + :payment/type #{}, + :expected-deposit/client #{"client"}, + :transaction/bank-account #{"bank-account"}, + :transaction-rule-account/account #{"account"}, + :import-batch/status #{}, + :user/clients #{"client"}, + :payment/client #{"client"}, + :expected-deposit/charges #{"charge"}, + :vendor/automatically-paid-when-due #{"client"}, + :payment/invoices #{"invoice"}, + :client/forecasted-transactions #{"forecasted-transaction"}, + :transaction/matched-rule #{"transaction-rule"}, + :invoice/import-status #{}, + :charge/processor #{}, + :expected-deposit/vendor #{"vendor"}, + :client/square-locations #{"square-location"}, + :payment/status #{}, + :client/location-matches #{"location-match"}, + :saved-query/client #{"client"}, + :transaction/payment #{"payment"}, + :transaction-rule/vendor #{"vendor"}, + :plaid-item/client #{"client"}, + :account/applicability #{}, + :journal-entry-line/account #{"account" "bank-account"}, + :client/bank-accounts #{"bank-account"}, + :yodlee-provider-account/client #{"client"}, + :account/vendor-allowance #{}, + :payment/bank-account #{"bank-account"}, + :account/default-allowance #{}, + :transaction-rule/yodlee-merchant #{"yodlee-merchant"}, + :vendor/account-overrides #{"vendor-account-override"}, + :transaction/client #{"client"}, + :invoice/vendor #{"vendor"}, + :sales-order/vendor #{"vendor"}, + :expected-deposit/status #{}, + :journal-entry/original-entity #{"transaction" "invoice"}, + :vendor-usage/client #{"client"}, + :transaction/expected-deposit #{"expected-deposit"}, + :client/ezcater-locations #{"ezcater-location"}, + :journal-entry/client #{"client"}, + :vendor/secondary-contact #{"contact"}, + :journal-entry/line-items #{"journal-entry-line"}, + :vendor/legal-entity-1099-type #{}, + :transaction-rule/bank-account #{"bank-account"}, + :transaction-account/account #{"account"}, + :vendor/terms-overrides #{"vendor-terms-override"}, + :vendor/default-account #{"account"}, + :transaction/yodlee-merchant #{"yodlee-merchant"}, + :sales-refund/client #{"client"}, + :client/emails #{"email-contact"}, + :payment/vendor #{"vendor"}, + :invoice-payment/invoice #{"invoice"}, + :report/client #{"client"}, + :transaction-rule/accounts #{"transaction-rule-account"}, + :charge/client #{"client"}, + :bank-account/type #{}, + :invoice-expense-account/account #{"account"}, + :vendor/legal-entity-tin-type #{}, + :transaction/approval-status #{}, + :import-batch/entry #{"transaction"}, + :bank-account/intuit-bank-account #{"intuit-bank-account"}, + :account/type #{}, + :sales-refund/vendor #{"vendor"}, + :bank-account/yodlee-account #{"yodlee-account"}, + :vendor/address #{"address"}, + :integration-status/state #{}, + :transaction/accounts #{"transaction-account"}, + :sales-order/charges #{"charge"}, + :client/address #{"address"}, + :ezcater-location/caterer #{"ezcater-caterer"}, + :vendor-account-override/client #{"client"}, + :bank-account/integration-status #{"integration-status"}, + :yodlee-provider-account/accounts #{"yodlee-account"}, + :account/invoice-allowance #{}, + :journal-entry/vendor #{"vendor"}, + :plaid-item/accounts #{"plaid-account"}, + :vendor-usage/vendor #{"vendor"}, + :sales-order/line-items #{"order-line-item"}, + :invoice/expense-accounts #{"invoice-expense-account"}, + :account-client-override/client #{"client"}, + :vendor/primary-contact #{"contact"}, + :vendor/schedule-payment-dom #{"vendor-schedule-payment-dom"}, + :account/client-overrides #{"account-client-override"}, + :transaction/vendor #{"vendor"}, + :client/square-integration-status #{"integration-status"}, + :ezcater-integration/caterers #{"ezcater-caterer"}, + :ezcater-integration/integration-status #{"integration-status"} + :vendor-account-override/account #{"account"}, + :import-batch/source #{}}) -(def entity-dependencies - {"transaction-rule" - #{"vendor" "yodlee-merchant" "transaction-rule-account" "bank-account" - "client"}, - "square-location" #{}, - "expected-deposit" #{"vendor" "charge" "client"}, - "journal-entry-line" #{"account" "bank-account"}, - "vendor" - #{"vendor-schedule-payment-dom" "address" "account" "client" "contact" - "vendor-account-override"}, - "transaction" - #{"transaction-rule" "expected-deposit" "vendor" "yodlee-merchant" - "transaction-account" "forecasted-transaction" "bank-account" "client" - "payment"}, - "yodlee-provider-account" #{"yodlee-account" "client"}, - "journal-entry" - #{"journal-entry-line" "vendor" "transaction" "invoice" "client"}, - "yodlee-merchant" #{}, - "invoice" #{"vendor" "invoice-expense-account" "client"}, - "vendor-terms-override" #{}, - "integration-status" #{}, - "conformity" #{}, - "user" #{"client"}, - "sales-refund" #{"vendor" "client"}, - "plaid-account" #{}, - "charge" #{"client"}, - "location-match" #{}, - "vendor-schedule-payment-dom" #{"client"}, - "account-client-override" #{"client"}, - "plaid-item" #{"plaid-account" "client"}, - "transaction-account" #{"account"}, - "address" #{}, - "order-line-item" #{}, - "ezcater-location" #{"ezcater-caterer"}, - "account" #{"account-client-override"}, - "intuit-bank-account" #{}, - "saved-query" #{"client"}, - "ezcater-caterer" #{}, - "forecasted-transaction" #{}, - "audit" #{}, - "yodlee-account" #{}, - "transaction-rule-account" #{"account"}, - "ezcater-integration" #{"ezcater-caterer" "integration-status"}, - "report" #{"client"}, - "bank-account" #{"integration-status" "intuit-bank-account" "yodlee-account"}, - "vendor-usage" #{"vendor" "client"}, - "invoice-expense-account" #{"account"}, - "sales-order" #{"vendor" "charge" "order-line-item" "client"}, - "client" - #{"square-location" "integration-status" "location-match" "address" - "ezcater-location" "forecasted-transaction" "bank-account" "email-contact"}, - "email-contact" #{}, - "invoice-payment" #{"invoice" "payment"}, - "contact" #{}, - "import-batch" #{"transaction"}, - "payment" #{"vendor" "invoice" "bank-account" "client"}, - "vendor-account-override" #{"account" "client"}}) + (def entity-dependencies + {"transaction-rule" + #{"vendor" "yodlee-merchant" "transaction-rule-account" "bank-account" + "client"}, + "square-location" #{}, + "expected-deposit" #{"vendor" "charge" "client"}, + "journal-entry-line" #{"account" "bank-account"}, + "vendor" + #{"vendor-schedule-payment-dom" "address" "account" "client" "contact" + "vendor-account-override"}, + "transaction" + #{"transaction-rule" "expected-deposit" "vendor" "yodlee-merchant" + "transaction-account" "forecasted-transaction" "bank-account" "client" + "payment"}, + "yodlee-provider-account" #{"yodlee-account" "client"}, + "journal-entry" + #{"journal-entry-line" "vendor" "transaction" "invoice" "client"}, + "yodlee-merchant" #{}, + "invoice" #{"vendor" "invoice-expense-account" "client"}, + "vendor-terms-override" #{}, + "integration-status" #{}, + "conformity" #{}, + "user" #{"client"}, + "sales-refund" #{"vendor" "client"}, + "plaid-account" #{}, + "charge" #{"client"}, + "location-match" #{}, + "vendor-schedule-payment-dom" #{"client"}, + "account-client-override" #{"client"}, + "plaid-item" #{"plaid-account" "client"}, + "transaction-account" #{"account"}, + "address" #{}, + "order-line-item" #{}, + "ezcater-location" #{"ezcater-caterer"}, + "account" #{"account-client-override"}, + "intuit-bank-account" #{}, + "saved-query" #{"client"}, + "ezcater-caterer" #{}, + "forecasted-transaction" #{}, + "audit" #{}, + "yodlee-account" #{}, + "transaction-rule-account" #{"account"}, + "ezcater-integration" #{"ezcater-caterer" "integration-status"}, + "report" #{"client"}, + "bank-account" #{"integration-status" "intuit-bank-account" "yodlee-account"}, + "vendor-usage" #{"vendor" "client"}, + "invoice-expense-account" #{"account"}, + "sales-order" #{"vendor" "charge" "order-line-item" "client"}, + "client" + #{"square-location" "integration-status" "location-match" "address" + "ezcater-location" "forecasted-transaction" "bank-account" "email-contact"}, + "email-contact" #{}, + "invoice-payment" #{"invoice" "payment"}, + "contact" #{}, + "import-batch" #{"transaction"}, + "payment" #{"vendor" "invoice" "bank-account" "client"}, + "vendor-account-override" #{"account" "client"}}) -(defn order-of-insert [entity-dependencies] - (loop [entity-dependencies entity-dependencies - order []] - (let [next-order (for [[entity deps] entity-dependencies - :when (not (seq deps))] - entity) - next-deps (reduce - (fn [entity-dependencies next-entity] - (into {} - (map - (fn [[k v]] - [k (disj v next-entity)]) - entity-dependencies))) - (apply dissoc entity-dependencies next-order) - next-order)] - (if (seq next-deps) - (recur next-deps (into order next-order)) - (into order next-order))))) + (defn order-of-insert [entity-dependencies] + (loop [entity-dependencies entity-dependencies + order []] + (let [next-order (for [[entity deps] entity-dependencies + :when (not (seq deps))] + entity) + next-deps (reduce + (fn [entity-dependencies next-entity] + (into {} + (map + (fn [[k v]] + [k (disj v next-entity)]) + entity-dependencies))) + (apply dissoc entity-dependencies next-order) + next-order)] + (if (seq next-deps) + (recur next-deps (into order next-order)) + (into order next-order))))) (def loaded (atom #{})) @@ -526,3 +527,4 @@ :service "export-backup") (Thread/sleep 5000) (throw e)))) +) diff --git a/src/clj/auto_ap/datomic.clj b/src/clj/auto_ap/datomic.clj index ed6f3eae..cd2aa2f4 100644 --- a/src/clj/auto_ap/datomic.clj +++ b/src/clj/auto_ap/datomic.clj @@ -853,3 +853,21 @@ :status "WARN") (transact-with-backoff tx (inc attempt))) (throw e)))))) + +(defn visible-clients [id] + (cond + (= (:user/role id) "none") + #{} + + (= (:user/role id) "admin") + (->> (dc/q '[:find (pull ?e [:db/id :client/code]) + :in $ + :where [?e :client/code]] + (dc/db conn)) + (map first) + (map :db/id) + (into #{})) + + (#{"manager" "user" "power-user"} (:user/role id)) + (into #{} + (map :db/id (:user/clients id []))))) diff --git a/src/clj/auto_ap/datomic/sales_orders.clj b/src/clj/auto_ap/datomic/sales_orders.clj index add87462..e9d20b03 100644 --- a/src/clj/auto_ap/datomic/sales_orders.clj +++ b/src/clj/auto_ap/datomic/sales_orders.clj @@ -4,11 +4,14 @@ :refer [add-sorter-fields-2 apply-pagination apply-sort-3 + pull-id merge-query pull-many + visible-clients conn]] [auto-ap.graphql.utils :refer [limited-clients]] [clj-time.coerce :as c] + [clj-time.core :as time] [clojure.set :as set] [clojure.tools.logging :as log] [datomic.client.api :as dc] @@ -30,132 +33,45 @@ {:sales-order/client [:client/name :db/id :client/code] :sales-order/charges [* {:charge/processor [:db/ident]} {:expected-deposit/_charges [:db/id]}]}]) -#_(defn client-index-search [db attr client-ids [start end]] - (for [c client-ids - d - (dc/q '[:find ?e - :in $ ?start ?end - :where [?e :sales-order/client+date ?g] - [(>= ?g ?start)] - [(<= ?g ?end)]] - db [c start] [c end]) - - #_(dc/index-range db {:attrid attr - :start [c start] - :end [c end]})] - (first d))) - -#_(comment - (do - (println "starting") - (doseq [n (partition-all 500 (dc/q '[:find ?s ?d - :where [?s :sales-order/date ?d]] - (dc/db conn)))] - (print ".") - (dc/transact conn {:tx-data (map (fn [[n d]] {:db/id n :sales-order/date d}) n)})) - (println "done")) - - - (time (count (client-index-search (dc/db conn) - :sales-order/client+date - [3575611821801781] - [#inst "2021-05-21T18:06:02.000-00:00" - #inst "2022-09-25T18:06:02.000-00:00"] - ))) - - (time (count (dc/q '[:find ?e - :in $ ?client ?start ?end - :where [?e :sales-order/client ?client] - [?e :sales-order/date ?date] - [(>= ?date ?start)] - [(<= ?date ?end)]] - (dc/db conn) - 3575611821801781 - - #inst "2021-05-21T18:06:02.000-00:00" - #inst "2022-09-25T18:06:02.000-00:00" - ))) - - (time (do (count (dc/q '[:find ?e, - :in $ [[?s1 ?e1]] - :where - #_[(untuple ?period) [?s1 ?e1]] - [(q '[:find ?e - :in $ ?s1 ?e1 - :where [?e :sales-order/client+date ?g] - [(>= ?g ?s1)] - [(<= ?g ?e1)]] - $ ?s1 ?e1) [?e ...]] - ] - (dc/db conn) [[[3575611821801781 #inst "2022-08-21T18:06:02.000-00:00" ] [3575611821801781 #inst "2022-09-25T18:06:02.000-00:00"]] - [[3575611821801766 #inst "2022-08-21T18:06:02.000-00:00" ] [3575611821801766 #inst "2022-09-25T18:06:02.000-00:00"]]])) - (println "done"))) - - (dc/index-range (dc/db conn) {:attrid :sales-order/date+client3 - :start [#inst "2022-08-25T18:06:02.000-00:00" ] - :end [#inst "2022-08-25T20:06:02.000-00:00" ]}) - (dc/pull (dc/db conn) '[*] :sales-order/date+client3) - (dc/pull (dc/db conn) '[*] 5040161313201309) - - #_(time (do (dc/q {:query '{:find [(count ?x)], - :in [$ ?client-id], - :where [[?e :sales-order/date+client3 ?x]]}, - :args [(dc/db conn) 3575611821801781]}) - (println "done"))) - - #_(datomic.dev-local.async/return-1) - - (clojure.core.async/ {:query {:find [] - :in ['$] + (let [visible-clients (visible-clients (:id args)) + selected-clients (->> (cond + (:client-id args) + (set/intersection #{(:client-id args)} + visible-clients) + + + (:client-code args) + (set/intersection #{(pull-id db [:client/code (:client-code args)])} + visible-clients) + + :else + visible-clients) + (take 3) + set) + _ (mu/log ::selected-clients + :selected-clients selected-clients) + query (cond-> {:query {:find [] + :in ['$ '[?c ...]] :where []} - :args [db]} - (:sort args) (add-sorter-fields-2 {"client" ['[?e :sales-order/client ?c] - '[?c :client/name ?sort-client]] - "location" ['[?e :sales-order/location ?sort-location]] - "source" ['[?e :sales-order/source ?sort-source]] - "date" ['[?e :sales-order/date ?sort-date]] - "total" ['[?e :sales-order/total ?sort-total]] - "tax" ['[?e :sales-order/tax ?sort-tax]] - "tip" ['[?e :sales-order/tip ?sort-tip]]} + :args [db selected-clients]} + + + true + (merge-query {:query {:in ['?start-date '?end-date] + :where '[[(iol-ion.query/sales-orders-in-range $ ?c ?start-date ?end-date) [?e ...]]]} + :args [(or (some-> (:start (:date-range args)) c/to-date) (iol-ion.query/recent-date 5)) + (or (some-> (:end (:date-range args)) c/to-date ) + (c/to-date (time/now)))]}) + (:sort args) (add-sorter-fields-2 {"client" ['[?e :sales-order/client ?c] + '[?c :client/name ?sort-client]] + "location" ['[?e :sales-order/location ?sort-location]] + "source" ['[?e :sales-order/source ?sort-source]] + "date" ['[?e :sales-order/date ?sort-date]] + "total" ['[?e :sales-order/total ?sort-total]] + "tax" ['[?e :sales-order/tax ?sort-tax]] + "tip" ['[?e :sales-order/tip ?sort-tip]]} args) - - (:start (:date-range args)) - (merge-query {:query {:in '[?start-date] - :where ['[?e :sales-order/date ?date] - '[(>= ?date ?start-date)]]} - :args [(c/to-date (:start (:date-range args)))]}) - - (:end (:date-range args)) - (merge-query {:query {:in '[?end-date] - :where ['[?e :sales-order/date ?date] - '[(<= ?date ?end-date)]]} - :args [(c/to-date (:end (:date-range args)))]}) - - (limited-clients (:id args)) - (merge-query {:query {:in ['[?xx ...]] - :where ['[?e :sales-order/client ?xx]]} - :args [(set (map :db/id (limited-clients (:id args))))]}) - - (:client-id args) - (merge-query {:query {:in ['?client-id] - :where ['[?e :sales-order/client ?client-id]]} - :args [(:client-id args)]}) - (:client-code args) - (merge-query {:query {:in ['?client-code] - :where ['[?e :sales-order/client ?client-id] - '[?client-id :client/code ?client-code]]} - :args [(:client-code args)]}) - (:category args) (merge-query {:query {:in ['?category] :where ['[?e :sales-order/line-items ?li] @@ -163,11 +79,11 @@ :args [(:category args)]}) (:processor args) - (merge-query {:query {:in ['?processor] + (merge-query {:query {:in ['?processor] :where ['[?e :sales-order/charges ?chg] '[?chg :charge/processor ?processor]]} - :args [(keyword "ccp-processor" - (name (:processor args)))]}) + :args [(keyword "ccp-processor" + (name (:processor args)))]}) (:type-name args) (merge-query {:query {:in ['?type-name] :where ['[?e :sales-order/charges ?chg] @@ -175,28 +91,27 @@ :args [(:type-name args)]}) (:total-gte args) - (merge-query {:query {:in ['?total-gte] + (merge-query {:query {:in ['?total-gte] :where ['[?e :sales-order/total ?a] '[(>= ?a ?total-gte)]]} - :args [(:total-gte args)]}) + :args [(:total-gte args)]}) (:total-lte args) - (merge-query {:query {:in ['?total-lte] + (merge-query {:query {:in ['?total-lte] :where ['[?e :sales-order/total ?a] '[(<= ?a ?total-lte)]]} - :args [(:total-lte args)]}) + :args [(:total-lte args)]}) (:total args) - (merge-query {:query {:in ['?total] + (merge-query {:query {:in ['?total] :where ['[?e :sales-order/total ?sales-order-total] '[(iol-ion.query/dollars= ?sales-order-total ?total)]]} - :args [(:total args)]}) + :args [(:total args)]}) true - (merge-query {:query {:find ['?date '?e] + (merge-query {:query {:find ['?date '?e] :where ['[?e :sales-order/date ?date]]}}))] - (println query) (mu/log ::query-stats :stats (:query-stats (dc/q (assoc query :query-stats true))) :q (str query)) @@ -207,12 +122,12 @@ true (apply-pagination args)))) (defn graphql-results [ids db _] - (let [results (->> (pull-many db default-read ids) + (let [results (->> (pull-many db default-read ids) (group-by :db/id)) payments (->> ids - (map results) - (map first) - (mapv <-datomic))] + (map results) + (map first) + (mapv <-datomic))] payments)) (defn summarize-orders [ids] diff --git a/src/clj/auto_ap/graphql/utils.clj b/src/clj/auto_ap/graphql/utils.clj index e04ab46a..47db75c5 100644 --- a/src/clj/auto_ap/graphql/utils.clj +++ b/src/clj/auto_ap/graphql/utils.clj @@ -98,6 +98,8 @@ (#{"manager" "user" "power-user"} (:user/role id)) (:user/clients id []))) + + (defn result->page [results result-count key args] {key (map ->graphql results) :total result-count diff --git a/src/clj/auto_ap/pdf/ledger.clj b/src/clj/auto_ap/pdf/ledger.clj index a17f3502..421bf2f3 100644 --- a/src/clj/auto_ap/pdf/ledger.clj +++ b/src/clj/auto_ap/pdf/ledger.clj @@ -363,13 +363,13 @@ :input-stream (io/make-input-stream pdf-data {}) :metadata {:content-length (count pdf-data) :content-type "application/pdf"}) - @(d/transact conn - [{:report/name name - :report/client (:client_ids args) - :report/key key - :report/url url - :report/creator (:user user) - :report/created (java.util.Date.)}]) + (dc/transact conn + {:tx-data [{:report/name name + :report/client (:client_ids args) + :report/key key + :report/url url + :report/creator (:user user) + :report/created (java.util.Date.)}]}) {:report/name name :report/url url }))