diff --git a/src/cljs/auto_ap/events/expense_accounts.cljs b/src/cljs/auto_ap/events/expense_accounts.cljs new file mode 100644 index 00000000..4d82b292 --- /dev/null +++ b/src/cljs/auto_ap/events/expense_accounts.cljs @@ -0,0 +1,75 @@ +(ns auto-ap.events.expense-accounts + (:require [re-frame.core :as re-frame] + [reagent.core :as r] + [clojure.string :as str] + [clojure.spec.alpha :as s] + [cljs-time.core :as c] + [goog.string :as gstring] + [auto-ap.entities.companies :as company] + [auto-ap.entities.invoice :as invoice] + [auto-ap.entities.vendors :as vendor] + [auto-ap.expense-accounts :as expense-accounts] + [auto-ap.entities.invoices-expense-accounts :as invoices-expense-accounts] + [auto-ap.views.utils :refer [dispatch-event bind-field horizontal-field date->str str->date pretty standard]] + [auto-ap.utils :refer [by replace-if]] + [auto-ap.events :as events])) + +(re-frame/reg-event-fx + ::change-expense-accounts + (fn [{:keys [db]} [_ id]] + {:dispatch [::events/modal-status ::change-expense-accounts {:visible? true}] + :db (assoc-in db [::change-expense-accounts :invoice] (get (by :id (get-in db [::invoice-page :invoices])) id))})) + +(re-frame/reg-event-fx + ::change-expense-accounts-saving + (fn [{:keys [db]} [_ id]] + (let [{:keys [id expense-accounts]} (get-in db [::change-expense-accounts :invoice])] + {:graphql + {:token (-> db :user) + :query-obj {:venia/operation {:operation/type :mutation + :operation/name "EditExpenseAccounts"} + + :venia/queries [{:query/data [:edit-expense-accounts + {:invoice-id id + :expense-accounts (map (fn [ea] {:id (:id ea) + :amount (:amount ea) + :location (:location ea) + :expense-account-id (:expense-account-id ea)}) + expense-accounts)} + [:id :total :outstanding-balance :invoice-number :date + [:vendor [:name :id]] + [:expense_accounts [:amount :id :location :expense_account_id + [:expense_account [:id :name [:parent [:id :name]]]]]] + [:company [:name :id :locations]] + [:checks [:amount [:check [:amount :s3_url :check_number ]]]] + ]]}]} + :on-success [::expense-accounts-updated]}}))) + + +(re-frame/reg-event-fx + ::expense-accounts-updated + (fn [{:keys [db]} [_ data]] + (let [updated (:edit-expense-accounts data)] + {:dispatch [::events/modal-completed ::change-expense-accounts] + :db (-> db + (update-in [::invoice-page :invoices] + + (fn [is] + + (replace-if #(= (:id %1) (:id %2)) updated is))) + (dissoc ::change-expense-accounts))}))) + +(re-frame/reg-event-db + ::add-expense-account-split + (fn [db _] + (let [{{{:keys [locations]} :company} :invoice} @(re-frame/subscribe [::change-expense-accounts])] + (update-in db [::change-expense-accounts :invoice :expense-accounts] + conj {:amount 0 :expense-account-id nil :location (first locations)})))) + +(re-frame/reg-event-db + ::remove-expense-account-split + (fn [db [_ index]] + (update-in db [::change-expense-accounts :invoice :expense-accounts] + (fn [expense-accounts] + (vec (concat (take index expense-accounts) + (drop (inc index) expense-accounts))))))) diff --git a/src/cljs/auto_ap/views/components/expense_accounts_dialog.cljs b/src/cljs/auto_ap/views/components/expense_accounts_dialog.cljs new file mode 100644 index 00000000..bf015938 --- /dev/null +++ b/src/cljs/auto_ap/views/components/expense_accounts_dialog.cljs @@ -0,0 +1,148 @@ +(ns auto-ap.views.components.expense-accounts-dialog + (:require [re-frame.core :as re-frame] + [reagent.core :as r] + [clojure.string :as str] + [clojure.spec.alpha :as s] + [cljs-time.core :as c] + [goog.string :as gstring] + [auto-ap.subs :as subs] + [auto-ap.entities.companies :as company] + [auto-ap.entities.invoice :as invoice] + [auto-ap.entities.vendors :as vendor] + [auto-ap.expense-accounts :as expense-accounts] + [auto-ap.entities.invoices-expense-accounts :as invoices-expense-accounts] + [auto-ap.views.components.modal :refer [modal action-modal]] + [auto-ap.views.utils :refer [dispatch-event bind-field horizontal-field date->str str->date pretty standard]] + [auto-ap.utils :refer [by replace-if]] + [auto-ap.views.components.typeahead :refer [typeahead]] + [auto-ap.events :as events])) + +(re-frame/reg-sub + ::change-expense-accounts + (fn [db] + (-> db ::change-expense-accounts))) + +(re-frame/reg-event-fx + ::change-expense-accounts + (fn [{:keys [db]} [_ i]] + {:dispatch [::events/modal-status ::change-expense-accounts {:visible? true}] + :db (assoc-in db [::change-expense-accounts :invoice] i)})) + +(re-frame/reg-event-fx + ::change-expense-accounts-saving + (fn [{:keys [db]} [_ on-success id ]] + (let [{:keys [id expense-accounts]} (get-in db [::change-expense-accounts :invoice])] + {:graphql + {:token (-> db :user) + :query-obj {:venia/operation {:operation/type :mutation + :operation/name "EditExpenseAccounts"} + + :venia/queries [{:query/data [:edit-expense-accounts + {:invoice-id id + :expense-accounts (map (fn [ea] {:id (:id ea) + :amount (:amount ea) + :location (:location ea) + :expense-account-id (:expense-account-id ea)}) + expense-accounts)} + [:id :total :outstanding-balance :invoice-number :date + [:vendor [:name :id]] + [:expense_accounts [:amount :id :location :expense_account_id + [:expense_account [:id :name [:parent [:id :name]]]]]] + [:company [:name :id :locations]] + [:checks [:amount [:check [:amount :s3_url :check_number ]]]] + ]]}]} + :on-success on-success}}))) + + + + +(re-frame/reg-event-db + ::add-expense-account-split + (fn [db _] + (let [{{{:keys [locations]} :company} :invoice} @(re-frame/subscribe [::change-expense-accounts])] + (update-in db [::change-expense-accounts :invoice :expense-accounts] + conj {:amount 0 :expense-account-id nil :location (first locations)})))) + +(re-frame/reg-event-db + ::remove-expense-account-split + (fn [db [_ index]] + (update-in db [::change-expense-accounts :invoice :expense-accounts] + (fn [expense-accounts] + (vec (concat (take index expense-accounts) + (drop (inc index) expense-accounts))))))) + + +(defn change-expense-accounts-modal [{:keys [updated-event]}] + (let [{{:keys [expense-accounts total ] :or {expense-accounts [] total 0} {:keys [locations]} :company} :invoice :as data} @(re-frame/subscribe [::change-expense-accounts]) + multi-location? (> (count locations) 1) + change-event [::events/change-form [::change-expense-accounts]] + chooseable-expense-accounts @(re-frame/subscribe [::subs/chooseable-expense-accounts]) + expense-accounts-total (->> expense-accounts + (map :amount) + (map js/parseFloat) + (map #(or % 0)) + (reduce + 0)) + does-add-up? (= expense-accounts-total (js/parseFloat total))] + [action-modal {:id ::change-expense-accounts + :title "Change expense accounts" + :action-text "Save" + :save-event [::change-expense-accounts-saving updated-event] + :can-submit? (and does-add-up? + (s/valid? (s/* ::invoices-expense-accounts/invoices-expense-account) expense-accounts))} + + [:div + [:a.button.is-primary {:on-click (dispatch-event [::add-expense-account-split])} "Add split"]] + [:table.table + [:thead + [:tr + [:th {:style {:width "500px"}} "Expense Account"] + (when multi-location? + [:th {:style {:width "200px"}} "Location"]) + [:th {:style {:width "300px"}} "Amount"] + [:th {:style {:width "5em"}}]]] + [:tbody + (for [[expense-account index] (map vector expense-accounts (range))] + ^{:key index} + [:tr + [:td.expandable [:div.control + [bind-field + [typeahead {:matches (map (fn [x] [(:id x) (str (:id x) " - " (:name x))]) chooseable-expense-accounts) + :type "typeahead" + :field [:invoice :expense-accounts index :expense-account-id] + :event change-event + :spec ::invoice/vendor-id + :subscription data}]]]] + + (when multi-location? + [:td + (if-let [forced-location (-> expense-account :expense-account-id expense-accounts/expense-accounts :location)] + [:div.select + [:select {:disabled "disabled" :value forced-location} [:option {:value forced-location} forced-location]]] + [:div.select + [bind-field + [:select {:type "select" + :field [:invoice :expense-accounts index :location] + :spec (set locations) + :event change-event + :subscription data} + (map (fn [l] ^{:key l} [:option {:value l} l]) locations)]]])]) + + [:td + [:div.control + [:div.field.has-addons.is-extended + [:p.control [:a.button.is-static "$"]] + [:p.control + [bind-field + [:input.input {:type "number" + :field [:invoice :expense-accounts index :amount] + :event change-event + :subscription data + :value (get-in data [:invoice :expense-accounts index :amount]) + + :max (:total data) + :step "0.01"}]]]]]] + [:td [:a.button {:on-click (dispatch-event [::remove-expense-account-split index])} [:i.fa.fa-times]]]] + ) + [:tr + [:th "TOTAL"] + [:th (str (gstring/format "$%.2f" expense-accounts-total ) " (" (gstring/format "$%.2f" total ) ")" )]]]]])) diff --git a/src/cljs/auto_ap/views/components/invoice_table.cljs b/src/cljs/auto_ap/views/components/invoice_table.cljs index 6cefe61e..00ae9dbc 100644 --- a/src/cljs/auto_ap/views/components/invoice_table.cljs +++ b/src/cljs/auto_ap/views/components/invoice_table.cljs @@ -169,7 +169,7 @@ :aria-haspopup true :tab-index "0" - #_#_:on-blur (delayed-dispatch [::toggle-expense-accounts id]) + :on-blur (delayed-dispatch [::toggle-expense-accounts id]) :on-focus (dispatch-event [::toggle-expense-accounts id]) } "Accounts"]] [:div.dropdown-menu {:role "menu"} @@ -181,7 +181,7 @@ [:hr.dropdown-divider] (when expense-event - [:a.dropdown-item.is-primary {:on-click (dispatch-event (conj expense-event id))} "Change"])]]]) + [:a.dropdown-item.is-primary {:on-click (dispatch-event (conj expense-event i))} "Change"])]]]) [:span {:style {:margin-left "1em"}}] (when on-edit-invoice [:button.button {:on-click (fn [] (on-edit-invoice i))} [:span.icon [:i.fa.fa-pencil]]]) diff --git a/src/cljs/auto_ap/views/pages/paid_invoices.cljs b/src/cljs/auto_ap/views/pages/paid_invoices.cljs index fbacb641..ef6640d1 100644 --- a/src/cljs/auto_ap/views/pages/paid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/paid_invoices.cljs @@ -4,14 +4,13 @@ [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.utils :refer [by replace-if]] [auto-ap.views.pages.check :as check] [auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table] + [auto-ap.views.components.expense-accounts-dialog :as expense-accounts-dialog] [auto-ap.subs :as subs])) - - (re-frame/reg-sub ::invoice-page (fn [db] @@ -47,6 +46,19 @@ (fn [cofx [_ params]] {:dispatch [::params-change @(re-frame/subscribe [::params])]})) +(re-frame/reg-event-fx + ::expense-accounts-updated + (fn [{:keys [db]} [_ data]] + (let [updated (:edit-expense-accounts data)] + {:dispatch [::events/modal-completed ::expense-accounts-dialog/change-expense-accounts] + :db (-> db + (update-in [::invoice-page :invoices] + + (fn [is] + + (replace-if #(= (:id %1) (:id %2)) updated is))) + (dissoc ::change-expense-accounts))}))) + (def paid-invoices-page (with-meta @@ -60,8 +72,11 @@ :params (re-frame/subscribe [::params]) :invoice-page (re-frame/subscribe [::invoice-page]) :status (re-frame/subscribe [::subs/status]) + :expense-event [::expense-accounts-dialog/change-expense-accounts] :on-params-change (fn [params] (re-frame/dispatch [::params-change params])) - :check-boxes false}]])) + :check-boxes false}] + [expense-accounts-dialog/change-expense-accounts-modal + {:updated-event [::expense-accounts-updated]}]])) {: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 0801ff1d..20f09213 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -8,6 +8,7 @@ [auto-ap.entities.companies :as company] [auto-ap.entities.invoice :as invoice] [auto-ap.entities.vendors :as vendor] + [auto-ap.views.components.expense-accounts-dialog :as expense-accounts-dialog] [auto-ap.expense-accounts :as expense-accounts] [auto-ap.entities.invoices-expense-accounts :as invoices-expense-accounts] [auto-ap.views.utils :refer [dispatch-event bind-field horizontal-field date->str str->date pretty standard]] @@ -15,6 +16,7 @@ [auto-ap.views.pages.check :as check] [auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table] [auto-ap.views.components.modal :refer [modal action-modal]] + [auto-ap.views.components.expense-accounts-dialog :refer [change-expense-accounts-modal ] :as change-expense-accounts] [auto-ap.views.components.typeahead :refer [typeahead]] [auto-ap.subs :as subs] [auto-ap.events :as events])) @@ -387,42 +389,16 @@ (assoc void-invoice :class "live-removed") i)) is))))})) -(re-frame/reg-event-fx - ::change-expense-accounts - (fn [{:keys [db]} [_ id]] - {:dispatch [::events/modal-status ::change-expense-accounts {:visible? true}] - :db (assoc-in db [::change-expense-accounts :invoice] (get (by :id (get-in db [::invoice-page :invoices])) id))})) -(re-frame/reg-event-fx - ::change-expense-accounts-saving - (fn [{:keys [db]} [_ id]] - (let [{:keys [id expense-accounts]} (get-in db [::change-expense-accounts :invoice])] - {:graphql - {:token (-> db :user) - :query-obj {:venia/operation {:operation/type :mutation - :operation/name "EditExpenseAccounts"} - - :venia/queries [{:query/data [:edit-expense-accounts - {:invoice-id id - :expense-accounts (map (fn [ea] {:id (:id ea) - :amount (:amount ea) - :location (:location ea) - :expense-account-id (:expense-account-id ea)}) - expense-accounts)} - [:id :total :outstanding-balance :invoice-number :date - [:vendor [:name :id]] - [:expense_accounts [:amount :id :location :expense_account_id - [:expense_account [:id :name [:parent [:id :name]]]]]] - [:company [:name :id :locations]] - [:checks [:amount [:check [:amount :s3_url :check_number ]]]] - ]]}]} - :on-success [::expense-accounts-updated]}}))) + + + (re-frame/reg-event-fx ::expense-accounts-updated (fn [{:keys [db]} [_ data]] (let [updated (:edit-expense-accounts data)] - {:dispatch [::events/modal-completed ::change-expense-accounts] + {:dispatch [::events/modal-completed ::expense-accounts-dialog/change-expense-accounts] :db (-> db (update-in [::invoice-page :invoices] @@ -431,98 +407,6 @@ (replace-if #(= (:id %1) (:id %2)) updated is))) (dissoc ::change-expense-accounts))}))) - -(re-frame/reg-event-db - ::add-expense-account-split - (fn [db _] - (let [{{{:keys [locations]} :company} :invoice} @(re-frame/subscribe [::change-expense-accounts])] - (update-in db [::change-expense-accounts :invoice :expense-accounts] - conj {:amount 0 :expense-account-id nil :location (first locations)})))) - -(re-frame/reg-event-db - ::remove-expense-account-split - (fn [db [_ index]] - (update-in db [::change-expense-accounts :invoice :expense-accounts] - (fn [expense-accounts] - (vec (concat (take index expense-accounts) - (drop (inc index) expense-accounts))))))) - -(defn change-expense-accounts-modal [] - (let [{{:keys [expense-accounts total ] :or {expense-accounts [] total 0} {:keys [locations]} :company} :invoice :as data} @(re-frame/subscribe [::change-expense-accounts]) - multi-location? (> (count locations) 1) - change-event [::events/change-form [::change-expense-accounts]] - chooseable-expense-accounts @(re-frame/subscribe [::subs/chooseable-expense-accounts]) - expense-accounts-total (->> expense-accounts - (map :amount) - (map js/parseFloat) - (map #(or % 0)) - (reduce + 0)) - does-add-up? (= expense-accounts-total (js/parseFloat total))] - [action-modal {:id ::change-expense-accounts - :title "Change expense accounts" - :action-text "Save" - :save-event [::change-expense-accounts-saving] - :can-submit? (and does-add-up? - (s/valid? (s/* ::invoices-expense-accounts/invoices-expense-account) expense-accounts))} - - [:div - [:a.button.is-primary {:on-click (dispatch-event [::add-expense-account-split])} "Add split"]] - [:table.table - [:thead - [:tr - [:th {:style {:width "500px"}} "Expense Account"] - (when multi-location? - [:th {:style {:width "200px"}} "Location"]) - [:th {:style {:width "300px"}} "Amount"] - [:th {:style {:width "5em"}}]]] - [:tbody - (for [[expense-account index] (map vector expense-accounts (range))] - ^{:key index} - [:tr - [:td.expandable [:div.control - [bind-field - [typeahead {:matches (map (fn [x] [(:id x) (str (:id x) " - " (:name x))]) chooseable-expense-accounts) - :type "typeahead" - :field [:invoice :expense-accounts index :expense-account-id] - :event change-event - :spec ::invoice/vendor-id - :subscription data}]]]] - - (when multi-location? - [:td - (if-let [forced-location (-> expense-account :expense-account-id expense-accounts/expense-accounts :location)] - [:div.select - [:select {:disabled "disabled" :value forced-location} [:option {:value forced-location} forced-location]]] - [:div.select - [bind-field - [:select {:type "select" - :field [:invoice :expense-accounts index :location] - :spec (set locations) - :event change-event - :subscription data} - (map (fn [l] ^{:key l} [:option {:value l} l]) locations)]]])]) - - [:td - [:div.control - [:div.field.has-addons.is-extended - [:p.control [:a.button.is-static "$"]] - [:p.control - [bind-field - [:input.input {:type "number" - :field [:invoice :expense-accounts index :amount] - :event change-event - :subscription data - :value (get-in data [:invoice :expense-accounts index :amount]) - - :max (:total data) - :step "0.01"}]]]]]] - [:td [:a.button {:on-click (dispatch-event [::remove-expense-account-split index])} [:i.fa.fa-times]]]] - ) - [:tr - [:th "TOTAL"] - [:th (str (gstring/format "$%.2f" expense-accounts-total ) " (" (gstring/format "$%.2f" total ) ")" )]]]]])) - - (defn print-checks-modal [] (let [{:keys [checked]} @(re-frame/subscribe [::invoice-page]) {:keys [shown? invoices printing?] :as advanced-print-checks} @(re-frame/subscribe [::advanced-print-checks]) @@ -834,13 +718,13 @@ :checked checked :on-check-changed (fn [which] (re-frame/dispatch [::toggle-check which])) - :expense-event [::change-expense-accounts]}] + :expense-event [::expense-accounts-dialog/change-expense-accounts]}] [print-checks-modal] [new-invoice-modal] [edit-invoice-modal] [handwrite-checks-modal] - [change-expense-accounts-modal] + [change-expense-accounts-modal {:updated-event [::expense-accounts-updated]}] (when check-results-shown? (if pdf-url [modal