From e055a1e120d643abe1d81a2bc950d9f5ebb6e183 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Thu, 17 May 2018 19:37:50 -0700 Subject: [PATCH] outstanding balance and addresses. --- .dockerignore | 6 +- ...6400685-DOWN-store-outstanding-balance.sql | 2 + ...526400685-UP-store-outstanding-balance.sql | 3 + nm/auto_ap/numeric.clj | 14 +++ resources/public/index.html | 2 + src/clj/auto_ap/db/companies.clj | 9 +- src/clj/auto_ap/db/invoices.clj | 30 ++--- src/clj/auto_ap/graphql.clj | 1 + src/clj/auto_ap/routes/checks.clj | 28 ++--- src/clj/auto_ap/routes/invoices.clj | 1 + src/cljc/auto_ap/entities/address.cljc | 17 +++ src/cljc/auto_ap/entities/companies.cljc | 8 +- src/cljc/auto_ap/numeric.cljc | 104 ++++++++++++++++++ .../views/components/invoice_table.cljs | 27 +++-- src/cljs/auto_ap/views/pages.cljs | 3 +- .../auto_ap/views/pages/admin/companies.cljs | 56 ++++++++++ .../auto_ap/views/pages/paid_invoices.cljs | 85 +++++++++----- .../auto_ap/views/pages/unpaid_invoices.cljs | 28 +++-- src/cljs/auto_ap/views/utils.cljs | 25 +++-- 19 files changed, 351 insertions(+), 98 deletions(-) create mode 100644 migrator/migrations/1526400685-DOWN-store-outstanding-balance.sql create mode 100644 migrator/migrations/1526400685-UP-store-outstanding-balance.sql create mode 100644 nm/auto_ap/numeric.clj create mode 100644 src/cljc/auto_ap/entities/address.cljc create mode 100644 src/cljc/auto_ap/numeric.cljc diff --git a/.dockerignore b/.dockerignore index 1bc703e5..123eb4aa 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,4 @@ -examples/ -examples/** -target/** +**/* !target/auto-ap.jar +!config/** +!config diff --git a/migrator/migrations/1526400685-DOWN-store-outstanding-balance.sql b/migrator/migrations/1526400685-DOWN-store-outstanding-balance.sql new file mode 100644 index 00000000..5202df6f --- /dev/null +++ b/migrator/migrations/1526400685-DOWN-store-outstanding-balance.sql @@ -0,0 +1,2 @@ +-- 1526400685 DOWN store-outstanding-balance +ALTER TABLE invoices drop column outstanding_balance; diff --git a/migrator/migrations/1526400685-UP-store-outstanding-balance.sql b/migrator/migrations/1526400685-UP-store-outstanding-balance.sql new file mode 100644 index 00000000..f48fab6b --- /dev/null +++ b/migrator/migrations/1526400685-UP-store-outstanding-balance.sql @@ -0,0 +1,3 @@ +-- 1526400685 UP store-outstanding-balance +ALTER TABLE invoices add column outstanding_balance DECIMAL; +UPDATE invoices set outstanding_balance = total; diff --git a/nm/auto_ap/numeric.clj b/nm/auto_ap/numeric.clj new file mode 100644 index 00000000..a016db43 --- /dev/null +++ b/nm/auto_ap/numeric.clj @@ -0,0 +1,14 @@ +(ns auto-ap.numeric + (:require [clojure.test :refer :all])) + + +(deftest num->words-test + + (is (= "one dollars" (num->words 1.00))) + (is (= "two dollars" (num->words 2.00))) + (is (= "twelve dollars" (num->words 12.00))) + (is (= "twenty-one dollars" (num->words 21.00))) + (is (= "one hundred and twenty-one dollars" (num->words 121.00))) + (is (= "thirty-five thousand one hundred and twenty-one dollars" (num->words 35121.00))) + (is (= "twelve dollars and thirty-three cents" (num->words 12.33))) + (is (= "ninety-nine cents" (num->words 0.99)))) diff --git a/resources/public/index.html b/resources/public/index.html index 38ba7b3c..a7c57a9a 100644 --- a/resources/public/index.html +++ b/resources/public/index.html @@ -246,6 +246,8 @@ .card.active { background-color:#F5F5F5; } + .table { table-layout: fixed } + diff --git a/src/clj/auto_ap/db/companies.clj b/src/clj/auto_ap/db/companies.clj index fd843af6..c111427d 100644 --- a/src/clj/auto_ap/db/companies.clj +++ b/src/clj/auto_ap/db/companies.clj @@ -6,6 +6,8 @@ [honeysql.core :as sql] [honeysql.helpers :as helpers])) +(def all-fields #{:name :email :data :id}) + (def base-query (sql/build :select :* :from :companies)) @@ -17,7 +19,9 @@ (defn fields->data [x] (-> x (assoc-in [:data :bank-accounts] (:bank-accounts x)) - (dissoc :bank-accounts))) + (assoc-in [:data :address] (:address x)) + (dissoc :bank-accounts) + (dissoc :address))) (defn get-all [] (map data->fields (query base-query))) @@ -28,10 +32,9 @@ (helpers/merge-where [:= :id id])))))) (defn upsert [id data] - (prn (clj->db (select-keys data entity/all-keys))) (-> (sql/build :update :companies - :set (clj->db (select-keys (fields->data data) entity/all-keys )) + :set (clj->db (select-keys (fields->data data) all-fields)) :where [:= :id (if (int? id) id (Integer/parseInt id))]) diff --git a/src/clj/auto_ap/db/invoices.clj b/src/clj/auto_ap/db/invoices.clj index 3a943684..274525cd 100644 --- a/src/clj/auto_ap/db/invoices.clj +++ b/src/clj/auto_ap/db/invoices.clj @@ -11,7 +11,7 @@ [honeysql.core :as sql] [honeysql.helpers :as helpers])) -(def all-keys #{:company-id :vendor-id :imported :potential-duplicate :total :invoice-number :date}) +(def all-keys #{:company-id :vendor-id :imported :potential-duplicate :total :invoice-number :date :outstanding-balance}) (defn insert-multi! [rows] (j/insert-multi! (get-conn) @@ -20,7 +20,7 @@ (defn upsert-multi! [rows] - (let [k (vec (map #(keyword (kebab->snake (name %))) [:company-id :vendor-id :invoice-number :total :date :imported :status])) + (let [k (vec (map #(keyword (kebab->snake (name %))) [:company-id :vendor-id :invoice-number :total :date :imported :status :outstanding-balance])) column-names (str/join "," (map name k))] (reduce (fn [affected rows] @@ -31,7 +31,7 @@ (map clj->db ) (map (apply juxt k))))]] :insert-into [[:invoices k] - {:select [:v.company-id :v.vendor-id :v.invoice-number :v.total (sql/raw "cast(v.date as timestamp)") :v.imported :v.status] + {:select [:v.company-id :v.vendor-id :v.invoice-number :v.total (sql/raw "cast(v.date as timestamp)") :v.imported :v.status :v.outstanding-balance] :from [:v] :left-join [[:invoices :exist] [:and @@ -136,15 +136,15 @@ :potential-duplicate false) :vendor-code))))) -(defn mark-finished-if-complete [invoice-id] - (let [{:keys [total]} (get-by-id invoice-id) - _ (println "TOTAL total" total) - - paid (invoices-checks/get-sum-by-invoice invoice-id) - _ (println "PAID" paid)] - (when (< (Math/abs (float (- paid total))) 0.01) - (j/db-do-prepared (get-conn) - (-> (helpers/update :invoices) - (helpers/sset {:status "paid"}) - (helpers/where [:= :id invoice-id]) - (sql/format)))))) +(defn apply-payment [invoice-id amount] + (j/db-do-prepared (get-conn) + (-> (helpers/update :invoices) + (helpers/sset {:outstanding-balance (sql/call :- :outstanding-balance amount)}) + (helpers/where [:= :id invoice-id]) + (sql/format))) + (j/db-do-prepared (get-conn) + (-> (helpers/update :invoices) + (helpers/sset {:status "paid"}) + (helpers/where [:and [:< :outstanding-balance 0.01] + [:= :id invoice-id]]) + (sql/format)))) diff --git a/src/clj/auto_ap/graphql.clj b/src/clj/auto_ap/graphql.clj index 6af8d817..b045be49 100644 --- a/src/clj/auto_ap/graphql.clj +++ b/src/clj/auto_ap/graphql.clj @@ -66,6 +66,7 @@ :invoice {:fields {:id {:type 'Int} :total {:type 'String} + :outstanding_balance {:type 'String} :invoice_number {:type 'String} :date {:type 'String} :company_id {:type 'Int} diff --git a/src/clj/auto_ap/routes/checks.clj b/src/clj/auto_ap/routes/checks.clj index 74489f15..a8875053 100644 --- a/src/clj/auto_ap/routes/checks.clj +++ b/src/clj/auto_ap/routes/checks.clj @@ -3,6 +3,7 @@ [auto-ap.db.vendors :as vendors] [auto-ap.db.invoices :as invoices] [auto-ap.utils :refer [by]] + [auto-ap.numeric :refer [num->words]] [auto-ap.db.checks :as checks] [auto-ap.db.invoices-checks :as invoices-checks] [auto-ap.db.utils :refer [query]] @@ -26,12 +27,13 @@ [{:left-margin 10 :right-margin 0 :top-margin 0 :bottom-margin 0} (let [{:keys [paid-to company check date amount memo] {vendor-name :name :as vendor} :vendor} check df (DecimalFormat. "#,###.00") - _ (println amount (class amount)) + word-amount (num->words amount) + amount (str "--" (.format df amount) "--")] [:table {:num-cols 12 :border false :leading 11} - [(let [{:keys [name address1 city state zip bank]} company] - [:cell {:colspan 4 } [:paragraph {:leading 14} name "\n" address1 "\n" (str city ", " state zip)] ]) + [(let [{:keys [name bank] {:keys [street1 street2 city state zip ]} :address} company] + [:cell {:colspan 4 } [:paragraph {:leading 14} name "\n" street1 "\n" (str city ", " state " " zip)] ]) (let [{{:keys [name acct]} :bank} company] [:cell {:colspan 6 :align :center} [:paragraph {:style :bold} name] [:paragraph acct]]) [:cell {:colspan 2 :size 13} @@ -46,7 +48,7 @@ [:cell {:colspan 3} amount]] [[:cell {}] - [:cell {:colspan 8} "One thousand two hundred thirty four and fifty six cents" [:line]] + [:cell {:colspan 8} word-amount [:line]] [:cell {:colspan 3}]] [[:cell {:colspan 12} [:spacer]]] @@ -67,11 +69,12 @@ [[:cell] (into [:cell {:colspan 9}] - (let [{:keys [name address1 city state zip bank]} company] + (let [{:keys [name] + {:keys [street1 city state zip bank]} :address} company] (list [:paragraph name] - [:paragraph address1] - [:paragraph city ", " state zip] + [:paragraph street1] + [:paragraph city ", " state " " zip] ))) [:cell {:colspan 2 :size 13} check]] @@ -177,10 +180,7 @@ :memo memo :date "5/10/2018" :company {:name (:name company) - :address1 "123 main st" - :city "Campbell" - :state "CA" - :zip "95008" + :address (:address company) :bank {:name "Bank of America, NA" :acct "11-35/2010" :acct-number (:number bank-account)}}} @@ -216,9 +216,9 @@ (make-pdfs (map second checks)) (companies/upsert company-id updated-company) - (doseq [{:keys [invoice-id]} invoice-payments] - (invoices/mark-finished-if-complete invoice-id)) - {:invoices (mapcat first checks) + (doseq [{:keys [invoice-id amount]} invoice-payments] + (invoices/apply-payment invoice-id amount)) + {:invoices (invoices/get-multi (map :id (doto (mapcat first checks) println))) :pdf-url (merge-pdfs (map (comp :s3-key second) checks))})) diff --git a/src/clj/auto_ap/routes/invoices.clj b/src/clj/auto_ap/routes/invoices.clj index 9d1934bd..456e3cc1 100644 --- a/src/clj/auto_ap/routes/invoices.clj +++ b/src/clj/auto_ap/routes/invoices.clj @@ -134,6 +134,7 @@ {:vendor-id vendor-id :company-id company-id :total total + :outstanding-balance total :imported true :status "unpaid" :invoice-number invoice-number diff --git a/src/cljc/auto_ap/entities/address.cljc b/src/cljc/auto_ap/entities/address.cljc new file mode 100644 index 00000000..e75eb87b --- /dev/null +++ b/src/cljc/auto_ap/entities/address.cljc @@ -0,0 +1,17 @@ +(ns auto-ap.entities.address + (:require [clojure.spec.alpha :as s] + [clojure.string :as str])) + +(s/def ::street1 (s/nilable string?)) +(s/def ::street2 (s/nilable string?)) +(s/def ::city (s/nilable string?)) +(s/def ::state (s/nilable (s/and string? + #(re-matches #"[a-zA-Z]{2}" %)))) +(s/def ::zip (s/nilable string?)) + +(s/def ::address (s/keys :opt-un [::email + ::street1 + ::street2 + ::city + ::state + ::zip])) diff --git a/src/cljc/auto_ap/entities/companies.cljc b/src/cljc/auto_ap/entities/companies.cljc index a565fa4f..dc8196e1 100644 --- a/src/cljc/auto_ap/entities/companies.cljc +++ b/src/cljc/auto_ap/entities/companies.cljc @@ -1,6 +1,7 @@ (ns auto-ap.entities.companies (:require [clojure.spec.alpha :as s] - [clojure.string :as str])) + [clojure.string :as str] + [auto-ap.entities.address :as address])) (def email-regex #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$") (s/def ::id int) @@ -9,14 +10,15 @@ #(not (str/blank? %)))) (s/def ::name ::required-identifier) -(s/def ::data map?) +(s/def ::address ::address/address) (s/def ::email (s/nilable (s/and string? (s/or :is-email #(re-matches email-regex %) :is-empty #(= % ""))))) + (s/def ::company (s/keys :req-un [::name] :opt-un [::email - ::data + ::address ::id])) diff --git a/src/cljc/auto_ap/numeric.cljc b/src/cljc/auto_ap/numeric.cljc new file mode 100644 index 00000000..e122f3ba --- /dev/null +++ b/src/cljc/auto_ap/numeric.cljc @@ -0,0 +1,104 @@ +(ns auto-ap.numeric + (:require [clojure.string :as str])) + +(def ^:private smalls ["zero" + "one" + "two" + "three" + "four" + "five" + "six" + "seven" + "eight" + "nine" + "ten" + "eleven" + "twelve" + "thirteen" + "fourteen" + "fifteen" + "sixteen" + "seventeen" + "eighteen" + "nineteen"]) + +(def ^:private tens ["twenty" + "thirty" + "forty" + "fifty" + "sixty" + "seventy" + "eighty" + "ninety"]) + +(def ^:private magnitudes ["thousand" + "million" + "billion" + "trillion" + "quadrillion" + "quintillion" + "sextillion" + "septillion" + "octillion" + "nonillion" + "decillion" + "undecillion" + "duodecillion" + "tredecillion" + "quattuordecillion" + "quindecillion" + "quinquadecillion" + "sexdecillion" + "sedecillion" + "septendecillion" + "octodecillion" + "novemdecillion" + "novendecillion" + "vigintillion" + #_"centillion"]) + +(defn words + [n] + {:pre [(not (neg? n))]} + (cond + (< n 20) (smalls n) + (< n 100) (let [pre (tens (- (quot n 10) 2)), + x (rem n 10)] + (if (zero? x) pre (str pre "-" (words x)))) + (< n 1000) (let [hun (quot n 100), + x (rem n 100), + s (str (words hun) " hundred")] + (if (zero? x) s (str s " and " (words x)))) + :else (loop [parts [] n n mag -1] + (if (zero? n) + (str/join " " parts) + (let [x (rem n 1000) + n (quot n 1000) + parts (if (zero? x) + parts + (let [s (words x)] + (cons + (if (neg? mag) + (if (< x 100) + (str "and " s) + s) + (str s " " (magnitudes mag))) + parts)))] + (recur parts n (inc mag))))))) + + +(defn num->words [num] + (let [total-cents (int (* 100 num)) + dollar-num (int (quot total-cents 100)) + cent-num (int (rem total-cents 100)) + dollars (str (words dollar-num) " dollars") + cents (str (words cent-num) " cents")] + (cond + (and (> dollar-num 0) (> cent-num 0)) + (str dollars " and " cents) + + (> dollar-num 0) + dollars + + :else + cents))) diff --git a/src/cljs/auto_ap/views/components/invoice_table.cljs b/src/cljs/auto_ap/views/components/invoice_table.cljs index 2c3ed813..524f1d08 100644 --- a/src/cljs/auto_ap/views/components/invoice_table.cljs +++ b/src/cljs/auto_ap/views/components/invoice_table.cljs @@ -9,9 +9,7 @@ [cljs-time.format :as format] [goog.string :as gstring])) -;; TODO show busy ;; TODO partial payments -;; TODO invoice status = paid when complete ;; TODO performance ;; TODO refactor graphql @@ -21,7 +19,7 @@ {:venia/queries [[:invoice_page (assoc params :company-id (:id @(re-frame/subscribe [::subs/company]))) - [[:invoices [:id :total :invoice-number :date [:vendor [:name :id]] [:company [:name :id]] [:checks [:amount [:check [:amount :s3_url :check_number ]]]]]] + [[:invoices [:id :total :outstanding-balance :invoice-number :date [:vendor [:name :id]] [:company [:name :id]] [:checks [:amount [:check [:amount :s3_url :check_number ]]]]]] :total :start :end]]]}) @@ -46,44 +44,50 @@ [:thead [:tr (when check-boxes - [:th]) + [:th {:style {"width" "20px"}}]) [sorted-column {:on-sort opc - :style {:width "23%" :cursor "pointer"} + :style {:width "33%" :cursor "pointer"} :sort-key "vendor" :sort-by sort-by :asc asc} "Vendor"] [sorted-column {:on-sort opc - :style {:width "23%" :cursor "pointer"} + :style {:width "33%" :cursor "pointer"} :sort-key "company" :sort-by sort-by :asc asc} "Company"] [sorted-column {:on-sort opc - :style {:width "16%" :cursor "pointer"} + :style {:width "33%" :cursor "pointer"} :sort-key "invoice-number" :sort-by sort-by :asc asc} "Invoice #"] [sorted-column {:on-sort opc - :style {:width "14%" :cursor "pointer"} + :style {:width "8em" :cursor "pointer"} :sort-key "date" :sort-by sort-by :asc asc} "Date"] [sorted-column {:on-sort opc - :style {:width "14%" :cursor "pointer"} + :style {:width "8em" :cursor "pointer"} :sort-key "total" :sort-by sort-by :asc asc} "Amount"] - [:th {:style {:width "10%"}} "" ]]] + [sorted-column {:on-sort opc + :style {:width "10em" :cursor "pointer"} + :sort-key "outstanding" + :sort-by sort-by + :asc asc} + "Outstanding"] + [:th {:style {:width "10em"}} "" ]]] [:tbody (if (:loading @status) [:tr [:td {:col-span 5} [:i.fa.fa-spin.fa-spinner]]] - (for [{:keys [company checks invoice-number date total id vendor] :as i} (:invoices @invoice-page)] + (for [{:keys [company checks invoice-number date total outstanding-balance id vendor] :as i} (:invoices @invoice-page)] ^{:key id} [:tr (when check-boxes @@ -99,6 +103,7 @@ [:td (date->str date) ] [:td (gstring/format "$%.2f" total )] + [:td (gstring/format "$%.2f" outstanding-balance )] [:td (for [check checks] ^{:key (:id check)} [:a.tag {:href (:s3-url (:check check)) :target "_new"} [:i.fa.fa-money-check] [:span.icon [:i.fa.fa-money]] (str " " (:check-number (:check check)) " (" (gstring/format "$%.2f" (:amount check) ) ")")])]]))]]])))) diff --git a/src/cljs/auto_ap/views/pages.cljs b/src/cljs/auto_ap/views/pages.cljs index f0ca284d..629d8923 100644 --- a/src/cljs/auto_ap/views/pages.cljs +++ b/src/cljs/auto_ap/views/pages.cljs @@ -50,12 +50,11 @@ (defmethod active-page :admin-excel-import [] [admin-excel-import-page]) - (defmethod active-page :unpaid-invoices [] [unpaid-invoices-page]) (defmethod active-page :paid-invoices [] - paid-invoices-page) + [paid-invoices-page]) (defmethod active-page :invoices [] [(with-meta diff --git a/src/cljs/auto_ap/views/pages/admin/companies.cljs b/src/cljs/auto_ap/views/pages/admin/companies.cljs index a88e755b..53d088e2 100644 --- a/src/cljs/auto_ap/views/pages/admin/companies.cljs +++ b/src/cljs/auto_ap/views/pages/admin/companies.cljs @@ -5,6 +5,7 @@ [auto-ap.subs :as subs] [auto-ap.events.admin.companies :as events] [auto-ap.entities.companies :as entity] + [auto-ap.entities.address :as address] [auto-ap.views.utils :refer [login-url dispatch-value-change bind-field horizontal-field]] [cljs.reader :as edn] [auto-ap.routes :as routes] @@ -66,6 +67,61 @@ :event ::events/change :subscription editing-company}]]]] + [:h2.subtitle "Address"] + [horizontal-field + nil + [:div.control + [:p.help "Address"] + [bind-field + [:input.input.is-expanded {:type "text" + :placeholder "1700 Pennsylvania Ave" + :field [:address :street1] + :spec ::address/street1 + :event ::events/change + :subscription editing-company}]]]] + + [horizontal-field + nil + [:div.control + [bind-field + [:input.input.is-expanded {:type "text" + :placeholder "Suite 400" + :field [:address :street2] + :spec ::address/street2 + :event ::events/change + :subscription editing-company}]]]] + + [horizontal-field + nil + [:div.control + [:p.help "City"] + [bind-field + [:input.input.is-expanded {:type "text" + :placeholder "Cupertino" + :field [:address :city] + :spec ::address/city + :event ::events/change + :subscription editing-company}]]] + [:div.control + [:p.help "State"] + [bind-field + [:input.input {:type "text" + :placeholder "CA" + :field [:address :state] + :spec ::address/state + :event ::events/change + :subscription editing-company}]]] + [:div.control + [:p.help "Zip"] + [bind-field + [:input.input {:type "text" + :field [:address :zip] + :spec ::address/zip + :event ::events/change + :subscription editing-company + :placeholder "95014"}]]]] + + [horizontal-field [:label.label "Bank Accounts"] [:div.control diff --git a/src/cljs/auto_ap/views/pages/paid_invoices.cljs b/src/cljs/auto_ap/views/pages/paid_invoices.cljs index fe45bbba..fbacb641 100644 --- a/src/cljs/auto_ap/views/pages/paid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/paid_invoices.cljs @@ -1,34 +1,67 @@ (ns auto-ap.views.pages.paid-invoices (:require [re-frame.core :as re-frame] - [auto-ap.subs :as subs] - [auto-ap.events :as events])) + [auto-ap.entities.companies :as company] + [auto-ap.entities.vendors :as vendor] + [auto-ap.events :as events] + [auto-ap.views.utils :refer [dispatch-event]] + [auto-ap.utils :refer [by]] + [auto-ap.views.pages.check :as check] + [auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table] + [auto-ap.subs :as subs])) + + +(re-frame/reg-sub + ::invoice-page + (fn [db] + (-> db ::invoice-page))) + +(re-frame/reg-sub + ::params + (fn [db] + (-> db (::params {})))) + +(re-frame/reg-event-fx + ::params-change + (fn [cofx [_ params]] + (println "HERE") + + + {:db (-> (:db cofx) + (assoc-in [:status :loading] true) + (assoc-in [::params] params)) + :graphql {:token (-> cofx :db :user) + :query-obj (invoice-table/query (assoc params :imported true :status "paid")) + :on-success [::received]}})) + +(re-frame/reg-event-db + ::received + (fn [db [_ data]] + (-> db + (assoc ::invoice-page (first (:invoice-page data))) + (assoc-in [:status :loading] false)))) + +(re-frame/reg-event-fx + ::invalidated + (fn [cofx [_ params]] + {:dispatch [::params-change @(re-frame/subscribe [::params])]})) + (def paid-invoices-page + (with-meta (fn [] - (let [invoices (re-frame/subscribe [::subs/unpaid-invoices]) - status (re-frame/subscribe [::subs/status])] - [:div + (let [current-company @(re-frame/subscribe [::subs/company])] + [:div [:h1.title "Paid invoices"] - (if (:loading @status) - [:div - [:h1.title - [:i.fa.fa-spin.fa-spinner]]] - [:table {:class "table", :style {:width "100%"}} - [:thead - [:tr - [:th "Vendor"] - [:th "Customer"] - [:th "Invoice #"] - [:th "Date"] - [:th "Amount"]]] - [:tbody (for [{:keys [company invoice-number date total id vendor] :as i} @invoices] - ^{:key (str company "-" invoice-number "-" date "-" total "-" id)} - [:tr - [:td (:name vendor)] - [:td (:name company)] - [:td invoice-number] - [:td date] - [:td total]])]])])) - {:component-will-mount #(re-frame/dispatch-sync [::events/view-unpaid-invoices]) })) + + + [invoice-table {:id :paid + :params (re-frame/subscribe [::params]) + :invoice-page (re-frame/subscribe [::invoice-page]) + :status (re-frame/subscribe [::subs/status]) + :on-params-change (fn [params] + (re-frame/dispatch [::params-change params])) + :check-boxes false}]])) + {:component-will-mount #(do (println "HERE2") (re-frame/dispatch-sync [::params-change {}])) })) + diff --git a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs index 4e676d88..b3df9743 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -57,7 +57,9 @@ (fn [{:keys [db]} [_ bank-account-id]] (let [invoice-amounts (by :id :total (get-in db [::invoice-page :invoices]))] { - :db (assoc-in db [::invoice-page :print-checks-shown?] false ) + :db (-> db + (assoc-in [::invoice-page :print-checks-shown?] false ) + (assoc-in [::invoice-page :print-checks-loading?] true )) :graphql {:token (-> db :user) @@ -71,7 +73,7 @@ (get-in db [::invoice-page :checked])) :bank_account_id bank-account-id :company_id (:company db)} - [[:invoices [:id [:checks [:amount [:check [:amount :s3_url :check_number ]]]]]] + [[:invoices [:id :outstanding-balance [:checks [:amount [:check [:amount :s3_url :check_number ]]]]]] :pdf_url]]]} :on-success [::checks-created]}}))) @@ -88,7 +90,8 @@ (map (fn [i] (merge i (invoices-by-id (:id i)))) invoices))) - (assoc-in [::invoice-page :checked] nil))}))) + (assoc-in [::invoice-page :checked] nil) + (assoc-in [::invoice-page :print-checks-loading?] false))}))) (re-frame/reg-event-fx ::invalidated @@ -98,7 +101,7 @@ (def unpaid-invoices-page (with-meta (fn [] - (let [{:keys [checked print-checks-shown?]} @(re-frame/subscribe [::invoice-page]) + (let [{:keys [checked print-checks-shown? print-checks-loading?]} @(re-frame/subscribe [::invoice-page]) current-company @(re-frame/subscribe [::subs/company])] [:div [:h1.title "Unpaid invoices"] @@ -108,12 +111,17 @@ "is-active" "")} [:div.dropdown-trigger - [:button.button {:aria-haspopup true - :on-click (dispatch-event [::print-checks-clicked ]) - :disabled (if (seq checked) - "" - "disabled") - } "Print checks " + [:button.button.is-success {:aria-haspopup true + :on-click (dispatch-event [::print-checks-clicked ]) + :disabled (if (seq checked) + "" + "disabled") + + :class (if print-checks-loading? + "is-loading" + "") + } + "Print checks " [:span.icon.is-small [:i.fa.fa-angle-down {:aria-hidden "true"}]]]] [:div.dropdown-menu {:role "menu"} [:div.dropdown-content diff --git a/src/cljs/auto_ap/views/utils.cljs b/src/cljs/auto_ap/views/utils.cljs index 369142bb..817e1fc2 100644 --- a/src/cljs/auto_ap/views/utils.cljs +++ b/src/cljs/auto_ap/views/utils.cljs @@ -38,32 +38,35 @@ type)) (defmethod do-bind "select" [dom {:keys [field subscription event class value spec] :as keys} & rest] - (let [keys (assoc keys - :on-change (dispatch-value-change [event [field]]) + (let [field (if (keyword? field) [field] field) + keys (assoc keys + :on-change (dispatch-value-change [event field]) :class (str class - (when (and spec (not (s/valid? spec (field subscription)))) + (when (and spec (not (s/valid? spec (get-in subscription field)))) " is-danger"))) keys (dissoc keys :field :subscription :event :spec)] (vec (concat [dom keys] rest)))) (defmethod do-bind "radio" [dom {:keys [field subscription event class value spec] :as keys} & rest] - (let [keys (assoc keys - :on-change (dispatch-value-change [event [field]]) - :checked (= (field subscription) value) + (let [field (if (keyword? field) [field] field) + keys (assoc keys + :on-change (dispatch-value-change [event field]) + :checked (= (get-in subscription field) value) :class (str class - (when (and spec (not (s/valid? spec (field subscription)))) + (when (and spec (not (s/valid? spec (get-in subscription field )))) " is-danger"))) keys (dissoc keys :field :subscription :event :spec)] (vec (concat [dom keys] rest)))) (defmethod do-bind :default [dom {:keys [field event subscription class spec] :as keys} & rest] - (let [keys (assoc keys - :on-change (dispatch-value-change [event [field]]) - :value (field subscription) + (let [field (if (keyword? field) [field] field) + keys (assoc keys + :on-change (dispatch-value-change [event field]) + :value (get-in subscription field) :class (str class - (when (and spec (not (s/valid? spec (field subscription)))) + (when (and spec (not (s/valid? spec (get-in subscription field)))) " is-danger"))) keys (dissoc keys :field :subscription :event :spec)] (vec (concat [dom keys] rest))))