From 1832aad33554a8f619aab8c7dab8fd9f41c8a376 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Wed, 26 Aug 2020 06:31:49 -0700 Subject: [PATCH] added start date. --- src/clj/auto_ap/datomic/clients.clj | 4 +- src/clj/auto_ap/datomic/migrate.clj | 438 +++++++++--------- src/clj/auto_ap/graphql.clj | 2 + src/clj/auto_ap/graphql/clients.clj | 4 +- src/clj/auto_ap/yodlee/import.clj | 11 +- src/cljs/auto_ap/events.cljs | 4 +- .../views/pages/admin/clients/form.cljs | 27 +- test/clj/auto_ap/yodlee/import.clj | 45 +- 8 files changed, 293 insertions(+), 242 deletions(-) diff --git a/src/clj/auto_ap/datomic/clients.clj b/src/clj/auto_ap/datomic/clients.clj index 4780d55d..500159ee 100644 --- a/src/clj/auto_ap/datomic/clients.clj +++ b/src/clj/auto_ap/datomic/clients.clj @@ -1,7 +1,8 @@ (ns auto-ap.datomic.clients (:require [datomic.api :as d] [auto-ap.datomic :refer [uri]] - [clojure.tools.logging :as log])) + [clojure.tools.logging :as log] + [clj-time.coerce :as coerce])) (defn cleanse [e] (-> e @@ -13,6 +14,7 @@ (map (fn [i ba] (-> ba (update :bank-account/type :db/ident ) + (update :bank-account/start-date #(some-> % (coerce/to-date-time))) (update :bank-account/sort-order (fn [so] (or so i))))) (range) bas))))) (defn get-all [] diff --git a/src/clj/auto_ap/datomic/migrate.clj b/src/clj/auto_ap/datomic/migrate.clj index ddfe5f3c..c3439277 100644 --- a/src/clj/auto_ap/datomic/migrate.clj +++ b/src/clj/auto_ap/datomic/migrate.clj @@ -6,6 +6,7 @@ [auto-ap.datomic.migrate.invoice-converter :refer [add-import-status-existing-invoices]] [auto-ap.datomic.migrate.add-general-ledger :as add-general-ledger] [auto-ap.datomic.migrate.sales :as sales] + [auto-ap.datomic.migrate.clients :as clients] [clojure.java.io :as io] [io.rkn.conformity :as c]) @@ -94,228 +95,229 @@ (let [ conn (d/connect uri) - norms-map {:auto-ap/base-schema {:txes auto-ap.datomic/base-schema} - :auto-ap/functions {:txes-fn 'auto-ap.datomic.migrate/functions - :requires [:auto-ap/base-schema]} - :auto-ap/fx-pay-function-2 {:txes-fn 'auto-ap.datomic.migrate/fix-pay-function - :requires [:auto-ap/functions]} - :auto-ap/migrate-vendors {:txes-fn 'auto-ap.datomic/migrate-vendors - :requires [:auto-ap/base-schema]} - :auto-ap/migrate-clients {:txes-fn 'auto-ap.datomic/migrate-clients - :requires [:auto-ap/migrate-vendors]} - :auto-ap/migrate-users {:txes-fn 'auto-ap.datomic/migrate-users - :requires [:auto-ap/migrate-clients]} - :auto-ap/migrate-invoices {:txes-fn 'auto-ap.datomic/migrate-invoices - :requires [:auto-ap/migrate-vendors :auto-ap/migrate-clients]} - :auto-ap/migrate-payments {:txes-fn 'auto-ap.datomic/migrate-payments - :requires [:auto-ap/migrate-invoices]} - :auto-ap/migrate-invoices-payments {:txes-fn 'auto-ap.datomic/migrate-invoices-payments - :requires [:auto-ap/migrate-payments :auto-ap/migrate-invoices]} - :auto-ap/migrate-invoices-expense-accounts {:txes-fn 'auto-ap.datomic/migrate-invoices-expense-accounts - :requires [:auto-ap/migrate-invoices-payments]} - :auto-ap/migrate-transactions {:txes-fn 'auto-ap.datomic/migrate-transactions - :requires [:auto-ap/migrate-invoices-expense-accounts]} - :auto-ap/add-client-codes {:txes-fn 'auto-ap.datomic.migrate.add-client-codes/add-client-codes - :requires [:auto-ap/migrate-transactions]} - :auto-ap/add-bank-account-codes-schema {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes-schema - :requires [:auto-ap/add-client-codes]} - :auto-ap/add-bank-account-codes {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes - :requires [:auto-ap/add-bank-account-codes-schema]} - :auto-ap/add-nick-the-greek {:txes [[{:client/name "Nick the Greek" :client/code "NGAK" :client/locations ["MH"] :client/bank-accounts [{:bank-account/code "NGAK-0" :bank-account/type :bank-account-type/cash :bank-account/name "Cash"}]}]] - :requires [:auto-ap/add-bank-account-codes]} - :auto-ap/rename-codes-1 {:txes-fn 'auto-ap.datomic.migrate.rename-codes/rename-codes-1 - :requires [:auto-ap/add-nick-the-greek]} - :auto-ap/invoice-converter {:txes auto-ap.datomic.migrate.invoice-converter/add-matches - :requires [:auto-ap/rename-codes-1]} - :auto-ap/starter {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-starter - :requires [:auto-ap/invoice-converter]} - :auto-ap/add-default-location {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-default-location - :requires [:auto-ap/invoice-converter]} - :auto-ap/add-default-location-2 {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-default-location-2 - :requires [:auto-ap/add-default-location]} - :auto-ap/add-import-status {:txes auto-ap.datomic.migrate.invoice-converter/add-import-status - :requires [:auto-ap/add-default-location-2]} - :auto-ap/add-import-status-existing-invoices {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-import-status-existing-invoices - :requires [:auto-ap/add-import-status]} - :auto-ap/fix-check-numbers {:txes-fn 'auto-ap.datomic.migrate.check-numbers/fix-check-numbers - :requires [:auto-ap/add-import-status-existing-invoices]} - :auto-ap/add-new-vendors {:txes-fn 'auto-ap.datomic.migrate.add-new-vendors/add-new-vendors - :requires [:auto-ap/fix-check-numbers]} - :auto-ap/add-account-visibility-fields {:txes-fn 'auto-ap.datomic.migrate.account-sorting/add-account-visibility-fields - :requires [:auto-ap/add-new-vendors]} - :auto-ap/make-every-account-visible {:txes-fn 'auto-ap.datomic.migrate.account-sorting/make-every-account-visible - :requires [:auto-ap/add-account-visibility-fields]} - :auto-ap/add-general-ledger6 {:txes add-general-ledger/add-general-ledger - :requires [:auto-ap/make-every-account-visible]} - :auto-ap/add-general-ledger-fns2 {:txes-fn 'auto-ap.datomic.migrate.add-general-ledger/add-general-ledger-fns - :requires [:auto-ap/add-general-ledger6]} - :auto-ap/add-accounts {:txes auto-ap.datomic.migrate.add-general-ledger/add-accounts - :requires [:auto-ap/add-general-ledger-fns2]} - :auto-ap/add-transaction-account {:txes auto-ap.datomic.migrate.add-general-ledger/add-transaction-account - :requires [:auto-ap/add-accounts]} - :auto-ap/change-expense-account-to-entity {:txes auto-ap.datomic.migrate.add-general-ledger/change-expense-account-to-entity - :requires [:auto-ap/add-transaction-account]} - :auto-ap/add-account-to-vendor {:txes auto-ap.datomic.migrate.add-general-ledger/add-account-to-vendor - :requires [:auto-ap/change-expense-account-to-entity]} - :auto-ap/add-location-to-transaction {:txes add-general-ledger/add-location-to-transaction - :requires [:auto-ap/add-account-to-vendor]} - :auto-ap/add-credit-bank-account {:txes add-general-ledger/add-credit-bank-account - :requires [:auto-ap/add-location-to-transaction]} - :auto-ap/add-hidden-to-vendor {:txes-fn `add-general-ledger/add-hidden-to-vendor :requires [:auto-ap/add-credit-bank-account]} - :auto-ap/convert-vendors {:txes-fn `add-general-ledger/convert-vendors - :requires [:auto-ap/add-hidden-to-vendor]} - :auto-ap/convert-invoices {:txes-fn `add-general-ledger/convert-invoices - :requires [:auto-ap/convert-vendors]} - :auto-ap/add-yodlee-merchant2 {:txes add-general-ledger/add-yodlee-merchant :requires [:auto-ap/convert-vendors]} - :auto-ap/add-external-id-to-ledger {:txes add-general-ledger/add-external-id-to-ledger :requires [:auto-ap/add-yodlee-merchant2]} - :auto-ap/add-exclude-to-transaction {:txes add-general-ledger/add-exclude-to-transaction :requires [:auto-ap/add-external-id-to-ledger]} - :auto-ap/add-client-identifier2 {:txes add-client-identifier :requires [:auto-ap/make-every-account-visible]} - :auto-ap/add-transaction-rules {:txes add-general-ledger/add-transaction-rules :requires [:auto-ap/add-exclude-to-transaction]} - :auto-ap/add-bank-account-locations {:txes add-general-ledger/add-bank-account-locations :requires [:auto-ap/add-transaction-rules]} - - :auto-ap/convert-transactions {:txes-fn `add-general-ledger/convert-transactions :requires [:auto-ap/add-bank-account-locations]} - :auto-ap/add-exclude-to-invoice {:txes add-general-ledger/add-exclude-to-invoice :requires [:auto-ap/convert-transactions]} - :auto-ap/add-terms {:txes [[{:db/ident :vendor/terms - :db/doc "How many days till you pay" - :db/valueType :db.type/long - :db/cardinality :db.cardinality/one}]]} - :auto-ap/add-due {:txes [[{:db/ident :invoice/due - :db/doc "When you gotta pay" - :db/valueType :db.type/instant - :db/cardinality :db.cardinality/one}]]} - :auto-ap/add-vendor-overrides {:txes [[{:db/ident :vendor-account-override/account - :db/doc "the account for invoices" - :db/valueType :db.type/ref - :db/cardinality :db.cardinality/one} - {:db/ident :vendor-account-override/client - :db/doc "How many days till you pay" - :db/valueType :db.type/ref - :db/cardinality :db.cardinality/one} - {:db/ident :vendor-terms-override/terms - :db/doc "How many days till you pay" - :db/valueType :db.type/long - :db/cardinality :db.cardinality/one} - {:db/ident :vendor-terms-override/client - :db/doc "How many days till you pay" - :db/valueType :db.type/ref - :db/cardinality :db.cardinality/one} - {:db/ident :vendor/terms-overrides - :db/doc "Overrides per-client" - :db/isComponent true - :db/valueType :db.type/ref - :db/cardinality :db.cardinality/many} - {:db/ident :vendor/account-overrides - :db/isComponent true - :db/doc "Overrides per-client" - :db/valueType :db.type/ref - :db/cardinality :db.cardinality/many}]]} - :auto-ap/add-reset-rels {:txes-fn `reset-function} - :auto-ap/add-account-overrides {:txes [[{:db/ident :account/applicability - :db/doc ":global, :optional :customized" - :db/valueType :db.type/ref - :db/cardinality :db.cardinality/one} - - {:db/ident :account-applicability/global - :db/doc "The account applies to all cutsomers"} - - {:db/ident :account-applicability/optional - :db/doc "This account is optional"} - - {:db/ident :account-applicability/customized - :db/doc "This account is customized per-customer"} - - {:db/ident :account/client-overrides - :db/doc "Customizations per customer" - :db/valueType :db.type/ref - :db/isComponent true - :db/cardinality :db.cardinality/many} - - - {:db/ident :account-client-override/client - :db/doc "The client for the override" - :db/valueType :db.type/ref - :db/cardinality :db.cardinality/one} - - {:db/ident :account-client-override/enabled - :db/doc "Does this apply?" - :db/valueType :db.type/boolean - :db/cardinality :db.cardinality/one} - - {:db/ident :account-client-override/name - :db/doc "client override" - :db/valueType :db.type/string - :db/cardinality :db.cardinality/one}]]} - :auto-ap/add-cleared-against {:txes [[{:db/ident :transaction/cleared-against - :db/doc "which entitiy it was cleared against" - :db/valueType :db.type/string - :db/cardinality :db.cardinality/one}]]} - :auto-ap/add-cash-flow-schema {:txes [[{:db/ident :client/weekly-debits - :db/doc "How much money gets debited each week" - :db/valueType :db.type/double - :db/cardinality :db.cardinality/one} - {:db/ident :client/weekly-credits - :db/doc "How much money gets credited each week" - :db/valueType :db.type/double - :db/cardinality :db.cardinality/one} - {:db/ident :client/forecasted-transactions - :db/doc "Regular, planned transactions" - :db/valueType :db.type/ref - :db/isComponent true - :db/cardinality :db.cardinality/many} - {:db/ident :forecasted-transaction/amount - :db/doc "Amount of a forcested transaction" - :db/valueType :db.type/double - :db/cardinality :db.cardinality/one} - {:db/ident :forecasted-transaction/day-of-month - :db/doc "Which day the transaction occurs" - :db/valueType :db.type/long - :db/cardinality :db.cardinality/one} - {:db/ident :forecasted-transaction/identifier - :db/doc "An identifier for this forcasted transaction, e.g., 'RENT'" - :db/valueType :db.type/string - :db/cardinality :db.cardinality/one}]]} - :auto-ap/add-manager-schema {:txes [[{:db/ident :user-role/manager}]]} - :auto-ap/add-include-in-reports1 {:txes [[{:db/ident :bank-account/include-in-reports - :db/doc "Whether to include this bank account in balance sheet, etc." - :db/valueType :db.type/boolean - :db/cardinality :db.cardinality/one}]] - :depends-on [:auto-ap/add-manager-schema]} - :auto-ap/migrate-include-in-reports {:txes-fn `add-include-in-reports :depends-on [:auto-ap/add-include-in-reports1] } - :auto-ap/add-forecasted-transaction-match {:txes [[{:db/ident :transaction/forecast-match - :db/doc "Which forecast this transaction matches, for cashflow" - :db/valueType :db.type/ref - :db/cardinality :db.cardinality/one}]]} - :auto-ap/add-week-a-and-b {:txes [[{:db/ident :client/week-a-debits - :db/doc "How much money gets debited each week" - :db/valueType :db.type/double - :db/cardinality :db.cardinality/one} - {:db/ident :client/week-a-credits - :db/doc "How much money gets credited each week" - :db/valueType :db.type/double - :db/cardinality :db.cardinality/one} - - {:db/ident :client/week-b-debits - :db/doc "How much money gets debited each week" - :db/valueType :db.type/double - :db/cardinality :db.cardinality/one} - {:db/ident :client/week-b-credits - :db/doc "How much money gets credited each week" - :db/valueType :db.type/double + norms-map (merge {:auto-ap/base-schema {:txes auto-ap.datomic/base-schema} + :auto-ap/functions {:txes-fn 'auto-ap.datomic.migrate/functions + :requires [:auto-ap/base-schema]} + :auto-ap/fx-pay-function-2 {:txes-fn 'auto-ap.datomic.migrate/fix-pay-function + :requires [:auto-ap/functions]} + :auto-ap/migrate-vendors {:txes-fn 'auto-ap.datomic/migrate-vendors + :requires [:auto-ap/base-schema]} + :auto-ap/migrate-clients {:txes-fn 'auto-ap.datomic/migrate-clients + :requires [:auto-ap/migrate-vendors]} + :auto-ap/migrate-users {:txes-fn 'auto-ap.datomic/migrate-users + :requires [:auto-ap/migrate-clients]} + :auto-ap/migrate-invoices {:txes-fn 'auto-ap.datomic/migrate-invoices + :requires [:auto-ap/migrate-vendors :auto-ap/migrate-clients]} + :auto-ap/migrate-payments {:txes-fn 'auto-ap.datomic/migrate-payments + :requires [:auto-ap/migrate-invoices]} + :auto-ap/migrate-invoices-payments {:txes-fn 'auto-ap.datomic/migrate-invoices-payments + :requires [:auto-ap/migrate-payments :auto-ap/migrate-invoices]} + :auto-ap/migrate-invoices-expense-accounts {:txes-fn 'auto-ap.datomic/migrate-invoices-expense-accounts + :requires [:auto-ap/migrate-invoices-payments]} + :auto-ap/migrate-transactions {:txes-fn 'auto-ap.datomic/migrate-transactions + :requires [:auto-ap/migrate-invoices-expense-accounts]} + :auto-ap/add-client-codes {:txes-fn 'auto-ap.datomic.migrate.add-client-codes/add-client-codes + :requires [:auto-ap/migrate-transactions]} + :auto-ap/add-bank-account-codes-schema {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes-schema + :requires [:auto-ap/add-client-codes]} + :auto-ap/add-bank-account-codes {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes + :requires [:auto-ap/add-bank-account-codes-schema]} + :auto-ap/add-nick-the-greek {:txes [[{:client/name "Nick the Greek" :client/code "NGAK" :client/locations ["MH"] :client/bank-accounts [{:bank-account/code "NGAK-0" :bank-account/type :bank-account-type/cash :bank-account/name "Cash"}]}]] + :requires [:auto-ap/add-bank-account-codes]} + :auto-ap/rename-codes-1 {:txes-fn 'auto-ap.datomic.migrate.rename-codes/rename-codes-1 + :requires [:auto-ap/add-nick-the-greek]} + :auto-ap/invoice-converter {:txes auto-ap.datomic.migrate.invoice-converter/add-matches + :requires [:auto-ap/rename-codes-1]} + :auto-ap/starter {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-starter + :requires [:auto-ap/invoice-converter]} + :auto-ap/add-default-location {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-default-location + :requires [:auto-ap/invoice-converter]} + :auto-ap/add-default-location-2 {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-default-location-2 + :requires [:auto-ap/add-default-location]} + :auto-ap/add-import-status {:txes auto-ap.datomic.migrate.invoice-converter/add-import-status + :requires [:auto-ap/add-default-location-2]} + :auto-ap/add-import-status-existing-invoices {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-import-status-existing-invoices + :requires [:auto-ap/add-import-status]} + :auto-ap/fix-check-numbers {:txes-fn 'auto-ap.datomic.migrate.check-numbers/fix-check-numbers + :requires [:auto-ap/add-import-status-existing-invoices]} + :auto-ap/add-new-vendors {:txes-fn 'auto-ap.datomic.migrate.add-new-vendors/add-new-vendors + :requires [:auto-ap/fix-check-numbers]} + :auto-ap/add-account-visibility-fields {:txes-fn 'auto-ap.datomic.migrate.account-sorting/add-account-visibility-fields + :requires [:auto-ap/add-new-vendors]} + :auto-ap/make-every-account-visible {:txes-fn 'auto-ap.datomic.migrate.account-sorting/make-every-account-visible + :requires [:auto-ap/add-account-visibility-fields]} + :auto-ap/add-general-ledger6 {:txes add-general-ledger/add-general-ledger + :requires [:auto-ap/make-every-account-visible]} + :auto-ap/add-general-ledger-fns2 {:txes-fn 'auto-ap.datomic.migrate.add-general-ledger/add-general-ledger-fns + :requires [:auto-ap/add-general-ledger6]} + :auto-ap/add-accounts {:txes auto-ap.datomic.migrate.add-general-ledger/add-accounts + :requires [:auto-ap/add-general-ledger-fns2]} + :auto-ap/add-transaction-account {:txes auto-ap.datomic.migrate.add-general-ledger/add-transaction-account + :requires [:auto-ap/add-accounts]} + :auto-ap/change-expense-account-to-entity {:txes auto-ap.datomic.migrate.add-general-ledger/change-expense-account-to-entity + :requires [:auto-ap/add-transaction-account]} + :auto-ap/add-account-to-vendor {:txes auto-ap.datomic.migrate.add-general-ledger/add-account-to-vendor + :requires [:auto-ap/change-expense-account-to-entity]} + :auto-ap/add-location-to-transaction {:txes add-general-ledger/add-location-to-transaction + :requires [:auto-ap/add-account-to-vendor]} + :auto-ap/add-credit-bank-account {:txes add-general-ledger/add-credit-bank-account + :requires [:auto-ap/add-location-to-transaction]} + :auto-ap/add-hidden-to-vendor {:txes-fn `add-general-ledger/add-hidden-to-vendor :requires [:auto-ap/add-credit-bank-account]} + :auto-ap/convert-vendors {:txes-fn `add-general-ledger/convert-vendors + :requires [:auto-ap/add-hidden-to-vendor]} + :auto-ap/convert-invoices {:txes-fn `add-general-ledger/convert-invoices + :requires [:auto-ap/convert-vendors]} + :auto-ap/add-yodlee-merchant2 {:txes add-general-ledger/add-yodlee-merchant :requires [:auto-ap/convert-vendors]} + :auto-ap/add-external-id-to-ledger {:txes add-general-ledger/add-external-id-to-ledger :requires [:auto-ap/add-yodlee-merchant2]} + :auto-ap/add-exclude-to-transaction {:txes add-general-ledger/add-exclude-to-transaction :requires [:auto-ap/add-external-id-to-ledger]} + :auto-ap/add-client-identifier2 {:txes add-client-identifier :requires [:auto-ap/make-every-account-visible]} + :auto-ap/add-transaction-rules {:txes add-general-ledger/add-transaction-rules :requires [:auto-ap/add-exclude-to-transaction]} + :auto-ap/add-bank-account-locations {:txes add-general-ledger/add-bank-account-locations :requires [:auto-ap/add-transaction-rules]} + + :auto-ap/convert-transactions {:txes-fn `add-general-ledger/convert-transactions :requires [:auto-ap/add-bank-account-locations]} + :auto-ap/add-exclude-to-invoice {:txes add-general-ledger/add-exclude-to-invoice :requires [:auto-ap/convert-transactions]} + :auto-ap/add-terms {:txes [[{:db/ident :vendor/terms + :db/doc "How many days till you pay" + :db/valueType :db.type/long :db/cardinality :db.cardinality/one}]]} - :auto-ap/auto-pay {:txes [[{:db/ident :vendor/automatically-paid-when-due - :db/doc "The clients for which invoices will automatically be paid." - :db/valueType :db.type/ref - :db/cardinality :db.cardinality/many} - - {:db/ident :invoice/automatically-paid-when-due - :db/doc "Whether this invoice should be marked as paid when it's due" - :db/valueType :db.type/boolean - :db/cardinality :db.cardinality/one}]]} - :auto-ap/fix-reset-rels {:txes-fn `reset-function}} + :auto-ap/add-due {:txes [[{:db/ident :invoice/due + :db/doc "When you gotta pay" + :db/valueType :db.type/instant + :db/cardinality :db.cardinality/one}]]} + :auto-ap/add-vendor-overrides {:txes [[{:db/ident :vendor-account-override/account + :db/doc "the account for invoices" + :db/valueType :db.type/ref + :db/cardinality :db.cardinality/one} + {:db/ident :vendor-account-override/client + :db/doc "How many days till you pay" + :db/valueType :db.type/ref + :db/cardinality :db.cardinality/one} + {:db/ident :vendor-terms-override/terms + :db/doc "How many days till you pay" + :db/valueType :db.type/long + :db/cardinality :db.cardinality/one} + {:db/ident :vendor-terms-override/client + :db/doc "How many days till you pay" + :db/valueType :db.type/ref + :db/cardinality :db.cardinality/one} + {:db/ident :vendor/terms-overrides + :db/doc "Overrides per-client" + :db/isComponent true + :db/valueType :db.type/ref + :db/cardinality :db.cardinality/many} + {:db/ident :vendor/account-overrides + :db/isComponent true + :db/doc "Overrides per-client" + :db/valueType :db.type/ref + :db/cardinality :db.cardinality/many}]]} + :auto-ap/add-reset-rels {:txes-fn `reset-function} + :auto-ap/add-account-overrides {:txes [[{:db/ident :account/applicability + :db/doc ":global, :optional :customized" + :db/valueType :db.type/ref + :db/cardinality :db.cardinality/one} + + {:db/ident :account-applicability/global + :db/doc "The account applies to all cutsomers"} + + {:db/ident :account-applicability/optional + :db/doc "This account is optional"} + + {:db/ident :account-applicability/customized + :db/doc "This account is customized per-customer"} + + {:db/ident :account/client-overrides + :db/doc "Customizations per customer" + :db/valueType :db.type/ref + :db/isComponent true + :db/cardinality :db.cardinality/many} + + + {:db/ident :account-client-override/client + :db/doc "The client for the override" + :db/valueType :db.type/ref + :db/cardinality :db.cardinality/one} + + {:db/ident :account-client-override/enabled + :db/doc "Does this apply?" + :db/valueType :db.type/boolean + :db/cardinality :db.cardinality/one} + + {:db/ident :account-client-override/name + :db/doc "client override" + :db/valueType :db.type/string + :db/cardinality :db.cardinality/one}]]} + :auto-ap/add-cleared-against {:txes [[{:db/ident :transaction/cleared-against + :db/doc "which entitiy it was cleared against" + :db/valueType :db.type/string + :db/cardinality :db.cardinality/one}]]} + :auto-ap/add-cash-flow-schema {:txes [[{:db/ident :client/weekly-debits + :db/doc "How much money gets debited each week" + :db/valueType :db.type/double + :db/cardinality :db.cardinality/one} + {:db/ident :client/weekly-credits + :db/doc "How much money gets credited each week" + :db/valueType :db.type/double + :db/cardinality :db.cardinality/one} + {:db/ident :client/forecasted-transactions + :db/doc "Regular, planned transactions" + :db/valueType :db.type/ref + :db/isComponent true + :db/cardinality :db.cardinality/many} + {:db/ident :forecasted-transaction/amount + :db/doc "Amount of a forcested transaction" + :db/valueType :db.type/double + :db/cardinality :db.cardinality/one} + {:db/ident :forecasted-transaction/day-of-month + :db/doc "Which day the transaction occurs" + :db/valueType :db.type/long + :db/cardinality :db.cardinality/one} + {:db/ident :forecasted-transaction/identifier + :db/doc "An identifier for this forcasted transaction, e.g., 'RENT'" + :db/valueType :db.type/string + :db/cardinality :db.cardinality/one}]]} + :auto-ap/add-manager-schema {:txes [[{:db/ident :user-role/manager}]]} + :auto-ap/add-include-in-reports1 {:txes [[{:db/ident :bank-account/include-in-reports + :db/doc "Whether to include this bank account in balance sheet, etc." + :db/valueType :db.type/boolean + :db/cardinality :db.cardinality/one}]] + :depends-on [:auto-ap/add-manager-schema]} + :auto-ap/migrate-include-in-reports {:txes-fn `add-include-in-reports :depends-on [:auto-ap/add-include-in-reports1] } + :auto-ap/add-forecasted-transaction-match {:txes [[{:db/ident :transaction/forecast-match + :db/doc "Which forecast this transaction matches, for cashflow" + :db/valueType :db.type/ref + :db/cardinality :db.cardinality/one}]]} + :auto-ap/add-week-a-and-b {:txes [[{:db/ident :client/week-a-debits + :db/doc "How much money gets debited each week" + :db/valueType :db.type/double + :db/cardinality :db.cardinality/one} + {:db/ident :client/week-a-credits + :db/doc "How much money gets credited each week" + :db/valueType :db.type/double + :db/cardinality :db.cardinality/one} + + {:db/ident :client/week-b-debits + :db/doc "How much money gets debited each week" + :db/valueType :db.type/double + :db/cardinality :db.cardinality/one} + {:db/ident :client/week-b-credits + :db/doc "How much money gets credited each week" + :db/valueType :db.type/double + :db/cardinality :db.cardinality/one}]]} + :auto-ap/auto-pay {:txes [[{:db/ident :vendor/automatically-paid-when-due + :db/doc "The clients for which invoices will automatically be paid." + :db/valueType :db.type/ref + :db/cardinality :db.cardinality/many} + + {:db/ident :invoice/automatically-paid-when-due + :db/doc "Whether this invoice should be marked as paid when it's due" + :db/valueType :db.type/boolean + :db/cardinality :db.cardinality/one}]]} + :auto-ap/fix-reset-rels {:txes-fn `reset-function}} + sales/norms-map + clients/norms-map) ] (println "Conforming database...") (c/ensure-conforms conn norms-map) - (c/ensure-conforms conn sales/norms-map) (when (not (seq args)) (d/release conn)) (println "Done"))) diff --git a/src/clj/auto_ap/graphql.clj b/src/clj/auto_ap/graphql.clj index 4149bf6d..620b45b5 100644 --- a/src/clj/auto_ap/graphql.clj +++ b/src/clj/auto_ap/graphql.clj @@ -95,6 +95,7 @@ :bank_account {:fields {:id {:type :id } :type {:type :ident} + :start_date {:type :iso_date} :number {:type 'String} :sort_order {:type 'Int} :visible {:type 'Boolean} @@ -625,6 +626,7 @@ {:fields {:id {:type :id } :code {:type 'String} :type {:type :bank_account_type} + :start_date {:type :iso_date} :number {:type 'String} :check_number {:type 'Int} :visible {:type 'Boolean} diff --git a/src/clj/auto_ap/graphql/clients.clj b/src/clj/auto_ap/graphql/clients.clj index 6917946f..cc53f8bf 100644 --- a/src/clj/auto_ap/graphql/clients.clj +++ b/src/clj/auto_ap/graphql/clients.clj @@ -4,7 +4,8 @@ [auto-ap.datomic :refer [uri remove-nils]] [auto-ap.graphql.utils :refer [->graphql assert-admin can-see-client?]] [clojure.string :as str] - [clojure.tools.logging :as log])) + [clojure.tools.logging :as log] + [clj-time.coerce :as coerce])) (defn assert-client-code-is-unique [code] (when (seq (d/query {:query {:find '[?id] @@ -54,6 +55,7 @@ :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 %) diff --git a/src/clj/auto_ap/yodlee/import.clj b/src/clj/auto_ap/yodlee/import.clj index 8a07c9a9..dc3a4552 100644 --- a/src/clj/auto_ap/yodlee/import.clj +++ b/src/clj/auto_ap/yodlee/import.clj @@ -14,7 +14,8 @@ [auto-ap.rule-matching :as rm] [clojure.string :as str] [unilog.context :as lc] - [clojure.tools.logging :as log])) + [clojure.tools.logging :as log] + [clj-time.core :as t])) (defn rough-match [client-id bank-account-id amount] @@ -89,17 +90,21 @@ client (:client/_bank-accounts bank-account) client-id (:db/id client) valid-locations (or (:bank-account/locations bank-account) (:client/locations client)) - check (transaction->payment transaction check-number client-id bank-account-id amount id)] + check (transaction->payment transaction check-number client-id bank-account-id amount id) + date (time/parse date "YYYY-MM-dd")] :when (and client-id (not (existing (sha-256 (str id)))) (= "POSTED" status) + + (or (not (:start-date bank-account)) + (t/after? date (:start-date bank-account))) )] (-> #:transaction {:post-date (coerce/to-date (time/parse post-date "YYYY-MM-dd")) :id (sha-256 (str id)) :account-id account-id - :date (coerce/to-date (time/parse date "YYYY-MM-dd")) + :date (coerce/to-date date) :amount (double amount) :description-original (some-> description-original (str/replace #"\s+" " ")) :description-simple (some-> description-simple (str/replace #"\s+" " ")) diff --git a/src/cljs/auto_ap/events.cljs b/src/cljs/auto_ap/events.cljs index 95ec1898..93eb050d 100644 --- a/src/cljs/auto_ap/events.cljs +++ b/src/cljs/auto_ap/events.cljs @@ -44,7 +44,7 @@ :graphql {:token token :query-obj {:venia/queries [[:client - [:id :name :code :email :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits :locations [:location-matches [:id :location :match]] [:bank-accounts [:id :code :number :bank-name :bank-code :check-number :name :routing :type :sort-order :visible :yodlee-account-id :locations :include-in-reports] ] + [:id :name :code :email :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits :locations [:location-matches [:id :location :match]] [:bank-accounts [:id :start-date :code :number :bank-name :bank-code :check-number :name :routing :type :sort-order :visible :yodlee-account-id :locations :include-in-reports] ] [:address [:street1 :street2 :city :state :zip]] [:forecasted-transactions [:id :amount :identifier :day-of-month]]]] [:vendor @@ -77,7 +77,7 @@ :query-obj {:venia/queries [[:client [:id :name :code :matches :locations :week-a-debits :week-a-credits :week-b-debits :week-b-credits [:location-matches [:id :location :match]] [:address [:street1 :street2 :city :state :zip]] - [:bank-accounts [:id :code :number :bank-name :bank-code :check-number :name :routing :type :sort-order :visible :yodlee-account-id :locations :include-in-reports] ] + [:bank-accounts [:id :start-date :code :number :bank-name :bank-code :check-number :name :routing :type :sort-order :visible :yodlee-account-id :locations :include-in-reports] ] [:forecasted-transactions [:id :amount :identifier :day-of-month]]]] [:vendor vendor-query] diff --git a/src/cljs/auto_ap/views/pages/admin/clients/form.cljs b/src/cljs/auto_ap/views/pages/admin/clients/form.cljs index ffd61bc7..eed55059 100644 --- a/src/cljs/auto_ap/views/pages/admin/clients/form.cljs +++ b/src/cljs/auto_ap/views/pages/admin/clients/form.cljs @@ -4,7 +4,7 @@ [auto-ap.subs :as subs] [auto-ap.views.components.address :refer [address-field]] [auto-ap.views.components.layouts :refer [side-bar]] - [auto-ap.views.utils :refer [dispatch-event horizontal-field nf multi-field]] + [auto-ap.views.utils :refer [dispatch-event horizontal-field nf multi-field date-picker standard date->str]] [cljs-time.coerce :as coerce] [cljs-time.core :as t] [clojure.spec.alpha :as s] @@ -44,11 +44,20 @@ :identifier identifier :amount amount}) (:forecasted-transactions new-client-data)) - :bank-accounts (map (fn [{:keys [number name check-number include-in-reports type id code bank-name routing bank-code new? sort-order visible yodlee-account-id locations]}] + :bank-accounts (map (fn [{:keys [number name check-number include-in-reports type id code start-date bank-name routing bank-code new? sort-order visible yodlee-account-id locations]}] {:number number :name name :check-number check-number :include-in-reports include-in-reports + :start-date (cond (not start-date) + nil + + (instance? goog.date.Date start-date) + (date->str start-date standard) + + :else + start-date + ) :type type :id id :sort-order sort-order @@ -101,7 +110,7 @@ [:location-matches [:location :match :id]] [:address [:street1 :street2 :city :state :zip]] [:forecasted-transactions [:id :amount :identifier :day-of-month]] - [:bank-accounts [:id :number :check-number :name :code :bank-code :bank-name :routing :type :visible :yodlee-account-id :sort-order :locations]]]]}]} + [:bank-accounts [:id :number :start-date :check-number :name :code :bank-code :bank-name :routing :type :visible :yodlee-account-id :sort-order :locations]]]]}]} :on-success [::save-complete] :on-error [::forms/save-error ::form]}}))) (re-frame/reg-event-db @@ -231,7 +240,17 @@ [field "Nickname" [:input.input {:placeholder "BOA Checking #1" :type "text" - :field [:bank-accounts sort-order :name]}]]] + :field [:bank-accounts sort-order :name]}]] + [field "Start date" + [date-picker {:class-name "input" + :class "input" + :format-week-number (fn [] "") + :previous-month-button-label "" + :placeholder "mm/dd/yyyy" + :next-month-button-label "" + :next-month-label "" + :type "date" + :field [:bank-accounts sort-order :start-date]}]]] (when (#{:check ":check"} type ) [:div diff --git a/test/clj/auto_ap/yodlee/import.clj b/test/clj/auto_ap/yodlee/import.clj index 62822855..b299b017 100644 --- a/test/clj/auto_ap/yodlee/import.clj +++ b/test/clj/auto_ap/yodlee/import.clj @@ -32,7 +32,7 @@ :merchant {:id "123" :name "456"} :baseType "DEBIT" - :status "PENDING" + :status "POSTED" :bank-account {:db/id 456 :client/_bank-accounts {:db/id 123 @@ -49,14 +49,22 @@ :post-date #inst "2014-01-04T08:00:00.000-00:00" :account-id 1234 :description-original "original-description" - :yodlee-merchant #:yodlee-merchant {:yodlee-id "123" - :name "456"} - :status "PENDING" + :status "POSTED" :id "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" :approval-status :transaction-approval-status/unapproved :description-simple "simple-description"}] result)))) + (t/testing "Should exclude a transaction before start date" + (let [result (sut/transactions->txs [(assoc-in base-transaction + [:bank-account :start-date] + (clj-time.coerce/to-date-time #inst "2020-01-01"))] + :bank-account + noop-rule + #{})] + (t/is (= [] + result)))) + (t/testing "Should not reimport an existing transaction" (let [result (sut/transactions->txs [base-transaction] :bank-account @@ -207,23 +215,28 @@ :transaction-rule/transaction-approval-status :transaction-approval-status/approved :transaction-rule/vendor {:db/id 123}}])] (t/is (= 123 - (-> {:transaction/date #inst "2019-01-04T00:00:00.000-08:00"} + (-> {:transaction/date #inst "2019-01-04T00:00:00.000-08:00" + :transaction/amount 1.0} (apply-rules []) :transaction/matched-rule))) (t/is (= 123 - (-> {:transaction/date #inst "2019-01-03T00:00:00.000-08:00"} + (-> {:transaction/date #inst "2019-01-03T00:00:00.000-08:00" + :transaction/amount 1.0} (apply-rules []) :transaction/matched-rule))) (t/is (= 123 - (-> {:transaction/date #inst "2019-01-09T00:00:00.000-08:00"} + (-> {:transaction/date #inst "2019-01-09T00:00:00.000-08:00" + :transaction/amount 1.0} (apply-rules []) :transaction/matched-rule))) (t/is (nil? - (-> {:transaction/date #inst "2019-01-01T00:00:00.000-08:00"} + (-> {:transaction/date #inst "2019-01-01T00:00:00.000-08:00" + :transaction/amount 1.0} (apply-rules []) :transaction/matched-rule))) (t/is (nil? - (-> {:transaction/date #inst "2019-01-10T00:00:00.000-08:00"} + (-> {:transaction/date #inst "2019-01-10T00:00:00.000-08:00" + :transaction/amount 1.0} (apply-rules []) :transaction/matched-rule))))) @@ -232,6 +245,8 @@ :transaction-rule/amount-gte 3.0 :transaction-rule/amount-lte 9.0 :transaction-rule/transaction-approval-status :transaction-approval-status/approved + :transaction-rule/accounts [#:transaction-rule-account {:percentage 1.0 + :locatoin "HQ"}] :transaction-rule/vendor {:db/id 123}}])] (t/is (= 123 (-> {:transaction/amount 4.0} @@ -258,22 +273,26 @@ (let [apply-rules (rm/rule-applying-fn [{:db/id 123 :transaction-rule/client {:db/id 456}}])] (t/is (= 123 - (-> {:transaction/client 456} + (-> {:transaction/client 456 + :transaction/amount 1.0} (apply-rules []) :transaction/matched-rule))) (t/is (nil? - (-> {:transaction/client 89} + (-> {:transaction/client 89 + :transaction/amount 1.0} (apply-rules []) :transaction/matched-rule))))) (t/testing "Should match if bank-account matches" (let [apply-rules (rm/rule-applying-fn [{:db/id 123 :transaction-rule/bank-account {:db/id 456}}])] (t/is (= 123 - (-> {:transaction/bank-account 456} + (-> {:transaction/bank-account 456 + :transaction/amount 1.0} (apply-rules []) :transaction/matched-rule))) (t/is (nil? - (-> {:transaction/bank-account 89} + (-> {:transaction/bank-account 89 + :transaction/amount 1.0} (apply-rules []) :transaction/matched-rule)))))