graphql used for invoices
This commit is contained in:
@@ -1,20 +1,33 @@
|
||||
(ns auto-ap.db.companies
|
||||
(:require [auto-ap.db.utils :refer [clj->db db->clj get-conn]]
|
||||
(:require [auto-ap.db.utils :refer [clj->db db->clj get-conn query execute!]]
|
||||
[auto-ap.entities.companies :as entity]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.java.jdbc :as j]))
|
||||
[clojure.java.jdbc :as j]
|
||||
[honeysql.core :as sql]
|
||||
[honeysql.helpers :as helpers]))
|
||||
|
||||
(defn parse [x]
|
||||
(db->clj x))
|
||||
(def base-query (sql/build :select :*
|
||||
:from :companies))
|
||||
|
||||
|
||||
(defn get-all []
|
||||
(->> (j/query (get-conn) "SELECT * FROM companies")
|
||||
(map parse)))
|
||||
|
||||
(defn upsert [id data]
|
||||
(j/update! (get-conn) :companies (clj->db data) ["id = ?" (Integer/parseInt id)] )
|
||||
(parse (first (j/query (get-conn) ["SELECT * FROM companies WHERE id = ?" (Integer/parseInt id)]))))
|
||||
(query base-query))
|
||||
|
||||
(defn get-by-id [id]
|
||||
(parse (first (j/query (get-conn) ["SELECT * FROM companies WHERE id = ?" id]))))
|
||||
(first (query (-> base-query
|
||||
(helpers/merge-where [:= :id id])))))
|
||||
(defn upsert [id data]
|
||||
(prn (clj->db (select-keys data entity/all-keys)))
|
||||
(-> (sql/build
|
||||
:update :companies
|
||||
:set (clj->db (select-keys data entity/all-keys ))
|
||||
:where [:= :id (if (int? id)
|
||||
id
|
||||
(Integer/parseInt id))])
|
||||
execute!)
|
||||
(get-by-id (if (int? id)
|
||||
id
|
||||
(Integer/parseInt id))))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,66 +1,56 @@
|
||||
(ns auto-ap.db.invoices
|
||||
(:require [auto-ap.db.utils :refer [clj->db db->clj get-conn]]
|
||||
(:require [auto-ap.db.utils :refer [clj->db db->clj get-conn query] :as utils]
|
||||
[auto-ap.parse :as parse]
|
||||
[auto-ap.db.companies :as companies]
|
||||
[auto-ap.db.vendors :as vendors]
|
||||
[auto-ap.entities.companies :as company]
|
||||
[auto-ap.entities.vendors :as vendor]
|
||||
[clojure.java.jdbc :as j]
|
||||
[clojure.string :as str]))
|
||||
[clojure.string :as str]
|
||||
[honeysql.core :as sql]
|
||||
[honeysql.helpers :as helpers]))
|
||||
|
||||
(defn insert-multi! [rows]
|
||||
(j/insert-multi! (get-conn)
|
||||
:invoices
|
||||
(map clj->db rows)))
|
||||
|
||||
(defn with-relations [results]
|
||||
(let [companies (reduce
|
||||
#(assoc %1 (:id %2) %2)
|
||||
{}
|
||||
(companies/get-all))
|
||||
vendors (reduce
|
||||
#(assoc %1 (:id %2) %2)
|
||||
{}
|
||||
(vendors/get-all))]
|
||||
(println companies vendors)
|
||||
(->> results
|
||||
(map #(assoc % :vendor (vendors (:vendor-id %))))
|
||||
(map #(assoc % :company (companies (:company-id %)))))))
|
||||
(def base-query (sql/build :select :*
|
||||
:from :invoices))
|
||||
|
||||
|
||||
(defn get-all []
|
||||
(->> (j/query (get-conn)
|
||||
(str " SELECT invoices.* "
|
||||
" FROM invoices "))
|
||||
(map db->clj)
|
||||
with-relations
|
||||
))
|
||||
|
||||
(query base-query))
|
||||
|
||||
(defn approve []
|
||||
(map db->clj (j/update! (get-conn) :invoices {:imported true} [] )))
|
||||
(j/update! (get-conn) :invoices {:imported true} [] ))
|
||||
|
||||
(defn reject []
|
||||
(j/delete! (get-conn) :invoices ["imported = false"]))
|
||||
|
||||
(defn get-unpaid [company]
|
||||
(if company
|
||||
(with-relations (map db->clj (j/query (get-conn) ["SELECT * FROM invoices WHERE imported=true AND company_id = ?" (Integer/parseInt company)])))
|
||||
(with-relations (map db->clj (j/query (get-conn) "SELECT * FROM invoices WHERE imported=true")))))
|
||||
(query
|
||||
(if company
|
||||
(-> base-query
|
||||
(helpers/merge-where [:= :imported true])
|
||||
(helpers/merge-where [:= :company-id company]))
|
||||
(-> base-query
|
||||
(helpers/merge-where [:= :imported true])))))
|
||||
|
||||
(defn get-pending [company]
|
||||
(if company
|
||||
(with-relations (map db->clj (j/query (get-conn) ["SELECT * FROM invoices WHERE (imported=false or imported is null) AND company_id = ?" (Integer/parseInt company)])))
|
||||
(with-relations (map db->clj (j/query (get-conn) "SELECT * FROM invoices WHERE imported=false or imported is null")))))
|
||||
(query
|
||||
(if company
|
||||
(-> base-query
|
||||
(helpers/merge-where [:= :imported false])
|
||||
(helpers/merge-where [:= :company-id company]))
|
||||
(-> base-query
|
||||
(helpers/merge-where [:= :imported false])))))
|
||||
|
||||
(defn query [params]
|
||||
(let [ks (keys params)
|
||||
sql (str " SELECT * FROM invoices "
|
||||
(when (seq params)
|
||||
" WHERE ")
|
||||
(str/join " AND " (map (fn [k] (str (name k) " = ?")) ks)))
|
||||
vs (map params ks)]
|
||||
|
||||
(j/query (get-conn) (into [sql] vs))))
|
||||
(defn get-graphql [{:keys [imported company-id]}]
|
||||
(query
|
||||
(cond-> base-query
|
||||
(not (nil? imported)) (helpers/merge-where [:= :imported imported])
|
||||
(not (nil? company-id)) (helpers/merge-where [:= :company-id company-id]))))
|
||||
|
||||
(defn import [parsed-invoices companies vendors]
|
||||
(insert-multi!
|
||||
@@ -71,4 +61,4 @@
|
||||
:vendor-id (:id (first (filter #(= (:code %) vendor-code) vendors)))
|
||||
:imported false
|
||||
:potential-duplicate false)
|
||||
:vendor-code)))))
|
||||
:vendor-code)))))
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
(ns auto-ap.db.utils
|
||||
(ns auto-ap.db.utils
|
||||
(:require [clojure.string :as str]
|
||||
[clojure.edn :as edn]
|
||||
[config.core :refer [env]]))
|
||||
[clojure.java.jdbc :as j]
|
||||
[config.core :refer [env]]
|
||||
[honeysql.core :as sql]))
|
||||
|
||||
(defn snake->kebab [s]
|
||||
(str/replace s #"_" "-"))
|
||||
@@ -52,3 +54,13 @@
|
||||
:user "ap"
|
||||
:password "fifteen-invoices-imported!"}))
|
||||
|
||||
(defn query [q]
|
||||
(let [formatted (sql/format q)]
|
||||
(println "Executing query " q " SQL: " formatted)
|
||||
|
||||
(map db->clj (j/query (get-conn) formatted))))
|
||||
|
||||
(defn execute! [q]
|
||||
(let [formatted (sql/format q)]
|
||||
(println "Executing query " q " SQL: " formatted)
|
||||
(j/execute! (get-conn) formatted)))
|
||||
|
||||
@@ -1,33 +1,46 @@
|
||||
(ns auto-ap.db.vendors
|
||||
(:require [auto-ap.db.utils :refer [clj->db db->clj get-conn]]
|
||||
(:require [auto-ap.db.utils :refer [clj->db db->clj get-conn query execute!]]
|
||||
[auto-ap.entities.vendors :as entities]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.java.jdbc :as j]))
|
||||
[clojure.java.jdbc :as j]
|
||||
[honeysql.core :as sql]
|
||||
[honeysql.helpers :as helpers]
|
||||
[honeysql.format :as f]))
|
||||
|
||||
|
||||
(defn parse [x]
|
||||
(db->clj x))
|
||||
|
||||
(defn unparse [x]
|
||||
(-> x
|
||||
(select-keys entities/all-keys)
|
||||
clj->db))
|
||||
(select-keys entities/all-keys)))
|
||||
|
||||
(def base-query (sql/build :select :*
|
||||
:from :vendors))
|
||||
|
||||
|
||||
(defn get-all []
|
||||
(->> (j/query (get-conn) "SELECT * FROM vendors")
|
||||
(map parse)))
|
||||
(query base-query))
|
||||
|
||||
(defn get-by-id [id]
|
||||
(parse (first (j/query (get-conn) ["SELECT * FROM vendors WHERE id = ?" id]))))
|
||||
(first (query (-> base-query
|
||||
(helpers/merge-where [:= :id id])))))
|
||||
|
||||
(defn upsert [id data]
|
||||
(j/update! (get-conn) :vendors (unparse data) ["id = ?" (Integer/parseInt id)] )
|
||||
(parse (first (j/query (get-conn) ["SELECT * FROM vendors WHERE id = ?" (Integer/parseInt id)]))))
|
||||
(-> (sql/build
|
||||
:update :vendors
|
||||
:set (unparse data)
|
||||
:where [:= :id (if (int? id)
|
||||
id
|
||||
(Integer/parseInt id))])
|
||||
execute!)
|
||||
(get-by-id (if (int? id)
|
||||
id
|
||||
(Integer/parseInt id))))
|
||||
|
||||
(defn insert [data]
|
||||
(parse (first (j/insert! (get-conn)
|
||||
:vendors
|
||||
(unparse data)))))
|
||||
(let [[id] (-> (sql/build :insert-into :vendors
|
||||
:values [(unparse data)])
|
||||
execute!)]
|
||||
(get-by-id id)))
|
||||
|
||||
(defn find-with-reminders []
|
||||
(map parse (j/query (get-conn) ["SELECT * FROM vendors WHERE invoice_reminder_schedule = ?" "Weekly"])))
|
||||
(query (-> base-query
|
||||
(helpers/merge-where [:= :invoice-reminder-schedule "Weekly"]))))
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
(ns auto-ap.graphql
|
||||
(:require
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[com.walmartlabs.lacinia.schema :as schema]
|
||||
[com.walmartlabs.lacinia :refer [execute]]
|
||||
[com.walmartlabs.lacinia.executor :as executor]
|
||||
[com.walmartlabs.lacinia.resolve :as resolve]
|
||||
[auto-ap.db.invoices :as invoices]
|
||||
[auto-ap.db.vendors :as vendors]
|
||||
[auto-ap.db.companies :as companies]
|
||||
[auto-ap.db.utils :as utils]
|
||||
[clojure.walk :as walk])
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[com.walmartlabs.lacinia.schema :as schema]
|
||||
[com.walmartlabs.lacinia :refer [execute]]
|
||||
[com.walmartlabs.lacinia.executor :as executor]
|
||||
[com.walmartlabs.lacinia.resolve :as resolve]
|
||||
[auto-ap.db.invoices :as invoices]
|
||||
[auto-ap.db.vendors :as vendors]
|
||||
[auto-ap.db.companies :as companies]
|
||||
[auto-ap.db.utils :as utils]
|
||||
[clojure.walk :as walk]
|
||||
[clojure.string :as str])
|
||||
(:import
|
||||
(clojure.lang IPersistentMap)))
|
||||
|
||||
@@ -19,14 +20,20 @@
|
||||
{
|
||||
:company
|
||||
{:fields {:id {:type 'Int}
|
||||
:name {:type 'String}}}
|
||||
:name {:type 'String}
|
||||
:email {:type 'String}}}
|
||||
:vendor
|
||||
{:fields {:id {:type 'Int}
|
||||
:name {:type 'String}}}
|
||||
:name {:type 'String}
|
||||
:invoice_reminder_schedule {:type 'String}}}
|
||||
:invoice
|
||||
{:fields {:id {:type 'Int}
|
||||
:total {:type 'String}
|
||||
:invoice_number {:type 'String}
|
||||
:date {:type 'String}
|
||||
:company_id {:type 'Int}
|
||||
:vendor {:type :vendor
|
||||
|
||||
:resolve :get-vendor}
|
||||
:company {:type :company
|
||||
:resolve :get-company}}}}
|
||||
@@ -44,22 +51,65 @@
|
||||
{}
|
||||
x))
|
||||
|
||||
(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))
|
||||
|
||||
(defn get-invoice [context args value]
|
||||
|
||||
(println (<-graphql args))
|
||||
(let [extra-context
|
||||
(cond-> {}
|
||||
(executor/selects-field? context :invoice/vendor) (assoc :vendor-cache (by (vendors/get-all) :id ))
|
||||
(executor/selects-field? context :invoice/company) (assoc :company-cache (by (companies/get-all) :id )))]
|
||||
(resolve/with-context (invoices/query args) extra-context)))
|
||||
(resolve/with-context
|
||||
(map
|
||||
->graphql
|
||||
(invoices/get-graphql (<-graphql args))) extra-context)))
|
||||
|
||||
(defn get-vendor [context args value]
|
||||
(if-let [vendor-cache (:vendor-cache context)]
|
||||
(vendor-cache (:vendor_id value))
|
||||
(vendors/get-by-id (:vendor_id value))))
|
||||
(->graphql
|
||||
(if-let [vendor-cache (:vendor-cache context)]
|
||||
(vendor-cache (:vendor_id value))
|
||||
(vendors/get-by-id (:vendor_id value)))))
|
||||
|
||||
(defn get-company [context args value]
|
||||
(if-let [company-cache (:company-cache context)]
|
||||
(company-cache (:company_id value))
|
||||
(companies/get-by-id (:company_id value))))
|
||||
(->graphql
|
||||
(if-let [company-cache (:company-cache context)]
|
||||
(company-cache (:company_id value))
|
||||
(companies/get-by-id (:company_id value)))))
|
||||
|
||||
(def schema
|
||||
(-> integreat-schema
|
||||
@@ -68,6 +118,8 @@
|
||||
:get-company get-company})
|
||||
schema/compile))
|
||||
|
||||
|
||||
|
||||
(defn simplify
|
||||
"Converts all ordered maps nested within the map into standard hash maps, and
|
||||
sequences into vectors, which makes for easier constants in the tests, and eliminates ordering problems."
|
||||
@@ -81,9 +133,15 @@
|
||||
(seq? node)
|
||||
(vec node)
|
||||
|
||||
(keyword? node)
|
||||
(kebab node)
|
||||
|
||||
:else
|
||||
node))
|
||||
m))
|
||||
|
||||
(defn query [q]
|
||||
(simplify (execute schema q nil nil)))
|
||||
(defn query
|
||||
([q]
|
||||
(simplify (execute schema q nil nil)))
|
||||
([q v]
|
||||
(simplify (execute schema q v nil))))
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[auto-ap.routes.utils :refer [wrap-secure wrap-spec]]
|
||||
[auto-ap.entities.companies :as entity]
|
||||
[auto-ap.graphql :as ql]
|
||||
[clojure.edn :as edn]
|
||||
[compojure.core :refer [GET PUT context defroutes
|
||||
wrap-routes]]))
|
||||
|
||||
@@ -11,7 +12,10 @@
|
||||
(wrap-routes
|
||||
(context "/graphql" []
|
||||
(GET "/" {:keys [query-params]}
|
||||
{:status 200
|
||||
:body (pr-str (ql/query (query-params "query")))
|
||||
:headers {"Content-Type" "application/edn"}}))
|
||||
(let [variables (some-> (query-params "variables")
|
||||
edn/read-string)]
|
||||
(println variables)
|
||||
{:status 200
|
||||
:body (pr-str (ql/query (query-params "query") variables))
|
||||
:headers {"Content-Type" "application/edn"}})))
|
||||
wrap-secure))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require [auto-ap.db.companies :as companies]
|
||||
[auto-ap.db.vendors :as vendors]
|
||||
[auto-ap.db.invoices :as invoices]
|
||||
[auto-ap.db.utils :refer [query]]
|
||||
[auto-ap.parse :as parse]
|
||||
[auto-ap.routes.utils :refer [wrap-secure]]
|
||||
[compojure.core :refer [GET POST context defroutes
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
#(not (str/blank? %))))
|
||||
|
||||
(s/def ::name ::required-identifier)
|
||||
(s/def ::data map?)
|
||||
|
||||
(s/def ::email (s/nilable (s/and string? (s/or :is-email #(re-matches email-regex %)
|
||||
:is-empty #(= % "")))))
|
||||
|
||||
(s/def ::company (s/keys :req-un [::name]
|
||||
:opt-un [::email
|
||||
::data
|
||||
::id]))
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
[cljs-time.coerce :as c]
|
||||
[cljs-time.core :as time]
|
||||
[cljs.core.async :refer [<!]]
|
||||
[clojure.string :as str]
|
||||
[clojure.walk :as walk]
|
||||
[venia.core :as v]
|
||||
[auto-ap.history :as p]
|
||||
[pushy.core :as pushy]))
|
||||
|
||||
@@ -54,3 +57,50 @@
|
||||
(dates->date-times)
|
||||
(conj on-success)
|
||||
(re-frame/dispatch)))))))
|
||||
|
||||
(defn kebab->snake [s]
|
||||
(str/replace s #"-" "_"))
|
||||
|
||||
(defn snake [x]
|
||||
(if (namespace x)
|
||||
(keyword (namespace x) (kebab->snake (name x)))
|
||||
(keyword (kebab->snake (name x)))))
|
||||
|
||||
(defn ->graphql [m]
|
||||
(walk/postwalk
|
||||
(fn [node]
|
||||
(cond
|
||||
|
||||
(keyword? node)
|
||||
(snake node)
|
||||
|
||||
:else
|
||||
node))
|
||||
m))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:graphql
|
||||
(fn [{:keys [query on-success on-error token variables query-obj]}]
|
||||
(go
|
||||
(let [headers (if token
|
||||
{"Authorization" (str "Token " token)}
|
||||
{})
|
||||
query (or query (v/graphql-query (->graphql query-obj)))
|
||||
response (<! (http/request {:method :get
|
||||
:headers headers
|
||||
:url (str "/api/graphql?query=" (js/encodeURIComponent query)
|
||||
"&variables=" (pr-str (or variables {})))}))]
|
||||
(if (>= (:status response) 400)
|
||||
(when on-error
|
||||
(->> response
|
||||
:body
|
||||
:data
|
||||
(dates->date-times)
|
||||
(conj on-error)
|
||||
(re-frame/dispatch)))
|
||||
(->> response
|
||||
:body
|
||||
:data
|
||||
(dates->date-times)
|
||||
(conj on-success)
|
||||
(re-frame/dispatch)))))))
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[auto-ap.subs :as subs]
|
||||
[auto-ap.routes :as routes]
|
||||
[auto-ap.effects :as effects]
|
||||
[venia.core :as v]
|
||||
[bidi.bidi :as bidi]))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
@@ -62,7 +63,7 @@
|
||||
(re-frame/reg-event-db
|
||||
::imported-invoices
|
||||
(fn [db [_ new-invoices]]
|
||||
(assoc-in db [:invoices] new-invoices)))
|
||||
(assoc-in db [:invoices :pending] new-invoices)))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::approve-invoices
|
||||
@@ -79,23 +80,22 @@
|
||||
::view-pending-invoices
|
||||
(fn [cofx []]
|
||||
{:db (assoc-in (:db cofx) [:status :loading] true)
|
||||
:http {:method :get
|
||||
:token (-> cofx :db :user)
|
||||
:uri (str "/api/invoices/pending"
|
||||
(when-let [company-id (:id @(re-frame/subscribe [::subs/company]))]
|
||||
(str "?company=" company-id)))
|
||||
:on-success [::received-invoices :pending]}}))
|
||||
:graphql {:token (-> cofx :db :user)
|
||||
:query-obj {:venia/queries [[:invoice
|
||||
{:imported false :company_id (:id @(re-frame/subscribe [::subs/company]))}
|
||||
[:id :total :invoice-number :date [:vendor [:name :id]] [:company [:name :id]]]]]}
|
||||
|
||||
:on-success [::received-invoices :pending]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::view-unpaid-invoices
|
||||
(fn [cofx []]
|
||||
{:db (assoc-in (:db cofx) [:status :loading] true)
|
||||
:http {:method :get
|
||||
:token (-> cofx :db :user)
|
||||
:uri (str "/api/invoices/unpaid"
|
||||
(when-let [company-id (:id @(re-frame/subscribe [::subs/company]))]
|
||||
(str "?company=" company-id)))
|
||||
:on-success [::received-invoices :unpaid]}}))
|
||||
:graphql {:token (-> cofx :db :user)
|
||||
:query-obj {:venia/queries [[:invoice
|
||||
{:imported true :company_id (:id @(re-frame/subscribe [::subs/company]))}
|
||||
[:id :total :invoice-number :date [:vendor [:name :id]] [:company [:name :id]]]]]}
|
||||
:on-success [::received-invoices :unpaid]}}))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::reject-invoices
|
||||
@@ -133,11 +133,13 @@
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::received-invoices
|
||||
(fn [db [_ type new-invoices]]
|
||||
(-> db
|
||||
(assoc-in [:invoices type] new-invoices)
|
||||
(assoc-in [:status :loading] false)
|
||||
)))
|
||||
(fn [db [_ type result]]
|
||||
(let [new-invoices (if (:invoice result)
|
||||
(:invoice result)
|
||||
result)]
|
||||
(-> db
|
||||
(assoc-in [:invoices type] new-invoices)
|
||||
(assoc-in [:status :loading] false)))))
|
||||
|
||||
(re-frame/reg-event-db
|
||||
::change-form-state
|
||||
|
||||
@@ -58,11 +58,11 @@
|
||||
[:th "Date"]
|
||||
[:th "Amount"]
|
||||
[:th]]]
|
||||
[:tbody (for [{:keys [vendor vendor-id potential-duplicate company-id customer-identifier invoice-number date total id] :as i} @invoices]
|
||||
^{:key (str company-id "-" invoice-number "-" date "-" total "-" id)}
|
||||
[:tbody (for [{:keys [vendor vendor-id potential-duplicate company customer-identifier invoice-number date total id] :as i} @invoices]
|
||||
^{:key id}
|
||||
[:tr
|
||||
[:td (:name (:vendor i))]
|
||||
(if company-id
|
||||
(if company
|
||||
[:td (:name (:company i))]
|
||||
[:td [:i.icon.fa.fa-warning {:title "potential duplicate"}]
|
||||
(str "'" customer-identifier "' doesn't match any known company")])
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
[:th "Invoice #"]
|
||||
[:th "Date"]
|
||||
[:th "Amount"]]]
|
||||
[:tbody (for [{:keys [company vendor invoice-number date total id] :as i} @invoices]
|
||||
^{:key (str (:id company) "-" invoice-number "-" date "-" total "-" id)}
|
||||
[:tbody (for [{:keys [company invoice-number date total id vendor] :as i} @invoices]
|
||||
^{:key (str company "-" invoice-number "-" date "-" total "-" id)}
|
||||
[:tr
|
||||
[:td (:name vendor)]
|
||||
[:td (:name company)]
|
||||
|
||||
Reference in New Issue
Block a user