Adds ability for users to configure basic ezcater integration.
This commit is contained in:
@@ -38,6 +38,10 @@
|
||||
:square-location/name
|
||||
:square-location/client-location
|
||||
:db/id]}
|
||||
|
||||
{:client/ezcater-locations [{:ezcater-location/caterer [:ezcater-caterer/name :db/id]}
|
||||
:ezcater-location/location
|
||||
:db/id]}
|
||||
{:client/bank-accounts [* {:bank-account/type [*]
|
||||
:bank-account/yodlee-account [:yodlee-account/name :yodlee-account/id :yodlee-account/number]
|
||||
:bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance]
|
||||
@@ -60,11 +64,14 @@
|
||||
|
||||
(->>
|
||||
(d/pull (d/db conn )
|
||||
'[* {:client/bank-accounts [* {:bank-account/type [*]
|
||||
:bank-account/yodlee-account [:yodlee-account/name :yodlee-account/id :yodlee-account/number]
|
||||
'[* {:client/bank-accounts [* {:bank-account/type [*]
|
||||
:bank-account/yodlee-account [:yodlee-account/name :yodlee-account/id :yodlee-account/number]
|
||||
:bank-account/intuit-bank-account [:intuit-bank-account/name :intuit-bank-account/external-id :db/id]
|
||||
:bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance]}]
|
||||
:client/emails [:db/id :email-contact/email :email-contact/description]}
|
||||
:bank-account/plaid-account [:plaid-account/name :db/id :plaid-account/number :plaid-account/balance]}]
|
||||
:client/emails [:db/id :email-contact/email :email-contact/description]}
|
||||
{:client/ezcater-locations [{:ezcater-location/caterer [:ezcater-caterer/name :db/id]}
|
||||
:ezcater-location/location
|
||||
:db/id]}
|
||||
{:yodlee-provider-account/_client [*]}
|
||||
{:plaid-item/_client [*]}]
|
||||
id)
|
||||
|
||||
@@ -37,4 +37,66 @@
|
||||
|
||||
{:db/ident :integration-state/failed}
|
||||
{:db/ident :integration-state/success}
|
||||
{:db/ident :integration-state/unauthorized}]]}})
|
||||
{:db/ident :integration-state/unauthorized}]]}
|
||||
::add-ezcater-base7
|
||||
{:txes [[{:db/ident :ezcater-integration/subscriber-uuid
|
||||
:db/doc "The subscriber uuid"
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity}
|
||||
|
||||
{:db/ident :ezcater-integration/api-key
|
||||
:db/doc "The API key that can be used for requests"
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity}
|
||||
|
||||
{:db/ident :ezcater-integration/subscriber-secret
|
||||
:db/doc "Used to validate events"
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one}
|
||||
{:db/ident :ezcater-integration/integration-status
|
||||
:db/doc "The status for this integration"
|
||||
:db/valueType :db.type/ref
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/isComponent true}
|
||||
|
||||
{:db/ident :ezcater-integration/caterers
|
||||
:db/doc "All caterers for this integration"
|
||||
:db/valueType :db.type/ref
|
||||
:db/cardinality :db.cardinality/many
|
||||
:db/isComponent true}
|
||||
|
||||
{:db/ident :ezcater-caterer/uuid
|
||||
:db/doc "Id of the caterer"
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity}
|
||||
|
||||
{:db/ident :ezcater-caterer/name
|
||||
:db/doc "Name of the caterer"
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one}
|
||||
|
||||
{:db/ident :ezcater-caterer/search-terms
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "a name search for caterer"
|
||||
:db/fulltext true}
|
||||
|
||||
{:db/ident :client/ezcater-locations
|
||||
:db/valueType :db.type/ref
|
||||
:db/cardinality :db.cardinality/many
|
||||
:db/isComponent true}
|
||||
|
||||
{:db/ident :ezcater-location/location
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one}
|
||||
|
||||
{:db/ident :ezcater-location/caterer
|
||||
:db/valueType :db.type/ref
|
||||
:db/cardinality :db.cardinality/one}]
|
||||
[{:ezcater-integration/api-key "bmlrdHNpZ2FyaXNAZ21haWwuY29tOmQwMzQwMjYzOWI2ODQxNmVkMjdmZWYxMWFhZTk3YzU1MDlmNTcyNjYwMDAzOTA5MDE2OGMzODllNDBjNTVkZGE"
|
||||
:ezcater-integration/subscriber-uuid "007d4353-fbb8-4725-9c0a-81bbd565dbe5"
|
||||
:ezcater-integration/subscriber-secret "3dccc547f6c4d9b3cbed15ab81d3748d2a34be7fdb9b8edfdc9abd6c75a821fe"}]]
|
||||
:requires [::add-integration-status3]}})
|
||||
|
||||
62
src/clj/auto_ap/ezcater/core.clj
Normal file
62
src/clj/auto_ap/ezcater/core.clj
Normal file
@@ -0,0 +1,62 @@
|
||||
(ns auto-ap.ezcater.core
|
||||
(:require
|
||||
[auto-ap.datomic :refer [conn]]
|
||||
[datomic.api :as d]
|
||||
[clj-http.client :as client]
|
||||
[venia.core :as v]
|
||||
[clojure.data.json :as json]
|
||||
[clj-time.coerce :as coerce]
|
||||
[clj-time.core :as time]))
|
||||
|
||||
(defn get-caterers [{:ezcater-integration/keys [api-key]}]
|
||||
(-> (client/post "https://api.ezcater.com/graphql/"
|
||||
{:headers {"Authorization" api-key
|
||||
"Content-Type" "application/json"}
|
||||
:body (json/write-str {"query" (v/graphql-query {:venia/queries [{:query/data [:caterers [:name :uuid [:address [:name :street]]]]}]})})
|
||||
:as :json})
|
||||
:body
|
||||
:data
|
||||
:caterers))
|
||||
|
||||
(defn get-integrations []
|
||||
(d/q '[:find [(pull ?i [:ezcater-integration/api-key
|
||||
:db/id
|
||||
:ezcater-integration/integration-status [:db/id]]) ...]
|
||||
:in $
|
||||
:where [?i :ezcater-integration/api-key]]
|
||||
(d/db conn)))
|
||||
|
||||
(defn mark-integration-status [integration integration-status]
|
||||
@(d/transact conn
|
||||
[{:db/id (:db/id integration)
|
||||
:ezcater-integration/integration-status (assoc integration-status
|
||||
:db/id (or (-> integration :ezcater-integration/integration-status :db/id)
|
||||
#db/id [:db.part/user]))}]))
|
||||
|
||||
(defn upsert-caterers
|
||||
([integration]
|
||||
@(d/transact
|
||||
conn
|
||||
(for [caterer (get-caterers integration)]
|
||||
{:db/id (:db/id integration)
|
||||
:ezcater-integration/caterers [{:ezcater-caterer/name (str (:name caterer) " (" (:street (:address caterer)) ")")
|
||||
:ezcater-caterer/search-terms (str (:name caterer) " " (:street (:address caterer)))
|
||||
:ezcater-caterer/uuid (:uuid caterer)}]}))))
|
||||
|
||||
(defn upsert-ezcater
|
||||
([] (upsert-ezcater (get-integrations)))
|
||||
([integrations]
|
||||
(doseq [integration integrations]
|
||||
(mark-integration-status integration {:integration-status/last-attempt (coerce/to-date (time/now))})
|
||||
(try
|
||||
(upsert-caterers integration)
|
||||
(mark-integration-status integration {:integration-status/state :integration-state/success
|
||||
:integration-status/last-updated (coerce/to-date (time/now))})
|
||||
|
||||
(catch Exception e
|
||||
(log/warn e)
|
||||
(mark-integration-status integration {:integration-status/state :integration-state/failed
|
||||
:integration-status/message (.getMessage e)}))))))
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[auto-ap.datomic.users :as d-users]
|
||||
[auto-ap.graphql.accounts :as gq-accounts]
|
||||
[auto-ap.graphql.checks :as gq-checks]
|
||||
[auto-ap.graphql.ezcater :as gq-ezcater]
|
||||
[auto-ap.graphql.clients :as gq-clients]
|
||||
[auto-ap.graphql.expected-deposit :as gq-expected-deposit]
|
||||
[auto-ap.graphql.import-batch :as gq-import-batches]
|
||||
@@ -804,6 +805,7 @@
|
||||
gq-import-batches/attach
|
||||
gq-transactions/attach
|
||||
gq-expected-deposit/attach
|
||||
gq-ezcater/attach
|
||||
gq-invoices/attach
|
||||
gq-clients/attach
|
||||
gq-sales-orders/attach
|
||||
|
||||
@@ -259,7 +259,7 @@
|
||||
:check (str (+ index (:bank-account/check-number bank-account)))
|
||||
:memo memo
|
||||
:date (date->str (local-now))
|
||||
:client (dissoc client :client/bank-accounts :client/square-integration-status :client/locked-until :client/emails :client/square-auth-token :client/square-locations)
|
||||
:client (dissoc client :client/bank-accounts :client/square-integration-status :client/ezcater-locations :client/locked-until :client/emails :client/square-auth-token :client/square-locations)
|
||||
:bank-account (dissoc bank-account :bank-account/start-date :bank-account/integration-status)
|
||||
#_#_:client {:name (:name client)
|
||||
:address (:address client)
|
||||
|
||||
@@ -112,6 +112,14 @@
|
||||
{:db/id (:id sl)
|
||||
:square-location/client-location (:client_location sl)}))
|
||||
(:square_locations edit_client))
|
||||
|
||||
:client/ezcater-locations (map
|
||||
(fn [el]
|
||||
(remove-nils
|
||||
{:db/id (:id el)
|
||||
:ezcater-location/location (:location el)
|
||||
:ezcater-location/caterer (:caterer el)}))
|
||||
(:ezcater_locations edit_client))
|
||||
:client/week-b-credits (:week_b_credits edit_client)
|
||||
:client/location-matches (->> (:location_matches edit_client)
|
||||
(filter (fn [lm] (and (:location lm) (:match lm))))
|
||||
@@ -430,6 +438,11 @@
|
||||
:square_id {:type 'String}
|
||||
:id {:type :id}}}
|
||||
|
||||
:ezcater_location
|
||||
{:fields {:location {:type 'String}
|
||||
:caterer {:type :ezcater_caterer}
|
||||
:id {:type :id}}}
|
||||
|
||||
:email_contact {:fields {:id {:type :id}
|
||||
:email {:type 'String}
|
||||
:description {:type 'String}}}
|
||||
@@ -454,6 +467,7 @@
|
||||
:matches {:type '(list String)}
|
||||
:bank_accounts {:type '(list :bank_account)}
|
||||
:square_locations {:type '(list :square_location)}
|
||||
:ezcater_locations {:type '(list :ezcater_location)}
|
||||
:forecasted_transactions {:type '(list :forecasted_transaction)}
|
||||
:yodlee_provider_accounts {:type '(list :yodlee_provider_account)}
|
||||
:plaid_items {:type '(list :plaid_item)}}}
|
||||
@@ -510,6 +524,10 @@
|
||||
:edit_square_location {:fields {:client_location {:type 'String}
|
||||
:id {:type :id}}}
|
||||
|
||||
:edit_ezcater_location {:fields {:location {:type 'String}
|
||||
:caterer {:type :id}
|
||||
:id {:type :id}}}
|
||||
|
||||
:edit_forecasted_transaction {:fields {:identifier {:type 'String}
|
||||
:id {:type :id}
|
||||
:day_of_month {:type 'Int}
|
||||
@@ -534,6 +552,7 @@
|
||||
:matches {:type '(list String)}
|
||||
:location_matches {:type '(list :edit_location_match)}
|
||||
:square_locations {:type '(list :edit_square_location)}
|
||||
:ezcater_locations {:type '(list :edit_ezcater_location)}
|
||||
:bank_accounts {:type '(list :edit_bank_account)}
|
||||
:forecasted_transactions {:type '(list :edit_forecasted_transaction)}}}
|
||||
|
||||
|
||||
46
src/clj/auto_ap/graphql/ezcater.clj
Normal file
46
src/clj/auto_ap/graphql/ezcater.clj
Normal file
@@ -0,0 +1,46 @@
|
||||
(ns auto-ap.graphql.ezcater
|
||||
(:require
|
||||
[auto-ap.datomic :refer [conn]]
|
||||
[auto-ap.graphql.utils :refer [assert-admin cleanse-query]]
|
||||
[auto-ap.graphql.vendors :refer [partial-match-first]]
|
||||
[com.walmartlabs.lacinia.util :refer [attach-resolvers]]
|
||||
[datomic.api :as d]))
|
||||
|
||||
(defn search [context args _]
|
||||
(assert-admin (:id context))
|
||||
(let [search-query (cleanse-query (:query args))
|
||||
data (d/q '[:find ?n ?i ?s
|
||||
:in $ ?q
|
||||
:where [(fulltext $ :ezcater-caterer/search-terms ?q) [[?i ?n _ ?s]]]]
|
||||
(d/db conn)
|
||||
search-query)]
|
||||
(->> data
|
||||
(sort-by (comp - last))
|
||||
(partial-match-first (:query args))
|
||||
(map (fn [[n i]]
|
||||
{:name n
|
||||
:id i})))))
|
||||
|
||||
|
||||
(def objects
|
||||
{:ezcater_caterer {:fields {:name {:type 'String}
|
||||
:id {:type :id}}}})
|
||||
|
||||
(def queries
|
||||
{:search_ezcater_caterer {:type '(list :search_result)
|
||||
:args {:query {:type 'String}}
|
||||
:resolve :search-ezcater-caterer}})
|
||||
|
||||
(def enums
|
||||
{})
|
||||
|
||||
(def resolvers
|
||||
{:search-ezcater-caterer search})
|
||||
|
||||
(defn attach [schema]
|
||||
(->
|
||||
(merge-with merge schema
|
||||
{:objects objects
|
||||
:queries queries
|
||||
:enums enums})
|
||||
(attach-resolvers resolvers)))
|
||||
@@ -1,22 +1,10 @@
|
||||
(ns auto-ap.plaid.core
|
||||
(:require [auto-ap.datomic :refer [conn remove-nils]]
|
||||
[amazonica.aws.s3 :as s3]
|
||||
[auto-ap.utils :refer [by]]
|
||||
[clj-http.client :as client]
|
||||
[clj-time.coerce :as coerce]
|
||||
[clj-time.core :as time]
|
||||
[clj-time.format :as f]
|
||||
[config.core :refer [env] :as cfg ]
|
||||
[clojure.string :as str]
|
||||
[clojure.data.json :as json]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.tools.logging :as log]
|
||||
[datomic.api :as d]
|
||||
[mount.core :as mount]
|
||||
[unilog.context :as lc]
|
||||
[yang.scheduler :as scheduler]
|
||||
[clojure.core.async :as async]
|
||||
[clojure.core.memoize :as m]))
|
||||
(:require
|
||||
[clj-http.client :as client]
|
||||
[clojure.data.json :as json]
|
||||
[clojure.tools.logging :as log]
|
||||
[config.core :as cfg :refer [env]]
|
||||
[auto-ap.time :as atime]))
|
||||
|
||||
(def base-url (-> env :plaid :base-url))
|
||||
|
||||
@@ -65,8 +53,8 @@
|
||||
:body (json/write-str {"client_id" client-id
|
||||
"secret" secret-key
|
||||
"access_token" access-token
|
||||
"start_date" (auto-ap.time/unparse start auto-ap.time/iso-date)
|
||||
"end_date" (auto-ap.time/unparse end auto-ap.time/iso-date)
|
||||
"start_date" (atime/unparse start atime/iso-date)
|
||||
"end_date" (atime/unparse end atime/iso-date)
|
||||
"options" {"account_ids" [account-id]}})})
|
||||
:body))
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
(defn wrap-csv-response [handler]
|
||||
(fn [request]
|
||||
(let [response (handler request)]
|
||||
(println response)
|
||||
(update response :body #(with-open [w (java.io.StringWriter.)]
|
||||
(csv/write-csv w %)
|
||||
(.toString w))))))
|
||||
|
||||
@@ -491,7 +491,8 @@
|
||||
(doseq [client (apply get-square-clients clients)
|
||||
:when (seq (filter :square-location/client-location (:client/square-locations client)))]
|
||||
(lc/with-context {:client (:client/code client)}
|
||||
(mark-integration-status client {:integration-sttus/last-attempt (coerce/to-date (time/now))})
|
||||
(mark-integration-status client {:integration-status/last-attempt (coerce/to-date (time/now))})
|
||||
|
||||
(try+
|
||||
(upsert-locations client)
|
||||
(upsert client)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
(cond-> [:id :name :signature-file :code :email :matches :week-a-debits :week-a-credits :week-b-debits :week-b-credits :locations :locked-until :square-auth-token
|
||||
[:square-integration-status [:last-updated :last-attempt :message :state :id]]
|
||||
[:square-locations [:square-id :id :name :client-location]]
|
||||
[:ezcater-locations [:id [:caterer [:name :id]] :location]]
|
||||
[:emails [:id :email :description]]
|
||||
[:location-matches [:id :location :match]]
|
||||
[:bank-accounts [:id :start-date :numeric-code :code :number :bank-name :bank-code :check-number :name :routing :type :sort-order :visible :yodlee-account-id
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
[auto-ap.events :as events]
|
||||
[auto-ap.views.components.address :refer [address-field]]
|
||||
[auto-ap.views.components.typeahead :refer [typeahead-v3]]
|
||||
[auto-ap.views.components.typeahead.vendor
|
||||
:refer [search-backed-typeahead]]
|
||||
[auto-ap.views.components.layouts :refer [side-bar]]
|
||||
[auto-ap.views.utils
|
||||
:refer
|
||||
@@ -41,7 +43,7 @@
|
||||
)
|
||||
:ref (fn [i] (reset! button i))} ]])})))
|
||||
|
||||
(defn signature [{:keys [signature-file signature-data on-change]}]
|
||||
(defn signature [_]
|
||||
(let [canvas (atom nil)
|
||||
edit-mode? (r/atom false)
|
||||
w (* 1.5 464)
|
||||
@@ -94,7 +96,7 @@
|
||||
(re-frame/reg-sub
|
||||
::can-submit
|
||||
:<- [::new-client-request]
|
||||
(fn [r _]
|
||||
(fn [_ _]
|
||||
true
|
||||
|
||||
#_(s/valid? ::entity/client r)))
|
||||
@@ -115,6 +117,13 @@
|
||||
:client-location (:client-location x)})
|
||||
(:square-locations new-client-data))
|
||||
|
||||
:ezcater-locations (map
|
||||
(fn [x]
|
||||
{:id (:id x)
|
||||
:caterer (:id (:caterer x))
|
||||
:location (:location x)})
|
||||
(:ezcater-locations new-client-data))
|
||||
|
||||
:locked-until (cond (not (:locked-until new-client-data))
|
||||
nil
|
||||
|
||||
@@ -198,13 +207,12 @@
|
||||
(re-frame/reg-event-fx
|
||||
::save-new-client
|
||||
[(forms/in-form ::form)]
|
||||
(fn [{{new-client-data :data :as new-client-form} :db} _]
|
||||
(fn [_ _]
|
||||
|
||||
(let [new-client-req @(re-frame/subscribe [::new-client-request])
|
||||
user @(re-frame/subscribe [::subs/token])]
|
||||
|
||||
{:db (-> new-client-form)
|
||||
:graphql
|
||||
{:graphql
|
||||
{:token user
|
||||
:owns-state {:single ::form}
|
||||
:query-obj {:venia/operation {:operation/type :mutation
|
||||
@@ -304,8 +312,8 @@
|
||||
[])))
|
||||
|
||||
|
||||
(defn bank-account-card [new-client {:keys [active? new? type visible code name number check-number id sort-order] :as bank-account} first? last?]
|
||||
(let [{:keys [form field raw-field error-notification submit-button ]} client-form]
|
||||
(defn bank-account-card [new-client {:keys [active? new? type visible code name sort-order]} first? last?]
|
||||
(let [{:keys [field raw-field]} client-form]
|
||||
[:div.card {:style {:margin-bottom "1em"}}
|
||||
[:header.card-header
|
||||
[:div.card-header-title {:style {:text-overflow "ellipsis"}}
|
||||
@@ -692,5 +700,27 @@
|
||||
:step "0.01"}]]
|
||||
:disable-remove? true
|
||||
:disable-new? true}])]]
|
||||
|
||||
[:div.field
|
||||
[:label.label "EZCater Locations"]
|
||||
[:div.control
|
||||
(raw-field
|
||||
[multi-field {:type "multi-field"
|
||||
:field :ezcater-locations
|
||||
:template [
|
||||
[search-backed-typeahead {:search-query (fn [i]
|
||||
[:search_ezcater_caterer
|
||||
{:query i}
|
||||
[:name :id]])
|
||||
:entity->text :name
|
||||
:type "typeahead-v3"
|
||||
:field [:caterer]
|
||||
:style {:width "20em"}}]
|
||||
[:input.input {:type "text"
|
||||
:style {:width "4em"}
|
||||
:field [:location]
|
||||
:step "0.01"}]]
|
||||
:disable-remove? true}])]]
|
||||
|
||||
(error-notification)
|
||||
(submit-button "Save")])]]))
|
||||
|
||||
Reference in New Issue
Block a user