diff --git a/src/clj/auto_ap/datomic/transactions.clj b/src/clj/auto_ap/datomic/transactions.clj index 34cabfbb..04c7d976 100644 --- a/src/clj/auto_ap/datomic/transactions.clj +++ b/src/clj/auto_ap/datomic/transactions.clj @@ -99,10 +99,10 @@ '[?c :client/name ?sort-client]] "account" ['[?e :transaction/date] '(or-join [?e ?sort-account] - (and [?e :transaction/account ?c] - [?c :account/name ?sort-account]) + (and [?e :transaction/bank-account ?c] + [?c :bank-account/name ?sort-account]) (and - (not [?e :transaction/account]) + (not [?e :transaction/bank-account]) [(ground "") ?sort-account]))] "description-original" ['[?e :transaction/description-original ?sort-description-original]] "date" ['[?e :transaction/date ?sort-date]] diff --git a/src/cljs/auto_ap/forms.cljs b/src/cljs/auto_ap/forms.cljs index 7f9265e1..db399e2a 100644 --- a/src/cljs/auto_ap/forms.cljs +++ b/src/cljs/auto_ap/forms.cljs @@ -1,6 +1,7 @@ (ns auto-ap.forms (:require [re-frame.core :as re-frame] [re-frame.interceptor :as i] + [auto-ap.status :as status] [auto-ap.views.utils :refer [dispatch-event bind-field]])) @@ -198,10 +199,11 @@ ^{:key error} [:div.notification.is-warning.animated.fadeInUp {} error])) :submit-button (fn [child] - (let [error (:error @(re-frame/subscribe [::form id]))] - [:button.button.is-medium.is-primary.is-fullwidth {:disabled (if @(re-frame/subscribe can-submit) - "" - "disabled") - :class (str @(re-frame/subscribe [::loading-class id]) - (when error " animated shake"))} child]))}) + (let [error (:error @(re-frame/subscribe [::form id])) + status @(re-frame/subscribe [::status/single id]) + can-submit @(re-frame/subscribe can-submit)] + [:button.button.is-medium.is-primary.is-fullwidth {:disabled (or (status/disabled-for status) + (not can-submit)) + :class (status/class-for status) } + child]))}) diff --git a/src/cljs/auto_ap/status.cljs b/src/cljs/auto_ap/status.cljs index 74c37f49..911877ed 100644 --- a/src/cljs/auto_ap/status.cljs +++ b/src/cljs/auto_ap/status.cljs @@ -37,6 +37,16 @@ :else [])) +(defn disabled-for [which] + (cond (= :loading (:state which)) + true + + (= :error (:state which)) + false + + :else + false)) + (re-frame/reg-sub ::multi @@ -92,3 +102,16 @@ (fn [db [_ single error]] (assoc db single {:state :error :error error}))) + +(defn status-notification [{:keys [statuses]}] + (let [states + (->> statuses + (mapv #(deref (re-frame/subscribe %))) + (filter #(= :error (:state %))))] + (when (seq states) + [:div.notification + (for [state states + state (:error state)] + (do + ^{:key (:message state)} + [:p (:message state)]))]))) diff --git a/src/cljs/auto_ap/views/components/invoice_table.cljs b/src/cljs/auto_ap/views/components/invoice_table.cljs index fdf354f4..5d420d42 100644 --- a/src/cljs/auto_ap/views/components/invoice_table.cljs +++ b/src/cljs/auto_ap/views/components/invoice_table.cljs @@ -175,16 +175,15 @@ [buttons/fa-icon {:icon "fa-undo" :event [::unvoid-invoice i]}])]]])) -(defn invoice-table [{:keys [id invoice-page status vendors check-boxes on-check-changed expense-event overrides]}] +(defn invoice-table [{:keys [id data checked status vendors check-boxes on-check-changed expense-event overrides]}] (let [selected-client @(re-frame/subscribe [::subs/client]) {:keys [sort]} @(re-frame/subscribe [::table-params]) - {:keys [invoices outstanding]} invoice-page selected-client @(re-frame/subscribe [::subs/client]) is-loading? (= :loading (:state status)) is-sorted-by-vendor? (and (= "vendor" (:sort-key (first sort))) (not is-loading?) - (or (apply <= (map (comp :name :vendor) (:invoices invoice-page))) - (apply >= (map (comp :name :vendor) (:invoices invoice-page))))) + (or (apply <= (map (comp :name :vendor) (:data data))) + (apply >= (map (comp :name :vendor) (:data data))))) [invoice-groups] (if is-sorted-by-vendor? (reduce @@ -196,19 +195,19 @@ [(update-in acc [(dec (clojure.core/count acc))] #(conj (or % []) invoice)) (:id (:vendor invoice))])) [[] nil] - (:invoices invoice-page)) - [[(:invoices invoice-page)]])] + (:data data)) + [[(:data data)]])] [grid/grid {:on-params-change (fn [p] (re-frame/dispatch [::params-changed p])) :on-check-changed on-check-changed :params @(re-frame/subscribe [::table-params]) - :checked (:checked invoice-page) + :checked checked :status status :check-boxes? check-boxes :column-count (if selected-client 7 8)} - [grid/controls invoice-page + [grid/controls data [:div.level-item - "Outstanding " (nf outstanding)]] + "Outstanding " (nf (:outstanding data))]] (for [invoices invoice-groups] ^{:key (or (:id (first invoices)) "init")} [grid/table {:fullwidth true} diff --git a/src/cljs/auto_ap/views/components/modal.cljs b/src/cljs/auto_ap/views/components/modal.cljs index 6fb2336e..79b047ee 100644 --- a/src/cljs/auto_ap/views/components/modal.cljs +++ b/src/cljs/auto_ap/views/components/modal.cljs @@ -102,7 +102,10 @@ [:button.delete {:on-click (dispatch-event [::modal-closed])}]] [:section.modal-card-body body] - (let [status (some-> confirm :status-from re-frame/subscribe deref )] + (let [status (some-> confirm :status-from re-frame/subscribe deref ) + can-submit (if-let [can-submit (-> confirm :can-submit)] + @(re-frame/subscribe can-submit) + true)] (if foot [:footer.modal-card-foot [appearing {:visible? (= :error (:state status)) @@ -122,7 +125,11 @@ [:div.buttons (when confirm [:button.button {:class (conj (status/class-for status) (:class confirm) ) + :disabled (if can-submit + false + true) :on-click (:on-click confirm)} (:value confirm)]) (when cancel? [:button.button {:on-click (dispatch-event [::modal-closed] )} "Cancel"])]]]))]]))))) + diff --git a/src/cljs/auto_ap/views/pages/admin/accounts/side_bar.cljs b/src/cljs/auto_ap/views/pages/admin/accounts/side_bar.cljs new file mode 100644 index 00000000..5c9a4531 --- /dev/null +++ b/src/cljs/auto_ap/views/pages/admin/accounts/side_bar.cljs @@ -0,0 +1,81 @@ +(ns auto-ap.views.pages.admin.accounts.side-bar + (:require + [re-frame.core :as re-frame] + [auto-ap.subs :as subs] + [auto-ap.views.utils :refer [active-when dispatch-value-change]] + [auto-ap.views.components.typeahead :refer [typeahead-entity]])) + + +(re-frame/reg-sub + ::specific-filters + (fn [db ] + (::filters db nil))) + +(re-frame/reg-sub + ::filters + :<- [::specific-filters] + :<- [::subs/vendors-by-id] + :<- [::subs/query-params] + (fn [[specific-filters vendors-by-id query-params] ] + (let [url-filters (-> query-params + (select-keys #{:name-like :code-like}) + (update :name-like #(some-> % str)) + (update :code-like #(some-> % str)))] + (merge url-filters specific-filters )))) + +(re-frame/reg-sub + ::filter + :<- [::filters] + (fn [filters [_ which]] + (get filters which))) + +(re-frame/reg-sub + ::settled-filters + (fn [db ] + (::settled-filters db))) + +(re-frame/reg-sub + ::filter-params + :<- [::settled-filters] + :<- [::filters] + :<- [::subs/active-page] + (fn [[settled-filters filters ap ]] + (let [filters (or settled-filters filters)] + {:name-like (:name-like filters) + :code-like (:code-like filters)}))) + +(re-frame/reg-event-fx + ::filters-settled + (fn [{:keys [db]} [_ & params]] + {:db (assoc db ::settled-filters @(re-frame/subscribe [::filters]))})) + +(re-frame/reg-event-fx + ::filter-changed + (fn [{:keys [db]} [_ & params]] + (let [[a b c] params + [which val] (if (= 3 (count params)) + [(into [a] b) c] + [[a] b])] + {:db (assoc-in db (into [::filters] which) val) + :dispatch-debounce {:event [::filters-settled] + :time 800 + :key ::filters}}))) + + +(defn accounts-side-bar [] + [:div + [:p.menu-label "Name"] + + [:div.field + [:div.control [:input.input {:placeholder "Food Cost" + :value @(re-frame/subscribe [::filter :name-like]) + :on-change (dispatch-value-change [::filter-changed :name-like])} ]]] + + [:p.menu-label "Code"] + + [:div.field + [:div.control [:input.input {:placeholder "11000" + :value @(re-frame/subscribe [::filter :code-like]) + :on-change (dispatch-value-change [::filter-changed :code-like])}]]]]) + + diff --git a/src/cljs/auto_ap/views/pages/data_page.cljs b/src/cljs/auto_ap/views/pages/data_page.cljs new file mode 100644 index 00000000..0f198cb4 --- /dev/null +++ b/src/cljs/auto_ap/views/pages/data_page.cljs @@ -0,0 +1,74 @@ +(ns auto-ap.views.pages.data-page + (:require [auto-ap.status :as status] + [auto-ap.utils :refer [by merge-by replace-by]] + [re-frame.core :as re-frame])) + +(re-frame/reg-sub + ::checked + (fn [db [_ id]] + (get-in db [::checked id] #{}))) + +(re-frame/reg-event-db + ::toggle-check + (fn [db [_ id new]] + (assoc-in db [::checked id] new))) + +(re-frame/reg-event-db + ::remove-check + (fn [db [_ id to-remove]] + (update-in db + [::checked id] + (fn [checked] + (let [checked (or checked #{})] + (disj checked to-remove)))))) + +(re-frame/reg-event-db + ::updated-entity + (fn [db [_ id entity]] + (update-in db + [::data id] + replace-by :id (assoc entity :class "live-added")))) + +(re-frame/reg-event-db + ::received + (fn [db [_ id data]] + (assoc-in db [::data id] data))) + +(re-frame/reg-event-db + ::dispose + (fn [db [_ id]] + (-> db + (update ::data dissoc id) + (update ::checked dissoc id) + (update ::params dissoc id)))) + +(re-frame/reg-sub + ::data + (fn [db [_ id]] + (get-in db [::data id]))) + +(re-frame/reg-sub + ::page + (fn [[_ id]] + [(re-frame/subscribe [::data id]) + (re-frame/subscribe [::status/single [::page id]]) + (re-frame/subscribe [::checked id])]) + (fn [[data status checked] [_ id]] + {:id id + :data data + :status status + :checked checked})) + +(defn in-page-entities [which] + (re-frame/path [::data which :data ] )) + +(re-frame/reg-event-db + ::entity-updated + (fn [db [_ which [_ entity] :as g]] + (println g) + (update-in db [::data which :data] + (fn [entities] + (let [by-id (by :id entities )] + (if (by-id (:id entity)) + (merge-by entities :id entity) + (into [entity] entities))))))) diff --git a/src/cljs/auto_ap/views/pages/invoices/form.cljs b/src/cljs/auto_ap/views/pages/invoices/form.cljs index 0f148317..6af3033d 100644 --- a/src/cljs/auto_ap/views/pages/invoices/form.cljs +++ b/src/cljs/auto_ap/views/pages/invoices/form.cljs @@ -10,6 +10,7 @@ [auto-ap.views.components.money-field :refer [money-field]] [auto-ap.views.components.typeahead :refer [typeahead-entity]] [auto-ap.views.pages.invoices.common :refer [invoice-read]] + [auto-ap.status :as status] [auto-ap.views.utils :refer [date->str date-picker dispatch-event standard with-user]] [cljs-time.core :as c] [clojure.spec.alpha :as s] @@ -17,8 +18,6 @@ [re-frame.core :as re-frame])) ;; SUBS - - (re-frame/reg-sub ::can-submit :<- [::forms/form ::form] @@ -26,8 +25,7 @@ (let [min-total (if (= (:total (:original data)) (:outstanding-balance (:original data))) nil (- (:total (:original data)) (:outstanding-balance (:original data))))] - (and (not= :loading status) - (s/valid? ::invoice/invoice data) + (and (s/valid? ::invoice/invoice data) (or (not min-total) (>= (:total data) min-total)) (or (not (:id data)) (dollars= (js/parseFloat (:total data)) (reduce + 0 (map (fn [ea] (js/parseFloat (:amount ea))) (:expense-accounts data))))))))) @@ -107,6 +105,15 @@ ;; EVENTS +(re-frame/reg-event-db + ::updated + (fn [db [_ invoice command]] + (-> db + (forms/stop-form ::form ) + (forms/start-form ::form {:client @(re-frame/subscribe [::subs/client]) + :status :unpaid + :date (date->str (c/now) standard)})))) + (re-frame/reg-event-db ::adding (fn [db [_ new]] @@ -168,48 +175,41 @@ (re-frame/reg-event-fx ::add-and-print - [with-user (forms/triggers-loading ::form) (forms/in-form ::form)] + [with-user (forms/in-form ::form)] (fn [{:keys [user] {:keys [data]} :db} [_ params bank-account-id type]] {:graphql {:token user + :owns-state {:single ::form} :query-obj @(re-frame/subscribe [::add-and-print-query bank-account-id type]) - :on-success [::succeeded params :add-and-print] + :on-success [::added-and-printed params] :on-error [::forms/save-error ::form]}})) (re-frame/reg-event-fx ::saving - [with-user (forms/triggers-loading ::form) (forms/in-form ::form)] + [with-user (forms/in-form ::form)] (fn [{:keys [user] {:keys [data]} :db} [_ params]] (let [command (if (:id data) :edit :create)] {:graphql {:token user + :owns-state {:single ::form} :query-obj (if (:id data) @(re-frame/subscribe [::edit-query]) @(re-frame/subscribe [::create-query])) - :on-success [::succeeded params command] + :on-success (fn [result] + [::updated (assoc (if (:id data) + (:edit-invoice result) + (:add-invoice result)) + :class "live-added")]) :on-error [::forms/save-error ::form]}}))) (re-frame/reg-event-fx - ::succeeded - (fn [{:keys [db]} [_ {:keys [invoice-created invoice-printed]} command result]] - (let [invoice (condp = command - :edit (:edit-invoice result) - - :create (:add-invoice result) - - :add-and-print (first (:invoices (:add-and-print-invoice result))))] - - - {:db (cond-> db - (#{:create :add-and-print} command) (-> (forms/stop-form ::form ) - (forms/start-form ::form {:client @(re-frame/subscribe [::subs/client]) - :status :unpaid - :date (date->str (c/now) standard)})) - (= :edit command) (forms/stop-form ::form)) - :dispatch-n (cond-> [(conj invoice-created invoice)] - (= :add-and-print command) (conj (conj invoice-printed (:pdf-url (:add-and-print-invoice result)))))}))) + ::added-and-printed + (fn [{:keys [db]} [_ {:keys [invoice-printed]} result]] + (let [invoice (first (:invoices (:add-and-print-invoice result)))] + {:dispatch-n [[::updated (assoc invoice :class "live-added")] + (conj invoice-printed (:pdf-url (:add-and-print-invoice result)))]}))) @@ -224,6 +224,7 @@ [layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form ])} (let [{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::form]) {:keys [form-inline field raw-field error-notification submit-button ]} invoice-form + status @(re-frame/subscribe [::status/single ::form]) exists? (:id data) can-change-amount? (#{:unpaid ":unpaid"} (:status data)) min-total (if (= (:total (:original data)) (:outstanding-balance (:original data))) @@ -319,13 +320,8 @@ [drop-down {:header [:button.button.is-info.is-outlined.is-medium.is-fullwidth {:aria-haspopup true :type "button" :on-click (dispatch-event [::events/toggle-menu ::add-and-print-invoice ]) - :disabled (if @(re-frame/subscribe [::can-submit]) - "" - "disabled") - - :class (if false - "is-loading" - "")} + :disabled (status/disabled-for status) + :class (status/class-for status)} "Save & Pay " [:span " "] [:span.icon.is-small [:i.fa.fa-angle-down {:aria-hidden "true"}]]] diff --git a/src/cljs/auto_ap/views/pages/transactions/table.cljs b/src/cljs/auto_ap/views/pages/transactions/table.cljs index fa3a6f75..d412f9b4 100644 --- a/src/cljs/auto_ap/views/pages/transactions/table.cljs +++ b/src/cljs/auto_ap/views/pages/transactions/table.cljs @@ -68,7 +68,7 @@ [grid/row {} (when-not selected-client [grid/sortable-header-cell {:sort-key "client" :sort-name "Client"} "Client"]) - [grid/sortable-header-cell {:sort-key "bank-account" :sort-name "Bank Account"} "Bank Account"] + [grid/sortable-header-cell {:sort-key "account" :sort-name "Bank Account"} "Bank Account"] [grid/sortable-header-cell {:sort-key "vendor" :sort-name "Vendor"} "Vendor"] [grid/sortable-header-cell {:sort-key "date" :sort-name "Date" :style {:width "8em"}} "Date"] [grid/sortable-header-cell {:sort-key "amount" :sort-name "Amount" :class "has-text-right" :style {:width "8em"}} "Amount"] diff --git a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs index 2b17b5bc..58113b0e 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -14,6 +14,7 @@ [auto-ap.views.components.typeahead :refer [typeahead]] [auto-ap.views.components.vendor-filter :refer [vendor-filter]] [auto-ap.views.pages.invoices.common :refer [invoice-read]] + [auto-ap.views.pages.data-page :as data-page] [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] @@ -24,7 +25,9 @@ [reagent.core :as r] [auto-ap.status :as status] [vimsical.re-frame.fx.track :as track] - [auto-ap.utils :refer [merge-by]])) + [auto-ap.utils :refer [merge-by]] + [clojure.set :as set] + [auto-ap.views.components.modal :as modal])) (defn does-amount-exceed-outstanding? [amount outstanding-balance] (let [amount (js/parseFloat amount) @@ -49,20 +52,11 @@ (assoc i :checkable? (not (:automatically-paid-when-due i)))) is)))))) -(re-frame/reg-sub - ::invoice - (fn [db id] - (get (by :id (-> db ::invoice-page :invoices )) id))) - (re-frame/reg-sub ::advanced-print-checks (fn [db] (-> db ::advanced-print-checks))) -(re-frame/reg-sub - ::handwrite-checks - (fn [db] - (-> db ::handwrite-checks))) (re-frame/reg-sub ::change-expense-accounts @@ -85,23 +79,21 @@ (seq filter-params) (merge filter-params) (seq table-params) (merge table-params)))) -(re-frame/reg-event-db - ::invoice-updated - (fn [db [_ invoice]] - (update-in db - [::invoice-page :invoices] - replace-by :id (assoc invoice :class "live-added")))) + (re-frame/reg-event-fx ::params-change [with-user] (fn [{:keys [user]} [_ params]] - (println "REQUERY") {:graphql {:token user - :owns-state {:single ::page} + :owns-state {:single [::data-page/page :invoices]} :query-obj (table/query params ) - :on-success [::received] + :on-success (fn [result] + (let [result (set/rename-keys (first (:invoice-page result)) + {:invoices :data})] + + [::data-page/received :invoices result])) :on-error [::events/page-failed]} :set-uri-params (dissoc params :status @@ -112,45 +104,32 @@ ::unmounted (fn [{:keys [db]} _] {:db (dissoc db ::invoice-page ::table/table-params ::side-bar/filters ::side-bar/settled-filters ::last-params) - :forward-events {:unregister ::updated} - ::track/dispose {:id ::params}})) + :dispatch [::data-page/dispose :invoices] + :forward-events [{:unregister ::updated}] + ::track/dispose [{:id ::params}]})) (re-frame/reg-event-fx ::mounted (fn [{:keys [db]} _] - {::track/register {:id ::params - :subscription [::params] - :event-fn (fn [params] - [::params-change params])} - :forward-events {:register ::updated - :events #{::table/invoice-updated} - :dispatch-to [::invoice-updated]}})) + {::track/register [{:id ::params + :subscription [::params] + :event-fn (fn [params] + [::params-change params])}] + :forward-events [{:register ::updated + :events #{::table/invoice-updated ::form/updated} + :dispatch-to [::data-page/entity-updated :invoices]} -(re-frame/reg-event-db - ::received - (fn [db [_ data]] - (-> db - (update ::invoice-page merge (first (:invoice-page data))) - (assoc-in [:status :loading] false)))) + {:register ::checks-printed + :events #{::form/checks-printed} + :dispatch-to [::checks-printed]}]})) -(re-frame/reg-event-db - ::toggle-check - [(re-frame/path [::invoice-page :checked])] - (fn [db [_ new]] - new)) - -(re-frame/reg-event-db - ::remove-check - [(re-frame/path [::invoice-page :checked])] - (fn [db [_ to-remove]] - (let [db (or db #{})] - (disj db to-remove)))) (re-frame/reg-sub ::checked-invoices - :<- [::invoice-page] - (fn [page] - (filter (comp #(get (:checked page) %) :id) (:invoices page)))) + :<- [::data-page/data :invoices] + :<- [::data-page/checked :invoices] + (fn [[data checked]] + (filter (comp #(get checked %) :id) (:data data)))) @@ -165,18 +144,7 @@ :bank-account-id (:id (first @(re-frame/subscribe [::subs/bank-accounts]))) :invoices (map #(assoc % :amount (:outstanding-balance %)) invoices )} ))))) -(re-frame/reg-event-fx - ::handwrite-checks - (fn [{:keys [db]} _] - (let [invoices @(re-frame/subscribe [::checked-invoices]) - invoices (map #(assoc % :amount (:outstanding-balance %)) invoices)] - - {:dispatch [::events/modal-status ::handwrite-checks {:visible? true}] - :db (-> db - (forms/stop-form ::form/form) - (update-in [::invoice-page :print-checks-shown?] #(not %) ) - (assoc-in [::handwrite-checks] {:bank-account-id (:id (first @(re-frame/subscribe [::subs/real-bank-accounts]))) - :invoices invoices } ))}))) + (re-frame/reg-event-db ::cancel-advanced-print @@ -204,23 +172,8 @@ i)))))) -(re-frame/reg-event-db - ::action-failed - [(re-frame/path [::invoice-page])] - (fn [db [_ result]] - (-> db - (assoc :action-notification (first (map :message result))) - (assoc :print-checks-loading? false)))) -(re-frame/reg-event-db - ::edit-handwritten-payment - (fn [db [_ which f v]] - (update-in db [::handwrite-checks :invoices] - (fn [is] - (for [i is] - (if (= which (:id i)) - (assoc-in i f v) - i)))))) + (defn print-checks-query [invoice-payments bank-account-id type client-id] {:venia/operation {:operation/type :mutation @@ -238,10 +191,10 @@ ::print-checks (fn [{:keys [db]} [_ bank-account-id type]] {:db (-> db - (assoc-in [::invoice-page :print-checks-shown?] false ) - (assoc-in [::invoice-page :print-checks-loading?] true )) + (assoc-in [::invoice-page :print-checks-shown?] false )) :graphql {:token (-> db :user) + :owns-state {:single ::print-checks} :query-obj (print-checks-query (map (fn [{:keys [id outstanding-balance] }] {:invoice-id id @@ -250,8 +203,7 @@ bank-account-id type (:client db)) - :on-success [::checks-created] - :on-error [::action-failed]}})) + :on-success [::checks-created]}})) @@ -299,15 +251,13 @@ (merge i (invoices-by-id (:id i)))) invoices))) (assoc-in [::invoice-page :checked] nil) - (assoc-in [::invoice-page :print-checks-loading?] false) - (assoc-in [::invoice-page :action-notification] nil) (assoc-in [::advanced-print-checks :printing?] false) (assoc-in [::advanced-print-checks :shown?] false)) :dispatch [::checks-printed pdf-url]}))) (re-frame/reg-event-db ::checks-printed - (fn [db [_ pdf-url :as g]] + (fn [db [_ [_ pdf-url :as g]]] (-> db (assoc-in [::check-results :shown?] true) (assoc-in [::check-results :pdf-url] pdf-url)))) @@ -321,60 +271,9 @@ :location (first (:locations @(re-frame/subscribe [::subs/client])))}]})) -(re-frame/reg-event-fx - ::handwrite-checks-save - (fn [{:keys [db]} _] - (let [{:keys [date invoices check-number bank-account-id]} @(re-frame/subscribe [::handwrite-checks]) - invoice-amounts (by :id (comp js/parseFloat :amount) invoices)] - - {:graphql - {:token (-> db :user) - :query-obj {:venia/operation {:operation/type :mutation - :operation/name "AddHandwrittenCheck"} - - :venia/queries [{:query/data [:add-handwritten-check - {:date date - :invoice_payments (map (fn [x] - {:invoice-id (:id x) - :amount (invoice-amounts (:id x))}) - invoices) - :check-number check-number - :bank-account-id bank-account-id - } - [[:invoices invoice-read]]]}]} - :on-success [::handwrite-checks-succeeded] - :on-error [::handwrite-checks-failed]}}))) - -(re-frame/reg-event-fx - ::handwrite-checks-failed - (fn [{:keys [db]} [_ result]] - - {:dispatch [::events/modal-failed ::handwrite-checks (:message (first result))]})) - -(re-frame/reg-event-fx - ::handwrite-checks-succeeded - (fn [{:keys [db]} [_ {:keys [add-handwritten-check] :as result}]] - (let [invoices-by-id (by :id (:invoices add-handwritten-check))] - {:dispatch [::events/modal-completed ::handwrite-checks] - :db (-> db - (update-in [::invoice-page :invoices] - (fn [invoices] - (map (fn [i] - (merge i (invoices-by-id (:id i)))) - invoices))) - (dissoc ::handwrite-checks))}))) -(re-frame/reg-event-fx - ::invoice-updated - [(re-frame/path [::invoice-page :invoices])] - (fn [{:keys [db]} [_ [_ invoice]]] - (let [by-id (by :id db )] - {:db (if (by-id (:id invoice)) - (merge-by db :id invoice) - (into [invoice] db))}))) - (re-frame/reg-event-fx ::invoice-edited [(re-frame/path [::invoice-page :invoices])] @@ -455,99 +354,152 @@ :max outstanding-balance :step "0.01"}]]]]]])]]]))) +;; HANDWRITE CHECKS +(def handwrite-checks-form (forms/vertical-form {:submit-event [::handwrite-checks-save] + :change-event [::forms/change ::handwrite-checks] + :can-submit [::can-submit-handwrite-checks] + :id ::handwrite-checks})) (defn handwrite-checks-modal [] (let [{:keys [checked]} @(re-frame/subscribe [::invoice-page]) - {:keys [invoices] :as handwrite-checks} @(re-frame/subscribe [::handwrite-checks]) change-event [::events/change-form [::handwrite-checks]] - current-client @(re-frame/subscribe [::subs/client])] - + current-client @(re-frame/subscribe [::subs/client]) + real-bank-accounts @(re-frame/subscribe [::subs/real-bank-accounts]) + {:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::handwrite-checks]) + {:keys [form-inline horizontal-field field raw-field error-notification submit-button]} handwrite-checks-form] - [action-modal {:id ::handwrite-checks - :title "Handwrite Check" - :action-text "Save" - :save-event [::handwrite-checks-save] - :can-submit? (cond (seq (filter - (fn [{:keys [outstanding-balance amount]}] - (does-amount-exceed-outstanding? amount outstanding-balance )) - invoices)) - false + (form-inline {} + [:<> + [:div.field + [:label.label "Pay using"] + [:div.control + [:span.select + [raw-field + [:select {:type "select" + :field :bank-account-id} + (for [{:keys [id number name]} real-bank-accounts] + ^{:key id} [:option {:value id} name])]]]]] - :else - (and (not (blank? (:check-number handwrite-checks))) - (not (blank? (:date handwrite-checks))))) - } - [horizontal-field - [:label.label "Pay using"] - [:span.select - [bind-field - [:select {:type "select" - :field :bank-account-id - :event change-event - :subscription handwrite-checks} - (for [{:keys [id number name]} @(re-frame/subscribe [::subs/real-bank-accounts])] - ^{:key id} [:option {:value id} name])]]]] + (field "Date" + [date-picker {:class-name "input" + :class "input" + :format-week-number (fn [] "") + :previous-month-button-label "" + :placeholder "mm/dd/yyyy" + :next-month-button-label "" + :next-month-label "" + :type "date" + :field [:date] + :spec ::invoice/date}]) + + + (field "Check number" + [:input.input {:type "number" + :field [:check-number]}]) + + [:table.table.is-fullwidth + [:thead + [:tr + [:th "Invoice ID"] + [:th {:style {"width" "14em"}} "Payment"]]] + [:tbody + (doall + (for [{:keys [payment outstanding-balance invoice-number id] :as i} (:invoices data)] + ^{:key id} + [:tr + [:td invoice-number] + + [:td [:div.field.has-addons.is-extended + [:p.control [:a.button.is-static "$"]] + [:p.control + + (raw-field + [:input.input.has-text-right {:type "number" + :field [:invoice-amounts id :amount] + #_#_:max outstanding-balance + :step "0.01"}])]]]]))]]]))) + +(re-frame/reg-sub + ::can-submit-handwrite-checks + :<- [::forms/form ::handwrite-checks] + (fn [{ {:keys [check-number date invoices invoice-amounts]} :data}] + (boolean (cond (seq (filter + (fn [{:keys [id outstanding-balance]}] + (does-amount-exceed-outstanding? (get-in invoice-amounts [id :amount]) outstanding-balance )) + invoices)) + false + + :else + (and (not (str/blank? check-number)) + (not (str/blank? date))))))) + +(re-frame/reg-event-fx + ::handwrite-checks + (fn [{:keys [db]} _] + (let [invoices @(re-frame/subscribe [::checked-invoices])] - - - - [horizontal-field - [:label.label "Date"] - [bind-field - [date-picker {:class-name "input" - :class "input" - :format-week-number (fn [] "") - :previous-month-button-label "" - :placeholder "mm/dd/yyyy" - :next-month-button-label "" - :next-month-label "" - :type "date" - :field [:date] - :event change-event - :spec ::invoice/date - :popper-props (clj->js {:placement "right"}) - :subscription handwrite-checks}]]] + {:dispatch [::modal/modal-requested {::handwrite-checks {:visible? true} + :title "Handwrite checks" + :body [handwrite-checks-modal] + :confirm {:value "Save handwritten check" + :status-from [::status/single ::handwrite-checks] + :class "is-primary" + :on-click (dispatch-event [::handwrite-checks-save]) + :can-submit [::can-submit-handwrite-checks] + :close-event [::status/completed ::form]}}] + :db (-> db + (forms/stop-form ::form/form) + (forms/start-form ::handwrite-checks + {:bank-account-id (:id (first @(re-frame/subscribe [::subs/real-bank-accounts]))) + :invoices invoices + :invoice-amounts (into {} + (map (fn [i] [(:id i) + {:amount (:outstanding-balance i)}]) + invoices))}))}))) - [horizontal-field - [:label.label "Check number"] - [bind-field - [:input.input {:type "number" - :field [:check-number] - :event change-event - :subscription handwrite-checks}]]] - [:table.table.is-fullwidth - [:thead - [:tr - [:th "Invoice ID"] - [:th {:style {"width" "10em"}} "Payment"]]] - [:tbody - (for [{:keys [payment outstanding-balance invoice-number id] :as i} invoices] - ^{:key id} - [:tr - [:td invoice-number] - - [:td [:div.field.has-addons.is-extended - [:p.control [:a.button.is-static "$"]] - [:p.control - [bind-field - [:input.input {:type "number" - :field :amount - :event [::edit-handwritten-payment id] - :subscription i - :value payment - #_#_:max outstanding-balance - :step "0.01"}]]]]]])]]])) + +(re-frame/reg-event-fx + ::handwrite-checks-save + [with-user (forms/in-form ::handwrite-checks)] + (fn [{:keys [db user]} _] + (let [{:keys [date invoices invoice-amounts check-number bank-account-id]} (:data db)] + {:graphql + {:token user + :owns-state {:single ::handwrite-checks} + :query-obj {:venia/operation {:operation/type :mutation + :operation/name "AddHandwrittenCheck"} + + :venia/queries [{:query/data [:add-handwritten-check + {:date date + :invoice_payments (map (fn [x] + {:invoice-id (:id x) + :amount (get-in invoice-amounts [(:id x) :amount])}) + invoices) + :check-number check-number + :bank-account-id bank-account-id + } + [[:invoices invoice-read]]]}]} + :on-success [::handwrite-checks-succeeded]}}))) + +(re-frame/reg-event-fx + ::handwrite-checks-succeeded + [(forms/triggers-stop ::handwrite-checks)] + (fn [{:keys [db]} [_ {:keys [add-handwritten-check] :as result}]] + (let [invoices-by-id (by :id (:invoices add-handwritten-check))] + {:dispatch-n (into [[::modal/modal-closed]] + (map + (fn [i] + [::data-page/entity-updated :invoices [_ (assoc i :class "live-added")]]) + (:invoices add-handwritten-check)))}))) - - -(defn pay-button [{:keys [print-checks-shown? print-checks-loading?]}] +(defn pay-button [] (let [current-client @(re-frame/subscribe [::subs/client]) checked-invoices @(re-frame/subscribe [::checked-invoices])] [:div @@ -561,9 +513,7 @@ "" "disabled") - :class (if print-checks-loading? - "is-loading" - "")} + :class (status/class-for @(re-frame/subscribe [::status/single ::print-checks]))} "Pay " (when (> (count checked-invoices )) (str @@ -595,7 +545,7 @@ (into [:div.tags ] (map (fn [{:keys [id invoice-number]}] [:span.tag.is-medium invoice-number [:button.delete.is-small {:on-click - (dispatch-event [::remove-check id])}]]) checked-invoices))]] + (dispatch-event [::data-page/remove-check :invoices id])}]]) checked-invoices))]] )) (defn check-results-dialog [] @@ -615,23 +565,21 @@ ])))) (defn unpaid-invoices-content [{:keys [status] :as params}] - (let [{:keys [checked action-notification print-checks-shown? print-checks-loading? advanced-print-shown? vendor-filter]} @(re-frame/subscribe [::invoice-page]) + (let [page @(re-frame/subscribe [::data-page/page :invoices]) current-client @(re-frame/subscribe [::subs/client])] [:div #_[:h1.title (str (str/capitalize (or status "all")) " invoices")] - (when action-notification - [:div.notification - action-notification]) + [status/status-notification {:statuses [[::status/single ::print-checks]]}] + (when (= status :unpaid) - [pay-button {:print-checks-shown? print-checks-shown? :print-checks-loading? print-checks-loading?}]) - [table/invoice-table {:id :unpaid - :invoice-page @(re-frame/subscribe [::invoice-page]) - :status @(re-frame/subscribe [::status/single ::page]) - + [pay-button]) + [table/invoice-table {:id (:id page) + :checked (:checked page) + :data (:data page) + :status (:status page) :check-boxes (= status :unpaid) - :checked checked :on-check-changed (fn [new] - (re-frame/dispatch [::toggle-check new ])) + (re-frame/dispatch [::data-page/toggle-check :invoices new ])) :expense-event [::expense-accounts-dialog/change-expense-accounts]}]])) (defn unpaid-invoices-page [params] @@ -648,7 +596,6 @@ :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-edited] :invoice-printed [::checks-printed]}]]}]))}))