Undoes old way of doing forms in favor of context version. Much easier
This commit is contained in:
@@ -138,68 +138,3 @@
|
||||
(assoc-in [::forms id :error] nil)))
|
||||
|
||||
|
||||
(defn vertical-form [{:keys [can-submit id change-event submit-event fullwidth?] :or {fullwidth? true}}]
|
||||
{:form
|
||||
(fn [{:keys [title] :as params} & children]
|
||||
(let [{:keys [data active? error]} @(re-frame/subscribe [::form id])
|
||||
can-submit @(re-frame/subscribe can-submit)]
|
||||
|
||||
[:form { :on-submit (fn [e]
|
||||
(when (.-stopPropagation e)
|
||||
(.stopPropagation e)
|
||||
(.preventDefault e))
|
||||
(when can-submit
|
||||
(re-frame/dispatch-sync (vec (conj submit-event params)))))}
|
||||
[:h1.title.is-2 title]
|
||||
[:<>
|
||||
children]]))
|
||||
|
||||
:form-inline
|
||||
(fn [{:keys [title] :as params} children]
|
||||
(let [{:keys [data active? error]} @(re-frame/subscribe [::form id])
|
||||
can-submit @(re-frame/subscribe can-submit)]
|
||||
|
||||
[:form { :on-submit (fn [e]
|
||||
(when (.-stopPropagation e)
|
||||
(.stopPropagation e)
|
||||
(.preventDefault e))
|
||||
(when can-submit
|
||||
(re-frame/dispatch-sync (vec (conj submit-event params)))))}
|
||||
(when title
|
||||
[:h1.title.is-2 title])
|
||||
children]))
|
||||
:raw-field (fn [control]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::form id])]
|
||||
[bind-field (-> control
|
||||
(assoc-in [1 :subscription] data)
|
||||
(assoc-in [1 :event] change-event))]))
|
||||
:field-holder (fn [label control]
|
||||
[:div.field
|
||||
(when label (if fullwidth? [:p.help label]
|
||||
[:label.label label]))
|
||||
[:div.control control]])
|
||||
:field ^{:key "field"}
|
||||
(fn [label control]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::form id])]
|
||||
[:div.field
|
||||
(when label (if fullwidth? [:p.help label]
|
||||
[:label.label label]))
|
||||
[:div.control [bind-field (-> control
|
||||
(assoc-in [1 :subscription] data)
|
||||
(assoc-in [1 :event] change-event))]]]))
|
||||
|
||||
:error-notification
|
||||
(fn []
|
||||
(when-let [error (:error @(re-frame/subscribe [::form id]))]
|
||||
^{:key error}
|
||||
[:div.has-text-danger.animated.fadeInUp {} error]))
|
||||
:submit-button (fn [child]
|
||||
(let [error (:error @(re-frame/subscribe [::form id]))
|
||||
status @(re-frame/subscribe [::status/single id])
|
||||
can-submit @(re-frame/subscribe can-submit)]
|
||||
[:button.button.is-medium.is-primary {:disabled (or (status/disabled-for status)
|
||||
(not can-submit))
|
||||
:class (cond-> (status/class-for status)
|
||||
fullwidth? (conj "is-fullwidth")) }
|
||||
child]))})
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
(let [data-sub (or data-sub [::forms/form id])
|
||||
change-event (or change-event [::forms/change id])
|
||||
{:keys [data error] form-key :id} @(re-frame/subscribe data-sub)
|
||||
status @(re-frame/subscribe [::status/single id])]
|
||||
(r/create-element Provider #js {:value #js {:can-submit @(re-frame/subscribe can-submit)
|
||||
status @(re-frame/subscribe [::status/single id])
|
||||
can-submit (if can-submit @(re-frame/subscribe can-submit)
|
||||
true)]
|
||||
(r/create-element Provider #js {:value #js {:can-submit can-submit
|
||||
:change-event change-event
|
||||
:submit-event submit-event
|
||||
:error error
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.components.typeahead.vendor :refer [search-backed-typeahead]]
|
||||
@@ -10,17 +9,13 @@
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[clojure.string :as str]
|
||||
[goog.string :as gstring]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
(fn [db]
|
||||
true))
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.forms.builder :as form-builder]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::try-save
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{:keys [db]} [_ id ]]
|
||||
(fn [{:keys [db]} _]
|
||||
(let [{{:keys [ total]} :invoice
|
||||
:keys [expense-accounts]} (:data db)
|
||||
expense-accounts (vals expense-accounts)
|
||||
@@ -44,7 +39,7 @@
|
||||
(re-frame/reg-event-fx
|
||||
::save
|
||||
[with-user (forms/in-form ::form)]
|
||||
(fn [{:keys [db user] } [_ id]]
|
||||
(fn [{:keys [db user] } _]
|
||||
(let [{{:keys [id]} :invoice
|
||||
:keys [expense-accounts]} (:data db)
|
||||
expense-accounts (vals expense-accounts)]
|
||||
@@ -85,16 +80,10 @@
|
||||
(fn [db [_ x]]
|
||||
(update-in db [:data :expense-accounts] dissoc x)))
|
||||
|
||||
(def change-expense-accounts-form (forms/vertical-form {:submit-event [::try-save]
|
||||
:change-event [::forms/change ::form]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}))
|
||||
|
||||
(defn form []
|
||||
(let [{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])
|
||||
expense-accounts (:expense-accounts data)
|
||||
{:keys [total] :or {total 0} {:keys [locations] :as client} :client} (:invoice data)
|
||||
{:keys [form-inline horizontal-field field raw-field error-notification submit-button]} change-expense-accounts-form
|
||||
multi-location? (> (count locations) 1)
|
||||
expense-accounts-total (->> expense-accounts
|
||||
vals
|
||||
@@ -108,72 +97,75 @@
|
||||
[:div
|
||||
[:div
|
||||
[:a.button.is-outlined {:on-click (dispatch-event [::add-split])} "Add split"]]
|
||||
(form-inline {}
|
||||
[:table.table
|
||||
[:thead
|
||||
[:tr
|
||||
[:th {:style {:width "500px"}} "Expense Account"]
|
||||
(when multi-location?
|
||||
[:th {:style {:width "200px"}} "Location"])
|
||||
[:th {:style {:width "200px"}} "Original Amount"]
|
||||
[:th {:style {:width "300px"}} "Amount"]
|
||||
[:th {:style {:width "5em"}}]]]
|
||||
[:tbody
|
||||
(doall (for [[id expense-account] expense-accounts]
|
||||
^{:key id}
|
||||
[:tr
|
||||
[:td.expandable [:div.control
|
||||
(raw-field
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_account
|
||||
{:query i
|
||||
:client-id (:id client)}
|
||||
[:name :id :location]])
|
||||
:type "typeahead-v3"
|
||||
:field [:expense-accounts id :account]}])]]
|
||||
[form-builder/builder {:submit-event [::try-save]
|
||||
:id ::form}
|
||||
[:table.table
|
||||
[:thead
|
||||
[:tr
|
||||
[:th {:style {:width "500px"}} "Expense Account"]
|
||||
(when multi-location?
|
||||
[:th {:style {:width "200px"}} "Location"])
|
||||
[:th {:style {:width "200px"}} "Original Amount"]
|
||||
[:th {:style {:width "300px"}} "Amount"]
|
||||
[:th {:style {:width "5em"}}]]]
|
||||
[:tbody
|
||||
(doall (for [[id _] expense-accounts]
|
||||
^{:key id}
|
||||
[:tr
|
||||
[:td.expandable [:div.control
|
||||
[form-builder/raw-field
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_account
|
||||
{:query i
|
||||
:client-id (:id client)}
|
||||
[:name :id :location]])
|
||||
:type "typeahead-v3"
|
||||
:field [:expense-accounts id :account]}]]]]
|
||||
|
||||
(when multi-location?
|
||||
[:td
|
||||
(if-let [forced-location (get-in expense-accounts [id :account :location])]
|
||||
[:div.select
|
||||
[:select {:disabled "disabled" :value forced-location} [:option {:value forced-location} forced-location]]]
|
||||
[:div.select
|
||||
(raw-field
|
||||
[:select {:type "select"
|
||||
:field [:expense-accounts id :location]
|
||||
:spec (set locations)}
|
||||
(map (fn [l] ^{:key l} [:option {:value l} l]) locations)])])])
|
||||
|
||||
[:td
|
||||
(str "$" (get-in expense-accounts [id :amount]))]
|
||||
[:td
|
||||
[:div.control
|
||||
[:div.field.has-addons.is-extended
|
||||
[:p.control [:a.button.is-static "$"]]
|
||||
[:p.control
|
||||
(raw-field
|
||||
[:input.input {:type "number"
|
||||
:field [:expense-accounts id :new-amount-temp]
|
||||
:style {:text-align "right"}
|
||||
:on-blur (dispatch-event [::forms/change ::form [:expense-accounts id :new-amount] (get-in expense-accounts [id :new-amount-temp])])
|
||||
:on-key-down (fn [e ]
|
||||
(if (= 13 (.-keyCode e))
|
||||
(do
|
||||
(re-frame/dispatch [::forms/change ::form [:expense-accounts id :new-amount] (get-in expense-accounts [id :new-amount-temp])])
|
||||
true)
|
||||
false))
|
||||
:max (:total data)
|
||||
:step "0.01"}])]]]]
|
||||
[:td [:a.button {:on-click (dispatch-event [::remove-expense-account-split id])} [:i.fa.fa-times]]]]))
|
||||
[:tr
|
||||
[:td.no-border { :col-span (if multi-location? "3" "2") :style { :text-align "right"} } "Invoice total: "]
|
||||
[:td.no-border { :style { :text-align "right"} } (str (gstring/format "$%.2f" total ) )]]
|
||||
[:tr
|
||||
[:td { :col-span (if multi-location? "3" "2") :style { :text-align "right"} } "Account total: "]
|
||||
[:td { :style { :text-align "right"} } (str (gstring/format "$%.2f" expense-accounts-total ) )]]
|
||||
[:tr
|
||||
[:td.no-border { :col-span (if multi-location? "3" "2") :style { :text-align "right"} } "Difference: "]
|
||||
[:td.no-border { :style { :text-align "right"} } (str (gstring/format "$%.2f" (- total expense-accounts-total) ) )]]]])]))
|
||||
(when multi-location?
|
||||
[:td
|
||||
(if-let [forced-location (get-in expense-accounts [id :account :location])]
|
||||
[:div.select
|
||||
[:select {:disabled "disabled" :value forced-location} [:option {:value forced-location} forced-location]]]
|
||||
[:div.select
|
||||
|
||||
[form-builder/raw-field
|
||||
[:select {:type "select"
|
||||
:field [:expense-accounts id :location]
|
||||
:spec (set locations)}
|
||||
(map (fn [l] ^{:key l} [:option {:value l} l]) locations)]]])])
|
||||
|
||||
[:td
|
||||
(str "$" (get-in expense-accounts [id :amount]))]
|
||||
[:td
|
||||
[:div.control
|
||||
[:div.field.has-addons.is-extended
|
||||
[:p.control [:a.button.is-static "$"]]
|
||||
[:p.control
|
||||
[form-builder/raw-field
|
||||
[:input.input {:type "number"
|
||||
:field [:expense-accounts id :new-amount-temp]
|
||||
:style {:text-align "right"}
|
||||
:on-blur (dispatch-event [::forms/change ::form [:expense-accounts id :new-amount] (get-in expense-accounts [id :new-amount-temp])])
|
||||
:on-key-down (fn [e ]
|
||||
(if (= 13 (.-keyCode e))
|
||||
(do
|
||||
(re-frame/dispatch [::forms/change ::form [:expense-accounts id :new-amount] (get-in expense-accounts [id :new-amount-temp])])
|
||||
true)
|
||||
false))
|
||||
:max (:total data)
|
||||
:step "0.01"}]]]]]]
|
||||
[:td [:a.button {:on-click (dispatch-event [::remove-expense-account-split id])} [:i.fa.fa-times]]]]))
|
||||
[:tr
|
||||
[:td.no-border { :col-span (if multi-location? "3" "2") :style { :text-align "right"} } "Invoice total: "]
|
||||
[:td.no-border { :style { :text-align "right"} } (str (gstring/format "$%.2f" total ) )]]
|
||||
[:tr
|
||||
[:td { :col-span (if multi-location? "3" "2") :style { :text-align "right"} } "Account total: "]
|
||||
[:td { :style { :text-align "right"} } (str (gstring/format "$%.2f" expense-accounts-total ) )]]
|
||||
[:tr
|
||||
[:td.no-border { :col-span (if multi-location? "3" "2") :style { :text-align "right"} } "Difference: "]
|
||||
[:td.no-border { :style { :text-align "right"} } (str (gstring/format "$%.2f" (- total expense-accounts-total) ) )]]]]
|
||||
[form-builder/hidden-submit-button]]]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::show
|
||||
@@ -184,11 +176,10 @@
|
||||
:status-from [::status/single ::form]
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::try-save])
|
||||
:can-submit [::can-submit]
|
||||
:close-event [::status/completed ::form]}}]
|
||||
:db (-> db
|
||||
(forms/start-form ::form
|
||||
(forms/start-form ::form
|
||||
|
||||
{:expense-accounts (by :id
|
||||
(:expense-accounts i))
|
||||
:invoice i}))}))
|
||||
{:expense-accounts (by :id
|
||||
(:expense-accounts i))
|
||||
:invoice i}))}))
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[react :as react]))
|
||||
(def good-$ #"^\-?[0-9]+(\.[0-9][0-9])?$")
|
||||
|
||||
(defn -money-field [{:keys [min max disabled on-change value class style]}]
|
||||
(defn -money-field [{:keys [min max disabled on-change value class style placeholder]}]
|
||||
(let [[ parsed-amount set-parsed-amount] (react/useState {:parsed value
|
||||
:raw (cond
|
||||
(str/blank? value)
|
||||
@@ -40,6 +40,7 @@
|
||||
[:div.control.has-icons-left
|
||||
[:input.input {:type "text"
|
||||
:disabled disabled
|
||||
:placeholder placeholder
|
||||
:class class
|
||||
:on-change (fn [e]
|
||||
(let [raw (.. e -target -value)
|
||||
|
||||
@@ -119,7 +119,9 @@
|
||||
[:div.level-item
|
||||
[:div.control
|
||||
[:div.tags.has-addons
|
||||
[:span.tag (:name selectedItem)]
|
||||
[:span.tag (if entity->text
|
||||
(entity->text selectedItem)
|
||||
(:name selectedItem))]
|
||||
(when name
|
||||
[:input {:type "hidden" :name name :value (:id (js->clj selectedItem :keywordize-keys true))}])
|
||||
(when-not disabled
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.layouts :refer [side-bar]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.utils :refer [dispatch-event multi-field]]
|
||||
[auto-ap.views.utils :refer [dispatch-event multi-field with-user]]
|
||||
[clojure.spec.alpha :as s]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]))
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.forms.builder :as form-builder]
|
||||
[vimsical.re-frame.cofx.inject :as inject]))
|
||||
|
||||
(def types [:dividend :expense :asset :liability :equity :revenue])
|
||||
(def applicabilities [:global :optional :customized])
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::request
|
||||
:<- [::forms/form ::form]
|
||||
@@ -51,103 +51,99 @@
|
||||
(re-frame/reg-event-fx
|
||||
::edited
|
||||
[(forms/triggers-saved ::form :upsert-account)]
|
||||
(fn [{:keys [db]} [_ {:keys [upsert-account]}]]))
|
||||
(fn [_ [_ _]]))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::add-client-override
|
||||
[(forms/in-form ::form)]
|
||||
(fn [form]
|
||||
(update form :data (fn [data]
|
||||
(-> data
|
||||
(update :client-overrides conj (:new-client-override data))
|
||||
(dissoc :new-client-override))))))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::saving
|
||||
(fn [{:keys [db]} _]
|
||||
[with-user (re-frame/inject-cofx ::inject/sub [::request]) ]
|
||||
(fn [{:keys [user] ::keys [request]} _]
|
||||
(when @(re-frame/subscribe [::can-submit])
|
||||
(let [{{:keys [id type name numeric-code account-set]} :data :as data} @(re-frame/subscribe [::forms/form ::form])]
|
||||
{:db (forms/loading db ::form )
|
||||
:graphql
|
||||
{:token (-> db :user)
|
||||
(let [_ @(re-frame/subscribe [::forms/form ::form])]
|
||||
{:graphql
|
||||
{:owns-state {:single ::form}
|
||||
:token user
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
:operation/name "UpsertAccount"}
|
||||
:venia/queries [{:query/data [:upsert-account
|
||||
{:account @(re-frame/subscribe [::request])}
|
||||
{:account request}
|
||||
[:id :type :name :account-set :numeric-code :location :applicability [:client-overrides [:name :id [:client [:id :name]]]]]]}]}
|
||||
:on-success [::edited]
|
||||
:on-error [::forms/save-error ::form]}}))))
|
||||
|
||||
(def account-form (forms/vertical-form {:can-submit [::can-submit]
|
||||
:change-event [::forms/change ::form]
|
||||
:submit-event [::saving]
|
||||
:id ::form}))
|
||||
|
||||
(defn form [_]
|
||||
(let [{error :error account :data } @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline field field-holder raw-field error-notification submit-button]} account-form]
|
||||
|
||||
^{:key (:id account)}
|
||||
(let [{account :data } @(re-frame/subscribe [::forms/form ::form])]
|
||||
[side-bar {:on-close (dispatch-event [::forms/form-closing ::form])}
|
||||
(form-inline {:title (if (:id account)
|
||||
"Edit account"
|
||||
"Add account")}
|
||||
[:<>
|
||||
[form-builder/builder {:can-submit [::can-submit]
|
||||
:change-event [::forms/change ::form]
|
||||
:submit-event [::saving]
|
||||
:id ::form}
|
||||
[form-builder/section {:title (if (:id account)
|
||||
"Edit account"
|
||||
"Add account")}
|
||||
[form-builder/field
|
||||
"Account Set"
|
||||
[:input.input {:type "text"
|
||||
:field :account-set
|
||||
:disabled (boolean (:id account))
|
||||
:spec ::entity/account-set}]]
|
||||
|
||||
(field "Account Set"
|
||||
[:input.input {:type "text"
|
||||
:field :account-set
|
||||
:disabled (boolean (:id account))
|
||||
:spec ::entity/account-set}])
|
||||
[form-builder/field
|
||||
"Code"
|
||||
[:input.input {:type "text"
|
||||
:field :numeric-code
|
||||
:disabled (boolean (:id account))
|
||||
:spec ::entity/numeric-code}]]
|
||||
|
||||
(field "Code"
|
||||
[:input.input {:type "text"
|
||||
:field :numeric-code
|
||||
:disabled (boolean (:id account))
|
||||
:spec ::entity/numeric-code}])
|
||||
[form-builder/field
|
||||
"Name"
|
||||
[:input.input {:type "text"
|
||||
:field :name
|
||||
:spec ::entity/name}]]
|
||||
|
||||
(field "Name"
|
||||
[:input.input {:type "text"
|
||||
:field :name
|
||||
:spec ::entity/name}])
|
||||
|
||||
(field-holder "Account Type"
|
||||
[:div.select
|
||||
(raw-field
|
||||
[:select {:type "select"
|
||||
:field :type
|
||||
:spec (set types)}
|
||||
(map (fn [l]
|
||||
[:option {:value (name l)} (str/capitalize (name l))]) types)])])
|
||||
[form-builder/vertical-control
|
||||
"Account Type"
|
||||
[:div.select
|
||||
[form-builder/raw-field
|
||||
[:select {:type "select"
|
||||
:field :type
|
||||
:spec (set types)}
|
||||
(map (fn [l]
|
||||
[:option {:value (name l)} (str/capitalize (name l))]) types)]]]]
|
||||
|
||||
|
||||
(field "Location"
|
||||
[:input.input.known-field.location {:type "text"
|
||||
:field :location
|
||||
:spec ::entity/location}])
|
||||
[form-builder/field
|
||||
"Location"
|
||||
[:input.input.known-field.location {:type "text"
|
||||
:field :location
|
||||
:spec ::entity/location}]]
|
||||
|
||||
[:h2.subtitle "Client"]
|
||||
(field-holder "Applicability"
|
||||
[:div.select
|
||||
(raw-field
|
||||
[:select {:type "select"
|
||||
:field :applicability
|
||||
:spec (set applicabilities)}
|
||||
(map (fn [l]
|
||||
[:option {:value (name l)} (str/capitalize (name l))]) applicabilities)])])
|
||||
(field "Customizations"
|
||||
[multi-field {:type "multi-field"
|
||||
:field [:client-overrides]
|
||||
:template [[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
||||
:style {:width "13em"}
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:field [:client]}]
|
||||
[:input.input {:type "text"
|
||||
:style {:width "15em"}
|
||||
:placeholder "Bubblegum"
|
||||
:field [:name]}]
|
||||
]}])
|
||||
(error-notification)
|
||||
[form-builder/section {:title "Client"}
|
||||
[:h2.subtitle "Client"]
|
||||
[form-builder/vertical-control
|
||||
"Applicability"
|
||||
[:div.select
|
||||
[form-builder/raw-field
|
||||
[:select {:type "select"
|
||||
:field :applicability
|
||||
:spec (set applicabilities)}
|
||||
(map (fn [l]
|
||||
[:option {:value (name l)} (str/capitalize (name l))]) applicabilities)]]]]
|
||||
[form-builder/field
|
||||
"Customizations"
|
||||
[multi-field {:type "multi-field"
|
||||
:field [:client-overrides]
|
||||
:template [[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
||||
:style {:width "13em"}
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:field [:client]}]
|
||||
[:input.input {:type "text"
|
||||
:style {:width "15em"}
|
||||
:placeholder "Bubblegum"
|
||||
:field [:name]}]
|
||||
]}]]]
|
||||
[form-builder/error-notification]
|
||||
|
||||
(submit-button "Save")])]))
|
||||
[form-builder/submit-button "Save"]]]]))
|
||||
|
||||
@@ -3,13 +3,16 @@
|
||||
[auto-ap.entities.transaction-rule :as entity]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.forms.builder :as form-builder]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.level :refer [left-stack]]
|
||||
[auto-ap.views.components.button-radio :refer [button-radio]]
|
||||
[auto-ap.views.components.expense-accounts-field
|
||||
:as expense-accounts-field
|
||||
:refer [expense-accounts-field]]
|
||||
[auto-ap.views.components.layouts :as layouts]
|
||||
[auto-ap.views.components.money-field :refer [money-field]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
@@ -29,7 +32,6 @@
|
||||
::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
|
||||
@@ -185,18 +187,21 @@
|
||||
: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)
|
||||
[])]
|
||||
:else
|
||||
[]))))
|
||||
::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
|
||||
@@ -223,9 +228,8 @@
|
||||
(re-frame/reg-event-fx
|
||||
::updated
|
||||
[(forms/triggers-stop ::form)]
|
||||
(fn [{:keys [db]} [_ {:keys [rule-saved]} result]]
|
||||
{:db (forms/start-form db ::form {:client @(re-frame/subscribe [::subs/client])})
|
||||
:dispatch (conj rule-saved (:upsert-transaction-rule result))}))
|
||||
(fn [{:keys [db]} [_ {:keys [rule-saved]} _]]
|
||||
{:db (forms/start-form db ::form {:client @(re-frame/subscribe [::subs/client])})}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::succeeded-test
|
||||
@@ -238,10 +242,6 @@
|
||||
|
||||
;; VIEWS
|
||||
|
||||
(def rule-form (forms/vertical-form {:can-submit [::can-submit]
|
||||
:change-event [::changed]
|
||||
:submit-event [::saving ]
|
||||
:id ::form}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
@@ -263,131 +263,127 @@
|
||||
|
||||
(defn form-contents [params]
|
||||
[layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form ])}
|
||||
(let [{:keys [data id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline field raw-field error-notification submit-button ]} rule-form
|
||||
default-note @(re-frame/subscribe [::default-note])
|
||||
test-state @(re-frame/subscribe [::status/single ::test])]
|
||||
^{:key id}
|
||||
(form-inline (assoc params :title "New Transaction Rule")
|
||||
[:<>
|
||||
|
||||
(let [{:keys [data id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
default-note @(re-frame/subscribe [::default-note])
|
||||
test-state @(re-frame/subscribe [::status/single ::test])]
|
||||
[form-builder/builder {:can-submit [::can-submit]
|
||||
:change-event [::changed]
|
||||
:submit-event [::saving ]
|
||||
:id ::form}
|
||||
[form-builder/section {:title "Transaction Rule"}
|
||||
[form-builder/field {:required? true}
|
||||
"Client"
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
||||
:auto-focus true
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:field [:client]
|
||||
:spec ::entity/client}]]
|
||||
|
||||
(field "Client"
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
||||
:auto-focus true
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:field [:client]
|
||||
:spec ::entity/client}])
|
||||
|
||||
[form-builder/field
|
||||
"Bank account"
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/real-bank-accounts-for-client (:client data)])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:field [:bank-account]
|
||||
:spec ::entity/bank-account}]]
|
||||
|
||||
|
||||
(with-meta
|
||||
(field "Bank account"
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/real-bank-accounts-for-client (:client data)])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:field [:bank-account]
|
||||
:spec ::entity/bank-account}])
|
||||
;; TODO this forces unmounting when client changes, since it is an "uncontorlled" input
|
||||
{:key (str "client-" (:id (:client data)))})
|
||||
#_[form-builder/field
|
||||
"Yodlee Merchant"
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/yodlee-merchants])
|
||||
:entity->text #(str (:name %) " - " (:yodlee-id %))
|
||||
:type "typeahead-v3"
|
||||
:field [:yodlee-merchant]}]]
|
||||
|
||||
(field "Yodlee Merchant"
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/yodlee-merchants])
|
||||
:entity->text #(str (:name %) " - " (:yodlee-id %))
|
||||
:type "typeahead-v3"
|
||||
:field [:yodlee-merchant]}])
|
||||
[form-builder/field
|
||||
[:span "Description (" [:a {:href "https://regex101.com" :target "_new"} "regex tester"] ")" ]
|
||||
[:input.input {:type "text"
|
||||
:field [:description]
|
||||
:spec ::entity/description}]]
|
||||
|
||||
(field [:span "Description (" [:a {:href "https://regex101.com" :target "_new"} "regex tester"] ")" ]
|
||||
[:input.input {:type "text"
|
||||
:field [:description]
|
||||
:spec ::entity/description}])
|
||||
[:div.field
|
||||
[:p.help "Amount"]
|
||||
[left-stack
|
||||
[form-builder/raw-field
|
||||
[money-field {:type "money"
|
||||
:placeholder ">="
|
||||
:field [:amount-gte]
|
||||
:spec ::entity/amount-gte}]]
|
||||
"-"
|
||||
[form-builder/raw-field
|
||||
[money-field {:type "money"
|
||||
:placeholder "<="
|
||||
:field [:amount-lte]
|
||||
:spec ::entity/amount-lte}]]]]
|
||||
|
||||
[:div.field
|
||||
[:p.help "Amount"]
|
||||
[:div.control
|
||||
[:div.columns
|
||||
[:div.column
|
||||
(raw-field
|
||||
[:input.input {:type "number"
|
||||
:placeholder ">="
|
||||
:field [:amount-gte]
|
||||
:spec ::entity/amount-gte
|
||||
:step "0.01"}])]
|
||||
[:div.column
|
||||
(raw-field
|
||||
[:input.input {:type "number"
|
||||
:placeholder "<="
|
||||
:field [:amount-lte]
|
||||
:spec ::entity/amount-lte
|
||||
:step "0.01"}])]]]]
|
||||
[:div.field
|
||||
[:p.help "Day of Month"]
|
||||
[:div.control
|
||||
[:div.columns
|
||||
[:div.column
|
||||
[form-builder/raw-field
|
||||
[:input.input {:type "number"
|
||||
:placeholder ">="
|
||||
:field [:dom-gte]
|
||||
:spec ::entity/dom-gte
|
||||
:precision 0
|
||||
:step "1"}]]]
|
||||
[:div.column
|
||||
[form-builder/raw-field
|
||||
[:input.input {:type "number"
|
||||
:placeholder "<="
|
||||
:field [:dom-lte]
|
||||
:spec ::entity/dom-lte
|
||||
:precision 0
|
||||
:step "1"}]]]]]]
|
||||
|
||||
[:div.field
|
||||
[:p.help "Day of Month"]
|
||||
[:div.control
|
||||
[:div.columns
|
||||
[:div.column
|
||||
(raw-field
|
||||
[:input.input {:type "number"
|
||||
:placeholder ">="
|
||||
:field [:dom-gte]
|
||||
:spec ::entity/dom-gte
|
||||
:precision 0
|
||||
:step "1"}])]
|
||||
[:div.column
|
||||
(raw-field
|
||||
[:input.input {:type "number"
|
||||
:placeholder "<="
|
||||
:field [:dom-lte]
|
||||
:spec ::entity/dom-lte
|
||||
:precision 0
|
||||
:step "1"}])]]]]
|
||||
[:h2.title.is-4 "Outcomes"]
|
||||
|
||||
[:h2.title.is-4 "Outcomes"]
|
||||
[form-builder/field "Assign Vendor"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:field [:vendor]}]]
|
||||
|
||||
(field "Assign Vendor"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:field [:vendor]}])
|
||||
[form-builder/raw-field
|
||||
[expense-accounts-field {:type "expense-accounts"
|
||||
: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
|
||||
:field [:accounts]}]]
|
||||
|
||||
(with-meta
|
||||
(field nil
|
||||
[expense-accounts-field {:type "expense-accounts"
|
||||
: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
|
||||
:field [:accounts]}])
|
||||
{:key (str (some-> data :vendor :id str) "-" (some-> data :client :id str))})
|
||||
[form-builder/field
|
||||
"Approval Status"
|
||||
[button-radio
|
||||
{:type "button-radio"
|
||||
:field [:transaction-approval-status]
|
||||
:options [[:unapproved "Unapproved"]
|
||||
[:requires-feedback "Client Review"]
|
||||
[:approved "Approved"]
|
||||
[:excluded "Excluded from Ledger"]]}]]
|
||||
|
||||
(field "Approval Status"
|
||||
[button-radio
|
||||
{:type "button-radio"
|
||||
:field [:transaction-approval-status]
|
||||
:options [[:unapproved "Unapproved"]
|
||||
[:requires-feedback "Client Review"]
|
||||
[:approved "Approved"]
|
||||
[:excluded "Excluded from Ledger"]]}])
|
||||
[form-builder/field "Note"
|
||||
[:input.input {:type "text"
|
||||
:field [:note]
|
||||
:placeholder default-note
|
||||
:spec (s/nilable ::entity/note)}]]
|
||||
|
||||
(field "Note"
|
||||
[:input.input {:type "text"
|
||||
:field [:note]
|
||||
:placeholder default-note
|
||||
:spec (s/nilable ::entity/note)}])
|
||||
|
||||
[:div.is-divider]
|
||||
(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
|
||||
(submit-button "Save")]]]))])
|
||||
[: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
|
||||
|
||||
@@ -1,49 +1,14 @@
|
||||
(ns auto-ap.views.pages.admin.users.form
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[clojure.string :as str]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.entities.clients :as entity]
|
||||
[auto-ap.views.components.address :refer [address-field]]
|
||||
[auto-ap.views.components.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[auto-ap.views.utils :refer [login-url dispatch-value-change bind-field horizontal-field dispatch-event with-user]]
|
||||
[auto-ap.views.components.grid :as grid]
|
||||
[auto-ap.utils :refer [by replace-if]]
|
||||
[cljs.reader :as edn]
|
||||
[auto-ap.routes :as routes]
|
||||
[bidi.bidi :as bidi]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.views.components.modal :as modal]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
(fn [db]
|
||||
true))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::changed
|
||||
(forms/change-handler ::form
|
||||
(fn [data field value]
|
||||
[])))
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::add-client
|
||||
[(forms/in-form ::form)]
|
||||
(fn [form [_ d]]
|
||||
(let [client (get @(re-frame/subscribe [::subs/clients-by-id])
|
||||
(get-in form [:data :adding-client]))]
|
||||
(update-in form [:data :clients] conj client ))))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::remove-client
|
||||
[(forms/in-form ::form)]
|
||||
(fn [form [_ d]]
|
||||
(update-in form [:data :clients] #(filter (fn [c] (not= (:id c) d)) %))))
|
||||
(:require
|
||||
[auto-ap.entities.clients :as entity]
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.forms.builder :as form-builder]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.utils :refer [dispatch-event multi-field with-user]]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::saving
|
||||
@@ -56,7 +21,7 @@
|
||||
:operation/name "EditUser"}
|
||||
:venia/queries [{:query/data [:edit-user
|
||||
{:edit-user (-> (:data db)
|
||||
(update :clients #(map :id %))
|
||||
(update :clients #(map (comp :id :client) %))
|
||||
(select-keys #{:id :name :clients :role}))}
|
||||
[:id :name :role [:clients [:id :name]]]]}]}
|
||||
:on-success [::saved]}}))
|
||||
@@ -64,66 +29,54 @@
|
||||
(re-frame/reg-event-fx
|
||||
::saved
|
||||
(forms/triggers-stop ::form)
|
||||
(fn [{:keys [db]} [_ {:keys [edit-user]}]]
|
||||
(fn [_ _]
|
||||
{:dispatch [::modal/modal-closed]}))
|
||||
|
||||
(def user-form (forms/vertical-form {:submit-event [::saving]
|
||||
:change-event [::changed]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}))
|
||||
|
||||
(defn form []
|
||||
(let [{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline field raw-field error-notification submit-button]} user-form]
|
||||
(form-inline {}
|
||||
[:<>
|
||||
(field "Name"
|
||||
[:input.input {:type "text"
|
||||
:field [:name]
|
||||
:spec ::entity/name}])
|
||||
[:div.field
|
||||
[:p.help "Role"]
|
||||
[:div.control
|
||||
[:div.select
|
||||
[raw-field
|
||||
[:select {:type "select"
|
||||
:field [:role]}
|
||||
[:option {:value ":none"} "None"]
|
||||
[:option {:value ":user"} "User"]
|
||||
[:option {:value ":manager"} "Manager"]
|
||||
[:option {:value ":power_user"} "Power User"]
|
||||
[:option {:value ":admin"} "Admin"]]]]]]
|
||||
(when (#{":user" ":manager" ":power_user"} (:role data))
|
||||
[:div.field
|
||||
[:p.help "Clients"]
|
||||
[:div.control
|
||||
[:div.field.has-addons
|
||||
[:div.control
|
||||
[:div.select
|
||||
[raw-field
|
||||
[:select {:type "select"
|
||||
:field [:adding-client]}
|
||||
[:option]
|
||||
(let [used-clients (set (map :id (:clients data)))]
|
||||
(for [{:keys [id name] :as client} @(re-frame/subscribe [::subs/clients])
|
||||
:when (not (used-clients id))]
|
||||
^{:key id} [:option {:value id} name]))]]]]
|
||||
[:p.control
|
||||
[:button.button.is-primary {:on-click (dispatch-event [::add-client])} "Add"]]]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])
|
||||
clients @(re-frame/subscribe [::subs/clients])]
|
||||
[form-builder/builder {:submit-event [::saving]
|
||||
:id ::form}
|
||||
[form-builder/field
|
||||
"Name"
|
||||
[:input.input {:type "text"
|
||||
:field [:name]
|
||||
:spec ::entity/name}]]
|
||||
[:div.field
|
||||
[:p.help "Role"]
|
||||
[:div.control
|
||||
[:div.select
|
||||
[form-builder/raw-field
|
||||
[:select {:type "select"
|
||||
:field [:role]}
|
||||
[:option {:value ":none"} "None"]
|
||||
[:option {:value ":user"} "User"]
|
||||
[:option {:value ":manager"} "Manager"]
|
||||
[:option {:value ":power_user"} "Power User"]
|
||||
[:option {:value ":admin"} "Admin"]]]]]]
|
||||
(when (#{":user" ":manager" ":power_user"} (:role data))
|
||||
[form-builder/field
|
||||
"Client"
|
||||
[multi-field {:type "multi-field"
|
||||
:field [:clients]
|
||||
:template [[typeahead-v3 {:entities clients
|
||||
:entity->text :name
|
||||
:style {:width "13em"}
|
||||
:type "typeahead-v3"
|
||||
:field [:client]}]]}]])
|
||||
[form-builder/hidden-submit-button]]))
|
||||
|
||||
[:ul
|
||||
(for [{:keys [id name]} (:clients data)]
|
||||
^{:key id} [:li name [:a.icon {:on-click (dispatch-event [::remove-client id])} [:i.fa.fa-times ]]])]]])])))
|
||||
(re-frame/reg-event-fx
|
||||
::editing
|
||||
(fn [{:keys [db]} [_ d]]
|
||||
{:db (-> db
|
||||
(forms/start-form ::form d))
|
||||
:dispatch [::modal/modal-requested {:title (str "Edit user " (:name d))
|
||||
:body [form]
|
||||
:cancel? false
|
||||
:confirm {:value "Save"
|
||||
{:db (-> db
|
||||
(forms/start-form ::form (update d :clients #(map (fn [x] {:client x}) %))))
|
||||
:dispatch [::modal/modal-requested {:title (str "Edit user " (:name d))
|
||||
:body [form]
|
||||
:cancel? false
|
||||
:confirm {:value "Save"
|
||||
:status-from [::status/single ::form]
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::saving])
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::saving])
|
||||
:close-event [::status/completed ::form]}}]}))
|
||||
|
||||
@@ -7,59 +7,51 @@
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.utils :refer [dispatch-event]]
|
||||
[re-frame.core :as re-frame]))
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.forms.builder :as form-builder]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
:<- [::forms/form ::form]
|
||||
(fn [{:keys [data]}]
|
||||
(println data)
|
||||
(and (:from data)
|
||||
(:to data))))
|
||||
|
||||
(def merge-form (forms/vertical-form {:submit-event [::save]
|
||||
:change-event [::forms/change ::form]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}))
|
||||
|
||||
(defn form []
|
||||
(let [_ @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline field]} merge-form]
|
||||
|
||||
|
||||
(form-inline {}
|
||||
[:<>
|
||||
(field "Form Vendor (will be deleted)"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:from]}])
|
||||
[form-builder/builder {:submit-event [::save]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}
|
||||
[form-builder/field "Form Vendor (will be deleted)"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:from]}]]
|
||||
|
||||
|
||||
(field "To Vendor"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:field [:to]}])])))
|
||||
[form-builder/field "To Vendor"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:field [:to]}]]
|
||||
[form-builder/hidden-submit-button]])
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::show
|
||||
(fn [{:keys [db]} _]
|
||||
{:dispatch [::modal/modal-requested {:title "Merge Vendors"
|
||||
:body [form]
|
||||
{:dispatch [::modal/modal-requested {:title "Merge Vendors"
|
||||
:body [form]
|
||||
:confirm {:value "Merge"
|
||||
:status-from [::status/single ::form]
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::save])
|
||||
:can-submit [::can-submit]
|
||||
:close-event [::status/completed ::form]}}]
|
||||
:db (forms/start-form db ::form {})}
|
||||
))
|
||||
:db (forms/start-form db ::form {})}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::complete
|
||||
|
||||
@@ -1,415 +0,0 @@
|
||||
(ns auto-ap.views.pages.admin.yodlee
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[auto-ap.forms :as forms]
|
||||
[reagent.core :as reagent]
|
||||
[clojure.string :as str]
|
||||
[cljs-time.format :as f]
|
||||
[cljs-time.core :as time]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.entities.clients :as entity]
|
||||
[auto-ap.views.components.layouts :refer [side-bar-layout]]
|
||||
[auto-ap.views.components.admin.side-bar :refer [admin-side-bar]]
|
||||
[auto-ap.views.components.address :refer [address-field]]
|
||||
[auto-ap.views.utils :refer [login-url dispatch-event dispatch-value-change bind-field horizontal-field str->date date->str with-user]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.status :as status]
|
||||
[cljs.reader :as edn]
|
||||
[auto-ap.routes :as routes]
|
||||
[bidi.bidi :as bidi]))
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::authentication
|
||||
(fn [db]
|
||||
(-> db ::yodlee :authentication)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
(fn [db]
|
||||
true))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::loading?
|
||||
(fn [db]
|
||||
(-> db ::yodlee :loading?)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::accounts
|
||||
(fn [db]
|
||||
(-> db ::yodlee :accounts)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::accounts-loading?
|
||||
(fn [db]
|
||||
(-> db ::yodlee :accounts-loading?)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::provider-accounts-loading?
|
||||
(fn [db]
|
||||
(-> db ::provider-accounts-loading?)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::provider-accounts
|
||||
(fn [db]
|
||||
(-> db ::provider-accounts)))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::authenticate-with-yodlee
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (assoc-in db [::yodlee :loading?] true)
|
||||
:http {:token (:user db)
|
||||
:method :get
|
||||
:headers {"Content-Type" "application/edn"}
|
||||
:uri (str "/api/yodlee/fastlink")
|
||||
:on-success [::authenticated]
|
||||
:on-error [::save-error]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::mounted
|
||||
(fn [{:keys [db]} _]
|
||||
{:db (-> db
|
||||
(assoc ::yodlee {:provider-accounts-loading? true})
|
||||
(assoc ::save-error nil)
|
||||
(assoc ::provider-accounts [])
|
||||
(assoc ::provider-accounts-loading? true))
|
||||
:http {:token (:user db)
|
||||
:method :get
|
||||
:headers {"Content-Type" "application/edn"}
|
||||
:uri (str "/api/yodlee/provider-accounts")
|
||||
:on-success [::got-provider-accounts]
|
||||
:on-error [::save-error]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::kicked
|
||||
(fn [{:keys [db]} [_ id state]]
|
||||
{:dispatch [::mounted]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::kicked
|
||||
(fn [{:keys [db]} [_ id state]]
|
||||
{:dispatch [::mounted]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::kick
|
||||
(fn [{:keys [db]} [_ id]]
|
||||
{:http {:token (:user db)
|
||||
:method :post
|
||||
:headers {"Content-Type" "application/edn"}
|
||||
:uri (str "/api/yodlee/provider-accounts/" id)
|
||||
:on-success [::kicked id :kicked]
|
||||
:on-error [::kicked id :errored]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::got-accounts
|
||||
(fn [{:keys [db]} [_ accounts]]
|
||||
{:db (-> db
|
||||
(assoc-in [::yodlee :accounts] accounts)
|
||||
(assoc-in [::yodlee :accounts-loading?] false))}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::got-provider-accounts
|
||||
(fn [{:keys [db]} [_ accounts]]
|
||||
{:db (-> db
|
||||
(assoc-in [::provider-accounts] accounts)
|
||||
(assoc-in [::provider-accounts-loading?] false))}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::authenticated
|
||||
(fn [{:keys [db]} [_ authentication]]
|
||||
{:db (-> db
|
||||
(assoc-in [::yodlee :authentication] authentication)
|
||||
(assoc-in [::yodlee :loading?] false))}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::authenticated-mfa
|
||||
(fn [{:keys [db]} [_ provider-account-id authentication]]
|
||||
{:db (-> db
|
||||
(assoc-in [::yodlee :authentication] authentication)
|
||||
(assoc-in [::yodlee :loading?] false)
|
||||
(forms/stop-form [::mfa-form provider-account-id]))}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::save-error
|
||||
(fn [{:keys [db]} [_ authentication]]
|
||||
{:db (assoc db ::load-error "error")}))
|
||||
|
||||
(defn yodlee-link-button []
|
||||
[:div
|
||||
(let [authentication @(re-frame/subscribe [::authentication])
|
||||
loading? @(re-frame/subscribe [::loading?])]
|
||||
|
||||
(if authentication
|
||||
[:div
|
||||
"Authentication successful!"
|
||||
[:form {:action (:url authentication) :method "POST"}
|
||||
[:input {:type "hidden"
|
||||
:name "rsession"
|
||||
:value (:session authentication)}]
|
||||
[:input {:type "hidden"
|
||||
:name "token"
|
||||
:value (:token authentication)}]
|
||||
[:input {:type "hidden"
|
||||
:name "app"
|
||||
:value (:app authentication)}]
|
||||
|
||||
[:input {:type "hidden"
|
||||
:name "redirectReq"
|
||||
:value "true"}]
|
||||
[:button.button.is-primary [:span [:span.icon [:i.fa.fa-external-link]] " Go to yodlee"]]]]
|
||||
|
||||
[:button.button.is-primary {:class (if loading? "is-loading" "") :on-click (dispatch-event [::authenticate-with-yodlee])} "Authenticate with Yodlee"]))])
|
||||
|
||||
(defn yodlee-date->date [d]
|
||||
(try
|
||||
(some-> d
|
||||
(str->date (:date-time-no-ms f/formatters))
|
||||
)
|
||||
(catch js/Error e
|
||||
nil)))
|
||||
|
||||
(defn yodlee-date->str [d]
|
||||
(try
|
||||
(or (some-> d
|
||||
(str->date (:date-time-no-ms f/formatters))
|
||||
date->str)
|
||||
"N/A")
|
||||
(catch js/Error e
|
||||
"N/A")))
|
||||
|
||||
(defn yodlee-accounts-table [accounts]
|
||||
(let [bank-accounts @(re-frame/subscribe [::bank-accounts-by-yodlee-account-id])]
|
||||
[:div
|
||||
[:table.table
|
||||
[:thead
|
||||
[:tr
|
||||
[:th "Account Name"]
|
||||
[:th "Account Number"]
|
||||
[:th "Yodlee Account Number"]
|
||||
[:th "Balance"]
|
||||
[:th "Yodlee Status"]
|
||||
[:th "Usage"]]]
|
||||
[:tbody
|
||||
|
||||
(for [account accounts]
|
||||
^{:key (:id account)} [:tr
|
||||
[:td (:accountName account)]
|
||||
[:td (:accountNumber account)]
|
||||
[:td (:id account)]
|
||||
[:td.has-text-right (:amount (:balance account))]
|
||||
[:td (str/join ", " (map :additionalStatus (:dataset account)))]
|
||||
[:td
|
||||
(when-let [bank-accounts (get bank-accounts (:id account))]
|
||||
[:div.tags
|
||||
(for [bank-account bank-accounts]
|
||||
^{:key (:id bank-account)}
|
||||
[:div.tag (:name bank-account) " (" (:code bank-account) ")"])])]
|
||||
])]]]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::reauthenticate-mfa
|
||||
[with-user ]
|
||||
(fn [{:keys [user db]} [_ provider-account-id ]]
|
||||
{:db (forms/loading db [::mfa-form provider-account-id])
|
||||
:http {:token user
|
||||
:method :post
|
||||
:headers {"Content-Type" "application/edn"}
|
||||
:uri (str "/api/yodlee/reauthenticate/" provider-account-id )
|
||||
:body {"loginForm"
|
||||
{"row"
|
||||
(->> (get-in db [::forms/forms [::mfa-form provider-account-id]])
|
||||
:data
|
||||
:login
|
||||
(sort-by (fn [[k v]] k))
|
||||
(map second)
|
||||
(map (fn [row]
|
||||
{"field"
|
||||
(mapv (fn [[k v]]
|
||||
{"id" k
|
||||
"value" v})
|
||||
row)})))}
|
||||
"field"
|
||||
(mapv (fn [[k v]]
|
||||
{"id" k
|
||||
"value" v})
|
||||
(:mfa (:data (get-in db [::forms/forms [::mfa-form provider-account-id]]))))}
|
||||
|
||||
:on-success [::authenticated-mfa provider-account-id]
|
||||
:on-error [::forms/save-error [::mfa-form provider-account-id] ]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::provider-account-refreshed
|
||||
(fn [{:keys [db]} [_ i result]]
|
||||
|
||||
{:db (assoc-in db [::provider-accounts] result)
|
||||
:dispatch [::forms/form-closing [::refresh-provider-account i]]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::refresh-provider-account
|
||||
[with-user ]
|
||||
(fn [{:keys [user db]} [_ provider-account-id ]]
|
||||
{:db (forms/loading db [::refresh-provider-account provider-account-id])
|
||||
:http {:token user
|
||||
:method :post
|
||||
:headers {"Content-Type" "application/edn"}
|
||||
:uri (str "/api/yodlee/provider-accounts/refresh/" provider-account-id )
|
||||
:body {}
|
||||
:on-success [::provider-account-refreshed provider-account-id]
|
||||
:on-error [::forms/save-error [::refresh-provider-account provider-account-id] ]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::provider-account-deleted
|
||||
(fn [{:keys [db]} [_ i result]]
|
||||
{:db (assoc-in db [::provider-accounts] result)
|
||||
:dispatch-n [[::forms/form-closing [::refresh-provider-account i]]
|
||||
[::modal/modal-closed ]]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::delete-provider-account
|
||||
[with-user ]
|
||||
(fn [{:keys [user db]} [_ provider-account-id ]]
|
||||
{:http {:token user
|
||||
:method :post
|
||||
:owns-state {:single ::delete-provider-account}
|
||||
:headers {"Content-Type" "application/edn"}
|
||||
:uri (str "/api/yodlee/provider-accounts/delete/" provider-account-id )
|
||||
:body {}
|
||||
:on-success [::provider-account-deleted provider-account-id]
|
||||
:on-error [::forms/save-error [::delete-provider-account provider-account-id] ]}}))
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::delete-requested
|
||||
[with-user]
|
||||
(fn [{:keys [user db]} [_ 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}]}))
|
||||
|
||||
|
||||
(defn delete-button [account-id]
|
||||
[:button.button
|
||||
{:on-click (dispatch-event [::delete-requested account-id])}
|
||||
[:span.icon [:i.fa.fa-times]]])
|
||||
|
||||
(re-frame/reg-sub
|
||||
::bank-accounts-by-yodlee-account-id
|
||||
:<- [::subs/bank-accounts]
|
||||
(fn [bank-accounts]
|
||||
(group-by :yodlee-account-id bank-accounts)))
|
||||
|
||||
(defn yodlee-provider-accounts-table []
|
||||
(let [bank-accounts @(re-frame/subscribe [::bank-accounts-by-yodlee-account-id])]
|
||||
|
||||
(if @(re-frame/subscribe [::provider-accounts-loading?])
|
||||
[:div "Loading..."]
|
||||
[:div.columns
|
||||
[:div.column.is-half
|
||||
(doall
|
||||
(for [account @(re-frame/subscribe [::provider-accounts])
|
||||
:let [{:keys [error status] :as g} @(re-frame/subscribe [::forms/form [::refresh-provider-account (:id account)]])
|
||||
total-usages (mapcat (comp bank-accounts :id) (:accounts account))]]
|
||||
|
||||
^{:key (:id account)}
|
||||
[:div.card {:style {:margin-bottom "1em"}}
|
||||
[:div.card-header
|
||||
[:div.card-header-title "Provider account " (:id account)]
|
||||
[:div.card-header-icon
|
||||
(when (seq total-usages)
|
||||
[:div.tags
|
||||
[:div.tag.is-primary (count total-usages) " usages"]])]
|
||||
[:div.card-header-icon
|
||||
[delete-button (:id account)]]
|
||||
[:div.card-header-icon
|
||||
(cond
|
||||
(= :loading status) [:button.button.is-disabled.is-loading [:i.fa.fa-refresh]]
|
||||
error [:button.button.is-disabled [:span.icon [:i.fa.fa-exclamation-triangle]]]
|
||||
:else
|
||||
[:button.button
|
||||
{:on-click (dispatch-event [::refresh-provider-account (:id account)])}
|
||||
[:span.icon [:i.fa.fa-refresh]]])]]
|
||||
[:div.card-content
|
||||
|
||||
(if (> (some-> (-> account :dataset first :lastUpdated)
|
||||
(yodlee-date->date )
|
||||
(time/interval (time/now))
|
||||
(time/in-days ))
|
||||
1)
|
||||
[:div.notification.is-info.is-light
|
||||
[:div.level
|
||||
[:div.level-left
|
||||
[:div.level-item
|
||||
[:p
|
||||
"This account was last updated on "
|
||||
(yodlee-date->str (-> account :dataset first :lastUpdated))
|
||||
", and last attempted "
|
||||
(yodlee-date->str (-> account :dataset first :lastUpdateAttempt))
|
||||
"."]]]
|
||||
[:div.level-right [:button.button.is-success {:on-click (dispatch-event [::kick (:id account)] )} "Sync yodlee with bank" ]]]
|
||||
|
||||
])
|
||||
|
||||
|
||||
[yodlee-accounts-table (:accounts account)]
|
||||
(if (not= (-> account :dataset first :additionalStatus)
|
||||
"AVAILABLE_DATA_RETRIEVED")
|
||||
[:div
|
||||
[:div.notification.is-info.is-warning
|
||||
[:div.level
|
||||
[:div.level-left
|
||||
[:div.level-item
|
||||
"This provider account's status is '"
|
||||
(-> account :dataset first :additionalStatus)
|
||||
"'. If this is in error, it might help to try reauthenticating by filling out the form below."]]]]
|
||||
(let [{error :error account-data :data } @(re-frame/subscribe [::forms/form [::mfa-form (:id account)]])
|
||||
change-event [::forms/change [::mfa-form (:id account)]]
|
||||
{:keys [form-inline field field-holder raw-field error-notification submit-button]} (forms/vertical-form {:can-submit [::can-submit]
|
||||
:change-event change-event
|
||||
:submit-event [::reauthenticate-mfa (:id account)]
|
||||
:id [::mfa-form (:id account)]} )]
|
||||
(form-inline {:title "Reauthenticate"}
|
||||
[:<>
|
||||
(error-notification)
|
||||
(doall
|
||||
(for [[row i] (map vector (-> account :loginForm last :row) (range))
|
||||
f (:field row)
|
||||
:let [options (map :optionValue (:option f))]]
|
||||
^{:key (:id f)}
|
||||
[:div
|
||||
(field (:label row)
|
||||
[:input.input {:type "text" :field [:login i (:id f)]}])
|
||||
(if (seq options)
|
||||
[:ul
|
||||
(for [o options]
|
||||
^{:key o}
|
||||
[:li [:pre o]])])]))
|
||||
(doall
|
||||
(for [f (-> account :field)]
|
||||
^{:key (:id f)}
|
||||
(field (:label f)
|
||||
[:input.input {:type "text" :mfa [:form (:id f)] :value (-> f :field first :value)}])))
|
||||
(submit-button "Reauthenticate")]))])]]))]])))
|
||||
|
||||
|
||||
(defn admin-yodlee-content []
|
||||
[(with-meta
|
||||
(fn []
|
||||
[:div
|
||||
[:h1.title "Yodlee provider accounts"]
|
||||
|
||||
[yodlee-provider-accounts-table]
|
||||
[yodlee-link-button]])
|
||||
{:component-did-mount (fn []
|
||||
(re-frame/dispatch [::mounted]))})])
|
||||
|
||||
#_(defn admin-yodlee-page []
|
||||
[side-bar-layout {:side-bar [admin-side-bar {}]
|
||||
:main [admin-yodlee-content]}])
|
||||
@@ -1,19 +1,29 @@
|
||||
(ns auto-ap.views.pages.invoices.advanced-print-checks
|
||||
(:require [auto-ap.forms :as forms]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.pages.invoices.common :refer [invoice-read does-amount-exceed-outstanding?]]
|
||||
[auto-ap.views.pages.invoices.form :as form]
|
||||
[auto-ap.views.utils :refer [dispatch-event horizontal-field with-user]]
|
||||
[re-frame.core :as re-frame]))
|
||||
(:require
|
||||
[auto-ap.forms :as forms]
|
||||
[auto-ap.forms.builder :as form-builder]
|
||||
[auto-ap.status :as status]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.pages.invoices.common
|
||||
:refer [does-amount-exceed-outstanding? invoice-read]]
|
||||
[auto-ap.views.components.money-field :refer [money-field]]
|
||||
[auto-ap.views.utils :refer [dispatch-event horizontal-field with-user]]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
:<- [::forms/form ::form]
|
||||
(fn [{ {:keys [invoices invoice-amounts]} :data}]
|
||||
(cond (seq (filter
|
||||
(cond
|
||||
(->> invoice-amounts
|
||||
vals
|
||||
(map :amount)
|
||||
(filter nil?)
|
||||
seq)
|
||||
false
|
||||
|
||||
(seq (filter
|
||||
(fn [{:keys [id outstanding-balance]}]
|
||||
(does-amount-exceed-outstanding? (get-in invoice-amounts [id :amount]) outstanding-balance ))
|
||||
invoices))
|
||||
@@ -22,63 +32,55 @@
|
||||
:else
|
||||
true)))
|
||||
|
||||
(def advanced-print-checks-form (forms/vertical-form {:submit-event [::save]
|
||||
:change-event [::forms/change ::form]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}))
|
||||
|
||||
|
||||
(defn form []
|
||||
(let [real-bank-accounts @(re-frame/subscribe [::subs/real-bank-accounts])
|
||||
{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline horizontal-field field raw-field error-notification submit-button]} advanced-print-checks-form]
|
||||
{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
|
||||
|
||||
(form-inline {}
|
||||
[:<>
|
||||
[:div.field
|
||||
[:label.label "Pay using"]
|
||||
[:div.control
|
||||
[:span.select
|
||||
[raw-field
|
||||
[:select {:type "select"
|
||||
:field :bank-account-id}
|
||||
(for [{:keys [id number name]} real-bank-accounts]
|
||||
^{:key id} [:option {:value id} name])]]]]]
|
||||
[form-builder/builder {:submit-event [::save]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}
|
||||
[:div.field
|
||||
[:label.label "Pay using"]
|
||||
[:div.control
|
||||
[:span.select
|
||||
[form-builder/raw-field
|
||||
[:select {:type "select"
|
||||
:field :bank-account-id}
|
||||
(for [{:keys [id name]} real-bank-accounts]
|
||||
^{:key id} [:option {:value id} name])]]]]]
|
||||
|
||||
[:table.table.is-fullwidth
|
||||
[:thead
|
||||
[:tr
|
||||
[:th "Vendor"]
|
||||
[:th "Invoice ID"]
|
||||
[:th {:style {"width" "10em"}} "Payment"]]]
|
||||
[:tbody
|
||||
(doall
|
||||
(for [{:keys [vendor payment outstanding-balance invoice-number id] :as i} (:invoices data)]
|
||||
^{:key id}
|
||||
[:tr
|
||||
[:td (:name vendor)]
|
||||
[:td invoice-number]
|
||||
|
||||
[:td [:div.field.has-addons.is-extended
|
||||
[:p.control [:a.button.is-static "$"]]
|
||||
[:p.control
|
||||
(raw-field
|
||||
[:input.input.has-text-right {:type "number"
|
||||
:field [:invoice-amounts id :amount]
|
||||
:step "0.01"}])]]]]))]]])))
|
||||
[:table.table.is-fullwidth
|
||||
[:thead
|
||||
[:tr
|
||||
[:th "Vendor"]
|
||||
[:th "Invoice ID"]
|
||||
[:th {:style {"width" "10em"}} "Payment"]]]
|
||||
[:tbody
|
||||
(doall
|
||||
(for [{:keys [vendor invoice-number id] :as i} (:invoices data)]
|
||||
^{:key id}
|
||||
[:tr
|
||||
[:td (:name vendor)]
|
||||
[:td invoice-number]
|
||||
|
||||
[:td
|
||||
[form-builder/raw-field
|
||||
[money-field {:type "money"
|
||||
:field [:invoice-amounts id :amount]
|
||||
:step "0.01"}]]]]))]]]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::show
|
||||
(fn [{:keys [db]} [_ invoices]]
|
||||
{:dispatch [::modal/modal-requested {:title "Print Checks"
|
||||
:body [form]
|
||||
:confirm {:value "Print checks"
|
||||
{:dispatch [::modal/modal-requested {:title "Print Checks"
|
||||
:body [form]
|
||||
:confirm {:value "Print checks"
|
||||
:status-from [::status/single ::form]
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::save])
|
||||
:can-submit [::can-submit]
|
||||
:class "is-primary"
|
||||
:on-click (dispatch-event [::save])
|
||||
:can-submit [::can-submit]
|
||||
:close-event [::status/completed ::form]}}]
|
||||
:db (-> db
|
||||
:db (-> db
|
||||
(forms/start-form ::form
|
||||
{:bank-account-id (:id (first @(re-frame/subscribe [::subs/real-bank-accounts])))
|
||||
:invoices invoices
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
[reagent.core :as reagent]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[vimsical.re-frame.cofx.inject :as inject]
|
||||
[auto-ap.views.pages.ledger.report-table :as rtable]))
|
||||
[auto-ap.views.pages.ledger.report-table :as rtable]
|
||||
[auto-ap.forms.builder :as form-builder]))
|
||||
|
||||
(defn data-params->query-params [params]
|
||||
(when params
|
||||
@@ -36,11 +37,6 @@
|
||||
:to-numeric-code (:to-numeric-code params)
|
||||
:date-range (:date-range params)}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
(fn [_]
|
||||
true))
|
||||
|
||||
|
||||
(re-frame/reg-sub
|
||||
::ledger-list-active?
|
||||
@@ -183,53 +179,46 @@ NOTE: Please review the transactions we may have question for you here: https://
|
||||
:event-fn (fn [params] [::ledger-params-change params])}}))
|
||||
|
||||
|
||||
(def balance-sheet-form (forms/vertical-form {:can-submit [::can-submit]
|
||||
:change-event [::change]
|
||||
:submit-event [::report-requested]
|
||||
:id ::form}))
|
||||
|
||||
(defn report-form []
|
||||
(let [{:keys [form-inline raw-field]} balance-sheet-form
|
||||
{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
|
||||
(form-inline {}
|
||||
[:div
|
||||
[:div.report-controls
|
||||
[:div.level
|
||||
[:div.level-left
|
||||
[:div.level-item
|
||||
[:div.control
|
||||
[:p.help "Date"]
|
||||
(raw-field
|
||||
[date-picker {:output :cljs-date
|
||||
:type "date"
|
||||
:field [:date]}])]]
|
||||
[:div.level-item
|
||||
[:div.control
|
||||
[:div.mt-3]
|
||||
[switch-field {:id "include-comparison"
|
||||
:checked (:include-comparison data)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::change [:include-comparison] (.-checked (.-target e))]))
|
||||
:label "Include comparison"
|
||||
:type "checkbox"}]]]
|
||||
[:div.level-item
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
|
||||
[form-builder/builder {:change-event [::change]
|
||||
:submit-event [::report-requested]
|
||||
:id ::form}
|
||||
[:div
|
||||
[:div.report-controls
|
||||
[:div.level
|
||||
[:div.level-left
|
||||
[:div.level-item
|
||||
[:div.control
|
||||
[form-builder/field
|
||||
"Date"
|
||||
[date-picker {:output :cljs-date
|
||||
:type "date"
|
||||
:field [:date]}]]]]
|
||||
[:div.level-item
|
||||
[form-builder/field
|
||||
[:div.mt-5]
|
||||
[switch-field {:id "include-comparison"
|
||||
:field [:include-comparison]
|
||||
:label "Include compariison"
|
||||
:type "checkbox"}]]]
|
||||
[:div.level-item
|
||||
|
||||
(when (boolean (:include-comparison data))
|
||||
[:div.control
|
||||
[:p.help "Comparison Date"]
|
||||
(raw-field
|
||||
[date-picker {:output :cljs-date
|
||||
:type "date"
|
||||
:field [:comparison-date]}])])]]
|
||||
[:div.level-right
|
||||
[:div.buttons
|
||||
(when (boolean (:include-comparison data))
|
||||
[form-builder/field
|
||||
"Comparison Date"
|
||||
[date-picker {:output :cljs-date
|
||||
:type "date"
|
||||
:field [:comparison-date]}]])]]
|
||||
[:div.level-right
|
||||
[:div.buttons
|
||||
|
||||
(when @(re-frame/subscribe [::subs/is-admin?])
|
||||
[:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"])
|
||||
[:button.button.is-primary "Run"]]]]]])))
|
||||
(when @(re-frame/subscribe [::subs/is-admin?])
|
||||
[:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"])
|
||||
[:button.button.is-primary "Run"]]]]]]]))
|
||||
|
||||
(defn balance-sheet-report [{:keys [args report-data]}]
|
||||
(let [pnl-data (concat (->> (:balance-sheet-accounts report-data)
|
||||
(let [pnl-data (concat (->> (:balance-sheet-accounts report-data)
|
||||
(map (fn [b]
|
||||
(assoc b
|
||||
:period (:date args)
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
[react-dom :as react-dom]
|
||||
[reagent.core :as reagent]
|
||||
[vimsical.re-frame.cofx.inject :as inject]
|
||||
[vimsical.re-frame.fx.track :as track]))
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.forms.builder :as form-builder]))
|
||||
|
||||
|
||||
|
||||
@@ -223,14 +224,11 @@ NOTE: Please review the transactions we may have question for you here: https://
|
||||
(fn [_]
|
||||
true))
|
||||
|
||||
(def pnl-form (forms/vertical-form {:can-submit [::can-submit]
|
||||
:change-event [::change]
|
||||
:submit-event [::report-requested]
|
||||
:id ::form}))
|
||||
|
||||
(defn report-control-detail [{:keys [active box which]} children]
|
||||
(when (and @box
|
||||
(= which @active))
|
||||
(println @box)
|
||||
(react-dom/createPortal (reagent/as-element
|
||||
[:div.notification.is-light
|
||||
[:a.delete {:on-click (fn [] (reset! active nil))}]
|
||||
@@ -243,191 +241,189 @@ NOTE: Please review the transactions we may have question for you here: https://
|
||||
[:div.control
|
||||
[:a.button
|
||||
{:class (when (= selected-preset title) "is-active")
|
||||
:on-click (dispatch-event
|
||||
[::change
|
||||
[:periods]
|
||||
periods
|
||||
[:selected-preset] title])}
|
||||
:on-click (fn []
|
||||
(re-frame/dispatch-sync [::change
|
||||
[:periods]
|
||||
periods
|
||||
[:selected-preset] title])
|
||||
(re-frame/dispatch-sync [::change
|
||||
[:show-advanced?]
|
||||
false]))}
|
||||
title]]))
|
||||
|
||||
(defn report-controls [_]
|
||||
(let [!box (reagent/atom nil)
|
||||
(defn report-controls []
|
||||
(let [!box (atom nil)
|
||||
active (reagent/atom nil)]
|
||||
(fn [pnl-form]
|
||||
(let [{:keys [raw-field]} pnl-form
|
||||
{:keys [data]} @(re-frame/subscribe [::forms/form ::form])
|
||||
(fn []
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [periods selected-preset include-deltas column-per-location]} data]
|
||||
[:div.report-controls
|
||||
[:div.level.mb-2
|
||||
[:div.level-left
|
||||
[:div.level-item
|
||||
[buttons/dropdown {:on-click (fn [] (reset! active :clients))}
|
||||
[:span (str "Companies"
|
||||
(when-let [clients (:clients data)]
|
||||
(str " (" (str/join ", " (map :name clients)) ")")))]]
|
||||
[report-control-detail {:active active :box !box :which :clients}
|
||||
[:div {:style {:width "20em"}}
|
||||
[:h4.subtitle "Companies"]
|
||||
[raw-field
|
||||
[multi-field {:type "multi-field"
|
||||
:field [:clients]
|
||||
:template [[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"}]]}]]
|
||||
]]]
|
||||
[:div.level-item
|
||||
[buttons/dropdown {:on-click (fn [] (reset! active :range))}
|
||||
[:span (str "Range"
|
||||
(when selected-preset
|
||||
(str " (" selected-preset ")")))]]
|
||||
[report-control-detail {:active active :box !box :which :range}
|
||||
[:div
|
||||
[:h4.subtitle "Range"]
|
||||
[:div.field.is-grouped
|
||||
[:div.control
|
||||
[:div.field.has-addons
|
||||
[:div.control
|
||||
(raw-field
|
||||
[form-builder/builder {:can-submit [::can-submit]
|
||||
:change-event [::change]
|
||||
:submit-event [::report-requested]
|
||||
:id ::form}
|
||||
[:div.report-controls
|
||||
[:div.level.mb-2
|
||||
[:div.level-left
|
||||
[:div.level-item
|
||||
[buttons/dropdown {:on-click (fn [] (reset! active :clients))}
|
||||
[:span (str "Companies"
|
||||
(when-let [clients (:clients data)]
|
||||
(str " (" (str/join ", " (map :name clients)) ")")))]]
|
||||
[report-control-detail {:active active :box !box :which :clients}
|
||||
[:div {:style {:width "20em"}}
|
||||
[:h4.subtitle "Companies"]
|
||||
[form-builder/raw-field
|
||||
[multi-field {:type "multi-field"
|
||||
:field [:clients]
|
||||
:template [[typeahead-v3 {:entities @(re-frame/subscribe [::subs/clients])
|
||||
:style {:width "18em"}
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"}]]}]]]]]
|
||||
[:div.level-item
|
||||
[buttons/dropdown {:on-click (fn [] (reset! active :range))}
|
||||
[:span (str "Range"
|
||||
(when selected-preset
|
||||
(str " (" selected-preset ")")))]]
|
||||
[report-control-detail {:active active :box !box :which :range}
|
||||
[:div
|
||||
[:h4.subtitle "Range"]
|
||||
[:div.field.is-grouped
|
||||
[:div.control
|
||||
[:div.field.has-addons
|
||||
[:div.control
|
||||
[form-builder/raw-field
|
||||
[date-picker {:placeholder "End date"
|
||||
:type "date"
|
||||
:output :cljs-date
|
||||
:field [:thirteen-periods-end]}])]
|
||||
[period-preset-button {:title "13 periods"
|
||||
:periods (let [today (or (some-> (:thirteen-periods-end data))
|
||||
(local-today))]
|
||||
(into
|
||||
[{:start (t/plus (t/minus today (t/weeks (* 13 4)))
|
||||
(t/days 1))
|
||||
:end today
|
||||
:title "Total"}]
|
||||
(for [i (range 13)]
|
||||
{:start (t/plus (t/minus today (t/weeks (* (inc i) 4)))
|
||||
:field [:thirteen-periods-end]}]]]
|
||||
[period-preset-button {:title "13 periods"
|
||||
:periods (let [today (or (some-> (:thirteen-periods-end data))
|
||||
(local-today))]
|
||||
(into
|
||||
[{:start (t/plus (t/minus today (t/weeks (* 13 4)))
|
||||
(t/days 1))
|
||||
:end (t/minus today (t/weeks (* i 4)))})))}]]]
|
||||
:end today
|
||||
:title "Total"}]
|
||||
(for [i (range 13)]
|
||||
{:start (t/plus (t/minus today (t/weeks (* (inc i) 4)))
|
||||
(t/days 1))
|
||||
:end (t/minus today (t/weeks (* i 4)))})))}]]]
|
||||
|
||||
[:div.control
|
||||
[:div.field.has-addons
|
||||
[:div.control
|
||||
(raw-field
|
||||
[date-picker {:placeholder "End date"
|
||||
:output :cljs-date
|
||||
:type "date"
|
||||
:field [:twelve-periods-end]}])]
|
||||
[period-preset-button {:title "12 months"
|
||||
:periods (let [end-date (or (some-> (:twelve-periods-end data))
|
||||
(local-today))
|
||||
this-month (t/local-date (t/year end-date)
|
||||
(t/month end-date)
|
||||
1)]
|
||||
(into
|
||||
[{:start (t/minus this-month (t/months 11))
|
||||
:end (t/minus (t/plus this-month (t/months 1))
|
||||
(t/days 1))
|
||||
:title "Total"}]
|
||||
(for [i (range 12)]
|
||||
{:start (t/minus this-month (t/months (- 11 i)))
|
||||
:end (t/minus (t/minus this-month (t/months (- 10 i)))
|
||||
(t/days 1))})))}]]]
|
||||
[:div.control
|
||||
[:div.field.has-addons
|
||||
[:div.control
|
||||
[form-builder/raw-field
|
||||
[date-picker {:placeholder "End date"
|
||||
:output :cljs-date
|
||||
:type "date"
|
||||
:field [:twelve-periods-end]}]]]
|
||||
[period-preset-button {:title "12 months"
|
||||
:periods (let [end-date (or (some-> (:twelve-periods-end data))
|
||||
(local-today))
|
||||
this-month (t/local-date (t/year end-date)
|
||||
(t/month end-date)
|
||||
1)]
|
||||
(into
|
||||
[{:start (t/minus this-month (t/months 11))
|
||||
:end (t/minus (t/plus this-month (t/months 1))
|
||||
(t/days 1))
|
||||
:title "Total"}]
|
||||
(for [i (range 12)]
|
||||
{:start (t/minus this-month (t/months (- 11 i)))
|
||||
:end (t/minus (t/minus this-month (t/months (- 10 i)))
|
||||
(t/days 1))})))}]]]
|
||||
|
||||
[period-preset-button {:periods (let [last-sunday (loop [current (local-today)]
|
||||
(if (= 7 (t/day-of-week current))
|
||||
current
|
||||
(recur (t/minus current (t/period :days 1)))))]
|
||||
(and-last-year {:start (t/minus last-sunday (t/period :days 6))
|
||||
:end last-sunday}))
|
||||
:title "Last week"}]
|
||||
[period-preset-button {:periods (let [last-sunday (loop [current (local-today)]
|
||||
(if (= 7 (t/day-of-week current))
|
||||
current
|
||||
(recur (t/minus current (t/period :days 1)))))]
|
||||
(and-last-year {:start (t/minus last-sunday (t/period :days 6))
|
||||
:end last-sunday}))
|
||||
:title "Last week"}]
|
||||
|
||||
[period-preset-button {:periods (and-last-year {:start (loop [current (local-today)]
|
||||
(if (= 1 (t/day-of-week current))
|
||||
current
|
||||
(recur (t/minus current (t/period :days 1)))))
|
||||
:end (local-today)})
|
||||
:title "Week to date"}]
|
||||
[period-preset-button {:periods (and-last-year {:start (loop [current (local-today)]
|
||||
(if (= 1 (t/day-of-week current))
|
||||
current
|
||||
(recur (t/minus current (t/period :days 1)))))
|
||||
:end (local-today)})
|
||||
:title "Week to date"}]
|
||||
|
||||
[period-preset-button {:periods (and-last-year {:start (t/minus (t/local-date (t/year (local-today))
|
||||
(t/month (local-today))
|
||||
1)
|
||||
(t/period :months 1))
|
||||
:end (t/minus (t/local-date (t/year (local-today))
|
||||
(t/month (local-today))
|
||||
1)
|
||||
(t/period :days 1))})
|
||||
:title "Last month"}]
|
||||
[period-preset-button {:periods (and-last-year {:start (t/minus (t/local-date (t/year (local-today))
|
||||
(t/month (local-today))
|
||||
1)
|
||||
(t/period :months 1))
|
||||
:end (t/minus (t/local-date (t/year (local-today))
|
||||
(t/month (local-today))
|
||||
1)
|
||||
(t/period :days 1))})
|
||||
:title "Last month"}]
|
||||
|
||||
[period-preset-button {:periods (and-last-year {:start (t/local-date (t/year (local-today))
|
||||
(t/month (local-today))
|
||||
1)
|
||||
:end (local-today)})
|
||||
:title "Month to date"}]
|
||||
[period-preset-button {:periods (and-last-year {:start (t/local-date (t/year (local-today))
|
||||
(t/month (local-today))
|
||||
1)
|
||||
:end (local-today)})
|
||||
:title "Month to date"}]
|
||||
|
||||
[period-preset-button {:periods (and-last-year {:start (t/local-date (t/year (local-today)) 1 1)
|
||||
:end
|
||||
(local-today)})
|
||||
:title "Year to date"}]
|
||||
[period-preset-button {:periods (and-last-year {:start (t/local-date (t/year (local-today)) 1 1)
|
||||
:end
|
||||
(local-today)})
|
||||
:title "Year to date"}]
|
||||
|
||||
[period-preset-button {:periods [{:start (t/local-date (dec (t/year (local-today))) 1 1)
|
||||
:end (t/local-date (dec (t/year (local-today))) 12 31)}]
|
||||
:title "Last calendar year"}]
|
||||
[period-preset-button {:periods [{:start (t/local-date (dec (t/year (local-today))) 1 1)
|
||||
:end (t/local-date (dec (t/year (local-today))) 12 31)}]
|
||||
:title "Last calendar year"}]
|
||||
|
||||
[period-preset-button {:periods (and-last-year {:start (t/plus (t/minus (local-today) (t/period :years 1))
|
||||
(t/period :days 1))
|
||||
:end (local-today)})
|
||||
:title "Full year"}]]
|
||||
[:div
|
||||
[:div.field
|
||||
[:label.checkbox
|
||||
(raw-field
|
||||
[:input {:type "checkbox"
|
||||
:field [:show-advanced?]}])
|
||||
" Show Advanced"]]]
|
||||
(when (:show-advanced? data)
|
||||
(doall
|
||||
(for [[_ i] (map vector periods (range))]
|
||||
^{:key i}
|
||||
[:div.field.is-grouped
|
||||
[:div.control
|
||||
[:p.help "From"]
|
||||
(raw-field
|
||||
[date-picker {:type "date"
|
||||
:output :cljs-date
|
||||
:field [:periods i :start]}])]
|
||||
[period-preset-button {:periods (and-last-year {:start (t/plus (t/minus (local-today) (t/period :years 1))
|
||||
(t/period :days 1))
|
||||
:end (local-today)})
|
||||
:title "Full year"}]]
|
||||
[:div
|
||||
[:div.field
|
||||
[:label.checkbox
|
||||
[form-builder/raw-field
|
||||
[:input {:type "checkbox"
|
||||
:field [:show-advanced?]}]]
|
||||
" Show Advanced"]]]
|
||||
(when (:show-advanced? data)
|
||||
[form-builder/raw-field
|
||||
[multi-field {:type "multi-field"
|
||||
:field [:periods]
|
||||
:template [[date-picker {:type "date"
|
||||
:output :cljs-date
|
||||
:field [:start]}]
|
||||
[date-picker {:type "date"
|
||||
:output :cljs-date
|
||||
:field [:end]}]]}]])]]]
|
||||
|
||||
[:div.control
|
||||
[:p.help "To"]
|
||||
(raw-field
|
||||
[date-picker {:type "date"
|
||||
:output :cljs-date
|
||||
:field [:periods i :end]}])]])))]]]
|
||||
[:div.level-item
|
||||
[:div
|
||||
[switch-field {:id "include-deltas"
|
||||
:checked (boolean include-deltas)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::change
|
||||
[:include-deltas] (.-checked (.-target e))]))
|
||||
:label "Include deltas"
|
||||
:type "checkbox"}]]]
|
||||
[:div.level-item
|
||||
[:div
|
||||
[switch-field {:id "column-per-location"
|
||||
:checked (boolean column-per-location)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::change
|
||||
[:column-per-location] (.-checked (.-target e))]))
|
||||
:label "Column per location"
|
||||
:type "checkbox"}]]]]
|
||||
[:div.level-right
|
||||
[:div.buttons
|
||||
|
||||
[:div.level-item
|
||||
[:div
|
||||
[switch-field {:id "include-deltas"
|
||||
:checked (boolean include-deltas)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::change
|
||||
[:include-deltas] (.-checked (.-target e))]))
|
||||
:label "Include deltas"
|
||||
:type "checkbox"}]]]
|
||||
[:div.level-item
|
||||
[:div
|
||||
[switch-field {:id "column-per-location"
|
||||
:checked (boolean column-per-location)
|
||||
:on-change (fn [e]
|
||||
(re-frame/dispatch [::change
|
||||
[:column-per-location] (.-checked (.-target e))]))
|
||||
:label "Column per location"
|
||||
:type "checkbox"}]]]]
|
||||
[:div.level-right
|
||||
[:div.buttons
|
||||
(when @(re-frame/subscribe [::subs/is-admin?])
|
||||
[:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"])
|
||||
[:button.button.is-primary "Run"]]
|
||||
|
||||
(when @(re-frame/subscribe [::subs/is-admin?])
|
||||
[:button.button.is-secondary {:on-click (dispatch-event [::export-pdf])} "Export"])
|
||||
[:button.button.is-primary "Run"]]
|
||||
|
||||
]]
|
||||
[:div.report-control-detail {:ref (fn [el]
|
||||
(when-not @!box
|
||||
(reset! !box el)))}]]))))
|
||||
]]
|
||||
[:div.report-control-detail {:ref (fn [el]
|
||||
(when (not= @!box el)
|
||||
(reset! !box el)))}]]]))))
|
||||
|
||||
|
||||
|
||||
@@ -466,13 +462,11 @@ NOTE: Please review the transactions we may have question for you here: https://
|
||||
|
||||
(defn profit-and-loss-content []
|
||||
(let [status @(re-frame/subscribe [::status/single ::page])
|
||||
{:keys [data report]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline]} pnl-form]
|
||||
{:keys [data report]} @(re-frame/subscribe [::forms/form ::form])]
|
||||
[:div
|
||||
(form-inline {}
|
||||
[:div
|
||||
[status/status-notification {:statuses [[::status/single ::page]]}]
|
||||
[report-controls pnl-form]])
|
||||
[:div
|
||||
[status/status-notification {:statuses [[::status/single ::page]]}]
|
||||
[report-controls]]
|
||||
[status/big-loader status]
|
||||
(when (and (not= :loading (:state status))
|
||||
report)
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
[reagent.core :as r]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.events :as events]
|
||||
[vimsical.re-frame.cofx.inject :as inject]))
|
||||
[vimsical.re-frame.cofx.inject :as inject]
|
||||
[auto-ap.forms.builder :as form-builder]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
@@ -105,45 +106,41 @@
|
||||
(fn []
|
||||
{::track/dispose {:id ::vendor-change}}))
|
||||
|
||||
(def code-form (forms/vertical-form {:submit-event [::code-selected]
|
||||
:change-event [::changed]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}))
|
||||
(defn form-content [_]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline field]} code-form]
|
||||
(let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])]
|
||||
[form-builder/builder {:submit-event [::code-selected]
|
||||
:change-event [::changed]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}
|
||||
|
||||
(form-inline {}
|
||||
[:<>
|
||||
(field "Vendor"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:vendor]}])
|
||||
|
||||
[form-builder/field "Vendor"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:vendor]}]]
|
||||
|
||||
(field "Approval Status"
|
||||
[button-radio
|
||||
{:type "button-radio"
|
||||
:field [:transaction-approval-status]
|
||||
:options [[:unapproved "Unapproved"]
|
||||
[:requires-feedback "Client Review"]
|
||||
[:approved "Approved"]
|
||||
[:excluded "Excluded from Ledger"]]}])
|
||||
[form-builder/field
|
||||
"Approval Status"
|
||||
[button-radio
|
||||
{:type "button-radio"
|
||||
:field [:transaction-approval-status]
|
||||
:options [[:unapproved "Unapproved"]
|
||||
[:requires-feedback "Client Review"]
|
||||
[:approved "Approved"]
|
||||
[:excluded "Excluded from Ledger"]]}]]
|
||||
|
||||
(with-meta
|
||||
(field nil
|
||||
[expense-accounts-field {:type "expense-accounts"
|
||||
:descriptor "account asssignment"
|
||||
:percentage-only? true
|
||||
:client (:client data)
|
||||
:locations (into ["Shared"] @(re-frame/subscribe [::subs/locations-for-client (:id (:client data))]))
|
||||
:max 100
|
||||
:field [:accounts]}])
|
||||
{:key (some-> data :vendor :id str)})
|
||||
])))
|
||||
[form-builder/raw-field
|
||||
[expense-accounts-field {:type "expense-accounts"
|
||||
:descriptor "account asssignment"
|
||||
:percentage-only? true
|
||||
:client (:client data)
|
||||
:locations (into ["Shared"] @(re-frame/subscribe [::subs/locations-for-client (:id (:client data))]))
|
||||
:max 100
|
||||
:field [:accounts]}]]]))
|
||||
(defn form [_]
|
||||
(r/create-class
|
||||
{:display-name "transaction-bulk-update-form"
|
||||
|
||||
@@ -13,13 +13,14 @@
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.pages.transactions.common :refer [transaction-read]]
|
||||
[auto-ap.views.utils
|
||||
:refer [->$ date->str dispatch-event pretty with-user]]
|
||||
:refer [->$ date->str date-picker dispatch-event pretty with-user]]
|
||||
[clojure.string :as str]
|
||||
[re-frame.core :as re-frame]
|
||||
[react :as react]
|
||||
[reagent.core :as r]
|
||||
[vimsical.re-frame.fx.track :as track]
|
||||
[auto-ap.events :as events]))
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.forms.builder :as form-builder]))
|
||||
|
||||
;; SUBS
|
||||
(re-frame/reg-sub
|
||||
@@ -211,10 +212,6 @@
|
||||
|
||||
;; VIEWS
|
||||
|
||||
(def transaction-form (forms/vertical-form {:can-submit [::can-submit]
|
||||
:change-event [::changed]
|
||||
:submit-event [::saving ]
|
||||
:id ::form}))
|
||||
|
||||
(defn potential-transaction-rule-matches-box [{:keys [potential-transaction-rule-matches]}]
|
||||
(let [states @(re-frame/subscribe [::status/multi ::matching])]
|
||||
@@ -340,122 +337,116 @@
|
||||
[layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form])}
|
||||
(let [{:keys [data] } @(re-frame/subscribe [::forms/form ::form])
|
||||
locations @(re-frame/subscribe [::subs/locations-for-client (:id (:client data))])
|
||||
{: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?])
|
||||
|
||||
should-disable-for-client? (and (not (or is-admin? is-power-user?))
|
||||
(not= :requires-feedback (:original-status data)))
|
||||
is-already-matched? (:payment data)]
|
||||
(with-meta
|
||||
(form-inline {:title "Transaction"}
|
||||
[:<>
|
||||
[form-builder/builder {:can-submit [::can-submit]
|
||||
:change-event [::changed]
|
||||
:submit-event [::saving ]
|
||||
:id ::form}
|
||||
[form-builder/section {:title "Transaction"}
|
||||
[:<>
|
||||
|
||||
(when (and @(re-frame/subscribe [::subs/is-admin?])
|
||||
(get-in data [:yodlee-merchant]))
|
||||
[:div.control
|
||||
[:p.help "Merchant"]
|
||||
[:input.input {:type "text"
|
||||
:disabled true
|
||||
:value (str (get-in data [:yodlee-merchant :name])
|
||||
" - "
|
||||
(get-in data [:yodlee-merchant :yodlee-id]))}]])
|
||||
(when is-admin?
|
||||
|
||||
(when is-admin?
|
||||
(field "Matched Rule"
|
||||
[:input.input {:type "text"
|
||||
:field [:matched-rule :note]
|
||||
:disabled "disabled"}]))
|
||||
(field "Amount"
|
||||
[:input.input {:type "text"
|
||||
:field [:amount]
|
||||
:disabled "disabled"}])
|
||||
(field "Description"
|
||||
[:input.input {:type "text"
|
||||
:field [:description-original]
|
||||
:disabled "disabled"}])
|
||||
[form-builder/field
|
||||
"Matched Rule"
|
||||
[:input.input {:type "text"
|
||||
:field [:matched-rule :note]
|
||||
:disabled "disabled"}]])
|
||||
[form-builder/field "Amount"
|
||||
[:input.input {:type "text"
|
||||
:field [:amount]
|
||||
:disabled "disabled"}]]
|
||||
[form-builder/field
|
||||
"Description"
|
||||
[:input.input {:type "text"
|
||||
:field [:description-original]
|
||||
:disabled "disabled"}]]
|
||||
|
||||
(field "Date"
|
||||
[:input.input {:type "text"
|
||||
:field [:date]
|
||||
:disabled "disabled"}])
|
||||
[form-builder/field "Date"
|
||||
[date-picker {:type "date"
|
||||
:field [:date]
|
||||
:disabled "disabled"}]]
|
||||
|
||||
|
||||
(when (and (:payment data)
|
||||
(or is-admin? is-power-user?))
|
||||
[:p.notification.is-info.is-light>div.level>div.level-left
|
||||
[: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
|
||||
(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
|
||||
(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 (and (:payment data)
|
||||
(or is-admin? is-power-user?))
|
||||
[:p.notification.is-info.is-light>div.level>div.level-left
|
||||
[: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
|
||||
(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
|
||||
(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
|
||||
(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
|
||||
(and (seq (:potential-payment-matches data))
|
||||
(not is-already-matched?)
|
||||
(or is-admin? is-power-user?))
|
||||
[tab {:title "Payment" :key :payment}
|
||||
[potential-payment-matches-box {:potential-payment-matches (:potential-payment-matches data)}]])
|
||||
(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
|
||||
(and (seq (:potential-payment-matches data))
|
||||
(not is-already-matched?)
|
||||
(or is-admin? is-power-user?))
|
||||
[tab {:title "Payment" :key :payment}
|
||||
[potential-payment-matches-box {:potential-payment-matches (:potential-payment-matches data)}]])
|
||||
|
||||
[tab {:title "Details" :key :details}
|
||||
[:div
|
||||
(field "Vendor"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:vendor]
|
||||
:disabled (or (boolean (:payment data))
|
||||
should-disable-for-client?)}])
|
||||
(with-meta
|
||||
(field nil
|
||||
[expense-accounts-field
|
||||
{:type "expense-accounts"
|
||||
:field [:accounts]
|
||||
:max (Math/abs (js/parseFloat (:amount data)))
|
||||
:descriptor "credit account"
|
||||
:client (:client data)
|
||||
:disabled (or (boolean (:payment data))
|
||||
should-disable-for-client?)
|
||||
:locations locations}])
|
||||
{:key (str (:id (:vendor data)))})
|
||||
(field "Approval Status"
|
||||
[button-radio
|
||||
{:type "button-radio"
|
||||
:field [:approval-status]
|
||||
:options [[:unapproved "Unapproved"]
|
||||
[:requires-feedback "Client Review"]
|
||||
[:approved "Approved"]
|
||||
[:excluded "Excluded from Ledger"]]
|
||||
:disabled should-disable-for-client?}])
|
||||
[tab {:title "Details" :key :details}
|
||||
[:div
|
||||
[form-builder/field
|
||||
"Vendor"
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_vendor
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:type "typeahead-v3"
|
||||
:auto-focus true
|
||||
:field [:vendor]
|
||||
:disabled (or (boolean (:payment data))
|
||||
should-disable-for-client?)}]]
|
||||
[form-builder/raw-field [expense-accounts-field
|
||||
{:type "expense-accounts"
|
||||
:field [:accounts]
|
||||
:max (Math/abs (js/parseFloat (:amount data)))
|
||||
:descriptor "credit account"
|
||||
:client (:client data)
|
||||
:disabled (or (boolean (:payment data))
|
||||
should-disable-for-client?)
|
||||
:locations locations}]]
|
||||
[form-builder/field
|
||||
"Approval Status"
|
||||
[button-radio
|
||||
{:type "button-radio"
|
||||
:field [:approval-status]
|
||||
:options [[:unapproved "Unapproved"]
|
||||
[:requires-feedback "Client Review"]
|
||||
[:approved "Approved"]
|
||||
[:excluded "Excluded from Ledger"]]
|
||||
:disabled should-disable-for-client?}]]
|
||||
|
||||
(field "Forecasted-transaction"
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/forecasted-transactions-for-client (:id (:client data))])
|
||||
:entity->text :identifier
|
||||
:type "typeahead-v3"
|
||||
:field [:forecast-match]}])
|
||||
(error-notification)
|
||||
(when-not should-disable-for-client?
|
||||
(submit-button "Save"))]]]])
|
||||
{:key (:id data)}))])
|
||||
[form-builder/field
|
||||
"Forecasted-transaction"
|
||||
[typeahead-v3 {:entities @(re-frame/subscribe [::subs/forecasted-transactions-for-client (:id (:client data))])
|
||||
:entity->text :identifier
|
||||
:type "typeahead-v3"
|
||||
:field [:forecast-match]}]]
|
||||
[form-builder/error-notification]
|
||||
(when-not should-disable-for-client?
|
||||
[form-builder/submit-button "Save"])]]]]]])])
|
||||
|
||||
(defn form [_]
|
||||
(r/create-class
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.views.components.modal :as modal]
|
||||
[auto-ap.views.utils :refer [dispatch-event with-user]]
|
||||
[re-frame.core :as re-frame]))
|
||||
[re-frame.core :as re-frame]
|
||||
[auto-ap.forms.builder :as form-builder]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
@@ -13,22 +14,16 @@
|
||||
(fn [{ {:keys [data]} :data}]
|
||||
(not-empty data)))
|
||||
|
||||
(def import-form (forms/vertical-form {:submit-event [::save]
|
||||
:change-event [::forms/change ::form]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}))
|
||||
(defn form []
|
||||
[form-builder/builder {:submit-event [::save]
|
||||
:can-submit [::can-submit]
|
||||
:id ::form}
|
||||
|
||||
(defn form [{import-completed-event :import-completed}]
|
||||
(let [{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::form])
|
||||
{:keys [form-inline horizontal-field field raw-field error-notification submit-button]} import-form]
|
||||
|
||||
(form-inline {}
|
||||
[:div.field
|
||||
[:label.label
|
||||
"Yodlee manual import table"]
|
||||
[:div.control
|
||||
[raw-field
|
||||
[:textarea.textarea {:field [:data]}]]]])))
|
||||
[form-builder/field {:required? true}
|
||||
"Yodlee manual import table"
|
||||
[:div.control
|
||||
[:textarea.textarea {:field [:data]}]]]
|
||||
[form-builder/hidden-submit-button]])
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::opening
|
||||
@@ -46,11 +41,9 @@
|
||||
{:client-id (:id @(re-frame/subscribe [::subs/client]))
|
||||
:data ""}))}))
|
||||
|
||||
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::import-completed
|
||||
(fn [{:keys [db]} [_ {:keys [imported errors] :as result}]]
|
||||
(fn [_ _]
|
||||
{:dispatch [::modal/modal-closed ]}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
e)]
|
||||
(if (map? this-value)
|
||||
(update this-value :key (fnil identity (random-uuid)))
|
||||
this-value)) ))))
|
||||
this-value))))))
|
||||
(on-change (mapv
|
||||
(fn [v]
|
||||
(dissoc v :new? :key))
|
||||
@@ -251,7 +251,6 @@
|
||||
options (if allow-nil?
|
||||
(with-keys (conj rest [:option {:value nil}]))
|
||||
(with-keys rest))]
|
||||
(println "KEYS" keys (dissoc keys :allow-nil?))
|
||||
(into [dom (dissoc keys :allow-nil?)] options)))
|
||||
|
||||
|
||||
@@ -281,21 +280,6 @@
|
||||
keys (dissoc keys :field :subscription :event :spec)]
|
||||
(into [dom keys] (with-keys rest))))
|
||||
|
||||
(defmethod do-bind "typeahead" [dom {:keys [field text-field event text-event subscription class spec] :as keys} & rest]
|
||||
(let [field (if (keyword? field) [field] field)
|
||||
event (if (keyword? event) [event] event)
|
||||
keys (assoc keys
|
||||
:on-change (fn [selected text-value]
|
||||
(re-frame/dispatch (conj (conj event field) selected))
|
||||
(when text-field
|
||||
(re-frame/dispatch (conj (conj (or text-event event) text-field) text-value))))
|
||||
:value (get-in subscription field)
|
||||
:class (str class
|
||||
(when (and spec (not (s/valid? spec (get-in subscription field))))
|
||||
" is-danger")))
|
||||
keys (dissoc keys :field :subscription :event :spec)]
|
||||
(into [dom keys] (with-keys rest))))
|
||||
|
||||
(defmethod do-bind "multi-field" [dom {:keys [field event subscription class spec] :as keys} & rest]
|
||||
(let [field (if (keyword? field) [field] field)
|
||||
event (if (keyword? event) [event] event)
|
||||
@@ -310,20 +294,6 @@
|
||||
(into [dom keys] (with-keys rest))))
|
||||
|
||||
|
||||
(defmethod do-bind "typeahead-entity" [dom {:keys [field event subscription class spec] :as keys} & rest]
|
||||
(let [field (if (keyword? field) [field] field)
|
||||
event (if (keyword? event) [event] event)
|
||||
keys (assoc keys
|
||||
:on-change (fn [selected]
|
||||
(re-frame/dispatch (conj (conj event field) selected))
|
||||
#_(when text-field
|
||||
(re-frame/dispatch (conj (conj (or text-event event) text-field) text-value))))
|
||||
:value (get-in subscription field)
|
||||
:class (str class
|
||||
(when (and spec (not (s/valid? spec (get-in subscription field))))
|
||||
" is-danger")))
|
||||
keys (dissoc keys :field :subscription :event :spec)]
|
||||
(into [dom keys] (with-keys rest))))
|
||||
|
||||
(defmethod do-bind "typeahead-v3" [dom {:keys [field event subscription class spec] :as keys} & rest]
|
||||
(let [field (if (keyword? field) [field] field)
|
||||
|
||||
Reference in New Issue
Block a user