304 lines
15 KiB
Clojure
304 lines
15 KiB
Clojure
(ns auto-ap.views.pages.unpaid-invoices
|
|
(:require
|
|
[auto-ap.effects.forward :as forward]
|
|
[auto-ap.events :as events]
|
|
[auto-ap.forms :as forms]
|
|
[auto-ap.status :as status]
|
|
[auto-ap.subs :as subs]
|
|
[auto-ap.views.components.buttons :as buttons]
|
|
[auto-ap.views.components.dropdown :refer [drop-down]]
|
|
[auto-ap.views.components.expense-accounts-dialog
|
|
:as expense-accounts-dialog]
|
|
[auto-ap.views.components.invoice-table :as table]
|
|
[auto-ap.views.components.invoices.side-bar
|
|
:as side-bar
|
|
:refer [invoices-side-bar]]
|
|
[auto-ap.views.components.layouts
|
|
:refer [appearing-side-bar side-bar-layout]]
|
|
[auto-ap.views.components.modal :as modal]
|
|
[auto-ap.views.pages.data-page :as data-page]
|
|
[auto-ap.views.pages.invoices.advanced-print-checks
|
|
:as advanced-print-checks]
|
|
[auto-ap.views.pages.invoices.common :refer [invoice-read]]
|
|
[auto-ap.views.pages.invoices.form :as form]
|
|
[auto-ap.views.pages.invoices.handwritten-checks :as handwritten-checks]
|
|
[auto-ap.views.utils
|
|
:refer [dispatch-event dispatch-event-with-propagation with-user]]
|
|
[clojure.set :as set]
|
|
[clojure.string :as str]
|
|
[goog.string :as gstring]
|
|
[re-frame.core :as re-frame]
|
|
[reagent.core :as r]
|
|
[vimsical.re-frame.fx.track :as track]))
|
|
|
|
(re-frame/reg-event-fx
|
|
::params-change
|
|
[with-user]
|
|
(fn [{:keys [user]} [_ params]]
|
|
(try
|
|
{:graphql {:token user
|
|
:owns-state {:single [::data-page/page :invoices]}
|
|
:query-obj (table/query params )
|
|
:on-success (fn [result]
|
|
(let [result (set/rename-keys (first (:invoice-page result))
|
|
{:invoices :data})]
|
|
|
|
[::data-page/received :invoices result]))}}
|
|
(catch js/Error e
|
|
(println "Warning" e)))))
|
|
|
|
(re-frame/reg-event-fx
|
|
::unmounted
|
|
(fn [{:keys [db]} _]
|
|
{:dispatch [::data-page/dispose :invoices]
|
|
::forward/dispose [{:id ::updated}
|
|
{:id ::checks-printed}]
|
|
::track/dispose [{:id ::params}]}))
|
|
|
|
(re-frame/reg-event-fx
|
|
::mounted
|
|
(fn [{:keys [db]} _]
|
|
{::track/register [{:id ::params
|
|
:subscription [::data-page/params :invoices]
|
|
:event-fn (fn [params]
|
|
[::params-change params])}]
|
|
::forward/register [{:id ::updated
|
|
:events #{::table/invoice-updated ::form/updated ::expense-accounts-dialog/updated}
|
|
:event-fn (fn [[_ invoice]]
|
|
[::data-page/updated-entity :invoices invoice])}
|
|
{:id ::checks-printed
|
|
:events #{::form/checks-printed ::advanced-print-checks/checks-printed ::handwritten-checks/succeeded}
|
|
:event-fn (fn [[_ invoices pdf-url]]
|
|
[::checks-printed invoices pdf-url])}]}))
|
|
|
|
|
|
(defn print-checks-query [invoice-payments bank-account-id type client-id]
|
|
{:venia/operation {:operation/type :mutation
|
|
:operation/name "PrintChecks"}
|
|
:venia/queries [[:print-checks
|
|
{:invoice_payments invoice-payments
|
|
:type type
|
|
:bank_account_id bank-account-id
|
|
:client_id client-id}
|
|
[[:invoices invoice-read]
|
|
:pdf_url]]]})
|
|
|
|
(re-frame/reg-event-fx
|
|
::print-checks
|
|
(fn [{:keys [db]} [_ bank-account-id type]]
|
|
{:graphql
|
|
{:token (-> db :user)
|
|
:owns-state {:single ::print-checks}
|
|
|
|
:query-obj (print-checks-query (->> @(re-frame/subscribe [::data-page/checked :invoices])
|
|
(vals )
|
|
(filter (fn [{:keys [id outstanding-balance] }]
|
|
(and id outstanding-balance)))
|
|
(map (fn [{:keys [id outstanding-balance] }]
|
|
{:invoice-id id
|
|
:amount outstanding-balance})))
|
|
bank-account-id
|
|
type
|
|
(:client db))
|
|
:on-success (fn [result]
|
|
[::checks-printed
|
|
(:invoices (:print-checks result))
|
|
(:pdf-url (:print-checks result))])}}))
|
|
|
|
|
|
(re-frame/reg-event-fx
|
|
::checks-printed
|
|
(fn [{:keys [db]} [_ invoices pdf-url]]
|
|
{:dispatch-n (cond->> [[::data-page/reset-checked :invoices]]
|
|
true (into (mapv
|
|
(fn [i]
|
|
[::data-page/updated-entity :invoices i])
|
|
invoices))
|
|
|
|
pdf-url (into [[::modal/modal-requested {:title "Your checks are ready!"
|
|
:body [:div
|
|
[:div "Click " [:a {:href pdf-url :target "_new"} "here"] " to print them."]
|
|
[:div [:em "Remember to turn off all scaling and margins."]]]}]]))}))
|
|
|
|
|
|
(re-frame/reg-event-fx
|
|
::new-invoice-clicked
|
|
(fn [{:keys [db]} _]
|
|
{: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])))}]}))
|
|
(re-frame/reg-event-fx
|
|
::voided-selected
|
|
(fn [cofx [_]]
|
|
{:dispatch-n [[::modal/modal-closed]
|
|
[::params-change @(re-frame/subscribe [::data-page/params ::page])]
|
|
[::data-page/reset-checked :invoices]]}))
|
|
|
|
(re-frame/reg-event-fx
|
|
::void-selected
|
|
(fn [cofx [_ which]]
|
|
(let [checked-params (get which "header")
|
|
specific-invoices (map :id (vals (dissoc which "header")))]
|
|
{:graphql {:token (-> cofx :db :user)
|
|
:owns-state {:single ::void-selected}
|
|
:query-obj
|
|
{:venia/operation {:operation/type :mutation
|
|
:operation/name "VoidInvoices"}
|
|
:venia/queries [{:query/data
|
|
[:void-invoices
|
|
{:filters (some-> checked-params table/data-params->query-params)
|
|
:ids specific-invoices}
|
|
[:message]]}]}
|
|
:on-success (fn [_]
|
|
[::voided-selected])}})))
|
|
|
|
(re-frame/reg-event-fx
|
|
::void-selected-requested
|
|
(fn [_ [_ which]]
|
|
(let [to-delete (if (get which "header")
|
|
"all visible invoices"
|
|
(str (count which) " invoices"))]
|
|
|
|
|
|
{:dispatch [::modal/modal-requested {:title "Confirmation"
|
|
:body [:div (str "Are you sure you want to void " to-delete "?")]
|
|
:cancel? true
|
|
:confirm {:value "Void"
|
|
:class "is-danger"
|
|
:status-from [::status/single ::void-selected]
|
|
:on-click (dispatch-event [::void-selected which] )}
|
|
:close-event [::status/completed ::void-selected]}]})))
|
|
|
|
(defn void-selected-button []
|
|
(let [status @(re-frame/subscribe [::status/single ::void-selected])
|
|
checked-invoices @(re-frame/subscribe [::data-page/checked :invoices])
|
|
is-admin? @(re-frame/subscribe [::subs/is-admin?])]
|
|
(when is-admin?
|
|
[:button.button.is-danger {:on-click (dispatch-event [::void-selected-requested checked-invoices])
|
|
:class (status/class-for status)
|
|
:disabled (or (status/disabled-for status)
|
|
(not (seq checked-invoices)))}
|
|
"Void"])))
|
|
|
|
|
|
(defn pay-button []
|
|
(let [current-client @(re-frame/subscribe [::subs/client])
|
|
checked-invoices @(re-frame/subscribe [::data-page/checked :invoices])
|
|
print-checks-status @(re-frame/subscribe [::status/single ::print-checks])]
|
|
[:div
|
|
[:div.is-pulled-right
|
|
[:div.buttons
|
|
[void-selected-button]
|
|
|
|
[buttons/new-button {:event [::new-invoice-clicked]
|
|
:name "Invoice"
|
|
:class "is-primary"}]
|
|
|
|
(when current-client
|
|
(let [balance (->> checked-invoices
|
|
vals
|
|
(map (comp js/parseFloat :outstanding-balance))
|
|
(reduce + 0)
|
|
)]
|
|
[drop-down {:header [:button.button.is-primary {:aria-haspopup true
|
|
:on-click (dispatch-event [::events/toggle-menu ::print-checks ])
|
|
:disabled (or (status/disabled-for print-checks-status) (not (seq checked-invoices)))
|
|
:class (status/class-for @(re-frame/subscribe [::status/single ::print-checks]))}
|
|
"Pay "
|
|
(when (> (count checked-invoices ) 0)
|
|
(str
|
|
(count checked-invoices)
|
|
" invoices "
|
|
"(" (gstring/format "$%.2f" balance ) ")"))
|
|
[:span " "]
|
|
[:span.icon.is-small [:i.fa.fa-angle-down {:aria-hidden "true"}]]]
|
|
:id ::print-checks
|
|
:is-right? true}
|
|
[:div
|
|
(list
|
|
(for [{:keys [id number name type]} (->> (:bank-accounts current-client) (filter :visible) (sort-by :sort-order))]
|
|
(if (= :cash type)
|
|
^{:key id} [:a.dropdown-item {:on-click (dispatch-event [::print-checks id :cash])
|
|
:disabled (status/disabled-for print-checks-status)} "With cash"]
|
|
(if (> balance 0.001)
|
|
(list
|
|
^{:key (str id "-check")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::print-checks id :check])
|
|
:disabled (status/disabled-for print-checks-status)} "Print checks from " name]
|
|
^{:key (str id "-debit")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::print-checks id :debit])
|
|
:disabled (status/disabled-for print-checks-status)} "Debit from " name])
|
|
(list
|
|
^{:key (str id "-credit")} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::print-checks id :credit])
|
|
:disabled (status/disabled-for print-checks-status)} "Credit from " name]))))
|
|
(when (> balance 0.001)
|
|
^{:key "advanced-divider"} [:hr.dropdown-divider])
|
|
|
|
(when (and (= 1 (count (set (map (comp :id :vendor) (vals checked-invoices)))))
|
|
(> balance 0.001))
|
|
^{:key "handwritten"} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::handwritten-checks/show (vals checked-invoices)])
|
|
:disabled (status/disabled-for print-checks-status)} "Handwritten Check..."])
|
|
(when (> balance 0.001)
|
|
^{:key "advanced"} [:a.dropdown-item {:on-click (dispatch-event-with-propagation [::advanced-print-checks/show (vals checked-invoices)])
|
|
:disabled (status/disabled-for print-checks-status)} "Advanced..."]))]]))]]
|
|
[:div.is-pulled-right {:style {:margin-right "0.5rem"}}
|
|
(into [:div.tags ] (map (fn [[z {:keys [id invoice-number]}]]
|
|
(if (= z "header")
|
|
[:span.tag.is-medium "All visible invoices"
|
|
[:button.delete.is-small {:on-click
|
|
(dispatch-event [::data-page/remove-check :invoices z])}]]
|
|
[:span.tag.is-medium invoice-number
|
|
[:button.delete.is-small {:on-click
|
|
(dispatch-event [::data-page/remove-check :invoices id])}]]))
|
|
checked-invoices))]]))
|
|
|
|
|
|
(defn unpaid-invoices-content [{:keys [status]}]
|
|
(let [page @(re-frame/subscribe [::data-page/page :invoices])
|
|
current-client @(re-frame/subscribe [::subs/client])]
|
|
[:div
|
|
[:h1.title (str (str/capitalize (name (or status :all))) " invoices")]
|
|
[status/status-notification {:statuses [[::status/single ::print-checks]
|
|
[::status/last-multi ::table/void]
|
|
[::status/last-multi ::table/unvoid]]}]
|
|
(when (= status :unpaid)
|
|
[pay-button])
|
|
[table/invoice-table {:id (:id page)
|
|
:data-page :invoices
|
|
:check-boxes (= status :unpaid)
|
|
:checkable-fn (fn [i] (not (:scheduled-payment i)))
|
|
:actions #{:edit :void :expense-accounts}}]]))
|
|
|
|
(defn layout [params]
|
|
(let [{invoice-bar-active? :active?} @(re-frame/subscribe [::forms/form ::form/form])]
|
|
[side-bar-layout {:side-bar [invoices-side-bar {:data-page :invoices}]
|
|
:main [unpaid-invoices-content params]
|
|
:right-side-bar [appearing-side-bar {:visible? invoice-bar-active?} [form/form {}]]}]))
|
|
|
|
(defn unpaid-invoices-page [params]
|
|
(r/create-class
|
|
{:display-name "unpaid-invoices-page"
|
|
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])
|
|
:component-did-mount #(re-frame/dispatch [::mounted])
|
|
:reagent-render layout}))
|
|
|
|
(defn paid-invoices-page [params]
|
|
(r/create-class
|
|
{:display-name "paid-invoices-page"
|
|
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])
|
|
:component-did-mount #(re-frame/dispatch [::mounted])
|
|
:reagent-render layout}))
|
|
|
|
(defn voided-invoices-page [params]
|
|
(r/create-class
|
|
{:display-name "voided-invoices-page"
|
|
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])
|
|
:component-did-mount #(re-frame/dispatch [::mounted])
|
|
:reagent-render layout}))
|
|
|
|
(defn all-invoices-page [params]
|
|
(r/create-class
|
|
{:display-name "all-invoices-page"
|
|
:component-will-unmount #(re-frame/dispatch-sync [::unmounted])
|
|
:component-did-mount #(re-frame/dispatch [::mounted])
|
|
:reagent-render layout}))
|