214 lines
9.8 KiB
Clojure
214 lines
9.8 KiB
Clojure
(ns auto-ap.views.components.invoice-table
|
|
(:require [re-frame.core :as re-frame]
|
|
[auto-ap.subs :as subs]
|
|
[auto-ap.views.utils :refer [date->str dispatch-event delayed-dispatch]]
|
|
[auto-ap.views.components.paginator :refer [paginator]]
|
|
[auto-ap.views.components.sorter :refer [sorted-column]]
|
|
[reagent.core :as reagent]
|
|
[clojure.string :as str]
|
|
[cljs-time.format :as format]
|
|
[goog.string :as gstring]))
|
|
|
|
;; TODO graphql schema enforcement
|
|
;; TODO postgres constraints for data integrity
|
|
;; TODO performance
|
|
;; TODO refactor graphql
|
|
|
|
(re-frame/reg-event-fx
|
|
::toggle-checks
|
|
(fn [{:keys [db] } [_ invoice-id]]
|
|
{:db
|
|
(update-in db [::visible-checks] (fn [i] (if (= i invoice-id) nil invoice-id) ))}))
|
|
|
|
(re-frame/reg-sub
|
|
::visible-checks
|
|
(fn [db]
|
|
(::visible-checks db)))
|
|
|
|
(re-frame/reg-event-fx
|
|
::toggle-expense-accounts
|
|
(fn [{:keys [db] } [_ invoice-id]]
|
|
{:db
|
|
(update-in db [::visible-expense-accounts] (fn [i] (if (= i invoice-id) nil invoice-id) ))}))
|
|
|
|
(re-frame/reg-sub
|
|
::visible-expense-accounts
|
|
(fn [db]
|
|
(::visible-expense-accounts db)))
|
|
|
|
|
|
|
|
(defn query [params]
|
|
{:venia/queries [[:invoice_page
|
|
(assoc params
|
|
:company-id (:id @(re-frame/subscribe [::subs/company])))
|
|
[[:invoices [:id :total :outstanding-balance :invoice-number :date
|
|
[:vendor [:name :id]]
|
|
[:expense_accounts [:amount :id :expense_account_id :location
|
|
[:expense_account [:id :name [:parent [:id :name]]]]]]
|
|
[:company [:name :id :locations]]
|
|
[:checks [:amount [:check [:amount :s3_url :check_number ]]]]
|
|
]]
|
|
:total
|
|
:start
|
|
:end]]]})
|
|
|
|
|
|
|
|
(defn invoice-table [{:keys [id invoice-page status on-params-change vendors params check-boxes checked on-check-changed on-edit-invoice on-void-invoice expense-event]}]
|
|
(let [state (reagent/atom (or @params {}))
|
|
visible-checks @(re-frame/subscribe [::visible-checks])
|
|
visible-expense-accounts @(re-frame/subscribe [::visible-expense-accounts])
|
|
selected-company @(re-frame/subscribe [::subs/company])
|
|
opc (fn [p]
|
|
(swap! state merge p)
|
|
(on-params-change p))]
|
|
(fn [{:keys [id invoice-page status on-params-change vendors checked]}]
|
|
(let [{:keys [sort-by asc]} @state
|
|
{:keys [invoices start end count total]} @invoice-page
|
|
visible-checks @(re-frame/subscribe [::visible-checks])
|
|
visible-expense-accounts @(re-frame/subscribe [::visible-expense-accounts])
|
|
selected-company @(re-frame/subscribe [::subs/company])
|
|
percentage-size (if selected-company "%50%" "33%")
|
|
]
|
|
[:div
|
|
[paginator {:start start :end end :count count :total total
|
|
:on-change (fn [p ]
|
|
(on-params-change (swap! state merge p)))}]
|
|
"Showing " (inc start) "-" end "/" total
|
|
|
|
[:table.table.is-fullwidth
|
|
[:thead
|
|
[:tr
|
|
(when check-boxes
|
|
[:th {:style {"width" "20px"}}])
|
|
|
|
(when-not selected-company
|
|
[sorted-column {:on-sort opc
|
|
:style {:width percentage-size :cursor "pointer"}
|
|
:sort-key "company"
|
|
:sort-by sort-by
|
|
:asc asc}
|
|
"Company"])
|
|
[sorted-column {:on-sort opc
|
|
:style {:width percentage-size :cursor "pointer"}
|
|
:sort-key "vendor"
|
|
:sort-by sort-by
|
|
:asc asc}
|
|
"Vendor"]
|
|
[sorted-column {:on-sort opc
|
|
:style {:width percentage-size :cursor "pointer"}
|
|
:sort-key "invoice-number"
|
|
:sort-by sort-by
|
|
:asc asc}
|
|
"Invoice #"]
|
|
[sorted-column {:on-sort opc
|
|
:style {:width "8em" :cursor "pointer"}
|
|
:sort-key "date"
|
|
:sort-by sort-by
|
|
:asc asc}
|
|
"Date"]
|
|
[sorted-column {:on-sort opc
|
|
:style {:width "8em" :cursor "pointer"}
|
|
:sort-key "location"
|
|
:sort-by sort-by
|
|
:asc asc}
|
|
"Location"]
|
|
[sorted-column {:on-sort opc
|
|
:style {:width "8em" :cursor "pointer"}
|
|
:sort-key "total"
|
|
:sort-by sort-by
|
|
:asc asc}
|
|
"Amount"]
|
|
|
|
[sorted-column {:on-sort opc
|
|
:style {:width "10em" :cursor "pointer"}
|
|
:sort-key "outstanding"
|
|
:sort-by sort-by
|
|
:asc asc}
|
|
"Outstanding"]
|
|
|
|
[:th {
|
|
:style {:width "15em" :cursor "pointer"}
|
|
|
|
|
|
}
|
|
""]]]
|
|
[:tbody
|
|
(if (:loading @status)
|
|
[:tr
|
|
[:td {:col-span 5}
|
|
[:i.fa.fa-spin.fa-spinner]]]
|
|
(for [{:keys [company checks expense-accounts invoice-number date total outstanding-balance id vendor] :as i} (:invoices @invoice-page)]
|
|
^{:key id}
|
|
[:tr {:class (:class i)}
|
|
(when check-boxes
|
|
[:td [:input.checkbox {:type "checkbox"
|
|
:checked (if (get checked id)
|
|
"checked"
|
|
"")
|
|
:on-change (fn [x e] (when on-check-changed
|
|
(on-check-changed id)))} ]])
|
|
(when-not selected-company
|
|
[:td (:name company)])
|
|
[:td (:name vendor)]
|
|
[:td invoice-number]
|
|
[:td (date->str date) ]
|
|
[:td (str/join ", " (set (map :location expense-accounts)))]
|
|
|
|
[:td (gstring/format "$%.2f" total )]
|
|
[:td (gstring/format "$%.2f" outstanding-balance )]
|
|
[:td.expandable
|
|
(when (seq expense-accounts)
|
|
|
|
[:div.dropdown.is-right {:class (if (= id visible-expense-accounts)
|
|
"is-active"
|
|
"")}
|
|
[:div.dropdown-trigger
|
|
[:a.button.badge {:data-badge (str (clojure.core/count expense-accounts))
|
|
:aria-haspopup true
|
|
:tab-index "0"
|
|
|
|
:on-blur (delayed-dispatch [::toggle-expense-accounts id])
|
|
:on-focus (dispatch-event [::toggle-expense-accounts id])
|
|
} "Accounts"]]
|
|
[:div.dropdown-menu {:role "menu"}
|
|
[:div.dropdown-content
|
|
(for [e expense-accounts]
|
|
^{:key (:id e)}
|
|
[:span.dropdown-item (:name (:expense-account e)) " "(gstring/format "$%.2f" (:amount e) ) ])
|
|
|
|
[:hr.dropdown-divider]
|
|
|
|
(when expense-event
|
|
[:a.dropdown-item.is-primary {:on-click (dispatch-event (conj expense-event id))} "Change"])]]])
|
|
[:span {:style {:margin-left "1em"}}]
|
|
(when on-edit-invoice
|
|
[:button.button {:on-click (fn [] (on-edit-invoice i))} [:span.icon [:i.fa.fa-pencil]]])
|
|
(when (and on-void-invoice (= (:outstanding-balance i) (:total i)))
|
|
[:button.button.is-warning.is-outlined {:on-click (fn [] (on-void-invoice i))} [:span [:span.icon [:i.fa.fa-undo]]]])
|
|
(when (seq checks)
|
|
|
|
[:div.dropdown.is-right {:class (if (= id visible-checks)
|
|
"is-active"
|
|
"")}
|
|
[:div.dropdown-trigger
|
|
[:a.button.badge {:data-badge (str (clojure.core/count checks))
|
|
:aria-haspopup true
|
|
:tab-index "0"
|
|
|
|
:on-blur (delayed-dispatch [::toggle-checks id])
|
|
:on-focus (dispatch-event [::toggle-checks id])
|
|
} "Checks"]]
|
|
[:div.dropdown-menu {:role "menu"}
|
|
[:div.dropdown-content
|
|
(for [check checks]
|
|
(if (:s3-url (:check check))
|
|
^{:key (:id check)}
|
|
[:a.dropdown-item {:href (:s3-url (:check check)) :target "_new"} [:i.fa.fa-money-check] [:span.icon [:i.fa.fa-money]] (str " " (:check-number (:check check)) " (" (gstring/format "$%.2f" (:amount check) ) ")")]
|
|
|
|
^{:key (:id check)}
|
|
[:span.dropdown-item [:i.fa.fa-money-check] [:span.icon [:i.fa.fa-money]] (str " " (:check-number (:check check)) " (" (gstring/format "$%.2f" (:amount check) ) ")")]))]]])
|
|
|
|
]]))]]]))))
|