diff --git a/src/clj/auto_ap/graphql/transactions.clj b/src/clj/auto_ap/graphql/transactions.clj index 241b99e7..a3647490 100644 --- a/src/clj/auto_ap/graphql/transactions.clj +++ b/src/clj/auto_ap/graphql/transactions.clj @@ -128,7 +128,28 @@ [:client/locations] (:client_id (:filters args)))) all-ids (get-ids-matching-filters args) - transactions (d/pull-many (d/db conn) '[:db/id :transaction/amount] (vec all-ids))] + transactions (d/pull-many (d/db conn) '[:db/id :transaction/amount] (vec all-ids)) + account-total (reduce + 0 (map (fn [x] (:percentage x)) (:accounts args)))] + (when + (and + (seq (:accounts args)) + (not (dollars= 1.0 account-total))) + (let [error (str "Account total (" account-total ") does not reach 100%")] + (throw (ex-info error {:validation-error error})))) + + (doseq [a (:accounts args) + :let [{:keys [:account/location :account/name]} (d/entity (d/db conn) (:account_id a)) + client (d/entity (d/db conn) (:client_id (:filters args)))]] + (when (and location (not= location (:location a))) + (let [err (str "Account " name " uses location " (:location a) ", but is supposed to be " location)] + (throw (ex-info err {:validation-error err}) ))) + + (when (and (not location) + (not (get (into #{"Shared"} (:client/locations client)) + (:location a)))) + (let [err (str "Account " name " uses location " (:location a) ", but doesn't belong to the client.")] + (throw (ex-info err {:validation-error err}) )))) + (log/info "Bulk coding " (count all-ids) args) (audit-transact-batch (mapcat (fn [i] diff --git a/src/cljs/auto_ap/views/pages/transactions.cljs b/src/cljs/auto_ap/views/pages/transactions.cljs index ac3b3403..eee88869 100644 --- a/src/cljs/auto_ap/views/pages/transactions.cljs +++ b/src/cljs/auto_ap/views/pages/transactions.cljs @@ -25,7 +25,7 @@ (re-frame/reg-event-fx ::params-change [with-user] - (fn [{:keys [user]} [_ params]] + (fn [{:keys [user db]} [_ params]] (try {:graphql {:token user :owns-state {:single [::data-page/page ::page]} @@ -37,34 +37,13 @@ :end]] :query/alias :result}]} :on-success (fn [result] - [::data-page/received ::page (:result result)])}} + [::data-page/received ::page (:result result)])} + :db (-> db + (forms/stop-form ::edit/form))} (catch js/Error e ;; this catches an error where you choose a parameter, change to invoices page, then change to voided invoices (println "Error!" e))))) -(re-frame/reg-event-fx - ::bulk-change-transaction-status - (fn [cofx [_ status params]] - (let [checked @(re-frame/subscribe [::data-page/checked ::page]) - checked-params (get checked "header") - specific-transactions (map :id (vals (dissoc checked "header")))] - (println checked-params) - {:db (-> (:db cofx) - (assoc-in [:status :loading] true)) - :graphql {:token (-> cofx :db :user) - :owns-state {:single ::bulk-change-transaction-status} - :query-obj - {:venia/operation {:operation/type :mutation - :operation/name "BulkChangeTransactionStatus"} - :venia/queries [{:query/data - [:bulk-change-transaction-status - {:filters (some-> checked-params data-params->query-params) - :status status - :ids specific-transactions} - [:message]]}]} - :on-success (fn [_] - [::params-change params])}}))) - (re-frame/reg-event-fx ::delete-selected (fn [cofx [_ params suppress]] @@ -153,13 +132,11 @@ checked @(re-frame/subscribe [::data-page/checked ::page])] [:div [:h1.title "Transactions"] - [status/status-notification {:statuses [[::status/single ::bulk-change-transaction-status] - [::status/single ::delete-selected] + [status/status-notification {:statuses [[::status/single ::delete-selected] [::status/single ::manual-import]]}] (when is-admin? [:div.is-pulled-right [:div.buttons - (into [:div.tags ] (map (fn [[z {:keys [id]}]] (if (= "header" z) [:span.tag.is-medium {:on-click @@ -171,22 +148,6 @@ checked)) [:button.button.is-outlined.is-primary {:on-click (dispatch-event [::manual/opening])} "Manual Yodlee Import"] - [:button.button.is-warning {:on-click (dispatch-event [::bulk-change-transaction-status :unapproved params]) - :class (status/class-for @(re-frame/subscribe [::status/single ::bulk-change-transaction-status])) - :disabled (or (status/disabled-for @(re-frame/subscribe [::status/single ::bulk-change-transaction-status])) - (not (seq checked)))} - "Unapprove"] - - [:button.button.is-warning {:on-click (dispatch-event [::bulk-change-transaction-status :excluded params]) - :class (status/class-for @(re-frame/subscribe [::status/single ::bulk-change-transaction-status])) - :disabled (or (status/disabled-for @(re-frame/subscribe [::status/single ::bulk-change-transaction-status])) - (not (seq checked)))} - "Exclude"] - [:button.button.is-warning {:on-click (dispatch-event [::bulk-change-transaction-status :requires-feedback params]) - :class (status/class-for @(re-frame/subscribe [::status/single ::bulk-change-transaction-status])) - :disabled (or (status/disabled-for @(re-frame/subscribe [::status/single ::bulk-change-transaction-status])) - (not (seq checked)))} - "Client Review"] (when (:client-id params) [:button.button.is-warning {:on-click (dispatch-event [::bulk/code-requested checked params]) :disabled (not (seq checked))} diff --git a/src/cljs/auto_ap/views/pages/transactions/bulk_updates.cljs b/src/cljs/auto_ap/views/pages/transactions/bulk_updates.cljs index 73a85594..eefc3955 100644 --- a/src/cljs/auto_ap/views/pages/transactions/bulk_updates.cljs +++ b/src/cljs/auto_ap/views/pages/transactions/bulk_updates.cljs @@ -13,7 +13,8 @@ :refer [data-params->query-params]] [auto-ap.views.utils :refer [dispatch-event with-user]] [clojure.string :as str] - [re-frame.core :as re-frame])) + [re-frame.core :as re-frame] + [auto-ap.views.pages.data-page :as data-page])) (re-frame/reg-sub ::can-submit @@ -23,8 +24,10 @@ (re-frame/reg-event-fx ::coded - (fn [_ [_ _]] - {:dispatch [::modal/modal-closed]})) + (fn [_ [_ _ _]] + {:dispatch-n [[::modal/modal-closed] + [:auto-ap.views.pages.transactions/params-change + @(re-frame/subscribe [::data-page/params :auto-ap.views.pages.transactions/page])]]})) (re-frame/reg-event-fx ::code-selected @@ -57,6 +60,7 @@ :on-success (fn [result] [::coded (:message result) + checked-params ])}}))) (re-frame/reg-event-db @@ -128,8 +132,5 @@ :on-click (dispatch-event [::code-selected checked] )} :close-event [::status/completed ::code-selected]}] :db (-> db - (forms/start-form ::form {:accounts [{:id (str "new-" (random-uuid)) - :amount-mode "%" - :amount-percentage 100 - :location nil}] + (forms/start-form ::form {:accounts [] :client @(re-frame/subscribe [::subs/client (:client-id params)])}))}))) diff --git a/src/cljs/auto_ap/views/pages/transactions/form.cljs b/src/cljs/auto_ap/views/pages/transactions/form.cljs index 01d14d37..2ed439ab 100644 --- a/src/cljs/auto_ap/views/pages/transactions/form.cljs +++ b/src/cljs/auto_ap/views/pages/transactions/form.cljs @@ -45,7 +45,7 @@ (re-frame/reg-sub ::can-submit :<- [::forms/form ::form] - (fn [{:keys [data status]} _] + (fn [{:keys [status]} _] (not= :loading status))) @@ -181,7 +181,7 @@ (re-frame/reg-event-fx ::edited [(forms/triggers-stop ::form)] - (fn [{:keys [db]} [_ transaction]] + (fn [_ [_ _]] {})) @@ -204,7 +204,7 @@ :submit-event [::saving ] :id ::form})) -(defn potential-transaction-rule-matches-box [{:keys [potential-transaction-rule-matches] :as params}] +(defn potential-transaction-rule-matches-box [{:keys [potential-transaction-rule-matches]}] (let [states @(re-frame/subscribe [::status/multi ::matching])] [:div.box [:div.columns @@ -224,7 +224,7 @@ -(defn potential-payment-matches-box [{:keys [potential-payment-matches] :as params}] +(defn potential-payment-matches-box [{:keys [potential-payment-matches]}] (let [states @(re-frame/subscribe [::status/multi ::matching])] [:div [:h1.subtitle.is-5 "Potentially matching payments:"] @@ -241,7 +241,7 @@ :disabled (status/disabled-if-any states)} "Match"]]]))]])) -(defn potential-autopay-invoices-matches-box [{:keys [potential-autopay-invoices-matches] :as params}] +(defn potential-autopay-invoices-matches-box [{:keys [potential-autopay-invoices-matches]}] (let [states @(re-frame/subscribe [::status/multi ::matching])] [:div [:div.notification.is-light.is-info "This transaction may match the following autopay invoice(s)."] @@ -265,7 +265,7 @@ "Match"]]]))]])) -(defn potential-unpaid-invoices-matches-box [{:keys [potential-unpaid-invoices-matches] :as params}] +(defn potential-unpaid-invoices-matches-box [{:keys [potential-unpaid-invoices-matches]}] (let [states @(re-frame/subscribe [::status/multi ::matching])] [:div [:div.notification.is-light.is-info "This transaction may match the following unpaid invoice(s)."] @@ -294,9 +294,9 @@ #_(println "Provider is" Provider) (def ^js/React.Consumer CurrentTabConsumer (. current-tab-context -Consumer)) -(defn tabs [props & children] +(defn tabs [props & _] (let [current-tab (r/atom (:default-tab props))] - (fn [props & children] + (fn [_ & _] (let [current-tab-v @current-tab] (r/create-element CurrentTabProvider #js {:value #js {:current-tab current-tab-v :on-tab-clicked (fn [new] @@ -313,12 +313,12 @@ first (drop 2)))])))))) -(defn tab [props & children] +(defn tab [props & _] [:> CurrentTabConsumer {} (fn [consume] (let [{:strs [current-tab on-tab-clicked]} (js->clj consume)] (r/as-element - [:li (if (= (:key props) + [:li (when (= (:key props) current-tab) {:class "is-active"}) [:a {:on-click (fn [] (on-tab-clicked (:key props)))} (:title props)]])))]) @@ -326,10 +326,9 @@ (defn form [_] [layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form])} - (let [change-event [::forms/change ::form] - {:keys [data] } @(re-frame/subscribe [::forms/form ::form]) + (let [{:keys [data] } @(re-frame/subscribe [::forms/form ::form]) locations @(re-frame/subscribe [::subs/locations-for-client (:id (:client data))]) - {:keys [form-inline form field raw-field error-notification submit-button ]} transaction-form + {:keys [form-inline field error-notification submit-button ]} transaction-form is-admin? @(re-frame/subscribe [::subs/is-admin?]) is-power-user? @(re-frame/subscribe [::subs/is-power-user?]) @@ -376,28 +375,26 @@ [:div.level-item "This transaction is linked to a payment "] [:div.level-item [:button.button.is-warning {:on-click (dispatch-event [::unlink])} "Unlink"]]]) [tabs {:default-tab :details} - (when + (when (and (seq (:potential-transaction-rule-matches data)) (not (:matched-rule data)) is-admin?) [tab {:title "Transaction Rule" :key :transaction-rule} [potential-transaction-rule-matches-box {:potential-transaction-rule-matches (:potential-transaction-rule-matches data)}]]) - - (when + (when (and (seq (:potential-autopay-invoices-matches data)) (not is-already-matched?) (or is-admin? is-power-user?)) [tab {:title "Autopay Invoices" :key :autopay-invoices} [potential-autopay-invoices-matches-box {:potential-autopay-invoices-matches (:potential-autopay-invoices-matches data)}]]) - (when + (when (and (seq (:potential-unpaid-invoices-matches data)) (not is-already-matched?) (or is-admin? is-power-user?)) [tab {:title "Unpaid Invoices" :key :unpaid-invoices} [potential-unpaid-invoices-matches-box {:potential-unpaid-invoices-matches (:potential-unpaid-invoices-matches data)}]]) - - (when + (when (and (seq (:potential-payment-matches data)) (not is-already-matched?) (or is-admin? is-power-user?)) @@ -426,13 +423,6 @@ should-disable-for-client?) :locations locations}]) {:key (str (:id (:vendor data)))}) - - - - - - - (field "Approval Status" [button-radio {:type "button-radio"