diff --git a/resources/public/css/main.css b/resources/public/css/main.css index 2f605a11..f3714bac 100644 --- a/resources/public/css/main.css +++ b/resources/public/css/main.css @@ -478,3 +478,12 @@ table.balance-sheet th.total { } } + + +.loader.big { + height: 150px !important; + width: 150px !important; + border: 4px solid #00d1b2; + border-right-color: transparent; + border-top-color: transparent; +} diff --git a/resources/public/index.html b/resources/public/index.html index 6a5b9f1d..e86a1157 100644 --- a/resources/public/index.html +++ b/resources/public/index.html @@ -17,37 +17,7 @@ -
- -
-
-

-
-
- -
+
diff --git a/src/clj/auto_ap/datomic/invoices.clj b/src/clj/auto_ap/datomic/invoices.clj index 6823d955..fae52eeb 100644 --- a/src/clj/auto_ap/datomic/invoices.clj +++ b/src/clj/auto_ap/datomic/invoices.clj @@ -193,3 +193,16 @@ (map <-datomic))) +(defn get-existing-set [] + (d/query + (cond-> {:query {:find ['?vendor '?client '?invoice-number] + :in ['$] + :where '[[?e :invoice/invoice-number ?invoice-number] + [?e :invoice/vendor ?vendor] + [?e :invoice/client ?client] + (not [?e :invoice/status :invoice-status/voided]) + ]} + + :args [(d/db (d/connect uri))]}))) + + diff --git a/src/clj/auto_ap/ledger.clj b/src/clj/auto_ap/ledger.clj index fa8989e0..49b4595f 100644 --- a/src/clj/auto_ap/ledger.clj +++ b/src/clj/auto_ap/ledger.clj @@ -174,7 +174,7 @@ @(d/transact (d/connect uri) (mapv - #(auto-ap.ledger/entity-change->ledger (d/db (d/connect uri)) [:transaction %]) + #(entity-change->ledger (d/db (d/connect uri)) [:transaction %]) (concat (->> (d/query {:query {:find ['?t ] diff --git a/src/clj/auto_ap/routes/invoices.clj b/src/clj/auto_ap/routes/invoices.clj index 2ba45682..fe544515 100644 --- a/src/clj/auto_ap/routes/invoices.clj +++ b/src/clj/auto_ap/routes/invoices.clj @@ -39,8 +39,6 @@ (if-let [id (:db/id (or (clients client-code) (clients client)))] (do - (println "FOUND CLIENT" (or (clients client-code) - (clients client))) (when (not ((set (:client/locations (or (clients client-code) (clients client)))) default-location)) @@ -78,8 +76,8 @@ (defn parse-account-numeric-code [i] (try (when-let [account-numeric-code (:account-numeric-code i)] - (d-accounts/get-account-by-numeric-code-and-sets (Integer/parseInt account-numeric-code) - ["default"])) + (:db/id (d-accounts/get-account-by-numeric-code-and-sets (Integer/parseInt account-numeric-code) + ["default"]))) (catch Exception e (throw (Exception. (str "Could not parse expense account from value '" (:account-numeric-code i) "'") e))))) @@ -481,12 +479,7 @@ {{:keys [excel-rows]} :edn-params user :identity} (assert-admin user) (let [parsed-invoice-rows (parse-invoice-rows excel-rows) - existing-rows (->> (d-invoices/get-graphql {:count Integer/MAX_VALUE}) - first - (filter (fn [i] (not= :invoice-status/voided (:invoice/status i)))) - (map (fn [{:keys [:invoice/vendor :invoice/client :invoice/invoice-number]}] - [(:db/id vendor) (:db/id client) invoice-number])) - set) + existing-rows (set (d-invoices/get-existing-set )) grouped-rows (group-by (fn [i] (cond (seq (:errors i)) diff --git a/src/clj/user.clj b/src/clj/user.clj index 17330052..6acd73d3 100644 --- a/src/clj/user.clj +++ b/src/clj/user.clj @@ -2,6 +2,7 @@ (:require [auto-ap.datomic :refer [uri]] [auto-ap.utils :refer [by]] + #_[auto-ap.ledger :as l] [datomic.api :as d] [clojure.data.csv :as csv] [clj-time.coerce :as c] @@ -300,11 +301,12 @@ ) vec)) -(defn patch-missing-ledger-entries [] +;; TODO uncommenting the two below this makes lein build not work, probably related to the ledger +#_(defn patch-missing-ledger-entries [] @(d/transact (d/connect uri) (mapv - #(auto-ap.ledger/entity-change->ledger (d/db (d/connect uri)) [:transaction %]) + #(l/entity-change->ledger (d/db (d/connect uri)) [:transaction %]) (concat (->> (d/query {:query {:find ['?t ] @@ -317,7 +319,7 @@ -(defn check-for-out-of-date-ledger [?code] +#_(defn check-for-out-of-date-ledger [code] [(d/query {:query {:find ['(count ?e)] :in ['$ '?code] :where ['[?e :transaction/accounts ?ta] @@ -327,11 +329,13 @@ '[?e :transaction/client ?c] '[?c :client/code ?code] ]} - :args [(d/db (d/connect uri)) ?code]}) + :args [(d/db (d/connect uri)) code]}) (d/query {:query {:find ['?t ] :in ['$] :where ['[?t :transaction/date] + '[?t :transaction/client ?c] + '[?c :client/code ?code] '(not [?t :transaction/approval-status :transaction-approval-status/excluded]) '(not-join [?t] [?e :journal-entry/original-entity ?t])]} :args [(d/db (d/connect uri))]}) @@ -339,9 +343,20 @@ (d/query {:query {:find ['?t ] :in ['$] :where ['[?t :transaction/date] + '[?t :transaction/client ?c] + '[?c :client/code ?code] '(not [?t :transaction/approval-status :transaction-approval-status/excluded]) '[?t :transaction/vendor ?v] '[?j :journal-entry/original-entity ?t] '(not [?j :journal-entry/vendor ?v]) #_'(not-join [?t] [?e :journal-entry/original-entity ?t])]} + :args [(d/db (d/connect uri))]}) + + (d/query {:query {:find ['(count ?i) ] + :in ['$] + :where ['[?i :invoice/client ?c] + '(not [?i :invoice/status :invoice-status/voided]) + '[?c :client/code ?code] + '(not-join [?i] [?e :journal-entry/original-entity ?i])]} :args [(d/db (d/connect uri))]})]) + diff --git a/src/cljs/auto_ap/events.cljs b/src/cljs/auto_ap/events.cljs index ac68d5d2..e9d117c0 100644 --- a/src/cljs/auto_ap/events.cljs +++ b/src/cljs/auto_ap/events.cljs @@ -19,7 +19,6 @@ ::initialize-db (fn [{:keys [db]} [_ token]] (let [handler (:handler (bidi/match-route routes/routes (.. js/window -location -pathname)))] - (prn (and token (get (jwt->data token) "user/role"))) (cond (and (not= :login handler) (not token)) {:redirect "/login" @@ -38,6 +37,7 @@ :else {:db (assoc db/default-db :active-page handler + :is-initial-loading? true :last-client-id (.getItem js/localStorage "last-client-id") :query-params (auto-ap.views.utils/query-params) :user token) @@ -84,7 +84,9 @@ [:accounts [:numeric-code :name :location :type :account_set :applicability :id [:client-overrides [:name [:client [:name :id]]]]]]]} :on-success [::received-initial]} - :db (assoc db :user (assoc user :token token))})) + :db (assoc db + :user (assoc user :token token) + :is-initial-loading? true)})) (re-frame/reg-event-db ::received-initial @@ -93,6 +95,7 @@ (-> db (assoc :clients (by :id clients) ) (assoc :vendors (by :id vendors) ) + (assoc :is-initial-loading? false) (assoc :accounts accounts ) (assoc :client (or (when (= 1 (count clients)) (->> clients first :id )) (->> clients diff --git a/src/cljs/auto_ap/subs.cljs b/src/cljs/auto_ap/subs.cljs index 7e8c459b..8a2da605 100644 --- a/src/cljs/auto_ap/subs.cljs +++ b/src/cljs/auto_ap/subs.cljs @@ -150,6 +150,11 @@ (fn [db] (:menu db))) +(re-frame/reg-sub + ::is-initial-loading? + (fn [db] + (:is-initial-loading? db))) + (re-frame/reg-sub ::modal-state (fn [db [_ id status-from]] diff --git a/src/cljs/auto_ap/views/components/invoices/side_bar.cljs b/src/cljs/auto_ap/views/components/invoices/side_bar.cljs index eedaa5b5..88ada957 100644 --- a/src/cljs/auto_ap/views/components/invoices/side_bar.cljs +++ b/src/cljs/auto_ap/views/components/invoices/side_bar.cljs @@ -37,7 +37,8 @@ url-filters {:vendor (when-let [vendor-id (:vendor-id url-filters)] {:id (str vendor-id) :name (get-in vendors-by-id [(str vendor-id) :name] "Loading...")}) - :date-range (:date-range url-filters) + :date-range {:raw (:date-range url-filters) + :settled (:date-range url-filters)} :due-range (:due-range url-filters) :amount-range {:raw {:amount-gte (:amount-gte url-filters) :amount-lte (:amount-lte url-filters)} @@ -60,7 +61,7 @@ (fn [[filters ap ]] {:vendor-id (:id (:vendor filters)) - :date-range (:date-range filters) + :date-range (:settled (:date-range filters)) :due-range (:due-range filters) :amount-gte (:amount-gte (:settled (:amount-range filters))) :amount-lte (:amount-lte (:settled (:amount-range filters))) @@ -114,6 +115,25 @@ :key ::amount-range} :db (assoc-in db [:raw which] value)})) +(re-frame/reg-event-fx + ::date-range-settled + [(re-frame/path [::filters :date-range])] + (fn [{:keys [db]} [_ which value]] + {:db (assoc-in db [:settled which] value) + :dispatch [::filter-changed :date-range [:settled] (assoc (:settled db) which value)]})) + +;; TODO for some reason reloading is borken, and typing will unset stuff, has nothing to do with it being debounced +(re-frame/reg-event-fx + ::date-range-changed + [(re-frame/path [::filters :date-range])] + (fn [{:keys [db]} [_ [which] value]] + (println which value) + {:dispatch-debounce + {:event [::date-range-settled which value] + :time 1000 + :key ::date-range} + :db (assoc-in db [:raw which] value)})) + (defn invoice-number-filter [] [:div.field [:div.control [:input.input {:placeholder "AP-123" @@ -171,8 +191,8 @@ [:p.menu-label "Date Range"] [:div [date-range-filter - {:on-change-event [::filter-changed :date-range] - :value @(re-frame/subscribe [::filter :date-range])}]] + {:on-change-event [::date-range-changed] + :value (:raw @(re-frame/subscribe [::filter :date-range]))}]] [:p.menu-label "Due Range"] [:div diff --git a/src/cljs/auto_ap/views/components/layouts.cljs b/src/cljs/auto_ap/views/components/layouts.cljs index 1fb6229a..86128d69 100644 --- a/src/cljs/auto_ap/views/components/layouts.cljs +++ b/src/cljs/auto_ap/views/components/layouts.cljs @@ -90,71 +90,75 @@ clients (re-frame/subscribe [::subs/clients]) matching-clients @(re-frame/subscribe [::matching-clients]) menu (re-frame/subscribe [::subs/menu]) - client-search @(re-frame/subscribe [::client-search])] + client-search @(re-frame/subscribe [::client-search]) + is-initial-loading @(re-frame/subscribe [::subs/is-initial-loading?])] [:nav {:class "navbar has-shadow is-fixed-top"} [:div {:class "container"} [:div {:class "navbar-brand"} [:a {:class "navbar-item", :href "../"} [:img {:src "/img/logo.png"}]]] [:div.navbar-menu - [:div.navbar-start - [:a.navbar-item {:class [(active-when ap = :index)] - :href (bidi/path-for routes/routes :index)} - "Home" ] - [:a.navbar-item {:class [(active-when ap #{:unpaid-invoices :paid-invoices})] - :href (bidi/path-for routes/routes :unpaid-invoices)} - "Invoices" ] - [:a.navbar-item {:class [(active-when ap = :payments)] - :href (bidi/path-for routes/routes :payments)} - "Payments" ] - [:a.navbar-item {:class [(active-when ap = :transactions)] - :href (bidi/path-for routes/routes :transactions)} - "Transactions" ] - - (when (not= "manager" (:user/role @user)) - [:a.navbar-item {:class [(active-when ap = :ledger)] - :href (bidi/path-for routes/routes :ledger)} - "Ledger" ])] + (when-not is-initial-loading + [:div.navbar-start + [:a.navbar-item {:class [(active-when ap = :index)] + :href (bidi/path-for routes/routes :index)} + "Home" ] + [:a.navbar-item {:class [(active-when ap #{:unpaid-invoices :paid-invoices})] + :href (bidi/path-for routes/routes :unpaid-invoices)} + "Invoices" ] + [:a.navbar-item {:class [(active-when ap = :payments)] + :href (bidi/path-for routes/routes :payments)} + "Payments" ] + [:a.navbar-item {:class [(active-when ap = :transactions)] + :href (bidi/path-for routes/routes :transactions)} + "Transactions" ] + + (when (not= "manager" (:user/role @user)) + [:a.navbar-item {:class [(active-when ap = :ledger)] + :href (bidi/path-for routes/routes :ledger)} + "Ledger" ])]) [:div {:class "navbar-burger burger", :data-target "navMenu"} [:span] [:span] [:span]] - [:div.navbar-end - [:div.navbar-item - [:a.button.is-primary.is-outlined - {:on-click (dispatch-event [::vendor-dialog/started {}])} - [:span.icon [:i.fa.fa-plus] ] [:span "Vendor"]]] - + (when-not is-initial-loading + [:div.navbar-end + [:div.navbar-item + [:a.button.is-primary.is-outlined + {:on-click (dispatch-event [::vendor-dialog/started {}])} + [:span.icon [:i.fa.fa-plus] ] [:span "Vendor"]]] + - (when (> (count @clients) 1) - [navbar-drop-down {:header (str "Client: " (if @client (:name @client) - "All")) - :id ::select-client} - [:div - [:a {:class "navbar-item" - :on-click (fn [] - (re-frame/dispatch [::events/swap-client nil]))} "All" ] - [:hr {:class "navbar-divider"}] - [bind-field - [:input.input.navbar-item {:placeholder "Client name" - :auto-focus true - :field [:value] - :on-key-up (fn [k] - (when (= 13 (.-which k)) - (do - (re-frame/dispatch [::events/swap-client (first matching-clients)]) - (re-frame/dispatch [::events/toggle-menu ::select-client]) - (re-frame/dispatch [::client-search-changed [:value] nil]))) - ) - :event [::client-search-changed] - :subscription client-search}]] - (for [{:keys [name id] :as client} matching-clients] - ^{:key id } + (when (> (count @clients) 1) + [navbar-drop-down {:header (str "Client: " (if @client (:name @client) + "All")) + :id ::select-client} + [:div [:a {:class "navbar-item" :on-click (fn [] - (re-frame/dispatch [::events/swap-client client])) - } name])]])]] - [login-dropdown]]])) + (re-frame/dispatch [::events/swap-client nil]))} "All" ] + [:hr {:class "navbar-divider"}] + [bind-field + [:input.input.navbar-item {:placeholder "Client name" + :auto-focus true + :field [:value] + :on-key-up (fn [k] + (when (= 13 (.-which k)) + (do + (re-frame/dispatch [::events/swap-client (first matching-clients)]) + (re-frame/dispatch [::events/toggle-menu ::select-client]) + (re-frame/dispatch [::client-search-changed [:value] nil]))) + ) + :event [::client-search-changed] + :subscription client-search}]] + (for [{:keys [name id] :as client} matching-clients] + ^{:key id } + [:a {:class "navbar-item" + :on-click (fn [] + (re-frame/dispatch [::events/swap-client client])) + } name])]])])] + (when-not is-initial-loading + [login-dropdown])]])) (defn footer [] @@ -170,7 +174,8 @@ (defn side-bar-layout [{:keys [side-bar main ap bottom right-side-bar]}] (let [ap @(re-frame/subscribe [::subs/active-page]) - client @(re-frame/subscribe [::subs/client])] + client @(re-frame/subscribe [::subs/client]) + is-initial-loading @(re-frame/subscribe [::subs/is-initial-loading?])] [:div [navbar ap] [:div {:class "columns has-shadow", :style {:margin-bottom "0px" :height "calc(100vh - 46px)" } :id "mail-app" } @@ -190,7 +195,8 @@ ] #_[footer] [:div - [vendor-dialog {}] + (when-not is-initial-loading + [vendor-dialog {}]) bottom] [:div#dz-hidden]])) @@ -198,3 +204,11 @@ (defn side-bar [{:keys [on-close]} children] [:div [:a.delete.is-pulled-right {:on-click on-close}] [:div children]]) +(defn loading-layout [] + [side-bar-layout + {:main [:div.has-text-centered.hero.is-fullheight.is-vertically-centered.is-centered + [:div.hero-body + [:div.container + [:div.column.is-4.is-offset-4.has-text-centered + [:div.loader.is-loading.is-active.big.is-centered]]]]]}]) + diff --git a/src/cljs/auto_ap/views/main.cljs b/src/cljs/auto_ap/views/main.cljs index de212b22..41b1c71c 100644 --- a/src/cljs/auto_ap/views/main.cljs +++ b/src/cljs/auto_ap/views/main.cljs @@ -6,7 +6,7 @@ [auto-ap.subs :as subs] [auto-ap.events :as events] [auto-ap.views.utils :refer [active-when active-when= login-url dispatch-event]] - [auto-ap.views.components.layouts :refer [side-bar-layout]] + [auto-ap.views.components.layouts :refer [side-bar-layout loading-layout]] [auto-ap.views.pages.unpaid-invoices :refer [unpaid-invoices-page]] [auto-ap.views.pages.import-invoices :refer [import-invoices-page]] [auto-ap.views.pages.needs-activation :refer [needs-activation-page]] @@ -111,8 +111,44 @@ (defmethod page :admin-excel-import [_] [admin-excel-import-page]) +;; +;; ;;
+;; +;;
+;;
+;;

+;;
+;;
+;; +;;
(defn active-page [] - (let [ap (re-frame/subscribe [::subs/active-page])] - [:div - ^{:key @ap} [page @ap]])) + (let [ap (re-frame/subscribe [::subs/active-page]) + is-loading? @(re-frame/subscribe [::subs/is-initial-loading?])] + (if is-loading? + [loading-layout] + + [:div + ^{:key @ap} [page @ap]]))) diff --git a/src/cljs/auto_ap/views/pages/transactions/side_bar.cljs b/src/cljs/auto_ap/views/pages/transactions/side_bar.cljs index b75f7d8d..9860c055 100644 --- a/src/cljs/auto_ap/views/pages/transactions/side_bar.cljs +++ b/src/cljs/auto_ap/views/pages/transactions/side_bar.cljs @@ -27,8 +27,8 @@ {:vendor-id (:id (:vendor filters)) :date-range (:date-range filters) :bank-account-id (:id (:bank-account filters)) - :amount-gte (:amount-gte (:amount-range filters)) - :amount-lte (:amount-lte (:amount-range filters)) + :amount-gte (:amount-gte (:settled (:amount-range filters))) + :amount-lte (:amount-lte (:settled (:amount-range filters))) :description (:settled (:description filters)) :approval-status (condp = ap :transactions nil @@ -65,6 +65,23 @@ :key ::description} :db (assoc db :raw description)})) +(re-frame/reg-event-fx + ::amount-range-settled + [(re-frame/path [::filters :amount-range])] + (fn [{:keys [db]} [_ which value]] + {:db (assoc-in db [:settled which] value) + :dispatch [::filter-changed :amount-range [:settled] (assoc (:settled db) which value)]})) + +(re-frame/reg-event-fx + ::amount-range-changed + [(re-frame/path [::filters :amount-range])] + (fn [{:keys [db]} [_ [which] value]] + {:dispatch-debounce + {:event [::amount-range-settled which value] + :time 500 + :key ::amount-range} + :db (assoc-in db [:raw which] value)})) + (defn side-bar [] (let [ap @(re-frame/subscribe [::subs/active-page]) user @(re-frame/subscribe [::subs/user])] @@ -119,8 +136,8 @@ [:p.menu-label "Amount"] [:div [number-filter - {:on-change-event [::filter-changed :amount-range] - :value @(re-frame/subscribe [::filter :amount-range])}]] + {:on-change-event [::amount-range-changed] + :value (:raw @(re-frame/subscribe [::filter :amount-range]))}]] [:p.menu-label "Vendor"] [:div diff --git a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs index fd392bc5..0ab55eb0 100644 --- a/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs +++ b/src/cljs/auto_ap/views/pages/unpaid_invoices.cljs @@ -82,7 +82,6 @@ (seq filter-params) (merge filter-params) (seq table-params) (merge table-params))] (when (not= params last-params) - (println "DISPATCHING" params last-params) (re-frame/dispatch [::params-change])) params))) @@ -113,6 +112,7 @@ (re-frame/reg-event-fx ::unmounted (fn [{:keys [db]} _] + (println "UNMOUNTING?") {:db (dissoc db ::invoice-page ::table/table-params ::side-bar/filters ::last-params)})) (re-frame/reg-event-db