tons of small fixes.

This commit is contained in:
Bryce Covert
2020-09-01 17:07:03 -07:00
parent 183c74f128
commit 9f46f85330
24 changed files with 520 additions and 221 deletions

View File

@@ -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)

View 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}]]}})

View File

@@ -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))))

View File

@@ -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]

View File

@@ -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))

View File

@@ -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]

View File

@@ -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)))))

View File

@@ -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)

View File

@@ -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"]

View File

@@ -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\.]+)"

View File

@@ -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)))))

View File

@@ -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

View File

@@ -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]

View File

@@ -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"

View File

@@ -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

View File

@@ -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 {}

View File

@@ -48,6 +48,7 @@
:amount :amount
:note :note
:cleared-against :cleared-against
:alternate-description
[:vendor [:vendor
[:name :id]] [:name :id]]
[:client [:client

View File

@@ -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]}]]]
"13 periods"])} [:div.control
"13 periods"]] [: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"]]]]
[: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?])

View File

@@ -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

View File

@@ -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 )]

View File

@@ -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

View File

@@ -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

View File

@@ -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 } }}")

View 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))))))))