From 970a27da56377583ef398c61ae9a0115c8f7e768 Mon Sep 17 00:00:00 2001 From: Bryce Covert Date: Thu, 7 Jun 2018 15:17:07 -0700 Subject: [PATCH] making it possible to see a list of checks --- src/clj/auto_ap/db/checks.clj | 33 ++++++ src/clj/auto_ap/graphql.clj | 26 ++++- src/clj/auto_ap/graphql/checks.clj | 44 +++++++ src/cljs/auto_ap/routes.cljs | 2 +- src/cljs/auto_ap/views/main.cljs | 8 +- src/cljs/auto_ap/views/pages.cljs | 4 + src/cljs/auto_ap/views/pages/checks.cljs | 142 +++++++++++++++++++++++ 7 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 src/clj/auto_ap/graphql/checks.clj create mode 100644 src/cljs/auto_ap/views/pages/checks.cljs diff --git a/src/clj/auto_ap/db/checks.clj b/src/clj/auto_ap/db/checks.clj index b341a6de..1c07acf3 100644 --- a/src/clj/auto_ap/db/checks.clj +++ b/src/clj/auto_ap/db/checks.clj @@ -49,3 +49,36 @@ (map clj->db))) (map db->clj) (map data->fields))) + +#_(defn add-sort-by [q sort-by asc] + (let [sort-by-key (keyword sort-by)] + (cond (all-keys sort-by-key) + (helpers/merge-order-by q [sort-by-key (when-not asc :desc)]) + + (= :vendor sort-by-key) + (-> q + (helpers/merge-left-join [:vendors :v] [:= :v.id :invoices.vendor-id] ) + (helpers/merge-order-by [:v.name (when-not asc :desc)])) + + (= :company sort-by-key) + (-> q + (helpers/merge-left-join [:companies :c] [:= :c.id :invoices.company-id] ) + (helpers/merge-order-by [:c.name (when-not asc :desc)])) + + :else + q))) + +(defn base-graphql [{:keys [company-id]}] + (cond-> base-query + (not (nil? company-id)) (helpers/merge-where [:= :company-id company-id]))) + +(defn get-graphql [{:keys [start sort-by asc] :as args}] + (query + (cond-> (base-graphql args) + #_#_(not (nil? sort-by) ) (add-sort-by sort-by asc) + true (assoc :limit 20) + start (assoc :offset start)))) + +(defn count-graphql [args] + (:count (first (query + (assoc (base-graphql args) :select [:%count.*]))))) diff --git a/src/clj/auto_ap/graphql.clj b/src/clj/auto_ap/graphql.clj index a542e1bd..d63cf3ea 100644 --- a/src/clj/auto_ap/graphql.clj +++ b/src/clj/auto_ap/graphql.clj @@ -13,6 +13,7 @@ [auto-ap.db.checks :as checks] [auto-ap.routes.checks :as rchecks] [auto-ap.graphql.users :as gq-users] + [auto-ap.graphql.checks :as gq-checks] [auto-ap.graphql.expense-accounts :as expense-accounts] [auto-ap.graphql.invoices :as gq-invoices] [auto-ap.db.reminders :as reminders] @@ -54,11 +55,17 @@ :scheduled {:type 'String} :sent {:type 'String} :vendor {:type :vendor - :resolve :get-vendor-for-invoice}} + :resolve :get-vendor-for-invoice} + } } :check {:fields {:id {:type 'Int} :amount {:type 'String} + :vendor {:type :vendor + :resolve :get-vendor-for-check} + :company {:type :company + :resolve :get-company-for-check} + :date {:type 'String} :s3_url {:type 'String} :check_number {:type 'Int}}} @@ -113,6 +120,12 @@ :start {:type 'Int} :end {:type 'Int}}} + :check_page {:fields {:checks {:type '(list :check)} + :count {:type 'Int} + :total {:type 'Int} + :start {:type 'Int} + :end {:type 'Int}}} + :reminder_page {:fields {:reminders {:type '(list :reminder)} :count {:type 'Int} :total {:type 'Int} @@ -136,6 +149,14 @@ :asc {:type 'Boolean}} :resolve :get-invoice-page} + + :check_page {:type '(list :check_page) + :args {:company_id {:type 'Int} + :start {:type 'Int} + :sort_by {:type 'String} + :asc {:type 'Boolean}} + + :resolve :get-check-page} :reminder_page {:type '(list :reminder_page) :args {:start {:type 'Int} :sort_by {:type 'String} @@ -329,8 +350,11 @@ (def schema (-> integreat-schema (attach-resolvers {:get-invoice-page get-invoice-page + :get-check-page gq-checks/get-check-page :get-reminder-page get-reminder-page :get-vendor-for-invoice get-vendor-for-invoice + :get-vendor-for-check gq-checks/get-vendor-for-check + :get-company-for-check gq-checks/get-company-for-check :get-company-for-invoice get-company-for-invoice :get-invoices-checks get-invoices-checks :get-check-by-id get-check-by-id diff --git a/src/clj/auto_ap/graphql/checks.clj b/src/clj/auto_ap/graphql/checks.clj new file mode 100644 index 00000000..77278caa --- /dev/null +++ b/src/clj/auto_ap/graphql/checks.clj @@ -0,0 +1,44 @@ +(ns auto-ap.graphql.checks + (:require [auto-ap.graphql.utils :refer [->graphql <-graphql]] + + [com.walmartlabs.lacinia :refer [execute]] + [com.walmartlabs.lacinia.executor :as executor] + [com.walmartlabs.lacinia.resolve :as resolve] + [auto-ap.db.checks :as checks] + [auto-ap.db.vendors :as vendors] + [auto-ap.utils :refer [by]] + [auto-ap.db.companies :as companies] + [auto-ap.time :refer [parse normal-date]])) + +(defn get-vendor-for-check [context args value] + (->graphql + (if-let [vendor-cache (:vendor-cache context)] + (vendor-cache (:vendor_id value)) + (vendors/get-by-id (:vendor_id value))))) + +(defn get-company-for-check [context args value] + (->graphql + (if-let [company-cache (:company-cache context)] + (company-cache (:company_id value)) + (companies/get-by-id (:company_id value))))) + +(defn get-check-page [context args value] + (let [extra-context + (cond-> {} + (executor/selects-field? context :invoice/vendor) (assoc :vendor-cache (by :id (vendors/get-all))) + (executor/selects-field? context :invoice/company) (assoc :company-cache (by :id (companies/get-all)))) + + checks (map + ->graphql + (checks/get-graphql (<-graphql args))) + checks-count (checks/count-graphql (<-graphql args))] + (resolve/with-context + [{:checks checks + :total checks-count + :count (count checks) + :start (:start args 0) + :end (+ (:start args 0) (count checks))}] extra-context))) + + + + diff --git a/src/cljs/auto_ap/routes.cljs b/src/cljs/auto_ap/routes.cljs index 647676ba..d12a2c5c 100644 --- a/src/cljs/auto_ap/routes.cljs +++ b/src/cljs/auto_ap/routes.cljs @@ -4,7 +4,7 @@ (def routes ["/" {"" :index "login/" :login "needs-activation/" :needs-activation - "check/" :check + "checks/" :checks "admin/" {"" :admin "companies" :admin-companies "users" :admin-users diff --git a/src/cljs/auto_ap/views/main.cljs b/src/cljs/auto_ap/views/main.cljs index 6f29ecf3..427db083 100644 --- a/src/cljs/auto_ap/views/main.cljs +++ b/src/cljs/auto_ap/views/main.cljs @@ -11,7 +11,7 @@ (defn page->layout [page] ({:login :blank - :check :blank + :checks :left-panel :needs-activation :blank :index :left-panel :invoices :left-panel @@ -188,6 +188,12 @@ [:i {:class "fa fa-envelope-o"}]] [:span {:class "name"} "Paid Invoices"]] ] + [:li.menu-item + [:a {:href (bidi/path-for routes/routes :checks), :class (str "item" (active-when= ap :checks))} + [:span {:class "icon"} + [:i {:class "fa fa-envelope-o"}]] + [:span {:class "name"} "Payments"]]] + [:ul ]]] ] diff --git a/src/cljs/auto_ap/views/pages.cljs b/src/cljs/auto_ap/views/pages.cljs index b6b1af18..36393035 100644 --- a/src/cljs/auto_ap/views/pages.cljs +++ b/src/cljs/auto_ap/views/pages.cljs @@ -14,6 +14,7 @@ [auto-ap.views.pages.admin.vendors :refer [admin-vendors-page]] [auto-ap.views.pages.admin.reminders :refer [admin-reminders-page]] [auto-ap.views.pages.unpaid-invoices :refer [unpaid-invoices-page]] + [auto-ap.views.pages.checks :refer [checks-page]] [auto-ap.views.pages.new-invoice :refer [new-invoice-page]] [auto-ap.views.pages.import-invoices :refer [import-invoices-page]] [auto-ap.views.pages.admin.excel-import :refer [admin-excel-import-page]] @@ -64,6 +65,9 @@ (defmethod active-page :paid-invoices [] [paid-invoices-page]) +(defmethod active-page :checks [] + [checks-page]) + (defmethod active-page :invoices [] [(with-meta (fn [] diff --git a/src/cljs/auto_ap/views/pages/checks.cljs b/src/cljs/auto_ap/views/pages/checks.cljs new file mode 100644 index 00000000..1edafd07 --- /dev/null +++ b/src/cljs/auto_ap/views/pages/checks.cljs @@ -0,0 +1,142 @@ +(ns auto-ap.views.pages.checks + (:require [re-frame.core :as re-frame] + [auto-ap.entities.companies :as company] + [auto-ap.entities.vendors :as vendor] + [reagent.core :as reagent] + [goog.string :as gstring] + [auto-ap.views.components.sorter :refer [sorted-column]] + [auto-ap.views.components.paginator :refer [paginator]] + [auto-ap.events :as events] + [auto-ap.views.utils :refer [dispatch-event date->str ]] + [auto-ap.utils :refer [by]] + [auto-ap.views.pages.check :as check] + [auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table] + [auto-ap.subs :as subs])) + + + + +(re-frame/reg-sub + ::check-page + (fn [db] + (-> db ::check-page))) + +(re-frame/reg-sub + ::params + (fn [db] + (-> db (::params {})))) + +(re-frame/reg-event-fx + ::params-change + (fn [cofx [_ params]] + + {:db (-> (:db cofx) + (assoc-in [:status :loading] true) + (assoc-in [::params] params)) + :graphql {:token (-> cofx :db :user) + :query-obj {:venia/queries [[:check_page + (assoc params :company-id (:id @(re-frame/subscribe [::subs/company]))) + [[:checks [:id :amount :check_number :s3_url :date [:vendor [:name :id]] [:company [:name :id]]]] + :total + :start + :end]]]} + :on-success [::received]}})) + +(re-frame/reg-event-db + ::received + (fn [db [_ data]] + (-> db + (assoc ::check-page (first (:check-page data))) + (assoc-in [:status :loading] false)))) + +(re-frame/reg-event-fx + ::invalidated + (fn [cofx [_ params]] + {:dispatch [::params-change @(re-frame/subscribe [::params])]})) + +(defn check-table [{:keys [id check-page status on-params-change vendors params check-boxes checked on-check-changed expense-event]}] + (let [state (reagent/atom (or @params {})) + opc (fn [p] + (swap! state merge p) + (on-params-change p))] + (fn [{:keys [id check-page status on-params-change vendors checked]}] + (println @check-page) + (let [{:keys [sort-by asc]} @state + {:keys [checks start end count total]} @check-page] + [: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 + + + [sorted-column {:on-sort opc + :style {:width "33%" :cursor "pointer"} + :sort-key "company" + :sort-by sort-by + :asc asc} + "Company"] + [sorted-column {:on-sort opc + :style {:width "33%" :cursor "pointer"} + :sort-key "vendor" + :sort-by sort-by + :asc asc} + "Vendor"] + [sorted-column {:on-sort opc + :style {:width "33%" :cursor "pointer"} + :sort-key "invoice-number" + :sort-by sort-by + :asc asc} + "Check #"] + [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 "total" + :sort-by sort-by + :asc asc} + "Amount"] + + + [:th {:style {:width "10em"}} "" ]]] + [:tbody + (if (:loading @status) + [:tr + [:td {:col-span 5} + [:i.fa.fa-spin.fa-spinner]]] + (for [{:keys [company s3-url checks check-number date amount id vendor] :as i} (:checks @check-page)] + ^{:key id} + [:tr {:class (:class i)} + + [:td (:name company)] + [:td (:name vendor)] + [:td check-number] + [:td (date->str date) ] + [:td (gstring/format "$%.2f" amount )] + [:td [:a.tag {:href s3-url :target "_new"} [:i.fa.fa-money-check] [:span.icon [:i.fa.fa-money]] (str " " check-number " (" (gstring/format "$%.2f" amount ) ")")]] + ]))]]])))) + + +(def checks-page + + (with-meta + (fn [] + (let [current-company @(re-frame/subscribe [::subs/company])] + [:div + [:h1.title "Payments"] + [check-table {:id :checks + :params (re-frame/subscribe [::params]) + :check-page (re-frame/subscribe [::check-page]) + :status (re-frame/subscribe [::subs/status]) + :on-params-change (fn [params] + (re-frame/dispatch [::params-change params]))}]])) + {:component-will-mount #(re-frame/dispatch-sync [::params-change {}]) })) +