added ability to remove a transaction rule.
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
[ring/ring-defaults "0.2.1"]
|
||||
[mount "0.1.16"]
|
||||
[tolitius/yang "0.1.10"]
|
||||
|
||||
[day8.re-frame/forward-events-fx "0.0.6"]
|
||||
[ring "1.6.3" :exclusions [commons-codec
|
||||
commons-io
|
||||
clj-time
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
@keyframes flashWarning {
|
||||
from {
|
||||
background-color: #00d1b2;
|
||||
background-color: hsl(348, 100%, 61%);
|
||||
|
||||
}
|
||||
to {
|
||||
|
||||
@@ -742,7 +742,9 @@
|
||||
:approval_status {:type :transaction_approval_status}}
|
||||
|
||||
:resolve :mutation/unapprove-transactions}
|
||||
|
||||
:delete_transaction_rule {:type :id
|
||||
:args {:transaction_rule_id {:type :id}}
|
||||
:resolve :mutation/delete-transaction-rule}
|
||||
:merge_vendors {:type :id
|
||||
:args {:from {:type :id}
|
||||
:to {:type :id}}
|
||||
@@ -1060,6 +1062,7 @@
|
||||
:get-client gq-clients/get-client
|
||||
:get-user get-user
|
||||
:mutation/add-handwritten-check gq-checks/add-handwritten-check
|
||||
:mutation/delete-transaction-rule gq-transaction-rules/delete-transaction-rule
|
||||
:mutation/print-checks print-checks
|
||||
:mutation/reject-invoices gq-invoices/reject-invoices
|
||||
:mutation/approve-invoices gq-invoices/approve-invoices
|
||||
|
||||
@@ -45,6 +45,15 @@
|
||||
:account account_id
|
||||
:location location}))
|
||||
|
||||
(defn delete-transaction-rule [context {:keys [transaction_rule_id ]} value]
|
||||
(assert-admin (:id context))
|
||||
(let [existing-transaction-rule (tr/get-by-id transaction_rule_id)]
|
||||
(when-not (:transaction-rule/description existing-transaction-rule)
|
||||
(throw (ex-info "Transaction rule not found" {:validation-error "Transaction Rule not found"})))
|
||||
|
||||
@(d/transact (d/connect uri) [[:db/retractEntity transaction_rule_id]])
|
||||
transaction_rule_id))
|
||||
|
||||
(defn upsert-transaction-rule [context {{:keys [id description yodlee_merchant_id note client_id bank_account_id amount_lte amount_gte vendor_id accounts transaction_approval_status dom_gte dom_lte]} :transaction_rule :as z} value]
|
||||
(assert-admin (:id context))
|
||||
(let [existing-transaction (tr/get-by-id id)
|
||||
|
||||
@@ -31,6 +31,19 @@
|
||||
replaced
|
||||
(into [x] replaced))))
|
||||
|
||||
(defn merge-by [xs f x]
|
||||
(let [found? (atom false)
|
||||
replaced (mapv
|
||||
(fn [t]
|
||||
(if (= (f t) (f x))
|
||||
(do (reset! found? true)
|
||||
(merge t x))
|
||||
t))
|
||||
xs)]
|
||||
(if @found?
|
||||
replaced
|
||||
(into [x] replaced))))
|
||||
|
||||
(defn dollars-0? [amt]
|
||||
(< -0.001 amt 0.001))
|
||||
|
||||
|
||||
@@ -4,3 +4,8 @@
|
||||
(defn fa-icon [{:keys [event icon class]}]
|
||||
[:a.button {:class class
|
||||
:on-click (dispatch-event event)} [:span.icon [:i.fa {:class icon}]]])
|
||||
|
||||
(defn sl-icon [{:keys [event icon class]}]
|
||||
[:a.button {:class class
|
||||
:on-click (dispatch-event event)}
|
||||
[:span.icon [:span {:class icon :style {:font-weight "400"}}]]])
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
[auto-ap.views.components.vendor-dialog :refer [vendor-dialog]]
|
||||
|
||||
[auto-ap.views.components.vendor-dialog :refer [vendor-dialog]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.entities.vendors :as vendor]
|
||||
[auto-ap.views.components.vendor-dialog :as vendor-dialog]
|
||||
[clojure.string :as str]))
|
||||
@@ -177,6 +178,7 @@
|
||||
client @(re-frame/subscribe [::subs/client])
|
||||
is-initial-loading @(re-frame/subscribe [::subs/is-initial-loading?])]
|
||||
[:div
|
||||
[modal/global-modal]
|
||||
[navbar ap]
|
||||
[:div {:class "columns has-shadow", :style {:margin-bottom "0px" :height "calc(100vh - 46px)" } :id "mail-app" }
|
||||
[:aside {:class "column aside menu is-2 " }
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
[reagent.core :as r]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.utils :refer [with-keys appearing]]))
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.views.utils :refer [with-keys appearing dispatch-event]]))
|
||||
|
||||
(defn modal [{:keys [title foot hide-event class]} & body]
|
||||
[:div.modal.is-active (cond-> {}
|
||||
@@ -67,3 +68,61 @@
|
||||
(into (r/children (r/current-component)))
|
||||
(into [(when saving? [:div.is-overlay {:style {"backgroundColor" "rgba(150,150,150, 0.5)"}}])])))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::modal-state
|
||||
(fn [db]
|
||||
(::state db)))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::modal-requested
|
||||
(fn [db [_ state]]
|
||||
(assoc db ::state (assoc state :visible? true))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::modal-closed
|
||||
(fn [{:keys [db]} [_ state]]
|
||||
(let [[_ status-id] (some-> db ::state :confirm :status-from )]
|
||||
(cond-> {:db (dissoc db ::state)}
|
||||
status-id (assoc :dispatch [::status/completed status-id])))))
|
||||
|
||||
|
||||
(defn global-modal []
|
||||
(let [state (re-frame/subscribe [::modal-state])]
|
||||
(fn []
|
||||
(if (:visible? @state)
|
||||
(let [{:keys [title body foot class cancel? confirm]} @state]
|
||||
[:div.modal.is-active (cond-> {}
|
||||
class (assoc :class class))
|
||||
[:div.modal-background {:on-click (dispatch-event [::modal-closed])}]
|
||||
|
||||
[:div.modal-card
|
||||
[:header.modal-card-head
|
||||
[:p.modal-card-title
|
||||
title]
|
||||
[:button.delete {:on-click (dispatch-event [::modal-closed])}]]
|
||||
[:section.modal-card-body
|
||||
body]
|
||||
(let [status (some-> confirm :status-from re-frame/subscribe deref )]
|
||||
(if foot
|
||||
[:footer.modal-card-foot
|
||||
[appearing {:visible? (= :error (:state status))
|
||||
:timeout 200
|
||||
:enter-class "appear"
|
||||
:exit-class "disappear"}
|
||||
[:div.notification.is-warning (:message (first (:error status)))]]
|
||||
foot]
|
||||
[:footer.modal-card-foot
|
||||
[:div
|
||||
[appearing {:visible? (= :error (:state status))
|
||||
:timeout 200
|
||||
:enter-class "appear"
|
||||
:exit-class "disappear"}
|
||||
[:div.notification.is-warning (:message (first (:error status)))]]
|
||||
|
||||
[:div.buttons
|
||||
(when confirm
|
||||
[:button.button.is-danger {:class (status/class-for status)
|
||||
:on-click (:on-click confirm)}
|
||||
(:value confirm)])
|
||||
(when cancel?
|
||||
[:button.button {:on-click (dispatch-event [::modal-closed] )} "Cancel"])]]]))]])))))
|
||||
|
||||
@@ -10,17 +10,15 @@
|
||||
[auto-ap.views.pages.admin.rules.common :refer [default-read]]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[vimsical.re-frame.cofx.inject :as inject]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[day8.re-frame.forward-events-fx]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.utils :refer [replace-by]]
|
||||
[auto-ap.utils :refer [replace-by merge-by]]
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.status :as status]))
|
||||
|
||||
;; SUBS
|
||||
|
||||
(re-frame/reg-sub
|
||||
::notification
|
||||
(fn [db]
|
||||
(-> db ::notification)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::page
|
||||
@@ -57,34 +55,22 @@
|
||||
(update :transaction-rules (fn [rules]
|
||||
(mapv ungraphql-transaction-rule rules))))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::last-params
|
||||
(fn [db]
|
||||
(-> db ::last-params)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::params
|
||||
:<- [::last-params]
|
||||
:<- [::subs/client]
|
||||
:<- [::side-bar/filter-params]
|
||||
:<- [::table/table-params]
|
||||
(fn [[last-params client filter-params table-params]]
|
||||
(let [params (cond-> {}
|
||||
client (assoc :client-id (:id client))
|
||||
(seq filter-params) (merge filter-params)
|
||||
(seq table-params) (merge table-params))]
|
||||
(when (not= params last-params)
|
||||
(re-frame/dispatch [::params-change]))
|
||||
params)))
|
||||
(fn [[client filter-params table-params]]
|
||||
(cond-> {}
|
||||
client (assoc :client-id (:id client))
|
||||
(seq filter-params) (merge filter-params)
|
||||
(seq table-params) (merge table-params))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::params-change
|
||||
[with-user (re-frame/inject-cofx ::inject/sub [::params])]
|
||||
(fn [{:keys [db user] ::keys [params] :as cofx} _]
|
||||
{:db (-> db
|
||||
(assoc-in [::last-params] params))
|
||||
|
||||
:graphql {:token user
|
||||
[with-user ]
|
||||
(fn [{:keys [db user] :as cofx} [_ params]]
|
||||
{:graphql {:token user
|
||||
:owns-state {:single ::page}
|
||||
:query-obj {:venia/queries [[:transaction_rule_page
|
||||
(or params {})
|
||||
@@ -102,13 +88,34 @@
|
||||
(fn [{:keys [db]} _]
|
||||
{:dispatch [::form/adding {:client @(re-frame/subscribe [::subs/client])}]}))
|
||||
|
||||
;; VIEWS
|
||||
(re-frame/reg-event-db
|
||||
::deleted-transaction-rule
|
||||
[(re-frame/path [::page :transaction-rules])]
|
||||
(fn [transaction-rules [_ [_ {id :delete-transaction-rule}]]]
|
||||
(merge-by transaction-rules :id {:id id :class "live-removed"})))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [{:keys [db]}]
|
||||
{:dispatch-n [[::events/yodlee-merchants-needed]]
|
||||
:forward-events {:register ::page
|
||||
:events #{::table/deleted-transaction-rule}
|
||||
:dispatch-to [::deleted-transaction-rule]}
|
||||
::track/register {:id ::params
|
||||
:subscription [::params]
|
||||
:event-fn (fn [params] [::params-change params])}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::unmounted
|
||||
(fn [{:keys [db]}]
|
||||
{:forward-events {:unregister ::page}
|
||||
::track/dispose {:id ::params}}))
|
||||
|
||||
;; VIEWS
|
||||
(def rules-content
|
||||
(with-meta
|
||||
(fn []
|
||||
(let [notification (re-frame/subscribe [::notification])
|
||||
current-client @(re-frame/subscribe [::subs/client])
|
||||
(let [current-client @(re-frame/subscribe [::subs/client])
|
||||
user @(re-frame/subscribe [::subs/user])]
|
||||
[:div
|
||||
[:h1.title "Transaction Rules"]
|
||||
@@ -123,16 +130,14 @@
|
||||
(println "CHANGING PARAMS TO" params)
|
||||
(re-frame/dispatch [::params-change params]))}]
|
||||
]))
|
||||
{:component-will-mount #(do (re-frame/dispatch-sync [::params-change {}])
|
||||
(re-frame/dispatch [::events/yodlee-merchants-needed])) }))
|
||||
{:component-did-mount (dispatch-event [::mounted ])
|
||||
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])}))
|
||||
|
||||
(defn admin-rules-page []
|
||||
(let [{:keys [active?]} @(re-frame/subscribe [::forms/form ::form/form])
|
||||
params @(re-frame/subscribe [::params])]
|
||||
(let [{:keys [active?]} @(re-frame/subscribe [::forms/form ::form/form])]
|
||||
[side-bar-layout {:side-bar [admin-side-bar {}
|
||||
[:<>
|
||||
[side-bar/rule-side-bar]
|
||||
]]
|
||||
[side-bar/rule-side-bar]]]
|
||||
:main [rules-content]
|
||||
:right-side-bar [appearing-side-bar {:visible? active?}
|
||||
[form/form {:rule-saved [::edit-completed]}]]
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
[auto-ap.views.components.sorter :refer [sorted-column toggle-sort-by sort-icon]]
|
||||
[auto-ap.views.components.buttons :as buttons]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.views.components.modal :refer [simple-modal]]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.status :as status]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[reagent.core :as r]))
|
||||
[reagent.core :as r]
|
||||
[auto-ap.views.components.modal :as modal]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::run-clicked
|
||||
@@ -63,6 +66,39 @@
|
||||
{:db (merge table-params params)}))
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::deleted-transaction-rule
|
||||
(fn []
|
||||
{:dispatch [::modal/modal-closed]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::delete-transaction-rule
|
||||
[with-user]
|
||||
(fn [{:keys [db user]} [_ id]]
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:single ::delete-transaction-rule}
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
:operation/name "DeleteTransactionRule"}
|
||||
:venia/queries [{:query/data [:delete-transaction-rule
|
||||
{:transaction-rule-id id}]}]}
|
||||
:on-success [::deleted-transaction-rule]}}))
|
||||
|
||||
|
||||
;; TODO count how many transactions
|
||||
(re-frame/reg-event-fx
|
||||
::request-delete
|
||||
(fn [_ [_ which]]
|
||||
{:dispatch [::modal/modal-requested {:title "Confirmation"
|
||||
:body [:div "Are you sure you want to delete transaction rule '" (:description which) "'? Any previously transactions will remain updated, but the rule association will be lost."]
|
||||
:cancel? true
|
||||
:confirm {:value "Delete Transaction Rule"
|
||||
:status-from [::status/single ::delete-transaction-rule]
|
||||
:on-click (dispatch-event [::delete-transaction-rule (:id which)] )}
|
||||
:close-event [::status/completed ::delete-transaction-rule]}]}))
|
||||
|
||||
|
||||
|
||||
(defn table* [{:keys [id rule-page on-params-change params status]}]
|
||||
(let [{:keys [sort asc]} @params
|
||||
{:keys [transaction-rules start end count total]} @rule-page
|
||||
@@ -70,33 +106,34 @@
|
||||
opc (fn [p]
|
||||
(re-frame/dispatch [::params-changed p]))
|
||||
states @(re-frame/subscribe [::status/multi ::run])]
|
||||
[grid/grid {:on-params-change opc
|
||||
:params @(re-frame/subscribe [::table-params])
|
||||
:status status
|
||||
:column-count 6}
|
||||
[grid/controls {:start start :end end :count count :total total}]
|
||||
[grid/table {:fullwidth true }
|
||||
[:div
|
||||
[grid/grid {:on-params-change opc
|
||||
:params @(re-frame/subscribe [::table-params])
|
||||
:status status
|
||||
:column-count 6}
|
||||
[grid/controls {:start start :end end :count count :total total}]
|
||||
[grid/table {:fullwidth true }
|
||||
[grid/header
|
||||
[grid/row {}
|
||||
[grid/sortable-header-cell {:sort-key "client"
|
||||
:sort-name "Client"}
|
||||
:sort-name "Client"}
|
||||
"Client"]
|
||||
|
||||
[grid/sortable-header-cell {:sort-key "bank-account"
|
||||
:sort-name "Bank Account"}
|
||||
:sort-name "Bank Account"}
|
||||
"Bank Account"]
|
||||
|
||||
[grid/sortable-header-cell {:sort-key "description"
|
||||
:sort-name "Description"}
|
||||
:sort-name "Description"}
|
||||
"Description"]
|
||||
|
||||
[grid/header-cell {:style {:width "12em"}} "Amount"]
|
||||
|
||||
[grid/sortable-header-cell {:sort-key "note"
|
||||
:sort-name "Note"}
|
||||
:sort-name "Note"}
|
||||
"Note"]
|
||||
|
||||
[grid/header-cell {:style {:width (str (inc (* 2 44)) "px")}}]]]
|
||||
[grid/header-cell {:style {:width (str (inc (* 3 44)) "px")}}]]]
|
||||
[grid/body
|
||||
(for [{:keys [client bank-account description amount-lte amount-gte note id] :as r} transaction-rules]
|
||||
^{:key id}
|
||||
@@ -120,7 +157,8 @@
|
||||
[grid/cell {}
|
||||
[:div.buttons
|
||||
[buttons/fa-icon {:event [::run-clicked r] :icon :fa-play :class (status/class-for (get states (:id r)))}]
|
||||
[buttons/fa-icon {:event [::form/editing r] :icon :fa-pencil}]]]])]]]))
|
||||
[buttons/sl-icon {:event [::request-delete r] :icon :icon-bin-2}]
|
||||
[buttons/fa-icon {:event [::form/editing r] :icon :fa-pencil}]]]])]]]]))
|
||||
|
||||
(defn table [params]
|
||||
(r/create-class {:component-will-unmount (dispatch-event [::unmounted])
|
||||
|
||||
Reference in New Issue
Block a user