tons of small fixes.
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
[auto-ap.datomic.migrate.add-bank-account-codes :refer [add-bank-account-codes]]
|
[auto-ap.datomic.migrate.add-bank-account-codes :refer [add-bank-account-codes]]
|
||||||
[auto-ap.datomic.migrate.invoice-converter :refer [add-import-status-existing-invoices]]
|
[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.add-general-ledger :as add-general-ledger]
|
||||||
|
[auto-ap.datomic.migrate.ledger :as ledger]
|
||||||
[auto-ap.datomic.migrate.sales :as sales]
|
[auto-ap.datomic.migrate.sales :as sales]
|
||||||
[auto-ap.datomic.migrate.clients :as clients]
|
[auto-ap.datomic.migrate.clients :as clients]
|
||||||
[auto-ap.datomic.migrate.audit :as audit]
|
[auto-ap.datomic.migrate.audit :as audit]
|
||||||
@@ -316,11 +317,12 @@
|
|||||||
:auto-ap/fix-reset-rels {:txes-fn `reset-function}}
|
:auto-ap/fix-reset-rels {:txes-fn `reset-function}}
|
||||||
sales/norms-map
|
sales/norms-map
|
||||||
clients/norms-map
|
clients/norms-map
|
||||||
|
ledger/norms-map
|
||||||
audit/norms-map)
|
audit/norms-map)
|
||||||
]
|
]
|
||||||
(println "Conforming database...")
|
(println "Conforming database...")
|
||||||
(c/ensure-conforms conn norms-map)
|
(c/ensure-conforms conn norms-map)
|
||||||
(when (not (seq args))
|
#_(when (not (seq args))
|
||||||
(d/release conn))
|
(d/release conn))
|
||||||
(println "Done")))
|
(println "Done")))
|
||||||
#_(-main false)
|
#_(-main false)
|
||||||
|
|||||||
6
src/clj/auto_ap/datomic/migrate/ledger.clj
Normal file
6
src/clj/auto_ap/datomic/migrate/ledger.clj
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
(ns auto-ap.datomic.migrate.ledger)
|
||||||
|
|
||||||
|
(def norms-map {::add-alternat-description {:txes [[{:db/ident :journal-entry/alternate-description
|
||||||
|
:db/doc "The description if there is no vendor"
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/cardinality :db.cardinality/one}]]}})
|
||||||
@@ -116,7 +116,6 @@
|
|||||||
args)
|
args)
|
||||||
true
|
true
|
||||||
(merge-query {:query {:find ['?e] :where ['[?e :transaction/id]]}}))]
|
(merge-query {:query {:find ['?e] :where ['[?e :transaction/id]]}}))]
|
||||||
(println query)
|
|
||||||
(cond->> query
|
(cond->> query
|
||||||
true (d/query)
|
true (d/query)
|
||||||
true (apply-sort-3 args)
|
true (apply-sort-3 args)
|
||||||
@@ -179,18 +178,3 @@
|
|||||||
(update :transaction/post-date c/from-date)
|
(update :transaction/post-date c/from-date)
|
||||||
(dissoc :transaction/id)))
|
(dissoc :transaction/id)))
|
||||||
|
|
||||||
(defn unapprove [ids]
|
|
||||||
(doseq [x (partition-all 100 ids)]
|
|
||||||
@(d/transact (d/connect uri)
|
|
||||||
(mapv (fn [i]
|
|
||||||
{:db/id i
|
|
||||||
:transaction/approval-status :transaction-approval-status/unapproved})
|
|
||||||
x))))
|
|
||||||
|
|
||||||
(defn delete [ids]
|
|
||||||
(doseq [x (partition-all 100 ids)]
|
|
||||||
@(d/transact (d/connect uri)
|
|
||||||
(mapcat (fn [i]
|
|
||||||
[[:db/retractEntity i]
|
|
||||||
[:db/retractEntity [:journal-entry/original-entity i]]])
|
|
||||||
x))))
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
(ns auto-ap.datomic.vendors
|
(ns auto-ap.datomic.vendors
|
||||||
(:require [datomic.api :as d]
|
(:require [datomic.api :as d]
|
||||||
[auto-ap.graphql.utils :refer [limited-clients]]
|
[auto-ap.graphql.utils :refer [limited-clients ]]
|
||||||
[auto-ap.datomic :refer [uri]]))
|
|
||||||
|
[auto-ap.datomic :refer [uri conn merge-query]]))
|
||||||
(defn cleanse [id vendor]
|
(defn cleanse [id vendor]
|
||||||
(let [clients (if-let [clients (limited-clients id)]
|
(let [clients (if-let [clients (limited-clients id)]
|
||||||
(set (map :db/id clients))
|
(set (map :db/id clients))
|
||||||
@@ -18,14 +19,42 @@
|
|||||||
:vendor/terms-overrides [* {:vendor-terms-override/client [:client/name :client/code :db/id]}]
|
:vendor/terms-overrides [* {:vendor-terms-override/client [:client/name :client/code :db/id]}]
|
||||||
:vendor/automatically-paid-when-due [:db/id :client/name]}])
|
:vendor/automatically-paid-when-due [:db/id :client/name]}])
|
||||||
|
|
||||||
(defn get-graphql [args]
|
(defn get-usages [args]
|
||||||
(->> (cond-> {:query {:find [(list 'pull '?e default-read)]
|
(->> (cond-> {:query {:find ['?v '?c '(count ?e)]
|
||||||
:in ['$]
|
:in ['$]
|
||||||
:where ['[?e :vendor/name]]}
|
:where ['[?v :vendor/name]
|
||||||
:args [(d/db (d/connect uri))]})
|
'(or-join [?v ?c ?e]
|
||||||
|
(and
|
||||||
|
[?e :invoice/vendor ?v]
|
||||||
|
[?e :invoice/client ?c])
|
||||||
|
(and
|
||||||
|
[?e :transaction/vendor ?v]
|
||||||
|
[?e :transaction/client ?c])
|
||||||
|
(and
|
||||||
|
[?e :journal-entry/vendor ?v]
|
||||||
|
[?e :journal-entry/client ?c]))]}
|
||||||
|
:args [(d/db conn)]}
|
||||||
|
|
||||||
|
(limited-clients (:id args))
|
||||||
|
(merge-query {:query {:in ['?xx]
|
||||||
|
:where [['(get ?xx ?c)]]}
|
||||||
|
:args [(set (map :db/id (limited-clients (:id args))))]}))
|
||||||
(d/query)
|
(d/query)
|
||||||
(map first)
|
(reduce
|
||||||
(map #(cleanse (:id args) %))))
|
(fn [usages [v c cnt]]
|
||||||
|
(update usages v (fnil conj []) {:client-id c :count cnt}))
|
||||||
|
{})))
|
||||||
|
|
||||||
|
(defn get-graphql [args]
|
||||||
|
(let [usages (time (get-usages args))]
|
||||||
|
(->> (cond-> {:query {:find [(list 'pull '?e default-read)]
|
||||||
|
:in ['$]
|
||||||
|
:where ['[?e :vendor/name]]}
|
||||||
|
:args [(d/db (d/connect uri))]})
|
||||||
|
(d/query)
|
||||||
|
(map first)
|
||||||
|
(map #(cleanse (:id args) %))
|
||||||
|
(map #(assoc % :usage (get usages (:db/id %)))))))
|
||||||
|
|
||||||
(defn get-by-id [id]
|
(defn get-by-id [id]
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,9 @@
|
|||||||
:client {:type :client}
|
:client {:type :client}
|
||||||
:account {:type :account}}}
|
:account {:type :account}}}
|
||||||
|
|
||||||
|
:usage {:fields {:client_id {:type :id}
|
||||||
|
:count {:type 'Int}}}
|
||||||
|
|
||||||
:vendor
|
:vendor
|
||||||
{:fields {:id {:type :id}
|
{:fields {:id {:type :id}
|
||||||
:name {:type 'String}
|
:name {:type 'String}
|
||||||
@@ -157,6 +160,7 @@
|
|||||||
:automatically_paid_when_due {:type '(list :client)}
|
:automatically_paid_when_due {:type '(list :client)}
|
||||||
:terms_overrides {:type '(list :terms_override)}
|
:terms_overrides {:type '(list :terms_override)}
|
||||||
:account_overrides {:type '(list :vendor_account_override)}
|
:account_overrides {:type '(list :vendor_account_override)}
|
||||||
|
:usage {:type '(list :usage)}
|
||||||
|
|
||||||
:print_as {:type 'String}
|
:print_as {:type 'String}
|
||||||
:primary_contact {:type :contact}
|
:primary_contact {:type :contact}
|
||||||
@@ -189,6 +193,7 @@
|
|||||||
:cleared_against {:type 'String}
|
:cleared_against {:type 'String}
|
||||||
:client {:type :client}
|
:client {:type :client}
|
||||||
:vendor {:type :vendor}
|
:vendor {:type :vendor}
|
||||||
|
:alternate_description {:type 'String}
|
||||||
:date {:type 'String}
|
:date {:type 'String}
|
||||||
:line_items {:type '(list :journal_entry_line)}}}
|
:line_items {:type '(list :journal_entry_line)}}}
|
||||||
|
|
||||||
@@ -928,9 +933,7 @@
|
|||||||
(let [users (d-users/get-graphql args)]
|
(let [users (d-users/get-graphql args)]
|
||||||
(->graphql users)))
|
(->graphql users)))
|
||||||
|
|
||||||
(defn get-vendor [context args value]
|
|
||||||
(->graphql
|
|
||||||
(d-vendors/get-graphql (assoc args :id (:id context)))))
|
|
||||||
|
|
||||||
(defn print-checks [context args value]
|
(defn print-checks [context args value]
|
||||||
|
|
||||||
@@ -1145,7 +1148,7 @@
|
|||||||
:mutation/void-payment gq-checks/void-check
|
:mutation/void-payment gq-checks/void-check
|
||||||
:mutation/edit-expense-accounts gq-invoices/edit-expense-accounts
|
:mutation/edit-expense-accounts gq-invoices/edit-expense-accounts
|
||||||
:mutation/import-ledger gq-ledger/import-ledger
|
:mutation/import-ledger gq-ledger/import-ledger
|
||||||
:get-vendor get-vendor})
|
:get-vendor gq-vendors/get-graphql})
|
||||||
schema/compile))
|
schema/compile))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,8 @@
|
|||||||
(fn [acc [location account-id] {:keys [debit credit count]}]
|
(fn [acc [location account-id] {:keys [debit credit count]}]
|
||||||
(let [account (lookup-account account-id)
|
(let [account (lookup-account account-id)
|
||||||
account-type (:account_type account)]
|
account-type (:account_type account)]
|
||||||
|
|
||||||
|
|
||||||
(conj acc (merge {:id (str account-id "-" location)
|
(conj acc (merge {:id (str account-id "-" location)
|
||||||
:location (or location "")
|
:location (or location "")
|
||||||
:amount (if account-type (if (#{:account-type/asset
|
:amount (if account-type (if (#{:account-type/asset
|
||||||
@@ -129,17 +131,26 @@
|
|||||||
|
|
||||||
(defn full-ledger-for-client [client-id]
|
(defn full-ledger-for-client [client-id]
|
||||||
(->> (d/query
|
(->> (d/query
|
||||||
{:query {:find ['?d '?jel '?account '?location '?debit '?credit ]
|
{:query {:find ['?d '?jel '?account '?location '?debit '?credit]
|
||||||
:in ['$ '?client-id]
|
:in ['$ '?client-id]
|
||||||
:where ['[?e :journal-entry/client ?client-id]
|
:where '[[?e :journal-entry/client ?client-id]
|
||||||
'[?e :journal-entry/date ?d]
|
[?e :journal-entry/date ?d]
|
||||||
'[?e :journal-entry/line-items ?jel]
|
[?e :journal-entry/line-items ?jel]
|
||||||
'[(get-else $ ?jel :journal-entry-line/account :account/unknown) ?account]
|
(or-join [?e]
|
||||||
'[(get-else $ ?jel :journal-entry-line/debit 0.0) ?debit ]
|
(and [?e :journal-entry/original-entity ?i]
|
||||||
'[(get-else $ ?jel :journal-entry-line/credit 0.0) ?credit]
|
(or-join [?e ?i]
|
||||||
'[(get-else $ ?jel :journal-entry-line/location "") ?location]]
|
(and
|
||||||
}
|
[?i :transaction/bank-account ?b]
|
||||||
:args [(d/db (d/connect uri)) client-id]})
|
(or [?b :bank-account/include-in-reports true]
|
||||||
|
(not [?b :bank-account/include-in-reports])))
|
||||||
|
(not [?i :transaction/bank-account])))
|
||||||
|
(not [?e :journal-entry/original-entity ]))
|
||||||
|
[(get-else $ ?jel :journal-entry-line/account :account/unknown) ?account]
|
||||||
|
[(get-else $ ?jel :journal-entry-line/debit 0.0) ?debit ]
|
||||||
|
[(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]})
|
||||||
(sort-by first)))
|
(sort-by first)))
|
||||||
|
|
||||||
(defn get-balance-sheet [context args value]
|
(defn get-balance-sheet [context args value]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[auto-ap.datomic.vendors :as d-vendors]
|
[auto-ap.datomic.vendors :as d-vendors]
|
||||||
[auto-ap.time :refer [parse iso-date]]
|
[auto-ap.time :refer [parse iso-date]]
|
||||||
[datomic.api :as d]
|
[datomic.api :as d]
|
||||||
[auto-ap.datomic :refer [uri remove-nils]]
|
[auto-ap.datomic :refer [uri remove-nils audit-transact]]
|
||||||
[clj-time.coerce :as coerce]
|
[clj-time.coerce :as coerce]
|
||||||
[clojure.set :as set]))
|
[clojure.set :as set]))
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
{:db/id apwd})
|
{:db/id apwd})
|
||||||
(:automatically_paid_when_due in))]))
|
(:automatically_paid_when_due in))]))
|
||||||
|
|
||||||
transaction-result @(d/transact (d/connect uri) transaction)]
|
transaction-result (audit-transact transaction (:id context))]
|
||||||
|
|
||||||
(-> (d-vendors/get-by-id (or (-> transaction-result :tempids (get "vendor"))
|
(-> (d-vendors/get-by-id (or (-> transaction-result :tempids (get "vendor"))
|
||||||
id))
|
id))
|
||||||
@@ -100,3 +100,7 @@
|
|||||||
transaction (conj transaction [:db/retractEntity from])]
|
transaction (conj transaction [:db/retractEntity from])]
|
||||||
@(d/transact conn transaction)
|
@(d/transact conn transaction)
|
||||||
to))
|
to))
|
||||||
|
|
||||||
|
(defn get-graphql [context args value]
|
||||||
|
(->graphql
|
||||||
|
(d-vendors/get-graphql (assoc args :id (:id context)))))
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[yang.scheduler :as scheduler]
|
[yang.scheduler :as scheduler]
|
||||||
[mount.core :as mount]
|
[mount.core :as mount]
|
||||||
[auto-ap.datomic.accounts :as a]
|
[auto-ap.datomic.accounts :as a]
|
||||||
[auto-ap.datomic :refer [uri remove-nils]]
|
[auto-ap.datomic :refer [uri remove-nils conn]]
|
||||||
[clojure.spec.alpha :as s]
|
[clojure.spec.alpha :as s]
|
||||||
[clojure.tools.logging :as log]
|
[clojure.tools.logging :as log]
|
||||||
[auto-ap.logging :refer [info-event]]
|
[auto-ap.logging :refer [info-event]]
|
||||||
@@ -84,6 +84,7 @@
|
|||||||
:journal-entry/client (:db/id (:transaction/client entity))
|
:journal-entry/client (:db/id (:transaction/client entity))
|
||||||
:journal-entry/date (:transaction/date entity)
|
:journal-entry/date (:transaction/date entity)
|
||||||
:journal-entry/original-entity (:db/id entity)
|
:journal-entry/original-entity (:db/id entity)
|
||||||
|
:journal-entry/alternate-description (:transaction/description-original entity)
|
||||||
:journal-entry/vendor (:db/id (:transaction/vendor entity))
|
:journal-entry/vendor (:db/id (:transaction/vendor entity))
|
||||||
:journal-entry/amount (Math/abs (:transaction/amount entity))
|
:journal-entry/amount (Math/abs (:transaction/amount entity))
|
||||||
:journal-entry/cleared-against (:transaction/cleared-against entity)
|
:journal-entry/cleared-against (:transaction/cleared-against entity)
|
||||||
@@ -122,9 +123,7 @@
|
|||||||
(into [[:replace-general-ledger (:journal-entry/original-entity (first entries))]]
|
(into [[:replace-general-ledger (:journal-entry/original-entity (first entries))]]
|
||||||
entries))
|
entries))
|
||||||
|
|
||||||
(mount/defstate conn
|
|
||||||
:start (d/connect uri)
|
|
||||||
:stop (d/release conn))
|
|
||||||
|
|
||||||
(mount/defstate tx-report-queue
|
(mount/defstate tx-report-queue
|
||||||
:start (d/tx-report-queue conn)
|
:start (d/tx-report-queue conn)
|
||||||
|
|||||||
@@ -512,7 +512,7 @@
|
|||||||
:date [#"Date" 0 0 #"Date: (.*)"]
|
:date [#"Date" 0 0 #"Date: (.*)"]
|
||||||
:invoice-number [#"Invoice #" 0 0 #"Invoice #: (.*)"]
|
:invoice-number [#"Invoice #" 0 0 #"Invoice #: (.*)"]
|
||||||
:account-number [#"Customer #" 0 0 #"Customer #: (.*)"]}
|
:account-number [#"Customer #" 0 0 #"Customer #: (.*)"]}
|
||||||
:parser { :total [:trim-commas-and-remove-dollars nil]
|
:parser { :total [:trim-commas-and-remove-dollars-and-invert-parentheses nil]
|
||||||
:date [:clj-time "MM/dd/yyyy"]}}
|
:date [:clj-time "MM/dd/yyyy"]}}
|
||||||
{:vendor "Mama Lu's Foods"
|
{:vendor "Mama Lu's Foods"
|
||||||
:keywords [#"Mama Lu's Foods"]
|
:keywords [#"Mama Lu's Foods"]
|
||||||
|
|||||||
@@ -18,6 +18,13 @@
|
|||||||
[_ _ value]
|
[_ _ value]
|
||||||
(str/replace (str/replace value #"," "") #"\$" ""))
|
(str/replace (str/replace value #"," "") #"\$" ""))
|
||||||
|
|
||||||
|
(defmethod parse-value :trim-commas-and-remove-dollars-and-invert-parentheses
|
||||||
|
[_ _ value]
|
||||||
|
(let [v (str/replace (str/replace value #"," "") #"\$" "")]
|
||||||
|
(if-let [[_ a ] (re-find #"\((.*)\)" v)]
|
||||||
|
(str "-" a)
|
||||||
|
v)))
|
||||||
|
|
||||||
(defmethod parse-value :trim-commas-and-negate
|
(defmethod parse-value :trim-commas-and-negate
|
||||||
[_ _ value]
|
[_ _ value]
|
||||||
(let [[_ raw-value] (re-find #"([\d\.]+)"
|
(let [[_ raw-value] (re-find #"([\d\.]+)"
|
||||||
|
|||||||
@@ -58,13 +58,18 @@
|
|||||||
:account)))
|
:account)))
|
||||||
|
|
||||||
(defn get-accounts-for-provider-account [provider-account-id]
|
(defn get-accounts-for-provider-account [provider-account-id]
|
||||||
(let [cob-session (login-cobrand)
|
(try
|
||||||
user-session (login-user cob-session)]
|
(let [cob-session (login-cobrand)
|
||||||
(-> (str (:yodlee-base-url env) "/accounts?providerAccountId=" provider-account-id)
|
user-session (login-user cob-session)]
|
||||||
(client/get {:headers (merge base-headers {"Authorization" (auth-header cob-session user-session)})
|
(-> (str (:yodlee-base-url env) "/accounts?providerAccountId=" provider-account-id)
|
||||||
:as :json})
|
(client/get {:headers (merge base-headers {"Authorization" (auth-header cob-session user-session)})
|
||||||
:body
|
:as :json})
|
||||||
:account)))
|
:body
|
||||||
|
:account))
|
||||||
|
(catch Exception e
|
||||||
|
(log/error (str "Couldn't get accounts for provider account '" provider-account-id "'")
|
||||||
|
e)
|
||||||
|
[])))
|
||||||
|
|
||||||
(defn get-account [i]
|
(defn get-account [i]
|
||||||
(let [cob-session (login-cobrand)
|
(let [cob-session (login-cobrand)
|
||||||
@@ -234,7 +239,6 @@
|
|||||||
output-chan
|
output-chan
|
||||||
(map (fn [provider-account]
|
(map (fn [provider-account]
|
||||||
(lc/with-context {:provider-account-id (:id provider-account)}
|
(lc/with-context {:provider-account-id (:id provider-account)}
|
||||||
(log/info "fetching details for provider" (:id provider-account))
|
|
||||||
(get-provider-account-detail (:id provider-account)))))
|
(get-provider-account-detail (:id provider-account)))))
|
||||||
(async/to-chan provider-accounts))
|
(async/to-chan provider-accounts))
|
||||||
(async/<!! (async/into [] output-chan)))))
|
(async/<!! (async/into [] output-chan)))))
|
||||||
|
|||||||
@@ -15,6 +15,17 @@
|
|||||||
(defn jwt->data [token]
|
(defn jwt->data [token]
|
||||||
(js->clj (.parse js/JSON (b64/decodeString (second (str/split token #"\." ))))))
|
(js->clj (.parse js/JSON (b64/decodeString (second (str/split token #"\." ))))))
|
||||||
|
|
||||||
|
(def vendor-query
|
||||||
|
[:id :name :hidden :terms [:default-account [:name :id :location]]
|
||||||
|
[:account-overrides [[:client [:id :name]] :id [:account [:id :numeric-code :name]]]]
|
||||||
|
[:automatically-paid-when-due [:id :name]]
|
||||||
|
[:terms-overrides [[:client [:id :name]] :id :terms]]
|
||||||
|
[:usage [:client-id :count]]
|
||||||
|
[:primary-contact [:name :phone :email :id]]
|
||||||
|
[:secondary-contact [:id :name :phone :email]]
|
||||||
|
:print-as :invoice-reminder-schedule :code
|
||||||
|
[:address [:street1 :street2 :city :state :zip]]])
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::initialize-db
|
::initialize-db
|
||||||
(fn [{:keys [db]} [_ token]]
|
(fn [{:keys [db]} [_ token]]
|
||||||
@@ -48,22 +59,10 @@
|
|||||||
[:address [:street1 :street2 :city :state :zip]]
|
[:address [:street1 :street2 :city :state :zip]]
|
||||||
[:forecasted-transactions [:id :amount :identifier :day-of-month]]]]
|
[:forecasted-transactions [:id :amount :identifier :day-of-month]]]]
|
||||||
[:vendor
|
[:vendor
|
||||||
[:id :name :hidden [:default-account [:name :id :location]] [:primary-contact [:name :phone :email :id]] [:secondary-contact [:id :name :phone :email]] :print-as :invoice-reminder-schedule :code
|
vendor-query]
|
||||||
[:account-overrides [[:client [:id :name]] :id [:account [:id :numeric-code :name]]]]
|
|
||||||
|
|
||||||
[:automatically-paid-when-due [:id :name]]
|
|
||||||
[:terms-overrides [[:client [:id :name]] :id :terms]]]]
|
|
||||||
[:accounts [:numeric-code :location :name :type :account_set :applicability :id [:client-overrides [:name [:client [:name :id]]]]]]]}
|
[:accounts [:numeric-code :location :name :type :account_set :applicability :id [:client-overrides [:name [:client [:name :id]]]]]]]}
|
||||||
:on-success [::received-initial]}}))))
|
:on-success [::received-initial]}}))))
|
||||||
(def vendor-query
|
|
||||||
[:id :name :hidden :terms [:default-account [:name :id :location]]
|
|
||||||
[:account-overrides [[:client [:id :name]] :id [:account [:id :numeric-code :name]]]]
|
|
||||||
[:automatically-paid-when-due [:id :name]]
|
|
||||||
[:terms-overrides [[:client [:id :name]] :id :terms]]
|
|
||||||
[:primary-contact [:name :phone :email :id]]
|
|
||||||
[:secondary-contact [:id :name :phone :email]]
|
|
||||||
:print-as :invoice-reminder-schedule :code
|
|
||||||
[:address [:street1 :street2 :city :state :zip]]])
|
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
(re-frame/reg-event-db
|
||||||
::toggle-menu
|
::toggle-menu
|
||||||
|
|||||||
@@ -177,6 +177,30 @@
|
|||||||
(filter #(or (not (:hidden %))
|
(filter #(or (not (:hidden %))
|
||||||
is-admin) all-vendors)))
|
is-admin) all-vendors)))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
::searchable-vendors
|
||||||
|
:<- [::is-admin?]
|
||||||
|
:<- [::client]
|
||||||
|
:<- [::all-vendors]
|
||||||
|
(fn [[is-admin client all-vendors]]
|
||||||
|
(cond client
|
||||||
|
(filter (fn [{:keys [hidden usage name] :as vendor}]
|
||||||
|
(or (not hidden)
|
||||||
|
(-> (first (filter #(= (:client-id %)
|
||||||
|
(:id client))
|
||||||
|
usage))
|
||||||
|
(:count 0)
|
||||||
|
(> 0))))
|
||||||
|
all-vendors)
|
||||||
|
|
||||||
|
is-admin
|
||||||
|
all-vendors
|
||||||
|
|
||||||
|
:else
|
||||||
|
|
||||||
|
|
||||||
|
(filter #(not (:hidden %)) all-vendors))))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
::all-vendors
|
::all-vendors
|
||||||
(fn [db]
|
(fn [db]
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
[:div
|
[:div
|
||||||
[:p.menu-label "Vendor"]
|
[:p.menu-label "Vendor"]
|
||||||
[:div
|
[:div
|
||||||
[typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors])
|
[typeahead-entity {:matches @(re-frame/subscribe [::subs/searchable-vendors])
|
||||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
||||||
:match->text :name
|
:match->text :name
|
||||||
:type "typeahead-entity"
|
:type "typeahead-entity"
|
||||||
|
|||||||
@@ -31,13 +31,16 @@
|
|||||||
[typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors])
|
[typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors])
|
||||||
:type "typeahead-entity"
|
:type "typeahead-entity"
|
||||||
:auto-focus true
|
:auto-focus true
|
||||||
:match->text :name
|
:match->text (fn [x]
|
||||||
|
(str (:name x) " (" (reduce + 0 (map :count (:usage x))) " usages)") )
|
||||||
:field [:from]}])
|
:field [:from]}])
|
||||||
|
|
||||||
|
|
||||||
(field "To Vendor"
|
(field "To Vendor"
|
||||||
[typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors])
|
[typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors])
|
||||||
:type "typeahead-entity"
|
:type "typeahead-entity"
|
||||||
:match->text :name
|
:match->text (fn [x]
|
||||||
|
(str (:name x) " (" (reduce + 0 (map :count (:usage x))) " usages)") )
|
||||||
:field [:to]}])])))
|
:field [:to]}])])))
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
|
|||||||
@@ -40,7 +40,11 @@
|
|||||||
(for [v (:data page)]
|
(for [v (:data page)]
|
||||||
^{:key (str (:id v))}
|
^{:key (str (:id v))}
|
||||||
[grid/row {:class (:class v) :id (:id v)}
|
[grid/row {:class (:class v) :id (:id v)}
|
||||||
[grid/cell {} (:name v)]
|
[grid/cell {} (:name v)
|
||||||
|
(let [total-usage (reduce + 0 (map :count (:usage v)))]
|
||||||
|
(if (> total-usage 0 )
|
||||||
|
[:div.mx-2.tag.is-info.is-light total-usage " usages, " (count (:usage v)) " clients" ]
|
||||||
|
[:div.mx-2.tag.is-warning.is-light "Unused"]))]
|
||||||
[grid/cell {} (:email (:primary-contact v))]
|
[grid/cell {} (:email (:primary-contact v))]
|
||||||
[grid/cell {} (-> v :default-account :id accounts :name)]
|
[grid/cell {} (-> v :default-account :id accounts :name)]
|
||||||
[grid/cell {}
|
[grid/cell {}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
:amount
|
:amount
|
||||||
:note
|
:note
|
||||||
:cleared-against
|
:cleared-against
|
||||||
|
:alternate-description
|
||||||
[:vendor
|
[:vendor
|
||||||
[:name :id]]
|
[:name :id]]
|
||||||
[:client
|
[:client
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
[goog.string :as gstring]
|
[goog.string :as gstring]
|
||||||
[auto-ap.utils :refer [dollars-0? by ]]
|
[auto-ap.utils :refer [dollars-0? by ]]
|
||||||
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
|
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar]]
|
||||||
[auto-ap.views.utils :refer [date->str date-picker bind-field standard pretty dispatch-event local-today ->% ->$ str->date with-user]]
|
[auto-ap.views.utils :refer [date->str date-picker bind-field standard pretty dispatch-event local-today ->% ->$ str->date with-user dispatch-value-change query-params]]
|
||||||
[cljs-time.core :as t]
|
[cljs-time.core :as t]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[auto-ap.status :as status]
|
[auto-ap.status :as status]
|
||||||
@@ -22,6 +22,10 @@
|
|||||||
:fixed-overhead [80000 89999]
|
:fixed-overhead [80000 89999]
|
||||||
:ownership-controllable [90000 99999]})
|
:ownership-controllable [90000 99999]})
|
||||||
|
|
||||||
|
(defn and-last-year [[from to]]
|
||||||
|
[[from to]
|
||||||
|
[(t/minus from (t/years 1)) (t/minus to (t/years 1))]])
|
||||||
|
|
||||||
;; SUBS
|
;; SUBS
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
::locations
|
::locations
|
||||||
@@ -112,6 +116,11 @@
|
|||||||
(fn [db]
|
(fn [db]
|
||||||
(-> db ::params)))
|
(-> db ::params)))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
::period-inputs
|
||||||
|
(fn [db]
|
||||||
|
(-> db ::period-inputs)))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
::periods
|
::periods
|
||||||
(fn [db]
|
(fn [db]
|
||||||
@@ -124,6 +133,24 @@
|
|||||||
(fn [db]
|
(fn [db]
|
||||||
(assoc db ::ledger-list-active? false)))
|
(assoc db ::ledger-list-active? false)))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::mounted
|
||||||
|
(fn [{:keys [db]}]
|
||||||
|
(let [qp (query-params)]
|
||||||
|
(if (:periods qp)
|
||||||
|
(let [periods (mapv (fn [[start end title]]
|
||||||
|
[
|
||||||
|
(str->date start standard)
|
||||||
|
(str->date end standard)
|
||||||
|
title])
|
||||||
|
(:periods qp))]
|
||||||
|
{:dispatch [::range-selected periods (:include-deltas qp) nil]})
|
||||||
|
{:dispatch [::range-selected (and-last-year [(t/minus (local-today) (t/period :years 1)) (local-today)]) true nil]}))))
|
||||||
|
|
||||||
|
(re-frame/reg-event-db
|
||||||
|
::period-inputs-change
|
||||||
|
(fn [db [_ field value]]
|
||||||
|
(assoc-in db (into [::period-inputs ] field) value)))
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::params-change
|
::params-change
|
||||||
@@ -131,7 +158,15 @@
|
|||||||
(let [c @(re-frame/subscribe [::subs/client])]
|
(let [c @(re-frame/subscribe [::subs/client])]
|
||||||
(cond-> {:db (-> (:db cofx)
|
(cond-> {:db (-> (:db cofx)
|
||||||
(assoc-in [::params] params)
|
(assoc-in [::params] params)
|
||||||
(dissoc ::report))}
|
(dissoc ::report))
|
||||||
|
:set-uri-params (update params
|
||||||
|
:periods
|
||||||
|
(fn [p]
|
||||||
|
(mapv (fn [[start end title]]
|
||||||
|
[(date->str start standard)
|
||||||
|
(date->str end standard)
|
||||||
|
title]
|
||||||
|
) p)))}
|
||||||
c (assoc :graphql (when @(re-frame/subscribe [::subs/client])
|
c (assoc :graphql (when @(re-frame/subscribe [::subs/client])
|
||||||
{:token (-> cofx :db :user)
|
{:token (-> cofx :db :user)
|
||||||
:owns-state {:single ::page}
|
:owns-state {:single ::page}
|
||||||
@@ -149,15 +184,17 @@
|
|||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::date-picked
|
::date-picked
|
||||||
(fn [cofx [_ [_ period which] date]]
|
(fn [cofx [_ [_ period which] date]]
|
||||||
(println date (str->date date standard))
|
{:dispatch [::range-selected (assoc-in @(re-frame/subscribe [::periods]) [period which] (str->date date standard)) nil nil]}))
|
||||||
{:dispatch [::range-selected (assoc-in @(re-frame/subscribe [::periods]) [period which] (str->date date standard)) nil]}))
|
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::range-selected
|
::range-selected
|
||||||
(fn [{:keys [db]} [_ periods selected]]
|
(fn [{:keys [db]} [_ periods include-deltas selected]]
|
||||||
{:dispatch [::params-change (assoc @(re-frame/subscribe [::params])
|
{:dispatch [::params-change (cond-> @(re-frame/subscribe [::params])
|
||||||
:periods periods
|
true (assoc
|
||||||
:selected selected)]
|
:periods periods
|
||||||
|
:include-deltas include-deltas
|
||||||
|
:selected selected)
|
||||||
|
(not (nil? include-deltas)) (assoc :include-deltas include-deltas))]
|
||||||
:db (assoc db ::periods periods)}))
|
:db (assoc db ::periods periods)}))
|
||||||
|
|
||||||
|
|
||||||
@@ -186,6 +223,7 @@
|
|||||||
[[:journal-entries [:id
|
[[:journal-entries [:id
|
||||||
:source
|
:source
|
||||||
:amount
|
:amount
|
||||||
|
:alternate-description
|
||||||
[:vendor
|
[:vendor
|
||||||
[:name :id]]
|
[:name :id]]
|
||||||
[:client
|
[:client
|
||||||
@@ -267,72 +305,77 @@
|
|||||||
(set)
|
(set)
|
||||||
(sort-by :numeric-code)))
|
(sort-by :numeric-code)))
|
||||||
|
|
||||||
(defn map-periods [for-every between periods]
|
(defn map-periods [for-every between periods include-deltas]
|
||||||
(for [[_ i] (map vector periods (range))]
|
(for [[_ i] (map vector periods (range))]
|
||||||
^{:key (str "period-" i)}
|
^{:key (str "period-" i)}
|
||||||
[:<>
|
[:<>
|
||||||
(with-meta
|
(with-meta
|
||||||
(for-every i)
|
(for-every i)
|
||||||
{:key i})
|
{:key i})
|
||||||
(if (not= 0 i)
|
(if (and include-deltas (not= 0 i))
|
||||||
(with-meta (between i)
|
(with-meta (between i)
|
||||||
{:key (str "between-" i)}))]))
|
{:key (str "between-" i)}))]))
|
||||||
|
|
||||||
|
|
||||||
(defn grouping [{:keys [header type groupings location periods all-accounts]}]
|
(defn grouping [{:keys [header type groupings location periods all-accounts]}]
|
||||||
[:<>
|
(let [params @(re-frame/subscribe [::params])]
|
||||||
(doall
|
[:<>
|
||||||
(for [[grouping-name from to] groupings
|
(doall
|
||||||
:let [account-codes (used-accounts all-accounts [from to] location)]
|
(for [[grouping-name from to] groupings
|
||||||
:when (seq account-codes)]
|
:let [account-codes (used-accounts all-accounts [from to] location)]
|
||||||
^{:key grouping-name}
|
:when (seq account-codes)]
|
||||||
[:<>
|
^{:key grouping-name}
|
||||||
[:tr [:td "---" grouping-name "---"]
|
[:<>
|
||||||
(map-periods
|
[:tr [:td "---" grouping-name "---"]
|
||||||
(fn [i]
|
(map-periods
|
||||||
[:<>
|
(fn [i]
|
||||||
[:td]
|
|
||||||
[:td]])
|
|
||||||
(fn [i]
|
|
||||||
[:td])
|
|
||||||
periods)]
|
|
||||||
[:<>
|
|
||||||
(for [{:keys [numeric-code name]} account-codes]
|
|
||||||
^{:key numeric-code}
|
|
||||||
[:tr
|
|
||||||
[:td name]
|
|
||||||
(map-periods
|
|
||||||
(fn [i]
|
|
||||||
(let [amount (get-in all-accounts [i [numeric-code location] :amount] 0.0)]
|
|
||||||
[:<>
|
|
||||||
[:td.has-text-right [:a {:on-click (dispatch-event [::investigate-clicked location numeric-code numeric-code i :current])}
|
|
||||||
(->$ amount)]]
|
|
||||||
[:td.has-text-right (->% (percent-of-sales amount all-accounts i location))]]))
|
|
||||||
(fn [i]
|
|
||||||
[:td.has-text-right (->$ (- (get-in all-accounts [i [numeric-code location] :amount] 0.0)
|
|
||||||
(get-in all-accounts [(dec i) [numeric-code location] :amount] 0.0)))])
|
|
||||||
periods)])]
|
|
||||||
|
|
||||||
[:tr
|
|
||||||
[:th]
|
|
||||||
(map-periods
|
|
||||||
(fn [i]
|
|
||||||
(let [amount (aggregate-accounts (filter-accounts all-accounts i [from to] location))]
|
|
||||||
[:<>
|
[:<>
|
||||||
[:th.has-text-right.total [:a {:on-click (dispatch-event [::investigate-clicked location from to i])}
|
[:td]
|
||||||
(->$ amount)]]
|
[:td]])
|
||||||
[:th.has-text-right.total (->% (percent-of-sales amount all-accounts i location))]]))
|
(fn [i]
|
||||||
(fn [i]
|
[:td])
|
||||||
[:th.has-text-right.total (->$ (- (aggregate-accounts (filter-accounts all-accounts i [from to] location))
|
periods
|
||||||
(aggregate-accounts (filter-accounts all-accounts (dec i) [from to] location))))])
|
(:include-deltas params))]
|
||||||
periods)]]))])
|
[:<>
|
||||||
|
(for [{:keys [numeric-code name]} account-codes]
|
||||||
|
^{:key numeric-code}
|
||||||
|
[:tr
|
||||||
|
[:td name]
|
||||||
|
(map-periods
|
||||||
|
(fn [i]
|
||||||
|
(let [amount (get-in all-accounts [i [numeric-code location] :amount] 0.0)]
|
||||||
|
[:<>
|
||||||
|
[:td.has-text-right [:a {:on-click (dispatch-event [::investigate-clicked location numeric-code numeric-code i :current])}
|
||||||
|
(->$ amount)]]
|
||||||
|
[:td.has-text-right (->% (percent-of-sales amount all-accounts i location))]]))
|
||||||
|
(fn [i]
|
||||||
|
[:td.has-text-right (->$ (- (get-in all-accounts [i [numeric-code location] :amount] 0.0)
|
||||||
|
(get-in all-accounts [(dec i) [numeric-code location] :amount] 0.0)))])
|
||||||
|
periods
|
||||||
|
(:include-deltas params))])]
|
||||||
|
|
||||||
|
[:tr
|
||||||
|
[:th]
|
||||||
|
(map-periods
|
||||||
|
(fn [i]
|
||||||
|
(let [amount (aggregate-accounts (filter-accounts all-accounts i [from to] location))]
|
||||||
|
[:<>
|
||||||
|
[:th.has-text-right.total [:a {:on-click (dispatch-event [::investigate-clicked location from to i])}
|
||||||
|
(->$ amount)]]
|
||||||
|
[:th.has-text-right.total (->% (percent-of-sales amount all-accounts i location))]]))
|
||||||
|
(fn [i]
|
||||||
|
[:th.has-text-right.total (->$ (- (aggregate-accounts (filter-accounts all-accounts i [from to] location))
|
||||||
|
(aggregate-accounts (filter-accounts all-accounts (dec i) [from to] location))))])
|
||||||
|
periods
|
||||||
|
(:include-deltas params))]]))]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn overall-grouping [type title location]
|
(defn overall-grouping [type title location]
|
||||||
(let [all-accounts @(re-frame/subscribe [::all-accounts])
|
(let [all-accounts @(re-frame/subscribe [::all-accounts])
|
||||||
periods @(re-frame/subscribe [::periods])
|
periods @(re-frame/subscribe [::periods])
|
||||||
[min-numeric-code max-numeric-code] (ranges type)]
|
[min-numeric-code max-numeric-code] (ranges type)
|
||||||
|
params @(re-frame/subscribe [::params])]
|
||||||
|
|
||||||
[:<>
|
[:<>
|
||||||
[:tr [:th.is-size-5 title]]
|
[:tr [:th.is-size-5 title]]
|
||||||
@@ -355,11 +398,13 @@
|
|||||||
(fn [i]
|
(fn [i]
|
||||||
[:th.has-text-right (->$ (- (aggregate-accounts (filter-accounts all-accounts i [min-numeric-code max-numeric-code] location))
|
[:th.has-text-right (->$ (- (aggregate-accounts (filter-accounts all-accounts i [min-numeric-code max-numeric-code] location))
|
||||||
(aggregate-accounts (filter-accounts all-accounts (dec i) [min-numeric-code max-numeric-code] location))))])
|
(aggregate-accounts (filter-accounts all-accounts (dec i) [min-numeric-code max-numeric-code] location))))])
|
||||||
periods)]]))
|
periods
|
||||||
|
(:include-deltas params))]]))
|
||||||
|
|
||||||
(defn subtotal [types negs title location]
|
(defn subtotal [types negs title location]
|
||||||
(let [all-accounts @(re-frame/subscribe [::all-accounts])
|
(let [all-accounts @(re-frame/subscribe [::all-accounts])
|
||||||
periods @(re-frame/subscribe [::periods])]
|
periods @(re-frame/subscribe [::periods])
|
||||||
|
params @(re-frame/subscribe [::params])]
|
||||||
[:tr [:th.is-size-5 title]
|
[:tr [:th.is-size-5 title]
|
||||||
|
|
||||||
(map-periods
|
(map-periods
|
||||||
@@ -380,7 +425,8 @@
|
|||||||
(cond->> (filter-accounts all-accounts (dec i) (ranges t) location)
|
(cond->> (filter-accounts all-accounts (dec i) (ranges t) location)
|
||||||
(negs t) (map #(update % :amount -))))
|
(negs t) (map #(update % :amount -))))
|
||||||
types))))])
|
types))))])
|
||||||
periods)]))
|
periods
|
||||||
|
(:include-deltas params))]))
|
||||||
|
|
||||||
(defn location-rows [location]
|
(defn location-rows [location]
|
||||||
|
|
||||||
@@ -400,21 +446,24 @@
|
|||||||
(defn location-summary [location params]
|
(defn location-summary [location params]
|
||||||
(let [periods @(re-frame/subscribe [::periods])]
|
(let [periods @(re-frame/subscribe [::periods])]
|
||||||
[:div
|
[:div
|
||||||
[:h2.title.is-4 {:style {:margin-bottom "1rem"}} location " Summary"]
|
[:h2.title.is-4.mb-4 location " Summary"]
|
||||||
[:table.table.compact.balance-sheet {:style {:margin-bottom "2.5rem"}}
|
[:table.table.compact.balance-sheet.mb-6
|
||||||
[:tbody
|
[:tbody
|
||||||
[:tr
|
[:tr
|
||||||
[:td.has-text-right "Period ending"]
|
[:td.has-text-right "Period ending"]
|
||||||
(map-periods
|
(map-periods
|
||||||
(fn [i]
|
(fn [i]
|
||||||
[:<>
|
[:<>
|
||||||
[:td.has-text-right (when-let [ date (get-in periods [i 1])]
|
[:td.has-text-right
|
||||||
(date->str date))]
|
(or (get-in periods [i 2])
|
||||||
|
(when-let [ date (get-in periods [i 1])]
|
||||||
|
(date->str date)))]
|
||||||
[:td]
|
[:td]
|
||||||
])
|
])
|
||||||
(fn [i]
|
(fn [i]
|
||||||
[:td])
|
[:td])
|
||||||
periods)]
|
periods
|
||||||
|
(:include-deltas params))]
|
||||||
[subtotal [:sales ] #{} "Sales" location]
|
[subtotal [:sales ] #{} "Sales" location]
|
||||||
[subtotal [:cogs ] #{} "Cogs" location]
|
[subtotal [:cogs ] #{} "Cogs" location]
|
||||||
[subtotal [:payroll ]#{} "Payroll" location]
|
[subtotal [:payroll ]#{} "Payroll" location]
|
||||||
@@ -424,9 +473,7 @@
|
|||||||
|
|
||||||
]))
|
]))
|
||||||
|
|
||||||
(defn and-last-year [[from to]]
|
|
||||||
[[from to]
|
|
||||||
[(t/minus from (t/years 1)) (t/minus to (t/years 1))]])
|
|
||||||
|
|
||||||
(def profit-and-loss-content
|
(def profit-and-loss-content
|
||||||
(with-meta
|
(with-meta
|
||||||
@@ -435,6 +482,7 @@
|
|||||||
user @(re-frame/subscribe [::subs/user])
|
user @(re-frame/subscribe [::subs/user])
|
||||||
status @(re-frame/subscribe [::status/single ::page])
|
status @(re-frame/subscribe [::status/single ::page])
|
||||||
params @(re-frame/subscribe [::params])
|
params @(re-frame/subscribe [::params])
|
||||||
|
period-inputs @(re-frame/subscribe [::period-inputs])
|
||||||
periods @(re-frame/subscribe [::periods])]
|
periods @(re-frame/subscribe [::periods])]
|
||||||
|
|
||||||
(if-not current-client
|
(if-not current-client
|
||||||
@@ -450,22 +498,82 @@
|
|||||||
[:div
|
[:div
|
||||||
[:div.field.is-grouped
|
[:div.field.is-grouped
|
||||||
[:div.control
|
[:div.control
|
||||||
[:a.button
|
[:div.field.has-addons
|
||||||
{:class (when (= (:selected params) "13 periods") "is-active")
|
[:div.control
|
||||||
:on-click (dispatch-event
|
[bind-field
|
||||||
[::range-selected
|
[date-picker {:class-name "input"
|
||||||
(let [this-month (t/local-date (t/year (local-today))
|
:class "input"
|
||||||
(t/month (local-today))
|
:format-week-number (fn [] "")
|
||||||
1)]
|
:previous-month-button-label ""
|
||||||
(into
|
:placeholder "End date"
|
||||||
[[this-month (t/minus (t/plus this-month (t/months 1)) (t/days 1))]]
|
:next-month-button-label ""
|
||||||
(for [i (range 12)]
|
:next-month-label ""
|
||||||
[(t/minus this-month (t/months (- 12 i)))
|
:type "date"
|
||||||
(t/minus (t/minus this-month (t/months (- 11 i)))
|
:field [:thirteen-periods-end]
|
||||||
(t/days 1))])))
|
:subscription period-inputs
|
||||||
|
:event [::period-inputs-change]}]]]
|
||||||
|
[:div.control
|
||||||
|
[:a.button
|
||||||
|
{:class (when (= (:selected params) "13 periods") "is-active")
|
||||||
|
:on-click (dispatch-event
|
||||||
|
[::range-selected
|
||||||
|
(let [today (or (some-> (:thirteen-periods-end period-inputs) (str->date standard))
|
||||||
|
(local-today))]
|
||||||
|
(into
|
||||||
|
[[(t/plus (t/minus today (t/weeks (* 13 4)))
|
||||||
|
(t/days 1))
|
||||||
|
today
|
||||||
|
"Total"]]
|
||||||
|
(for [i (range 13)]
|
||||||
|
[(t/plus (t/minus today (t/weeks (* (inc i) 4)))
|
||||||
|
(t/days 1))
|
||||||
|
(t/minus today (t/weeks (* i 4)))])))
|
||||||
|
|
||||||
|
false
|
||||||
|
"13 periods"])}
|
||||||
|
"13 periods"]]]]
|
||||||
|
|
||||||
|
[:div.control
|
||||||
|
[:div.field.has-addons
|
||||||
|
[:div.control
|
||||||
|
[bind-field
|
||||||
|
[date-picker {:class-name "input"
|
||||||
|
:class "input"
|
||||||
|
:format-week-number (fn [] "")
|
||||||
|
:previous-month-button-label ""
|
||||||
|
:placeholder "End date"
|
||||||
|
:next-month-button-label ""
|
||||||
|
:next-month-label ""
|
||||||
|
:type "date"
|
||||||
|
:field [:twelve-periods-end]
|
||||||
|
:subscription period-inputs
|
||||||
|
:event [::period-inputs-change]}]]]
|
||||||
|
[:div.control
|
||||||
|
[:a.button
|
||||||
|
{:class (when (= (:selected params) "13 periods") "is-active")
|
||||||
|
:on-click (dispatch-event
|
||||||
|
[::range-selected
|
||||||
|
(let [end-date (or (some-> (:twelve-periods-end period-inputs) (str->date standard))
|
||||||
|
(local-today))
|
||||||
|
this-month (t/local-date (t/year end-date)
|
||||||
|
(t/month end-date)
|
||||||
|
1)
|
||||||
|
]
|
||||||
|
(into
|
||||||
|
[[(t/minus this-month (t/months 11))
|
||||||
|
(t/minus (t/plus this-month (t/months 1))
|
||||||
|
(t/days 1))
|
||||||
|
"Total"]]
|
||||||
|
(for [i (range 12)]
|
||||||
|
[(t/minus this-month (t/months (- 11 i)))
|
||||||
|
(t/minus (t/minus this-month (t/months (- 10 i)))
|
||||||
|
(t/days 1))])))
|
||||||
|
|
||||||
|
false
|
||||||
|
"12 months"]
|
||||||
|
)}
|
||||||
|
"12 months"]]]]
|
||||||
|
|
||||||
"13 periods"])}
|
|
||||||
"13 periods"]]
|
|
||||||
[:div.control
|
[:div.control
|
||||||
[:a.button
|
[:a.button
|
||||||
{:class (when (= (:selected params) "Last week") "is-active")
|
{:class (when (= (:selected params) "Last week") "is-active")
|
||||||
@@ -476,6 +584,7 @@
|
|||||||
(recur (t/minus current (t/period :days 1)))))]
|
(recur (t/minus current (t/period :days 1)))))]
|
||||||
[::range-selected
|
[::range-selected
|
||||||
(and-last-year [(t/minus last-sunday (t/period :days 6)) last-sunday])
|
(and-last-year [(t/minus last-sunday (t/period :days 6)) last-sunday])
|
||||||
|
true
|
||||||
"Last week"]))}
|
"Last week"]))}
|
||||||
"Last week"]]
|
"Last week"]]
|
||||||
[:div.control
|
[:div.control
|
||||||
@@ -487,6 +596,7 @@
|
|||||||
current
|
current
|
||||||
(recur (t/minus current (t/period :days 1)))))
|
(recur (t/minus current (t/period :days 1)))))
|
||||||
(local-today)])
|
(local-today)])
|
||||||
|
true
|
||||||
"Week to date"])}
|
"Week to date"])}
|
||||||
"Week to date"]]
|
"Week to date"]]
|
||||||
[:div.control
|
[:div.control
|
||||||
@@ -501,6 +611,7 @@
|
|||||||
(t/month (local-today))
|
(t/month (local-today))
|
||||||
1)
|
1)
|
||||||
(t/period :days 1))])
|
(t/period :days 1))])
|
||||||
|
true
|
||||||
"Last Month"])}
|
"Last Month"])}
|
||||||
"Last Month"]]
|
"Last Month"]]
|
||||||
[:div.control
|
[:div.control
|
||||||
@@ -511,6 +622,7 @@
|
|||||||
(t/month (local-today))
|
(t/month (local-today))
|
||||||
1)
|
1)
|
||||||
(local-today)])
|
(local-today)])
|
||||||
|
true
|
||||||
"Month to date"])}
|
"Month to date"])}
|
||||||
"Month to date"]]
|
"Month to date"]]
|
||||||
[:div.control
|
[:div.control
|
||||||
@@ -519,6 +631,7 @@
|
|||||||
:on-click (dispatch-event [::range-selected
|
:on-click (dispatch-event [::range-selected
|
||||||
(and-last-year [(t/local-date (t/year (local-today)) 1 1)
|
(and-last-year [(t/local-date (t/year (local-today)) 1 1)
|
||||||
(local-today)])
|
(local-today)])
|
||||||
|
true
|
||||||
"Year to date"])}
|
"Year to date"])}
|
||||||
"Year to date"]]
|
"Year to date"]]
|
||||||
[:div.control
|
[:div.control
|
||||||
@@ -528,77 +641,92 @@
|
|||||||
(and-last-year [(t/plus (t/minus (local-today) (t/period :years 1))
|
(and-last-year [(t/plus (t/minus (local-today) (t/period :years 1))
|
||||||
(t/period :days 1))
|
(t/period :days 1))
|
||||||
(local-today)])
|
(local-today)])
|
||||||
|
true
|
||||||
"Full year"])}
|
"Full year"])}
|
||||||
"Full year"]]]]
|
"Full year"]]]]
|
||||||
(for [[_ i] (map vector periods (range))]
|
[:div
|
||||||
^{:key i}
|
[:div.field
|
||||||
[:div.field.is-grouped
|
[:label.checkbox
|
||||||
[:div.control
|
[bind-field
|
||||||
[:p.help "From"]
|
[:input {:type "checkbox"
|
||||||
[bind-field
|
:field [:show-advanced?]
|
||||||
[date-picker {:class-name "input"
|
:event [::period-inputs-change]
|
||||||
:class "input"
|
:subscription period-inputs}]]
|
||||||
:format-week-number (fn [] "")
|
" Show Advanced"]]]
|
||||||
:previous-month-button-label ""
|
(when (:show-advanced? period-inputs)
|
||||||
:placeholder "mm/dd/yyyy"
|
(for [[_ i] (map vector periods (range))]
|
||||||
:next-month-button-label ""
|
^{:key i}
|
||||||
:next-month-label ""
|
[:div.field.is-grouped
|
||||||
:type "date"
|
[:div.control
|
||||||
:field [:periods i 0]
|
[:p.help "From"]
|
||||||
:event [::date-picked]
|
[bind-field
|
||||||
:popper-props (clj->js {:placement "right"})
|
[date-picker {:class-name "input"
|
||||||
:subscription params}]]]
|
:class "input"
|
||||||
|
:format-week-number (fn [] "")
|
||||||
|
:previous-month-button-label ""
|
||||||
|
:placeholder "mm/dd/yyyy"
|
||||||
|
:next-month-button-label ""
|
||||||
|
:next-month-label ""
|
||||||
|
:type "date"
|
||||||
|
:field [:periods i 0]
|
||||||
|
:event [::date-picked]
|
||||||
|
:popper-props (clj->js {:placement "right"})
|
||||||
|
:subscription params}]]]
|
||||||
|
|
||||||
[:div.control
|
[:div.control
|
||||||
[:p.help "To"]
|
[:p.help "To"]
|
||||||
[bind-field
|
[bind-field
|
||||||
[date-picker {:class-name "input"
|
[date-picker {:class-name "input"
|
||||||
:class "input"
|
:class "input"
|
||||||
:format-week-number (fn [] "")
|
:format-week-number (fn [] "")
|
||||||
:previous-month-button-label ""
|
:previous-month-button-label ""
|
||||||
:placeholder "mm/dd/yyyy"
|
:placeholder "mm/dd/yyyy"
|
||||||
:next-month-button-label ""
|
:next-month-button-label ""
|
||||||
:next-month-label ""
|
:next-month-label ""
|
||||||
:type "date"
|
:type "date"
|
||||||
:field [:periods i 1]
|
:field [:periods i 1]
|
||||||
:event [::date-picked]
|
:event [::date-picked]
|
||||||
:popper-props (clj->js {:placement "right"})
|
:popper-props (clj->js {:placement "right"})
|
||||||
:subscription params}]]]])]
|
:subscription params}]]]]))]
|
||||||
[status/big-loader status]
|
[status/big-loader status]
|
||||||
[:div
|
(when (not= :loading (:state status))
|
||||||
[:<>
|
[:div
|
||||||
(for [location @(re-frame/subscribe [::locations])]
|
|
||||||
^{:key (str location "-summary")}
|
|
||||||
[location-summary location params]
|
|
||||||
)]
|
|
||||||
[:h2.title.is-4 {:style {:margin-bottom "1rem"}} "Detail"]
|
|
||||||
[:table.table.compact.balance-sheet
|
|
||||||
[:tbody
|
|
||||||
[:tr
|
|
||||||
[:td.has-text-right "Period Ending"]
|
|
||||||
(map-periods
|
|
||||||
(fn [i]
|
|
||||||
[:<>
|
|
||||||
[:td.has-text-right (date->str (get-in periods [i 1]))]
|
|
||||||
[:td]])
|
|
||||||
(fn [i]
|
|
||||||
[:td.has-text-right "𝝙"])
|
|
||||||
periods)]
|
|
||||||
[:<>
|
[:<>
|
||||||
(for [location @(re-frame/subscribe [::locations])]
|
(for [location @(re-frame/subscribe [::locations])]
|
||||||
^{:key location}
|
^{:key (str location "-summary")}
|
||||||
[location-rows location]
|
[location-summary location params]
|
||||||
)]]]]])))
|
)]
|
||||||
{:component-will-mount #(do (re-frame/dispatch-sync [::range-selected (and-last-year [(t/minus (local-today) (t/period :years 1)) (local-today)]) nil])) }))
|
[:h2.title.is-4 {:style {:margin-bottom "1rem"}} "Detail"]
|
||||||
|
[:table.table.compact.balance-sheet
|
||||||
|
[:tbody
|
||||||
|
[:tr
|
||||||
|
[:td.has-text-right "Period Ending"]
|
||||||
|
(map-periods
|
||||||
|
(fn [i]
|
||||||
|
[:<>
|
||||||
|
[:td.has-text-right
|
||||||
|
(or (get-in periods [i 2])
|
||||||
|
(date->str (get-in periods [i 1])))]
|
||||||
|
[:td]])
|
||||||
|
(fn [i]
|
||||||
|
[:td.has-text-right "𝝙"])
|
||||||
|
periods
|
||||||
|
(:include-deltas params))]
|
||||||
|
[:<>
|
||||||
|
(for [location @(re-frame/subscribe [::locations])]
|
||||||
|
^{:key location}
|
||||||
|
[location-rows location]
|
||||||
|
)]]]])])))
|
||||||
|
{:component-will-mount #(re-frame/dispatch [::mounted]) }))
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::unmounted
|
::unmounted-pnl
|
||||||
(fn [{:keys [db]} _]
|
(fn [{:keys [db]} _]
|
||||||
{:dispatch [::data-page/dispose ::ledger]
|
{:dispatch [::data-page/dispose ::ledger]
|
||||||
::track/dispose {:id ::ledger-params}}))
|
::track/dispose {:id ::ledger-params}}))
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::mounted
|
::mounted-pnl
|
||||||
(fn [{:keys [db]} _]
|
(fn [{:keys [db]} _]
|
||||||
{::track/register {:id ::ledger-params
|
{::track/register {:id ::ledger-params
|
||||||
:subscription [::data-page/params ::ledger]
|
:subscription [::data-page/params ::ledger]
|
||||||
@@ -614,8 +742,8 @@
|
|||||||
(defn profit-and-loss-page []
|
(defn profit-and-loss-page []
|
||||||
(reagent/create-class
|
(reagent/create-class
|
||||||
{:display-name "profit-and-loss-page"
|
{:display-name "profit-and-loss-page"
|
||||||
:component-did-mount #(re-frame/dispatch [::mounted])
|
:component-did-mount #(re-frame/dispatch [::mounted-pnl])
|
||||||
:component-will-unmount #(re-frame/dispatch [::unmounted])
|
:component-will-unmount #(re-frame/dispatch [::unmounted-pnl])
|
||||||
:reagent-render
|
:reagent-render
|
||||||
(fn []
|
(fn []
|
||||||
(let [ledger-list-active? @(re-frame/subscribe [::ledger-list-active?])
|
(let [ledger-list-active? @(re-frame/subscribe [::ledger-list-active?])
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
[:p.menu-label "Vendor"]
|
[:p.menu-label "Vendor"]
|
||||||
[:div
|
[:div
|
||||||
[typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors])
|
[typeahead-entity {:matches @(re-frame/subscribe [::subs/searchable-vendors])
|
||||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
||||||
:include-keys [:name :id]
|
:include-keys [:name :id]
|
||||||
:match->text :name
|
:match->text :name
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
[auto-ap.views.components.grid :as grid]
|
[auto-ap.views.components.grid :as grid]
|
||||||
[auto-ap.views.pages.data-page :as data-page]))
|
[auto-ap.views.pages.data-page :as data-page]))
|
||||||
|
|
||||||
(defn ledger-row [{{:keys [client vendor status date amount id line-items] :as i} :row
|
(defn ledger-row [{{:keys [client vendor alternate-description status date amount id line-items] :as i} :row
|
||||||
:keys [selected-client accounts-by-id bank-accounts-by-id]}]
|
:keys [selected-client accounts-by-id bank-accounts-by-id]}]
|
||||||
[:<>
|
[:<>
|
||||||
[grid/row {:class (:class i) :id id}
|
[grid/row {:class (:class i) :id id}
|
||||||
@@ -17,7 +17,8 @@
|
|||||||
[grid/cell {} (:name client)])
|
[grid/cell {} (:name client)])
|
||||||
[grid/cell {} (if vendor
|
[grid/cell {} (if vendor
|
||||||
(:name vendor)
|
(:name vendor)
|
||||||
[:i.has-text-grey (str "Unknown Merchant")])]
|
[:i.has-text-grey (or (when alternate-description (str "Bank Description: " alternate-description))
|
||||||
|
"Unknown Merchant")])]
|
||||||
[grid/cell {} (date->str date) ]
|
[grid/cell {} (date->str date) ]
|
||||||
[grid/cell {} ]
|
[grid/cell {} ]
|
||||||
[grid/cell {:class "has-text-right"} (nf amount )]
|
[grid/cell {:class "has-text-right"} (nf amount )]
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
[:div
|
[:div
|
||||||
[:p.menu-label "Vendor"]
|
[:p.menu-label "Vendor"]
|
||||||
[:div
|
[:div
|
||||||
[typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors])
|
[typeahead-entity {:matches @(re-frame/subscribe [::subs/searchable-vendors])
|
||||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
||||||
:include-keys [:name :id]
|
:include-keys [:name :id]
|
||||||
:match->text :name
|
:match->text :name
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
[:p.menu-label "Vendor"]
|
[:p.menu-label "Vendor"]
|
||||||
[:div
|
[:div
|
||||||
[typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors])
|
[typeahead-entity {:matches @(re-frame/subscribe [::subs/searchable-vendors])
|
||||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
||||||
:include-keys [:name :id]
|
:include-keys [:name :id]
|
||||||
:match->text :name
|
:match->text :name
|
||||||
|
|||||||
@@ -92,6 +92,15 @@
|
|||||||
(is (int? (:start result)))
|
(is (int? (:start result)))
|
||||||
(is (seqable? (:journal-entries result)))))))
|
(is (seqable? (:journal-entries result)))))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest vendors
|
||||||
|
(testing "vendors"
|
||||||
|
(testing "it should find vendors"
|
||||||
|
(let [result (:ledger-page (:data (sut/query (admin-token) "{ ledger_page(client_id: null) { count, start, journal_entries { id } }}")))]
|
||||||
|
(is (int? (:count result)))
|
||||||
|
(is (int? (:start result)))
|
||||||
|
(is (seqable? (:journal-entries result)))))))
|
||||||
|
|
||||||
(deftest transaction-rule-page
|
(deftest transaction-rule-page
|
||||||
(testing "it should find rules"
|
(testing "it should find rules"
|
||||||
(let [result (-> (sut/query (admin-token) "{ transaction_rule_page(client_id: null) { count, start, transaction_rules { id } }}")
|
(let [result (-> (sut/query (admin-token) "{ transaction_rule_page(client_id: null) { count, start, transaction_rules { id } }}")
|
||||||
|
|||||||
81
test/clj/auto_ap/graphql/vendors.clj
Normal file
81
test/clj/auto_ap/graphql/vendors.clj
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
(ns clj.auto-ap.graphql.vendors
|
||||||
|
(:require [auto-ap.graphql.vendors :as sut2]
|
||||||
|
[auto-ap.datomic :refer [uri conn]]
|
||||||
|
[auto-ap.datomic.migrate :as m]
|
||||||
|
|
||||||
|
[clojure.test :as t :refer [deftest is testing use-fixtures]]
|
||||||
|
[datomic.api :as d]
|
||||||
|
[clj-time.core :as time]))
|
||||||
|
|
||||||
|
(defn wrap-setup
|
||||||
|
[f]
|
||||||
|
(with-redefs [auto-ap.datomic/uri "datomic:mem://datomic-transactor:4334/invoice"]
|
||||||
|
(d/create-database uri)
|
||||||
|
(with-redefs [auto-ap.datomic/conn (d/connect uri)]
|
||||||
|
(m/-main false)
|
||||||
|
(f)
|
||||||
|
(d/release conn)
|
||||||
|
(d/delete-database uri))))
|
||||||
|
|
||||||
|
(defn admin-token []
|
||||||
|
{:user "TEST ADMIN"
|
||||||
|
:exp (time/plus (time/now) (time/days 1))
|
||||||
|
:user/role "admin"
|
||||||
|
:user/name "TEST ADMIN"})
|
||||||
|
|
||||||
|
(defn user-token [client-id]
|
||||||
|
{:user "TEST USER"
|
||||||
|
:exp (time/plus (time/now) (time/days 1))
|
||||||
|
:user/role "user"
|
||||||
|
:user/name "TEST USER"
|
||||||
|
:user/clients [{:db/id client-id}]})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn new-invoice [args]
|
||||||
|
(merge {:invoice/total 100.0
|
||||||
|
:invoice/invoice-number (.toString (java.util.UUID/randomUUID))}
|
||||||
|
args))
|
||||||
|
|
||||||
|
(use-fixtures :each wrap-setup)
|
||||||
|
|
||||||
|
|
||||||
|
(deftest vendors
|
||||||
|
(testing "vendors"
|
||||||
|
(let [{:strs [vendor client]} (:tempids @(d/transact (d/connect uri) [{:vendor/name "Test" :db/id "vendor"}
|
||||||
|
{:db/id "client"
|
||||||
|
:client/code "DEF"}]))]
|
||||||
|
(testing "it should find vendors"
|
||||||
|
(let [result (sut2/get-graphql {} {} {})]
|
||||||
|
(is (= 1 (count result)))))
|
||||||
|
|
||||||
|
(testing "It should count invoice usages for each client"
|
||||||
|
@(d/transact (d/connect uri)
|
||||||
|
[{:invoice/client client
|
||||||
|
:invoice/invoice-number "123"
|
||||||
|
:invoice/vendor vendor}])
|
||||||
|
|
||||||
|
|
||||||
|
(let [result (sut2/get-graphql {:id (admin-token)} {} {})]
|
||||||
|
(is (= [{:client_id client
|
||||||
|
:count 1}] (-> result first :usage)))))
|
||||||
|
|
||||||
|
(testing "It should count transaction usages for each client"
|
||||||
|
@(d/transact (d/connect uri)
|
||||||
|
[{:transaction/client client
|
||||||
|
:transaction/vendor vendor}])
|
||||||
|
(let [result (sut2/get-graphql {:id (admin-token)} {} {})]
|
||||||
|
(is (= [{:client_id client
|
||||||
|
:count 2}] (-> result first :usage)))))
|
||||||
|
|
||||||
|
(testing "It should limit usages to visible clients"
|
||||||
|
(let [result (sut2/get-graphql {:id (user-token client)} {} {})]
|
||||||
|
(is (= [{:client_id client
|
||||||
|
:count 2}] (-> result first :usage))))
|
||||||
|
|
||||||
|
(let [result (sut2/get-graphql {:id (user-token 0)} {} {})]
|
||||||
|
(is (= nil (-> result first :usage))))))))
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user