Merge branch 'master' into side-panel
This commit is contained in:
@@ -22,8 +22,9 @@
|
|||||||
|
|
||||||
(def default-read '(pull ?e [*
|
(def default-read '(pull ?e [*
|
||||||
{:invoice-payment/_payment [* {:invoice-payment/invoice [*]}]}
|
{:invoice-payment/_payment [* {:invoice-payment/invoice [*]}]}
|
||||||
{:payment/client [:client/name :db/id]}
|
{:payment/client [:client/name :db/id :client/code]}
|
||||||
{:payment/vendor [:vendor/name :db/id]}
|
{:payment/bank-account [*]}
|
||||||
|
{:payment/vendor [:vendor/name :vendor/default-expense-account :db/id {:vendor/primary-contact [*]} {:vendor/address [*]}]}
|
||||||
{:payment/status [:db/ident]}
|
{:payment/status [:db/ident]}
|
||||||
{:payment/type [:db/ident]}]))
|
{:payment/type [:db/ident]}]))
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
(ns auto-ap.datomic.invoices
|
(ns auto-ap.datomic.invoices
|
||||||
(:require [datomic.api :as d]
|
(:require [datomic.api :as d]
|
||||||
[auto-ap.datomic :refer [uri]]
|
[auto-ap.datomic :refer [uri remove-nils]]
|
||||||
[auto-ap.graphql.utils :refer [limited-clients]]
|
[auto-ap.graphql.utils :refer [limited-clients]]
|
||||||
|
[auto-ap.parse :as parse]
|
||||||
[clj-time.coerce :as c]
|
[clj-time.coerce :as c]
|
||||||
[clojure.set :refer [rename-keys]]
|
[clojure.set :refer [rename-keys]]
|
||||||
[clojure.string :as str]))
|
[clojure.string :as str]))
|
||||||
@@ -15,8 +16,8 @@
|
|||||||
(reduce #(update-in %1 [:query :where] conj %2) query rest)))
|
(reduce #(update-in %1 [:query :where] conj %2) query rest)))
|
||||||
|
|
||||||
(def default-read '(pull ?e [*
|
(def default-read '(pull ?e [*
|
||||||
{:invoice/client [:client/name :db/id :client/locations]}
|
{:invoice/client [:client/name :db/id :client/locations :client/code]}
|
||||||
{:invoice/vendor [:vendor/name :db/id]}
|
{:invoice/vendor [* {:vendor/address [*]}]}
|
||||||
{:invoice/status [:db/ident]}
|
{:invoice/status [:db/ident]}
|
||||||
{:invoice-payment/_invoice [* {:invoice-payment/payment [* {:payment/status [*]}
|
{:invoice-payment/_invoice [* {:invoice-payment/payment [* {:payment/status [*]}
|
||||||
{:payment/bank-account [*]}
|
{:payment/bank-account [*]}
|
||||||
@@ -49,6 +50,8 @@
|
|||||||
(:original-id args) (add-arg '?original-id (cond-> (:original-id args) (string? (:original-id args)) Long/parseLong )
|
(:original-id args) (add-arg '?original-id (cond-> (:original-id args) (string? (:original-id args)) Long/parseLong )
|
||||||
'[?e :invoice/client ?c]
|
'[?e :invoice/client ?c]
|
||||||
'[?c :client/original-id ?original-id])
|
'[?c :client/original-id ?original-id])
|
||||||
|
(:import-status args) (add-arg '?import-status (keyword "import-status" (:import-status args))
|
||||||
|
'[?e :invoice/import-status ?import-status])
|
||||||
(:status args) (add-arg '?status (keyword "invoice-status" (:status args))
|
(:status args) (add-arg '?status (keyword "invoice-status" (:status args))
|
||||||
'[?e :invoice/status ?status])
|
'[?e :invoice/status ?status])
|
||||||
(:vendor-id args) (add-arg '?vendor-id (:vendor-id args)
|
(:vendor-id args) (add-arg '?vendor-id (:vendor-id args)
|
||||||
@@ -127,3 +130,5 @@
|
|||||||
(map first)
|
(map first)
|
||||||
|
|
||||||
(<-datomic)))
|
(<-datomic)))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
[datomic.api :as d]
|
[datomic.api :as d]
|
||||||
[auto-ap.datomic.migrate.add-client-codes :refer [add-client-codes]]
|
[auto-ap.datomic.migrate.add-client-codes :refer [add-client-codes]]
|
||||||
[auto-ap.datomic.migrate.add-bank-account-codes :refer [add-bank-account-codes]]
|
[auto-ap.datomic.migrate.add-bank-account-codes :refer [add-bank-account-codes]]
|
||||||
|
[auto-ap.datomic.migrate.invoice-converter :refer [add-import-status-existing-invoices]]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[io.rkn.conformity :as c])
|
[io.rkn.conformity :as c])
|
||||||
(:import [datomic Util])
|
(:import [datomic Util])
|
||||||
@@ -53,6 +54,14 @@
|
|||||||
:auto-ap/add-client-codes {:txes-fn 'auto-ap.datomic.migrate.add-client-codes/add-client-codes :requires [:auto-ap/migrate-transactions]}
|
:auto-ap/add-client-codes {:txes-fn 'auto-ap.datomic.migrate.add-client-codes/add-client-codes :requires [:auto-ap/migrate-transactions]}
|
||||||
:auto-ap/add-bank-account-codes-schema {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes-schema :requires [:auto-ap/add-client-codes]}
|
:auto-ap/add-bank-account-codes-schema {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes-schema :requires [:auto-ap/add-client-codes]}
|
||||||
:auto-ap/add-bank-account-codes {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes :requires [:auto-ap/add-bank-account-codes-schema]}
|
:auto-ap/add-bank-account-codes {:txes-fn 'auto-ap.datomic.migrate.add-bank-account-codes/add-bank-account-codes :requires [:auto-ap/add-bank-account-codes-schema]}
|
||||||
|
:auto-ap/add-nick-the-greek {:txes [[{:client/name "Nick the Greek" :client/code "NGAK" :client/locations ["MH"] :client/bank-accounts [{:bank-account/code "NGAK-0" :bank-account/type :bank-account-type/cash :bank-account/name "Cash"}]}]] :requires [:auto-ap/add-bank-account-codes]}
|
||||||
|
:auto-ap/rename-codes-1 {:txes-fn 'auto-ap.datomic.migrate.rename-codes/rename-codes-1 :requires [:auto-ap/add-nick-the-greek]}
|
||||||
|
:auto-ap/invoice-converter {:txes auto-ap.datomic.migrate.invoice-converter/add-matches :requires [:auto-ap/rename-codes-1]}
|
||||||
|
:auto-ap/starter {:txes auto-ap.datomic.migrate.invoice-converter/add-starter :requires [:auto-ap/invoice-converter]}
|
||||||
|
:auto-ap/add-default-location {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-default-location :requires [:auto-ap/invoice-converter]}
|
||||||
|
:auto-ap/add-default-location-2 {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-default-location-2 :requires [:auto-ap/add-default-location]}
|
||||||
|
:auto-ap/add-import-status {:txes auto-ap.datomic.migrate.invoice-converter/add-import-status :requires [:auto-ap/add-default-location-2]}
|
||||||
|
:auto-ap/add-import-status-existing-invoices {:txes-fn 'auto-ap.datomic.migrate.invoice-converter/add-import-status-existing-invoices :requires [:auto-ap/add-import-status]}
|
||||||
}]
|
}]
|
||||||
(println "Conforming database...")
|
(println "Conforming database...")
|
||||||
(println (c/ensure-conforms conn norms-map))
|
(println (c/ensure-conforms conn norms-map))
|
||||||
|
|||||||
58
src/clj/auto_ap/datomic/migrate/invoice_converter.clj
Normal file
58
src/clj/auto_ap/datomic/migrate/invoice_converter.clj
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
(ns auto-ap.datomic.migrate.invoice-converter
|
||||||
|
(:require [datomic.api :as d]))
|
||||||
|
|
||||||
|
(def add-matches
|
||||||
|
[[{:db/ident :client/matches
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/cardinality :db.cardinality/many
|
||||||
|
:db/doc "The strings that match the client"}
|
||||||
|
{:db/ident :client/location-matches
|
||||||
|
:db/valueType :db.type/ref
|
||||||
|
:db/cardinality :db.cardinality/many
|
||||||
|
:db/isComponent true
|
||||||
|
:db/doc "The mapping from string to location"}
|
||||||
|
|
||||||
|
{:db/ident :location-match/matches
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/cardinality :db.cardinality/many
|
||||||
|
:db/doc "The strings that match the location"}
|
||||||
|
|
||||||
|
{:db/ident :location-match/location
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/doc "The location of the location match"}
|
||||||
|
]])
|
||||||
|
|
||||||
|
(def add-starter
|
||||||
|
[[{:db/id [:client/code "CBC"]
|
||||||
|
:client/matches ["campbell brewing company"]
|
||||||
|
:client/location-matches [{:location-match/location "CB"
|
||||||
|
:location-match/matches ["campbell brewing company"]}]}]])
|
||||||
|
|
||||||
|
(defn add-default-location [conn]
|
||||||
|
[[{:db/ident :client/default-location
|
||||||
|
:db/valueType :db.type/string
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/doc "The default location if one can't be found"}]])
|
||||||
|
|
||||||
|
(defn add-default-location-2 [conn]
|
||||||
|
[[{:db/id [:client/code "CBC"]
|
||||||
|
:client/default-location "CB"}]])
|
||||||
|
|
||||||
|
(def add-import-status
|
||||||
|
[[{:db/ident :invoice/import-status
|
||||||
|
:db/valueType :db.type/ref
|
||||||
|
:db/cardinality :db.cardinality/one
|
||||||
|
:db/doc "The status of importing the transaction"}
|
||||||
|
|
||||||
|
{:db/ident :import-status/pending}
|
||||||
|
{:db/ident :import-status/imported}]])
|
||||||
|
|
||||||
|
(defn add-import-status-existing-invoices [conn]
|
||||||
|
(let [existing-invoices (->> (d/query {:query {:find ['?e]
|
||||||
|
:in ['$]
|
||||||
|
:where ['[?e :invoice/invoice-number]]}
|
||||||
|
:args [(d/db conn)]}))]
|
||||||
|
[(map (fn [i] {:db/id (first i)
|
||||||
|
:invoice/import-status :import-status/imported})
|
||||||
|
existing-invoices)]))
|
||||||
41
src/clj/auto_ap/datomic/migrate/rename_codes.clj
Normal file
41
src/clj/auto_ap/datomic/migrate/rename_codes.clj
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
(ns auto-ap.datomic.migrate.rename-codes
|
||||||
|
(:require [datomic.api :as d]
|
||||||
|
[auto-ap.datomic :refer [uri]]
|
||||||
|
[clojure.string :as str]))
|
||||||
|
|
||||||
|
(defn rename [old-code new-code conn ]
|
||||||
|
(let [results (->> (d/query {:query {:find ['?e '?b '?bc]
|
||||||
|
:in ['$ '?old-code]
|
||||||
|
:where ['[?e :client/code ?old-code]
|
||||||
|
'[?e :client/bank-accounts ?b]
|
||||||
|
'[?b :bank-account/code ?bc]]}
|
||||||
|
:args [(d/db conn) old-code]})
|
||||||
|
(group-by first))
|
||||||
|
|
||||||
|
#_#_[[id]] results]
|
||||||
|
(for [[id change] results
|
||||||
|
[_ ba-id ba-code] change]
|
||||||
|
[{:db/id id
|
||||||
|
:client/code new-code}
|
||||||
|
{:db/id ba-id
|
||||||
|
:bank-account/code (str/replace ba-code #"^.*-" (str new-code "-"))}])
|
||||||
|
|
||||||
|
#_[{:db/id id
|
||||||
|
:client/code new-code
|
||||||
|
#_#_:client/bank-accounts (map)}]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn rename-codes-1 [conn]
|
||||||
|
(let [result (apply concat [(rename "WE" "WME" (d/connect uri))
|
||||||
|
(rename "HM" "HIM" (d/connect uri))
|
||||||
|
(rename "BES" "SBE" (d/connect uri))
|
||||||
|
(rename "BES" "SBE" (d/connect uri))
|
||||||
|
(rename "ORA" "OMG" (d/connect uri))
|
||||||
|
(rename "INT" "IGC" (d/connect uri))
|
||||||
|
(rename "MV" "MVSC" (d/connect uri))])]
|
||||||
|
(if (seq (seq result))
|
||||||
|
result
|
||||||
|
[[]]))
|
||||||
|
)
|
||||||
|
|
||||||
@@ -112,8 +112,8 @@
|
|||||||
true (apply-pagination args))))
|
true (apply-pagination args))))
|
||||||
|
|
||||||
(defn graphql-results [ids db args]
|
(defn graphql-results [ids db args]
|
||||||
(->> (d/pull-many db '[* {:transaction/client [:client/name :db/id]
|
(->> (d/pull-many db '[* {:transaction/client [:client/name :db/id :client/code]
|
||||||
:transaction/bank-account [:bank-account/name :bank-account/yodlee-account-id]}]
|
:transaction/bank-account [:bank-account/name :bank-account/code :bank-account/yodlee-account-id :db/id]}]
|
||||||
ids)
|
ids)
|
||||||
(map #(update % :transaction/date c/from-date))
|
(map #(update % :transaction/date c/from-date))
|
||||||
(map #(update % :transaction/post-date c/from-date))
|
(map #(update % :transaction/post-date c/from-date))
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
:check_number {:type 'Int}
|
:check_number {:type 'Int}
|
||||||
:name {:type 'String}
|
:name {:type 'String}
|
||||||
:bank_code {:type 'String}
|
:bank_code {:type 'String}
|
||||||
|
:routing {:type 'String}
|
||||||
:bank_name {:type 'String}
|
:bank_name {:type 'String}
|
||||||
:yodlee_account_id {:type 'Int}}}
|
:yodlee_account_id {:type 'Int}}}
|
||||||
:address
|
:address
|
||||||
@@ -106,6 +107,7 @@
|
|||||||
|
|
||||||
:payment {:fields {:id {:type :id}
|
:payment {:fields {:id {:type :id}
|
||||||
:type {:type :payment_type}
|
:type {:type :payment_type}
|
||||||
|
:original_id {:type 'Int}
|
||||||
:amount {:type 'String}
|
:amount {:type 'String}
|
||||||
:vendor {:type :vendor}
|
:vendor {:type :vendor}
|
||||||
:client {:type :client}
|
:client {:type :client}
|
||||||
@@ -161,6 +163,7 @@
|
|||||||
|
|
||||||
:invoice
|
:invoice
|
||||||
{:fields {:id {:type :id}
|
{:fields {:id {:type :id}
|
||||||
|
:original_id {:type 'Int}
|
||||||
:total {:type 'String}
|
:total {:type 'String}
|
||||||
:outstanding_balance {:type 'String}
|
:outstanding_balance {:type 'String}
|
||||||
:invoice_number {:type 'String}
|
:invoice_number {:type 'String}
|
||||||
@@ -203,7 +206,7 @@
|
|||||||
|
|
||||||
:queries
|
:queries
|
||||||
{:invoice_page {:type '(list :invoice_page)
|
{:invoice_page {:type '(list :invoice_page)
|
||||||
:args {:imported {:type 'Boolean}
|
:args {:import_status {:type 'String}
|
||||||
:status {:type 'String}
|
:status {:type 'String}
|
||||||
:client_id {:type :id}
|
:client_id {:type :id}
|
||||||
:vendor_id {:type :id}
|
:vendor_id {:type :id}
|
||||||
@@ -335,12 +338,20 @@
|
|||||||
:bank_account_type {:values [{:enum-value :check}
|
:bank_account_type {:values [{:enum-value :check}
|
||||||
{:enum-value :cash}]}}
|
{:enum-value :cash}]}}
|
||||||
:mutations
|
:mutations
|
||||||
{:print_checks {:type :check_result
|
{:reject_invoices {:type '(list :id)
|
||||||
:args {:invoice_payments {:type '(list :invoice_payment_amount)}
|
:args {:invoices {:type '(list :id)}}
|
||||||
:bank_account_id {:type :id}
|
:resolve :mutation/reject-invoices}
|
||||||
:type {:type :payment_type}
|
|
||||||
:client_id {:type :id}}
|
:approve_invoices {:type '(list :id)
|
||||||
:resolve :mutation/print-checks}
|
:args {:invoices {:type '(list :id)}}
|
||||||
|
:resolve :mutation/approve-invoices}
|
||||||
|
|
||||||
|
:print_checks {:type :check_result
|
||||||
|
:args {:invoice_payments {:type '(list :invoice_payment_amount)}
|
||||||
|
:bank_account_id {:type :id}
|
||||||
|
:type {:type :payment_type}
|
||||||
|
:client_id {:type :id}}
|
||||||
|
:resolve :mutation/print-checks}
|
||||||
|
|
||||||
:add_handwritten_check {:type :check_result
|
:add_handwritten_check {:type :check_result
|
||||||
:args {:invoice_id {:type :id}
|
:args {:invoice_id {:type :id}
|
||||||
@@ -424,7 +435,7 @@
|
|||||||
(map
|
(map
|
||||||
->graphql
|
->graphql
|
||||||
(d-checks/get-graphql (assoc (<-graphql args)
|
(d-checks/get-graphql (assoc (<-graphql args)
|
||||||
:limit Integer/MAX_VALUE))))
|
:count Integer/MAX_VALUE))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -465,6 +476,8 @@
|
|||||||
:get-user get-user
|
:get-user get-user
|
||||||
:mutation/add-handwritten-check gq-checks/add-handwritten-check
|
:mutation/add-handwritten-check gq-checks/add-handwritten-check
|
||||||
:mutation/print-checks print-checks
|
:mutation/print-checks print-checks
|
||||||
|
:mutation/reject-invoices gq-invoices/reject-invoices
|
||||||
|
:mutation/approve-invoices gq-invoices/approve-invoices
|
||||||
:mutation/edit-user gq-users/edit-user
|
:mutation/edit-user gq-users/edit-user
|
||||||
:mutation/add-invoice gq-invoices/add-invoice
|
:mutation/add-invoice gq-invoices/add-invoice
|
||||||
:mutation/edit-invoice gq-invoices/edit-invoice
|
:mutation/edit-invoice gq-invoices/edit-invoice
|
||||||
|
|||||||
@@ -95,7 +95,7 @@
|
|||||||
[[:cell {:size 9 :leading 11.5} "\n\n\n\n\nMEMO"]
|
[[:cell {:size 9 :leading 11.5} "\n\n\n\n\nMEMO"]
|
||||||
[:cell {:colspan 5 :leading 11.5} (split-memo memo)
|
[:cell {:colspan 5 :leading 11.5} (split-memo memo)
|
||||||
[:line {:line-width 0.15 :color [50 50 50]}]]
|
[:line {:line-width 0.15 :color [50 50 50]}]]
|
||||||
[:cell {:colspan 6 } (if (:signature-file client)
|
[:cell {:colspan 6 } (if (:client/signature-file client)
|
||||||
[:image { :top-margin 90 :xscale 0.30 :yscale 0.30 :align :center}
|
[:image { :top-margin 90 :xscale 0.30 :yscale 0.30 :align :center}
|
||||||
|
|
||||||
(:client/signature-file client)]
|
(:client/signature-file client)]
|
||||||
|
|||||||
@@ -27,7 +27,20 @@
|
|||||||
(map
|
(map
|
||||||
->graphql
|
->graphql
|
||||||
(d-invoices/get-graphql (assoc (<-graphql args)
|
(d-invoices/get-graphql (assoc (<-graphql args)
|
||||||
:limit Integer/MAX_VALUE))))
|
:count Integer/MAX_VALUE))))
|
||||||
|
|
||||||
|
(defn reject-invoices [context {:keys [invoices] :as in} value]
|
||||||
|
(assert-admin (:id context))
|
||||||
|
|
||||||
|
(let [transactions (map (fn [i] [:db/retractEntity i ]) invoices)
|
||||||
|
transaction-result @(d/transact (d/connect uri) transactions)]
|
||||||
|
invoices))
|
||||||
|
|
||||||
|
(defn approve-invoices [context {:keys [invoices] :as in} value]
|
||||||
|
(assert-admin (:id context))
|
||||||
|
(let [transactions (map (fn [i] {:db/id i :invoice/import-status :import-status/imported}) invoices)
|
||||||
|
transaction-result @(d/transact (d/connect uri) transactions)]
|
||||||
|
invoices))
|
||||||
|
|
||||||
(defn add-invoice [context {{:keys [total invoice_number location client_id vendor_id vendor_name date] :as in} :invoice} value]
|
(defn add-invoice [context {{:keys [total invoice_number location client_id vendor_id vendor_name date] :as in} :invoice} value]
|
||||||
(when (seq (d-invoices/find-conflicting {:invoice/invoice-number invoice_number
|
(when (seq (d-invoices/find-conflicting {:invoice/invoice-number invoice_number
|
||||||
@@ -44,6 +57,7 @@
|
|||||||
:invoice/invoice-number invoice_number
|
:invoice/invoice-number invoice_number
|
||||||
:invoice/client client_id
|
:invoice/client client_id
|
||||||
:invoice/vendor vendor_id
|
:invoice/vendor vendor_id
|
||||||
|
:invoice/import-status :import-status/imported
|
||||||
:invoice/total total
|
:invoice/total total
|
||||||
:invoice/outstanding-balance total
|
:invoice/outstanding-balance total
|
||||||
:invoice/status :invoice-status/unpaid
|
:invoice/status :invoice-status/unpaid
|
||||||
@@ -82,12 +96,15 @@
|
|||||||
|
|
||||||
(defn void-invoice [context {id :invoice_id} value]
|
(defn void-invoice [context {id :invoice_id} value]
|
||||||
(let [invoice (d-invoices/get-by-id id)
|
(let [invoice (d-invoices/get-by-id id)
|
||||||
|
_ (println invoice)
|
||||||
_ (assert-can-see-client (:id context) (:db/id (:invoice/client invoice)))
|
_ (assert-can-see-client (:id context) (:db/id (:invoice/client invoice)))
|
||||||
updated-invoice (d-invoices/update {:db/id id
|
updated-invoice (d-invoices/update {:db/id id
|
||||||
:invoice/total 0.0
|
:invoice/total 0.0
|
||||||
:invoice/outstanding-balance 0.0
|
:invoice/outstanding-balance 0.0
|
||||||
:invoice/status :invoice-status/voided})]
|
:invoice/status :invoice-status/voided
|
||||||
;; TODO void out all expense accounts
|
:invoice/expense-accounts (map (fn [ea] {:db/id (:db/id ea)
|
||||||
|
:invoice-expense-account/amount 0.0})
|
||||||
|
(:invoice/expense-accounts invoice))})]
|
||||||
|
|
||||||
(-> updated-invoice
|
(-> updated-invoice
|
||||||
(->graphql))))
|
(->graphql))))
|
||||||
|
|||||||
@@ -11,6 +11,12 @@
|
|||||||
(defmulti parse-value (fn [method _ _]
|
(defmulti parse-value (fn [method _ _]
|
||||||
method))
|
method))
|
||||||
|
|
||||||
|
|
||||||
|
(defmethod parse-value :trim-commas
|
||||||
|
[_ _ value]
|
||||||
|
(str/replace value #"," "")
|
||||||
|
)
|
||||||
|
|
||||||
(defmethod parse-value :clj-time
|
(defmethod parse-value :clj-time
|
||||||
[_ format value]
|
[_ format value]
|
||||||
(time/from-time-zone (f/parse (f/formatter format) value)
|
(time/from-time-zone (f/parse (f/formatter format) value)
|
||||||
@@ -30,17 +36,20 @@
|
|||||||
#(extract-template % (dissoc template :multi))
|
#(extract-template % (dissoc template :multi))
|
||||||
(str/split text (:multi template)))
|
(str/split text (:multi template)))
|
||||||
|
|
||||||
[(->> template
|
(when template
|
||||||
:extract
|
[(->> template
|
||||||
(reduce-kv
|
:extract
|
||||||
(fn [result k v]
|
(reduce-kv
|
||||||
(let [value (some-> (first (map second (re-seq v text)))
|
(fn [result k v]
|
||||||
str/trim )
|
(let [value (some-> (first (map second (re-seq v text)))
|
||||||
[value-parser parser-params] (-> template :parser k)]
|
str/trim )
|
||||||
(assoc result k (parse-value value-parser parser-params value))))
|
[value-parser parser-params] (-> template :parser k)]
|
||||||
{:vendor-code (:vendor template)}))]))
|
(assoc result k (parse-value value-parser parser-params value))))
|
||||||
|
{:vendor-code (:vendor template)
|
||||||
|
:text text}))])))
|
||||||
|
|
||||||
(defn parse [text]
|
(defn parse [text]
|
||||||
|
(println text)
|
||||||
(->> t/pdf-templates
|
(->> t/pdf-templates
|
||||||
(filter (partial template-applies? text))
|
(filter (partial template-applies? text))
|
||||||
first
|
first
|
||||||
@@ -67,13 +76,24 @@
|
|||||||
[file filename]
|
[file filename]
|
||||||
(excel/parse-file file filename))
|
(excel/parse-file file filename))
|
||||||
|
|
||||||
(defn best-match [clients client-identifier]
|
(defn best-match [clients invoice-client-name]
|
||||||
(->> clients
|
(->> clients
|
||||||
(map (fn [client]
|
|
||||||
(if-let [matches (:client/matches client)]
|
(mapcat (fn [{:keys [:db/id :client/matches :client/name] :as client :or {matches []}}]
|
||||||
[client (apply min (map #(m/jaccard (.toLowerCase client-identifier) %) matches))]
|
(map (fn [m]
|
||||||
[client 1])))
|
[client (m/jaccard (.toLowerCase invoice-client-name) (.toLowerCase m))])
|
||||||
|
(conj matches name))))
|
||||||
(filter #(< (second %) 0.25))
|
(filter #(< (second %) 0.25))
|
||||||
(sort-by second)
|
(sort-by second)
|
||||||
|
|
||||||
ffirst))
|
ffirst))
|
||||||
|
|
||||||
|
(defn best-location-match [client text]
|
||||||
|
(or (->> client
|
||||||
|
:client/location-matches
|
||||||
|
(mapcat (fn [{:keys [:location-match/location :location-match/matches]}]
|
||||||
|
(map (fn [match] [location match]) matches)))
|
||||||
|
(filter (fn [[location match]] (re-find (re-pattern (str "(?i)" match)) text)) )
|
||||||
|
first
|
||||||
|
first)
|
||||||
|
(:client/default-location client)
|
||||||
|
(first (:client/locations client))))
|
||||||
|
|||||||
@@ -10,13 +10,14 @@
|
|||||||
:invoice-number #"\s+[0-9]+/[0-9]+/[0-9]+\s+([0-9]+)"}
|
:invoice-number #"\s+[0-9]+/[0-9]+/[0-9]+\s+([0-9]+)"}
|
||||||
:parser {:date [:clj-time "MM/dd/yyyy"]}}
|
:parser {:date [:clj-time "MM/dd/yyyy"]}}
|
||||||
|
|
||||||
{:vendor "GGM"
|
{:vendor "Golden Gate Meat Company, Inc"
|
||||||
:keywords [#"Golden Gate Meat"]
|
:keywords [#"Golden Gate Meat"]
|
||||||
:extract {:total #"Invoice Total\:\s+\$([\d.,]+)"
|
:extract {:total #"Invoice Total\:\s+\$([\d.,]+)"
|
||||||
:customer-identifier #"Bill To\s*:\s*([\w ]+)\s{2,}"
|
:customer-identifier #"Bill To\s*:\s*([\w ]+)\s{2,}"
|
||||||
:date #"Printed:\s+([0-9]+/[0-9]+/[0-9]+)"
|
:date #"Printed:\s+([0-9]+/[0-9]+/[0-9]+)"
|
||||||
:invoice-number #"Invoice\s+[^\n]+\n[^\n]+\n\s+([0-9]+)"}
|
:invoice-number #"Invoice\s+[^\n]+\n[^\n]+\n\s+([0-9]+)"}
|
||||||
:parser {:date [:clj-time "MM/dd/yyyy"]}}
|
:parser {:date [:clj-time "MM/dd/yyyy"]
|
||||||
|
:total [:trim-commas nil]}}
|
||||||
|
|
||||||
{:vendor "CINTAS"
|
{:vendor "CINTAS"
|
||||||
:keywords [#"CINTAS CORPORATION"]
|
:keywords [#"CINTAS CORPORATION"]
|
||||||
@@ -25,7 +26,15 @@
|
|||||||
:date #"INVOICE DATE\s*\n.*\s+([0-9]+/[0-9]+/[0-9]+)"
|
:date #"INVOICE DATE\s*\n.*\s+([0-9]+/[0-9]+/[0-9]+)"
|
||||||
:total #"INVOICE TOTAL\s+([0-9.]+)"}
|
:total #"INVOICE TOTAL\s+([0-9.]+)"}
|
||||||
:parser {:date [:clj-time "MM/dd/yy"]}
|
:parser {:date [:clj-time "MM/dd/yy"]}
|
||||||
:multi #"\f\f"}])
|
:multi #"\f\f"}
|
||||||
|
|
||||||
|
{:vendor "Carbonic Service Inc"
|
||||||
|
:keywords [#"CARBONIC SERVICE INC"]
|
||||||
|
:extract {:invoice-number #"Invoice #\s*\n\s*[\w\.]+\s+[\w\./]+(.*)\s*\n"
|
||||||
|
:customer-identifier #"Bill To[^\n]+\n[^\n]*\n([\w ]+)\s{2,}"
|
||||||
|
:date #"Invoice #\s*\n\s*[\w\.]+\s+([\w\./]+)"
|
||||||
|
:total #"Total\s+\$([0-9.]+)"}
|
||||||
|
:parser {:date [:clj-time "MM/dd/yy"]}}])
|
||||||
|
|
||||||
(def excel-templates
|
(def excel-templates
|
||||||
[{:vendor "Isp Productions"
|
[{:vendor "Isp Productions"
|
||||||
|
|||||||
@@ -9,6 +9,14 @@
|
|||||||
(def google-client-id "264081895820-0nndcfo3pbtqf30sro82vgq5r27h8736.apps.googleusercontent.com")
|
(def google-client-id "264081895820-0nndcfo3pbtqf30sro82vgq5r27h8736.apps.googleusercontent.com")
|
||||||
(def google-client-secret "OC-WemHurPXYpuIw5cT-B90g")
|
(def google-client-secret "OC-WemHurPXYpuIw5cT-B90g")
|
||||||
|
|
||||||
|
(defn make-api-token []
|
||||||
|
(jwt/sign {:user "API"
|
||||||
|
:exp (time/plus (time/now) (time/days 700))
|
||||||
|
:user/role "admin"
|
||||||
|
:user/name "API"}
|
||||||
|
(:jwt-secret env)
|
||||||
|
{:alg :hs512}))
|
||||||
|
|
||||||
(defroutes routes
|
(defroutes routes
|
||||||
(GET "/oauth" {{:strs [code]} :query-params :keys [scheme] :as r {:strs [host]} :headers}
|
(GET "/oauth" {{:strs [code]} :query-params :keys [scheme] :as r {:strs [host]} :headers}
|
||||||
(try
|
(try
|
||||||
@@ -37,14 +45,14 @@
|
|||||||
;; TODO - these namespaces are not being transmitted/deserialized properly
|
;; TODO - these namespaces are not being transmitted/deserialized properly
|
||||||
(if (and token user)
|
(if (and token user)
|
||||||
{:status 301
|
{:status 301
|
||||||
:headers {"Location" (str "/?jwt=" (jwt/sign {:user (:name profile)
|
:headers {"Location" (str "/?jwt=" (jwt/sign (doto {:user (:name profile)
|
||||||
:exp (time/plus (time/now) (time/days 7))
|
:exp (time/plus (time/now) (time/days 7))
|
||||||
:user/clients (map (fn [c]
|
:user/clients (map (fn [c]
|
||||||
(dissoc c :client/bank-accounts )
|
(dissoc c :client/bank-accounts ))
|
||||||
)
|
(:user/clients user))
|
||||||
(:user/clients user))
|
:user/role (name (:user/role user))
|
||||||
:user/role (name (:user/role user))
|
:user/name (:name profile)}
|
||||||
:user/name (:name profile)}
|
println)
|
||||||
(:jwt-secret env)
|
(:jwt-secret env)
|
||||||
{:alg :hs512}))}}
|
{:alg :hs512}))}}
|
||||||
{:status 401
|
{:status 401
|
||||||
|
|||||||
@@ -23,12 +23,12 @@
|
|||||||
(let [query [[:all_invoices
|
(let [query [[:all_invoices
|
||||||
{:client-code (query-params "client-code")
|
{:client-code (query-params "client-code")
|
||||||
:original-id (query-params "original")}
|
:original-id (query-params "original")}
|
||||||
[:id :total :outstanding-balance :invoice-number :date :status
|
[:id :total :outstanding-balance :invoice-number :date :status :original-id
|
||||||
[:payments [:amount [:payment [:check-number :memo [:bank_account [:id :name :number :bank-name :bank-code]]]]]]
|
[:payments [:amount [:payment [:check-number :memo [:bank_account [:id :name :number :bank-name :bank-code :code]]]]]]
|
||||||
[:vendor [:name :id [:primary_contact [:name]] [:address [:street1 :city :state :zip]]]]
|
[:vendor [:name :id [:primary_contact [:name]] [:address [:street1 :city :state :zip]]]]
|
||||||
[:expense_accounts [:amount :id :expense_account_id :location
|
[:expense_accounts [:amount :id :expense_account_id :location
|
||||||
[:expense_account [:id :name [:parent [:id :name]]]]]]
|
[:expense_account [:id :name [:parent [:id :name]]]]]]
|
||||||
[:client [:name :id :locations]]]]]
|
[:client [:name :id :code :locations]]]]]
|
||||||
invoices (graphql/query identity (venia/graphql-query {:venia/queries (->graphql query)}))]
|
invoices (graphql/query identity (venia/graphql-query {:venia/queries (->graphql query)}))]
|
||||||
|
|
||||||
(doto (list (:all-invoices (:data invoices))) clojure.pprint/pprint)))
|
(doto (list (:all-invoices (:data invoices))) clojure.pprint/pprint)))
|
||||||
@@ -37,11 +37,11 @@
|
|||||||
(let [query [[:all_payments
|
(let [query [[:all_payments
|
||||||
{:client-code (query-params "client-code")
|
{:client-code (query-params "client-code")
|
||||||
:original-id (query-params "original")}
|
:original-id (query-params "original")}
|
||||||
[:id :check-number :amount :memo :date :status :type
|
[:id :check-number :amount :memo :date :status :type :original-id
|
||||||
[:invoices [[:invoice [:id]] :amount]]
|
[:invoices [[:invoice [:id :original-id]] :amount]]
|
||||||
[:bank-account [:number :bank-name :bank-code :id]]
|
[:bank-account [:number :code :bank-name :bank-code :id]]
|
||||||
[:vendor [:name :id [:primary-contact [:name :email :phone]] :default-expense-account [:address [:street1 :city :state :zip]]]]
|
[:vendor [:name :id [:primary-contact [:name :email :phone]] :default-expense-account [:address [:street1 :city :state :zip]]]]
|
||||||
[:client [:id :name]]
|
[:client [:id :name :code]]
|
||||||
]]]
|
]]]
|
||||||
payments (graphql/query identity (venia/graphql-query {:venia/queries (->graphql query)}))]
|
payments (graphql/query identity (venia/graphql-query {:venia/queries (->graphql query)}))]
|
||||||
(list (:all-payments (:data payments)))))
|
(list (:all-payments (:data payments)))))
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
(assert-admin identity)
|
(assert-admin identity)
|
||||||
(let [[transactions] (d-transactions/get-graphql {:client-code (query-params "client-code")
|
(let [[transactions] (d-transactions/get-graphql {:client-code (query-params "client-code")
|
||||||
#_#_:original-id (Integer/parseInt (query-params "original"))
|
#_#_:original-id (Integer/parseInt (query-params "original"))
|
||||||
:limit Integer/MAX_VALUE})
|
:count Integer/MAX_VALUE})
|
||||||
]
|
]
|
||||||
(map (comp ->graphql (fn [i]
|
(map (comp ->graphql (fn [i]
|
||||||
(-> i
|
(-> i
|
||||||
|
|||||||
@@ -114,6 +114,7 @@
|
|||||||
:vendor vendor-id
|
:vendor vendor-id
|
||||||
:client client-id
|
:client client-id
|
||||||
:default-location default-location
|
:default-location default-location
|
||||||
|
:import-status :import-status/imported
|
||||||
:default-expense-account default-expense-account
|
:default-expense-account default-expense-account
|
||||||
:total total
|
:total total
|
||||||
:outstanding-balance (if (= "Cash" check)
|
:outstanding-balance (if (= "Cash" check)
|
||||||
@@ -140,7 +141,59 @@
|
|||||||
)]
|
)]
|
||||||
[invoice payment])))
|
[invoice payment])))
|
||||||
(filter identity)
|
(filter identity)
|
||||||
(map remove-nils)))
|
(map remove-nils)
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
(defn import-uploaded-invoice [imports]
|
||||||
|
(let [clients (d-clients/get-all)
|
||||||
|
_ (println imports)
|
||||||
|
|
||||||
|
transactions (reduce (fn [result {:keys [invoice-number customer-identifier total date vendor-code text] :as info}]
|
||||||
|
(let [[matching-vendor default-expense-account] (->> (d/query
|
||||||
|
(cond-> {:query {:find ['?vendor '?default-expense-account]
|
||||||
|
:in ['$ '?vendor-name]
|
||||||
|
:where ['[?vendor :vendor/name ?vendor-name]
|
||||||
|
'[?vendor :vendor/default-expense-account ?default-expense-account]]}
|
||||||
|
:args [(d/db (d/connect uri)) vendor-code]}))
|
||||||
|
first)
|
||||||
|
matching-client (parse/best-match clients customer-identifier)
|
||||||
|
_ (println "New invoice matches client" matching-client)
|
||||||
|
matching-location (parse/best-location-match matching-client text )
|
||||||
|
[existing-id existing-outstanding-balance existing-status import-status] (->> (d/query
|
||||||
|
(cond-> {:query {:find ['?e '?outstanding-balance '?status '?import-status2]
|
||||||
|
:in ['$ '?invoice-number '?vendor '?client]
|
||||||
|
:where '[[?e :invoice/invoice-number ?invoice-number]
|
||||||
|
[?e :invoice/vendor ?vendor]
|
||||||
|
[?e :invoice/client ?client]
|
||||||
|
[?e :invoice/outstanding-balance ?outstanding-balance]
|
||||||
|
[?e :invoice/status ?status]
|
||||||
|
[?e :invoice/import-status ?import-status]
|
||||||
|
[?import-status :db/ident ?import-status2]]}
|
||||||
|
:args [(d/db (d/connect uri)) invoice-number matching-vendor (:db/id matching-client)]}))
|
||||||
|
first)]
|
||||||
|
|
||||||
|
(if (= :import-status/imported import-status)
|
||||||
|
result
|
||||||
|
(conj result (remove-nils #:invoice {:invoice/client (:db/id matching-client)
|
||||||
|
:invoice/vendor matching-vendor
|
||||||
|
:invoice/invoice-number invoice-number
|
||||||
|
:invoice/total (Double/parseDouble total)
|
||||||
|
:invoice/date (to-date date)
|
||||||
|
:invoice/import-status :import-status/pending
|
||||||
|
:invoice/outstanding-balance (or existing-outstanding-balance (Double/parseDouble total))
|
||||||
|
:invoice/status (or existing-status :invoice-status/unpaid)
|
||||||
|
:invoice/expense-accounts (when-not existing-id [#:invoice-expense-account {:expense-account-id default-expense-account
|
||||||
|
:location matching-location
|
||||||
|
:amount (Double/parseDouble total)}])
|
||||||
|
:db/id existing-id
|
||||||
|
})))
|
||||||
|
))
|
||||||
|
[]
|
||||||
|
imports)]
|
||||||
|
|
||||||
|
@(d/transact (d/connect uri) transactions)
|
||||||
|
))
|
||||||
|
|
||||||
(defroutes routes
|
(defroutes routes
|
||||||
(wrap-routes
|
(wrap-routes
|
||||||
@@ -183,6 +236,13 @@
|
|||||||
:headers {"Content-Type" "application/edn"}})))
|
:headers {"Content-Type" "application/edn"}})))
|
||||||
|
|
||||||
(context "/invoices" []
|
(context "/invoices" []
|
||||||
|
(POST "/upload"
|
||||||
|
{{ files "file"} :params :as params}
|
||||||
|
(let [{:keys [filename tempfile]} files]
|
||||||
|
(import-uploaded-invoice (parse/parse-file (.getPath tempfile) filename))
|
||||||
|
{:status 200
|
||||||
|
:body (pr-str {})
|
||||||
|
:headers {"Content-Type" "application/edn"}}))
|
||||||
(POST "/upload-integreat"
|
(POST "/upload-integreat"
|
||||||
{{:keys [excel-rows]} :edn-params user :identity}
|
{{:keys [excel-rows]} :edn-params user :identity}
|
||||||
(assert-admin user)
|
(assert-admin user)
|
||||||
|
|||||||
@@ -68,23 +68,23 @@
|
|||||||
(try
|
(try
|
||||||
(when client-id
|
(when client-id
|
||||||
@(->> [(remove-nils #:transaction
|
@(->> [(remove-nils #:transaction
|
||||||
{:post-date (time/parse post-date "YYYY-MM-dd")
|
{:post-date (coerce/to-date (time/parse post-date "YYYY-MM-dd"))
|
||||||
:id (sha-256 (str id))
|
:id (sha-256 (str id))
|
||||||
:account-id account-id
|
:account-id account-id
|
||||||
:date (coerce/to-date (time/parse date "YYYY-MM-dd"))
|
:date (coerce/to-date (time/parse date "YYYY-MM-dd"))
|
||||||
:amount amount
|
:amount (double amount)
|
||||||
:description-original description-original
|
:description-original description-original
|
||||||
:description-simple description-simple
|
:description-simple description-simple
|
||||||
:type type
|
:type type
|
||||||
:status status
|
:status status
|
||||||
:client client-id
|
:client client-id
|
||||||
:check-number check-number
|
:check-number check-number
|
||||||
:bank-account (transaction->bank-account-id transaction)
|
:bank-account (transaction->bank-account-id transaction)
|
||||||
:payment (when check-id
|
:payment (when check-id
|
||||||
{:db/id check-id
|
{:db/id check-id
|
||||||
:payment/status :payment-status/cleared}
|
:payment/status :payment-status/cleared}
|
||||||
)
|
)
|
||||||
})]
|
})]
|
||||||
|
|
||||||
|
|
||||||
(d/transact (d/connect uri))))
|
(d/transact (d/connect uri))))
|
||||||
@@ -115,8 +115,8 @@
|
|||||||
|
|
||||||
(defn do-import []
|
(defn do-import []
|
||||||
(let [transactions (client/get-transactions)
|
(let [transactions (client/get-transactions)
|
||||||
_ (println "All accounts:" (client/get-accounts))
|
#_#__ (println "All accounts:" (client/get-accounts))
|
||||||
_ (println "ALL Transactions:" transactions)
|
#_#__ (println "ALL Transactions:" transactions)
|
||||||
all-bank-accounts (mapcat (fn [c] (map
|
all-bank-accounts (mapcat (fn [c] (map
|
||||||
(fn [{:keys [:db/id :bank-account/yodlee-account-id]}]
|
(fn [{:keys [:db/id :bank-account/yodlee-account-id]}]
|
||||||
(when (and id yodlee-account-id)
|
(when (and id yodlee-account-id)
|
||||||
|
|||||||
@@ -119,6 +119,19 @@
|
|||||||
node))
|
node))
|
||||||
m))
|
m))
|
||||||
|
|
||||||
|
(defonce timeouts
|
||||||
|
(atom {}))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:dispatch-debounce
|
||||||
|
(fn [{:keys [event time key]}]
|
||||||
|
(js/clearTimeout (@timeouts key))
|
||||||
|
(swap! timeouts assoc key
|
||||||
|
(js/setTimeout (fn []
|
||||||
|
(re-frame/dispatch event)
|
||||||
|
(swap! timeouts dissoc key))
|
||||||
|
time))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:graphql
|
:graphql
|
||||||
(fn [{:keys [query on-success on-error token variables query-obj]}]
|
(fn [{:keys [query on-success on-error token variables query-obj]}]
|
||||||
|
|||||||
@@ -133,10 +133,12 @@
|
|||||||
}
|
}
|
||||||
""]]]
|
""]]]
|
||||||
[:tbody
|
[:tbody
|
||||||
|
(println checked)
|
||||||
(if (:loading @status)
|
(if (:loading @status)
|
||||||
[:tr
|
[:tr
|
||||||
[:td {:col-span 5}
|
[:td {:col-span 5}
|
||||||
[:i.fa.fa-spin.fa-spinner]]]
|
[:i.fa.fa-spin.fa-spinner]]]
|
||||||
|
|
||||||
(for [{:keys [client payments expense-accounts invoice-number date total outstanding-balance id vendor] :as i} (:invoices @invoice-page)]
|
(for [{:keys [client payments expense-accounts invoice-number date total outstanding-balance id vendor] :as i} (:invoices @invoice-page)]
|
||||||
^{:key id}
|
^{:key id}
|
||||||
[:tr {:class (:class i)}
|
[:tr {:class (:class i)}
|
||||||
@@ -146,7 +148,8 @@
|
|||||||
"checked"
|
"checked"
|
||||||
"")
|
"")
|
||||||
:on-change (fn [x e] (when on-check-changed
|
:on-change (fn [x e] (when on-check-changed
|
||||||
(on-check-changed id)))} ]])
|
(println id i)
|
||||||
|
(on-check-changed id i)))} ]])
|
||||||
(when-not selected-client
|
(when-not selected-client
|
||||||
[:td (:name client)])
|
[:td (:name client)])
|
||||||
[:td (:name vendor)]
|
[:td (:name vendor)]
|
||||||
@@ -174,7 +177,7 @@
|
|||||||
[:div.dropdown-content
|
[:div.dropdown-content
|
||||||
(for [e expense-accounts]
|
(for [e expense-accounts]
|
||||||
^{:key (:id e)}
|
^{:key (:id e)}
|
||||||
[:span.dropdown-item (:name (:expense-account e)) " "(gstring/format "$%.2f" (:amount e) ) ])
|
[:span.dropdown-item (:name (:expense-account e)) " " (gstring/format "$%.2f" (:amount e) ) ])
|
||||||
|
|
||||||
[:hr.dropdown-divider]
|
[:hr.dropdown-divider]
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,22 @@
|
|||||||
[:li.menu-item
|
[:li.menu-item
|
||||||
[:a.item {:href (bidi/path-for routes/routes :unpaid-invoices)
|
[:a.item {:href (bidi/path-for routes/routes :unpaid-invoices)
|
||||||
:class [(active-when ap = :unpaid-invoices)]}
|
:class [(active-when ap = :unpaid-invoices)]}
|
||||||
[:span {:class "icon icon-accounting-document" :style {:font-size "25px"}}]
|
[:span {:class "icon icon-accounting-invoice-mail" :style {:font-size "25px"}}]
|
||||||
[:span {:class "name"} "Unpaid Invoices"]]]
|
[:span {:class "name"} "Unpaid Invoices"]]]
|
||||||
[:li.menu-item
|
[:li.menu-item
|
||||||
[:a.item {:href (bidi/path-for routes/routes :paid-invoices)
|
[:a.item {:href (bidi/path-for routes/routes :paid-invoices)
|
||||||
:class [(active-when ap = :paid-invoices)]}
|
:class [(active-when ap = :paid-invoices)]}
|
||||||
|
|
||||||
[:span {:class "icon icon-accounting-invoice-mail" :style {:font-size "25px"}}]
|
[:span {:class "icon icon-check-payment-give" :style {:font-size "25px"}}]
|
||||||
|
|
||||||
[:span {:class "name"} "Paid Invoices"]]]]]
|
[:span {:class "name"} "Paid Invoices"]]]
|
||||||
|
[:li.menu-item
|
||||||
|
[:a.item {:href (bidi/path-for routes/routes :import-invoices)
|
||||||
|
:class [(active-when ap = :import-invoices)]}
|
||||||
|
|
||||||
|
[:span {:class "icon icon-accounting-document" :style {:font-size "25px"}}]
|
||||||
|
|
||||||
|
[:span {:class "name"} "Import Invoices"]]]]]
|
||||||
[:div
|
[:div
|
||||||
rest]
|
rest]
|
||||||
[:div {:class "compose has-text-centered"}
|
[:div {:class "compose has-text-centered"}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
[auto-ap.views.utils :refer [active-when active-when= login-url dispatch-event]]
|
[auto-ap.views.utils :refer [active-when active-when= login-url dispatch-event]]
|
||||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||||
[auto-ap.views.pages.unpaid-invoices :refer [unpaid-invoices-page]]
|
[auto-ap.views.pages.unpaid-invoices :refer [unpaid-invoices-page]]
|
||||||
|
[auto-ap.views.pages.import-invoices :refer [import-invoices-page]]
|
||||||
[auto-ap.views.pages.paid-invoices :refer [paid-invoices-page]]
|
[auto-ap.views.pages.paid-invoices :refer [paid-invoices-page]]
|
||||||
[auto-ap.views.pages.transactions :refer [transactions-page]]
|
[auto-ap.views.pages.transactions :refer [transactions-page]]
|
||||||
[auto-ap.views.pages.login :refer [login-page]]
|
[auto-ap.views.pages.login :refer [login-page]]
|
||||||
@@ -25,6 +26,10 @@
|
|||||||
(defmethod page :unpaid-invoices [_]
|
(defmethod page :unpaid-invoices [_]
|
||||||
(unpaid-invoices-page {:status "unpaid"}))
|
(unpaid-invoices-page {:status "unpaid"}))
|
||||||
|
|
||||||
|
(defmethod page :import-invoices [_]
|
||||||
|
(import-invoices-page ))
|
||||||
|
|
||||||
|
|
||||||
(defmethod page :paid-invoices [_]
|
(defmethod page :paid-invoices [_]
|
||||||
(unpaid-invoices-page {:status "paid"}))
|
(unpaid-invoices-page {:status "paid"}))
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
[auto-ap.events :as events]
|
[auto-ap.events :as events]
|
||||||
[auto-ap.subs :as subs]
|
[auto-ap.subs :as subs]
|
||||||
[auto-ap.entities.clients :as client]
|
[auto-ap.entities.clients :as client]
|
||||||
|
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||||
|
[auto-ap.views.components.invoices.side-bar :refer [invoices-side-bar]]
|
||||||
|
[auto-ap.views.utils :refer [dispatch-event]]
|
||||||
[auto-ap.entities.vendors :as vendor]
|
[auto-ap.entities.vendors :as vendor]
|
||||||
[auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
|
[auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
|
||||||
[cljsjs.dropzone :as dropzone]
|
[cljsjs.dropzone :as dropzone]
|
||||||
@@ -56,7 +59,7 @@
|
|||||||
(assoc-in [:status :loading] true)
|
(assoc-in [:status :loading] true)
|
||||||
(assoc-in [::params] params))
|
(assoc-in [::params] params))
|
||||||
:graphql {:token (-> cofx :db :user)
|
:graphql {:token (-> cofx :db :user)
|
||||||
:query-obj (invoice-table/query (assoc params :imported false))
|
:query-obj (invoice-table/query (assoc params :import-status "pending"))
|
||||||
:on-success [::received]}}))
|
:on-success [::received]}}))
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
(re-frame/reg-event-db
|
||||||
@@ -67,15 +70,32 @@
|
|||||||
(assoc-in [:status :loading] false))))
|
(assoc-in [:status :loading] false))))
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::reject-invoices
|
::reject-invoices-clicked
|
||||||
(fn [cofx [_ on-success]]
|
(fn [{:keys [db]} [_ invoices on-success]]
|
||||||
{:http {:method :post
|
{:graphql
|
||||||
:token (-> cofx :db :user)
|
{:token (-> db :user)
|
||||||
:uri (str "/api/invoices/reject"
|
:query-obj {:venia/operation {:operation/type :mutation
|
||||||
(when-let [client-id (:id @(re-frame/subscribe [::subs/client]))]
|
:operation/name "RejectInvoices"}
|
||||||
(str "?client=" client-id)))
|
|
||||||
:on-success on-success
|
:venia/queries [[:reject-invoices
|
||||||
}}))
|
{:invoices (keys invoices)}
|
||||||
|
[]]]}
|
||||||
|
:on-success [::invalidated]}
|
||||||
|
}))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::approve-invoices-clicked
|
||||||
|
(fn [{:keys [db]} [_ invoices on-success]]
|
||||||
|
{:graphql
|
||||||
|
{:token (-> db :user)
|
||||||
|
:query-obj {:venia/operation {:operation/type :mutation
|
||||||
|
:operation/name "ApproveInvoices"}
|
||||||
|
|
||||||
|
:venia/queries [[:approve-invoices
|
||||||
|
{:invoices (keys invoices)}
|
||||||
|
[]]]}
|
||||||
|
:on-success [::invalidated]}
|
||||||
|
}))
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::approve-invoices
|
::approve-invoices
|
||||||
@@ -88,7 +108,46 @@
|
|||||||
:on-success on-success
|
:on-success on-success
|
||||||
}}))
|
}}))
|
||||||
|
|
||||||
(def import-invoices-page
|
(re-frame/reg-event-db
|
||||||
|
::toggle-check
|
||||||
|
(fn [db [_ id invoice]]
|
||||||
|
(-> db
|
||||||
|
(update-in [::invoice-page :checked] (fn [x]
|
||||||
|
(let [x (or x {})]
|
||||||
|
(if (x id)
|
||||||
|
(dissoc x id)
|
||||||
|
(assoc x id invoice))))))))
|
||||||
|
|
||||||
|
(defn approve-reject-button [checked]
|
||||||
|
[:div.is-pulled-right
|
||||||
|
|
||||||
|
[:button.button.is-success {:on-click (dispatch-event [::approve-invoices-clicked checked])
|
||||||
|
:disabled (if (seq checked)
|
||||||
|
""
|
||||||
|
"disabled")}
|
||||||
|
"Approve "
|
||||||
|
(when (> (count checked ))
|
||||||
|
(str
|
||||||
|
(count checked)
|
||||||
|
" invoices"))
|
||||||
|
|
||||||
|
|
||||||
|
[:span " "]]
|
||||||
|
[:button.button.is-danger {:on-click (dispatch-event [::reject-invoices-clicked checked])
|
||||||
|
:disabled (if (seq checked)
|
||||||
|
""
|
||||||
|
"disabled")}
|
||||||
|
"Reject "
|
||||||
|
(when (> (count checked ))
|
||||||
|
(str
|
||||||
|
(count checked)
|
||||||
|
" invoices"))
|
||||||
|
|
||||||
|
|
||||||
|
[:span " "]
|
||||||
|
]])
|
||||||
|
|
||||||
|
(def import-invoices-content
|
||||||
(with-meta
|
(with-meta
|
||||||
(fn []
|
(fn []
|
||||||
(let [invoice-page (re-frame/subscribe [::invoice-page])
|
(let [invoice-page (re-frame/subscribe [::invoice-page])
|
||||||
@@ -102,30 +161,27 @@
|
|||||||
[:div {:class "card-header"}
|
[:div {:class "card-header"}
|
||||||
[:span {:class "card-header-title"} "Found Invoices"]]
|
[:span {:class "card-header-title"} "Found Invoices"]]
|
||||||
[:div {:class "card-content"}
|
[:div {:class "card-content"}
|
||||||
|
[approve-reject-button (:checked @invoice-page)]
|
||||||
(if (:loading @status)
|
(if (:loading @status)
|
||||||
[:h1.title
|
[:h1.title
|
||||||
[:i.fa.fa-spin.fa-spinner]]
|
[:i.fa.fa-spin.fa-spinner]]
|
||||||
(if (seq (:invoices @invoice-page))
|
(if (seq (:invoices @invoice-page))
|
||||||
[invoice-table {:id :approved
|
[invoice-table {:id :approved
|
||||||
:invoice-page invoice-page
|
:invoice-page invoice-page
|
||||||
|
:check-boxes true
|
||||||
|
:checked (:checked @invoice-page)
|
||||||
|
:on-check-changed (fn [which invoice]
|
||||||
|
(re-frame/dispatch [::toggle-check which invoice]))
|
||||||
:status (re-frame/subscribe [::subs/status])
|
:status (re-frame/subscribe [::subs/status])
|
||||||
:params (re-frame/subscribe [::params])
|
:params (re-frame/subscribe [::params])
|
||||||
:on-params-change (fn [params]
|
:on-params-change (fn [params]
|
||||||
(re-frame/dispatch [::params-change params])) }]
|
(re-frame/dispatch [::params-change params])) }]
|
||||||
[:span "No pending invoices"]))]
|
[:span "No pending invoices"]))]]]))
|
||||||
(if (and (seq (:invoices @invoice-page)) (not (:loading @status)))
|
|
||||||
[:div.card-footer
|
|
||||||
[:a.card-footer-item
|
|
||||||
{:on-click (fn [e]
|
|
||||||
(.preventDefault e)
|
|
||||||
(re-frame/dispatch [::approve-invoices
|
|
||||||
[::invalidated]]))}
|
|
||||||
"Accept all"]
|
|
||||||
[:a.card-footer-item
|
|
||||||
{:on-click (fn [e]
|
|
||||||
(.preventDefault e)
|
|
||||||
(re-frame/dispatch [::reject-invoices
|
|
||||||
[::invalidated]]))}
|
|
||||||
"Reject all"]])]]))
|
|
||||||
{:component-will-mount (fn []
|
{:component-will-mount (fn []
|
||||||
(re-frame/dispatch-sync [::invalidated]))}))
|
(re-frame/dispatch-sync [::invalidated]))}))
|
||||||
|
|
||||||
|
(defn import-invoices-page []
|
||||||
|
[side-bar-layout {:side-bar [invoices-side-bar {}]
|
||||||
|
:main [import-invoices-content ]}])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
[auto-ap.views.components.invoices.side-bar :refer [invoices-side-bar]]
|
[auto-ap.views.components.invoices.side-bar :refer [invoices-side-bar]]
|
||||||
[auto-ap.expense-accounts :as expense-accounts]
|
[auto-ap.expense-accounts :as expense-accounts]
|
||||||
[auto-ap.entities.invoices-expense-accounts :as invoices-expense-accounts]
|
[auto-ap.entities.invoices-expense-accounts :as invoices-expense-accounts]
|
||||||
[auto-ap.views.utils :refer [active-when dispatch-event bind-field horizontal-field date->str str->date pretty standard]]
|
[auto-ap.views.utils :refer [active-when dispatch-event bind-field horizontal-field date->str date-time->str str->date pretty standard]]
|
||||||
[auto-ap.utils :refer [by replace-if]]
|
[auto-ap.utils :refer [by replace-if]]
|
||||||
[auto-ap.views.pages.check :as check]
|
[auto-ap.views.pages.check :as check]
|
||||||
[auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
|
[auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
|
||||||
@@ -72,6 +72,7 @@
|
|||||||
(fn [db]
|
(fn [db]
|
||||||
(-> db (::params {}))))
|
(-> db (::params {}))))
|
||||||
|
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::params-change
|
::params-change
|
||||||
(fn [cofx [_ params]]
|
(fn [cofx [_ params]]
|
||||||
@@ -79,24 +80,30 @@
|
|||||||
(assoc-in [:status :loading] true)
|
(assoc-in [:status :loading] true)
|
||||||
(assoc-in [::params] params))
|
(assoc-in [::params] params))
|
||||||
:graphql {:token (-> cofx :db :user)
|
:graphql {:token (-> cofx :db :user)
|
||||||
:query-obj (invoice-table/query (doto (assoc params :imported true) println))
|
:query-obj (invoice-table/query (-> params (assoc :import-status "imported") (dissoc :invoice-number-like-current)) )
|
||||||
:on-success [::received]}}))
|
:on-success [::received]}}))
|
||||||
|
(re-frame/reg-event-db
|
||||||
|
::unmount-invoices
|
||||||
|
(fn [db [_ data]]
|
||||||
|
(-> db
|
||||||
|
(dissoc ::invoice-page ))))
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
(re-frame/reg-event-db
|
||||||
::received
|
::received
|
||||||
(fn [db [_ data]]
|
(fn [db [_ data]]
|
||||||
(-> db
|
(-> db
|
||||||
(assoc ::invoice-page (first (:invoice-page data)))
|
(update ::invoice-page merge (first (:invoice-page data)))
|
||||||
(assoc-in [:status :loading] false))))
|
(assoc-in [:status :loading] false))))
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
(re-frame/reg-event-db
|
||||||
::toggle-check
|
::toggle-check
|
||||||
(fn [db [_ data]]
|
(fn [db [_ id invoice]]
|
||||||
(update-in db [::invoice-page :checked] (fn [x]
|
(-> db
|
||||||
(let [x (or x #{})]
|
(update-in [::invoice-page :checked] (fn [x]
|
||||||
(if (x data)
|
(let [x (or x {})]
|
||||||
(disj x data)
|
(if (x id)
|
||||||
(conj x data)))))))
|
(dissoc x id)
|
||||||
|
(assoc x id invoice))))))))
|
||||||
|
|
||||||
(re-frame/reg-event-db
|
(re-frame/reg-event-db
|
||||||
::print-checks-clicked
|
::print-checks-clicked
|
||||||
@@ -111,8 +118,8 @@
|
|||||||
(update-in [::invoice-page :print-checks-shown?] #(not %) )
|
(update-in [::invoice-page :print-checks-shown?] #(not %) )
|
||||||
(assoc-in [::advanced-print-checks] {:shown? true
|
(assoc-in [::advanced-print-checks] {:shown? true
|
||||||
:bank-account-id (:id (first (:bank-accounts @(re-frame/subscribe [::subs/clients]))))
|
:bank-account-id (:id (first (:bank-accounts @(re-frame/subscribe [::subs/clients]))))
|
||||||
:invoices (->> invoices
|
:invoices (->> checked
|
||||||
(filter (comp checked :id))
|
vals
|
||||||
(map #(assoc % :amount (:outstanding-balance %))))} )))))
|
(map #(assoc % :amount (:outstanding-balance %))))} )))))
|
||||||
|
|
||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
@@ -171,22 +178,20 @@
|
|||||||
(re-frame/reg-event-fx
|
(re-frame/reg-event-fx
|
||||||
::print-checks
|
::print-checks
|
||||||
(fn [{:keys [db]} [_ bank-account-id type]]
|
(fn [{:keys [db]} [_ bank-account-id type]]
|
||||||
(let [invoice-amounts (by :id :outstanding-balance (get-in db [::invoice-page :invoices]))]
|
{:db (-> db
|
||||||
|
(assoc-in [::invoice-page :print-checks-shown?] false )
|
||||||
|
(assoc-in [::invoice-page :print-checks-loading?] true ))
|
||||||
|
:graphql
|
||||||
|
{:token (-> db :user)
|
||||||
|
|
||||||
{:db (-> db
|
:query-obj (print-checks-query (map (fn [[id invoice]]
|
||||||
(assoc-in [::invoice-page :print-checks-shown?] false )
|
{:invoice-id id
|
||||||
(assoc-in [::invoice-page :print-checks-loading?] true ))
|
:amount (:outstanding-balance invoice)})
|
||||||
:graphql
|
(get-in db [::invoice-page :checked]))
|
||||||
{:token (-> db :user)
|
bank-account-id
|
||||||
|
type
|
||||||
:query-obj (print-checks-query (map (fn [id]
|
(:client db))
|
||||||
{:invoice-id id
|
:on-success [::checks-created]}}))
|
||||||
:amount (invoice-amounts id)})
|
|
||||||
(get-in db [::invoice-page :checked]))
|
|
||||||
bank-account-id
|
|
||||||
type
|
|
||||||
(:client db))
|
|
||||||
:on-success [::checks-created]}})))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -675,57 +680,96 @@
|
|||||||
(if (and (= key :vendor-id)
|
(if (and (= key :vendor-id)
|
||||||
(not= value (get-in db [::params :vendor-id])))
|
(not= value (get-in db [::params :vendor-id])))
|
||||||
(do
|
(do
|
||||||
(re-frame/dispatch [::params-change (assoc (::params updated) :vendor-id value)])
|
(re-frame/dispatch [::params-change (assoc (::params updated) :vendor-id value :start 0)])
|
||||||
(assoc-in updated [::params :vendor-id] value))
|
(assoc-in updated [::params :vendor-id] value))
|
||||||
updated))))
|
updated))))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::invoice-number-like-current-changed
|
||||||
|
(fn [{:keys [db]} [_ params invoice-like]]
|
||||||
|
{:db (assoc-in db [::params :invoice-number-like-current] invoice-like )
|
||||||
|
:dispatch-debounce {:event [::invoice-number-like-settled invoice-like]
|
||||||
|
:time 500
|
||||||
|
:key ::invoice-nuber-like}}))
|
||||||
|
|
||||||
|
(re-frame/reg-event-fx
|
||||||
|
::invoice-number-like-settled
|
||||||
|
(fn [{:keys [db]} [_ invoice-like]]
|
||||||
|
{:dispatch [::params-change (assoc (::params db) :invoice-number-like invoice-like :start 0) ]}))
|
||||||
|
|
||||||
(defn invoice-number-filter []
|
(defn invoice-number-filter []
|
||||||
(let [{:keys [invoice-number-like] :as params} @(re-frame/subscribe [::params])]
|
(let [{:keys [invoice-number-like-current] :as params} @(re-frame/subscribe [::params])]
|
||||||
[:div.field
|
[:div.field
|
||||||
[:div.control [:input.input {:placeholder "AP-123"
|
[:div.control [:input.input {:placeholder "AP-123"
|
||||||
:value invoice-number-like
|
:value invoice-number-like-current
|
||||||
:on-change (fn [x]
|
:on-change (fn [x]
|
||||||
(re-frame/dispatch [::params-change (assoc params :invoice-number-like (.. x -target -value)) ])
|
(re-frame/dispatch [::invoice-number-like-current-changed params (.. x -target -value) ]))} ]]]))
|
||||||
)} ]]]))
|
|
||||||
|
|
||||||
(defn pay-button [{:keys [print-checks-shown? checked-invoices print-checks-loading?]}]
|
(defn pay-button [{:keys [print-checks-shown? checked-invoices print-checks-loading?]}]
|
||||||
(let [current-client @(re-frame/subscribe [::subs/client])]
|
(let [current-client @(re-frame/subscribe [::subs/client])]
|
||||||
[:div.is-pulled-right
|
[:div
|
||||||
[:button.button.is-danger {:on-click (dispatch-event [::new-invoice])} "New Invoice"]
|
|
||||||
(when current-client
|
|
||||||
[:div.dropdown.is-right {:class (if print-checks-shown?
|
|
||||||
"is-active"
|
|
||||||
"")}
|
|
||||||
[:div.dropdown-trigger
|
|
||||||
[:button.button.is-success {:aria-haspopup true
|
|
||||||
:on-click (dispatch-event [::print-checks-clicked ])
|
|
||||||
:disabled (if (seq checked-invoices)
|
|
||||||
""
|
|
||||||
"disabled")
|
|
||||||
|
|
||||||
:class (if print-checks-loading?
|
|
||||||
"is-loading"
|
|
||||||
"")}
|
|
||||||
"Pay "
|
|
||||||
[:span " "]
|
|
||||||
[:span.icon.is-small [:i.fa.fa-angle-down {:aria-hidden "true"}]]]]
|
|
||||||
[:div.dropdown-menu {:role "menu"}
|
|
||||||
[:div.dropdown-content
|
|
||||||
(list
|
|
||||||
(for [{:keys [id number name type]} (:bank-accounts current-client)]
|
|
||||||
(if (= :cash type)
|
|
||||||
^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :cash])} "With cash"]
|
|
||||||
(list
|
|
||||||
^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :check])} "Print checks from " name]
|
|
||||||
^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :debit])} "Debit from " name])))
|
|
||||||
^{:key "advanced-divider"} [:hr.dropdown-divider]
|
|
||||||
|
|
||||||
(when (= 1 (count checked-invoices))
|
|
||||||
^{:key "handwritten"} [:a.dropdown-item {:on-click (dispatch-event [::handwrite-checks])} "Handwritten Check..."])
|
[:div.is-pulled-right
|
||||||
^{:key "advanced"} [:a.dropdown-item {:on-click (dispatch-event [::advanced-print-checks])} "Advanced..."])]]])]))
|
|
||||||
|
|
||||||
|
[:button.button.is-danger {:on-click (dispatch-event [::new-invoice])} "New Invoice"]
|
||||||
|
|
||||||
|
|
||||||
|
(when current-client
|
||||||
|
[:div.dropdown.is-right {:class (if print-checks-shown?
|
||||||
|
"is-active"
|
||||||
|
"")}
|
||||||
|
[:div.dropdown-trigger
|
||||||
|
[:button.button.is-success {:aria-haspopup true
|
||||||
|
:on-click (dispatch-event [::print-checks-clicked ])
|
||||||
|
:disabled (if (seq checked-invoices)
|
||||||
|
""
|
||||||
|
"disabled")
|
||||||
|
|
||||||
|
:class (if print-checks-loading?
|
||||||
|
"is-loading"
|
||||||
|
"")}
|
||||||
|
"Pay "
|
||||||
|
(when (> (count checked-invoices ))
|
||||||
|
(str
|
||||||
|
(count checked-invoices)
|
||||||
|
" invoices "
|
||||||
|
"(" (->> checked-invoices
|
||||||
|
vals
|
||||||
|
(map (comp js/parseFloat :outstanding-balance))
|
||||||
|
(reduce + 0)
|
||||||
|
(gstring/format "$%.2f" ))
|
||||||
|
")"))
|
||||||
|
|
||||||
|
|
||||||
|
[:span " "]
|
||||||
|
[:span.icon.is-small [:i.fa.fa-angle-down {:aria-hidden "true"}]]]]
|
||||||
|
[:div.dropdown-menu {:role "menu"}
|
||||||
|
[:div.dropdown-content
|
||||||
|
(list
|
||||||
|
(for [{:keys [id number name type]} (:bank-accounts current-client)]
|
||||||
|
(if (= :cash type)
|
||||||
|
^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :cash])} "With cash"]
|
||||||
|
(list
|
||||||
|
^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :check])} "Print checks from " name]
|
||||||
|
^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :debit])} "Debit from " name])))
|
||||||
|
^{:key "advanced-divider"} [:hr.dropdown-divider]
|
||||||
|
|
||||||
|
(when (= 1 (count checked-invoices))
|
||||||
|
^{:key "handwritten"} [:a.dropdown-item {:on-click (dispatch-event [::handwrite-checks])} "Handwritten Check..."])
|
||||||
|
^{:key "advanced"} [:a.dropdown-item {:on-click (dispatch-event [::advanced-print-checks])} "Advanced..."])]]])]
|
||||||
|
[:div.is-pulled-right
|
||||||
|
(into [:div.tags {:style {:margin-right ".5 rem;"}}] (map (fn [[id invoice]] [:span.tag.is-medium (:invoice-number invoice) [:button.delete.is-small {:on-click (dispatch-event [::toggle-check id invoice])}]]) checked-invoices))]]
|
||||||
|
))
|
||||||
|
|
||||||
(defn unpaid-invoices-content [{:keys [status]}]
|
(defn unpaid-invoices-content [{:keys [status]}]
|
||||||
(r/create-class {:display-name "unpaid-invoices-content"
|
(r/create-class {:display-name "unpaid-invoices-content"
|
||||||
|
:component-will-unmount (fn [this]
|
||||||
|
(re-frame/dispatch [::unmount-invoices])
|
||||||
|
|
||||||
|
)
|
||||||
:reagent-render (fn [{:keys [status]}]
|
:reagent-render (fn [{:keys [status]}]
|
||||||
(let [{:keys [checked print-checks-shown? print-checks-loading? advanced-print-shown? vendor-filter]} @(re-frame/subscribe [::invoice-page])
|
(let [{:keys [checked print-checks-shown? print-checks-loading? advanced-print-shown? vendor-filter]} @(re-frame/subscribe [::invoice-page])
|
||||||
current-client @(re-frame/subscribe [::subs/client])
|
current-client @(re-frame/subscribe [::subs/client])
|
||||||
@@ -736,6 +780,7 @@
|
|||||||
[pay-button {:print-checks-shown? print-checks-shown? :checked-invoices checked :print-checks-loading? print-checks-loading?}])
|
[pay-button {:print-checks-shown? print-checks-shown? :checked-invoices checked :print-checks-loading? print-checks-loading?}])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[invoice-table {:id :unpaid
|
[invoice-table {:id :unpaid
|
||||||
:params (re-frame/subscribe [::params])
|
:params (re-frame/subscribe [::params])
|
||||||
:invoice-page (re-frame/subscribe [::invoice-page])
|
:invoice-page (re-frame/subscribe [::invoice-page])
|
||||||
@@ -749,8 +794,8 @@
|
|||||||
(re-frame/dispatch [::params-change params]))
|
(re-frame/dispatch [::params-change params]))
|
||||||
:check-boxes (= status "unpaid")
|
:check-boxes (= status "unpaid")
|
||||||
:checked checked
|
:checked checked
|
||||||
:on-check-changed (fn [which]
|
:on-check-changed (fn [which invoice]
|
||||||
(re-frame/dispatch [::toggle-check which]))
|
(re-frame/dispatch [::toggle-check which invoice]))
|
||||||
:expense-event [::expense-accounts-dialog/change-expense-accounts]}]
|
:expense-event [::expense-accounts-dialog/change-expense-accounts]}]
|
||||||
|
|
||||||
[print-checks-modal]
|
[print-checks-modal]
|
||||||
|
|||||||
Reference in New Issue
Block a user