merged.
This commit is contained in:
@@ -1,19 +1,35 @@
|
||||
(ns auto-ap.datomic.accounts
|
||||
(:require [datomic.api :as d]
|
||||
[auto-ap.graphql.utils :refer [->graphql]]
|
||||
[auto-ap.datomic :refer [uri merge-query]]))
|
||||
(:require
|
||||
[auto-ap.datomic
|
||||
:refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query uri]]
|
||||
[clojure.string :as str]
|
||||
[datomic.api :as d]
|
||||
[clojure.tools.logging :as log]))
|
||||
|
||||
(defn <-datomic [a]
|
||||
(update a :account/applicability :db/ident))
|
||||
|
||||
(def default-read ['* {:account/type [:db/ident :db/id]
|
||||
:account/applicability [:db/ident :db/id]
|
||||
:account/client-overrides [:db/id
|
||||
:account-client-override/name
|
||||
{:account-client-override/client [:db/id :client/name]}]}])
|
||||
|
||||
(defn clientize [a client]
|
||||
(if-let [override-name (->> a
|
||||
:account/client-overrides
|
||||
(filter #(= client
|
||||
(:db/id (:account-client-override/client %))))
|
||||
first
|
||||
:account-client-override/name)]
|
||||
(assoc a :account/name override-name)
|
||||
a))
|
||||
|
||||
(defn get-accounts
|
||||
([]
|
||||
(get-accounts {}))
|
||||
([args]
|
||||
(let [query (cond-> {:query {:find ['(pull ?e [* {:account/type [:db/ident :db/id]
|
||||
:account/applicability [:db/ident :db/id]
|
||||
:account/client-overrides [:db/id
|
||||
:account-client-override/name
|
||||
{:account-client-override/client [:db/id :client/name]}]}])]
|
||||
(let [query (cond-> {:query {:find [(list 'pull '?e default-read)]
|
||||
:in ['$]
|
||||
:where [['?e :account/name]]}
|
||||
:args [(d/db (d/connect uri))]}
|
||||
@@ -26,11 +42,7 @@
|
||||
(map <-datomic)))))
|
||||
|
||||
(defn get-by-id [id]
|
||||
(let [query {:query {:find ['(pull ?e [* {:account/type [:db/ident :db/id]
|
||||
:account/applicability [:db/ident :db/id]
|
||||
:account/client-overrides [:db/id
|
||||
:account-client-override/name
|
||||
{:account-client-override/client [:db/id :client/name]}]}])]
|
||||
(let [query {:query {:find [(list 'pull '?e default-read)]
|
||||
:in ['$ '?e]}
|
||||
:args [(d/db (d/connect uri) ) id]}]
|
||||
(->>
|
||||
@@ -39,6 +51,34 @@
|
||||
(map <-datomic)
|
||||
first)))
|
||||
|
||||
(defn get-for-vendor [vendor-id client-id]
|
||||
(if client-id
|
||||
(->>
|
||||
(d/q [:find (list 'pull '?e default-read)
|
||||
:in '$ '?v '?c
|
||||
:where '(or-join [?v ?c ?e]
|
||||
(and [?v :vendor/account-overrides ?ao]
|
||||
[?ao :vendor-account-override/client ?c]
|
||||
[?ao :vendor-account-override/account ?e])
|
||||
(and [?v :vendor/account-overrides ?ao]
|
||||
(not [?ao vendor-account-override/client ?c])
|
||||
[?v :vendor/default-account ?e])
|
||||
(and (not [?v :vendor/account-overrides])
|
||||
[?v :vendor/default-account ?e]))]
|
||||
|
||||
(d/db conn )
|
||||
vendor-id
|
||||
client-id)
|
||||
(map first)
|
||||
(map <-datomic)
|
||||
first)
|
||||
(d/q [:find (list 'pull '?e default-read)
|
||||
:in '$ '?v
|
||||
:where '[?v :vendor/default-account ?e]]
|
||||
|
||||
(d/db conn )
|
||||
vendor-id)))
|
||||
|
||||
(defn get-account-by-numeric-code-and-sets [numeric-code sets]
|
||||
(let [query (cond-> {:query {:find ['(pull ?e [* {:account/type [:db/ident :db/id]}])]
|
||||
:in ['$ '?numeric-code]
|
||||
@@ -50,4 +90,50 @@
|
||||
(map <-datomic)
|
||||
(first))))
|
||||
|
||||
#_(get-account-by-numeric-code-and-sets 5110 nil)
|
||||
(defn raw-graphql-ids [db args]
|
||||
(println args)
|
||||
(let [query (cond-> {:query {:find []
|
||||
:in ['$]
|
||||
:where []}
|
||||
:args [db]}
|
||||
(:sort args) (add-sorter-fields {"name" ['[?e :account/name ?sort-name]]}
|
||||
args)
|
||||
|
||||
(:numeric-code args)
|
||||
(merge-query {:query {:in ['?numeric-code]
|
||||
:where ['[?e :account/numeric-code ?numeric-code]]}
|
||||
:args [(:numeric-code args)]})
|
||||
|
||||
(not (str/blank? (:name-like args)))
|
||||
(merge-query {:query {:in ['?name-like]
|
||||
:where ['[?e :account/name ?n]
|
||||
'[(re-find ?name-like ?n)]]}
|
||||
:args [(re-pattern (str "(?i)" (:name-like args)))]})
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e ]
|
||||
:where ['[?e :account/name]
|
||||
'[?e :account/numeric-code ?sort-default]]}}))]
|
||||
|
||||
|
||||
(cond->> query
|
||||
true (d/query)
|
||||
true (apply-sort-3 args)
|
||||
true (apply-pagination args))))
|
||||
|
||||
|
||||
(defn graphql-results [ids db args]
|
||||
(let [results (->> (d/pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
accounts (->> ids
|
||||
(map results)
|
||||
(map first)
|
||||
(map <-datomic))]
|
||||
accounts))
|
||||
|
||||
(defn get-graphql [args]
|
||||
(log/info "ARGS" args)
|
||||
(let [db (d/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
[(->> (graphql-results ids-to-retrieve db args))
|
||||
matching-count]))
|
||||
|
||||
@@ -6,13 +6,18 @@
|
||||
[clj-time.coerce :as coerce]
|
||||
[auto-ap.time-utils :refer [next-dom]]
|
||||
[clj-time.core :as time]
|
||||
[auto-ap.datomic.vendors :as d-vendors]))
|
||||
[auto-ap.datomic.vendors :as d-vendors]
|
||||
[clojure.tools.logging :as log]
|
||||
[auto-ap.datomic.accounts :as d-accounts]))
|
||||
|
||||
(def default-read '[*
|
||||
{:invoice/client [:client/name :db/id :client/locations :client/code]}
|
||||
{:invoice/vendor [* {:vendor/address [*]}]}
|
||||
{:invoice/status [:db/ident]}
|
||||
{:invoice/expense-accounts [* {:invoice-expense-account/account [*]}]}
|
||||
{:invoice/expense-accounts [* {:invoice-expense-account/account [:account/name :db/id
|
||||
:account/location
|
||||
{:account/client-overrides [:account-client-override/name
|
||||
{:account-client-override/client [:db/id]}]}]}]}
|
||||
{:invoice-payment/_invoice [* {:invoice-payment/payment [* {:payment/status [*]}
|
||||
{:payment/bank-account [*]}
|
||||
{:transaction/_payment [*]}]}]}])
|
||||
@@ -23,6 +28,10 @@
|
||||
(update :invoice/due coerce/from-date)
|
||||
(update :invoice/scheduled-payment coerce/from-date)
|
||||
(update :invoice/status :db/ident)
|
||||
(update :invoice/expense-accounts (fn [eas]
|
||||
(map
|
||||
#(update % :invoice-expense-account/account d-accounts/clientize (:db/id (:invoice/client x)))
|
||||
eas)))
|
||||
(rename-keys {:invoice-payment/_invoice :invoice/payments})))
|
||||
|
||||
(defn raw-graphql-ids
|
||||
@@ -303,6 +312,7 @@
|
||||
|
||||
schedule-payment-dom
|
||||
(-> date
|
||||
coerce/to-date-time
|
||||
(next-dom schedule-payment-dom)
|
||||
coerce/to-date)
|
||||
:else nil)
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
(ns auto-ap.datomic.ledger
|
||||
(:require [datomic.api :as d]
|
||||
[auto-ap.graphql.utils :refer [->graphql limited-clients]]
|
||||
[auto-ap.utils :refer [dollars-0?]]
|
||||
[auto-ap.graphql.utils :refer [limited-clients]]
|
||||
[auto-ap.datomic :refer [merge-query apply-sort-3 apply-pagination add-sorter-fields conn]]
|
||||
[auto-ap.datomic :refer [uri]]
|
||||
|
||||
[clojure.tools.logging :as log]
|
||||
[clj-time.coerce :as c]
|
||||
[clj-time.core :as time]))
|
||||
[auto-ap.datomic.accounts :as d-accounts]))
|
||||
|
||||
(def export-read
|
||||
[:journal-entry/external-id
|
||||
@@ -34,12 +30,12 @@
|
||||
:account/name
|
||||
:account/numeric-code
|
||||
:account/location
|
||||
{:account/client-overrides [:account-client-override/name
|
||||
{:account-client-override/client [:db/id]}]}
|
||||
{:account/type [:db/ident :db/id]}
|
||||
{:bank-account/type [:db/ident :db/id]}]}]}])
|
||||
|
||||
(defn raw-graphql-ids [db args]
|
||||
(log/info "ARGS" args)
|
||||
|
||||
(let [query (cond-> {:query {:find []
|
||||
:in ['$ ]
|
||||
:where []}
|
||||
@@ -161,20 +157,27 @@
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?sort-default '?e] :where ['[?e :journal-entry/date ?sort-default]]}}))]
|
||||
(->> (doto query log/info)
|
||||
|
||||
(->> query
|
||||
(d/query)
|
||||
(apply-sort-3 (update args :sort conj {:sort-key "default-2" :asc true}))
|
||||
(apply-pagination args))))
|
||||
|
||||
(defn graphql-results [ids db args]
|
||||
(defn graphql-results [ids db _]
|
||||
(let [results (->> (d/pull-many db '[* {:journal-entry/client [:client/name :client/code :db/id]
|
||||
:journal-entry/vendor [:vendor/name :db/id]
|
||||
:journal-entry/line-items [* {:journal-entry-line/account [*
|
||||
{:account/type [*]}
|
||||
{:account/client-overrides [:account-client-override/name
|
||||
{:account-client-override/client [:db/id]}]}
|
||||
{:bank-account/type [*]}]}]}]
|
||||
ids)
|
||||
(map #(update % :journal-entry/date c/from-date))
|
||||
(map (fn [je]
|
||||
(update je :journal-entry/line-items
|
||||
(fn [jels]
|
||||
(map
|
||||
#(update % :journal-entry-line/account d-accounts/clientize (:db/id (:journal-entry/client je)))
|
||||
jels)))))
|
||||
(filter (fn [je]
|
||||
(every?
|
||||
(fn [jel]
|
||||
@@ -191,12 +194,9 @@
|
||||
(defn get-graphql [args]
|
||||
(let [db (d/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
|
||||
[(->> (graphql-results ids-to-retrieve db args))
|
||||
matching-count]))
|
||||
|
||||
|
||||
|
||||
(defn filter-ids [ids]
|
||||
(if ids
|
||||
(->> {:query {:find ['?e]
|
||||
@@ -207,8 +207,3 @@
|
||||
(map first)
|
||||
vec)
|
||||
[]))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -142,6 +142,22 @@
|
||||
{:db/id accounts-payable
|
||||
:db/ident :account/accounts-payable}]]))
|
||||
|
||||
(defn add-account-search-terms [conn]
|
||||
[(->> (d/q '[:find ?i ?n
|
||||
:in $
|
||||
:where [?i :account/name ?n]]
|
||||
(d/db conn))
|
||||
(map (fn [[i n]]
|
||||
{:db/id i
|
||||
:account/search-terms n})))
|
||||
(->> (d/q '[:find ?i ?n
|
||||
:in $
|
||||
:where [?i :account-client-override/name ?n]]
|
||||
(d/db conn))
|
||||
(map (fn [[i n]]
|
||||
{:db/id i
|
||||
:account-client-override/search-terms n})))])
|
||||
|
||||
(defn migrate [conn]
|
||||
(let [
|
||||
norms-map (merge {:auto-ap/base-schema {:txes auto-ap.datomic/base-schema}
|
||||
@@ -491,7 +507,20 @@
|
||||
:db/valueType :db.type/boolean
|
||||
:db/cardinality :db.cardinality/one}]]}
|
||||
:auto-ap/add-payment-type-credit {:txes [[{:db/ident :payment-type/credit
|
||||
:db/doc "Credit for negative invoices"}]]}}
|
||||
:db/doc "Credit for negative invoices"}]]}
|
||||
:auto-ap/fulltext-accounts {:txes [[{:db/ident :account/search-terms
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "a name search for accounts"
|
||||
:db/fulltext true}
|
||||
{:db/ident :account-client-override/search-terms
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "a name search for accounts"
|
||||
:db/fulltext true}]]
|
||||
:requires [:auto-ap/add-account-overrides]}
|
||||
:auto-ap/add-search-terms-accounts {:txes-fn `add-account-search-terms
|
||||
:requires [:auto-ap/fulltext-accounts]}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
(ns auto-ap.datomic.migrate.vendors
|
||||
(:require [datomic.api :as d]
|
||||
[auto-ap.datomic :refer [uri]]))
|
||||
(:require [datomic.api :as d]))
|
||||
|
||||
(defn add-vendor-search-terms [conn]
|
||||
[(->> (d/q '[:find ?i ?n
|
||||
:in $
|
||||
:where [?i :vendor/name ?n]]
|
||||
(d/db conn))
|
||||
(map (fn [[i n]]
|
||||
{:db/id i
|
||||
:vendor/search-terms n})))])
|
||||
|
||||
(def norms-map {:add-1099-stuff {:txes [[{:db/ident :vendor/legal-entity-first-name
|
||||
:db/doc "The first name for the legal entity"
|
||||
@@ -56,7 +64,15 @@
|
||||
:db/valueType :db.type/long
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/noHistory true}]
|
||||
]}})
|
||||
]}
|
||||
::make-fulltext-search {:txes [[{:db/ident :vendor/search-terms
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/many
|
||||
:db/doc "a name search for vendors"
|
||||
:db/fulltext true}]]
|
||||
:requires [:auto-ap/base-schema]}
|
||||
::add-vendor-search-terms {:txes-fn `add-vendor-search-terms
|
||||
:requires [::make-fulltext-search]}})
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
[clj-time.coerce :as c]
|
||||
[clj-time.coerce :as coerce]
|
||||
[clojure.tools.logging :as log]
|
||||
[clojure.string :as str]))
|
||||
[clojure.string :as str]
|
||||
[auto-ap.datomic.accounts :as d-accounts]))
|
||||
|
||||
(defn sort-fn [sort-by]
|
||||
(cond
|
||||
@@ -194,11 +195,20 @@
|
||||
:transaction/accounts [:transaction-account/amount
|
||||
:db/id
|
||||
:transaction-account/location
|
||||
{:transaction-account/account [:db/id :account/name :account/numeric-code]}]
|
||||
{:transaction-account/account [:account/name :db/id
|
||||
:account/location
|
||||
{:account/client-overrides [:account-client-override/name
|
||||
{:account-client-override/client [:db/id]}]}]}]
|
||||
:transaction/yodlee-merchant [:db/id :yodlee-merchant/yodlee-id :yodlee-merchant/name]}]
|
||||
ids)
|
||||
(map #(update % :transaction/date c/from-date))
|
||||
(map #(update % :transaction/post-date c/from-date))
|
||||
(map #(update % :transaction/accounts
|
||||
(fn [tas]
|
||||
(map
|
||||
(fn [ta]
|
||||
(update ta :transaction-account/account d-accounts/clientize (:db/id (:transaction/client %))))
|
||||
tas))))
|
||||
(map (fn [transaction]
|
||||
(cond-> transaction
|
||||
(:transaction/payment transaction) (update-in [:transaction/payment :payment/date] c/from-date)
|
||||
@@ -240,7 +250,10 @@
|
||||
:transaction/accounts [:transaction-account/amount
|
||||
:db/id
|
||||
:transaction-account/location
|
||||
{ :transaction-account/account [:db/id :account/name :account/numeric-code]}]
|
||||
{ :transaction-account/account [:account/name :db/id
|
||||
:account/location
|
||||
{:account/client-overrides [:account-client-override/name
|
||||
{:account-client-override/client [:db/id]}]}]}]
|
||||
:transaction/yodlee-merchant [:db/id :yodlee-merchant/yodlee-id :yodlee-merchant/name]}]
|
||||
id)
|
||||
(update :transaction/date c/from-date)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
(ns auto-ap.datomic.vendors
|
||||
(:require [datomic.api :as d]
|
||||
[auto-ap.graphql.utils :refer [limited-clients ]]
|
||||
(:require
|
||||
[auto-ap.datomic :refer [conn merge-query uri add-sorter-fields apply-pagination merge-query apply-sort-3]]
|
||||
[auto-ap.graphql.utils :refer [limited-clients]]
|
||||
[clojure.string :as str]
|
||||
[datomic.api :as d]
|
||||
[auto-ap.datomic.accounts :as d-accounts]))
|
||||
|
||||
[auto-ap.datomic :refer [uri conn merge-query]]))
|
||||
(defn <-datomic [a]
|
||||
(cond-> a
|
||||
(:vendor/legal-entity-tin-type a) (update :vendor/legal-entity-tin-type :db/ident)
|
||||
@@ -16,21 +19,28 @@
|
||||
nil)]
|
||||
(if clients
|
||||
(-> vendor
|
||||
(update :vendor/account-overrides (fn [ao] (filter #(clients (:db/id (:vendor-account-override/client %))) ao)))
|
||||
(update :vendor/account-overrides (fn [aos]
|
||||
(->> aos
|
||||
(filter #(clients (:db/id (:vendor-account-override/client %))))
|
||||
(map #(update % :vendor-account-override/account d-accounts/clientize (:db/id (:vendor-account-override/client %)))))))
|
||||
(update :vendor/terms-overrides (fn [to] (filter #(clients (:db/id (:vendor-terms-override/client %))) to)))
|
||||
(update :vendor/schedule-payment-dom (fn [to] (filter #(clients (:db/id (:vendor-schedule-payment-dom/client %))) to))))
|
||||
vendor)))
|
||||
(-> vendor
|
||||
(update :vendor/account-overrides (fn [aos]
|
||||
(->> aos
|
||||
(map #(update % :vendor-account-override/account d-accounts/clientize (:db/id (:vendor-account-override/client %)))))))))))
|
||||
|
||||
(def default-read
|
||||
'[* {:vendor/account-overrides [* {:vendor-account-override/client [:client/name :db/id]
|
||||
:vendor-account-override/account [:account/name :account/numeric-code :db/id]}]
|
||||
:vendor/terms-overrides [* {:vendor-terms-override/client [:client/name :client/code :db/id]}]
|
||||
:vendor/schedule-payment-dom [* {:vendor-schedule-payment-dom/client [:client/name :client/code :db/id]}]
|
||||
'[* {:vendor/account-overrides [* {:vendor-account-override/client [:client/name :db/id]
|
||||
:vendor-account-override/account [:account/name :account/numeric-code :db/id
|
||||
{:account/client-overrides [:account-client-override/client :account-client-override/name]}]}]
|
||||
:vendor/terms-overrides [* {:vendor-terms-override/client [:client/name :client/code :db/id]}]
|
||||
:vendor/schedule-payment-dom [* {:vendor-schedule-payment-dom/client [:client/name :client/code :db/id]}]
|
||||
:vendor/automatically-paid-when-due [:db/id :client/name]
|
||||
:vendor/legal-entity-tin-type [:db/ident :db/id]
|
||||
:vendor/legal-entity-1099-type [:db/ident :db/id]
|
||||
:vendor/default-account [:db/id :account/numeric-code :account/name]
|
||||
:vendor-usage/_vendor [:vendor-usage/client :vendor-usage/count]}])
|
||||
:vendor/legal-entity-tin-type [:db/ident :db/id]
|
||||
:vendor/legal-entity-1099-type [:db/ident :db/id]
|
||||
:vendor/default-account [:db/id :account/numeric-code :account/name]
|
||||
:vendor-usage/_vendor [:vendor-usage/client :vendor-usage/count]}])
|
||||
|
||||
(defn get-usages [args]
|
||||
(->> (cond-> {:query {:find ['?v '?c '(count ?e)]
|
||||
@@ -58,6 +68,30 @@
|
||||
(update usages v (fnil conj []) {:client-id c :count cnt}))
|
||||
{})))
|
||||
|
||||
(defn raw-graphql-ids [db args]
|
||||
(let [query (cond-> {:query {:find []
|
||||
:in ['$]
|
||||
:where []}
|
||||
:args [db]}
|
||||
(:sort args) (add-sorter-fields {"name" ['[?e :vendor/name ?sort-name]]}
|
||||
args)
|
||||
|
||||
(not (str/blank? (:name-like args)))
|
||||
(merge-query {:query {:in ['?name-like]
|
||||
:where ['[?e :vendor/name ?n]
|
||||
'[(re-find ?name-like ?n)]]}
|
||||
:args [(re-pattern (str "(?i)" (:name-like args)))]})
|
||||
|
||||
true
|
||||
(merge-query {:query {:find ['?e]
|
||||
:where ['[?e :vendor/name]]}}))]
|
||||
|
||||
|
||||
(cond->> query
|
||||
true (d/query)
|
||||
true (apply-sort-3 args)
|
||||
true (apply-pagination args))))
|
||||
|
||||
(defn trim-usage [v limited-clients]
|
||||
(->> (if limited-clients
|
||||
(update v :usage (fn [usages]
|
||||
@@ -73,22 +107,40 @@
|
||||
|
||||
))
|
||||
|
||||
(defn graphql-results [ids db args]
|
||||
(let [results (->> (d/pull-many db default-read ids)
|
||||
(group-by :db/id))
|
||||
vendors (->> ids
|
||||
(map results)
|
||||
(map first)
|
||||
(map #(cleanse (:id args) %))
|
||||
(map <-datomic))]
|
||||
vendors))
|
||||
|
||||
(defn get-graphql [args]
|
||||
(let [db (d/db conn)
|
||||
{ids-to-retrieve :ids matching-count :count} (raw-graphql-ids db args)]
|
||||
[(->> (graphql-results ids-to-retrieve db args))
|
||||
matching-count])
|
||||
|
||||
)
|
||||
|
||||
(defn get-graphql-by-id [args id]
|
||||
(->> (cond-> {:query {:find [(list 'pull '?e default-read)]
|
||||
:in ['$]
|
||||
:in ['$ '?e]
|
||||
:where ['[?e :vendor/name]]}
|
||||
:args [(d/db (d/connect uri))]})
|
||||
:args [(d/db (d/connect uri)) id]})
|
||||
(d/query)
|
||||
(map first)
|
||||
(map #(cleanse (:id args) %))
|
||||
(map <-datomic)
|
||||
(map #(trim-usage % (limited-clients (:id args))))
|
||||
#_(map #(assoc % :usage (get usages (:db/id %))))))
|
||||
first))
|
||||
|
||||
(defn get-by-id [id]
|
||||
|
||||
(->> (d/q '[:find (pull ?e [*
|
||||
{:default-account [:account/name :db/id :account/location]
|
||||
{:vendor/default-account [:account/name :db/id :account/location]
|
||||
:vendor/legal-entity-tin-type [:db/ident :db/id]
|
||||
:vendor/legal-entity-1099-type [:db/ident :db/id]
|
||||
:vendor/account-overrides [* {:vendor-account-override/client [:client/name :db/id]
|
||||
|
||||
@@ -98,6 +98,15 @@
|
||||
:message
|
||||
{:fields {:message {:type 'String}}}
|
||||
|
||||
:search_result
|
||||
{:fields {:name {:type 'String}
|
||||
:id {:type :id}}}
|
||||
|
||||
:account_search_result
|
||||
{:fields {:name {:type 'String}
|
||||
:id {:type :id}
|
||||
:location {:type 'String}}}
|
||||
|
||||
:yodlee_provider_account
|
||||
{:fields {:id {:type 'Int}
|
||||
:client {:type :client}
|
||||
@@ -290,11 +299,23 @@
|
||||
:sales_order_total {:type :money}
|
||||
:sales_order_tax {:type :money}}}
|
||||
|
||||
:vendor_page {:fields {:vendors {:type '(list :vendor)}
|
||||
:count {:type 'Int}
|
||||
:total {:type 'Int}
|
||||
:start {:type 'Int}
|
||||
:end {:type 'Int}}}
|
||||
|
||||
:account_page {:fields {:accounts {:type '(list :account)}
|
||||
:count {:type 'Int}
|
||||
:total {:type 'Int}
|
||||
:start {:type 'Int}
|
||||
:end {:type 'Int}}}
|
||||
|
||||
:reminder_page {:fields {:reminders {:type '(list :reminder)}
|
||||
:count {:type 'Int}
|
||||
:total {:type 'Int}
|
||||
:start {:type 'Int}
|
||||
:end {:type 'Int}}}
|
||||
:count {:type 'Int}
|
||||
:total {:type 'Int}
|
||||
:start {:type 'Int}
|
||||
:end {:type 'Int}}}
|
||||
:check_result {:fields {:invoices {:type '(list :invoice)}
|
||||
:pdf_url {:type 'String}}}
|
||||
|
||||
@@ -343,9 +364,21 @@
|
||||
:args {:client_id {:type :id}}
|
||||
:resolve :get-yodlee-provider-account-page}
|
||||
|
||||
:accounts {:type '(list :account)
|
||||
:args {:account_set {:type 'String}}
|
||||
:resolve :get-accounts}
|
||||
:account_page {:type :account_page
|
||||
:args {:name_like {:type 'String}
|
||||
:numeric_code {:type 'Int}
|
||||
:start {:type 'Int}
|
||||
:per_page {:type 'Int}
|
||||
:sort {:type '(list :sort_item)}}
|
||||
:resolve :get-accounts}
|
||||
|
||||
:search_vendor {:type '(list :search_result)
|
||||
:args {:query {:type 'String}}
|
||||
:resolve :search-vendor}
|
||||
:search_account {:type '(list :account_search_result)
|
||||
:args {:query {:type 'String}
|
||||
:client_id {:type :id}}
|
||||
:resolve :search-account}
|
||||
|
||||
|
||||
|
||||
@@ -386,14 +419,21 @@
|
||||
:per_page {:type 'Int}
|
||||
:sort {:type '(list :sort_item)}}
|
||||
:resolve :get-sales-order-page}
|
||||
|
||||
|
||||
|
||||
|
||||
:vendor {:type '(list :vendor)
|
||||
:vendor {:type :vendor_page
|
||||
:args {:name_like {:type 'String}
|
||||
:start {:type 'Int}
|
||||
:per_page {:type 'Int}
|
||||
:sort {:type '(list :sort_item)}}
|
||||
:resolve :get-vendor}
|
||||
:user {:type '(list :user)
|
||||
:resolve :get-user}}
|
||||
:user {:type '(list :user)
|
||||
:resolve :get-user}
|
||||
:vendor_by_id {:type :vendor
|
||||
:args {:id {:type :id}}
|
||||
:resolve :vendor-by-id}
|
||||
:account_for_vendor {:type :account
|
||||
:args {:client_id {:type :id}
|
||||
:vendor_id {:type :id}}
|
||||
:resolve :account-for-vendor}}
|
||||
|
||||
:input-objects
|
||||
{
|
||||
@@ -693,7 +733,7 @@
|
||||
'[(get-else $ ?je :journal-entry-line/debit 0.0) ?debit]
|
||||
'[(get-else $ ?je :journal-entry-line/credit 0.0) ?credit]]}
|
||||
:args [(d/db (d/connect uri)) client_id]}))
|
||||
bills-due-soon (d/query {:query {:find '[?due ?outstanding ?invoice-number ?vendor-id]
|
||||
bills-due-soon (d/query {:query {:find '[?due ?outstanding ?invoice-number ?vendor-id ?vendor-name]
|
||||
:in '[$ ?client ?due-before]
|
||||
:where ['[?i :invoice/client ?client]
|
||||
'[?i :invoice/status :invoice-status/unpaid]
|
||||
@@ -701,7 +741,8 @@
|
||||
'[(<= ?due ?due-before)]
|
||||
'[?i :invoice/outstanding-balance ?outstanding]
|
||||
'[?i :invoice/invoice-number ?invoice-number]
|
||||
'[?i :invoice/vendor ?vendor-id]]}
|
||||
'[?i :invoice/vendor ?vendor-id]
|
||||
'[?vendor-id :vendor/name ?vendor-name]]}
|
||||
:args [(d/db (d/connect uri)) client_id (coerce/to-date (t/plus (time/local-now) (t/days 180)))]})
|
||||
outstanding-checks (reduce
|
||||
+
|
||||
@@ -739,10 +780,10 @@
|
||||
|
||||
{:beginning_balance total-cash
|
||||
:outstanding_payments outstanding-checks
|
||||
:invoices_due_soon (mapv (fn [[due outstanding invoice-number vendor-id]]
|
||||
:invoices_due_soon (mapv (fn [[due outstanding invoice-number vendor-id vendor-name]]
|
||||
{:due (coerce/to-date-time due)
|
||||
:invoice_number invoice-number
|
||||
:vendor {:id vendor-id}
|
||||
:vendor {:id vendor-id :name vendor-name}
|
||||
:outstanding_balance outstanding})
|
||||
bills-due-soon)
|
||||
:upcoming_credits (into (mapv
|
||||
@@ -768,7 +809,7 @@
|
||||
(attach-resolvers {
|
||||
:get-yodlee-provider-account-page gq-yodlee2/get-yodlee-provider-account-page
|
||||
:get-all-sales-orders get-all-sales-orders
|
||||
:get-accounts gq-accounts/get-accounts
|
||||
:get-accounts gq-accounts/get-graphql
|
||||
:get-sales-order-page gq-sales-orders/get-sales-orders-page
|
||||
:get-transaction-rule-page gq-transaction-rules/get-transaction-rule-page
|
||||
:get-transaction-rule-matches gq-transaction-rules/get-transaction-rule-matches
|
||||
@@ -777,6 +818,8 @@
|
||||
:get-cash-flow get-cash-flow
|
||||
:get-yodlee-merchants ym/get-yodlee-merchants
|
||||
:get-intuit-bank-accounts gq-intuit-bank-accounts/get-intuit-bank-accounts
|
||||
:vendor-by-id gq-vendors/get-by-id
|
||||
:account-for-vendor gq-accounts/default-for-vendor
|
||||
:get-user get-user
|
||||
:mutation/delete-transaction-rule gq-transaction-rules/delete-transaction-rule
|
||||
:mutation/edit-user gq-users/edit-user
|
||||
@@ -787,7 +830,9 @@
|
||||
:mutation/upsert-account gq-accounts/upsert-account
|
||||
:mutation/merge-vendors gq-vendors/merge-vendors
|
||||
:mutation/request-import gq-requests/request-import
|
||||
:get-vendor gq-vendors/get-graphql})
|
||||
:get-vendor gq-vendors/get-graphql
|
||||
:search-vendor gq-vendors/search
|
||||
:search-account gq-accounts/search})
|
||||
gq-checks/attach
|
||||
gq-ledger/attach
|
||||
gq-reports/attach
|
||||
|
||||
@@ -1,39 +1,53 @@
|
||||
(ns auto-ap.graphql.accounts
|
||||
(:require [datomic.api :as d]
|
||||
[auto-ap.datomic.accounts :as d-accounts]
|
||||
[auto-ap.graphql.utils :refer [->graphql <-graphql enum->keyword] ]
|
||||
[auto-ap.datomic :refer [uri merge-query remove-nils audit-transact]]
|
||||
[clojure.tools.logging :as log]))
|
||||
(:require
|
||||
[auto-ap.datomic :refer [audit-transact conn remove-nils]]
|
||||
[auto-ap.datomic.accounts :as d-accounts]
|
||||
[auto-ap.graphql.utils
|
||||
:refer [->graphql
|
||||
<-graphql
|
||||
assert-admin
|
||||
assert-can-see-client
|
||||
enum->keyword
|
||||
result->page]]
|
||||
[datomic.api :as d]))
|
||||
|
||||
(defn get-graphql [context args _]
|
||||
(assert-admin (:id context))
|
||||
(let [args (assoc args :id (:id context))
|
||||
[accounts accounts-count ] (d-accounts/get-graphql (<-graphql args))]
|
||||
(result->page accounts accounts-count :accounts args)))
|
||||
|
||||
(defn default-for-vendor [context args _]
|
||||
(assert-can-see-client (:id context) (:client_id args))
|
||||
(let [result (d-accounts/get-for-vendor (:vendor_id args) (:client_id args))]
|
||||
(->graphql (d-accounts/clientize result (:client_id args)))))
|
||||
|
||||
(defn get-accounts [context args value]
|
||||
(->graphql (d-accounts/get-accounts (<-graphql args))))
|
||||
|
||||
(defn upsert-account [context args value]
|
||||
(defn upsert-account [context args _]
|
||||
(let [{{:keys [id client-overrides numeric-code location applicability account-set name type]} :account} (<-graphql args)]
|
||||
(when-not id
|
||||
(when (seq (d/query {:query {:find ['?e]
|
||||
:in '[$ ?account-set ?numeric-code]
|
||||
:where ['[?e :account/account-set ?account-set]
|
||||
'[?e :account/numeric-code ?numeric-code]]}
|
||||
:args [(d/db (d/connect uri)) account-set numeric-code]}))
|
||||
:args [(d/db conn) account-set numeric-code]}))
|
||||
|
||||
(throw (ex-info (str "Account set " account-set " already has an account for code " numeric-code)
|
||||
{} ))))
|
||||
|
||||
(let [original (if id (d/entity (d/db (d/connect uri)) id))
|
||||
(let [original (when id
|
||||
(d/entity (d/db conn) id))
|
||||
result (audit-transact (cond->
|
||||
[(remove-nils
|
||||
{:db/id (or id "new-account")
|
||||
:account/name name
|
||||
:account/search-terms name
|
||||
:account/type (keyword "account-type" (clojure.core/name type))
|
||||
:account/applicability (enum->keyword applicability "account-applicability")
|
||||
:account/account-set account-set
|
||||
:account/location location
|
||||
:account/numeric-code (if-not id
|
||||
:account/numeric-code (when-not id
|
||||
numeric-code)
|
||||
:account/code (if-not id
|
||||
:account/code (when-not id
|
||||
(str numeric-code))})
|
||||
[:reset (or id "new-account") :account/client-overrides
|
||||
(mapv
|
||||
@@ -41,10 +55,55 @@
|
||||
(remove-nils
|
||||
{:db/id (:id client-override)
|
||||
:account-client-override/client (:client-id client-override)
|
||||
:account-client-override/name (:name client-override)}))
|
||||
:account-client-override/name (:name client-override)
|
||||
:account-client-override/search-terms (:name client-override)}))
|
||||
client-overrides)]]
|
||||
(and (not location) (:account/location original)) (conj [:db/retract (or id "new-account") :account/location (:account/location original)]))
|
||||
(:id context))]
|
||||
(->graphql
|
||||
(d-accounts/get-by-id (or id (get-in result [:tempids "new-account"])))))))
|
||||
|
||||
(defn search [context {query :query client :client_id} _]
|
||||
(when client
|
||||
(assert-can-see-client (:id context) client))
|
||||
(let [num (some-> (re-find #"([0-9]+)" query)
|
||||
second
|
||||
(not-empty )
|
||||
Integer/parseInt)]
|
||||
(if num
|
||||
(->> (d/q '[:find ?n (pull ?i [:db/id :account/numeric-code :account/location])
|
||||
:in $ ?numeric-code
|
||||
:where [?i :account/numeric-code ?numeric-code]
|
||||
[?i :account/name ?n]]
|
||||
(d/db conn)
|
||||
num)
|
||||
(map (fn [[n a]]
|
||||
{:name (str (:account/numeric-code a) " - " n)
|
||||
:id (:db/id a)
|
||||
:location (:account/location a)})))
|
||||
|
||||
(->> (d/q '[:find ?n (pull ?i [:db/id :account/numeric-code :account/location]) ?s
|
||||
:in $ ?q
|
||||
:where [(fulltext $ :account/search-terms ?q) [[?i ?n _ ?s]]]
|
||||
[?i :account/numeric-code ?numeric-code]
|
||||
(or [?i :account/applicability :account-applicability/global]
|
||||
[?i :account/applicability :account-applicability/optional])]
|
||||
(d/db conn)
|
||||
query)
|
||||
(concat (when client
|
||||
(d/q '[:find ?n (pull ?a [:db/id :account/numeric-code :account/location]) ?s
|
||||
:in $ ?c ?q
|
||||
:where
|
||||
[?i :account-client-override/client ?c]
|
||||
[(fulltext $ :account-client-override/search-terms ?q) [[?i ?n _ ?s]]]
|
||||
[?a :account/client-overrides ?i]
|
||||
[?a :account/numeric-code ?numeric-code]]
|
||||
(d/db conn)
|
||||
client
|
||||
query)))
|
||||
(sort-by (comp - last))
|
||||
(map (fn [[n a]]
|
||||
{:name (str (:account/numeric-code a) " - " n)
|
||||
:id (:db/id a)
|
||||
:location (:account/location a)}))))))
|
||||
|
||||
|
||||
@@ -366,7 +366,12 @@
|
||||
(let [type (keyword "payment-type" (name type))
|
||||
invoices (d-invoices/get-multi (map :invoice-id invoice-payments))
|
||||
client (d-clients/get-by-id client-id)
|
||||
vendors (by :db/id (d-vendors/get-graphql {}))
|
||||
vendors (->> (d/q '[:find [?e ...]
|
||||
:in $
|
||||
:where [?e :vendor/name]]
|
||||
(d/db conn))
|
||||
(d/pull-many (d/db conn) d-vendors/default-read)
|
||||
(by :db/id))
|
||||
invoice-amounts (by :invoice-id :amount invoice-payments)
|
||||
invoices-grouped-by-vendor (group-by (comp :db/id :invoice/vendor) invoices)
|
||||
bank-account (d-bank-accounts/get-by-id bank-account-id)
|
||||
|
||||
@@ -307,6 +307,7 @@
|
||||
(assert (:invoice/client invoice))
|
||||
(assert-can-see-client (:id context) (:db/id (:invoice/client invoice)))
|
||||
(assert-not-locked (:db/id (:invoice/client invoice)) (:invoice/date invoice))
|
||||
(assert (not (seq (:invoice-payment/_invoice invoice))))
|
||||
(audit-transact [[:db/add id :invoice/status :invoice-status/unpaid]
|
||||
[:db/add id :invoice/outstanding-balance (:invoice/total invoice)]
|
||||
[:db/retract id :invoice/scheduled-payment (:invoice/scheduled-payment invoice)]]
|
||||
|
||||
@@ -134,13 +134,18 @@
|
||||
|
||||
(defn bulk-code-transactions [context args _]
|
||||
(assert-admin (:id context))
|
||||
(when-not (:client_id args)
|
||||
(throw (ex-info "Client is required"
|
||||
{:validation-error "client is required"})))
|
||||
(let [args (assoc args :id (:id context))
|
||||
locations (:client/locations (d/pull (d/db conn)
|
||||
[:client/locations]
|
||||
(:client_id (:filters args))))
|
||||
(:client_id args)))
|
||||
all-ids (all-ids-not-locked (get-ids-matching-filters args))
|
||||
transactions (d/pull-many (d/db conn) '[:db/id :transaction/amount] (vec all-ids))
|
||||
account-total (reduce + 0 (map (fn [x] (:percentage x)) (:accounts args)))]
|
||||
(log/info "client is" locations)
|
||||
|
||||
(when
|
||||
(and
|
||||
(seq (:accounts args))
|
||||
@@ -149,14 +154,13 @@
|
||||
(throw (ex-info error {:validation-error error}))))
|
||||
|
||||
(doseq [a (:accounts args)
|
||||
:let [{:keys [:account/location :account/name]} (d/entity (d/db conn) (:account_id a))
|
||||
client (d/entity (d/db conn) (:client_id (:filters args)))]]
|
||||
:let [{:keys [:account/location :account/name]} (d/entity (d/db conn) (:account_id a))]]
|
||||
(when (and location (not= location (:location a)))
|
||||
(let [err (str "Account " name " uses location " (:location a) ", but is supposed to be " location)]
|
||||
(throw (ex-info err {:validation-error err}) )))
|
||||
|
||||
(when (and (not location)
|
||||
(not (get (into #{"Shared"} (:client/locations client))
|
||||
(not (get (into #{"Shared"} locations)
|
||||
(:location a))))
|
||||
(let [err (str "Account " name " uses location " (:location a) ", but doesn't belong to the client.")]
|
||||
(throw (ex-info err {:validation-error err}) ))))
|
||||
@@ -599,6 +603,7 @@
|
||||
:resolve :mutation/bulk-change-transaction-status}
|
||||
:bulk_code_transactions {:type :message
|
||||
:args {:filters {:type :transaction_filters}
|
||||
:client_id {:type :id}
|
||||
:vendor {:type :id}
|
||||
:approval_status {:type :transaction_approval_status}
|
||||
:accounts {:type '(list :edit_percentage_account)}
|
||||
|
||||
@@ -1,23 +1,43 @@
|
||||
(ns auto-ap.graphql.vendors
|
||||
(:require [auto-ap.graphql.utils :refer [->graphql assert-can-see-client assert-admin is-admin? enum->keyword]]
|
||||
[auto-ap.datomic.vendors :as d-vendors]
|
||||
[auto-ap.time :refer [parse iso-date]]
|
||||
[datomic.api :as d]
|
||||
[auto-ap.datomic :refer [uri remove-nils audit-transact conn]]
|
||||
[clj-time.coerce :as coerce]
|
||||
[clojure.set :as set]
|
||||
[clojure.tools.logging :as log]))
|
||||
(:require
|
||||
[auto-ap.datomic :refer [audit-transact conn remove-nils]]
|
||||
[auto-ap.datomic.vendors :as d-vendors]
|
||||
[auto-ap.graphql.utils
|
||||
:refer [->graphql
|
||||
<-graphql
|
||||
assert-admin
|
||||
assert-failure
|
||||
enum->keyword
|
||||
is-admin?
|
||||
result->page]]
|
||||
[clojure.set :as set]
|
||||
[clojure.tools.logging :as log]
|
||||
[datomic.api :as d]))
|
||||
|
||||
(defn can-user-edit-vendor? [vendor-id id]
|
||||
(if (is-admin? id)
|
||||
true
|
||||
(empty?
|
||||
(set/difference (set (d/q '[:find [?c ...]
|
||||
:in $ ?v
|
||||
:where [?vu :vendor-usage/vendor ?v]
|
||||
[?vu :vendor-usage/client ?c]
|
||||
[?vu :vendor-usage/count ?d]
|
||||
[(>= ?d 0)]]
|
||||
(d/db conn)
|
||||
vendor-id))
|
||||
(set (map :db/id (:user/clients id)))))))
|
||||
|
||||
(defn upsert-vendor [context {{:keys [id name hidden terms code print_as primary_contact secondary_contact address default_account_id invoice_reminder_schedule schedule_payment_dom terms_overrides account_overrides] :as in} :vendor} value]
|
||||
(when id
|
||||
(assert-admin (:id context)))
|
||||
#_(Thread/sleep 3000)
|
||||
#_(throw (ex-info "" {:validation-error "can't do that."}))
|
||||
(let [hidden (if (is-admin? (:id context))
|
||||
|
||||
(when (and id (not (can-user-edit-vendor? id (:id context))))
|
||||
(assert-failure "This vendor is managed by Integreat. Please reach out to ben@integreatconsult.com for your changes."))
|
||||
(let [
|
||||
hidden (if (is-admin? (:id context))
|
||||
hidden
|
||||
false)
|
||||
|
||||
existing (when id
|
||||
(d/pull (d/db conn) '[:vendor/name] id))
|
||||
terms-overrides (mapv
|
||||
(fn [to]
|
||||
(cond->
|
||||
@@ -90,7 +110,8 @@
|
||||
(mapv
|
||||
(fn [apwd]
|
||||
{:db/id apwd})
|
||||
(:automatically_paid_when_due in))]))
|
||||
(:automatically_paid_when_due in))])
|
||||
(not= (:vendor/name existing) name) (conj [:reset (if id id "vendor") :vendor/search-terms [name]]))
|
||||
|
||||
_ (log/info "Upserting vendor" transaction)
|
||||
transaction-result (audit-transact transaction (:id context))]
|
||||
@@ -114,6 +135,34 @@
|
||||
(audit-transact transaction (:id context))
|
||||
to))
|
||||
|
||||
(defn get-graphql [context args value]
|
||||
|
||||
(defn get-graphql [context args _]
|
||||
(assert-admin (:id context))
|
||||
(let [args (assoc args :id (:id context))
|
||||
[vendors vendors-count ] (d-vendors/get-graphql (<-graphql args))]
|
||||
(result->page vendors vendors-count :vendors args)))
|
||||
|
||||
(defn get-by-id [context args _]
|
||||
(->graphql
|
||||
(d-vendors/get-graphql (assoc args :id (:id context)))))
|
||||
(d-vendors/get-graphql-by-id (assoc args :id (:id context))
|
||||
(:id args))))
|
||||
|
||||
(defn search [context args _]
|
||||
(let [data (if (is-admin? (:id context))
|
||||
(d/q '[:find ?n ?i ?s
|
||||
:in $ ?q
|
||||
:where [(fulltext $ :vendor/search-terms ?q) [[?i ?n _ ?s]]]]
|
||||
(d/db conn)
|
||||
(:query args))
|
||||
(d/q '[:find ?n ?i ?s
|
||||
:in $ ?q
|
||||
:where [(fulltext $ :vendor/search-terms ?q) [[?i ?n _ ?s]]]
|
||||
(not [?i :vendor/hidden true])]
|
||||
(d/db conn)
|
||||
(:query args)))]
|
||||
|
||||
(->> data
|
||||
(sort-by last)
|
||||
(map (fn [[n i]]
|
||||
{:name n
|
||||
:id i})))))
|
||||
|
||||
@@ -1,34 +1,18 @@
|
||||
(ns auto-ap.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[auto-ap.db :as db]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.effects :as effects]
|
||||
|
||||
[auto-ap.utils :refer [by]]
|
||||
[venia.core :as v]
|
||||
[bidi.bidi :as bidi]
|
||||
[cemerick.url :refer [url]]
|
||||
[goog.crypt.base64 :as b64]
|
||||
[clojure.string :as str]))
|
||||
(:require
|
||||
[auto-ap.db :as db]
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[auto-ap.views.utils :refer [with-user]]
|
||||
[bidi.bidi :as bidi]
|
||||
[clojure.string :as str]
|
||||
[goog.crypt.base64 :as b64]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn jwt->data [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]]
|
||||
[:schedule-payment-dom [[:client [:id :name]] :id :dom]]
|
||||
[:usage [:client-id :count]]
|
||||
[:primary-contact [:name :phone :email :id]]
|
||||
[:secondary-contact [:id :name :phone :email]]
|
||||
:print-as :invoice-reminder-schedule :code
|
||||
:legal-entity-first-name :legal-entity-middle-name :legal-entity-last-name
|
||||
:legal-entity-tin :legal-entity-tin-type
|
||||
:legal-entity-1099-type
|
||||
[:address [:street1 :street2 :city :state :zip]]])
|
||||
|
||||
(defn client-query [token]
|
||||
(cond-> [:id :name :signature-file :code :email :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits :locations :locked-until :square-auth-token
|
||||
@@ -47,7 +31,7 @@
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::initialize-db
|
||||
(fn [{:keys [db]} [_ token]]
|
||||
(fn [{:keys [_]} [_ token]]
|
||||
(let [handler (:handler (bidi/match-route routes/routes (.. js/window -location -pathname)))]
|
||||
(cond
|
||||
(= :login handler)
|
||||
@@ -78,12 +62,7 @@
|
||||
:query-params (auto-ap.views.utils/query-params)
|
||||
:user token)
|
||||
:graphql {:token token
|
||||
:query-obj {:venia/queries [[:client
|
||||
|
||||
(client-query token)]
|
||||
[:vendor
|
||||
vendor-query]
|
||||
[:accounts [:numeric-code :location :name :type :account_set :applicability :id [:client-overrides [:name :id [:client [:name :id]]]]]]]}
|
||||
:query-obj {:venia/queries [[:client (client-query token)]]}
|
||||
:on-success [::received-initial]
|
||||
:on-error [::failed-initial]}}))))
|
||||
|
||||
@@ -97,11 +76,7 @@
|
||||
::logged-in
|
||||
(fn [{:keys [db]} [_ token user]]
|
||||
{:graphql {:token token
|
||||
:query-obj {:venia/queries [[:client
|
||||
(client-query token)]
|
||||
[:vendor
|
||||
vendor-query]
|
||||
[:accounts [:numeric-code :name :location :type :account_set :applicability :id [:client-overrides [:name [:client [:name :id]]]]]]]}
|
||||
:query-obj {:venia/queries [[:client (client-query token)]]}
|
||||
|
||||
:on-success [::received-initial]
|
||||
:on-error [::failed-initial]}
|
||||
@@ -111,13 +86,11 @@
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::received-initial
|
||||
(fn [{:keys [db]} [_ {accounts :accounts clients :client vendors :vendor :as x}]]
|
||||
(fn [{:keys [db]} [_ {clients :client}]]
|
||||
|
||||
{:db (-> db
|
||||
(assoc :clients (by :id clients) )
|
||||
(assoc :vendors (by :id vendors) )
|
||||
(assoc :is-initial-loading? false)
|
||||
(assoc :accounts accounts )
|
||||
(assoc :client (or (when (= 1 (count clients)) (->> clients first :id ))
|
||||
(->> clients
|
||||
(map :id)
|
||||
@@ -180,36 +153,6 @@
|
||||
:auto-ap.forms/forms nil)
|
||||
(auto-ap.views.pages.data-page/dispose-all))})))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::imported-invoices
|
||||
(fn [db [_ new-invoices]]
|
||||
(assoc-in db [:invoices :pending] new-invoices)))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::view-pending-invoices
|
||||
(fn [cofx []]
|
||||
{:db (assoc-in (:db cofx) [:status :loading] true)
|
||||
:graphql {:token (-> cofx :db :user)
|
||||
:query-obj {:venia/queries [[:invoice
|
||||
{:imported false :client_id (:id @(re-frame/subscribe [::subs/client]))}
|
||||
[:id :total :invoice-number :date [:vendor [:name :id]] [:client [:name :id]]]]]}
|
||||
|
||||
:on-success [::received-invoices :pending]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::view-unpaid-invoices
|
||||
(fn [cofx []]
|
||||
{:db (assoc-in (:db cofx) [:status :loading] true)
|
||||
:graphql {:token (-> cofx :db :user)
|
||||
:query-obj {:venia/queries [[:invoice
|
||||
{:imported true :client_id (:id @(re-frame/subscribe [::subs/client]))}
|
||||
[:id :total :invoice-number :date [:vendor [:name :id]] [:client [:name :id]]]]]}
|
||||
:on-success [::received-invoices :unpaid]}}))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::submitted-new-invoice
|
||||
(fn [db [_ invoice]]
|
||||
(assoc db :new-invoice {})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::logout
|
||||
@@ -220,48 +163,6 @@
|
||||
:redirect (bidi/path-for routes/routes :login)
|
||||
:set-local-storage ["jwt" nil]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::submit-new-invoice
|
||||
(fn [{:keys [db]} [_ invoice]]
|
||||
{:http {:method :post
|
||||
:token (-> db :user)
|
||||
:uri "/api/invoices"
|
||||
:body (pr-str {:rows [(assoc invoice :imported true)]})
|
||||
:headers {"Content-Type" "application/edn"}
|
||||
:on-success [::submitted-new-invoice]}
|
||||
:db (assoc-in db [:new-invoice :loading?] true)}))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::received-invoices
|
||||
(fn [db [_ type result]]
|
||||
(let [new-invoices (if (:invoice result)
|
||||
(:invoice result)
|
||||
result)]
|
||||
(-> db
|
||||
(assoc-in [:invoices type] new-invoices)
|
||||
(assoc-in [:status :loading] false)))))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::change-form-state
|
||||
(fn [db [_ target value]]
|
||||
(assoc-in db target value)))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::change-nested-form-state
|
||||
(fn [db [_ form more value]]
|
||||
(update-in db form
|
||||
(fn [x]
|
||||
(assoc-in x more value)))))
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::page-failed
|
||||
(fn [db [_ result]]
|
||||
(println "Page failure" result)
|
||||
(assoc db :page-failure result
|
||||
:status nil)))
|
||||
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::yodlee-merchants-received
|
||||
@@ -275,3 +176,34 @@
|
||||
:query-obj {:venia/queries [[:yodlee-merchants
|
||||
[:name :yodlee-id :id]]]}
|
||||
:on-success [::yodlee-merchants-received]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::vendor-preferences-requested
|
||||
[with-user]
|
||||
(fn [{:keys [user]} [_ {:keys [ client-id vendor-id on-success on-failure owns-state]}]]
|
||||
{:graphql {:token user
|
||||
:query-obj {:venia/queries [[:vendor-by-id
|
||||
{:id vendor-id}
|
||||
[[:automatically-paid-when-due [:id]]
|
||||
[:schedule-payment-dom [[:client [:id]] :dom]]
|
||||
[:default-account [:id]]]]
|
||||
[:account-for-vendor
|
||||
{:vendor-id vendor-id
|
||||
:client-id client-id}
|
||||
[:name :id :numeric-code :location]]]}
|
||||
:owns-state owns-state
|
||||
:on-success (fn [r]
|
||||
(let [schedule-payment-dom (->> r
|
||||
:vendor-by-id
|
||||
:schedule-payment-dom
|
||||
(filter (fn [spd]
|
||||
(= (-> spd :client :id)
|
||||
client-id)))
|
||||
first
|
||||
:dom)
|
||||
automatically-paid-when-due (boolean ((->> r :vendor-by-id :automatically-paid-when-due (map :id) set) client-id))]
|
||||
(conj on-success {:default-account (:account-for-vendor r)
|
||||
:schedule-payment-dom schedule-payment-dom
|
||||
:automatically-paid-when-due automatically-paid-when-due
|
||||
:vendor-autopay? (or automatically-paid-when-due (boolean schedule-payment-dom))})))
|
||||
:on-failure on-failure}}))
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
(fn [db [_ x]]
|
||||
(get (-> db ::forms) x)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::field
|
||||
(fn [db [_ x f]]
|
||||
(-> (get (-> db ::forms) x)
|
||||
:data
|
||||
(get-in f))))
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::is-loading?
|
||||
|
||||
@@ -32,78 +32,6 @@
|
||||
(fn [db]
|
||||
(by :id (:accounts db))))
|
||||
|
||||
(defn clientize-account [account client]
|
||||
(let [override (->>
|
||||
(:client-overrides account)
|
||||
(filter (fn [co]
|
||||
(= (:id (:client co)) (:id client))))
|
||||
first)]
|
||||
(condp = (:applicability account)
|
||||
nil
|
||||
(assoc account :name (or (:name override) (:name account)))
|
||||
|
||||
:global
|
||||
(assoc account :name (or (:name override) (:name account)))
|
||||
|
||||
:optional
|
||||
(when override
|
||||
(assoc account :name (or (:name override) (:name account))))
|
||||
|
||||
:customized
|
||||
(when override
|
||||
(assoc account :name (or (:name override) (:name account)))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::accounts
|
||||
:<- [::all-accounts]
|
||||
:<- [::client]
|
||||
(fn [[accounts client] [_ client-override]]
|
||||
(transduce
|
||||
(comp
|
||||
(map
|
||||
#(clientize-account % (or client-override client)))
|
||||
(filter identity))
|
||||
conj
|
||||
[]
|
||||
accounts)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::accounts-index
|
||||
:<- [::accounts]
|
||||
(fn [accounts]
|
||||
(doto (MiniSearch. #js {:fields #js ["numeric-code" "name" "content"]
|
||||
:storeFields #js ["id" "numeric-code" "name" "content"]})
|
||||
(.addAll (clj->js (map (fn [v] {:id (:id v)
|
||||
:name (:name v)
|
||||
:numeric-code (:numeric-code v)
|
||||
:content (str (:numeric-code v) " " (:name v))})
|
||||
accounts))))))
|
||||
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::account
|
||||
(fn [[_ client]]
|
||||
[(re-frame/subscribe [::accounts-by-id client])])
|
||||
(fn [[as] [_ _ i]]
|
||||
(as i)))
|
||||
|
||||
(defn accounts-by-id [accounts client]
|
||||
(by :id
|
||||
(map
|
||||
#(clientize-account % client)
|
||||
|
||||
accounts)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::accounts-by-id
|
||||
(fn [[_ client-override]]
|
||||
[(re-frame/subscribe [::accounts client-override])
|
||||
(re-frame/subscribe [::client])])
|
||||
(fn [[accounts client] ]
|
||||
(accounts-by-id accounts client)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::bank-accounts
|
||||
:<- [::clients]
|
||||
@@ -181,116 +109,11 @@
|
||||
(fn [db]
|
||||
(::intuit-bank-accounts db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::modal-state
|
||||
(fn [db [_ id status-from]]
|
||||
(if status-from
|
||||
(assoc (get (:modal-state db) id)
|
||||
:error-message (get-in db [:auto-ap.forms/forms status-from :error])
|
||||
:saving? (= (get-in db [:auto-ap.forms/forms status-from :status]) :loading))
|
||||
(get (:modal-state db) id))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::token
|
||||
(fn [db]
|
||||
(:user db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::vendors
|
||||
:<- [::is-admin?]
|
||||
:<- [::all-vendors]
|
||||
(fn [[is-admin all-vendors]]
|
||||
(filter #(or (not (:hidden %))
|
||||
is-admin) all-vendors)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::searchable-vendors
|
||||
:<- [::is-admin?]
|
||||
:<- [::client]
|
||||
:<- [::all-vendors]
|
||||
(fn [[is-admin client all-vendors]]
|
||||
(cond is-admin
|
||||
all-vendors
|
||||
|
||||
client
|
||||
(filter (fn [{:keys [hidden usage]}]
|
||||
(or (not hidden)
|
||||
(-> (first (filter #(= (:client-id %)
|
||||
(:id client))
|
||||
usage))
|
||||
(:count 0)
|
||||
(> 0))))
|
||||
all-vendors)
|
||||
|
||||
|
||||
:else
|
||||
|
||||
|
||||
(filter #(not (:hidden %)) all-vendors))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::searchable-vendors-index
|
||||
:<- [::searchable-vendors]
|
||||
(fn [searchable-vendors]
|
||||
(doto (MiniSearch. #js {:fields #js ["name" "content"]
|
||||
:storeFields #js ["id" "name" "content" "usage"]})
|
||||
(.addAll (clj->js (map (fn [v] {:id (:id v)
|
||||
:name (:name v)
|
||||
:content (:name v)
|
||||
:usage (:usage v)})
|
||||
searchable-vendors))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::all-vendors-index
|
||||
:<- [::all-vendors]
|
||||
(fn [all-vendors]
|
||||
(doto (MiniSearch. #js {:fields #js ["name" "content"]
|
||||
:storeFields #js ["id" "name" "content" "usage"]})
|
||||
(.addAll (clj->js (map (fn [v] {:id (:id v)
|
||||
:name (:name v)
|
||||
:content (:name v)
|
||||
:usage (:usage v)})
|
||||
all-vendors))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::all-vendors
|
||||
(fn [db]
|
||||
(vals (:vendors db))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::vendors-by-id
|
||||
(fn [db]
|
||||
(:vendors db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::vendor-default-account
|
||||
(fn [db [_ v client]]
|
||||
(let [accounts (accounts-by-id (:accounts db) client)
|
||||
vendor (if (map? v)
|
||||
v
|
||||
(-> (:vendors db) (get v)))
|
||||
client-override (->> (:account-overrides vendor)
|
||||
(filter #(= (:id (:client %)) (:id client))
|
||||
)
|
||||
first
|
||||
:account
|
||||
:id)
|
||||
default-id (:id (:default-account vendor))
|
||||
i (or client-override default-id)]
|
||||
(accounts i))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::sorted-vendors
|
||||
:<- [::vendors]
|
||||
(fn [vendors]
|
||||
(sort-by :name vendors)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::sorted-all-vendors
|
||||
:<- [::all-vendors]
|
||||
(fn [all-vendors]
|
||||
(sort-by :name all-vendors)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::admin
|
||||
(fn [db]
|
||||
@@ -320,22 +143,6 @@
|
||||
(fn [db]
|
||||
(:active-page db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::pending-invoices
|
||||
(fn [db]
|
||||
(:pending (:invoices db))))
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::status
|
||||
(fn [db]
|
||||
(:status db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::new-invoice-form
|
||||
(fn [db]
|
||||
(:new-invoice db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::query-params
|
||||
(fn [db]
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
(ns auto-ap.views.components.expense-accounts-dialog
|
||||
(:require [auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.pages.invoices.common :refer [invoice-read]]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[clojure.string :as str]
|
||||
[goog.string :as gstring]
|
||||
[re-frame.core :as re-frame]))
|
||||
(:require
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.components.typeahead.vendor :refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.invoices.common :refer [invoice-read]]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[clojure.string :as str]
|
||||
[goog.string :as gstring]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
@@ -95,7 +96,6 @@
|
||||
{:keys [total] :or {total 0} {:keys [locations] :as client} :client} (:invoice data)
|
||||
{:keys [form-inline horizontal-field field raw-field error-notification submit-button]} change-expense-accounts-form
|
||||
multi-location? (> (count locations) 1)
|
||||
chooseable-expense-accounts @(re-frame/subscribe [::subs/accounts client])
|
||||
expense-accounts-total (->> expense-accounts
|
||||
vals
|
||||
(map :new-amount)
|
||||
@@ -124,14 +124,17 @@
|
||||
[:tr
|
||||
[:td.expandable [:div.control
|
||||
(raw-field
|
||||
[typeahead-v3 {:entities chooseable-expense-accounts
|
||||
:type "typeahead-v3"
|
||||
:entity->text (fn [x] (str (:numeric-code x) " - " (:name x)))
|
||||
:field [:expense-accounts id :account]}])]]
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_account
|
||||
{:query i
|
||||
:client-id (:id client)}
|
||||
[:name :id :location]])
|
||||
:type "typeahead-v3"
|
||||
:field [:expense-accounts id :account]}])]]
|
||||
|
||||
(when multi-location?
|
||||
[:td
|
||||
(if-let [forced-location (:location @(re-frame/subscribe [::subs/account client (get-in expense-accounts [id :account :id])]))]
|
||||
(if-let [forced-location (get-in expense-accounts [id :account :location])]
|
||||
[:div.select
|
||||
[:select {:disabled "disabled" :value forced-location} [:option {:value forced-location} forced-location]]]
|
||||
[:div.select
|
||||
@@ -175,21 +178,17 @@
|
||||
(re-frame/reg-event-fx
|
||||
::show
|
||||
(fn [{:keys [db]} [_ i]]
|
||||
(let [accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id])]
|
||||
{:dispatch [::modal/modal-requested {:title "Change expense accounts"
|
||||
:body [form]
|
||||
:confirm {:value "Save"
|
||||
:status-from [::status/single ::form]
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::try-save])
|
||||
:can-submit [::can-submit]
|
||||
:close-event [::status/completed ::form]}}]
|
||||
:db (-> db
|
||||
(forms/start-form ::form
|
||||
{:dispatch [::modal/modal-requested {:title "Change expense accounts"
|
||||
:body [form]
|
||||
:confirm {:value "Save"
|
||||
:status-from [::status/single ::form]
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::try-save])
|
||||
:can-submit [::can-submit]
|
||||
:close-event [::status/completed ::form]}}]
|
||||
:db (-> db
|
||||
(forms/start-form ::form
|
||||
|
||||
{:expense-accounts (by :id
|
||||
(mapv
|
||||
(fn [ea]
|
||||
(assoc ea :account (accounts-by-id (:id (:account ea)))))
|
||||
(:expense-accounts i)))
|
||||
:invoice i}))})))
|
||||
{:expense-accounts (by :id
|
||||
(:expense-accounts i))
|
||||
:invoice i}))}))
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
(ns auto-ap.views.components.expense-accounts-field
|
||||
(:require [auto-ap.forms :as forms]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.money-field :refer [money-field]]
|
||||
[auto-ap.views.utils :refer [bind-field dispatch-event ->$]]
|
||||
[goog.string :as gstring]
|
||||
[re-frame.core :as re-frame]
|
||||
[clojure.string :as str]))
|
||||
(:require
|
||||
[auto-ap.views.utils :refer [->$ bind-field dispatch-event]]
|
||||
[auto-ap.views.components.typeahead.vendor :refer [search-backed-typeahead]]
|
||||
[clojure.string :as str]
|
||||
[goog.string :as gstring]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn can-replace-with-default? [accounts]
|
||||
(and (or (not (seq accounts))
|
||||
@@ -14,8 +12,7 @@
|
||||
(not (get-in accounts [0 :account :id]))))
|
||||
|
||||
(defn default-account [accounts default-account amount locations]
|
||||
[{:id (get-in accounts [0 :id]
|
||||
(str "new-" (random-uuid)))
|
||||
[{:id (str "new-" (random-uuid))
|
||||
:amount (Math/abs amount)
|
||||
:amount-percentage 100
|
||||
:amount-mode "%"
|
||||
@@ -28,14 +25,11 @@
|
||||
:account default-account}])
|
||||
|
||||
|
||||
(defn from-graphql [accounts accounts-by-id total locations]
|
||||
(defn from-graphql [accounts total locations]
|
||||
(if (seq accounts)
|
||||
(vec (map
|
||||
(fn [a]
|
||||
(-> a
|
||||
(update :account (fn [a]
|
||||
(accounts-by-id (:id a))))
|
||||
|
||||
(update :amount js/parseFloat)
|
||||
(assoc :amount-percentage (* 100 (/ (js/parseFloat (:amount a))
|
||||
(Math/abs total))))
|
||||
@@ -95,14 +89,10 @@
|
||||
(re-frame/reg-event-fx
|
||||
::expense-account-changed
|
||||
(fn [_ [_ event expense-accounts max-value field value]]
|
||||
(println field value)
|
||||
(let [updated-accounts (cond-> expense-accounts
|
||||
true (assoc-in field value)
|
||||
(= (list :account) (drop 1 field)) (assoc-in [(first field) :location] nil)
|
||||
|
||||
(= (list :account :id) (drop 1 field)) (-> (assoc-in [(first field) :account] @(re-frame/subscribe [::subs/account nil value]))
|
||||
(assoc-in [(first field) :location] nil))
|
||||
|
||||
(= (list :amount-percentage) (drop 1 field)) (assoc-in [(first field) :amount]
|
||||
(js/parseFloat
|
||||
(goog.string/format "%.2f"
|
||||
@@ -119,111 +109,111 @@
|
||||
|
||||
;; VIEWS
|
||||
(defn expense-accounts-field [{expense-accounts :value client :client max-value :max locations :locations event :event descriptor :descriptor disabled :disabled percentage-only? :percentage-only? :or {percentage-only? false}}]
|
||||
(let [chooseable-expense-accounts @(re-frame/subscribe [::subs/accounts client])
|
||||
accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id client])]
|
||||
[:div
|
||||
[:div.columns
|
||||
[:div.column
|
||||
[:h1.subtitle.is-4.is-inline (str/capitalize descriptor) "s"]
|
||||
(when-not percentage-only?
|
||||
[:p.help "Remaining " (->$ (- max-value (reduce + 0 (map (comp js/parseFloat :amount) expense-accounts))))])]
|
||||
[:div.column.is-narrow
|
||||
(when-not disabled
|
||||
[:p.buttons
|
||||
[:a.button {:on-click (dispatch-event [::spread-evenly event expense-accounts max-value])} "Spread evenly"]
|
||||
[:a.button {:on-click (dispatch-event [::add-expense-account event expense-accounts locations])} "Add"]])]]
|
||||
[:div
|
||||
[:div.columns
|
||||
[:div.column
|
||||
[:h1.subtitle.is-4.is-inline (str/capitalize descriptor) "s"]
|
||||
(when-not percentage-only?
|
||||
[:p.help "Remaining " (->$ (- max-value (reduce + 0 (map (comp js/parseFloat :amount) expense-accounts))))])]
|
||||
[:div.column.is-narrow
|
||||
(when-not disabled
|
||||
[:p.buttons
|
||||
[:a.button {:on-click (dispatch-event [::spread-evenly event expense-accounts max-value])} "Spread evenly"]
|
||||
[:a.button {:on-click (dispatch-event [::add-expense-account event expense-accounts locations])} "Add"]])]]
|
||||
|
||||
(for [[index {:keys [account id location amount amount-percentage amount-mode] :as expense-account}] (map vector (range) expense-accounts)
|
||||
:let [account (accounts-by-id (:id account))]]
|
||||
^{:key id}
|
||||
[:div.box
|
||||
[:div.columns
|
||||
[:div.column
|
||||
[:h1.subtitle.is-6 (cond (and account (not percentage-only?))
|
||||
(str (:name account) " - "
|
||||
location ": "
|
||||
(gstring/format "$%.2f" (or amount 0) ))
|
||||
(for [[index {:keys [account id location amount amount-percentage amount-mode] :as expense-account}] (map vector (range) expense-accounts)]
|
||||
^{:key id}
|
||||
[:div.box
|
||||
[:div.columns
|
||||
[:div.column
|
||||
[:h1.subtitle.is-6 (cond (and account (not percentage-only?))
|
||||
(str (:name account) " - "
|
||||
location ": "
|
||||
(gstring/format "$%.2f" (or amount 0) ))
|
||||
|
||||
account
|
||||
(str (:name account) " - "
|
||||
location ": %"
|
||||
amount-percentage)
|
||||
account
|
||||
(str (:name account) " - "
|
||||
location ": %"
|
||||
amount-percentage)
|
||||
|
||||
:else
|
||||
[:i "New " descriptor])]]
|
||||
[:div.column.is-narrow
|
||||
(when-not disabled
|
||||
[:a.delete {:on-click (dispatch-event [::remove-expense-account event expense-accounts id])}])]]
|
||||
|
||||
[:div.field
|
||||
[:div.columns
|
||||
[:div.column
|
||||
[:p.help "Account"]
|
||||
[:div.control.is-fullwidth
|
||||
[bind-field
|
||||
^{:key (:id client)}
|
||||
[typeahead-v3 {:entities chooseable-expense-accounts
|
||||
:entity->text (fn [x ]
|
||||
(str (:numeric-code x) " - " (:name x)))
|
||||
:disabled disabled
|
||||
:type "typeahead-v3"
|
||||
:field [index :account]
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:subscription expense-accounts}]]]]
|
||||
[:div.column.is-narrow
|
||||
[:p.help "Location"]
|
||||
[:div.control
|
||||
(if-let [forced-location (:location account)]
|
||||
[:div.select
|
||||
[:select {:disabled "disabled" :style {:width "5em"} :value forced-location} [:option {:value forced-location} forced-location]]]
|
||||
[:div.select
|
||||
[bind-field
|
||||
[:select {:type "select"
|
||||
:disabled (boolean (or (:location account)
|
||||
disabled))
|
||||
:style {:width "5em"}
|
||||
:field [index :location]
|
||||
:allow-nil? true
|
||||
:spec (set locations)
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:subscription expense-accounts}
|
||||
(map (fn [l] ^{:key l} [:option {:value l} l]) locations)]]])]]]]
|
||||
|
||||
[:div.field
|
||||
[:p.help "Amount"]
|
||||
:else
|
||||
[:i "New " descriptor])]]
|
||||
[:div.column.is-narrow
|
||||
(when-not disabled
|
||||
[:a.delete {:on-click (dispatch-event [::remove-expense-account event expense-accounts id])}])]]
|
||||
|
||||
[:div.field
|
||||
[:div.columns
|
||||
[:div.column
|
||||
[:p.help "Account"]
|
||||
[:div.control.is-fullwidth
|
||||
[bind-field
|
||||
^{:key (:id client)}
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_account
|
||||
{:query i
|
||||
:client-id (:id client)}
|
||||
[:name :id :location]])
|
||||
:type "typeahead-v3"
|
||||
:field [index :account]
|
||||
|
||||
:disabled disabled
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:subscription expense-accounts}]]]]
|
||||
[:div.column.is-narrow
|
||||
[:p.help "Location"]
|
||||
[:div.control
|
||||
[:div.field.has-addons.is-extended
|
||||
[:p.control [:span.select
|
||||
[bind-field
|
||||
[:select {:type "select"
|
||||
:disabled (or disabled percentage-only?)
|
||||
:field [index :amount-mode]
|
||||
:allow-nil? false
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:subscription expense-accounts}
|
||||
[:option "$"]
|
||||
[:option "%"]]]]]
|
||||
[:p.control
|
||||
(if (= "$" amount-mode)
|
||||
[bind-field
|
||||
[:input.input {:type "number"
|
||||
:field [index :amount]
|
||||
:style {:text-align "right" :width "7em"}
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:disabled disabled
|
||||
:subscription expense-accounts
|
||||
:precision 2
|
||||
:value (get-in expense-account [:amount])
|
||||
:max max-value
|
||||
:step "0.01"}]]
|
||||
[bind-field
|
||||
[:input.input {:type "number"
|
||||
:field [index :amount-percentage]
|
||||
:style {:text-align "right" :width "7em"}
|
||||
:disabled disabled
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:precision 2
|
||||
:subscription expense-accounts
|
||||
:value (get-in expense-account [:amount-percentage])
|
||||
:max "100"
|
||||
:step "0.01"}]])]]]]])]))
|
||||
(if-let [forced-location (:location account)]
|
||||
[:div.select
|
||||
[:select {:disabled "disabled" :style {:width "5em"} :value forced-location} [:option {:value forced-location} forced-location]]]
|
||||
[:div.select
|
||||
[bind-field
|
||||
[:select {:type "select"
|
||||
:disabled (boolean (or (:location account)
|
||||
disabled))
|
||||
:style {:width "5em"}
|
||||
:field [index :location]
|
||||
:allow-nil? true
|
||||
:spec (set locations)
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:subscription expense-accounts}
|
||||
(map (fn [l] ^{:key l} [:option {:value l} l]) locations)]]])]]]]
|
||||
|
||||
[:div.field
|
||||
[:p.help "Amount"]
|
||||
[:div.control
|
||||
[:div.field.has-addons.is-extended
|
||||
[:p.control [:span.select
|
||||
[bind-field
|
||||
[:select {:type "select"
|
||||
:disabled (or disabled percentage-only?)
|
||||
:field [index :amount-mode]
|
||||
:allow-nil? false
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:subscription expense-accounts}
|
||||
[:option "$"]
|
||||
[:option "%"]]]]]
|
||||
[:p.control
|
||||
(if (= "$" amount-mode)
|
||||
[bind-field
|
||||
[:input.input {:type "number"
|
||||
:field [index :amount]
|
||||
:style {:text-align "right" :width "7em"}
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:disabled disabled
|
||||
:subscription expense-accounts
|
||||
:precision 2
|
||||
:value (get-in expense-account [:amount])
|
||||
:max max-value
|
||||
:step "0.01"}]]
|
||||
[bind-field
|
||||
[:input.input {:type "number"
|
||||
:field [index :amount-percentage]
|
||||
:style {:text-align "right" :width "7em"}
|
||||
:disabled disabled
|
||||
:event [::expense-account-changed event expense-accounts max-value]
|
||||
:precision 2
|
||||
:subscription expense-accounts
|
||||
:value (get-in expense-account [:amount-percentage])
|
||||
:max "100"
|
||||
:step "0.01"}]])]]]]])])
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
[auto-ap.views.utils :refer [date->str dispatch-event dispatch-event-with-propagation nf days-until]]
|
||||
[bidi.bidi :as bidi]
|
||||
[cemerick.url :as url]
|
||||
[cljs-time.core :as t]
|
||||
[clojure.string :as str]
|
||||
[goog.string :as gstring]
|
||||
[re-frame.core :as re-frame]
|
||||
@@ -51,7 +50,7 @@
|
||||
[[:invoices [:id :total :outstanding-balance :invoice-number :date :due :status :client-identifier :scheduled-payment :source-url :similarity
|
||||
[:vendor [:name :id]]
|
||||
[:expense_accounts [:amount :id :location
|
||||
[:account [:id ]]]]
|
||||
[:account [:id :name :location]]]]
|
||||
[:client [:name :id :locations]]
|
||||
[:payments [:amount :id [:payment [:id :status :amount :s3_url :check_number
|
||||
[:transaction [:post_date]]]]]]]]
|
||||
@@ -112,14 +111,13 @@
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::invoice-updated
|
||||
(fn [{:keys [db]} [_ invoice]]
|
||||
(fn [{:keys [db]} [_ _]]
|
||||
{:db db}))
|
||||
|
||||
(defn row [{:keys [invoice check-boxes selected-client overrides checkable? expense-event actions]}]
|
||||
(defn row [{:keys [invoice selected-client overrides checkable? actions]}]
|
||||
(let [{:keys [client status payments expense-accounts invoice-number date due total outstanding-balance id vendor source-url] :as i} invoice
|
||||
accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id client])
|
||||
unautopay-states @(re-frame/subscribe [::status/multi ::unautopay])
|
||||
account->name #(:name (accounts-by-id (:id %)))]
|
||||
editing-states @(re-frame/subscribe [::status/multi ::edits])]
|
||||
[grid/row {:class (:class i) :id id :checkable? checkable? :entity invoice}
|
||||
(when-not selected-client
|
||||
[grid/cell {}
|
||||
@@ -142,9 +140,8 @@
|
||||
|
||||
[grid/cell {:class "has-text-right"} (nf total )]
|
||||
[grid/cell {:class "has-text-right"}
|
||||
(if (:scheduled-payment i)
|
||||
[:<> [:div.tag.is-info.is-light "Autopay"] " "]
|
||||
)
|
||||
(when (:scheduled-payment i)
|
||||
[:<> [:div.tag.is-info.is-light "Autopay"] " "])
|
||||
(nf outstanding-balance )]
|
||||
[grid/button-cell {}
|
||||
[:div.buttons
|
||||
@@ -159,7 +156,7 @@
|
||||
[:div
|
||||
(for [e expense-accounts]
|
||||
^{:key (:id e)}
|
||||
[:span.dropdown-item (account->name (:account e)) " " (gstring/format "$%.2f" (:amount e) ) ])
|
||||
[:span.dropdown-item (:name (:account e)) " " (gstring/format "$%.2f" (:amount e) ) ])
|
||||
|
||||
(when (get actions :expense-accounts)
|
||||
[:<>
|
||||
@@ -213,7 +210,14 @@
|
||||
(when (and (get actions :edit)
|
||||
(not= ":voided" (:status i)))
|
||||
[buttons/fa-icon {:icon "fa-pencil"
|
||||
:event [::form/editing i]}])
|
||||
:class (status/class-for (get editing-states id))
|
||||
:event
|
||||
[::events/vendor-preferences-requested {:client-id (:id client)
|
||||
:vendor-id (:id vendor)
|
||||
:on-success [::form/editing i]
|
||||
:on-failure []
|
||||
:owns-state {:multi ::edits
|
||||
:which (:id i)}}]}])
|
||||
(when (and (get actions :void)
|
||||
(= (:outstanding-balance i) (:total i)) (not= ":voided" (:status i)))
|
||||
[buttons/sl-icon {:icon "icon-bin-2"
|
||||
@@ -224,22 +228,20 @@
|
||||
:event [::unvoid-invoice i]}])
|
||||
(when (and (get actions :void)
|
||||
(= ":paid" (:status i))
|
||||
(:scheduled-payment i))
|
||||
(:scheduled-payment i)
|
||||
(not (seq (:payments i))))
|
||||
[buttons/fa-icon {:icon "fa-undo"
|
||||
:class (status/class-for (get unautopay-states (:id i)))
|
||||
:event [::unautopay i]}])]]]))
|
||||
|
||||
(defn invoice-table [{:keys [id check-boxes overrides actions data-page checkable-fn]}]
|
||||
(let [selected-client @(re-frame/subscribe [::subs/client])
|
||||
{:keys [data status params table-params]} @(re-frame/subscribe [::data-page/page data-page])
|
||||
|
||||
(defn invoice-table [{:keys [check-boxes overrides actions data-page checkable-fn]}]
|
||||
(let [{:keys [data status params table-params]} @(re-frame/subscribe [::data-page/page data-page])
|
||||
selected-client @(re-frame/subscribe [::subs/client])
|
||||
is-loading? (= :loading (:state status))
|
||||
is-sorted-by-vendor? (and (= "vendor" (:sort-key (first (:sort table-params))))
|
||||
(not is-loading?)
|
||||
(or (apply <= (map (comp :name :vendor) (:data data)))
|
||||
(apply >= (map (comp :name :vendor) (:data data)))))
|
||||
|
||||
[invoice-groups] (if is-sorted-by-vendor?
|
||||
(reduce
|
||||
(fn [[acc last-vendor] invoice]
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
(ns auto-ap.views.components.invoices.side-bar
|
||||
(:require [auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.date-range-filter :refer [date-range-filter]]
|
||||
[auto-ap.views.components.number-filter :refer [number-filter]]
|
||||
[auto-ap.views.components.switch-field :refer [switch-field]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [active-when dispatch-event dispatch-value-change]]
|
||||
[bidi.bidi :as bidi]
|
||||
[re-frame.core :as re-frame]))
|
||||
(:require
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.date-range-filter :refer [date-range-filter]]
|
||||
[auto-ap.views.components.number-filter :refer [number-filter]]
|
||||
[auto-ap.views.components.switch-field :refer [switch-field]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils
|
||||
:refer [active-when dispatch-event dispatch-value-change]]
|
||||
[bidi.bidi :as bidi]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn invoice-number-filter [{:keys [data-page]}]
|
||||
[:div.field
|
||||
@@ -59,12 +62,13 @@
|
||||
[:div
|
||||
[:p.menu-label "Vendor"]
|
||||
[:div
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor (some-> % (select-keys [:name :id]))])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
[:p.menu-label "Date Range"]
|
||||
[:div
|
||||
[date-range-filter
|
||||
|
||||
@@ -1,53 +1,51 @@
|
||||
(ns auto-ap.views.components.layouts
|
||||
(:require
|
||||
[reagent.core :as reagent]
|
||||
[re-frame.core :as re-frame]
|
||||
[bidi.bidi :as bidi]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.views.utils :refer [active-when active-when= login-url dispatch-event appearing css-transition-group bind-field]]
|
||||
[auto-ap.views.components.dropdown :refer [drop-down drop-down-contents]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.entities.vendors :as vendor]
|
||||
[clojure.string :as str]
|
||||
[reagent.core :as r]
|
||||
[auto-ap.views.components.vendor-dialog :as vendor-dialog]
|
||||
[auto-ap.views.components.buttons :as buttons]))
|
||||
|
||||
[auto-ap.views.utils
|
||||
:refer [active-when appearing bind-field dispatch-event dispatch-event-with-propagation login-url]]
|
||||
[bidi.bidi :as bidi]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(defn navbar-drop-down-contents [{:keys [id]} children ]
|
||||
(let [toggle-fn (fn [] (re-frame/dispatch [::events/toggle-menu id]))]
|
||||
(reagent/create-class {:component-did-mount (fn [] (.addEventListener js/document "click" toggle-fn))
|
||||
(r/create-class {:component-did-mount (fn [] (.addEventListener js/document "click" toggle-fn))
|
||||
:component-will-unmount (fn [] (.removeEventListener js/document "click" toggle-fn))
|
||||
:reagent-render
|
||||
(fn [children]
|
||||
children)})))
|
||||
|
||||
(defn navbar-drop-down [{:keys [ header id class]} child]
|
||||
(let [menu-active? (re-frame/subscribe [::subs/menu-active? id])]
|
||||
(reagent/create-class
|
||||
{:reagent-render (fn [{:keys [header id]} child]
|
||||
(let [menu-active? @(re-frame/subscribe [::subs/menu-active? id])]
|
||||
[:div { :class (str "navbar-item has-dropdown " (when menu-active? "is-active " ) " " class)}
|
||||
[:a {:class "navbar-link login" :on-click (fn [e]
|
||||
(.preventDefault e)
|
||||
(.stopPropagation e)
|
||||
(re-frame/dispatch [::events/toggle-menu id])
|
||||
true)} header]
|
||||
[appearing {:visible? menu-active? :enter-class "appear" :exit-class "disappear" :timeout 200}
|
||||
[:div {:class "navbar-dropdown"}
|
||||
[navbar-drop-down-contents {:id id}
|
||||
[:div child]]]]]))})))
|
||||
(r/create-class
|
||||
{:reagent-render (fn [{:keys [header id]} child]
|
||||
(let [menu-active? @(re-frame/subscribe [::subs/menu-active? id])]
|
||||
[:div { :class (str "navbar-item has-dropdown " (when menu-active? "is-active " ) " " class)}
|
||||
[:a {:class "navbar-link login" :on-click (fn [e]
|
||||
(.preventDefault e)
|
||||
(.stopPropagation e)
|
||||
(re-frame/dispatch [::events/toggle-menu id])
|
||||
true)} header]
|
||||
[appearing {:visible? menu-active? :enter-class "appear" :exit-class "disappear" :timeout 200}
|
||||
[:div {:class "navbar-dropdown"}
|
||||
[navbar-drop-down-contents {:id id}
|
||||
[:div child]]]]]))}))
|
||||
|
||||
(defn login-dropdown []
|
||||
(let [user (re-frame/subscribe [::subs/user])
|
||||
menu (re-frame/subscribe [::subs/menu])]
|
||||
(let [user (re-frame/subscribe [::subs/user])]
|
||||
(if @user
|
||||
[navbar-drop-down {:header [:span [:span.icon [:i.fa.fa-user] ]
|
||||
[:span (:user/name @user)]] :id ::account}
|
||||
[:div
|
||||
[:a {:class "navbar-item"
|
||||
:href (bidi/path-for routes/routes :reports)} "My company"]
|
||||
[:a.dropdown-item {:on-click (dispatch-event-with-propagation [::vendor-dialog/started {}])} "New Vendor"]
|
||||
[:a.dropdown-item {:on-click (dispatch-event-with-propagation [::vendor-dialog/edit {}])} "Edit Vendor"]
|
||||
(when (= "admin" (:user/role @user))
|
||||
[:a {:class "navbar-item" :href (bidi/path-for routes/routes :admin)} "Administration"])
|
||||
[:hr {:class "navbar-divider"}]
|
||||
@@ -133,11 +131,6 @@
|
||||
|
||||
(when-not is-initial-loading
|
||||
[:div.navbar-end
|
||||
[:div.navbar-item
|
||||
[buttons/new-button {:event [::vendor-dialog/started {}]
|
||||
:name "Vendor"
|
||||
:class "is-primary"}]]
|
||||
|
||||
|
||||
(when (> (count @clients) 1)
|
||||
[navbar-drop-down {:header (str "Company: " (if @client (:name @client)
|
||||
@@ -188,8 +181,7 @@
|
||||
|
||||
(defn side-bar-layout [{:keys [side-bar main ap bottom right-side-bar]}]
|
||||
(let [ap @(re-frame/subscribe [::subs/active-page])
|
||||
client @(re-frame/subscribe [::subs/client])
|
||||
is-initial-loading @(re-frame/subscribe [::subs/is-initial-loading?])]
|
||||
client @(re-frame/subscribe [::subs/client])]
|
||||
[:div
|
||||
[modal/global-modal]
|
||||
[navbar ap]
|
||||
|
||||
130
src/cljs/auto_ap/views/components/typeahead/vendor.cljs
Normal file
130
src/cljs/auto_ap/views/components/typeahead/vendor.cljs
Normal file
@@ -0,0 +1,130 @@
|
||||
(ns auto-ap.views.components.typeahead.vendor
|
||||
(:require
|
||||
[downshift :as ds :refer [useCombobox]]
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.views.utils :refer [with-user]]
|
||||
[react]))
|
||||
|
||||
(set! *warn-on-infer* true)
|
||||
|
||||
;; TODO: This avoids the use of inferred externs by using aget. You could just use the ^js tag though
|
||||
(defn state-reducer [^js/FakeStateObject state ^js/FakeActionsAndChanges actions-and-changes]
|
||||
(let [useCombobox ^js/Downshift useCombobox]
|
||||
(cond
|
||||
(= (.-type actions-and-changes) (.-InputChange (.-stateChangeTypes ^js/Downshift useCombobox)))
|
||||
(set! (.-selectedItem (.-changes actions-and-changes)) nil)
|
||||
|
||||
(and (= (.-type actions-and-changes) (.-InputBlur (.-stateChangeTypes ^js/Downshift useCombobox)))
|
||||
(not (.-selectedItem state)))
|
||||
(set! (.-inputValue (.-changes actions-and-changes ))
|
||||
nil)
|
||||
|
||||
:else
|
||||
nil))
|
||||
(.-changes actions-and-changes))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::search-completed
|
||||
(fn [_ [_ set-items set-loading-status result]]
|
||||
(set-loading-status nil)
|
||||
(set-items (:search-results result))
|
||||
{}))
|
||||
(re-frame/reg-event-fx
|
||||
::search-failed
|
||||
(fn [_ _]
|
||||
{}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::input-value-settled
|
||||
[with-user]
|
||||
(fn [{:keys [user]} [_ input-value search-query set-items set-loading-status]]
|
||||
(when (> (count input-value) 2)
|
||||
(set-loading-status :loading)
|
||||
|
||||
|
||||
{:graphql {:token user
|
||||
:query-obj {:venia/queries [{:query/data (search-query input-value )
|
||||
:query/alias :search-results}]}
|
||||
:on-success [::search-completed set-items set-loading-status]
|
||||
:on-error [::search-failed set-loading-status]}})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::input-value-changed
|
||||
(fn [_ [_ input-value search-query set-items set-loading-status]]
|
||||
(set-items [])
|
||||
(when (> (count input-value) 2)
|
||||
(set-loading-status :loading)
|
||||
{:dispatch-debounce {:event [::input-value-settled input-value search-query set-items set-loading-status]
|
||||
:time 250
|
||||
:key ::input-value-settled}})))
|
||||
|
||||
(defn typeahead-v3-internal [{:keys [class style ^js on-change disabled value name search-query auto-focus] :or {disabled false} :as i}]
|
||||
(let [[items set-items] (react/useState [])
|
||||
[loading-status set-loading-status] (react/useState false)
|
||||
[getLabelProps getMenuProps getComboboxProps getToggleButtonProps getInputProps getItemProps isOpen highlightedIndex selectItem selectedItem setInputValue]
|
||||
(as-> (useCombobox (clj->js {:items items
|
||||
:defaultHighlightedIndex 0
|
||||
:defaultSelectedItem value
|
||||
:onInputValueChange (fn [input]
|
||||
(re-frame/dispatch [::input-value-changed (aget input "inputValue") search-query set-items set-loading-status])
|
||||
true)
|
||||
:stateReducer state-reducer
|
||||
:onSelectedItemChange (fn [z]
|
||||
(when on-change
|
||||
(on-change (js->clj (aget z "selectedItem") :keywordize-keys true))))})) $
|
||||
(map #(aget $ %) ["getLabelProps" "getMenuProps" "getComboboxProps" "getToggleButtonProps" "getInputProps" "getItemProps" "isOpen" "highlightedIndex" "selectItem" "selectedItem" "setInputValue"]))]
|
||||
[:<>
|
||||
[:div.typeahead (assoc (js->clj (getComboboxProps))
|
||||
:style style)
|
||||
(cond
|
||||
selectedItem
|
||||
^{:key "typeahead"}
|
||||
[:div.input (assoc (js->clj (getInputProps #js {:disabled (if disabled
|
||||
"disabled"
|
||||
"")}))
|
||||
:on-key-up (fn [e]
|
||||
(when (= 8 (aget e "keyCode" ))
|
||||
(selectItem nil)
|
||||
(setInputValue nil)
|
||||
(when on-change
|
||||
(on-change nil))))
|
||||
:class (if (= :loading loading-status)
|
||||
"is-loading"
|
||||
class)
|
||||
:tab-index "0")
|
||||
[:div.control
|
||||
[:div.tags.has-addons
|
||||
[:span.tag (:name (js->clj selectedItem :keywordize-keys true))]
|
||||
(when name
|
||||
[:input {:type "hidden" :name name :value (:id (js->clj selectedItem :keywordize-keys true))}])
|
||||
(when-not disabled
|
||||
[:a.tag.is-delete {:on-click (fn []
|
||||
(setInputValue nil)
|
||||
(selectItem nil)
|
||||
(when on-change
|
||||
(on-change nil)))}])]]]
|
||||
|
||||
:else
|
||||
^{:key "typeahead"} [:div.control {:class (when (= :loading loading-status)
|
||||
"is-loading")}
|
||||
[:input.input (js->clj
|
||||
(getInputProps #js {:disabled (if disabled
|
||||
"disabled"
|
||||
"")
|
||||
:autoFocus (if auto-focus
|
||||
"autoFocus"
|
||||
"")}))]])
|
||||
[:div {:class (when (and isOpen (seq items))
|
||||
"typeahead-menu")}
|
||||
[:ul (js->clj (getMenuProps))
|
||||
(if (and isOpen (seq items))
|
||||
(for [[index item] (map vector (range) (js->clj items :keywordize-keys true))]
|
||||
^{:key item}
|
||||
[:li.typeahead-suggestion (assoc (js->clj (getItemProps #js {:item item :index index}))
|
||||
:class (if (= index highlightedIndex)
|
||||
"typeahead-highlighted"))
|
||||
(:name item)]))]]]]))
|
||||
|
||||
(defn search-backed-typeahead [props]
|
||||
[:div
|
||||
[:f> typeahead-v3-internal props]])
|
||||
@@ -1,19 +1,24 @@
|
||||
(ns auto-ap.views.components.vendor-dialog
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[auto-ap.views.utils :refer [dispatch-event horizontal-field bind-field with-user with-is-admin? active-when account->match-text]]
|
||||
[auto-ap.views.components.address :refer [address-field]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.dropdown :refer [drop-down drop-down-contents]]
|
||||
[auto-ap.events :as events]
|
||||
[clj-fuzzy.metrics :refer [jaccard jaro-winkler]]
|
||||
[clojure.spec.alpha :as s]
|
||||
[clojure.string :as str]
|
||||
[auto-ap.entities.vendors :as entity]
|
||||
[auto-ap.entities.contact :as contact]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.status :as status]))
|
||||
(:require
|
||||
[auto-ap.entities.contact :as contact]
|
||||
[auto-ap.entities.vendors :as entity]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.address :refer [address-field]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.pages.admin.vendors.common :as common]
|
||||
[auto-ap.views.utils
|
||||
:refer [bind-field
|
||||
dispatch-event
|
||||
horizontal-field
|
||||
with-is-admin?
|
||||
with-user]]
|
||||
[clojure.spec.alpha :as s]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
@@ -21,32 +26,12 @@
|
||||
(fn [form]
|
||||
(s/valid? ::entity/vendor (:data form))))
|
||||
|
||||
(defn ngrams [text len]
|
||||
(mapv #(.toLowerCase (str/join "" %))
|
||||
(partition len 1 text)))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::settled
|
||||
[(forms/in-form ::vendor-form)]
|
||||
(fn [{:keys [data] :as form} _]
|
||||
form
|
||||
#_(let [vendors @(re-frame/subscribe [::subs/vendors])
|
||||
text (.toLowerCase (:name data ""))
|
||||
matching-vendor (when (> (count text) 5)
|
||||
(->> vendors
|
||||
(filter #(not= (:id %) (:id data)))
|
||||
(map :name)
|
||||
(mapcat
|
||||
(fn [v] (mapv
|
||||
(fn [n] [v (jaro-winkler text n ) n text])
|
||||
(ngrams v (count text)))))
|
||||
(filter #(> (second %) 0.9))
|
||||
|
||||
(map first)
|
||||
first))]
|
||||
(if matching-vendor
|
||||
(assoc form :warning (str "Are you sure you don't mean " matching-vendor "?"))
|
||||
(dissoc form :warning)))))
|
||||
(fn [form _]
|
||||
form))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::removed-override
|
||||
@@ -73,7 +58,7 @@
|
||||
:event [::settled]})]
|
||||
(forms/change-handler
|
||||
::vendor-form
|
||||
(fn [data field value]
|
||||
(fn [data field _]
|
||||
(let [[override-key? i?] field]
|
||||
(if (and (#{:account-overrides :terms-overrides :schedule-payment-dom} override-key?)
|
||||
(nil? (get-in data [override-key? i? :key])))
|
||||
@@ -83,64 +68,60 @@
|
||||
(re-frame/reg-event-fx
|
||||
::save-complete
|
||||
[(forms/triggers-stop ::vendor-form)]
|
||||
(fn [{:keys [db]} [_ {vendor :upsert-vendor} ]]
|
||||
{:dispatch [::modal/modal-closed ]
|
||||
:db (-> db (assoc-in [:vendors (:id vendor)] vendor))}))
|
||||
(fn [_ [_ _ ]]
|
||||
{:dispatch [::modal/modal-closed ]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::save
|
||||
[with-user with-is-admin? (forms/triggers-loading ::vendor-form) (forms/in-form ::vendor-form)]
|
||||
(fn [{:keys [user is-admin?] {{:keys [name hidden print-as terms invoice-reminder-schedule primary-contact automatically-paid-when-due schedule-payment-dom secondary-contact address default-account terms-overrides account-overrides id legal-entity-tin legal-entity-tin-type legal-entity-first-name legal-entity-last-name legal-entity-middle-name legal-entity-1099-type] :as data} :data} :db} _]
|
||||
(println data)
|
||||
(when (s/valid? ::entity/vendor data)
|
||||
{ :graphql
|
||||
{:token user
|
||||
:owns-state {:single ::vendor-form}
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
:operation/name "UpsertVendor"} :venia/queries [{:query/data [:upsert-vendor
|
||||
{:vendor (doto (cond-> {:id id
|
||||
:name name
|
||||
:print-as print-as
|
||||
:terms terms
|
||||
:default-account-id (:id default-account)
|
||||
:address address
|
||||
:primary-contact primary-contact
|
||||
:secondary-contact secondary-contact
|
||||
:invoice-reminder-schedule invoice-reminder-schedule}
|
||||
is-admin? (assoc :hidden hidden
|
||||
:terms-overrides (mapv
|
||||
(fn [{:keys [client override id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:terms override})
|
||||
terms-overrides)
|
||||
:account-overrides (mapv
|
||||
(fn [{:keys [client override id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:account-id (:id override)})
|
||||
account-overrides)
|
||||
:schedule-payment-dom (mapv
|
||||
(fn [{:keys [client override id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:dom override})
|
||||
schedule-payment-dom)
|
||||
:automatically-paid-when-due (mapv
|
||||
:id
|
||||
automatically-paid-when-due)
|
||||
:legal-entity-first-name legal-entity-first-name
|
||||
:legal-entity-middle-name legal-entity-middle-name
|
||||
:legal-entity-last-name legal-entity-last-name
|
||||
:legal-entity-tin legal-entity-tin
|
||||
:legal-entity-tin-type (some-> legal-entity-tin-type clojure.core/name not-empty keyword)
|
||||
:legal-entity-1099-type (some-> legal-entity-1099-type clojure.core/name not-empty keyword)
|
||||
))
|
||||
println)}
|
||||
events/vendor-query]}]}
|
||||
{:vendor (cond-> {:id id
|
||||
:name name
|
||||
:print-as print-as
|
||||
:terms terms
|
||||
:default-account-id (:id default-account)
|
||||
:address address :primary-contact primary-contact
|
||||
:secondary-contact secondary-contact
|
||||
:invoice-reminder-schedule invoice-reminder-schedule}
|
||||
is-admin? (assoc :hidden hidden
|
||||
:terms-overrides (mapv
|
||||
(fn [{:keys [client override id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:terms override})
|
||||
terms-overrides)
|
||||
:account-overrides (mapv
|
||||
(fn [{:keys [client override id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:account-id (:id override)})
|
||||
account-overrides)
|
||||
:schedule-payment-dom (mapv
|
||||
(fn [{:keys [client override id]}]
|
||||
{:id id
|
||||
:client-id (:id client)
|
||||
:dom override})
|
||||
schedule-payment-dom)
|
||||
:automatically-paid-when-due (mapv
|
||||
:id
|
||||
automatically-paid-when-due)
|
||||
:legal-entity-first-name legal-entity-first-name
|
||||
:legal-entity-middle-name legal-entity-middle-name
|
||||
:legal-entity-last-name legal-entity-last-name
|
||||
:legal-entity-tin legal-entity-tin
|
||||
:legal-entity-tin-type (some-> legal-entity-tin-type clojure.core/name not-empty keyword)
|
||||
:legal-entity-1099-type (some-> legal-entity-1099-type clojure.core/name not-empty keyword)
|
||||
))}
|
||||
common/default-read]}]}
|
||||
:on-success [::save-complete]}})))
|
||||
|
||||
(defn client-list [{:keys [override-key override-value-key change-event default-key data]} template]
|
||||
(defn client-list [{:keys [override-key change-event data]}]
|
||||
(let [clients @(re-frame/subscribe [::subs/clients])
|
||||
is-admin? @(re-frame/subscribe [::subs/is-admin?])]
|
||||
(when is-admin?
|
||||
@@ -164,7 +145,7 @@
|
||||
[:div.column.is-1
|
||||
[:a.button {:on-click (dispatch-event [::removed-override override-key i])} [:span.icon [:span.icon-remove]]]]]))])))
|
||||
|
||||
(defn default-with-overrides [{:keys [override-key override-value-key change-event default-key data mandatory?]} template]
|
||||
(defn default-with-overrides [{:keys [override-key change-event default-key data mandatory?]} template]
|
||||
(let [clients @(re-frame/subscribe [::subs/clients])
|
||||
is-admin? @(re-frame/subscribe [::subs/is-admin?])]
|
||||
[:div
|
||||
@@ -201,7 +182,7 @@
|
||||
[:div.column.is-1
|
||||
[:a.button {:on-click (dispatch-event [::removed-override override-key i])} [:span.icon [:span.icon-remove]]]]]))])]))
|
||||
|
||||
(defn client-overrides [{:keys [override-key override-value-key change-event data mandatory?]} template]
|
||||
(defn client-overrides [{:keys [override-key change-event data]} template]
|
||||
(let [clients @(re-frame/subscribe [::subs/clients])
|
||||
is-admin? @(re-frame/subscribe [::subs/is-admin?])]
|
||||
(when is-admin?
|
||||
@@ -231,9 +212,7 @@
|
||||
[:a.button {:on-click (dispatch-event [::removed-override override-key i])} [:span.icon [:span.icon-remove]]]]]))])))
|
||||
|
||||
(defn form-content [{:keys [data change-event]}]
|
||||
(let [accounts @(re-frame/subscribe [::subs/accounts])
|
||||
clients @(re-frame/subscribe [::subs/clients])
|
||||
is-admin? @(re-frame/subscribe [::subs/is-admin?])]
|
||||
(let [is-admin? @(re-frame/subscribe [::subs/is-admin?])]
|
||||
[:div
|
||||
[horizontal-field
|
||||
[:label.label [:span "Name "
|
||||
@@ -271,7 +250,7 @@
|
||||
[default-with-overrides {:data data :change-event change-event
|
||||
:default-key :terms
|
||||
:override-key :terms-overrides}
|
||||
(fn [field client]
|
||||
(fn [field _]
|
||||
[:input.input {:type "number"
|
||||
:step "1"
|
||||
:style {:width "4em"}
|
||||
@@ -281,15 +260,17 @@
|
||||
:event change-event
|
||||
:subscription data}])]
|
||||
|
||||
[:h2.subtitle "Schedule payment when due"]
|
||||
(when is-admin?
|
||||
[:h2.subtitle "Schedule payment when due"])
|
||||
[client-list {:data data :change-event change-event
|
||||
:override-key :automatically-paid-when-due}]
|
||||
|
||||
[:h2.subtitle "Schedule payment on day of month"]
|
||||
(when is-admin?
|
||||
[:h2.subtitle "Schedule payment on day of month"])
|
||||
[client-overrides {:data data :change-event change-event
|
||||
:mandatory? true
|
||||
:override-key :schedule-payment-dom}
|
||||
(fn [field client]
|
||||
(fn [field _]
|
||||
[:input.input {:type "number"
|
||||
:step "1"
|
||||
:style {:width "5em"}
|
||||
@@ -305,13 +286,15 @@
|
||||
:default-key :default-account
|
||||
:override-key :account-overrides}
|
||||
(fn [field client]
|
||||
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/accounts client])
|
||||
:entity->text account->match-text
|
||||
:field field
|
||||
:type "typeahead-v3"
|
||||
:event change-event
|
||||
:subscription data}])]
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_account
|
||||
{:query i
|
||||
:client-id (:id client)}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:field field
|
||||
:event change-event
|
||||
:subscription data}])]
|
||||
|
||||
[:h2.subtitle "Address"]
|
||||
[address-field {:field [:address]
|
||||
@@ -467,17 +450,56 @@
|
||||
[:option {:value nil} ""]
|
||||
[:option {:value "none"} "Don't 1099"]
|
||||
[:option {:value "misc"} "Misc"]
|
||||
[:option {:value "landlord"} "Landlord"]]]]]]
|
||||
]))
|
||||
[:option {:value "landlord"} "Landlord"]]]]]]]))
|
||||
|
||||
(defn vendor-dialog [{:keys [save-event] }]
|
||||
(let [clients @(re-frame/subscribe [::subs/clients])
|
||||
all-vendors @(re-frame/subscribe [::subs/vendors])
|
||||
{:keys [data error warning] :as f} @(re-frame/subscribe [::forms/form ::vendor-form])
|
||||
(defn vendor-dialog [ ]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::vendor-form])
|
||||
change-event [::changed]]
|
||||
[:div
|
||||
[form-content {:data data :change-event change-event}]]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::vendor-selected
|
||||
[with-user (forms/in-form ::select-vendor-form)]
|
||||
(fn [{{:keys [data]} :db :keys [user]} _]
|
||||
{:graphql {:token user
|
||||
:query-obj {:venia/queries [[:vendor-by-id
|
||||
{:id (:id (:vendor data))}
|
||||
common/default-read]]}
|
||||
:owns-state {:single ::select-vendor-form}
|
||||
:on-success (fn [r]
|
||||
(println (:vendor-by-id r))
|
||||
[::started (:vendor-by-id r)])}}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit-select-vendor-form
|
||||
:<- [::forms/field ::select-vendor-form [:vendor]]
|
||||
(fn [vendor]
|
||||
(if vendor
|
||||
true
|
||||
false)))
|
||||
|
||||
(def select-vendor-form (forms/vertical-form {:submit-event [::vendor-selected]
|
||||
:change-event [::forms/change ::select-vendor-form]
|
||||
:can-submit [::can-submit-select-vendor-form]
|
||||
:id ::select-vendor-form}))
|
||||
|
||||
(defn select-vendor-form-content []
|
||||
(let [_ @(re-frame/subscribe [::forms/form ::select-vendor-form])
|
||||
{:keys [form-inline field]} select-vendor-form]
|
||||
(form-inline {}
|
||||
[:<>
|
||||
(field "Vendor to edit"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:vendor]}])])))
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::started
|
||||
(fn [{:keys [db]} [_ vendor]]
|
||||
@@ -504,10 +526,7 @@
|
||||
(update :automatically-paid-when-due #(mapv identity %))
|
||||
(update :hidden #(if (nil? %)
|
||||
false
|
||||
%))
|
||||
(update :default-account
|
||||
(fn [da]
|
||||
@(re-frame/subscribe [::subs/account nil (:id da)]))))))
|
||||
%)))))
|
||||
:dispatch [::modal/modal-requested
|
||||
{:title "Vendor"
|
||||
:class "is-wide"
|
||||
@@ -518,3 +537,18 @@
|
||||
:on-click (dispatch-event [::save])
|
||||
:can-submit [::can-submit]
|
||||
:close-event [::status/completed ::vendor-form]}}]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::edit
|
||||
(fn [{:keys [db]} [_]]
|
||||
{:db (-> db (forms/start-form ::select-vendor-form {}))
|
||||
:dispatch [::modal/modal-requested
|
||||
{:title "Select Vendor"
|
||||
:class "is-wide"
|
||||
:body [select-vendor-form-content]
|
||||
:confirm {:value "Choose a vendor"
|
||||
:status-from [::status/single ::select-vendor-form]
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::vendor-selected])
|
||||
:can-submit [::can-submit-select-vendor-form]
|
||||
:close-event [::status/completed ::select-vendor-form]}}]}))
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
[auto-ap.utils :refer [replace-by]]
|
||||
[auto-ap.views.components.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.pages.admin.accounts.side-bar :as side-bar]
|
||||
[auto-ap.views.utils :refer [dispatch-event action-cell-width]]
|
||||
[auto-ap.views.pages.admin.accounts.table :as table]
|
||||
[auto-ap.views.utils :refer [dispatch-event action-cell-width with-user]]
|
||||
[auto-ap.views.components.layouts
|
||||
:refer
|
||||
[appearing-side-bar side-bar-layout]]
|
||||
@@ -15,96 +16,55 @@
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[reagent.core :as reagent]
|
||||
[clojure.string :as str]
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[clojure.set :as set]
|
||||
[auto-ap.effects.forward :as forward]))
|
||||
|
||||
(def default-read [:numeric-code :name :location :type :account_set :applicability :id [:client-overrides [:name [:client [:name :id]]]]])
|
||||
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::edit-completed
|
||||
(fn [db [_ edit-account]]
|
||||
(-> db
|
||||
(update :accounts replace-by :id (assoc edit-account :class "live-added")))))
|
||||
(re-frame/reg-event-db
|
||||
::table-params-changed
|
||||
(fn [db [_ p]]
|
||||
(assoc db ::table-params p)))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
(fn [db [_ p]]
|
||||
{:set-uri-params p}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::table-params
|
||||
(fn [db]
|
||||
(-> db ::table-params)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::params
|
||||
:<- [::table-params]
|
||||
:<- [::side-bar/filter-params]
|
||||
(fn [[table-params filter-params]]
|
||||
(cond-> {}
|
||||
(seq filter-params) (merge filter-params)
|
||||
(seq table-params) (merge table-params))))
|
||||
[with-user]
|
||||
(fn [{:keys [user]} [_ params]]
|
||||
{:set-uri-params params
|
||||
:graphql {:token user
|
||||
:owns-state {:single [::data-page/page ::page]}
|
||||
:query-obj {:venia/queries [{:query/data [:account_page
|
||||
{:sort (:sort params)
|
||||
:start (:start params 0)
|
||||
:per-page (:per-page params)
|
||||
:name-like (:name-like params)
|
||||
:numeric-code (some-> params :numeric-code not-empty js/parseInt)}
|
||||
[[:accounts default-read]
|
||||
:total
|
||||
:start
|
||||
:end]]
|
||||
:query/alias :result}]}
|
||||
:on-success (fn [result]
|
||||
[::data-page/received ::page
|
||||
(set/rename-keys (:result result)
|
||||
{:accounts :data})])}}))
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (dissoc db ::table-params ::side-bar/filter-params)
|
||||
::track/dispose {:id ::params}}))
|
||||
(fn [_ _]
|
||||
{::track/dispose {:id ::params}
|
||||
::forward/dispose [{:id ::updated}]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [{:keys [db]} _]
|
||||
(fn [_ _]
|
||||
{::track/register {:id ::params
|
||||
:subscription [::params]
|
||||
:event-fn (fn [params] [::params-change params])}}))
|
||||
(re-frame/reg-sub
|
||||
::account-page
|
||||
:<- [::params]
|
||||
:<- [::subs/all-accounts]
|
||||
(fn [[params all-accounts]]
|
||||
(let [matching-accounts (cond->> all-accounts
|
||||
(:name-like params) (filter #(str/includes? (str/lower-case (or (:name %) ""))
|
||||
(str/lower-case (:name-like params))))
|
||||
(not-empty (:code-like params)) (filter #(str/starts-with? (str (or (:numeric-code %) ""))
|
||||
(str/lower-case (:code-like params)))))]
|
||||
(assoc (grid/virtual-paginate-controls (:start params ) (:per-page params) matching-accounts)
|
||||
:data (grid/virtual-paginate (:start params)
|
||||
(:per-page params)
|
||||
(sort-by :numeric-code matching-accounts))))))
|
||||
|
||||
(defn accounts-table [{:keys [accounts]}]
|
||||
(let [status @(re-frame/subscribe [::status/single ::page])
|
||||
opc (fn [p]
|
||||
(re-frame/dispatch [::table-params-changed p]))
|
||||
params @(re-frame/subscribe [::params])]
|
||||
|
||||
[:div
|
||||
[grid/grid {:status status
|
||||
:on-params-change opc
|
||||
:params params
|
||||
:column-count 5}
|
||||
[grid/controls accounts]
|
||||
[grid/table {:fullwidth true}
|
||||
[grid/header
|
||||
[grid/row {}
|
||||
[grid/header-cell {} "Code"]
|
||||
[grid/header-cell {} "Name"]
|
||||
[grid/header-cell {} "Type"]
|
||||
[grid/header-cell {} "Location"]
|
||||
[grid/header-cell {:style {:width (action-cell-width 1)}} ]]]
|
||||
[grid/body
|
||||
(for [{:keys [id numeric-code name type location class] :as account} (:data accounts)]
|
||||
^{:key id}
|
||||
[grid/row {:class (:class account) :id id}
|
||||
[grid/cell {} numeric-code]
|
||||
[grid/cell {} name]
|
||||
[grid/cell {} type]
|
||||
[grid/cell {} location]
|
||||
[grid/cell {}
|
||||
[buttons/fa-icon {:event [::account-form/editing account [::edit-completed]]
|
||||
:icon "fa-pencil"}]]])]]]]))
|
||||
:subscription [::data-page/params ::page]
|
||||
:event-fn (fn [params] [::params-change params])}
|
||||
::forward/register [{:id ::updated
|
||||
:events #{::account-form/edited}
|
||||
:event-fn (fn [[_ edited-account]]
|
||||
[::data-page/updated-entity ::page (:upsert-account edited-account)])}]}))
|
||||
|
||||
(defn admin-accounts-content []
|
||||
[:div
|
||||
@@ -114,9 +74,8 @@
|
||||
:class "is-primary"
|
||||
:event [::account-form/editing
|
||||
{:type :asset
|
||||
:account-set "default"}
|
||||
[::edit-completed]]}]]
|
||||
[accounts-table {:accounts @(re-frame/subscribe [::account-page])}]])
|
||||
:account-set "default"}]}]]
|
||||
[table/accounts-table {:data-page ::page}]])
|
||||
|
||||
(defn admin-accounts-page []
|
||||
(reagent/create-class
|
||||
@@ -127,6 +86,6 @@
|
||||
(fn []
|
||||
(let [{:keys [active?]} @(re-frame/subscribe [::forms/form ::account-form/form])]
|
||||
[side-bar-layout {:side-bar [admin-side-bar {}
|
||||
[side-bar/accounts-side-bar]]
|
||||
[side-bar/accounts-side-bar {:data-page ::page}]]
|
||||
:main [admin-accounts-content]
|
||||
:right-side-bar [appearing-side-bar {:visible? active?} [account-form/form ]]}]))}))
|
||||
|
||||
@@ -2,79 +2,24 @@
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.utils :refer [active-when dispatch-value-change]]))
|
||||
[auto-ap.views.utils :refer [dispatch-value-change]]
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::specific-filters
|
||||
(fn [db ]
|
||||
(::filters db nil)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::filters
|
||||
:<- [::specific-filters]
|
||||
:<- [::subs/vendors-by-id]
|
||||
:<- [::subs/query-params]
|
||||
(fn [[specific-filters vendors-by-id query-params] ]
|
||||
(let [url-filters (-> query-params
|
||||
(select-keys #{:name-like :code-like})
|
||||
(update :name-like #(some-> % str))
|
||||
(update :code-like #(some-> % str)))]
|
||||
(merge url-filters specific-filters ))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::filter
|
||||
:<- [::filters]
|
||||
(fn [filters [_ which]]
|
||||
(get filters which)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::settled-filters
|
||||
(fn [db ]
|
||||
(::settled-filters db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::filter-params
|
||||
:<- [::settled-filters]
|
||||
:<- [::filters]
|
||||
:<- [::subs/active-page]
|
||||
(fn [[settled-filters filters ap ]]
|
||||
(let [filters (or settled-filters filters)]
|
||||
{:name-like (:name-like filters)
|
||||
:code-like (:code-like filters)})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::filters-settled
|
||||
(fn [{:keys [db]} [_ & params]]
|
||||
{:db (assoc db ::settled-filters @(re-frame/subscribe [::filters]))}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::filter-changed
|
||||
(fn [{:keys [db]} [_ & params]]
|
||||
(let [[a b c] params
|
||||
[which val] (if (= 3 (count params))
|
||||
[(into [a] b) c]
|
||||
[[a] b])]
|
||||
{:db (assoc-in db (into [::filters] which) val)
|
||||
:dispatch-debounce {:event [::filters-settled]
|
||||
:time 800
|
||||
:key ::filters}})))
|
||||
|
||||
|
||||
(defn accounts-side-bar []
|
||||
(defn accounts-side-bar [{:keys [data-page]}]
|
||||
[:div
|
||||
[:p.menu-label "Name"]
|
||||
|
||||
[:div.field
|
||||
[:div.control [:input.input {:placeholder "Food Cost"
|
||||
:value @(re-frame/subscribe [::filter :name-like])
|
||||
:on-change (dispatch-value-change [::filter-changed :name-like])} ]]]
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :name-like])
|
||||
:on-change (dispatch-value-change [::data-page/filter-changed data-page :name-like])} ]]]
|
||||
|
||||
[:p.menu-label "Code"]
|
||||
|
||||
[:div.field
|
||||
[:div.control [:input.input {:placeholder "11000"
|
||||
:value @(re-frame/subscribe [::filter :code-like])
|
||||
:on-change (dispatch-value-change [::filter-changed :code-like])}]]]])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :numeric-code])
|
||||
:on-change (dispatch-value-change [::data-page/filter-changed data-page :numeric-code])}]]]])
|
||||
|
||||
|
||||
|
||||
36
src/cljs/auto_ap/views/pages/admin/accounts/table.cljs
Normal file
36
src/cljs/auto_ap/views/pages/admin/accounts/table.cljs
Normal file
@@ -0,0 +1,36 @@
|
||||
(ns auto-ap.views.pages.admin.accounts.table
|
||||
(:require
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.pages.admin.accounts.form :as account-form]
|
||||
[auto-ap.views.utils :refer [action-cell-width]]
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
|
||||
(defn accounts-table [{:keys [data-page]}]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::data-page/page data-page])]
|
||||
|
||||
[:div
|
||||
[grid/grid {:data-page data-page
|
||||
:column-count 5}
|
||||
[grid/controls data]
|
||||
[grid/table {:fullwidth true}
|
||||
[grid/header
|
||||
[grid/row {}
|
||||
[grid/header-cell {} "Code"]
|
||||
[grid/header-cell {} "Name"]
|
||||
[grid/header-cell {} "Type"]
|
||||
[grid/header-cell {} "Location"]
|
||||
[grid/header-cell {:style {:width (action-cell-width 1)}} ]]]
|
||||
[grid/body
|
||||
(for [{:keys [id numeric-code name type location class] :as account} (:data data)]
|
||||
^{:key id}
|
||||
[grid/row {:class (:class account) :id id}
|
||||
[grid/cell {} numeric-code]
|
||||
[grid/cell {} name]
|
||||
[grid/cell {} type]
|
||||
[grid/cell {} location]
|
||||
[grid/cell {}
|
||||
[buttons/fa-icon {:event [::account-form/editing account [::edit-completed]]
|
||||
:icon "fa-pencil"}]]])]]]]))
|
||||
@@ -1,26 +1,22 @@
|
||||
(ns auto-ap.views.pages.admin.rules
|
||||
(:require [auto-ap.forms :as forms]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.pages.admin.rules.side-bar :as side-bar]
|
||||
[auto-ap.views.components.layouts :refer [appearing-side-bar side-bar-layout]]
|
||||
[auto-ap.views.pages.admin.rules.table :as table]
|
||||
[auto-ap.views.pages.admin.rules.results-modal :as results-modal]
|
||||
[auto-ap.views.pages.admin.rules.form :as form]
|
||||
[auto-ap.views.pages.admin.rules.common :refer [default-read]]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[vimsical.re-frame.cofx.inject :as inject]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.utils :refer [replace-by merge-by]]
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.effects.forward :as forward]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[clojure.set :as set]
|
||||
[auto-ap.views.components.buttons :as buttons]))
|
||||
|
||||
|
||||
(:require
|
||||
[auto-ap.effects.forward :as forward]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.views.components.layouts
|
||||
:refer [appearing-side-bar side-bar-layout]]
|
||||
[auto-ap.views.pages.admin.rules.common :refer [default-read]]
|
||||
[auto-ap.views.pages.admin.rules.form :as form]
|
||||
[auto-ap.views.pages.admin.rules.side-bar :as side-bar]
|
||||
[auto-ap.views.pages.admin.rules.table :as table]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[clojure.set :as set]
|
||||
[re-frame.core :as re-frame]
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
|
||||
;; EVENTS
|
||||
|
||||
@@ -29,7 +25,7 @@
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
[with-user ]
|
||||
(fn [{:keys [db user] :as cofx} [_ params]]
|
||||
(fn [{:keys [user]} [_ params]]
|
||||
{:graphql {:token user
|
||||
:owns-state {:single [::data-page/page ::page]}
|
||||
:query-obj {:venia/queries [{:query/data [:transaction_rule_page
|
||||
@@ -52,13 +48,13 @@
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::new-rule-clicked
|
||||
(fn [{:keys [db]} _]
|
||||
(fn [_ _]
|
||||
{:dispatch [::form/adding {:client @(re-frame/subscribe [::subs/client])}]}))
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [{:keys [db]}]
|
||||
(fn [_]
|
||||
{:dispatch-n [[::events/yodlee-merchants-needed]]
|
||||
::forward/register [{:id ::page
|
||||
:events #{::form/updated}
|
||||
@@ -75,7 +71,7 @@
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn [{:keys [db]}]
|
||||
(fn [_]
|
||||
{:dispatch [::data-page/dispose ::page]
|
||||
::forward/dispose [{:id ::page}
|
||||
{:id ::deleted-transaction-rule}]
|
||||
@@ -85,8 +81,7 @@
|
||||
(def rules-content
|
||||
(with-meta
|
||||
(fn []
|
||||
(let [current-client @(re-frame/subscribe [::subs/client])
|
||||
user @(re-frame/subscribe [::subs/user])]
|
||||
(let [user @(re-frame/subscribe [::subs/user])]
|
||||
[:div
|
||||
[:h1.title "Transaction Rules"]
|
||||
(when (= "admin" (:user/role user))
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
(ns auto-ap.views.pages.admin.rules.form
|
||||
(:require [auto-ap.entities.transaction-rule :as entity]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.button-radio :refer [button-radio]]
|
||||
[auto-ap.utils :refer [dollars=]]
|
||||
[auto-ap.views.components.dropdown :refer [drop-down]]
|
||||
[auto-ap.views.components.expense-accounts-field :as expense-accounts-field :refer [expense-accounts-field recalculate-amounts]]
|
||||
[auto-ap.views.components.layouts :as layouts]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.pages.admin.rules.common :refer [default-read]]
|
||||
[auto-ap.views.pages.admin.rules.results-modal :as results-modal]
|
||||
[auto-ap.views.utils :refer [date->str date-picker dispatch-event standard with-user]]
|
||||
[cljs-time.core :as c]
|
||||
[clojure.spec.alpha :as s]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.status :as status]))
|
||||
(:require
|
||||
[auto-ap.entities.transaction-rule :as entity]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.button-radio :refer [button-radio]]
|
||||
[auto-ap.views.components.expense-accounts-field
|
||||
:as expense-accounts-field
|
||||
:refer [expense-accounts-field]]
|
||||
[auto-ap.views.components.layouts :as layouts]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.admin.rules.common :refer [default-read]]
|
||||
[auto-ap.views.pages.admin.rules.results-modal :as results-modal]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[clojure.spec.alpha :as s]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as r]
|
||||
[vimsical.re-frame.cofx.inject :as inject]
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
|
||||
;; SUBS
|
||||
|
||||
@@ -45,7 +50,7 @@
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
:<- [::forms/form ::form]
|
||||
(fn [{:keys [data status]} _]
|
||||
(fn [{:keys [data]} _]
|
||||
(s/valid? ::entity/transaction-rule data)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
@@ -164,47 +169,57 @@
|
||||
xs)))))))))
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::changed-vendor
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{{{:keys [client]} :data} :db} [_ vendor]]
|
||||
(when (and (:id client) (:id vendor))
|
||||
{:dispatch [::events/vendor-preferences-requested {:client-id (:id client)
|
||||
:vendor-id (:id vendor)
|
||||
:on-success [::changed [:vendor-preferences]]}]})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::changed-client
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{{{:keys [vendor]} :data} :db} [_ client]]
|
||||
(when (and (:id client) (:id vendor))
|
||||
{:dispatch [::events/vendor-preferences-requested {:client-id (:id client)
|
||||
:vendor-id (:id vendor)
|
||||
:on-success [::changed [:vendor-preferences]]}]})))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::changed
|
||||
(forms/change-handler ::form
|
||||
(fn [data field value]
|
||||
(cond (and (= [:vendor] field)
|
||||
(cond (and (= [:vendor-preferences] field)
|
||||
value
|
||||
(expense-accounts-field/can-replace-with-default? (:accounts data)))
|
||||
[[:accounts] (expense-accounts-field/default-account (:accounts data)
|
||||
@(re-frame/subscribe [::subs/vendor-default-account (:id value) (:client data)])
|
||||
(:default-account value)
|
||||
(:total data)
|
||||
[])]
|
||||
|
||||
(= [:client] field)
|
||||
[[:accounts] (expense-accounts-field/default-account (:accounts data)
|
||||
@(re-frame/subscribe [::subs/vendor-default-account (:id (:vendor data)) value])
|
||||
(:total data)
|
||||
[])
|
||||
[:bank-account] nil]
|
||||
|
||||
:else
|
||||
[]))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::saving
|
||||
[with-user (forms/triggers-loading ::form) (forms/in-form ::form)]
|
||||
(fn [{:keys [user] {:keys [data]} :db} [_ params]]
|
||||
[with-user (forms/triggers-loading ::form) (forms/in-form ::form) (re-frame/inject-cofx ::inject/sub [::query])]
|
||||
(fn [{:keys [user] ::keys [query]} _]
|
||||
{:graphql
|
||||
{:token user
|
||||
:query-obj @(re-frame/subscribe [::query])
|
||||
:query-obj query
|
||||
:on-success (fn [result]
|
||||
[::updated (:upsert-transaction-rule result)])
|
||||
:on-error [::forms/save-error ::form]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::test-clicked
|
||||
[with-user (forms/triggers-loading ::form) (forms/in-form ::form)]
|
||||
(fn [{:keys [user] {:keys [data]} :db} [_ params]]
|
||||
[with-user (forms/triggers-loading ::form) (forms/in-form ::form) (re-frame/inject-cofx ::inject/sub [::test-query])]
|
||||
(fn [{:keys [user] ::keys [test-query]} _]
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:single ::test}
|
||||
:query-obj @(re-frame/subscribe [::test-query])
|
||||
:query-obj test-query
|
||||
:on-success [::succeeded-test]
|
||||
:on-error [::forms/save-error ::form]}}))
|
||||
|
||||
@@ -218,7 +233,7 @@
|
||||
(re-frame/reg-event-fx
|
||||
::succeeded-test
|
||||
[(forms/triggers-stop-loading ::form)]
|
||||
(fn [{:keys [db]} [_ result]]
|
||||
(fn [_ [_ result]]
|
||||
|
||||
{:dispatch [::results-modal/opening (:test-transaction-rule result) nil false]}))
|
||||
|
||||
@@ -231,15 +246,30 @@
|
||||
:submit-event [::saving ]
|
||||
:id ::form}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [_ _]
|
||||
{::track/register [{:id ::client
|
||||
:subscription [::forms/field ::form [:client]]
|
||||
:event-fn (fn [c]
|
||||
[::changed-client c])}
|
||||
{:id ::vendor-change
|
||||
:subscription [::forms/field ::form [:vendor]]
|
||||
:event-fn (fn [v]
|
||||
[::changed-vendor v])}]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn []
|
||||
{::track/dispose [{:id ::client}
|
||||
{:id ::vendor-change}]}))
|
||||
|
||||
(defn form [{:keys [can-change-amount?] :as params}]
|
||||
[layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form ])}
|
||||
(let [{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
(defn form-contents [params]
|
||||
[layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form ])}
|
||||
(let [{:keys [data id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline field raw-field error-notification submit-button ]} rule-form
|
||||
default-note @(re-frame/subscribe [::default-note])
|
||||
test-state @(re-frame/subscribe [::status/single ::test])
|
||||
exists? (:id data)]
|
||||
default-note @(re-frame/subscribe [::default-note])
|
||||
test-state @(re-frame/subscribe [::status/single ::test])]
|
||||
^{:key id}
|
||||
(form-inline (assoc params :title "New Transaction Rule")
|
||||
[:<>
|
||||
@@ -315,17 +345,15 @@
|
||||
:precision 0
|
||||
:step "1"}])]]]]
|
||||
|
||||
|
||||
|
||||
[:h2.title.is-4 "Outcomes"]
|
||||
|
||||
(field "Assign Vendor"
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/all-vendors-index])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:field [:vendor]
|
||||
:spec ::entity/vendor}])
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:field [:vendor]}])
|
||||
|
||||
(with-meta
|
||||
(field nil
|
||||
@@ -336,7 +364,7 @@
|
||||
:locations (into ["Shared"] @(re-frame/subscribe [::subs/locations-for-client-or-bank-account (:id (:client data)) (:id (:bank-account data))]))
|
||||
:max 100
|
||||
:field [:accounts]}])
|
||||
{:key (some-> data :vendor :id str)})
|
||||
{:key (str (some-> data :vendor :id str) "-" (some-> data :client :id str))})
|
||||
|
||||
(field "Approval Status"
|
||||
[button-radio
|
||||
@@ -363,3 +391,11 @@
|
||||
"Test Rule"]]
|
||||
[:div.column
|
||||
(submit-button "Save")]]]))])
|
||||
|
||||
(defn form [_]
|
||||
(r/create-class
|
||||
{:display-name "rule-form"
|
||||
:component-did-mount #(re-frame/dispatch [::mounted])
|
||||
:component-will-unmount #(re-frame/dispatch [::unmounted])
|
||||
:reagent-render (fn [p]
|
||||
[form-contents p])}))
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
(ns auto-ap.views.pages.admin.rules.side-bar
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [dispatch-value-change]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn rule-side-bar [{:keys [data-page]}]
|
||||
[:div
|
||||
[:p.menu-label "Vendor"]
|
||||
[:div
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor (some-> % (select-keys [:name :id]))])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
|
||||
[:p.menu-label "Note"]
|
||||
[:div
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
(ns auto-ap.views.pages.admin.rules.table
|
||||
(:require [auto-ap.subs :as subs]
|
||||
[auto-ap.views.utils :refer [dispatch-event ->$ with-user action-cell-width]]
|
||||
[auto-ap.views.pages.admin.rules.form :as form]
|
||||
[auto-ap.views.components.paginator :refer [paginator]]
|
||||
[auto-ap.views.components.sort-by-list :refer [sort-by-list]]
|
||||
[auto-ap.views.pages.admin.rules.results-modal :as results-modal]
|
||||
[auto-ap.views.components.sorter :refer [sorted-column toggle-sort-by sort-icon]]
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.status :as status]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[reagent.core :as r]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
(:require
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.pages.admin.rules.form :as form]
|
||||
[auto-ap.views.pages.admin.rules.results-modal :as results-modal]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils
|
||||
:refer [->$ action-cell-width dispatch-event with-user]]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::run-clicked
|
||||
|
||||
@@ -1,93 +1,76 @@
|
||||
(ns auto-ap.views.pages.admin.vendors
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[clojure.string :as str]
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.views.pages.admin.vendors.side-bar :as side-bar]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[auto-ap.entities.vendors :as entity]
|
||||
[auto-ap.views.components.address :refer [address-field]]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.components.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[clojure.spec.alpha :as s]
|
||||
[auto-ap.views.utils :refer [login-url dispatch-value-change dispatch-event bind-field horizontal-field action-cell-width]]
|
||||
[auto-ap.views.pages.admin.vendors.table :as table]
|
||||
[auto-ap.views.pages.admin.vendors.merge-dialog :as merge-dialog]
|
||||
[cljs.reader :as edn]
|
||||
[auto-ap.routes :as routes]
|
||||
[bidi.bidi :as bidi]
|
||||
[auto-ap.status :as status]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.effects.forward :as forward])
|
||||
(:require-macros [cljs.core.async.macros :refer [go]]
|
||||
[auto-ap.entities.vendors :as vendor]))
|
||||
(:require
|
||||
[auto-ap.effects.forward :as forward]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[auto-ap.views.pages.admin.vendors.merge-dialog :as merge-dialog]
|
||||
[auto-ap.views.pages.admin.vendors.side-bar :as side-bar]
|
||||
[auto-ap.views.pages.admin.vendors.table :as table]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[clojure.set :as set]
|
||||
[re-frame.core :as re-frame]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.views.components.vendor-dialog :as vendor-dialog]))
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::invalidated
|
||||
(fn [{:keys [db]}]
|
||||
{:graphql {:token (:user db)
|
||||
:owns-state {:single ::vendor-page}
|
||||
:query-obj {:venia/queries [[:vendor events/vendor-query]]}
|
||||
:on-success [::received-vendors]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [{:keys [db]} _]
|
||||
{:dispatch [::invalidated]
|
||||
::track/register {:id ::params
|
||||
:subscription [::params]
|
||||
:event-fn (fn [params] [::params-change params])}
|
||||
::forward/register {:id ::merge-complete
|
||||
:events #{::merge-dialog/complete}
|
||||
:event-fn (fn [_]
|
||||
[::invalidated])}}))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::received-vendors
|
||||
(fn [db [_ vendors]]
|
||||
(assoc db :vendors (by :id (:vendor vendors )))))
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (dissoc db ::table/params ::side-bar/filter-params)
|
||||
::forward/dispose {:id ::merge-complete}
|
||||
::track/dispose {:id ::params}}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::params
|
||||
:<- [::side-bar/filter-params]
|
||||
:<- [::table/params]
|
||||
(fn [[filter-params table-params]]
|
||||
(cond-> {}
|
||||
(seq filter-params) (merge filter-params)
|
||||
(seq table-params) (merge table-params))))
|
||||
(def default-read [: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]]
|
||||
[:schedule-payment-dom [[:client [:id :name]] :id :dom]]
|
||||
[:usage [:client-id :count]]
|
||||
[:primary-contact [:name :phone :email :id]]
|
||||
[:secondary-contact [:id :name :phone :email]]
|
||||
:print-as :invoice-reminder-schedule :code
|
||||
:legal-entity-first-name :legal-entity-middle-name :legal-entity-last-name
|
||||
:legal-entity-tin :legal-entity-tin-type
|
||||
:legal-entity-1099-type
|
||||
[:address [:street1 :street2 :city :state :zip]]])
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
(fn [_ [_ params]]
|
||||
{:set-uri-params params}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::vendor-page
|
||||
:<- [::params]
|
||||
:<- [::subs/sorted-all-vendors]
|
||||
(fn [[params all-vendors]]
|
||||
(let [matching-vendors (cond->> all-vendors
|
||||
(:name-like params) (filter #(str/includes? (str/lower-case (or (:name %) ""))
|
||||
(str/lower-case (:name-like params)))))]
|
||||
(assoc (grid/virtual-paginate-controls (:start params ) (:per-page params) matching-vendors)
|
||||
:data (grid/virtual-paginate (:start params) (:per-page params) matching-vendors)))))
|
||||
|
||||
|
||||
[with-user]
|
||||
(fn [{:keys [user]} [_ params]]
|
||||
{:graphql {:token user
|
||||
:owns-state {:single [::data-page/page ::page]}
|
||||
:query-obj {:venia/queries [{:query/data [:vendor
|
||||
{:sort (:sort params)
|
||||
:start (:start params 0)
|
||||
:per-page (:per-page params)
|
||||
:name-like (:name-like params)}
|
||||
[[:vendors default-read]
|
||||
:total
|
||||
:start
|
||||
:end]]
|
||||
:query/alias :result}]}
|
||||
:on-success (fn [result]
|
||||
[::data-page/received ::page
|
||||
(set/rename-keys (:result result)
|
||||
{:vendors :data})])}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [_ _]
|
||||
{::forward/register [{:id ::merge-complete
|
||||
:events #{::merge-dialog/complete}
|
||||
:event-fn (fn [_]
|
||||
[::params-change {}])}
|
||||
{:id ::save-complete
|
||||
:events #{::vendor-dialog/save-complete}
|
||||
:event-fn (fn [_]
|
||||
[::params-change {}])}]
|
||||
::track/register {:id ::params
|
||||
:subscription [::data-page/params ::page]
|
||||
:event-fn (fn [params]
|
||||
[::params-change params])}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn [_ _]
|
||||
{:dispatch [::data-page/dispose ::page]
|
||||
::forward/dispose [{:id ::merge-complete} {:id ::save-complete}]
|
||||
::track/dispose {:id ::params}}))
|
||||
|
||||
(defn admin-vendors-content []
|
||||
[(with-meta
|
||||
@@ -95,17 +78,15 @@
|
||||
[:div.inbox-messages
|
||||
(when-let [banner (:banner @(re-frame/subscribe [::subs/admin]))]
|
||||
[:div.notification banner])
|
||||
(let [vendors (re-frame/subscribe [::subs/vendors])
|
||||
editing-vendor (:vendor @(re-frame/subscribe [::subs/admin]))]
|
||||
[:div
|
||||
[:h1.title "Vendors"]
|
||||
[:div.is-pulled-right [:a.button.is-primary.is-outlined {:on-click (dispatch-event [::merge-dialog/show])} "Merge vendors"]]
|
||||
[table/vendors-table {:page @(re-frame/subscribe [::vendor-page])
|
||||
:status @(re-frame/subscribe [::status/single ::vendor-page])}]])])
|
||||
[:div
|
||||
[:h1.title "Vendors"]
|
||||
[:div.is-pulled-right [:a.button.is-primary.is-outlined {:on-click (dispatch-event [::merge-dialog/show])} "Merge vendors"]]
|
||||
[table/vendors-table {:id :vendors
|
||||
:data-page ::page}]]])
|
||||
{:component-did-mount #(re-frame/dispatch [::mounted])
|
||||
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])})])
|
||||
|
||||
(defn admin-vendors-page []
|
||||
[side-bar-layout {:side-bar [admin-side-bar {}
|
||||
[side-bar/vendor-side-bar]]
|
||||
[side-bar/vendor-side-bar {:data-page ::page}]]
|
||||
:main [admin-vendors-content]}])
|
||||
|
||||
15
src/cljs/auto_ap/views/pages/admin/vendors/common.cljs
vendored
Normal file
15
src/cljs/auto_ap/views/pages/admin/vendors/common.cljs
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
(ns auto-ap.views.pages.admin.vendors.common)
|
||||
|
||||
(def default-read [: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]]
|
||||
[:schedule-payment-dom [[:client [:id :name]] :id :dom]]
|
||||
[:usage [:client-id :count]]
|
||||
[:primary-contact [:name :phone :email :id]]
|
||||
[:secondary-contact [:id :name :phone :email]]
|
||||
:print-as :invoice-reminder-schedule :code
|
||||
:legal-entity-first-name :legal-entity-middle-name :legal-entity-last-name
|
||||
:legal-entity-tin :legal-entity-tin-type
|
||||
:legal-entity-1099-type
|
||||
[:address [:street1 :street2 :city :state :zip]]])
|
||||
@@ -1,11 +1,13 @@
|
||||
(ns auto-ap.views.pages.admin.vendors.merge-dialog
|
||||
(:require [auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.utils :refer [dispatch-event]]
|
||||
[re-frame.core :as re-frame]))
|
||||
(:require
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.utils :refer [dispatch-event]]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
@@ -21,29 +23,29 @@
|
||||
:id ::form}))
|
||||
|
||||
(defn form []
|
||||
(let [{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline horizontal-field field raw-field error-notification submit-button]} merge-form]
|
||||
(let [_ @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline field]} merge-form]
|
||||
|
||||
|
||||
(form-inline {}
|
||||
[:<>
|
||||
(field "Form Vendor (will be deleted)"
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/all-vendors-index])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:entity->text (fn [x]
|
||||
(str (:name x) " (" (reduce + 0 (map :count (:usage x))) " usages)") )
|
||||
:field [:from]}])
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:from]}])
|
||||
|
||||
|
||||
(field "To Vendor"
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:type "typeahead-v3"
|
||||
:entity->text (fn [x]
|
||||
(str (:name x) " (" (reduce + 0 (map :count (:usage x))) " usages)") )
|
||||
:field [:to]}])])))
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:field [:to]}])])))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::show
|
||||
@@ -68,7 +70,7 @@
|
||||
(re-frame/reg-event-fx
|
||||
::save
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{{{:keys [from to]} :data :as merge-vendors-form} :db :as g} _]
|
||||
(fn [{{{:keys [from to]} :data} :db} _]
|
||||
(let [user @(re-frame/subscribe [::subs/token])]
|
||||
{:graphql
|
||||
{:token user
|
||||
|
||||
@@ -2,69 +2,17 @@
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.utils :refer [active-when dispatch-value-change]]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::specific-filters
|
||||
(fn [db ]
|
||||
(::filters db nil)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::filters
|
||||
:<- [::specific-filters]
|
||||
:<- [::subs/vendors-by-id]
|
||||
:<- [::subs/query-params]
|
||||
(fn [[specific-filters vendors-by-id query-params] ]
|
||||
(let [url-filters (-> query-params
|
||||
(select-keys #{:name-like})
|
||||
(update :name-like #(some-> % str)))]
|
||||
(merge url-filters specific-filters ))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::filter
|
||||
:<- [::filters]
|
||||
(fn [filters [_ which]]
|
||||
(get filters which)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::settled-filters
|
||||
(fn [db ]
|
||||
(::settled-filters db)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::filter-params
|
||||
:<- [::settled-filters]
|
||||
:<- [::filters]
|
||||
:<- [::subs/active-page]
|
||||
(fn [[settled-filters filters ap ]]
|
||||
(let [filters (or settled-filters filters)]
|
||||
{:name-like (:name-like filters)})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::filters-settled
|
||||
(fn [{:keys [db]} [_ & params]]
|
||||
{:db (assoc db ::settled-filters @(re-frame/subscribe [::filters]))}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::filter-changed
|
||||
(fn [{:keys [db]} [_ & params]]
|
||||
(let [[a b c] params
|
||||
[which val] (if (= 3 (count params))
|
||||
[(into [a] b) c]
|
||||
[[a] b])]
|
||||
{:db (assoc-in db (into [::filters] which) val)
|
||||
:dispatch-debounce {:event [::filters-settled]
|
||||
:time 800
|
||||
:key ::filters}})))
|
||||
[auto-ap.views.utils :refer [dispatch-value-change]]
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
|
||||
|
||||
(defn vendor-side-bar []
|
||||
(defn vendor-side-bar [{:keys [data-page]}]
|
||||
[:div
|
||||
[:p.menu-label "Name"]
|
||||
|
||||
[:div.field
|
||||
[:div.control [:input.input {:placeholder "Harry's Food Products"
|
||||
:value @(re-frame/subscribe [::filter :name-like])
|
||||
:on-change (dispatch-value-change [::filter-changed :name-like])} ]]]])
|
||||
[:div
|
||||
[:div.field
|
||||
[:div.control [:input.input {:placeholder "HOME DEPOT"
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :name-like])
|
||||
:on-change (dispatch-value-change [::data-page/filter-changed data-page :name-like])} ]]]]])
|
||||
|
||||
|
||||
|
||||
@@ -1,34 +1,21 @@
|
||||
(ns auto-ap.views.pages.admin.vendors.table
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
(:require
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.views.components.vendor-dialog :refer [vendor-dialog] :as vendor-dialog]
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.utils :refer [login-url dispatch-value-change dispatch-event bind-field horizontal-field action-cell-width]]
|
||||
[auto-ap.views.components.buttons :as buttons]))
|
||||
[auto-ap.views.components.vendor-dialog :as vendor-dialog]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [action-cell-width]]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-changed
|
||||
(fn [{:keys [db]} [_ p]]
|
||||
{:db (assoc db ::params p)}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::params
|
||||
(fn [db]
|
||||
(-> db ::params)))
|
||||
|
||||
(defn vendors-table [{:keys [status page]}]
|
||||
(let [params @(re-frame/subscribe [::params])
|
||||
(defn vendors-table [{:keys [data-page]}]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::data-page/page data-page])
|
||||
accounts @(re-frame/subscribe [::subs/all-accounts-by-id])]
|
||||
(println "DATA COUNT" (keys data))
|
||||
|
||||
[grid/grid {:status status
|
||||
:on-params-change (fn [p]
|
||||
(re-frame/dispatch [::params-changed p]))
|
||||
:params params
|
||||
[grid/grid {:data-page data-page
|
||||
:column-count 4}
|
||||
[grid/controls page]
|
||||
[grid/controls data]
|
||||
[grid/table {:fullwidth true}
|
||||
[grid/header
|
||||
[grid/row {}
|
||||
@@ -37,7 +24,7 @@
|
||||
[grid/header-cell {} "Default Account"]
|
||||
[grid/header-cell {:style {:width (action-cell-width 1)}}]]]
|
||||
[grid/body
|
||||
(for [v (:data page)]
|
||||
(for [v (:data data)]
|
||||
^{:key (str (:id v))}
|
||||
[grid/row {:class (:class v) :id (:id v)}
|
||||
[grid/cell {} (:name v)
|
||||
|
||||
@@ -3,18 +3,17 @@
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.history :refer [history]]
|
||||
[cemerick.url :as url]
|
||||
[auto-ap.views.utils
|
||||
:refer
|
||||
[->$ date->str days-until dispatch-event local-now standard]]
|
||||
[bidi.bidi :as bidi]
|
||||
[cljs-time.coerce :as coerce]
|
||||
[cljs-time.core :as t]
|
||||
[clojure.string :as str]
|
||||
[pushy.core :as pushy]
|
||||
[re-frame.core :as re-frame]
|
||||
[recharts]
|
||||
[downshift :as ds :refer [useCombobox]]
|
||||
[reagent.core :as r]
|
||||
[react]))
|
||||
|
||||
@@ -39,7 +38,7 @@
|
||||
:data data
|
||||
:dataKey "value"
|
||||
:inner-radius 20}
|
||||
(map (fn [x y]
|
||||
(map (fn [_ y]
|
||||
^{:key y}
|
||||
[cell {:key y :fill (colors y)}]) data (range))
|
||||
]
|
||||
@@ -57,7 +56,7 @@
|
||||
|
||||
(defn make-cash-flow-chart [{:keys [width height data] }]
|
||||
(let [redirect-fn (fn [x]
|
||||
(pushy/set-token! auto-ap.history/history (str (bidi/path-for routes/routes :unpaid-invoices) "?" (get (js->clj x) "query-params")))
|
||||
(pushy/set-token! history (str (bidi/path-for routes/routes :unpaid-invoices) "?" (get (js->clj x) "query-params")))
|
||||
)]
|
||||
[bar-chart {:width width :height height :data data :fill "#FFFFFF" :stackOffset "sign"}
|
||||
[tool-tip]
|
||||
@@ -161,29 +160,29 @@
|
||||
(fn [[{:keys [effective-balance credits-yesterday] } :as acc] day]
|
||||
(let [invoices-due-today (invoices-due-soon (date->str (t/plus start-date (t/days day))) 0.0)
|
||||
credits-due-today (upcoming-credits (date->str (t/plus start-date (t/days day))) 0.0)
|
||||
debits-due-today (upcoming-debits (date->str (t/plus start-date (t/days day))) 0.0)]
|
||||
(let [today (t/plus start-date (t/days day))]
|
||||
(conj acc
|
||||
{:name (date->str today)
|
||||
:date today
|
||||
:effective-balance (+ (- effective-balance invoices-due-today )
|
||||
debits-due-today
|
||||
credits-yesterday)
|
||||
:credits-yesterday credits-due-today
|
||||
:credits credits-due-today
|
||||
:debits debits-due-today
|
||||
:invoices (- invoices-due-today)
|
||||
:query-params (cemerick.url/map->query {:due-range {:start (date->str today standard)
|
||||
:end (date->str today standard)}})}))))
|
||||
(list {:name (date->str start-date)
|
||||
:date start-date
|
||||
:effective-balance effective-balance
|
||||
:invoices (- (invoices-due-soon (date->str start-date) 0.0))
|
||||
:credits (upcoming-credits (date->str start-date) 0.0)
|
||||
:credits-yesterday (upcoming-credits (date->str start-date) 0.0)
|
||||
:debits (upcoming-debits (date->str start-date) 0.0)
|
||||
debits-due-today (upcoming-debits (date->str (t/plus start-date (t/days day))) 0.0)
|
||||
today (t/plus start-date (t/days day))]
|
||||
(conj acc
|
||||
{:name (date->str today)
|
||||
:date today
|
||||
:effective-balance (+ (- effective-balance invoices-due-today )
|
||||
debits-due-today
|
||||
credits-yesterday)
|
||||
:credits-yesterday credits-due-today
|
||||
:credits credits-due-today
|
||||
:debits debits-due-today
|
||||
:invoices (- invoices-due-today)
|
||||
:query-params (url/map->query {:due-range {:start (date->str today standard)
|
||||
:end (date->str today standard)}})})))
|
||||
(list {:name (date->str start-date)
|
||||
:date start-date
|
||||
:effective-balance effective-balance
|
||||
:invoices (- (invoices-due-soon (date->str start-date) 0.0))
|
||||
:credits (upcoming-credits (date->str start-date) 0.0)
|
||||
:credits-yesterday (upcoming-credits (date->str start-date) 0.0)
|
||||
:debits (upcoming-debits (date->str start-date) 0.0)
|
||||
:outstanding-payments (- outstanding-payments)
|
||||
:query-params (cemerick.url/map->query {:due-range {:end (date->str start-date standard)}})})
|
||||
:query-params (url/map->query {:due-range {:end (date->str start-date standard)}})})
|
||||
(condp = (:cash-flow-range chart-options)
|
||||
:seven-days
|
||||
(range 1 7)
|
||||
@@ -210,9 +209,8 @@
|
||||
::cash-flow-page
|
||||
:<- [::cash-flow-table-params]
|
||||
:<- [::cash-flow-data]
|
||||
:<- [::subs/vendors-by-id]
|
||||
(fn [[params cash-flow-data vendors-by-id]]
|
||||
(let [ {:keys [outstanding-payments invoices-due-soon upcoming-credits upcoming-debits]} cash-flow-data
|
||||
(fn [[params cash-flow-data]]
|
||||
(let [ {:keys [invoices-due-soon upcoming-credits upcoming-debits]} cash-flow-data
|
||||
rows (concat (map (fn [c]
|
||||
{:date (:date c)
|
||||
:days-until (days-until (:date c))
|
||||
@@ -230,7 +228,7 @@
|
||||
{:date (:due c)
|
||||
:days-until (days-until (:due c))
|
||||
:amount (:outstanding-balance c)
|
||||
:name (str (:name (get vendors-by-id (:id (:vendor c)))) " (" (:invoice-number c) ")")
|
||||
:name (str (:name (:vendor c)) " (" (:invoice-number c) ")")
|
||||
:type "Invoice"})
|
||||
invoices-due-soon))]
|
||||
(assoc (grid/virtual-paginate-controls (:start params ) (:per-page params) rows)
|
||||
@@ -253,7 +251,7 @@
|
||||
{:client-id (:id @(re-frame/subscribe [::subs/client]))}
|
||||
[:beginning-balance
|
||||
:outstanding-payments
|
||||
[:invoices-due-soon [:due :outstanding-balance [:vendor [:id]] :invoice-number]]
|
||||
[:invoices-due-soon [:due :outstanding-balance [:vendor [:id :name]] :invoice-number]]
|
||||
[:upcoming-credits [:date :amount :identifier]]
|
||||
[:upcoming-debits [:date :amount :identifier]]]]]}
|
||||
:on-success [::received]}}))
|
||||
@@ -300,11 +298,6 @@
|
||||
|
||||
(defn home-content []
|
||||
(let [client-id (-> @(re-frame/subscribe [::subs/client]) :id)
|
||||
vendors-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
vendors-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
|
||||
accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id])
|
||||
accounts-index @(re-frame/subscribe [::subs/accounts-index])
|
||||
chart-options @(re-frame/subscribe [::chart-options])]
|
||||
^{:key client-id}
|
||||
[side-bar-layout {:side-bar [:div
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[auto-ap.views.components.invoices.side-bar :refer [invoices-side-bar]]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user ->%]]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
|
||||
[cljs.reader :as edn]
|
||||
[auto-ap.status :as status]
|
||||
@@ -18,7 +17,7 @@
|
||||
[clojure.set :as set]
|
||||
[auto-ap.effects.forward :as forward]
|
||||
[goog.string :as gstring]
|
||||
))
|
||||
[auto-ap.views.components.typeahead.vendor :refer [search-backed-typeahead]]))
|
||||
|
||||
|
||||
(defn dropzone []
|
||||
@@ -57,15 +56,16 @@
|
||||
[:p.control
|
||||
[:a.button.is-static "Force vendor"]]
|
||||
[:div.control {:style {:width "400px"}}
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:entity->text :name
|
||||
:name "vendor"
|
||||
:type "typeahead-v3"
|
||||
:on-change (fn [v]
|
||||
(reset! vendor v))
|
||||
:value @vendor}]]
|
||||
]
|
||||
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:name "vendor"
|
||||
:on-change (fn [v]
|
||||
(reset! vendor v))
|
||||
:value @vendor}]]]
|
||||
[:div.tile.notification
|
||||
[:div.has-text-centered {:style {:padding "80px 0px" :width "100%"}}
|
||||
[:span
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.time-utils :refer [next-dom]]
|
||||
[auto-ap.utils :refer [by dollars=]]
|
||||
[auto-ap.utils :refer [dollars=]]
|
||||
[auto-ap.views.components.dropdown :refer [drop-down]]
|
||||
[auto-ap.views.components.expense-accounts-field
|
||||
:as
|
||||
@@ -17,6 +17,7 @@
|
||||
[auto-ap.views.components.money-field :refer [money-field]]
|
||||
[auto-ap.views.components.switch-field :refer [switch-field]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.typeahead.vendor :refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.invoices.common :refer [invoice-read]]
|
||||
[auto-ap.views.utils
|
||||
:refer
|
||||
@@ -26,13 +27,14 @@
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as r]
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[vimsical.re-frame.cofx.inject :as inject]))
|
||||
|
||||
;; SUBS
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
:<- [::forms/form ::form]
|
||||
(fn [{:keys [data status]} _]
|
||||
(fn [{:keys [data]} _]
|
||||
(let [min-total (if (= (:total (:original data)) (:outstanding-balance (:original data)))
|
||||
nil
|
||||
(- (:total (:original data)) (:outstanding-balance (:original data))))
|
||||
@@ -45,7 +47,7 @@
|
||||
(re-frame/reg-sub
|
||||
::create-query
|
||||
:<- [::forms/form ::form]
|
||||
(fn [{:keys [data] {:keys [id invoice-number date due scheduled-payment location total expense-accounts vendor client]} :data}]
|
||||
(fn [{{:keys [invoice-number date due scheduled-payment location total expense-accounts vendor client]} :data}]
|
||||
{:venia/operation {:operation/type :mutation
|
||||
:operation/name "AddInvoice"}
|
||||
:venia/queries [{:query/data [:add-invoice
|
||||
@@ -69,7 +71,7 @@
|
||||
(re-frame/reg-sub
|
||||
::edit-query
|
||||
:<- [::forms/form ::form]
|
||||
(fn [{:keys [data] {:keys [id invoice-number date due scheduled-payment location total expense-accounts vendor client]} :data}]
|
||||
(fn [{{:keys [id invoice-number date due scheduled-payment total expense-accounts]} :data}]
|
||||
{:venia/operation {:operation/type :mutation
|
||||
:operation/name "EditInvoice"}
|
||||
:venia/queries [{:query/data [:edit-invoice
|
||||
@@ -88,87 +90,57 @@
|
||||
expense-accounts)}}
|
||||
invoice-read]}]}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::add-and-print-query
|
||||
(fn [db [_ bank-account-id type]]
|
||||
(let [{:keys [data] {:keys [id invoice-number date location total expense-accounts scheduled-payment vendor client]} :data} @(re-frame/subscribe [::forms/form ::form])]
|
||||
{:venia/operation {:operation/type :mutation
|
||||
:operation/name "AddAndPrintInvoice"}
|
||||
:venia/queries [{:query/data [:add-and-print-invoice
|
||||
{:invoice {:date date
|
||||
:vendor-id (:id vendor)
|
||||
:client-id (:id client)
|
||||
:scheduled-payment scheduled-payment
|
||||
:invoice-number invoice-number
|
||||
:location location
|
||||
:total total
|
||||
:expense-accounts (map (fn [ea]
|
||||
{:id (when-not (str/starts-with? (:id ea) "new-")
|
||||
(:id ea))
|
||||
:account_id (:id (:account ea))
|
||||
:location (:location ea)
|
||||
:amount (:amount ea)})
|
||||
expense-accounts)}
|
||||
:bank-account-id bank-account-id
|
||||
:type type}
|
||||
[:pdf-url [:invoices invoice-read]]]}]})))
|
||||
|
||||
|
||||
|
||||
;; EVENTS
|
||||
|
||||
(re-frame/reg-event-db
|
||||
(re-frame/reg-event-fx
|
||||
::updated
|
||||
(fn [db [_ invoice command]]
|
||||
(if (= :create command)
|
||||
(-> db
|
||||
(forms/stop-form ::form )
|
||||
(forms/start-form ::form {:client @(re-frame/subscribe [::subs/client])
|
||||
:status :unpaid
|
||||
:date (date->str (c/now) standard)}))
|
||||
db)))
|
||||
[(re-frame/inject-cofx ::inject/sub [::subs/client])]
|
||||
(fn [{:keys [db] ::subs/keys [client]} [_ _ command]]
|
||||
(when (= :create command)
|
||||
{:db
|
||||
(-> db
|
||||
(forms/stop-form ::form )
|
||||
(forms/start-form ::form {:client client
|
||||
:status :unpaid
|
||||
:date (date->str (c/now) standard)}))})))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
(re-frame/reg-event-fx
|
||||
::adding
|
||||
(fn [db [_ new]]
|
||||
(let [locations @(re-frame/subscribe [::subs/locations-for-client (:client new)])
|
||||
accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id (:client new)])]
|
||||
(-> db (forms/start-form ::form (assoc new :expense-accounts
|
||||
(expense-accounts-field/from-graphql (:expense-accounts new)
|
||||
accounts-by-id
|
||||
0.0
|
||||
locations)))))))
|
||||
(re-frame/reg-event-db
|
||||
[(re-frame/inject-cofx ::inject/sub (fn [[_ which _]]
|
||||
[::subs/locations-for-client (:id (:client which))]))]
|
||||
(fn [{:keys [db] ::subs/keys [locations-for-client]} [_ new]]
|
||||
{:db
|
||||
(-> db (forms/start-form ::form (assoc new :expense-accounts
|
||||
(expense-accounts-field/from-graphql (:expense-accounts new)
|
||||
0.0
|
||||
locations-for-client))))}))
|
||||
(re-frame/reg-event-fx
|
||||
::editing
|
||||
(fn [db [_ which]]
|
||||
(let [accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id (:client which)])
|
||||
vendor (get @(re-frame/subscribe [::subs/vendors-by-id]) (:id (:vendor which)))
|
||||
edit-invoice (update which :date #(date->str % standard))
|
||||
[(re-frame/inject-cofx ::inject/sub (fn [[_ which _]]
|
||||
[::subs/locations-for-client (:id (:client which))]))]
|
||||
(fn [{:keys [db] ::subs/keys [locations-for-client]} [_ which vendor-preferences]]
|
||||
(let [edit-invoice (update which :date #(date->str % standard))
|
||||
edit-invoice (update edit-invoice :due #(date->str % standard))
|
||||
edit-invoice (update edit-invoice :scheduled-payment #(date->str % standard))
|
||||
edit-invoice (assoc edit-invoice :original edit-invoice)
|
||||
edit-invoice (assoc edit-invoice :vendor-autopay? (boolean ((set (map :id (:automatically-paid-when-due vendor)))
|
||||
(:id (:client which)))))
|
||||
locations @(re-frame/subscribe [::subs/locations-for-client (:id (:client which))])
|
||||
]
|
||||
(-> db
|
||||
(forms/start-form ::form {:id (:id edit-invoice)
|
||||
:payments (:payments edit-invoice)
|
||||
:status (:status edit-invoice)
|
||||
:date (:date edit-invoice)
|
||||
:due (:due edit-invoice)
|
||||
:vendor-autopay? (boolean ((set (map :id (:automatically-paid-when-due vendor)))
|
||||
(:id (:client which))))
|
||||
:scheduled-payment (:scheduled-payment edit-invoice)
|
||||
:invoice-number (:invoice-number edit-invoice)
|
||||
:total (:total edit-invoice)
|
||||
:original edit-invoice
|
||||
:vendor (:vendor edit-invoice)
|
||||
:client (:client edit-invoice)
|
||||
:expense-accounts (expense-accounts-field/from-graphql (:expense-accounts which)
|
||||
accounts-by-id
|
||||
(:total which)
|
||||
locations)})))))
|
||||
edit-invoice (assoc edit-invoice :original edit-invoice)]
|
||||
{:db
|
||||
(-> db
|
||||
(forms/start-form ::form {:id (:id edit-invoice)
|
||||
:payments (:payments edit-invoice)
|
||||
:status (:status edit-invoice)
|
||||
:date (:date edit-invoice)
|
||||
:due (:due edit-invoice)
|
||||
:vendor-preferences vendor-preferences
|
||||
:scheduled-payment (:scheduled-payment edit-invoice)
|
||||
:invoice-number (:invoice-number edit-invoice)
|
||||
:total (:total edit-invoice)
|
||||
:original edit-invoice
|
||||
:vendor (:vendor edit-invoice)
|
||||
:client (:client edit-invoice)
|
||||
:expense-accounts (expense-accounts-field/from-graphql (:expense-accounts which)
|
||||
(:total which)
|
||||
locations-for-client)}))})))
|
||||
|
||||
|
||||
|
||||
@@ -177,78 +149,87 @@
|
||||
::changed
|
||||
(forms/change-handler ::form
|
||||
(fn [data field value]
|
||||
(let [locations @(re-frame/subscribe [::subs/locations-for-client (:id (:client data))])]
|
||||
|
||||
(cond (and (= [:vendor] field)
|
||||
value)
|
||||
(let [schedule-payment-dom (get (by (comp :id :client ) :dom (:schedule-payment-dom value))
|
||||
(:id (:client data)))]
|
||||
(cond-> []
|
||||
|
||||
(expense-accounts-field/can-replace-with-default? (:expense-accounts data))
|
||||
(into [[:expense-accounts] (expense-accounts-field/default-account (:expense-accounts data)
|
||||
@(re-frame/subscribe [::subs/vendor-default-account (:id value) (:client data)])
|
||||
(:total data)
|
||||
locations)])
|
||||
(cond
|
||||
(= [:vendor-preferences] field)
|
||||
(cond-> []
|
||||
(expense-accounts-field/can-replace-with-default? (:expense-accounts data))
|
||||
(into [[:expense-accounts] (expense-accounts-field/default-account (:expense-accounts data)
|
||||
(:default-account value)
|
||||
(:total data)
|
||||
(:locations (:client data)))])
|
||||
|
||||
|
||||
(boolean ((set (map :id (:automatically-paid-when-due value))) (:id (:client data))))
|
||||
(into [[:scheduled-payment] (:due data)
|
||||
[:schedule-when-due] true
|
||||
[:vendor-autopay? ] true])
|
||||
(:automatically-paid-when-due value)
|
||||
(into [[:scheduled-payment] (:due data)
|
||||
[:schedule-when-due] true])
|
||||
|
||||
(:schedule-payment-dom value)
|
||||
(into [[:scheduled-payment] (date->str (next-dom (str->date (:date data) standard) (:schedule-payment-dom value)) standard)]))
|
||||
|
||||
schedule-payment-dom
|
||||
(into [[:scheduled-payment] (date->str (next-dom (str->date (:date data) standard) schedule-payment-dom) standard)
|
||||
[:vendor-autopay?] true])
|
||||
(= [:total] field)
|
||||
[[:expense-accounts] (recalculate-amounts (:expense-accounts data) value)]
|
||||
|
||||
true
|
||||
(into [[:schedule-payment-dom] schedule-payment-dom])))
|
||||
(and (= [:date] field)
|
||||
(:schedule-payment-dom (:vendor-preferences data)))
|
||||
[[:scheduled-payment] (date->str (next-dom (str->date value standard) (:schedule-payment-dom (:vendor-preferences data))) standard) ]
|
||||
|
||||
(= [:total] field)
|
||||
[[:expense-accounts] (recalculate-amounts (:expense-accounts data) value)]
|
||||
(and (= [:schedule-when-due] field) value)
|
||||
[[:scheduled-payment] (:due data)]
|
||||
|
||||
(and (= [:date] field)
|
||||
(:schedule-payment-dom data))
|
||||
[[:scheduled-payment] (date->str (next-dom (str->date value standard) (:schedule-payment-dom data)) standard) ]
|
||||
(and (= [:due] field) (:schedule-when-due data))
|
||||
[[:scheduled-payment] value]
|
||||
|
||||
(and (= [:schedule-when-due] field) value)
|
||||
[[:scheduled-payment] (:due data)]
|
||||
|
||||
(and (= [:due] field) (:schedule-when-due data))
|
||||
[[:scheduled-payment] value]
|
||||
|
||||
:else
|
||||
[])))))
|
||||
:else
|
||||
[]))))
|
||||
(re-frame/reg-event-db
|
||||
::maybe-change-client
|
||||
[ (forms/in-form ::form)]
|
||||
[ (forms/in-form ::form) ]
|
||||
(fn [{:keys [data] :as f} [_ c]]
|
||||
(if (:id data)
|
||||
f
|
||||
(assoc-in f [:data :client] c))))
|
||||
(if (and (not (:id data))
|
||||
(:id c))
|
||||
(assoc-in f [:data :client] c)
|
||||
f)))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::add-and-print
|
||||
[with-user (forms/in-form ::form)]
|
||||
(fn [{:keys [user] {:keys [data]} :db} [_ bank-account-id type]]
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:single ::form}
|
||||
:query-obj @(re-frame/subscribe [::add-and-print-query bank-account-id type])
|
||||
:on-success [::added-and-printed]
|
||||
:on-error [::forms/save-error ::form]}}))
|
||||
::add-and-print
|
||||
[with-user (forms/in-form ::form)]
|
||||
(fn [{:keys [user]
|
||||
{{:keys [invoice-number date location total expense-accounts scheduled-payment vendor client]} :data} :db} [_ bank-account-id type]]
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:single ::form}
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
:operation/name "AddAndPrintInvoice"}
|
||||
:venia/queries [{:query/data [:add-and-print-invoice
|
||||
{:invoice {:date date
|
||||
:vendor-id (:id vendor)
|
||||
:client-id (:id client)
|
||||
:scheduled-payment scheduled-payment
|
||||
:invoice-number invoice-number
|
||||
:location location
|
||||
:total total
|
||||
:expense-accounts (map (fn [ea]
|
||||
{:id (when-not (str/starts-with? (:id ea) "new-")
|
||||
(:id ea))
|
||||
:account_id (:id (:account ea))
|
||||
:location (:location ea)
|
||||
:amount (:amount ea)})
|
||||
expense-accounts)}
|
||||
:bank-account-id bank-account-id
|
||||
:type type}
|
||||
[:pdf-url [:invoices invoice-read]]]}]}
|
||||
:on-success [::added-and-printed]
|
||||
:on-error [::forms/save-error ::form]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::saving
|
||||
[with-user (forms/in-form ::form)]
|
||||
(fn [{:keys [user] {:keys [data]} :db} _]
|
||||
[with-user (forms/in-form ::form) (re-frame/inject-cofx ::inject/sub [::edit-query]) (re-frame/inject-cofx ::inject/sub [::create-query])]
|
||||
(fn [{:keys [user] {:keys [data]} :db ::keys [edit-query create-query]} _]
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:single ::form}
|
||||
:query-obj (if (:id data)
|
||||
@(re-frame/subscribe [::edit-query])
|
||||
@(re-frame/subscribe [::create-query]))
|
||||
edit-query
|
||||
create-query)
|
||||
:on-success (fn [result]
|
||||
[::updated
|
||||
(assoc (if (:id data)
|
||||
@@ -263,14 +244,13 @@
|
||||
(re-frame/reg-event-fx
|
||||
::save-requested
|
||||
[with-user (forms/in-form ::form)]
|
||||
(fn [{:keys [user db]} [_ fwd-event]]
|
||||
(fn [{:keys [db]} [_ fwd-event]]
|
||||
(if (and (:scheduled-payment (:data db))
|
||||
(not (:vendor-autopay? (:data db))))
|
||||
(not (:vendor-autopay? (:vendor-preferences (:data db)))))
|
||||
{:dispatch
|
||||
[::modal/modal-requested {:title "Scheduled payment date"
|
||||
:body [:div "This vendor isn't set up to be automatically paid. On "
|
||||
(:scheduled-payment (:data db))
|
||||
|
||||
" the invoice will be marked as paid, but no payment will be made to the vendor. "
|
||||
"Are you sure you want to continue?"]
|
||||
:confirm {:value "Save"
|
||||
@@ -282,16 +262,25 @@
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::added-and-printed
|
||||
(fn [{:keys [db]} [_ result]]
|
||||
(fn [_ [_ result]]
|
||||
(let [invoice (first (:invoices (:add-and-print-invoice result)))]
|
||||
{:dispatch-n [[::updated (assoc invoice :class "live-added") :create]
|
||||
[::checks-printed [invoice] (:pdf-url (:add-and-print-invoice result))]]})))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::checks-printed
|
||||
(fn [db [_ invoices pdf-url]]
|
||||
(fn [db [_]]
|
||||
db))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::changed-vendor
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{{{:keys [client]} :data} :db} [_ vendor]]
|
||||
(when (and (:id client) (:id vendor))
|
||||
{:dispatch [::events/vendor-preferences-requested {:client-id (:id client)
|
||||
:vendor-id (:id vendor)
|
||||
:on-success [::changed [:vendor-preferences]]
|
||||
:on-failure [:hello]}]})))
|
||||
|
||||
|
||||
;; VIEWS
|
||||
@@ -307,20 +296,25 @@
|
||||
{::track/register [{:id ::client
|
||||
:subscription [::subs/client]
|
||||
:event-fn (fn [c]
|
||||
|
||||
[::maybe-change-client c])}]}))
|
||||
[::maybe-change-client c])}
|
||||
{:id ::vendor-change
|
||||
:subscription [::forms/field ::form [:vendor]]
|
||||
:event-fn (fn [v]
|
||||
[::changed-vendor v])}]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn []
|
||||
{::track/dispose [{:id ::client}]}))
|
||||
{::track/dispose [{:id ::client}
|
||||
{:id ::vendor-change}]}))
|
||||
|
||||
(defn form-content [{:keys [can-change-amount?] :as params}]
|
||||
(defn form-content [params]
|
||||
[layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form ])}
|
||||
(let [{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
(let [{:keys [data id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline field raw-field error-notification submit-button ]} invoice-form
|
||||
can-submit? (boolean @(re-frame/subscribe [::can-submit]))
|
||||
status @(re-frame/subscribe [::status/single ::form])
|
||||
active-client @(re-frame/subscribe [::subs/client])
|
||||
exists? (:id data)
|
||||
can-change-amount? (#{:unpaid ":unpaid"} (:status data))
|
||||
min-total (if (= (:total (:original data)) (:outstanding-balance (:original data)))
|
||||
@@ -339,7 +333,7 @@
|
||||
(not (seq (:payments data))))
|
||||
[:div.tag.is-info.is-light "Automatically paid"]
|
||||
|
||||
(and (#{:paid ":paid"} (:status data)))
|
||||
(#{:paid ":paid"} (:status data))
|
||||
(if-let [check-number (:check-number (:payment (first (:payments data))))]
|
||||
[:div.tag.is-info.is-light "Paid by check #" check-number ]
|
||||
[:div.tag.is-info.is-light "Paid"])
|
||||
@@ -347,25 +341,26 @@
|
||||
:else
|
||||
nil)])
|
||||
[:<>
|
||||
(when-not @(re-frame/subscribe [::subs/client])
|
||||
(when-not active-client
|
||||
(field [:span "Client"
|
||||
[:span.has-text-danger " *"]]
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:auto-focus (if @(re-frame/subscribe [::subs/client]) false true)
|
||||
:auto-focus (if active-client false true)
|
||||
:field [:client]
|
||||
:disabled exists?
|
||||
:spec ::invoice/client}]))
|
||||
(field [:span "Vendor"
|
||||
[:span.has-text-danger " *"]]
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:disabled exists?
|
||||
:auto-focus (if @(re-frame/subscribe [::subs/client]) true false)
|
||||
:field [:vendor]}])
|
||||
[search-backed-typeahead {:disabled exists?
|
||||
:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus (if active-client true false)
|
||||
:field [:vendor]}])
|
||||
|
||||
(field [:span "Date"
|
||||
[:span.has-text-danger " *"]]
|
||||
@@ -374,6 +369,7 @@
|
||||
:format-week-number (fn [] "")
|
||||
:previous-month-button-label ""
|
||||
:placeholder "mm/dd/yyyy"
|
||||
:disable-keyboard-navigation true
|
||||
:next-month-button-label ""
|
||||
:next-month-label ""
|
||||
:type "date"
|
||||
@@ -386,6 +382,7 @@
|
||||
:format-week-number (fn [] "")
|
||||
:previous-month-button-label ""
|
||||
:placeholder "mm/dd/yyyy"
|
||||
:disable-keyboard-navigation true
|
||||
:next-month-button-label ""
|
||||
:next-month-label ""
|
||||
:type "date"
|
||||
@@ -438,13 +435,9 @@
|
||||
:descriptor "expense account"
|
||||
:locations (:locations (:client data))
|
||||
:max (:total data)
|
||||
:client (or (:client data) @(re-frame/subscribe [::subs/client]))
|
||||
:client (or (:client data) active-client)
|
||||
:field [:expense-accounts]}])
|
||||
{:key (str (:id (:vendor data)))})
|
||||
|
||||
|
||||
|
||||
|
||||
{:key (str (:id (:vendor data) "none") "-" (:id (:client data) "none") )})
|
||||
|
||||
(error-notification)
|
||||
|
||||
@@ -464,7 +457,7 @@
|
||||
:id ::add-and-print-invoice}
|
||||
[:div
|
||||
(list
|
||||
(for [{:keys [id number name type]} (->> (:bank-accounts (:client data)) (filter :visible) (sort-by :sort-order))]
|
||||
(for [{:keys [id name type]} (->> (:bank-accounts (:client data)) (filter :visible) (sort-by :sort-order))]
|
||||
(if (= :cash type)
|
||||
^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::save-requested [::add-and-print id :cash]])} "With cash"]
|
||||
(list
|
||||
@@ -476,7 +469,7 @@
|
||||
{:key id}))])
|
||||
|
||||
|
||||
(defn form [p]
|
||||
(defn form [_]
|
||||
(r/create-class
|
||||
{:display-name "invoice-form"
|
||||
:component-did-mount #(re-frame/dispatch [::mounted])
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
(ns auto-ap.views.pages.ledger
|
||||
(:require [auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.bank-account-filter :refer [bank-account-filter]]
|
||||
[auto-ap.views.components.layouts :refer [appearing-side-bar side-bar-layout]]
|
||||
[auto-ap.routes :as routes]
|
||||
[bidi.bidi :as bidi]
|
||||
[auto-ap.views.components.paginator :refer [paginator]]
|
||||
[auto-ap.views.components.sorter :refer [sorted-column]]
|
||||
[auto-ap.views.pages.ledger.table :as table]
|
||||
[auto-ap.views.pages.ledger.side-bar :refer [ledger-side-bar] :as side-bar]
|
||||
[auto-ap.views.pages.transactions.common :refer [transaction-read]]
|
||||
(:require
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.pages.ledger.side-bar
|
||||
:as side-bar
|
||||
:refer [ledger-side-bar]]
|
||||
[auto-ap.views.pages.ledger.table :as table]
|
||||
[auto-ap.views.utils :refer [with-user]]
|
||||
[clojure.set :as set]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
|
||||
[auto-ap.utils :refer [replace-by]]
|
||||
[auto-ap.views.pages.transactions.manual :as manual]
|
||||
[auto-ap.views.utils :refer [bind-field date->str dispatch-event nf active-when with-user]]
|
||||
[goog.string :as gstring]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[auto-ap.status :as status]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[clojure.set :as set]))
|
||||
(defn data-params->query-params [params]
|
||||
{:start (:start params 0)
|
||||
:sort (:sort params)
|
||||
@@ -39,7 +30,7 @@
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
[with-user]
|
||||
(fn [{:keys [user db]} [_ params]]
|
||||
(fn [{:keys [user]} [_ params]]
|
||||
{:graphql {:token user
|
||||
:owns-state {:single [::data-page/page ::page]}
|
||||
:query-obj {:venia/queries [[:ledger-page
|
||||
@@ -57,7 +48,7 @@
|
||||
[:name :id]]
|
||||
[:line-items
|
||||
[:id :debit :credit :location :running-balance
|
||||
[:account [:id]]]]
|
||||
[:account [:id :name]]]]
|
||||
:date]]
|
||||
:total
|
||||
:start
|
||||
@@ -68,13 +59,13 @@
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn [{:keys [db]} _]
|
||||
(fn [_ _]
|
||||
{:dispatch [::data-page/dispose ::page]
|
||||
::track/dispose {:id ::params}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [{:keys [db]} _]
|
||||
(fn [_ _]
|
||||
{::track/register {:id ::params
|
||||
:subscription [::data-page/params ::page]
|
||||
:event-fn (fn [params] [::params-change params])}}))
|
||||
@@ -82,11 +73,10 @@
|
||||
|
||||
|
||||
(defn ledger-content []
|
||||
(let [current-client @(re-frame/subscribe [::subs/client])]
|
||||
[:div
|
||||
[:h1.title "Ledger"]
|
||||
[table/table {:id :ledger
|
||||
:data-page ::page}]]))
|
||||
[:div
|
||||
[:h1.title "Ledger"]
|
||||
[table/table {:id :ledger
|
||||
:data-page ::page}]])
|
||||
|
||||
|
||||
(defn ledger-page []
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
[:name :id]]
|
||||
[:line-items
|
||||
[:id :debit :credit :location :running-balance
|
||||
[:account [:id]]]]
|
||||
[:account [:id :name]]]]
|
||||
:date]]
|
||||
:total
|
||||
:start
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
|
||||
(defn external-ledger-row [{{:keys [client vendor alternate-description status date amount id source external-id line-items] :as i} :row
|
||||
:keys [selected-client accounts-by-id bank-accounts-by-id]}]
|
||||
:keys [selected-client bank-accounts-by-id]}]
|
||||
[:<>
|
||||
[grid/row {:class (:class i) :id id :checkable? true :entity i}
|
||||
(when-not selected-client
|
||||
@@ -28,8 +28,8 @@
|
||||
[grid/cell {:class "has-text-right"} (nf amount )]]
|
||||
[:<>
|
||||
(for [{:keys [debit credit location account id running-balance]} line-items
|
||||
:let [account (or (accounts-by-id (:id account))
|
||||
(bank-accounts-by-id (:id account)))]]
|
||||
:let [account (or (bank-accounts-by-id (:id account))
|
||||
account)]]
|
||||
^{:key id}
|
||||
[grid/row {:checkable? false}
|
||||
(when-not selected-client
|
||||
@@ -49,7 +49,6 @@
|
||||
(defn table [{:keys [id data-page status vendors on-check-changed expense-event]}]
|
||||
(let [{:keys [data status params]} @(re-frame/subscribe [::data-page/page data-page])
|
||||
selected-client @(re-frame/subscribe [::subs/client])
|
||||
accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id selected-client])
|
||||
bank-accounts-by-id @(re-frame/subscribe [::subs/bank-accounts-by-id])]
|
||||
[grid/grid {:data-page data-page
|
||||
:check-boxes? true
|
||||
@@ -73,6 +72,5 @@
|
||||
^{:key id}
|
||||
[external-ledger-row {:row i
|
||||
:selected-client selected-client
|
||||
:accounts-by-id accounts-by-id
|
||||
:bank-accounts-by-id bank-accounts-by-id}])]]]))
|
||||
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
(ns auto-ap.views.pages.ledger.side-bar
|
||||
(:require [auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.date-range-filter :refer [date-range-filter]]
|
||||
[auto-ap.views.components.number-filter :refer [number-filter]]
|
||||
[auto-ap.views.components.bank-account-filter :refer [bank-account-filter]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [active-when dispatch-value-change]]
|
||||
[bidi.bidi :as bidi]
|
||||
[re-frame.core :as re-frame]))
|
||||
(:require
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.bank-account-filter
|
||||
:refer [bank-account-filter]]
|
||||
[auto-ap.views.components.date-range-filter :refer [date-range-filter]]
|
||||
[auto-ap.views.components.number-filter :refer [number-filter]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [active-when dispatch-value-change]]
|
||||
[bidi.bidi :as bidi]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn ledger-side-bar [{:keys [data-page]}]
|
||||
(let [ap @(re-frame/subscribe [::subs/active-page])
|
||||
user @(re-frame/subscribe [::subs/user])
|
||||
accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id])
|
||||
accounts-index @(re-frame/subscribe [::subs/accounts-index])]
|
||||
client @(re-frame/subscribe [::subs/client])]
|
||||
[:div
|
||||
[:ul.menu-list
|
||||
[:li.menu-item
|
||||
@@ -57,23 +60,25 @@
|
||||
|
||||
[:p.menu-label "Financial Account"]
|
||||
[:div
|
||||
[typeahead-v3 {:entities-by-id accounts-by-id
|
||||
:entity-index accounts-index
|
||||
:entity->text (fn [x ] (str (:numeric-code x) " - " (:name x)))
|
||||
:type "typeahead-v3"
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :account (some-> % (select-keys [:name :id :numeric-code]))])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :account])}]]
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_account
|
||||
{:query i
|
||||
:client-id (:id client)}
|
||||
[:name :id]])
|
||||
:entity->text (fn [x ] (str (:numeric-code x) " - " (:name x)))
|
||||
:type "typeahead-v3"
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :account (some-> % (select-keys [:name :id :numeric-code]))])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :account])}]]
|
||||
|
||||
[:p.menu-label "Vendor"]
|
||||
[:div
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor (some-> % (select-keys [:name :id]))])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
|
||||
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
|
||||
[:p.menu-label "Date Range"]
|
||||
[:div
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
[cemerick.url :as url]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn ledger-row [{{:keys [client vendor alternate-description note status date amount id line-items source original-entity] :as i} :row
|
||||
:keys [selected-client accounts-by-id bank-accounts-by-id]}]
|
||||
(defn ledger-row [{{:keys [client vendor alternate-description note date amount id line-items source original-entity] :as i} :row
|
||||
:keys [selected-client bank-accounts-by-id]}]
|
||||
[:<>
|
||||
[grid/row {:class (:class i) :id id}
|
||||
(when-not selected-client
|
||||
@@ -73,8 +73,8 @@
|
||||
)]]]]])]]
|
||||
[:<>
|
||||
(for [{:keys [debit credit location account id running-balance]} line-items
|
||||
:let [account (or (accounts-by-id (:id account))
|
||||
(bank-accounts-by-id (:id account)))]]
|
||||
:let [account (or (bank-accounts-by-id (:id account))
|
||||
account)]]
|
||||
^{:key id}
|
||||
[grid/row {}
|
||||
(when-not selected-client
|
||||
@@ -92,10 +92,9 @@
|
||||
|
||||
#_[grid/cell {:class "has-text-right"} (when running-balance (nf running-balance ))]])]])
|
||||
|
||||
(defn table [{:keys [id data-page status vendors on-check-changed expense-event]}]
|
||||
(let [{:keys [data status]} @(re-frame/subscribe [::data-page/page data-page])
|
||||
(defn table [{:keys [data-page]}]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::data-page/page data-page])
|
||||
selected-client @(re-frame/subscribe [::subs/client])
|
||||
accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id selected-client])
|
||||
bank-accounts-by-id @(re-frame/subscribe [::subs/bank-accounts-by-id])]
|
||||
[grid/grid {:data-page data-page
|
||||
:column-count (if selected-client 5 6)}
|
||||
@@ -113,10 +112,9 @@
|
||||
[grid/header-cell {:style {:width (action-cell-width 1)}}]
|
||||
#_[grid/header-cell {:class "has-text-right" :style {:width "10em"}} "Running Balance"]]]
|
||||
[grid/body
|
||||
(for [{:keys [client vendor status date amount id line-items] :as i} (:data data)]
|
||||
(for [{:keys [id] :as i} (:data data)]
|
||||
^{:key id}
|
||||
[ledger-row {:row i
|
||||
:selected-client selected-client
|
||||
:accounts-by-id accounts-by-id
|
||||
:bank-accounts-by-id bank-accounts-by-id}])]]]))
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
(ns auto-ap.views.pages.new-invoice
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.events :as events]))
|
||||
|
||||
(defn new-invoice-page []
|
||||
(let [form-data (re-frame/subscribe [::subs/new-invoice-form])]
|
||||
[:div
|
||||
[:form
|
||||
[:h1.title "New InvoiceR"]
|
||||
[:div.field
|
||||
[:label.label "Vendor"]
|
||||
[:div.control
|
||||
[:input.input {:type "text"
|
||||
:auto-focus true
|
||||
:placeholder "CINTAS"
|
||||
:value (:vendor @form-data)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::events/change-form-state
|
||||
[:new-invoice :vendor]
|
||||
(.. e -target -value)]))}]]]
|
||||
[:div.field
|
||||
[:label.label "Customer"]
|
||||
[:div.control
|
||||
[:input.input {:type "text"
|
||||
:placeholder "Brown Chicken Brown Cow"
|
||||
:value (:client @form-data)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::events/change-form-state
|
||||
[:new-invoice :client]
|
||||
(.. e -target -value)]))}]]]
|
||||
[:div.field
|
||||
[:label.label "Invoice #"]
|
||||
[:div.control
|
||||
[:input.input {:type "text"
|
||||
:placeholder "12345"
|
||||
:value (:invoice-number @form-data)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::events/change-form-state
|
||||
[:new-invoice :invoice-number]
|
||||
(.. e -target -value)]))}]]]
|
||||
[:div.field
|
||||
[:label.label "Date"]
|
||||
[:div.control
|
||||
[:input.input {:type "text"
|
||||
:placeholder "11/11/2011"
|
||||
:value (:date @form-data)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::events/change-form-state
|
||||
[:new-invoice :date]
|
||||
(.. e -target -value)]))}]]]
|
||||
[:div.field
|
||||
[:label.label "Total"]
|
||||
[:div.control
|
||||
[:input.input {:type "text"
|
||||
:placeholder "$14.50"
|
||||
:value (:total @form-data)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::events/change-form-state
|
||||
[:new-invoice :total]
|
||||
(.. e -target -value)]))}]]]
|
||||
[:div.control
|
||||
[:submit.button.is-large.is-primary {
|
||||
:disabled (if (and (:total @form-data) (:date @form-data) (:client @form-data) (:invoice-number @form-data)
|
||||
(:vendor @form-data))
|
||||
""
|
||||
"disabled")
|
||||
:on-click
|
||||
(fn [x]
|
||||
(.preventDefault x)
|
||||
(re-frame/dispatch [::events/submit-new-invoice @form-data]))}
|
||||
[:span
|
||||
(when (:loading? @form-data)
|
||||
[:i.fa.fa-spin.fa-spinner])
|
||||
"Save"]]]]]))
|
||||
@@ -1,11 +1,13 @@
|
||||
(ns auto-ap.views.pages.payments.side-bar
|
||||
(:require [auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.date-range-filter :refer [date-range-filter]]
|
||||
[auto-ap.views.components.number-filter :refer [number-filter]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [dispatch-event dispatch-value-change]]
|
||||
[re-frame.core :as re-frame]))
|
||||
(:require
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.date-range-filter :refer [date-range-filter]]
|
||||
[auto-ap.views.components.number-filter :refer [number-filter]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [dispatch-event dispatch-value-change]]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn side-bar [{:keys [data-page]}]
|
||||
(let [ap @(re-frame/subscribe [::subs/active-page])
|
||||
@@ -14,13 +16,13 @@
|
||||
[:div
|
||||
[:p.menu-label "Vendor"]
|
||||
[:div
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor (some-> % (select-keys [:name :id]))])
|
||||
:include-keys [:name :id]
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
|
||||
[:p.menu-label "Date Range"]
|
||||
[:div
|
||||
|
||||
@@ -8,13 +8,18 @@
|
||||
:as expense-accounts-field
|
||||
:refer [expense-accounts-field]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.pages.transactions.common
|
||||
:refer [data-params->query-params]]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.views.pages.data-page :as data-page]))
|
||||
[reagent.core :as r]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.events :as events]
|
||||
[vimsical.re-frame.cofx.inject :as inject]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
@@ -31,8 +36,8 @@
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::code-selected
|
||||
[with-user (forms/in-form ::form) ]
|
||||
(fn [{:keys [user db]} [_ checked]]
|
||||
[with-user (forms/in-form ::form) (re-frame/inject-cofx ::inject/sub [::subs/client])]
|
||||
(fn [{:keys [user db] ::subs/keys [client]} [_ checked]]
|
||||
(let [checked-params (get checked "header")
|
||||
specific-transactions (map :id (vals (dissoc checked "header")))
|
||||
data (:data db)]
|
||||
@@ -43,6 +48,7 @@
|
||||
:operation/name "BulkCodeTransactions"}
|
||||
:venia/queries [[:bulk-code-transactions
|
||||
{:filters (some-> checked-params data-params->query-params)
|
||||
:client_id (:id client)
|
||||
:ids specific-transactions
|
||||
:vendor (:id (:vendor data))
|
||||
:approval-status (:transaction-approval-status data)
|
||||
@@ -67,33 +73,56 @@
|
||||
::changed
|
||||
(forms/change-handler ::form
|
||||
(fn [data field value]
|
||||
(cond (and (= [:vendor] field)
|
||||
(cond (and (= [:vendor-preferences] field)
|
||||
value)
|
||||
[[:accounts] (expense-accounts-field/default-account (:accounts data)
|
||||
@(re-frame/subscribe [::subs/vendor-default-account (:id value) (:client data)])
|
||||
(:default-account value)
|
||||
(:total data)
|
||||
[])]
|
||||
:else
|
||||
[]))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::changed-vendor
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{{{:keys [client]} :data} :db} [_ vendor]]
|
||||
(when (and (:id client) (:id vendor))
|
||||
{:dispatch [::events/vendor-preferences-requested {:client-id (:id client)
|
||||
:vendor-id (:id vendor)
|
||||
:on-success [::changed [:vendor-preferences]]
|
||||
:on-failure [:hello]}]})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn []
|
||||
{::track/register {:id ::vendor-change
|
||||
:subscription [::forms/field ::form [:vendor]]
|
||||
:event-fn (fn [v]
|
||||
[::changed-vendor v])}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn []
|
||||
{::track/dispose {:id ::vendor-change}}))
|
||||
|
||||
(def code-form (forms/vertical-form {:submit-event [::code-selected]
|
||||
:change-event [::changed]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}))
|
||||
(defn form []
|
||||
:change-event [::changed]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}))
|
||||
(defn form-content [_]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline field]} code-form
|
||||
]
|
||||
{:keys [form-inline field]} code-form]
|
||||
|
||||
(form-inline {}
|
||||
[:<>
|
||||
(field "Vendor"
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:vendor]}])
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:vendor]}])
|
||||
|
||||
(field "Approval Status"
|
||||
[button-radio
|
||||
@@ -115,6 +144,13 @@
|
||||
:field [:accounts]}])
|
||||
{:key (some-> data :vendor :id str)})
|
||||
])))
|
||||
(defn form [_]
|
||||
(r/create-class
|
||||
{:display-name "transaction-bulk-update-form"
|
||||
:component-did-mount #(re-frame/dispatch [::mounted])
|
||||
:component-will-unmount #(re-frame/dispatch [::unmounted])
|
||||
:reagent-render (fn [p]
|
||||
[form-content p])}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::code-requested
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
(ns auto-ap.views.pages.transactions.form
|
||||
(:require [auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.button-radio :refer [button-radio]]
|
||||
[auto-ap.views.components.expense-accounts-field
|
||||
:as
|
||||
expense-accounts-field
|
||||
:refer
|
||||
[expense-accounts-field]]
|
||||
[auto-ap.views.components.layouts :as layouts]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.pages.transactions.common :refer [transaction-read]]
|
||||
[auto-ap.views.utils
|
||||
:refer
|
||||
[->$ date->str dispatch-event pretty with-user]]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[react :as react]
|
||||
[reagent.core :as r]))
|
||||
(:require
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.button-radio :refer [button-radio]]
|
||||
[auto-ap.views.components.expense-accounts-field
|
||||
:as expense-accounts-field
|
||||
:refer [expense-accounts-field]]
|
||||
[auto-ap.views.components.layouts :as layouts]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.transactions.common :refer [transaction-read]]
|
||||
[auto-ap.views.utils
|
||||
:refer [->$ date->str dispatch-event pretty with-user]]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[react :as react]
|
||||
[reagent.core :as r]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.events :as events]))
|
||||
|
||||
;; SUBS
|
||||
(re-frame/reg-sub
|
||||
@@ -54,8 +56,7 @@
|
||||
(re-frame/reg-event-db
|
||||
::editing
|
||||
(fn [db [_ which potential-payment-matches potential-autopay-invoices-matches potential-unpaid-invoices-matches potential-transaction-rule-matches]]
|
||||
(let [locations @(re-frame/subscribe [::subs/locations-for-client (:id (:client which))])
|
||||
accounts-by-id @(re-frame/subscribe [::subs/accounts-by-id (:client which)])]
|
||||
(let [locations @(re-frame/subscribe [::subs/locations-for-client (:id (:client which))])]
|
||||
(forms/start-form db ::form
|
||||
(-> which
|
||||
(select-keys [:vendor :amount :payment :client :description-original
|
||||
@@ -69,18 +70,18 @@
|
||||
(assoc :potential-transaction-rule-matches potential-transaction-rule-matches)
|
||||
(assoc :potential-autopay-invoices-matches potential-autopay-invoices-matches)
|
||||
(assoc :potential-unpaid-invoices-matches potential-unpaid-invoices-matches)
|
||||
(update :accounts expense-accounts-field/from-graphql accounts-by-id (:amount which) locations))))))
|
||||
(update :accounts expense-accounts-field/from-graphql (:amount which) locations))))))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::changed
|
||||
(forms/change-handler ::form
|
||||
(fn [data field value]
|
||||
(let [locations @(re-frame/subscribe [::subs/locations-for-client (:id (:client data))])]
|
||||
(if (and (= [:vendor] field)
|
||||
(if (and (= [:vendor-preferences] field)
|
||||
value
|
||||
(expense-accounts-field/can-replace-with-default? (:accounts data)))
|
||||
[[:accounts] (expense-accounts-field/default-account (:accounts data)
|
||||
@(re-frame/subscribe [::subs/vendor-default-account (:id value) (:client data)])
|
||||
(:default-account (:vendor-preferences data))
|
||||
(:amount data)
|
||||
locations)]
|
||||
[])))))
|
||||
@@ -185,17 +186,28 @@
|
||||
{}))
|
||||
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::manual-match
|
||||
[(forms/in-form ::form)]
|
||||
(fn [edit-transaction]
|
||||
(update-in edit-transaction [:data] dissoc :potential-payment-matches)))
|
||||
(re-frame/reg-event-fx
|
||||
::changed-vendor
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{{{:keys [client]} :data} :db} [_ vendor]]
|
||||
(when (and (:id client) (:id vendor))
|
||||
{:dispatch [::events/vendor-preferences-requested {:client-id (:id client)
|
||||
:vendor-id (:id vendor)
|
||||
:on-success [::changed [:vendor-preferences]]
|
||||
:on-failure [:hello]}]})))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::transaction-rule-closed
|
||||
[(forms/in-form ::form)]
|
||||
(fn [edit-transaction]
|
||||
(update-in edit-transaction [:data] dissoc :potential-transaction-rule-matches)))
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn []
|
||||
{::track/register {:id ::vendor-change
|
||||
:subscription [::forms/field ::form [:vendor]]
|
||||
:event-fn (fn [v]
|
||||
[::changed-vendor v])}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn []
|
||||
{::track/dispose {:id ::vendor-change}}))
|
||||
|
||||
;; VIEWS
|
||||
|
||||
@@ -324,7 +336,7 @@
|
||||
[:a {:on-click (fn [] (on-tab-clicked (:key props)))} (:title props)]])))])
|
||||
|
||||
|
||||
(defn form [_]
|
||||
(defn form-content [_]
|
||||
[layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form])}
|
||||
(let [{:keys [data] } @(re-frame/subscribe [::forms/form ::form])
|
||||
locations @(re-frame/subscribe [::subs/locations-for-client (:id (:client data))])
|
||||
@@ -404,14 +416,15 @@
|
||||
[tab {:title "Details" :key :details}
|
||||
[:div
|
||||
(field "Vendor"
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:vendor]
|
||||
:disabled (or (boolean (:payment data))
|
||||
should-disable-for-client?)}])
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:vendor]
|
||||
:disabled (or (boolean (:payment data))
|
||||
should-disable-for-client?)}])
|
||||
(with-meta
|
||||
(field nil
|
||||
[expense-accounts-field
|
||||
@@ -442,3 +455,11 @@
|
||||
(when-not should-disable-for-client?
|
||||
(submit-button "Save"))]]]])
|
||||
{:key (:id data)}))])
|
||||
|
||||
(defn form [_]
|
||||
(r/create-class
|
||||
{:display-name "transaction-form"
|
||||
:component-did-mount #(re-frame/dispatch [::mounted])
|
||||
:component-will-unmount #(re-frame/dispatch [::unmounted])
|
||||
:reagent-render (fn [p]
|
||||
[form-content p])}))
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
(ns auto-ap.views.pages.transactions.side-bar
|
||||
(:require [auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.bank-account-filter
|
||||
:refer
|
||||
[bank-account-filter]]
|
||||
[auto-ap.views.components.date-range-filter :refer [date-range-filter]]
|
||||
[auto-ap.views.components.number-filter :refer [number-filter]]
|
||||
[auto-ap.views.components.switch-field :refer [switch-field]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils :refer [active-when dispatch-event dispatch-value-change ->$ account->match-text]]
|
||||
[bidi.bidi :as bidi]
|
||||
[re-frame.core :as re-frame]))
|
||||
(:require
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.bank-account-filter
|
||||
:refer [bank-account-filter]]
|
||||
[auto-ap.views.components.date-range-filter :refer [date-range-filter]]
|
||||
[auto-ap.views.components.number-filter :refer [number-filter]]
|
||||
[auto-ap.views.components.switch-field :refer [switch-field]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.data-page :as data-page]
|
||||
[auto-ap.views.utils
|
||||
:refer [active-when dispatch-event dispatch-value-change]]
|
||||
[bidi.bidi :as bidi]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn side-bar [{:keys [data-page]}]
|
||||
(let [ap @(re-frame/subscribe [::subs/active-page])
|
||||
user @(re-frame/subscribe [::subs/user])
|
||||
|
||||
accounts @(re-frame/subscribe [::subs/accounts-by-id])
|
||||
account-index @(re-frame/subscribe [::subs/accounts-index])
|
||||
]
|
||||
client @(re-frame/subscribe [::subs/client])]
|
||||
[:div
|
||||
[:div [:p.menu-label "Type"]
|
||||
[:ul.menu-list
|
||||
@@ -65,21 +64,25 @@
|
||||
|
||||
[:p.menu-label "Financial Account"]
|
||||
[:div
|
||||
[typeahead-v3 {:entities-by-id accounts
|
||||
:entity-index account-index
|
||||
:entity->text account->match-text
|
||||
:type "typeahead-v3"
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :account (some-> % (select-keys [:name :id :numeric-code]))])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :account])}]]
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_account
|
||||
{:query i
|
||||
:client-id (:id client)}
|
||||
[:name :id]])
|
||||
:entity->text (fn [x ] (str (:numeric-code x) " - " (:name x)))
|
||||
:type "typeahead-v3"
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :account (some-> % (select-keys [:name :id :numeric-code]))])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :account])}]]
|
||||
|
||||
[:p.menu-label "Vendor"]
|
||||
[:div
|
||||
[typeahead-v3 {:entities-by-id @(re-frame/subscribe [::subs/vendors-by-id])
|
||||
:entity-index @(re-frame/subscribe [::subs/searchable-vendors-index])
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor (some-> % (select-keys [:name :id]))])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
|
||||
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
:which (:id which)}
|
||||
:query-obj {:venia/queries
|
||||
(cond-> [{:query/data [:potential-payment-matches
|
||||
{:transaction_id (:id which)}
|
||||
[:id :memo :check-number [:vendor [:name]]]]}
|
||||
{:query/data [:potential-payment-matches
|
||||
{:transaction_id (:id which)}
|
||||
[:id :memo :check-number [:vendor [:name]]]]}]
|
||||
(or (= "admin" role)
|
||||
@@ -55,8 +58,7 @@
|
||||
(into [{:query/data [:potential-transaction-rule-matches
|
||||
{:transaction_id (:id which)}
|
||||
[:id :note]]}]))}
|
||||
:on-success [::editing-matches-found which]
|
||||
:on-error [::editing-matches-failed which]}}))
|
||||
:on-success [::editing-matches-found which]}}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::table-params
|
||||
|
||||
Reference in New Issue
Block a user