diff --git a/src/clj/auto_ap/datomic/invoices.clj b/src/clj/auto_ap/datomic/invoices.clj index 3915c75b..37a177a8 100644 --- a/src/clj/auto_ap/datomic/invoices.clj +++ b/src/clj/auto_ap/datomic/invoices.clj @@ -69,7 +69,7 @@ (:status args) (merge-query {:query {:in ['?status] :where ['[?e :invoice/status ?status]]} - :args [ (keyword "invoice-status" (:status args))]}) + :args [ (:status args)]}) (:vendor-id args) (merge-query {:query {:in ['?vendor-id] :where ['[?e :invoice/vendor ?vendor-id]]} diff --git a/src/clj/auto_ap/graphql.clj b/src/clj/auto_ap/graphql.clj index 82e3887d..368fa544 100644 --- a/src/clj/auto_ap/graphql.clj +++ b/src/clj/auto_ap/graphql.clj @@ -381,7 +381,7 @@ :invoice_page {:type '(list :invoice_page) :args {:import_status {:type 'String} :date_range {:type :date_range} - :status {:type 'String} + :status {:type :invoice_status} :client_id {:type :id} :vendor_id {:type :id} :invoice_number_like {:type 'String} @@ -624,6 +624,9 @@ :enums {:payment_type {:values [{:enum-value :check} {:enum-value :cash} {:enum-value :debit}]} + :invoice_status {:values [{:enum-value :paid} + {:enum-value :unpaid} + {:enum-value :voided}]} :bank_account_type {:values [{:enum-value :check} {:enum-value :credit} {:enum-value :cash}]} diff --git a/src/clj/auto_ap/graphql/invoices.clj b/src/clj/auto_ap/graphql/invoices.clj index f4a97d39..8b413a35 100644 --- a/src/clj/auto_ap/graphql/invoices.clj +++ b/src/clj/auto_ap/graphql/invoices.clj @@ -1,5 +1,5 @@ (ns auto-ap.graphql.invoices - (:require [auto-ap.graphql.utils :refer [->graphql <-graphql assert-can-see-client assert-admin]] + (:require [auto-ap.graphql.utils :refer [->graphql <-graphql assert-can-see-client assert-admin enum->keyword]] [auto-ap.datomic.vendors :as d-vendors] [auto-ap.datomic.clients :as d-clients] @@ -17,7 +17,7 @@ (defn get-invoice-page [context args value] (let [args (assoc args :id (:id context)) - [invoices invoice-count] (d-invoices/get-graphql (<-graphql (assoc args :id (:id context))))] + [invoices invoice-count] (d-invoices/get-graphql (update (<-graphql (assoc args :id (:id context))) :status enum->keyword "invoice-status"))] [{:invoices (map ->graphql invoices) :total invoice-count :count (count invoices) diff --git a/src/clj/auto_ap/graphql/transactions.clj b/src/clj/auto_ap/graphql/transactions.clj index 3bb525bb..18f8d498 100644 --- a/src/clj/auto_ap/graphql/transactions.clj +++ b/src/clj/auto_ap/graphql/transactions.clj @@ -1,5 +1,5 @@ (ns auto-ap.graphql.transactions - (:require [auto-ap.graphql.utils :refer [->graphql <-graphql assert-can-see-client assert-admin ident->enum-f snake->kebab]] + (:require [auto-ap.graphql.utils :refer [->graphql <-graphql assert-can-see-client assert-admin ident->enum-f snake->kebab enum->keyword]] [auto-ap.datomic.transactions :as d-transactions] [auto-ap.datomic.vendors :as d-vendors] [auto-ap.datomic.checks :as d-checks] @@ -27,11 +27,7 @@ (defn get-transaction-page [context args value] (let [args (assoc args :id (:id context)) - [transactions transactions-count] (d-transactions/get-graphql (update (<-graphql args) :approval-status - #(some->> % - name - snake->kebab - (keyword "transaction-approval-status")))) + [transactions transactions-count] (d-transactions/get-graphql (update (<-graphql args) :approval-status enum->keyword "transaction-approval-status")) transactions (map ->graphql (map approval-status->graphql transactions))] [{:transactions transactions :total transactions-count @@ -41,11 +37,7 @@ (defn unapprove-transactions [context args value] (let [args (assoc args :id (:id context)) - ids (:ids (d-transactions/raw-graphql-ids (update (<-graphql args) :approval-status - #(some->> % - name - snake->kebab - (keyword "transaction-approval-status")))))] + ids (:ids (d-transactions/raw-graphql-ids (update (<-graphql args) :approval-status enum->keyword "transaction-approval-status")))] (d-transactions/unapprove ids) (get-transaction-page context args value))) diff --git a/src/clj/auto_ap/graphql/utils.clj b/src/clj/auto_ap/graphql/utils.clj index fbb2b5b3..e15c30ca 100644 --- a/src/clj/auto_ap/graphql/utils.clj +++ b/src/clj/auto_ap/graphql/utils.clj @@ -85,3 +85,6 @@ (defn ident->enum-f [k] #(update % k (fn [value] (some-> value :db/ident name keyword)))) + +(defn enum->keyword [e namespace] + (some->> e name snake->kebab (keyword namespace))) diff --git a/src/cljs/auto_ap/views/components/invoice_table.cljs b/src/cljs/auto_ap/views/components/invoice_table.cljs index e899952c..57433061 100644 --- a/src/cljs/auto_ap/views/components/invoice_table.cljs +++ b/src/cljs/auto_ap/views/components/invoice_table.cljs @@ -41,8 +41,6 @@ (fn [db] (::visible-expense-accounts db))) - - (defn query [params] {:venia/queries [[:invoice_page (-> params @@ -59,174 +57,191 @@ :start :end]]]}) -(defn invoice-table [{:keys [id invoice-page status on-params-change vendors params check-boxes checked on-check-changed on-edit-invoice on-void-invoice on-unvoid-invoice expense-event overrides]}] - (let [visible-checks @(re-frame/subscribe [::visible-checks]) +(re-frame/reg-sub + ::table-params + (fn [db] + (::table-params db))) + +(re-frame/reg-event-fx + ::params-changed + [(re-frame/path [::table-params])] + (fn [{table-params :db} [_ params :as z]] + {:db (merge table-params params) + :dispatch [:auto-ap.views.pages.unpaid-invoices/params-change]})) + +(defn row [{:keys [invoice check-boxes checked on-check-changed selected-client overrides expense-event on-edit-invoice on-void-invoice on-unvoid-invoice]}] + (let [{:keys [client payments expense-accounts invoice-number date due total outstanding-balance id vendor] :as i} invoice] + [:tr {:class (:class i)} + (when check-boxes + [:td [:input.checkbox {:type "checkbox" + :checked (if (get checked id) + "checked" + "") + :on-change (fn [x e] (when on-check-changed + (on-check-changed id i)))} ]]) + (when-not selected-client + [:td (if-let [client-override (:client overrides)] + (client-override i) + (:name client))]) + [:td (:name vendor)] + [:td invoice-number] + [:td (date->str date) ] + [:td (date->str due) ] + [:td (str/join ", " (set (map :location expense-accounts)))] + + [:td.has-text-right (nf total )] + [:td.has-text-right (nf outstanding-balance )] + [:td.expandable + [:div.buttons + (when (seq expense-accounts) + [drop-down {:id [::expense-accounts id ] + :header [:a.button.badge {:data-badge (str (clojure.core/count expense-accounts)) + :aria-haspopup true + :on-click (dispatch-event [::events/toggle-menu [::expense-accounts id]]) + :tab-index "0" + } "Accounts"]} + [drop-down-contents + [:div + (for [e expense-accounts] + ^{:key (:id e)} + [:span.dropdown-item (:name (:account e)) " " (gstring/format "$%.2f" (:amount e) ) ]) + + [:hr.dropdown-divider] + + (when expense-event + [:a.dropdown-item.is-primary {:on-click (dispatch-event (conj expense-event i))} "Change"])]]]) + [:span {:style {:margin-left "1em"}}] + (when (and on-edit-invoice (not= ":voided" (:status i))) + [:a.button {:on-click (fn [] (on-edit-invoice i))} [:span.icon [:i.fa.fa-pencil]]]) + (when (and on-void-invoice (= (:outstanding-balance i) (:total i)) (not= ":voided" (:status i))) + [:a.button {:on-click (fn [] (on-void-invoice i))} [:span.icon [:span.icon-bin-2 {:style {:font-weight "400"}}]]]) + (when (and on-unvoid-invoice (= ":voided" (:status i))) + [:a.button {:on-click (fn [] (on-unvoid-invoice i))} [:span [:span.icon [:i.fa.fa-undo]]]]) + (when (seq payments) + [drop-down {:id [::payments id] + :header [:button.button.badge {:data-badge (str (clojure.core/count payments)) + :aria-haspopup true + :tab-index "0" + :on-click (dispatch-event [::events/toggle-menu [::payments id]]) + } "Payments"]} + [:div + (for [payment payments] + (if (:s3-url (:payment payment)) + ^{:key (:id payment)} + [:a.dropdown-item {:href (:s3-url (:payment payment)) + :target "_new"} + [:i.fa.fa-money-check] + [:span.icon [:i.fa.fa-money]] + (str " " (:check-number (:payment payment)) " (" (gstring/format "$%.2f" (:amount payment) ) ")")] + + ^{:key (:id payment)} + [:span.dropdown-item [:span.icon {:class [(when (= :cleared (:status (:payment payment))) + "has-text-success")]} + [:i.fa.fa-money]] (str " " (:check-number (:payment payment)) " (" (gstring/format "$%.2f" (:amount payment) ) ") " + (when (= :cleared (:status (:payment payment))) + (str " - " (:post-date (:transaction (:payment payment))))))]))]])]]])) + +(defn invoice-table [{:keys [id invoice-page status vendors check-boxes checked on-check-changed on-edit-invoice on-void-invoice on-unvoid-invoice expense-event overrides]}] + (let [opc (fn [p] + (re-frame/dispatch [::params-changed p])) + visible-checks @(re-frame/subscribe [::visible-checks]) visible-expense-accounts @(re-frame/subscribe [::visible-expense-accounts]) selected-client @(re-frame/subscribe [::subs/client]) - opc (fn [p] - (on-params-change (merge @params p)))] - (fn [{:keys [id invoice-page status on-params-change vendors checked params]}] - (let [{:keys [sort asc]} @params - {:keys [invoices start end count total]} @invoice-page - visible-checks @(re-frame/subscribe [::visible-checks]) - visible-expense-accounts @(re-frame/subscribe [::visible-expense-accounts]) - selected-client @(re-frame/subscribe [::subs/client]) - percentage-size (if selected-client "%50%" "33%")] - [:div - [:div.level - [:div.level-left - [:div.level-item - [paginator {:start start :end end :count count :total total - :on-change (fn [p ] - (on-params-change (merge @params p) ))}]] - [:div.level-item - [sort-by-list {:sort sort - :on-change opc}]]]] - [:table.table.is-fullwidth - [:thead - [:tr - (when check-boxes - [:th {:style {"width" "20px"}}]) - - (when-not selected-client - [sorted-column {:on-sort opc - :style {:width percentage-size :cursor "pointer"} - :sort-name "Client" - :sort-key "client" - :sort sort - :asc asc} - "Client"]) - [sorted-column {:on-sort opc - :style {:width percentage-size :cursor "pointer"} - :sort-name "Vendor" - :sort-key "vendor" - :sort sort - :asc asc} - "Vendor"] - [sorted-column {:on-sort opc - :style {:width percentage-size :cursor "pointer"} - :sort-name "Invoice Number" - :sort-key "invoice-number" - :sort sort - :asc asc} - "Invoice #"] - [sorted-column {:on-sort opc - :style {:width "8em" :cursor "pointer"} - :sort-name "Date" - :sort-key "date" - :sort sort - :asc asc} - "Date"] - [sorted-column {:on-sort opc - :style {:width "8em" :cursor "pointer"} - :sort-name "Due" - :sort-key "due" - :sort sort - :asc asc} - "Due"] - [sorted-column {:on-sort opc - :style {:width "5em" :cursor "pointer"} - :sort-name "Location" - :sort-key "location" - :sort sort - :asc asc} - "Loc"] - [sorted-column {:on-sort opc - :style {:width "8em" :cursor "pointer"} - :sort-name "Total" - :sort-key "total" - :class "has-text-right" - :sort sort - :asc asc} - "Amount"] + {:keys [sort]} @(re-frame/subscribe [::table-params]) + {:keys [invoices start end count total]} @invoice-page + visible-checks @(re-frame/subscribe [::visible-checks]) + visible-expense-accounts @(re-frame/subscribe [::visible-expense-accounts]) + selected-client @(re-frame/subscribe [::subs/client]) + percentage-size (if selected-client "%50%" "33%")] + [:div + [:div.level + [:div.level-left + [:div.level-item + [paginator {:start start :end end :count count :total total + :on-change opc}]] + [:div.level-item + [sort-by-list {:sort sort + :on-change opc}]]]] + [:table.table.is-fullwidth + [:thead + [:tr + (when check-boxes + [:th {:style {"width" "20px"}}]) + (when-not selected-client + [sorted-column {:on-sort opc + :style {:width percentage-size :cursor "pointer"} + :sort-name "Client" + :sort-key "client" + :sort sort} + "Client"]) + [sorted-column {:on-sort opc + :style {:width percentage-size :cursor "pointer"} + :sort-name "Vendor" + :sort-key "vendor" + :sort sort} + "Vendor"] + [sorted-column {:on-sort opc + :style {:width percentage-size :cursor "pointer"} + :sort-name "Invoice Number" + :sort-key "invoice-number" + :sort sort} + "Invoice #"] + [sorted-column {:on-sort opc + :style {:width "8em" :cursor "pointer"} + :sort-name "Date" + :sort-key "date" + :sort sort} + "Date"] + [sorted-column {:on-sort opc + :style {:width "8em" :cursor "pointer"} + :sort-name "Due" + :sort-key "due" + :sort sort} + "Due"] + [sorted-column {:on-sort opc + :style {:width "5em" :cursor "pointer"} + :sort-name "Location" + :sort-key "location" + :sort sort} + "Loc"] + [sorted-column {:on-sort opc + :style {:width "8em" :cursor "pointer"} + :sort-name "Total" + :sort-key "total" + :class "has-text-right" + :sort sort} + "Amount"] - [sorted-column {:on-sort opc - :style {:width "10em" :cursor "pointer"} - :sort-name "Outstanding" - :sort-key "outstanding-balance" - :class "has-text-right" - :sort sort - :asc asc} - "Outstanding"] - - [:th { - :style {:width "20rem" :cursor "pointer"} - - - } - ""]]] - [:tbody - - (if (:loading @status) - [:tr - [:td {:col-span 5} - [:i.fa.fa-spin.fa-spinner]]] - - (for [{:keys [client payments expense-accounts invoice-number date due total outstanding-balance id vendor] :as i} (:invoices @invoice-page)] - ^{:key id} - [:tr {:class (:class i)} - (when check-boxes - [:td [:input.checkbox {:type "checkbox" - :checked (if (get checked id) - "checked" - "") - :on-change (fn [x e] (when on-check-changed - - (on-check-changed id i)))} ]]) - (when-not selected-client - [:td (if-let [client-override (:client overrides)] - (client-override i) - (:name client))]) - [:td (:name vendor)] - [:td invoice-number] - [:td (date->str date) ] - [:td (date->str due) ] - [:td (str/join ", " (set (map :location expense-accounts)))] - - [:td.has-text-right (nf total )] - [:td.has-text-right (nf outstanding-balance )] - [:td.expandable - [:div.buttons - (when (seq expense-accounts) - [drop-down {:id [::expense-accounts id ] - :header [:a.button.badge {:data-badge (str (clojure.core/count expense-accounts)) - :aria-haspopup true - :on-click (dispatch-event [::events/toggle-menu [::expense-accounts id]]) - :tab-index "0" - } "Accounts"]} - [drop-down-contents - [:div - (for [e expense-accounts] - ^{:key (:id e)} - [:span.dropdown-item (:name (:account e)) " " (gstring/format "$%.2f" (:amount e) ) ]) - - [:hr.dropdown-divider] - - (when expense-event - [:a.dropdown-item.is-primary {:on-click (dispatch-event (conj expense-event i))} "Change"])]]]) - [:span {:style {:margin-left "1em"}}] - (when (and on-edit-invoice (not= ":voided" (:status i))) - [:a.button {:on-click (fn [] (on-edit-invoice i))} [:span.icon [:i.fa.fa-pencil]]]) - (when (and on-void-invoice (= (:outstanding-balance i) (:total i)) (not= ":voided" (:status i))) - [:a.button {:on-click (fn [] (on-void-invoice i))} [:span.icon [:span.icon-bin-2 {:style {:font-weight "400"}}]]]) - (when (and on-unvoid-invoice (= ":voided" (:status i))) - [:a.button {:on-click (fn [] (on-unvoid-invoice i))} [:span [:span.icon [:i.fa.fa-undo]]]]) - (when (seq payments) - [drop-down {:id [::payments id] - :header [:button.button.badge {:data-badge (str (clojure.core/count payments)) - :aria-haspopup true - :tab-index "0" - :on-click (dispatch-event [::events/toggle-menu [::payments id]]) - } "Payments"]} - [:div - (for [payment payments] - (if (:s3-url (:payment payment)) - ^{:key (:id payment)} - [:a.dropdown-item {:href (:s3-url (:payment payment)) :target "_new"} [:i.fa.fa-money-check] [:span.icon [:i.fa.fa-money]] (str " " (:check-number (:payment payment)) " (" (gstring/format "$%.2f" (:amount payment) ) ")")] - - ^{:key (:id payment)} - [:span.dropdown-item [:span.icon {:class [(when (= :cleared (:status (:payment payment))) - "has-text-success")]} - [:i.fa.fa-money]] (str " " (:check-number (:payment payment)) " (" (gstring/format "$%.2f" (:amount payment) ) ") " - (when (= :cleared (:status (:payment payment))) - (str " - " (:post-date (:transaction (:payment payment))))))]))]])]]]))]]])))) + [sorted-column {:on-sort opc + :style {:width "10em" :cursor "pointer"} + :sort-name "Outstanding" + :sort-key "outstanding-balance" + :class "has-text-right" + :sort sort} + "Outstanding"] + + [:th { + :style {:width "20rem" :cursor "pointer"} + + + } + ""]]] + [:tbody + + (if (:loading @status) + [:tr + [:td {:col-span 5} + [:i.fa.fa-spin.fa-spinner]]] + + (for [{:keys [client payments expense-accounts invoice-number date due total outstanding-balance id vendor] :as i} (:invoices @invoice-page)] + ^{:key id} + [row {:invoice i + :check-boxes check-boxes + :checked checked + :on-check-changed on-check-changed + :selected-client selected-client + :overrides overrides + :expense-event expense-event + :on-edit-invoice on-edit-invoice + :on-void-invoice on-void-invoice + :on-unvoid-invoice on-unvoid-invoice}]))]]])) diff --git a/src/cljs/auto_ap/views/components/invoices/side_bar.cljs b/src/cljs/auto_ap/views/components/invoices/side_bar.cljs index 282319fe..0b23916a 100644 --- a/src/cljs/auto_ap/views/components/invoices/side_bar.cljs +++ b/src/cljs/auto_ap/views/components/invoices/side_bar.cljs @@ -7,11 +7,75 @@ [goog.string :as gstring] [bidi.bidi :as bidi] [auto-ap.routes :as routes] + [auto-ap.views.components.date-range-filter :refer [date-range-filter]] + [auto-ap.views.components.typeahead :refer [typeahead-entity]] [auto-ap.views.utils :refer [active-when dispatch-event bind-field horizontal-field date->str str->date pretty standard]] [auto-ap.subs :as subs] [auto-ap.events :as events])) -(defn invoices-side-bar [params & rest] + +(re-frame/reg-sub + ::filters + (fn [db ] + (::filters db {}))) + +(re-frame/reg-sub + ::filter + :<- [::filters] + (fn [filters [_ which]] + (filters which))) + +(re-frame/reg-sub + ::filter-params + :<- [::filters] + :<- [::subs/active-page] + (fn [[filters ap]] + (println (:invoice-number-like filters)) + {:vendor-id (:id (:vendor filters)) + :date-range (:date-range filters) + :invoice-number-like (:settled (:invoice-number-like filters)) + :status (condp = ap + :invoices nil + :unpaid-invoices :unpaid + :paid-invoices :paid + :voided-invoices :voided)})) + + +(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])] + {:dispatch [:auto-ap.views.pages.unpaid-invoices/params-change] + :db (assoc-in db (into [::filters] which) val)}))) + +(re-frame/reg-event-fx + ::invoice-number-like-settled + [(re-frame/path [::filters :invoice-number-like])] + (fn [{:keys [db]} [_ invoice-number-like]] + {:db (assoc db :settled invoice-number-like) + :dispatch [::filter-changed :invoice-number-like [:settled] invoice-number-like]})) + + +(re-frame/reg-event-fx + ::invoice-number-like-changed + [(re-frame/path [::filters :invoice-number-like])] + (fn [{:keys [db]} [_ invoice-number-like]] + {:dispatch-debounce {:event [::invoice-number-like-settled invoice-number-like] + :time 500 + :key ::invoice-number-like} + :db (assoc db :raw invoice-number-like)})) + +(defn invoice-number-filter [] + [:div.field + [:div.control [:input.input {:placeholder "AP-123" + :value (:raw @(re-frame/subscribe [::filter :invoice-number-like])) + :on-change (fn [x] + (re-frame/dispatch [::invoice-number-like-changed (.. x -target -value) ]))} ]]]) + +(defn invoices-side-bar [params] (let [ap @(re-frame/subscribe [::subs/active-page]) user @(re-frame/subscribe [::subs/user])] [:div @@ -49,5 +113,20 @@ [:span {:class "icon icon-accounting-document" :style {:font-size "25px"}}] [:span {:class "name"} "Import Invoices"]]])]] - [:div - rest]])) + (when (not= ap :import-invoices) + [:div + [:p.menu-label "Vendor"] + [:div + [typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors]) + :on-change #(re-frame/dispatch [::filter-changed :vendor %]) + :match->text :name + :type "typeahead-entity" + :value @(re-frame/subscribe [::filter :vendor])}]] + [:p.menu-label "Date Range"] + [:div + [date-range-filter + {:on-change-event [::filter-changed :date-range] + :value @(re-frame/subscribe [::filter :date-range])}]] + [:p.menu-label "Invoice #"] + [:div + [invoice-number-filter]]])])) diff --git a/src/cljs/auto_ap/views/pages/payments.cljs b/src/cljs/auto_ap/views/pages/payments.cljs index 7ff144ca..3cc3f9bd 100644 --- a/src/cljs/auto_ap/views/pages/payments.cljs +++ b/src/cljs/auto_ap/views/pages/payments.cljs @@ -2,7 +2,6 @@ (:require [re-frame.core :as re-frame] [auto-ap.entities.clients :as client] [auto-ap.entities.vendors :as vendor] - [auto-ap.entities.invoice :as invoice] [reagent.core :as reagent] [goog.string :as gstring] [clojure.spec.alpha :as s] @@ -18,7 +17,6 @@ [auto-ap.views.pages.payments.side-bar :as side-bar] [auto-ap.views.pages.payments.table :as table] [auto-ap.views.pages.check :as check] - [auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table] [auto-ap.subs :as subs])) @@ -91,21 +89,27 @@ (update ::payment-page merge (first (:payment-page data))) (assoc-in [:status :loading] false)))) -(def checks-content - (with-meta - (fn [] - (let [current-client @(re-frame/subscribe [::subs/client])] - [:div - [:h1.title "Checks"] - [table/table {:id :payments - :payment-page (re-frame/subscribe [::payment-page]) - :status (re-frame/subscribe [::subs/status]) - :void-event [::void-check] - }]])) - {:component-will-mount #(re-frame/dispatch-sync [::params-change {}]) })) +(re-frame/reg-event-fx + ::unmounted + (fn [{:keys [db]} _] + {:db (dissoc db ::last-params ::table/table-params ::side-bar/filters ::payment-page)})) +(defn content [] + (let [current-client @(re-frame/subscribe [::subs/client])] + [:div + [:h1.title "Payments"] + [table/table {:id :payments + :payment-page (re-frame/subscribe [::payment-page]) + :status (re-frame/subscribe [::subs/status]) + :void-event [::void-check]}]])) (defn payments-page [] - [side-bar-layout {:side-bar [side-bar/side-bar] - :main [checks-content]}]) + (reagent/create-class + {:display-name "payments-page" + :component-did-mount #(re-frame/dispatch [::params-change {}]) + :component-will-unmount #(re-frame/dispatch [::unmounted]) + :reagent-render + (fn [] + [side-bar-layout {:side-bar [side-bar/side-bar] + :main [content]}])})) diff --git a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs index 0f2bbe83..c75f6c85 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -7,22 +7,14 @@ [auto-ap.views.pages.invoices.form :as form] [auto-ap.views.components.dropdown :refer [drop-down]] [auto-ap.views.components.expense-accounts-dialog :as expense-accounts-dialog :refer [change-expense-accounts-modal]] - [auto-ap.views.components.invoice-table :as invoice-table :refer [invoice-table]] - [auto-ap.views.components.invoices.side-bar :refer [invoices-side-bar]] + [auto-ap.views.components.invoice-table :as table :refer [invoice-table]] + [auto-ap.views.components.invoices.side-bar :refer [invoices-side-bar] :as side-bar] [auto-ap.views.components.layouts :refer [appearing-side-bar side-bar-layout]] [auto-ap.views.components.modal :refer [action-modal modal]] [auto-ap.views.components.typeahead :refer [typeahead]] [auto-ap.views.components.vendor-filter :refer [vendor-filter]] - [auto-ap.views.components.date-range-filter :refer [date-range-filter]] [auto-ap.views.pages.invoices.common :refer [invoice-read]] - [auto-ap.views.utils - :refer - [bind-field - date->str - date-picker - dispatch-event - horizontal-field - standard]] + [auto-ap.views.utils :refer [bind-field date->str date-picker dispatch-event horizontal-field standard with-user]] [cljs-time.core :as c] [clojure.spec.alpha :as s] [clojure.string :as str :refer [blank?]] @@ -74,8 +66,14 @@ (re-frame/reg-sub ::params - (fn [db] - (-> db (::params {})))) + :<- [::subs/client] + :<- [::side-bar/filter-params] + :<- [::table/table-params] + (fn [[client filter-params table-params]] + (cond-> {:import-status "imported"} + client (assoc :client-id (:id client)) + (seq filter-params) (merge filter-params) + (seq table-params) (merge @(re-frame/subscribe [::table/table-params]))))) (re-frame/reg-event-db ::invoice-updated @@ -86,22 +84,24 @@ (re-frame/reg-event-fx ::params-change - (fn [cofx [_ params]] - {:db (-> (:db cofx) - (assoc-in [:status :loading] true) - (assoc-in [::params] params)) - :graphql {:token (-> cofx :db :user) - :query-obj (invoice-table/query (-> params (assoc :import-status "imported") (dissoc :invoice-number-like-current)) ) - :on-success [::received] - :on-error [::events/page-failed]}})) + [with-user] + (fn [cofx _] + (let [new-params @(re-frame/subscribe [::params])] + (when (not= new-params (::last-params (:db cofx))) + {:db (-> (:db cofx) + (assoc-in [:status :loading] true) + (assoc-in [::last-params] new-params)) + :graphql {:token (-> cofx :db :user) + :query-obj (table/query new-params ) + :on-success [::received] + :on-error [::events/page-failed]}})))) -(re-frame/reg-event-db - ::unmount-invoices - (fn [db [_ data]] - (-> db - (dissoc ::invoice-page )))) +(re-frame/reg-event-fx + ::unmounted + (fn [{:keys [db]} _] + {:db (dissoc db ::invoice-page ::table/table-params ::side-bar/filters ::last-params)})) (re-frame/reg-event-db ::received @@ -272,11 +272,6 @@ (assoc-in [::check-results :shown?] true) (assoc-in [::check-results :pdf-url] pdf-url)))) -(re-frame/reg-event-fx - ::invalidated - (fn [cofx [_ params]] - {:dispatch [::params-change @(re-frame/subscribe [::params])]})) - (re-frame/reg-event-fx ::new-invoice-clicked (fn [{:keys [db]} _] @@ -356,16 +351,6 @@ (dissoc ::handwrite-checks))}))) - - - - - - - - - - (re-frame/reg-event-fx ::invoice-unvoided (fn [{:keys [db]} [_ {:keys [unvoid-invoice]}]] @@ -551,48 +536,6 @@ -(re-frame/reg-event-db - ::change-selected-vendor - (fn [db [_ key value]] - (let [[key] key - updated (assoc-in db [::invoice-page :vendor-filter key] value)] - (if (and (= key :vendor-id) - (not= value (get-in db [::params :vendor-id]))) - (do - (re-frame/dispatch [::params-change (assoc (::params updated) :vendor-id value :start 0)]) - (assoc-in updated [::params :vendor-id] value)) - updated)))) - -(re-frame/reg-event-fx - ::change-selected-date-range - (fn [{:keys [db]} [_ key value]] - (let [[key] key - updated (-> db - (assoc-in [::invoice-page :date-range-filter key] value) - (assoc-in [::params :date-range key] value))] - {:dispatch [::params-change (::params updated)] - :db 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-number-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 [] - (let [{:keys [invoice-number-like-current] :as params} @(re-frame/subscribe [::params])] - [:div.field - [:div.control [:input.input {:placeholder "AP-123" - :value invoice-number-like-current - :on-change (fn [x] - (re-frame/dispatch [::invoice-number-like-current-changed params (.. x -target -value) ]))} ]]])) (defn pay-button [{:keys [print-checks-shown? checked-invoices print-checks-loading?]}] (let [current-client @(re-frame/subscribe [::subs/client])] @@ -603,14 +546,7 @@ (when current-client [drop-down {:header [:button.button.is-success {:aria-haspopup true :on-click (dispatch-event [::events/toggle-menu ::print-checks ]) - :disabled (if (and (seq checked-invoices) - #_(->> checked-invoices - vals - (group-by #(get-in % [:vendor :id])) - (reduce-kv (fn [negative? _ invoices] - (or negative? (< (reduce + 0 (map (fn [x] (-> x :outstanding-balance js/parseFloat)) invoices) ) 0))) - false) - not)) + :disabled (if (and (seq checked-invoices)) "" "disabled") @@ -666,63 +602,42 @@ ])))) (defn unpaid-invoices-content [{:keys [status] :as params}] - (r/create-class {:display-name "unpaid-invoices-content" - :component-will-unmount (fn [this] - (re-frame/dispatch [::unmount-invoices])) - :reagent-render (fn [{:keys [status]}] - (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])] - [:div - [:h1.title (str (str/capitalize (or status "all")) " invoices")] - - (when (= status "unpaid") - [pay-button {:print-checks-shown? print-checks-shown? :checked-invoices checked :print-checks-loading? print-checks-loading?}]) - - - - [invoice-table {:id :unpaid - :params (re-frame/subscribe [::params]) - :invoice-page (re-frame/subscribe [::invoice-page]) - :status (re-frame/subscribe [::subs/status]) - :on-edit-invoice (fn [which] - (re-frame/dispatch [::form/editing which])) - :on-unvoid-invoice (fn [which] - (re-frame/dispatch [::unvoid-invoice which])) - - :on-void-invoice (fn [which] - (re-frame/dispatch [::void-invoice which])) - :on-params-change (fn [params] - (re-frame/dispatch [::params-change params])) - :check-boxes (= status "unpaid") - :checked checked - :on-check-changed (fn [which invoice] - (re-frame/dispatch [::toggle-check which invoice])) - :expense-event [::expense-accounts-dialog/change-expense-accounts]}] - ])) - :component-will-mount #(re-frame/dispatch-sync [::params-change params]) })) + (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])] + [:div + [:h1.title (str (str/capitalize (or status "all")) " invoices")] + (when (= status "unpaid") + [pay-button {:print-checks-shown? print-checks-shown? :checked-invoices checked :print-checks-loading? print-checks-loading?}]) + [table/invoice-table {:id :unpaid + :invoice-page (re-frame/subscribe [::invoice-page]) + :status (re-frame/subscribe [::subs/status]) + :on-edit-invoice (fn [which] + (re-frame/dispatch [::form/editing which])) + :on-unvoid-invoice (fn [which] + (re-frame/dispatch [::unvoid-invoice which])) + :on-void-invoice (fn [which] + (re-frame/dispatch [::void-invoice which])) + :check-boxes (= status "unpaid") + :checked checked + :on-check-changed (fn [which invoice] + (re-frame/dispatch [::toggle-check which invoice])) + :expense-event [::expense-accounts-dialog/change-expense-accounts]}] + ])) (defn unpaid-invoices-page [params] - (let [{invoice-bar-active? :active?} @(re-frame/subscribe [::forms/form ::form/form])] - [side-bar-layout {:side-bar [invoices-side-bar {} - ^{:key "extra-filter"} - [:div - [:p.menu-label "Vendor"] - [:div [vendor-filter {:on-change-event [::change-selected-vendor] - :value (:vendor-filter @(re-frame/subscribe [::invoice-page])) - :vendors @(re-frame/subscribe [::subs/vendors])}]] - [:p.menu-label "Date Range"] - [:div - [date-range-filter - {:on-change-event [::change-selected-date-range] - :value (:date-range-filter @(re-frame/subscribe [::invoice-page]))}]] - [:p.menu-label "Invoice #"] - [:div - [invoice-number-filter]]]] - :main [unpaid-invoices-content params] - :bottom [:div - [check-results-dialog] - [print-checks-modal] - [handwrite-checks-modal] - [change-expense-accounts-modal {:updated-event [::expense-accounts-updated]}]] - :right-side-bar [appearing-side-bar {:visible? invoice-bar-active?} [form/form {:invoice-created [::invoice-updated] - :invoice-printed [::checks-printed]}]]}])) + (r/create-class + {:display-name "invoices-page" + :component-did-mount #(re-frame/dispatch [::params-change]) + :component-will-unmount #(re-frame/dispatch [::unmounted]) + :reagent-render + (fn [] + (let [{invoice-bar-active? :active?} @(re-frame/subscribe [::forms/form ::form/form])] + [side-bar-layout {:side-bar [invoices-side-bar {}] + :main [unpaid-invoices-content params] + :bottom [:div + [check-results-dialog] + [print-checks-modal] + [handwrite-checks-modal] + [change-expense-accounts-modal {:updated-event [::expense-accounts-updated]}]] + :right-side-bar [appearing-side-bar {:visible? invoice-bar-active?} [form/form {:invoice-created [::invoice-updated] + :invoice-printed [::checks-printed]}]]}]))}))