removed the cruft.

This commit is contained in:
2023-10-31 22:54:53 -07:00
parent 40fea65d9b
commit 03712afd12
18 changed files with 6 additions and 1593 deletions

View File

@@ -3,6 +3,7 @@
[amazonica.aws.s3 :as s3]
[auto-ap.datomic :refer [audit-transact conn]]
[auto-ap.datomic.clients :as d-clients]
[com.brunobonacci.mulog :as mu]
[auto-ap.datomic.invoices :as d-invoices]
[auto-ap.datomic.vendors :as d-vendors]
[auto-ap.graphql.utils :refer [assert-admin assert-can-see-client]]
@@ -335,12 +336,10 @@
(def routes {"api/" {"transactions/" {:post {#"batch-upload/?" :batch-upload-transactions
#"cleared-against/?" :cleared-against}}
"invoices/" {:post {#"upload/?" :upload-invoices
#"upload-integreat/?" :bulk-upload-invoices}}
"invoices/" {:post {#"upload/?" :upload-invoices}}
:post {#"account-overrides/?" :bulk-account-overrides}}})
(def match->handler {:batch-upload-transactions (wrap-secure batch-upload-transactions)
:upload-invoices (wrap-secure upload-invoices)
:bulk-upload-invoices (wrap-secure bulk-upload-invoices)
:cleared-against (wrap-secure cleared-against)
:bulk-account-overrides (wrap-secure (wrap-json-response bulk-account-overrides))})

View File

@@ -27,7 +27,7 @@
[:li
[:a {:href (bidi/path-for ssr-routes/only-routes :company), :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "My Company"]]
(when (= "admin" (:user/role identity))
[:a {:href (bidi/path-for client-routes2/routes :admin), :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "Admin"])
[:a {:href (bidi/path-for ssr-routes/only-routes :auto-ap.routes.admin/page), :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "Admin"])
[:li
[:a {:href "#", :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"
"_" (hiccup/raw "on click toggle .dark on <body />")}

View File

@@ -9,25 +9,19 @@
"admin/" {"clients/" {"" :admin-clients
[:id] {"" :admin-specific-client
"/bank-accounts/" {[:bank-account] :admin-specific-bank-account}}}
"vendors" :admin-vendors
"excel-import" :admin-excel-import
}
"vendors" :admin-vendors}
"invoices/" {"" :invoices
"import" :import-invoices
"unpaid" :unpaid-invoices
"paid" :paid-invoices
"voided" :voided-invoices
"new" :new-invoice}
"pos/" {"sales-orders" :sales-orders
"expected-deposits" :expected-deposits}
"transactions/" {"" :transactions
"unapproved" :unapproved-transactions
"approved" :approved-transactions
"requires-feedback" :requires-feedback-transactions
"excluded" :excluded-transactions}
"reports/" {"" :reports}
"company/" {"other" :company-other
"export-vendors" :company-export-vendors}
"plaid" :plaid
"yodlee2" :yodlee2
"ledger/" {"" :ledger

View File

@@ -18,16 +18,9 @@
[auto-ap.views.pages.ledger.profit-and-loss-detail :refer [profit-and-loss-detail-page]]
[auto-ap.views.pages.login :refer [login-page]]
[auto-ap.views.pages.payments :refer [payments-page]]
[auto-ap.views.pages.pos.sales-orders :refer [sales-orders-page]]
[auto-ap.views.pages.pos.expected-deposits :refer [expected-deposits-page]]
[auto-ap.views.pages.admin :refer [admin-page]]
[auto-ap.views.pages.home :refer [home-page]]
[auto-ap.views.pages.admin.clients :refer [admin-clients-page]]
[auto-ap.views.pages.admin.rules :refer [admin-rules-page]]
[auto-ap.views.pages.admin.vendors :refer [admin-vendors-page]]
[auto-ap.views.pages.admin.excel-import :refer [admin-excel-import-page]]
[auto-ap.views.pages.admin.import-batches :refer [import-batches-page]]
[auto-ap.views.pages.company.other :as company-other]))
[auto-ap.views.pages.admin.vendors :refer [admin-vendors-page]]))
(defmulti page (fn [active-page] active-page))
(defmethod page :unpaid-invoices [_]
@@ -55,12 +48,6 @@
(defmethod page :payments [_]
[payments-page])
(defmethod page :sales-orders [_]
[sales-orders-page])
(defmethod page :expected-deposits [_]
[expected-deposits-page])
(defmethod page :transactions [_]
(transactions-page {}))
@@ -92,31 +79,17 @@
(defmethod page :balance-sheet [_]
(balance-sheet-page))
(defmethod page :admin [_]
(admin-page))
(defmethod page :admin-clients [_]
(admin-clients-page))
(defmethod page :admin-specific-client [_]
(admin-clients-page))
(defmethod page :admin-rules [_]
(admin-rules-page))
(defmethod page :admin-vendors [_]
(admin-vendors-page))
(defmethod page :admin-import-batches [_]
[import-batches-page])
(defmethod page :company-other [_]
(company-other/company-other-page))
(defmethod page :index [_]
(home-page)
)
(home-page))
(defmethod page :login [_]
[login-page])
@@ -130,10 +103,6 @@
(defmethod page :external-ledger [_]
[external-ledger-page])
(defmethod page :admin-excel-import [_]
[admin-excel-import-page])
(defmethod page :initial-error [_]
[error-page])

View File

@@ -1,165 +0,0 @@
(ns auto-ap.views.pages.admin.excel-import
(:require
[auto-ap.forms :as forms]
[auto-ap.forms.builder :as form-builder]
[auto-ap.schema :as schema]
[auto-ap.views.components :as com]
[auto-ap.shared-views.admin.side-bar :refer [admin-side-bar]]
[auto-ap.views.components.layouts :refer [side-bar-layout]]
[auto-ap.views.utils :refer [with-user]]
[malli.core :as m]
[re-frame.core :as re-frame]
[reagent.core :as r]))
(re-frame/reg-event-fx
::save
[ with-user (forms/in-form ::form)]
(fn [{:keys [db user]}]
{:http {:token user
:method :post
:body (pr-str {:excel-rows (:excel-rows (:data db))})
:headers {"Content-Type" "application/edn"}
:uri (str "/api/invoices/upload-integreat")
:owns-state {:single ::form}
:on-success [::save-complete]}}))
(re-frame/reg-event-fx
::save-complete
(fn [{:keys [db]} [_ rows]]
(cond->
{:db (assoc db ::result rows)}
(seq (:vendors-not-found rows)) (assoc :dispatch [::forms/start-form ::create-vendors ]))))
(re-frame/reg-sub
::result
(fn [db]
(::result db)))
(re-frame/reg-event-fx
::create-vendors
[with-user (forms/in-form ::create-vendors)]
(fn [{:keys [user db]}]
{:graphql {:token user
:owns-state {:single ::create-vendors}
:query-obj {:venia/operation {:operation/type :mutation
:operation/name "UpsertVendor"}
:venia/queries
(for [[vendor-name {:keys [default-account]}] (:data db)]
{:query/data [:upsert-vendor
{:vendor {:name vendor-name :default-account-id (:id default-account)}}
[:id :name]]})}
:on-success [::create-vendor-complete]}}))
(re-frame/reg-event-db
::create-vendor-complete
(fn [db _]
(dissoc db ::result )))
(def missing-vendor-schema
(m/schema [:map-of :string
[:map
[:default-account schema/reference]]]))
(defn create-missing-vendors [{:keys [vendors]}]
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::create-vendors])
vendors-to-create (filter (fn [v] (:checked v))
(vals data))]
[form-builder/builder {:id ::create-vendors
:submit-event [::create-vendors]
:schema missing-vendor-schema}
[:article.message.is-warning.is-paddingless
[:div.message-header
"Some vendors could not be found"]
[:div.message-body
[:h2 "Check the vendors you want to create"]
(for [v vendors]
^{:key v}
[:div.field.is-grouped
[:div.control
[form-builder/raw-field-v2 {:field [v :checked]}
[com/checkbox {:label v}]]]
[:div.control
[form-builder/raw-field-v2 {:field [v :default-account]}
[com/search-backed-typeahead {:search-query (fn [i]
[:search_account
{:query i}
[:name :id :location]])}]]]])
[form-builder/error-notification]
[form-builder/submit-button {:disabled (when-not (seq vendors-to-create) "disabled")}
(str "Create " (count vendors-to-create) " vendors")]
[:div.is-clearfix]]]]))
(defn admin-excel-import-content []
[:div
(let [{:keys [vendors-not-found errors already-imported imported]} @(re-frame/subscribe [::result])]
[:div
[:h1.title "Import Invoices from Integreat Excel"]
(when (seq vendors-not-found)
[create-missing-vendors {:vendors vendors-not-found}]
)
[form-builder/builder {:id ::form
:submit-event [::save]}
[form-builder/raw-field-v2 {:field :excel-rows}
[:textarea.textarea {:rows "20"
:type "text"}]]
[form-builder/error-notification]
[form-builder/submit-button "Import"]]
[:div.is-clearfix]
[:div.is-clearfix
[:p
(when imported
(str imported " rows imported."))]
[:p
(when already-imported
(str already-imported " rows already imported."))]]
(when errors
[:div
[:h3 (str "Import errors (" (min 100 (count errors)) " / " (count errors) " )")]
[:table.table.is-fullwidth
[:thead
[:td "Date"]
[:td "Invoice #"]
[:td "Client"]
[:td "Vendor"]
[:td "Amount"]
[:td "Errors"]]
[:tbody
(for [{:keys [raw-date invoice-number client vendor-name amount] row-errors :errors} (take 100 errors)]
^{:key (str raw-date invoice-number client vendor-name amount)}
[:tr
[:td raw-date]
[:td invoice-number]
[:td client]
[:td vendor-name]
[:td amount]
[:td (map (fn [{:keys [info]}] ^{:key info} [:p info]) row-errors)]])]]])])])
(defn admin-excel-import-page-internal []
[side-bar-layout {:side-bar [admin-side-bar {}]
:main [admin-excel-import-content]}])
(re-frame/reg-event-fx
::mounted
(fn [_ _]
{:dispatch [::forms/start-form ::form]}))
(re-frame/reg-event-fx
::unmounted
(fn [{:keys [db]} _]
{:dispatch-n [[::forms/form-closing ::form]
[::forms/form-closing ::create-vendors]]
:db (dissoc db ::results)}))
(defn admin-excel-import-page []
(r/create-class
{:display-name "excel-import-page"
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])
:component-did-mount #(re-frame/dispatch [::mounted])
:reagent-render admin-excel-import-page-internal}))

View File

@@ -1,69 +0,0 @@
(ns auto-ap.views.pages.admin.import-batches
(:require
[auto-ap.subs :as subs]
[auto-ap.shared-views.admin.side-bar :refer [admin-side-bar]]
[auto-ap.views.components.layouts :refer [side-bar-layout]]
[auto-ap.views.pages.admin.import-batches.table :as table]
[auto-ap.views.pages.data-page :as data-page]
[auto-ap.views.utils :refer [dispatch-event with-user]]
[clojure.set :as set]
[re-frame.core :as re-frame]
[vimsical.re-frame.fx.track :as track]))
(def default-read [:user-name :date :source :status :id :imported :suppressed :extant])
(re-frame/reg-event-fx
::params-change
[with-user ]
(fn [{:keys [user]} [_ params]]
{:graphql {:token user
:owns-state {:single [::data-page/page ::page]}
:query-obj {:venia/queries [{:query/data [:import_batch_page
{:filters {:sort (:sort params)
:start (:start params 0)
:per-page (:per-page params)}}
[[:data default-read]
:total
:start
:end]]
:query/alias :result}]}
:on-success (fn [result]
[::data-page/received ::page
(set/rename-keys (:result result)
{:import-batches :data})])}}))
(re-frame/reg-event-fx
::mounted
(fn [_]
{::track/register {:id ::params
:subscription [::data-page/params ::page]
:event-fn (fn [params]
[::params-change params])}}))
(re-frame/reg-event-fx
::unmounted
(fn [{:keys [db]}]
{:dispatch [::data-page/dispose ::page]
::track/dispose {:id ::params}}))
;; VIEWS
(def import-batch-content
(with-meta
(fn []
(let [user @(re-frame/subscribe [::subs/user])]
[:div
[:h1.title "Import Batches"]
(when (= "admin" (:user/role user))
[:div
[:div.is-pulled-right
[:div.buttons]]
[table/table {:id :import-batches
:data-page ::page}]])]))
{:component-did-mount (dispatch-event [::mounted ])
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])}))
(defn import-batches-page []
[side-bar-layout {:side-bar [admin-side-bar {}]
:main [import-batch-content]}])

View File

@@ -1,82 +0,0 @@
(ns auto-ap.views.pages.admin.import-batches.table
(:require [auto-ap.routes :as routes]
[auto-ap.status :as status]
[auto-ap.subs :as subs]
[auto-ap.views.components.buttons :as buttons]
[auto-ap.views.components.grid :as grid]
[auto-ap.views.pages.data-page :as data-page]
[auto-ap.views.utils
:refer
[action-cell-width date->str dispatch-event pretty-long]]
[bidi.bidi :as bidi]
[cemerick.url :as url]
[re-frame.core :as re-frame]
[reagent.core :as r]))
(re-frame/reg-sub
::specific-table-params
(fn [db]
(::table-params db)))
(re-frame/reg-event-db
::unmounted
(fn [db]
(status/reset-multi db ::run)))
(re-frame/reg-sub
::table-params
:<- [::specific-table-params]
:<- [::subs/query-params]
(fn [[specific-table-params query-params]]
(merge (select-keys query-params #{:start :sort}) specific-table-params )))
(defn table* [{:keys [data-page]}]
(let [{:keys [data]} @(re-frame/subscribe [::data-page/page data-page])]
[grid/grid {:data-page data-page
:column-count 6}
[grid/controls data]
[grid/table {:fullwidth true}
[grid/header
[grid/row {}
[grid/sortable-header-cell {:sort-key "date"
:sort-name "Date"}
"Date"]
[grid/sortable-header-cell {:sort-key "source"
:sort-name "Source"}
"Source"]
[grid/sortable-header-cell {:sort-key "status"
:sort-name "Status"}
"Status"]
[grid/sortable-header-cell {:sort-key "user"
:sort-name "User"}
"User"]
[grid/header-cell {:style {:width "7em"}} "Imported"]
[grid/header-cell {:style {:width "7em"}} "Preexisting"]
[grid/header-cell {:style {:width "7em"}} "Suppressed"]
[grid/header-cell {:style {:width (action-cell-width 3)}}]]]
[grid/body
(for [{:keys [date source status user-name id imported extant suppressed] :as r} (:data data)]
^{:key id}
[grid/row {:class (:class r) :id id}
[grid/cell {} (date->str date pretty-long)]
[grid/cell {} source]
[grid/cell {} status]
[grid/cell {} user-name]
[grid/cell {} imported]
[grid/cell {} extant]
[grid/cell {} suppressed]
[grid/button-cell {}
[buttons/fa-icon {:href (str (bidi/path-for routes/routes :transactions)
"?"
(url/map->query {:import-batch-id id}))
:icon "fa-external-link"}]]])]]
[grid/bottom-paginator data]]))
(defn table []
(r/create-class {:component-will-unmount (dispatch-event [::unmounted])
:reagent-render (fn [params]
[table* params])}))

View File

@@ -1,103 +0,0 @@
(ns auto-ap.views.pages.admin.rules
(:require
[auto-ap.effects.forward :as forward]
[auto-ap.events :as events]
[auto-ap.forms :as forms]
[auto-ap.subs :as subs]
[auto-ap.shared-views.admin.side-bar :refer [admin-side-bar]]
[auto-ap.views.components.buttons :as buttons]
[auto-ap.views.components.layouts
:refer [appearing-side-bar side-bar-layout]]
[auto-ap.views.pages.admin.rules.common :refer [default-read]]
[auto-ap.views.pages.admin.rules.form :as form]
[auto-ap.views.pages.admin.rules.side-bar :as side-bar]
[auto-ap.views.pages.admin.rules.table :as table]
[auto-ap.views.pages.data-page :as data-page]
[auto-ap.views.utils :refer [dispatch-event with-user]]
[clojure.set :as set]
[re-frame.core :as re-frame]
[vimsical.re-frame.fx.track :as track]))
;; EVENTS
(re-frame/reg-event-fx
::params-change
[with-user ]
(fn [{:keys [user]} [_ params]]
{:graphql {:token user
:owns-state {:single [::data-page/page ::page]}
:query-obj {:venia/queries [{:query/data [:transaction_rule_page
{:sort (:sort params)
:start (:start params 0)
:per-page (:per-page params)
:vendor-id (:id (:vendor params))
:client-id (:id @(re-frame/subscribe [::subs/client]))
:note (:note params)
:description (:description params)}
[[:transaction-rules default-read]
:total
:start
:end]]
:query/alias :result}]}
:on-success (fn [result]
[::data-page/received ::page
(set/rename-keys (:result result)
{:transaction-rules :data})])}}))
(re-frame/reg-event-fx
::new-rule-clicked
(fn [_ _]
{:dispatch [::form/adding {:client @(re-frame/subscribe [::subs/client])}]}))
(re-frame/reg-event-fx
::mounted
(fn [_]
{:dispatch-n [[::events/yodlee-merchants-needed]]
::forward/register [{:id ::page
:events #{::form/updated}
:event-fn (fn [[_ result]]
[::data-page/updated-entity ::page result])}
{:id ::deleted-transaction-rule
:events #{::table/deleted-transaction-rule }
:event-fn (fn [[_ result]]
[::data-page/deleted-entity ::page result])}]
::track/register {:id ::params
:subscription [::data-page/params ::page]
:event-fn (fn [params]
[::params-change params])}}))
(re-frame/reg-event-fx
::unmounted
(fn [_]
{:dispatch [::data-page/dispose ::page]
::forward/dispose [{:id ::page}
{:id ::deleted-transaction-rule}]
::track/dispose {:id ::params}}))
;; VIEWS
(def rules-content
(with-meta
(fn []
(let [user @(re-frame/subscribe [::subs/user])]
[:div
[:h1.title "Transaction Rules"]
(when (= "admin" (:user/role user))
[:div.is-pulled-right
[buttons/new-button {:event [::new-rule-clicked]
:class "is-primary"
:name "Transaction Rule"}]])
[table/table {:id :transaction-rules
:data-page ::page}]]))
{: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])]
[side-bar-layout {:side-bar [admin-side-bar {}
[side-bar/rule-side-bar {:data-page ::page}]]
:main [rules-content]
:right-side-bar [appearing-side-bar {:visible? active?}
[form/form {:data-page ::page}]]}]))

View File

@@ -1,18 +0,0 @@
(ns auto-ap.views.pages.admin.rules.common)
(def default-read [:id
:description
:note
:amount-gte
:amount-lte
:dom-gte
:dom-lte
:transaction-approval-status
[:yodlee-merchant [:name :id :yodlee-id]]
[:vendor [:name :id]]
[:client [:name :id]]
[:bank-account [:name :id]]
[:accounts [[:account [:id :name :numeric-code :location]]
:id
:percentage
:location]]])

View File

@@ -1,373 +0,0 @@
(ns auto-ap.views.pages.admin.rules.form
(:require
[auto-ap.events :as events]
[auto-ap.forms :as forms]
[auto-ap.forms.builder :as form-builder]
[auto-ap.schema :as schema]
[auto-ap.status :as status]
[auto-ap.subs :as subs]
[auto-ap.views.components :as com]
[auto-ap.views.components.expense-accounts-field
:as expense-accounts-field
:refer [expense-accounts-field-v2]]
[auto-ap.views.components.layouts :as layouts]
[auto-ap.views.components.level :refer [left-stack]]
[auto-ap.views.pages.admin.rules.common :refer [default-read]]
[auto-ap.views.pages.admin.rules.results-modal :as results-modal]
[auto-ap.views.utils :refer [coerce-float dispatch-event with-user]]
[clojure.string :as str]
[malli.core :as m]
[re-frame.core :as re-frame]
[reagent.core :as r]
[vimsical.re-frame.cofx.inject :as inject]
[vimsical.re-frame.fx.track :as track]))
;; SUBS
(re-frame/reg-sub
::default-note
:<- [::forms/form ::form]
(fn [{{:keys [client description amount-lte amount-gte dom-lte dom-gte]} :data}]
(str/join " - " (filter (complement str/blank?)
[(:code client)
description
(when (or amount-lte amount-gte)
(str (when amount-gte
(str amount-gte "<"))
"amt"
(when amount-lte
(str "<" amount-lte))))
(when (or dom-lte dom-gte)
(str (when dom-gte
(str dom-gte "<"))
"dom"
(when dom-lte
(str "<" dom-lte))))]))))
(re-frame/reg-sub
::query
:<- [::forms/form ::form]
(fn [{:keys [data] }]
{:venia/operation {:operation/type :mutation
:operation/name "UpsertTransactionRule"}
:venia/queries [{:query/data [:upsert-transaction-rule
{:transaction-rule (-> data
(select-keys [:id
:description
:transaction-approval-status
:amount-lte
:amount-gte
:dom-lte
:dom-gte
:accounts
:note])
(update :note #(if (str/blank? %)
@(re-frame/subscribe [::default-note])
%))
(assoc :vendor-id (:id (:vendor data)))
(assoc :yodlee-merchant-id (:id (:yodlee-merchant data)))
(update :description (fn [d] (when d (str/replace d #"\\" "\\\\"))))
(update :accounts (fn [as]
(map #(-> %
(update :id (fn [i] (if (some-> i (str/starts-with? "new-"))
nil
i)))
(assoc :percentage (/ (get-in % [:amount-percentage]) 100 ))
(assoc :account-id (get-in % [:account :id]))
(select-keys [:percentage :id :location :account-id]))
as)))
(assoc :client-id (:id (:client data)))
(assoc :bank-account-id (:id (:bank-account data))))}
default-read]}]}))
(re-frame/reg-sub
::test-query
:<- [::forms/form ::form]
(fn [{:keys [data] }]
{:venia/operation {:operation/type :query
:operation/name "TestTransactionRule"}
:venia/queries [{:query/data [:test-transaction-rule
{:transaction-rule (-> data
(select-keys [:id
:description
:amount-lte
:amount-gte
:dom-lte
:dom-gte
:note])
(update :description (fn [d] (when d (str/replace d #"\\" "\\\\"))))
(assoc :yodlee-merchant-id (:id (:yodlee-merchant data)))
(assoc :client-id (:id (:client data)))
(assoc :bank-account-id (:id (:bank-account data))))}
[:id
:date
:amount
[:client [:name]]
[:bank-account [:name]]
:description-original]]}]}))
;; EVENTS
(re-frame/reg-event-db
::adding
(fn [db [_ new]]
(-> db (forms/start-form ::form (assoc new
:description nil
:client nil
:bank-account nil
:note nil
:amount-lte nil
:amount-gte nil
:dom-lte nil
:dom-gte nil
:vendor nil
:transaction-approval-status :unapproved
:accounts [{:id (str "new-" (random-uuid))
:amount-mode "%"
:amount-percentage 100
:location nil}])))))
(re-frame/reg-event-db
::editing
(fn [db [_ which]]
(-> db (forms/start-form ::form (-> which
(select-keys [:description
:id
:client
:bank-account
:note
:amount-lte
:amount-gte
:dom-lte
:dom-gte
:vendor
:accounts
:yodlee-merchant
:transaction-approval-status])
(update :amount-lte coerce-float)
(update :amount-gte coerce-float)
(update :accounts (fn [xs]
(mapv #(-> %
(assoc :amount-percentage (* (:percentage %) 100.0)))
xs))))))))
(re-frame/reg-event-fx
::changed-vendor
[(forms/in-form ::form)]
(fn [{{{:keys [client]} :data} :db} [_ vendor]]
(when (and (:id client) (:id vendor))
{:dispatch [::events/vendor-preferences-requested {:client-id (:id client)
:vendor-id (:id vendor)
:on-success [::changed [:vendor-preferences]]}]})))
(re-frame/reg-event-fx
::changed-client
[(forms/in-form ::form)]
(fn [{{{:keys [vendor]} :data} :db} [_ client]]
(when (and (:id client) (:id vendor))
{:dispatch [::events/vendor-preferences-requested {:client-id (:id client)
:vendor-id (:id vendor)
:on-success [::changed [:vendor-preferences]]}]})))
(re-frame/reg-event-db
::changed
(forms/change-handler ::form
(fn [data field value]
(cond (and (= [:vendor-preferences] field)
value
(expense-accounts-field/can-replace-with-default? (:accounts data)))
[[:accounts] (expense-accounts-field/default-account (:accounts data)
(:default-account value)
(:total data)
[])]
(= [:client] field)
[[:bank-account] nil]
:else
[]))))
(re-frame/reg-event-fx
::saving
[with-user (forms/triggers-loading ::form) (forms/in-form ::form) (re-frame/inject-cofx ::inject/sub [::query])]
(fn [{:keys [user] ::keys [query]} _]
{:graphql
{:token user
:query-obj query
:owns-state {:single ::form}
:on-success (fn [result]
[::updated (:upsert-transaction-rule result)])}}))
(re-frame/reg-event-fx
::test-clicked
[with-user (forms/triggers-loading ::form) (forms/in-form ::form) (re-frame/inject-cofx ::inject/sub [::test-query])]
(fn [{:keys [user] ::keys [test-query]} _]
{:graphql
{:token user
:owns-state {:single ::test}
:query-obj test-query
:on-success [::succeeded-test]
:on-error [::forms/save-error ::form]}}))
(re-frame/reg-event-fx
::updated
[(forms/triggers-stop ::form)]
(fn [{:keys [db]} _]
{:db (forms/start-form db ::form {:client @(re-frame/subscribe [::subs/client])})}))
(re-frame/reg-event-fx
::succeeded-test
[(forms/triggers-stop-loading ::form)]
(fn [_ [_ result]]
{:dispatch [::results-modal/opening (:test-transaction-rule result) nil false]}))
;; VIEWS
(re-frame/reg-event-fx
::mounted
(fn [_ _]
{::track/register [{:id ::client
:subscription [::forms/field ::form [:client]]
:event-fn (fn [c]
[::changed-client c])}
{:id ::vendor-change
:subscription [::forms/field ::form [:vendor]]
:event-fn (fn [v]
[::changed-vendor v])}]}))
(re-frame/reg-event-fx
::unmounted
(fn []
{::track/dispose [{:id ::client}
{:id ::vendor-change}]}))
(def rule-schema
(m/schema [:map
[:client {:optional true}
[:maybe schema/reference]]
[:bank-account {:optional true}
[:maybe schema/reference]]
[:description
schema/not-empty-string]
[:amount-gte {:optional true}
[:maybe schema/money]]
[:amount-lte {:optional true}
[:maybe schema/money]]
[:dom-gte {:optional true}
[:maybe [:int {:min 1 :max 31}]]]
[:dom-lte {:optional true}
[:maybe [:int {:min 1 :max 31}]]]
[:vendor {:optional true}
[:maybe schema/reference]]
[:transaction-approval-status {:optional true}
[:maybe schema/approval-status]]
[:note {:optional true}
[:maybe :string]]]))
(defn form-contents []
[layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form ])}
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])
default-note @(re-frame/subscribe [::default-note])
test-state @(re-frame/subscribe [::status/single ::test])]
[form-builder/builder {:change-event [::changed]
:submit-event [::saving ]
:id ::form
:schema rule-schema}
[form-builder/section {:title "Transaction Rule"}
[form-builder/field-v2 {:required? true
:field :client}
"Client"
[com/entity-typeahead {:entities @(re-frame/subscribe [::subs/clients])
:auto-focus true
:entity->text :name}]]
[form-builder/field-v2 {:field [:bank-account]}
"Bank account"
[com/entity-typeahead {:entities @(re-frame/subscribe [::subs/real-bank-accounts-for-client (:client data)])
:entity->text :name}]]
[form-builder/field-v2 {:field :description
:required? true}
[:span "Description (" [:a {:href "https://regex101.com" :target "_new"} "regex tester"] ")" ]
[:input.input {:type "text"}]]
[:div.field
[:p.help "Amount"]
[left-stack
[form-builder/raw-field-v2 {:field :amount-gte}
[com/money-input {:placeholder ">="}]]
"-"
[form-builder/raw-field-v2 {:field :amount-lte}
[com/money-input {:placeholder "<="}]]]]
[:div.field
[:p.help "Day of month"]
[left-stack
[form-builder/raw-field-v2 {:field :dom-gte}
[com/number-input {:placeholder ">="
:style {:width "7em"}}]]
"-"
[form-builder/raw-field-v2 {:field :dom-lte}
[com/number-input {:placeholder "<="
:style {:width "7em"}}]]]]
[:h2.title.is-4 "Outcomes"]
[form-builder/field-v2 {:field :vendor}
"Assign Vendor"
[com/search-backed-typeahead {:search-query (fn [i]
[:search_vendor
{:query i}
[:name :id]])}]]
[form-builder/field-v2 {:field :accounts}
"Accounts"
[expense-accounts-field-v2 {:descriptor "account asssignment"
:percentage-only? true
:client (:client data)
:locations (into ["Shared"] @(re-frame/subscribe [::subs/locations-for-client-or-bank-account (:id (:client data)) (:id (:bank-account data))]))
:max 100}]]
[form-builder/field-v2 {:field :transaction-approval-status}
"Approval Status"
[com/button-radio-input
{:options [[:unapproved "Unapproved"]
[:requires-feedback "Client Review"]
[:approved "Approved"]
[:excluded "Excluded from Ledger"]]}]]
[form-builder/field-v2 {:field :note}
"Note"
[:input.input {:type "text"
:placeholder default-note}]]
[:div.is-divider]
[form-builder/error-notification]
[:div.columns
[:div.column
[:a.button.is-medium.is-fullwidth.is-outlined {:on-click (dispatch-event [::test-clicked])
:disabled (status/disabled-for test-state)
:class (status/class-for test-state)}
"Test Rule"]]
[:div.column
[form-builder/submit-button {:class ["is-fullwidth"]}
"Save"]]]]])])
(defn form [_]
(r/create-class
{:display-name "rule-form"
:component-did-mount #(re-frame/dispatch [::mounted])
:component-will-unmount #(re-frame/dispatch [::unmounted])
:reagent-render (fn [p]
[form-contents p])}))

View File

@@ -1,136 +0,0 @@
(ns auto-ap.views.pages.admin.rules.results-modal
(:require [auto-ap.views.utils :refer [date->str dispatch-event with-user]]
[auto-ap.views.pages.transactions.common :refer [transaction-read]]
[re-frame.core :as re-frame]
[auto-ap.views.components.modal :as modal]
[auto-ap.status :as status]))
(re-frame/reg-sub
::test-results
(fn [db]
(::test-results db)))
(re-frame/reg-sub
::runnable?
(fn [db]
(::runnable? db)))
(re-frame/reg-sub
::checked
(fn [db]
(::checked db)))
(re-frame/reg-sub
::all-checked
(fn [db]
(::all-checked db nil)))
(re-frame/reg-sub
::checked-count
:<- [::checked]
(fn [checked]
(if (seq checked)
(count checked)
0)))
(defn results-body []
(let [runnable? @(re-frame/subscribe [::runnable?])
checked @(re-frame/subscribe [::checked])
all-checked @(re-frame/subscribe [::all-checked])]
[:table.table.is-fullwidth.compact
[:tr
(when runnable?
[:th {:style {:width "2em"}}
[:input.checkbox {:type "checkbox"
:checked all-checked
:on-change (dispatch-event [::toggle-all])}]])
[:th "Client"]
[:th "Bank Account"]
[:th "Description"]
[:th "Date"]
[:th "Amount"]]
(for [{:keys [id client bank-account description-original date amount]} @(re-frame/subscribe [::test-results])]
^{:key id}
[:tr
(when runnable?
[:td
[:input.checkbox {:type "checkbox"
:checked (boolean (checked id))
:on-change (dispatch-event [::toggle id])}]])
[:td (:name client)]
[:td (:name bank-account)]
[:td description-original]
[:td (when date (date->str date))]
[:td amount]])]))
(defn foot [params]
(let [runnable? @(re-frame/subscribe [::runnable?])
all-checked @(re-frame/subscribe [::all-checked])
checked-count @(re-frame/subscribe [::checked-count])
status @(re-frame/subscribe [::status/single ::apply])]
(when runnable?
[:div
[:button.button.is-primary {:disabled (or (boolean (= checked-count 0))
(status/disabled-for status))
:class (status/class-for status)
:on-click (dispatch-event [::apply-rule params])}
(str "Apply to " checked-count " transactions")]
[:button.button.is-warning {:disabled (or (boolean (not all-checked))
(status/disabled-for status))
:class (status/class-for status)
:on-click (dispatch-event [::apply-rule (assoc params :all? true)])}
(str "Apply to all transactions")]])))
(re-frame/reg-event-fx
::opening
(fn [{:keys [db]} [_ results transaction-rule-id runnable?]]
{:db (-> db
(assoc ::all-checked false)
(assoc ::test-results results)
(assoc ::transaction-rule-id transaction-rule-id)
(assoc ::checked #{})
(assoc ::runnable? runnable?))
:dispatch [::modal/modal-requested {:title "Rule results"
:class "wide"
:body [results-body]
:status-from [::status/single ::apply]
:foot [foot]}]}))
(re-frame/reg-event-db
::toggle
[(re-frame/path [::checked])]
(fn [checked [_ which]]
(let [checked (or checked #{})]
(if (checked which)
(disj checked which)
(conj checked which)))))
(re-frame/reg-event-db
::toggle-all
(fn [db [_ _]]
(let [{::keys [all-checked test-results]} db]
(assoc db
::all-checked (not all-checked)
::checked (if all-checked
#{}
(into #{} (map :id test-results)))))))
(re-frame/reg-event-fx
::apply-rule
[with-user]
(fn [{:keys [db user]} [_ params]]
{:graphql
{:token user
:owns-state {:single ::apply}
:query-obj {:venia/operation {:operation/type :mutation
:operation/name "MatchTransactionRules"}
:venia/queries [{:query/data [:match-transaction-rules
{:transaction-ids (seq @(re-frame/subscribe [::checked]))
:all (boolean (:all? params))
:transaction-rule-id (::transaction-rule-id db)}
transaction-read]}]}
:on-success [::modal/modal-closed]}}))

View File

@@ -1,33 +0,0 @@
(ns auto-ap.views.pages.admin.rules.side-bar
(:require
[auto-ap.views.components.typeahead.vendor
:refer [search-backed-typeahead]]
[auto-ap.views.pages.data-page :as data-page]
[auto-ap.views.utils :refer [dispatch-value-change]]
[re-frame.core :as re-frame]))
(defn rule-side-bar [{:keys [data-page]}]
[:div
[:p.menu-label "Vendor"]
[:div
[search-backed-typeahead {:search-query (fn [i]
[:search_vendor
{:query i}
[:name :id]])
:type "typeahead-v3"
:on-change #(re-frame/dispatch [::data-page/filter-changed data-page :vendor %])
:value @(re-frame/subscribe [::data-page/filter data-page :vendor])}]]
[:p.menu-label "Note"]
[:div
[:div.field
[:div.control [:input.input {:placeholder "HOME DEPOT"
:value @(re-frame/subscribe [::data-page/filter data-page :note])
:on-change (dispatch-value-change [::data-page/filter-changed data-page :note])} ]]]]
[:p.menu-label "Description"]
[:div
[:div.field
[:div.control [:input.input {:placeholder "HOME DEPOT"
:value @(re-frame/subscribe [::data-page/filter data-page :description])
:on-change (dispatch-value-change [::data-page/filter-changed data-page :description])} ]]]]])

View File

@@ -1,152 +0,0 @@
(ns auto-ap.views.pages.admin.rules.table
(:require
[auto-ap.status :as status]
[auto-ap.subs :as subs]
[auto-ap.views.components.buttons :as buttons]
[auto-ap.views.components.grid :as grid]
[auto-ap.views.components.modal :as modal]
[auto-ap.views.pages.admin.rules.form :as form]
[auto-ap.views.pages.admin.rules.results-modal :as results-modal]
[auto-ap.views.pages.data-page :as data-page]
[auto-ap.views.utils
:refer [->$ action-cell-width dispatch-event with-user]]
[re-frame.core :as re-frame]
[reagent.core :as r]))
(re-frame/reg-event-fx
::run-clicked
[with-user]
(fn [{:keys [user]} [_ which]]
{:graphql
{:token user
:owns-state {:multi ::run
:which (:id which)}
:query-obj {:venia/operation {:operation/type :query
:operation/name "RunTransactionRule"}
:venia/queries [{:query/data [:run-transaction-rule
{:transaction-rule-id (:id which)}
[:id
:date
:amount
[:client [:name]]
[:bank-account [:name]]
:description-original]]}]}
:on-success [::succeeded-run (:id which)]}}))
(re-frame/reg-event-fx
::succeeded-run
(fn [_ [_ transaction-rule-id result]]
{:dispatch [::results-modal/opening (:run-transaction-rule result) transaction-rule-id true]}))
(re-frame/reg-sub
::specific-table-params
(fn [db]
(::table-params db)))
(re-frame/reg-event-db
::unmounted
(fn [db]
(status/reset-multi db ::run)))
(re-frame/reg-sub
::table-params
:<- [::specific-table-params]
:<- [::subs/query-params]
(fn [[specific-table-params query-params]]
(merge (select-keys query-params #{:start :sort}) specific-table-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 [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"
:class "is-danger"
: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 [data-page]}]
(let [{:keys [data]} @(re-frame/subscribe [::data-page/page data-page])
_ @(re-frame/subscribe [::subs/client])
states @(re-frame/subscribe [::status/multi ::run])]
[grid/grid {:data-page data-page
:column-count 6}
[grid/controls data]
[grid/table {:fullwidth true}
[grid/header
[grid/row {}
[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 "description"
:sort-name "Description"}
"Description"]
[grid/header-cell {:style {:width "12em"}} "Amount"]
[grid/sortable-header-cell {:sort-key "note"
:sort-name "Note"}
"Note"]
[grid/header-cell {:style {:width (action-cell-width 3)}}]]]
[grid/body
(for [{:keys [client bank-account description amount-lte amount-gte note id] :as r} (:data data)]
^{:key id}
[grid/row {:class (:class r) :id id}
[grid/cell {} (:name client)]
[grid/cell {} (:name bank-account)]
[grid/cell {} description]
[grid/cell {:class "has-text-right"}
(cond (and amount-gte amount-lte)
(str (->$ amount-gte) " - " (->$ amount-lte))
amount-gte
(str ">=" (->$ amount-gte))
amount-lte
(str "<=" (->$ amount-lte))
:else
"")]
[grid/cell {} note]
[grid/cell {}
[:div.buttons
[buttons/fa-icon {:event [::run-clicked r] :icon :fa-play :class (status/class-for (get states (:id r)))}]
[buttons/sl-icon {:event [::request-delete r] :icon :icon-bin-2}]
[buttons/fa-icon {:event [::form/editing r] :icon :fa-pencil}]]]])]]
[grid/bottom-paginator data]]))
(defn table []
(r/create-class {:component-will-unmount (dispatch-event [::unmounted])
:reagent-render (fn [params]
[table* params])}))

View File

@@ -1,78 +0,0 @@
(ns auto-ap.views.pages.company.other
(:require
[auto-ap.subs :as subs]
[auto-ap.views.utils :refer [dispatch-event with-user]]
[auto-ap.views.components.buttons :refer [fa-icon]]
[auto-ap.views.components.layouts :refer [side-bar-layout]]
[auto-ap.shared-views.company.sidebar :refer [company-side-bar]]
[goog.crypt.base64 :as b64]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[vimsical.re-frame.cofx.inject :as inject]
[auto-ap.status :as status]
[clojure.string :as str]))
(re-frame/reg-event-fx
::ready
(fn [{:keys [db] } [_ result]]
{:db (assoc db ::export-result result)}))
(re-frame/reg-sub
::export-result
(fn [db]
(::export-result db)))
(re-frame/reg-event-fx
::export-vendors
[(re-frame/inject-cofx ::inject/sub [::subs/client]) with-user]
(fn [{:keys [db user] ::subs/keys [client]}]
{:http {:token user
:method :get
:headers {"Content-Type" "application/edn"}
:uri (str "/api/vendors/company/export?client=" (:code client))
:owns-state {:single ::export-vendors}
:on-success [::ready]}}))
(re-frame/reg-event-fx
::unmounted
(fn [{:keys [db]} _]
{:db (dissoc db ::export-result)}))
(defn company-other-content []
(let [client @(re-frame/subscribe [::subs/client])
state @(re-frame/subscribe [::status/single ::export-vendors])
export-result @(re-frame/subscribe [::export-result])]
(if client
[:div
[:h1.title "Other"]
[status/status-notification [::status/single ::export-vendors]]
[fa-icon {:icon "fa-external-link"
:class (into (status/class-for state) ["is-primary" ])
:disabled (status/disabled-for state)
:event [::export-vendors]
}
[:div
(str " Export " (:name client) " Vendors")
]]
(when export-result
[:<>
[:div
"Ready! Click "
[:a {:href (str "data:attachment/csv;base64," (b64/encodeString export-result))
:target "_blank"
:download (str "vendors-" (:code client) ".csv")}
"here"]
" to download"]])
]
[:div "Please select a company."])))
(defn company-other-page []
(reagent/create-class
{:reagent-render (fn []
[side-bar-layout {:side-bar [company-side-bar {}]
:main [company-other-content]}])
:component-will-unmount #(re-frame/dispatch [::unmounted])}))

View File

@@ -1,29 +0,0 @@
(ns auto-ap.views.pages.company.side-bar
(:require
[auto-ap.routes :as routes]
[auto-ap.subs :as subs]
[auto-ap.views.utils :refer [active-when]]
[bidi.bidi :as bidi]
[re-frame.core :as re-frame]))
(defn company-side-bar []
(let [ap @(re-frame/subscribe [::subs/active-page])]
[:div
[:ul.menu-list
[:li.menu-item
[:a.item {:href (bidi/path-for routes/routes :reports)
:class [(active-when ap = :reports)]}
[:span {:class "icon icon-receipt" :style {:font-size "25px"}}]
[:span {:class "name"} "Reports"]]]]
[:li.menu-item
[:a {:href (bidi/path-for routes/routes :plaid), :class (str "item" (active-when ap = :plaid))}
[:span {:class "icon icon-saving-bank-1" :style {:font-size "25px"}}]
[:span {:class "name"} "Plaid Link"]]]
[:li.menu-item
[:a {:href (bidi/path-for routes/routes :yodlee2), :class (str "item" (active-when ap = :yodlee2))}
[:span {:class "icon icon-saving-bank-1" :style {:font-size "25px"}}]
[:span {:class "name"} "Yodlee Link"]]]
[:li.menu-item
[:a {:href (bidi/path-for routes/routes :company-other), :class (str "item" (active-when ap = :company-other))}
[:span {:class "icon icon-cog-play-1" :style {:font-size "25px"}}]
[:span {:class "name"} "Other"]]]]))

View File

@@ -1,141 +0,0 @@
(ns auto-ap.views.pages.company.yodlee2
(:require
[auto-ap.effects.forward :as forward]
[auto-ap.status :as status]
[auto-ap.subs :as subs]
[auto-ap.views.components.grid :as grid]
[auto-ap.views.components.layouts :refer [side-bar-layout]]
[auto-ap.shared-views.company.sidebar :refer [company-side-bar]]
[auto-ap.views.pages.company.yodlee2.table :as table]
[auto-ap.views.utils :refer [dispatch-event with-user]]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[vimsical.re-frame.cofx.inject :as inject]))
(re-frame/reg-sub
::authentication
(fn [db]
(-> db ::authentication)))
(re-frame/reg-sub
::params
:<- [::table/params]
(fn [table-params]
table-params))
(re-frame/reg-sub
::yodlee-provider-accounts
(fn [db]
(::yodlee-provider-accounts db)))
(re-frame/reg-sub
::page
:<- [::params]
:<- [::yodlee-provider-accounts]
(fn [[params all-yodlee-provider-accounts]]
(assoc (grid/virtual-paginate-controls (:start params ) (:per-page params) (:yodlee-provider-accounts all-yodlee-provider-accounts) )
:data (grid/virtual-paginate (:start params) (:per-page params) (:yodlee-provider-accounts all-yodlee-provider-accounts)))))
(re-frame/reg-event-fx
::data-requested
[with-user (re-frame/inject-cofx ::inject/sub [::subs/client])]
(fn [{:keys [user] ::subs/keys [client]} _]
{:graphql {:token user
:owns-state {:single ::page}
:query-obj {:venia/queries [[:yodlee-provider-account-page {:client-id (:id client)}
[[:yodlee-provider-accounts [:id :last-updated :status :detailed-status
[:client [:id]]
[:accounts [:id :name :number :available-balance]]]]
:count]]]}
:on-success [::received]}}))
(re-frame/reg-event-fx
::mounted
(fn [{:keys [db]} _]
{:dispatch [::data-requested]
::forward/register {:id ::yodlee-account-refreshed
:events #{::table/refreshed ::table/provider-account-deleted}
:event-fn (fn [[_ _]]
[::data-requested])}
:db (dissoc db ::authentication)}))
(re-frame/reg-event-fx
::unmounted
(fn [_ _]
{::forward/dispose {:id ::yodlee-account-refreshed}}))
(re-frame/reg-event-fx
::authenticate-with-yodlee
[with-user]
(fn [{:keys [user]} [_ client]]
{:http {:token user
:method :get
:headers {"Content-Type" "application/edn"}
:uri (str "/api/yodlee2/fastlink?client=" client)
:owns-state {:single ::authenticating}
:on-success [::authenticated]
:on-error [::save-error]}}))
(re-frame/reg-event-fx
::authenticated
(fn [{:keys [db]} [_ authentication]]
{:db (-> db
(assoc-in [::authentication] authentication))}))
(re-frame/reg-event-db
::received
(fn [db [_ d]]
(assoc-in db [::yodlee-provider-accounts] (:yodlee-provider-account-page d))))
(defn yodlee-provider-accounts-table []
[table/table {:page @(re-frame/subscribe [::page])
:status @(re-frame/subscribe [::status/single ::page])}])
(defn yodlee-link-button []
[:div
(let [authentication @(re-frame/subscribe [::authentication])
status @(re-frame/subscribe [::status/single ::authenticating])
client-code (:code @(re-frame/subscribe [::subs/client]))]
(cond (and authentication client-code)
[:div
"Authentication successful!"
[:div#fa-spot]
[:button.button.is-primary {:on-click (fn []
(.open (.-fastlink js/window)
#js {"fastLinkURL" (:url authentication)
"accessToken" (:token authentication)
"params" #js { "configName" "Aggregation"}}
"fa-spot")
)}
[:span [:span.icon [:i.fa.fa-external-link]] " Go to yodlee"]]]
client-code
[:button.button.is-primary {:disabled (status/disabled-for status)
:class (status/class-for status)
:on-click (dispatch-event [::authenticate-with-yodlee client-code])}
"Authenticate with Yodlee (" client-code ")"]
:else
nil))])
(defn admin-yodlee-provider-accounts-content []
[:div
[:h1.title "Yodlee Provider Accounts"]
[yodlee-provider-accounts-table]
[yodlee-link-button]])
(defn admin-yodlee-provider-accounts-page []
(let [user (re-frame/subscribe [::subs/user])]
(reagent/create-class
{:component-will-unmount #(re-frame/dispatch [::unmounted])
:component-did-mount #(re-frame/dispatch [::mounted])
:reagent-render (fn []
(if (not= "manager" (:user/role @user))
[side-bar-layout {:side-bar [company-side-bar {}]
:main [admin-yodlee-provider-accounts-content]}]
[:div "Not authorized"]))})))

View File

@@ -1,36 +0,0 @@
(ns auto-ap.views.pages.company.yodlee2.form
(:require
[auto-ap.views.components.modal :as modal]
[re-frame.core :as re-frame]
[reagent.core :as r]))
(def form
(r/create-class {
:component-did-mount (fn [this]
(let [{:keys [authentication provider-account-id]} (r/props this)]
(try
(println (js/parseInt provider-account-id) (:url authentication) (:token authentication))
(.open (.-fastlink js/window)
#js {"fastLinkURL" (:url authentication)
"accessToken" (:token authentication)
"params" #js {"configName" "Aggregation"
"providerAccountId" (js/parseInt provider-account-id)
"flow" "edit"}}
"fa-modal-spot")
(catch js/Error e
(println e)))))
:reagent-render (fn [_]
[:div#fa-modal-spot])}))
(re-frame/reg-event-fx
::reauthenticate-start
(fn [_ [_ provider-account-id authentication]]
{:dispatch [::modal/modal-requested {:title (str "Reauthenticate " provider-account-id)
:body [form {:provider-account-id provider-account-id
:authentication authentication}]
:cancel? false}]}))

View File

@@ -1,134 +0,0 @@
(ns auto-ap.views.pages.company.yodlee2.table
(:require [auto-ap.status :as status]
[auto-ap.subs :as subs]
[auto-ap.views.components.buttons :as buttons]
[auto-ap.views.components.grid :as grid]
[auto-ap.views.components.modal :as modal]
[auto-ap.views.pages.company.yodlee2.form :as form]
[auto-ap.views.utils :refer [->$ action-cell-width date->str with-user dispatch-event]]
[re-frame.core :as re-frame]))
(re-frame/reg-event-fx
::refreshed
[with-user ]
(fn [_ _]
;; this is tracked in yodlee main, for refreshing
{}))
(re-frame/reg-event-fx
::request-refresh
[with-user ]
(fn [{:keys [user]} [_ provider-account client-id ]]
{:http {:token user
:method :post
:headers {"Content-Type" "application/edn"}
:uri (str "/api/yodlee2/provider-accounts/refresh/")
:owns-state {:multi ::refresh
:which provider-account}
:body {:client-id client-id
:provider-account-id provider-account}
:on-success [::refreshed provider-account]}}))
(re-frame/reg-event-fx
::provider-account-deleted
(fn [_ _]
{:dispatch [::modal/modal-closed ]}))
(re-frame/reg-event-fx
::request-login-form
[with-user ]
(fn [{:keys [user]} [_ provider-account client-id]]
{:http {:token user
:method :get
:headers {"Content-Type" "application/edn"}
:uri (str "/api/yodlee2/fastlink?client-id=" client-id)
:owns-state {:multi ::request-login-form
:which (:id provider-account)}
:on-success [::form/reauthenticate-start provider-account]}}))
(re-frame/reg-event-fx
::delete-provider-account
[with-user ]
(fn [{:keys [user]} [_ provider-account-id ]]
{:http {:token user
:method :post
:owns-state {:single ::delete-provider-account}
:headers {"Content-Type" "application/edn"}
:uri (str "/api/yodlee2/provider-accounts/delete/" )
:body {:client-id (:id @(re-frame/subscribe [::subs/client]))
:provider-account-id provider-account-id}
:on-success [::provider-account-deleted provider-account-id]
}}))
(re-frame/reg-event-fx
::delete-requested
[with-user]
(fn [_ [_ account-id]]
{:dispatch
[::modal/modal-requested {:title "Delete Provider account "
:body [:div "Are you sure you want to delete provider account " account-id "?"]
:confirm {:value "Delete provider account"
:status-from [::status/single ::delete-provider-account]
:class "is-danger"
:on-click (dispatch-event [::delete-provider-account account-id])
:close-event [::status/completed ::delete-provider-account]}
:cancel? true}]}))
(re-frame/reg-event-fx
::params-changed
(fn [{:keys [db]} [_ p]]
{:db (assoc db ::params p)}))
(re-frame/reg-sub
::params
(fn [db]
(-> db ::params)))
(defn table [{:keys [status page]}]
(let [params @(re-frame/subscribe [::params])
statuses @(re-frame/subscribe [::status/multi ::refresh])
login-statuses @(re-frame/subscribe [::status/multi ::request-login-form])
is-admin? @(re-frame/subscribe [::subs/is-admin?])]
[grid/grid {:status status
:on-params-change (fn [p]
(re-frame/dispatch [::params-changed p]))
:params params
:column-count 4}
[grid/controls page]
[grid/table {:fullwidth true}
[grid/header
[grid/row {}
[grid/header-cell {:style {:width "18em"}} "Provider Account"]
[grid/header-cell {:style {:width "20em"}} "Status"]
[grid/header-cell {:style {:width "20em"}} "Detailed Status"]
[grid/header-cell {:style {:width "12em"}} "Last Updated"]
[grid/header-cell {} "Accounts"]
[grid/header-cell {:style {:width (action-cell-width 3)}}]]]
[grid/body
(for [{:keys [id name accounts status detailed-status last-updated] :as c} (:data page)]
^{:key (str name "-" id)}
[grid/row {:class (:class c) :id id}
[grid/cell {} id]
[grid/cell {} status]
[grid/cell {} detailed-status]
[grid/cell {} (date->str last-updated)]
[grid/cell {}
[:ul
(for [a accounts]
^{:key (:id a)}
[:li (:name a) " - " (:number a) [:div.tag (->$ (:available-balance a))]])]]
[grid/cell {}
(when is-admin?
[:div.buttons
[buttons/fa-icon {:event
[::request-login-form (:id c) (:id (:client c))]
:class (status/class-for (get login-statuses (:id c)))
:icon "fa-pencil"}]
[buttons/fa-icon {:event [::request-refresh (:id c) (:id (:client c))]
:class (status/class-for (get statuses (:id c)))
:icon "fa-refresh"}]
[buttons/fa-icon {:event [::delete-requested (:id c)]
:icon "fa-times"}]])]])]]
]))