a lot of progress on typeaheads, etc.
This commit is contained in:
@@ -126,15 +126,17 @@
|
||||
(assoc (base-graphql args) :select [:%count.*])))))
|
||||
|
||||
(defn import [parsed-invoices companies vendors]
|
||||
(insert-multi!
|
||||
(for [{:keys [total date invoice-number customer-identifier vendor-code] :as row} parsed-invoices]
|
||||
(do
|
||||
(dissoc (assoc row
|
||||
:company-id (:id (parse/best-match companies customer-identifier))
|
||||
:vendor-id (:id (first (filter #(= (:code %) vendor-code) vendors)))
|
||||
:imported false
|
||||
:potential-duplicate false)
|
||||
:vendor-code)))))
|
||||
(->> (insert-multi!
|
||||
(for [{:keys [total date invoice-number customer-identifier vendor-code] :as row} parsed-invoices]
|
||||
(do
|
||||
(dissoc (assoc row
|
||||
:company-id (:id (parse/best-match companies customer-identifier))
|
||||
:vendor-id (:id (first (filter #(= (:code %) vendor-code) vendors)))
|
||||
:imported false
|
||||
:potential-duplicate false)
|
||||
:vendor-code))))
|
||||
|
||||
(map db->clj)))
|
||||
|
||||
(defn apply-payment [invoice-id amount]
|
||||
(j/db-do-prepared (get-conn)
|
||||
|
||||
@@ -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.invoices :as gq-invoices]
|
||||
[auto-ap.db.reminders :as reminders]
|
||||
[auto-ap.db.invoices-checks :as invoices-checks]
|
||||
[auto-ap.db.utils :as utils]
|
||||
@@ -141,7 +142,14 @@
|
||||
:name {:type 'String}
|
||||
:role {:type 'String}
|
||||
:companies {:type '(list Int)}}}
|
||||
}
|
||||
|
||||
:add_invoice
|
||||
{:fields {:id {:type 'Int}
|
||||
:invoice_number {:type 'String}
|
||||
:date {:type 'String}
|
||||
:company_id {:type 'Int}
|
||||
:vendor_id {:type 'Int}
|
||||
:total {:type 'Float}}}}
|
||||
|
||||
:mutations
|
||||
{:print_checks {:type :check_result
|
||||
@@ -151,7 +159,11 @@
|
||||
:resolve :mutation/print-checks}
|
||||
:edit_user {:type :user
|
||||
:args {:edit_user {:type :edit_user}}
|
||||
:resolve :mutation/edit-user}}})
|
||||
:resolve :mutation/edit-user}
|
||||
|
||||
:add_invoice {:type :invoice
|
||||
:args {:invoice {:type :add_invoice}}
|
||||
:resolve :mutation/add-invoice}}})
|
||||
|
||||
|
||||
|
||||
@@ -281,10 +293,7 @@
|
||||
(:company_id args)
|
||||
(:bank_account_id args))))
|
||||
|
||||
(defn edit-user [context args value]
|
||||
(Thread/sleep 1000)
|
||||
(->graphql
|
||||
(gq-users/edit-user (:edit_user args))))
|
||||
|
||||
|
||||
(def schema
|
||||
(-> integreat-schema
|
||||
@@ -298,7 +307,8 @@
|
||||
:get-user get-user
|
||||
:get-user-companies get-user-companies
|
||||
:mutation/print-checks print-checks
|
||||
:mutation/edit-user edit-user
|
||||
:mutation/edit-user gq-users/edit-user
|
||||
:mutation/add-invoice gq-invoices/add-invoice
|
||||
:get-vendor get-vendor})
|
||||
schema/compile))
|
||||
|
||||
|
||||
17
src/clj/auto_ap/graphql/invoices.clj
Normal file
17
src/clj/auto_ap/graphql/invoices.clj
Normal file
@@ -0,0 +1,17 @@
|
||||
(ns auto-ap.graphql.invoices
|
||||
(:require [auto-ap.graphql.utils :refer [->graphql]]
|
||||
[auto-ap.db.invoices :as invoices]
|
||||
[auto-ap.time :refer [parse normal-date]]))
|
||||
|
||||
(defn add-invoice [context {{:keys [total invoice_number company_id vendor_id date] :as in} :invoice} value]
|
||||
|
||||
(-> (invoices/insert-multi! [{:invoice-number invoice_number
|
||||
:company-id company_id
|
||||
:vendor-id vendor_id
|
||||
:total total
|
||||
:outstanding-balance total
|
||||
:status "unpaid"
|
||||
:imported true
|
||||
:date (parse date normal-date)}])
|
||||
(first)
|
||||
(->graphql)))
|
||||
@@ -1,8 +1,9 @@
|
||||
(ns auto-ap.graphql.users
|
||||
(:require [auto-ap.db.users :as users]))
|
||||
|
||||
(defn edit-user [user]
|
||||
(users/update! user)
|
||||
(users/get-by-id (:id user)))
|
||||
(:require [auto-ap.db.users :as users]
|
||||
[auto-ap.graphql.utils :refer [->graphql]]))
|
||||
|
||||
(defn edit-user [context args value]
|
||||
(users/update! (:edit_user args))
|
||||
(->graphql
|
||||
(users/get-by-id (:edit_user args))))
|
||||
|
||||
|
||||
40
src/clj/auto_ap/graphql/utils.clj
Normal file
40
src/clj/auto_ap/graphql/utils.clj
Normal file
@@ -0,0 +1,40 @@
|
||||
(ns auto-ap.graphql.utils
|
||||
(:require [clojure.string :as str]
|
||||
[clojure.walk :as walk]))
|
||||
|
||||
|
||||
(defn snake->kebab [s]
|
||||
(str/replace s #"_" "-"))
|
||||
|
||||
(defn kebab [x]
|
||||
(keyword (snake->kebab (name x))))
|
||||
|
||||
(defn kebab->snake [s]
|
||||
(str/replace s #"-" "_"))
|
||||
|
||||
(defn snake [x]
|
||||
(keyword (kebab->snake (name x))))
|
||||
|
||||
(defn ->graphql [m]
|
||||
(walk/postwalk
|
||||
(fn [node]
|
||||
(cond
|
||||
|
||||
(keyword? node)
|
||||
(snake node)
|
||||
|
||||
:else
|
||||
node))
|
||||
m))
|
||||
|
||||
(defn <-graphql [m]
|
||||
(walk/postwalk
|
||||
(fn [node]
|
||||
(cond
|
||||
|
||||
(keyword? node)
|
||||
(kebab node)
|
||||
|
||||
:else
|
||||
node))
|
||||
m))
|
||||
@@ -79,11 +79,7 @@
|
||||
{:status 200
|
||||
:body (pr-str (invoices/get-pending (query-params "company")))
|
||||
:headers {"Content-Type" "application/edn"}})
|
||||
(POST "/" {:keys [edn-params]}
|
||||
(invoices/insert-multi! (:rows edn-params))
|
||||
{:status 200
|
||||
:body (pr-str (invoices/get-all))
|
||||
:headers {"Content-Type" "application/edn"}})
|
||||
|
||||
(POST "/approve" {:keys [query-params]}
|
||||
(invoices/approve)
|
||||
{:status 200
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
(ns auto-ap.time
|
||||
(:require [clj-time.core :as time]))
|
||||
(:require [clj-time.core :as time]
|
||||
[clj-time.format :as f]))
|
||||
|
||||
(defn local-now []
|
||||
(time/to-time-zone (time/now) (time/time-zone-for-id "America/Los_Angeles")))
|
||||
|
||||
(def normal-date "MM/dd/yyyy")
|
||||
|
||||
(defn parse [v format]
|
||||
(time/from-time-zone (f/parse (f/formatter format) v)
|
||||
(time/time-zone-for-id "America/Los_Angeles")))
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
(re-frame/reg-sub
|
||||
::modal-state
|
||||
(fn [db [_ id]]
|
||||
(println "ID" id)
|
||||
(get (:modal-state db) id)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
|
||||
63
src/cljs/auto_ap/views/components/typeahead.cljs
Normal file
63
src/cljs/auto_ap/views/components/typeahead.cljs
Normal file
@@ -0,0 +1,63 @@
|
||||
(ns auto-ap.views.components.typeahead
|
||||
(:require [reagent.core :as r]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn typeahead [{:keys [matches on-change field value]}]
|
||||
(let [text (r/atom (or (second (first (filter #(= (first %) value) matches))) ""))
|
||||
highlighted (r/atom 0)
|
||||
selected (r/atom (first (first (filter #(= (first %) value) matches))))
|
||||
select (fn [[id t]]
|
||||
(reset! selected id)
|
||||
(reset! text t)
|
||||
(println [id t])
|
||||
(when on-change
|
||||
(on-change id)))]
|
||||
(fn [{:keys [matches on-change field value]}]
|
||||
(let [valid-matches (take 5 (for [[[id t :as match] i] (map vector matches (range))
|
||||
:when (str/includes? (.toLowerCase t) (.toLowerCase @text))]
|
||||
match))]
|
||||
[:div.typeahead
|
||||
(if @selected
|
||||
[:div.input
|
||||
[:div.control
|
||||
[:div.tags.has-addons
|
||||
[:span.tag @text]
|
||||
[:a.tag.is-delete {:on-click (fn [] (select [nil ""]))}]]]]
|
||||
|
||||
[:input.input {:type "text"
|
||||
:field [:vendor]
|
||||
:value @text
|
||||
:on-blur (fn [e]
|
||||
(cond @selected
|
||||
nil
|
||||
|
||||
(#{"" nil} @text)
|
||||
nil
|
||||
|
||||
(seq valid-matches)
|
||||
(do (select (first valid-matches))
|
||||
true)
|
||||
|
||||
:else
|
||||
(do (select [nil ""])
|
||||
true)))
|
||||
:on-key-up (fn [e]
|
||||
(if (= 13 (.-keyCode e))
|
||||
(do
|
||||
(select (first valid-matches))
|
||||
false)
|
||||
true))
|
||||
:on-change (fn [e]
|
||||
(reset! highlighted (ffirst valid-matches))
|
||||
(select [nil (.. e -target -value)]))}
|
||||
])
|
||||
(when (and (seq @text)
|
||||
(not @selected)
|
||||
(seq valid-matches))
|
||||
[:div.typeahead-menu
|
||||
[:ul
|
||||
(for [[id t :as match] valid-matches]
|
||||
|
||||
[:li.typeahead-suggestion {:class (if (= id @highlighted)
|
||||
"typeahead-highlighted")
|
||||
:on-mouse-down #(do (println "MATCH" match) (select match))} t])]])]))))
|
||||
@@ -9,6 +9,7 @@
|
||||
[auto-ap.views.pages.check :as check]
|
||||
[auto-ap.views.components.invoice-table :refer [invoice-table] :as invoice-table]
|
||||
[auto-ap.views.components.modal :refer [modal action-modal]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead]]
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.events :as events]))
|
||||
|
||||
@@ -190,7 +191,29 @@
|
||||
(re-frame/reg-event-fx
|
||||
::create-invoice
|
||||
(fn [{:keys [db]} _]
|
||||
{}))
|
||||
{:graphql
|
||||
{:token (-> db :user)
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
:operation/name "AddInvoice"}
|
||||
|
||||
:venia/queries [{:query/data [:add-invoice
|
||||
{:invoice @(re-frame/subscribe [::new-invoice])}
|
||||
[:id :total :outstanding-balance :date :invoice-number
|
||||
[:company [:id :name]]
|
||||
[:vendor [:id :name]]
|
||||
]]}]}
|
||||
:on-success [::invoice-created]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::invoice-created
|
||||
(fn [{:keys [db]} [_ result]]
|
||||
{:dispatch [::events/modal-completed ::new-invoice]
|
||||
:db (-> db
|
||||
(update-in [::invoice-page :invoices]
|
||||
(fn [is]
|
||||
(into [(:add-invoice result)]
|
||||
is)))
|
||||
(dissoc ::new-invoice))}))
|
||||
|
||||
(defn print-checks-modal []
|
||||
(let [{:keys [checked]} @(re-frame/subscribe [::invoice-page])
|
||||
@@ -240,55 +263,7 @@
|
||||
:max outstanding-balance
|
||||
:step "0.01"}]]]]]])]]])))
|
||||
|
||||
(defn typeahead [{:keys [matches on-change field value]}]
|
||||
(let [text (r/atom (or (second (first (filter #(= (first %) value) matches))) ""))
|
||||
highlighted (r/atom 0)
|
||||
selected (r/atom (first (first (filter #(= (first %) value) matches))))
|
||||
select (fn [[id t]]
|
||||
(reset! selected id)
|
||||
(reset! text t)
|
||||
(println [id t])
|
||||
(when on-change
|
||||
(on-change id)))]
|
||||
(fn [{:keys [matches on-change field value]}]
|
||||
(let [valid-matches (take 5 (for [[[id t :as match] i] (map vector matches (range))
|
||||
:when (str/includes? (.toLowerCase t) (.toLowerCase @text))]
|
||||
match))]
|
||||
[:div.typeahead
|
||||
[:input.input {:type "text"
|
||||
:field [:vendor]
|
||||
:value @text
|
||||
:on-blur (fn [e]
|
||||
(cond @selected
|
||||
nil
|
||||
|
||||
(seq valid-matches)
|
||||
(do (select (first valid-matches))
|
||||
true)
|
||||
|
||||
:else
|
||||
(do (select [nil ""])
|
||||
true))
|
||||
)
|
||||
:on-key-up (fn [e]
|
||||
(if (= 13 (.-keyCode e))
|
||||
(do
|
||||
(select (first valid-matches))
|
||||
false)
|
||||
true))
|
||||
:on-change (fn [e]
|
||||
(reset! highlighted (ffirst valid-matches))
|
||||
(select [nil (.. e -target -value)]))}]
|
||||
(when (and (seq @text)
|
||||
(not @selected)
|
||||
(seq valid-matches))
|
||||
[:div.typeahead-menu
|
||||
[:ul
|
||||
(for [[id t :as match] valid-matches]
|
||||
|
||||
[:li.typeahead-suggestion {:class (if (= id @highlighted)
|
||||
"typeahead-highlighted")
|
||||
:on-mouse-down #(do (println "MATCH" match) (select match))} t])]])]))))
|
||||
|
||||
(defn new-invoice-modal []
|
||||
(let [data @(re-frame/subscribe [::new-invoice])
|
||||
|
||||
Reference in New Issue
Block a user