From 20f8bfe921956f290a8242edf50dfeef4b1c3cf8 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Mon, 29 Apr 2019 20:07:28 -0700 Subject: [PATCH] made the invoice form work like the other one. --- src/cljc/auto_ap/entities/invoice.cljc | 8 +- .../auto_ap/views/pages/invoices/form.cljs | 404 ++++++++---------- .../auto_ap/views/pages/unpaid_invoices.cljs | 2 +- 3 files changed, 182 insertions(+), 232 deletions(-) diff --git a/src/cljc/auto_ap/entities/invoice.cljc b/src/cljc/auto_ap/entities/invoice.cljc index 11a04bca..8da143fa 100644 --- a/src/cljc/auto_ap/entities/invoice.cljc +++ b/src/cljc/auto_ap/entities/invoice.cljc @@ -2,17 +2,17 @@ (:require [clojure.spec.alpha :as s] [auto-ap.entities.shared :as shared])) -(s/def ::vendor-id string?) +(s/def ::vendor map?) (s/def ::vendor-name string?) -(s/def ::client-id string?) +(s/def ::client map?) (s/def ::invoice-number ::shared/required-identifier) (s/def ::date ::shared/date) (s/def ::total ::shared/money) -(s/def ::invoice (s/keys :req-un [::client-id +(s/def ::invoice (s/keys :req-un [::client ::invoice-number ::date - ::vendor-id + ::vendor ::total] :opt-un [ ::vendor-name])) diff --git a/src/cljs/auto_ap/views/pages/invoices/form.cljs b/src/cljs/auto_ap/views/pages/invoices/form.cljs index a76fafea..04d2814d 100644 --- a/src/cljs/auto_ap/views/pages/invoices/form.cljs +++ b/src/cljs/auto_ap/views/pages/invoices/form.cljs @@ -5,23 +5,24 @@ [auto-ap.forms :as forms] [auto-ap.subs :as subs] [auto-ap.views.components.dropdown :refer [drop-down]] - [auto-ap.views.components.typeahead :refer [typeahead]] + [auto-ap.views.components.typeahead :refer [typeahead typeahead-entity]] [auto-ap.views.components.expense-accounts-field :refer [expense-accounts-field recalculate-amounts] :as expense-accounts-field] [auto-ap.views.pages.invoices.common :refer [invoice-read]] [auto-ap.views.utils :refer - [bind-field date->str date-picker dispatch-event standard]] + [bind-field date->str date-picker dispatch-event standard with-user]] [cljs-time.core :as c] [clojure.spec.alpha :as s] [re-frame.core :as re-frame] [clojure.string :as str] - [goog.string :as gstring])) + [goog.string :as gstring] + [auto-ap.views.components.layouts :as layouts])) ;; SUBS (re-frame/reg-sub - ::can-submit-edit-invoice + ::can-submit :<- [::forms/form ::form] (fn [{:keys [data status]} _] (let [min-total (if (= (:total (:original data)) (:outstanding-balance (:original data))) @@ -33,79 +34,80 @@ (or (not (:id data)) (dollars= (js/parseFloat (:total data)) (reduce + 0 (map (fn [ea] (js/parseFloat (:amount ea))) (:expense-accounts data))))))))) -(defmulti submit-query (fn [_ [_ command]] - command)) - -(defmethod submit-query :create [db] - (let [{:keys [data] {:keys [id invoice-number date location total expense-accounts vendor-id client-id]} :data} @(re-frame/subscribe [::forms/form ::form])] - {:venia/operation {:operation/type :mutation - :operation/name "AddInvoice"} - :venia/queries [{:query/data [:add-invoice - {:invoice {:date date - :vendor-id vendor-id - :client-id client-id - :invoice-number invoice-number - :location location - :total total - :expense-accounts (map (fn [ea] - {:id (when-not (str/starts-with? (:id ea) "new-") - (:id ea)) - :account_id (:id (:account ea)) - :location (:location ea) - :amount (:amount ea)}) - expense-accounts)}} - invoice-read]}]})) - -(defmethod submit-query :edit [db] - (let [{:keys [data] {:keys [id invoice-number date location total expense-accounts vendor-id client-id]} :data} @(re-frame/subscribe [::forms/form ::form])] - {:venia/operation {:operation/type :mutation - :operation/name "EditInvoice"} - :venia/queries [{:query/data [:edit-invoice - {:invoice {:id id - :invoice-number invoice-number - :date date - :total total - :expense-accounts (map (fn [ea] - {:id (when-not (str/starts-with? (:id ea) "new-") - (:id ea)) - :account_id (:id (:account ea)) - :location (:location ea) - :amount (:amount ea)}) - expense-accounts)}} - invoice-read]}]})) - -(defmethod submit-query :add-and-print [db [_ _ bank-account-id type]] - (let [{:keys [data] {:keys [id invoice-number date location total expense-accounts vendor-id client-id]} :data} @(re-frame/subscribe [::forms/form ::form])] - {:venia/operation {:operation/type :mutation - :operation/name "AddAndPrintInvoice"} - :venia/queries [{:query/data [:add-and-print-invoice - {:invoice {:date date - :vendor-id vendor-id - :client-id client-id - :invoice-number invoice-number - :location location - :total total - :expense-accounts (map (fn [ea] - {:id (when-not (str/starts-with? (:id ea) "new-") - (:id ea)) - :account_id (:id (:account ea)) - :location (:location ea) - :amount (:amount ea)}) - expense-accounts)} - :bank-account-id bank-account-id - :type type} - [:pdf-url [:invoices invoice-read]]]}]})) +(re-frame/reg-sub + ::create-query + :<- [::forms/form ::form] + (fn [{:keys [data] {:keys [id invoice-number date location total expense-accounts vendor client]} :data}] + {:venia/operation {:operation/type :mutation + :operation/name "AddInvoice"} + :venia/queries [{:query/data [:add-invoice + {:invoice {:date date + :vendor-id (:id vendor) + :client-id (:id client) + :invoice-number invoice-number + :location location + :total total + :expense-accounts (map (fn [ea] + {:id (when-not (str/starts-with? (:id ea) "new-") + (:id ea)) + :account_id (:id (:account ea)) + :location (:location ea) + :amount (:amount ea)}) + expense-accounts)}} + invoice-read]}]})) (re-frame/reg-sub - ::submit-query - submit-query) + ::edit-query + :<- [::forms/form ::form] + (fn [{:keys [data] {:keys [id invoice-number date location total expense-accounts vendor client]} :data}] + {:venia/operation {:operation/type :mutation + :operation/name "EditInvoice"} + :venia/queries [{:query/data [:edit-invoice + {:invoice {:id id + :invoice-number invoice-number + :date date + :total total + :expense-accounts (map (fn [ea] + {:id (when-not (str/starts-with? (:id ea) "new-") + (:id ea)) + :account_id (:id (:account ea)) + :location (:location ea) + :amount (:amount ea)}) + expense-accounts)}} + invoice-read]}]})) + +(re-frame/reg-sub + ::add-and-print-query + (fn [db [_ bank-account-id type]] + (let [{:keys [data] {:keys [id invoice-number date location total expense-accounts vendor client]} :data} @(re-frame/subscribe [::forms/form ::form])] + {:venia/operation {:operation/type :mutation + :operation/name "AddAndPrintInvoice"} + :venia/queries [{:query/data [:add-and-print-invoice + {:invoice {:date date + :vendor-id (:id vendor) + :client-id (:id client) + :invoice-number invoice-number + :location location + :total total + :expense-accounts (map (fn [ea] + {:id (when-not (str/starts-with? (:id ea) "new-") + (:id ea)) + :account_id (:id (:account ea)) + :location (:location ea) + :amount (:amount ea)}) + expense-accounts)} + :bank-account-id bank-account-id + :type type} + [:pdf-url [:invoices invoice-read]]]}]}))) + + ;; EVENTS (re-frame/reg-event-db ::adding (fn [db [_ new]] - (let [locations @(re-frame/subscribe [::subs/locations-for-client (:client-id new)])] + (let [locations @(re-frame/subscribe [::subs/locations-for-client (:client new)])] (-> db (forms/start-form ::form (assoc new :expense-accounts (expense-accounts-field/from-graphql (:expense-accounts new) 0.0 @@ -123,65 +125,60 @@ :invoice-number (:invoice-number edit-invoice) :total (:total edit-invoice) :original edit-invoice - :vendor-id (:id (:vendor edit-invoice)) - :vendor-name (:name (:vendor edit-invoice)) - :client-id (:id (:client edit-invoice)) + :vendor (:vendor edit-invoice) + :client (:client edit-invoice) :expense-accounts (expense-accounts-field/from-graphql (:expense-accounts which) (:amount which) - locations) - :client-name (:name (:client edit-invoice))}))))) + locations)}))))) +(re-frame/reg-event-db + ::changed + (forms/change-handler ::form + (fn [data field value] + (let [locations @(re-frame/subscribe [::subs/locations-for-client (:id (:client data))])] + (cond (and (= [:vendor] field) + value + (expense-accounts-field/can-replace-with-default? (:expense-accounts data))) + [[:expense-accounts] (expense-accounts-field/default-account (:expense-accounts data) + @(re-frame/subscribe [::subs/vendor-default-account value]) + (:total data) + locations)] + + (= [:total] field) + [[:expense-accounts] (recalculate-amounts (:expense-accounts data) value)] + + :else + []))))) + (re-frame/reg-event-fx - ::change-new-invoice-client - (fn [{:keys [db ]} [_ location field value]] - (let [first-location (-> @(re-frame/subscribe [::subs/clients-by-id]) - (get-in [value :locations]) - first)] - {:dispatch [::forms/change ::form - [:client-id] value - [:location] first-location]}))) + ::add-and-print + [with-user (forms/triggers-loading ::form) (forms/in-form ::form)] + (fn [{:keys [user] {:keys [data]} :db} [_ params bank-account-id type]] + {:graphql + {:token user + :query-obj @(re-frame/subscribe [::add-and-print-query bank-account-id type]) + :on-success [::succeeded params :add-and-print] + :on-error [::forms/save-error ::form]}})) (re-frame/reg-event-fx - ::change-amount - [(forms/in-form ::form)] - (fn [{{:keys [data]} :db} [_ field value]] - (print field value (:expense-accounts data)) - {:dispatch [::forms/change ::form - field value - [:expense-accounts] (recalculate-amounts (:expense-accounts data) value)]})) - - -(re-frame/reg-event-fx - ::change-vendor - [(forms/in-form ::form)] - (fn [{{:keys [data]} :db} [_ field value]] - (let [locations @(re-frame/subscribe [::subs/locations-for-client (:client-id data)])] - (if (and value (expense-accounts-field/can-replace-with-default? (:expense-accounts data))) - {:dispatch [::forms/change ::form - field value - [:expense-accounts] (expense-accounts-field/default-account (:expense-accounts data) - @(re-frame/subscribe [::subs/vendor-default-account value]) - (:amount data) - locations)]} - {:dispatch [::forms/change ::form field value]})))) - - -(re-frame/reg-event-fx - ::submitted - (fn [{:keys [db]} [_ params command bank-account-id type]] - (when @(re-frame/subscribe [::can-submit-edit-invoice]) - (let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])] - {:db (forms/loading db ::form) - :graphql - {:token (-> db :user) - :query-obj @(re-frame/subscribe [::submit-query command bank-account-id type]) - :on-success [::succeeded params command] - :on-error [::forms/save-error ::form]}})))) - + ::saving + [with-user (forms/triggers-loading ::form) (forms/in-form ::form)] + (fn [{:keys [user] {:keys [data]} :db} [_ params]] + (let [command (if (:id data) + :edit + :create)] + {:graphql + {:token user + :query-obj @(re-frame/subscribe (if (:id data) + @(re-frame/subscribe [::edit-query]) + @(re-frame/subscribe [::create-query]))) + :on-success [::succeeded params command] + :on-error [::forms/save-error ::form]}}))) (re-frame/reg-event-fx ::succeeded + [(forms/triggers-stop ::form)] (fn [{:keys [db]} [_ {:keys [invoice-created invoice-printed]} command result]] (let [invoice (condp = command :edit (:edit-invoice result) @@ -191,12 +188,9 @@ :add-and-print (first (:invoices (:add-and-print-invoice result))))] {:db (cond-> db - true (forms/stop-form ::form) - - (#{:create :add-and-print} command) (forms/start-form ::form {:client-id (:id @(re-frame/subscribe [::subs/client])) + (#{:create :add-and-print} command) (forms/start-form ::form {:client @(re-frame/subscribe [::subs/client]) :status :unpaid - :date (date->str (c/now) standard) - :location (first (:locations @(re-frame/subscribe [::subs/client])))})) + :date (date->str (c/now) standard)})) :dispatch-n (cond-> [(conj invoice-created invoice)] (= :add-and-print command) (conj (conj invoice-printed (:pdf-url (:add-and-print-invoice result)))))}))) @@ -204,119 +198,78 @@ ;; VIEWS +(def invoice-form (forms/vertical-form {:can-submit [::can-submit] + :change-event [::changed] + :submit-event [::saving ] + :id ::form})) (defn form [{:keys [can-change-amount?] :as params}] - [forms/side-bar-form {:form ::form } + [layouts/side-bar {:on-close (dispatch-event [::forms/form-closing ::form ])} (let [{:keys [data active? error id]} @(re-frame/subscribe [::forms/form ::form]) + {:keys [form field raw-field error-notification submit-button ]} invoice-form exists? (:id data) - current-client @(re-frame/subscribe [::subs/client]) can-change-amount? (#{:unpaid ":unpaid"} (:status data)) - change-event [::forms/change ::form] - locations (get-in @(re-frame/subscribe [::subs/clients-by-id]) [(:client-id data) :locations]) - multi-location? (> (count locations) 1) - min-total (if (= (:total (:original data)) (:outstanding-balance (:original data))) nil (- (:total (:original data)) (:outstanding-balance (:original data)))) - should-select-location? (and locations - (> (count locations) 1)) chooseable-expense-accounts @(re-frame/subscribe [::subs/chooseable-expense-accounts]) accounts-by-id @(re-frame/subscribe [::subs/accounts-for-client-by-id])] ^{:key id} - [:form { :on-submit (fn [e] - (when (.-stopPropagation e) - (.stopPropagation e) - (.preventDefault e)) - (if exists? - (re-frame/dispatch-sync [::submitted params :edit]) - (re-frame/dispatch-sync [::submitted params :create])))} - [:h1.title.is-2 "New Invoice"] + [form (assoc params :title "New Invoice") (when-not @(re-frame/subscribe [::subs/client]) - [:div.field - [:p.help "Client"] - [:div.control - [bind-field - [typeahead {:matches (map (fn [x] [(:id x) (:name x)]) @(re-frame/subscribe [::subs/clients])) - :type "typeahead" - :auto-focus (if @(re-frame/subscribe [::subs/client]) false true) - :field [:client-id] - :disabled exists? - :event [::change-new-invoice-client [::form]] - :spec ::invoice/client-id - :subscription data}]]]]) - - [:div.field - [:p.help "Vendor"] - [:div.control - [bind-field - [typeahead {:matches (map (fn [x] [(:id x) (:name x)]) @(re-frame/subscribe [::subs/vendors])) - :type "typeahead" - :disabled exists? - :auto-focus (if @(re-frame/subscribe [::subs/client]) true false) - :field [:vendor-id] - :text-event change-event - :event [::change-vendor] - :spec (s/nilable ::invoice/vendor-id) - :subscription data}]]]] + [field "Client" + [typeahead-entity {:matches @(re-frame/subscribe [::subs/clients]) + :match->text :name + :type "typeahead" + :auto-focus (if @(re-frame/subscribe [::subs/client]) false true) + :field [:client] + :disabled exists? + :spec ::invoice/client}]]) - [:div.field - [:p.help "Date"] - [:div.control - [bind-field - [date-picker {:class-name "input" - :class "input" - :format-week-number (fn [] "") - :previous-month-button-label "" - :placeholder "mm/dd/yyyy" - :next-month-button-label "" - :next-month-label "" - :type "date" - :field [:date] - :event change-event - :spec ::invoice/date - :subscription data}]]]] + [field "Vendor" + [typeahead-entity {:matches @(re-frame/subscribe [::subs/vendors]) + :match->text :name + :type "typeahead" + :disabled exists? + :auto-focus (if @(re-frame/subscribe [::subs/client]) true false) + :field [:vendor]}]] - [:div.field - [:p.help "Invoice #"] - [:div.control - [bind-field - [:input.input {:type "text" - :field [:invoice-number] - :event change-event - :spec ::invoice/invoice-number - :subscription data}]]]] + [field "Date" + [date-picker {:class-name "input" + :class "input" + :format-week-number (fn [] "") + :previous-month-button-label "" + :placeholder "mm/dd/yyyy" + :next-month-button-label "" + :next-month-label "" + :type "date" + :field [:date] + :spec ::invoice/date}]] - [:div.field - [:p.help "Total"] - [:div.control - [:div.field.has-addons.is-extended - [:p.control [:a.button.is-static "$"]] - [:p.control - [bind-field - [:input.input {:type "number" - :field [:total] - :disabled (if can-change-amount? "" "disabled") - :event [::change-amount] - :min min-total - :subscription data - :spec ::invoice/total - :step "0.01"}]]]]]] + [field "Invoice #" + [:input.input {:type "text" + :field [:invoice-number] + :spec ::invoice/invoice-number}]] - [:div.field - [bind-field - [expense-accounts-field {:subscription data - :type "expense-accounts" - :descriptor "expense account" - :event change-event - :locations locations - :max (:total data) - :field [:expense-accounts]}]]] + + [field "Total" + [:input.input {:type "number" + :field [:total] + :disabled (if can-change-amount? "" "disabled") + :min min-total + :spec ::invoice/total + :step "0.01"}]] + + [field nil + [expense-accounts-field {:type "expense-accounts" + :descriptor "expense account" + :locations (:locations (:client data)) + :max (:total data) + :field [:expense-accounts]}]] - (when error - ^{:key error} [:div.notification.is-warning.animated.fadeInUp - error]) + [error-notification] [:div.columns (when-not exists? @@ -324,7 +277,7 @@ [drop-down {:header [:button.button.is-info.is-outlined.is-medium.is-fullwidth {:aria-haspopup true :type "button" :on-click (dispatch-event [::events/toggle-menu ::add-and-print-invoice ]) - :disabled (if @(re-frame/subscribe [::can-submit-edit-invoice]) + :disabled (if @(re-frame/subscribe [::can-submit]) "" "disabled") @@ -338,15 +291,12 @@ :id ::add-and-print-invoice} [:div (list - (for [{:keys [id number name type]} (->> (:bank-accounts current-client) (filter :visible) (sort-by :sort-order))] + (for [{:keys [id number name type]} (->> (:bank-accounts (:client data)) (filter :visible) (sort-by :sort-order))] (if (= :cash type) - ^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::submitted params id :cash])} "With cash"] + ^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::add-and-print params id :cash])} "With cash"] (list - ^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::submitted params :add-and-print id :check])} "Print checks from " name] - ^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::submitted params :add-and-print id :debit])} "Debit from " name]))))]]]) + ^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event [::add-and-print params id :check])} "Print checks from " name] + ^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event [::add-and-print params id :debit])} "Debit from " name]))))]]]) [:div.column - [:button.button.is-medium.is-primary.is-fullwidth {:disabled (if @(re-frame/subscribe [::can-submit-edit-invoice]) - "" - "disabled") - :class (str @(re-frame/subscribe [::forms/loading-class ::form]) - (when error " animated shake"))} "Save"]] ]])]) + + [submit-button "Save"]]]])]) diff --git a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs index 8e839623..b73b6666 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -281,7 +281,7 @@ (re-frame/reg-event-fx ::new-invoice-clicked (fn [{:keys [db]} _] - {:dispatch [::form/adding {:client-id (:id @(re-frame/subscribe [::subs/client])) + {:dispatch [::form/adding {:client @(re-frame/subscribe [::subs/client]) :status :unpaid #_#_:date (date->str (c/now) standard) :location (first (:locations @(re-frame/subscribe [::subs/client])))}]}))