(ns auto-ap.ssr.account (:require [auto-ap.datomic :refer [conn]] [auto-ap.graphql.utils :refer [assert-can-see-client can-see-client? cleanse-query is-admin?]] [auto-ap.solr :as solr] [auto-ap.logging :as alog] [auto-ap.ssr.utils :refer [entity-id ref->enum-schema wrap-schema-enforce]] [com.brunobonacci.mulog :as mu] [datomic.api :as dc] [ring.middleware.json :refer [wrap-json-response]])) ;; TODO this is basically duplicative of graphql version, make sure to keep in sync ;; TODO use valid clients from request rather than stuff like assert-can-see-client (def search-pattern [:db/id :account/numeric-code :account/location {:account/vendor-allowance [:db/ident] :account/default-allowance [:db/ident] :account/invoice-allowance [:db/ident]}]) (defn search- [id query client] (let [client-part (if (some->> client (can-see-client? id)) (format "((applicability:(global OR optional) AND -client_id:*) OR (account_client_override_id:* AND client_id:%s))" client) "(applicability:(global OR optional) AND -client_id:*)") query (format "_text_:(%s) AND %s" (cleanse-query query) client-part)] (mu/log ::searching :search-query query) (for [{:keys [account_id name] :as g} (solr/query solr/impl "accounts" {"query" query "fields" "id, name, client_id, numeric_code, applicability, account_id"})] {:account_id (first account_id) :name (first name)}))) (defn account-search [{{:keys [q client-id purpose vendor-id] :as qp} :query-params id :identity}] (when client-id (assert-can-see-client id client-id)) (let [num (some-> (re-find #"([0-9]+)" q) second (not-empty) Integer/parseInt) valid-allowances (cond-> #{:allowance/allowed :allowance/warn} (is-admin? id) (conj :allowance/admin-only)) allowance (cond (= purpose "vendor") :account/vendor-allowance (= purpose "invoice") :account/invoice-allowance :else :account/default-allowance) vendor-account (when vendor-id (-> (dc/q '[:find ?da :in $ ?v :where [?v :vendor/default-account ?da]] (dc/db conn) vendor-id) ffirst)) xform (comp (filter (fn [[_ a]] (or (valid-allowances (-> a allowance :db/ident)) (= (:db/id a) vendor-account)))) (map (fn [[n a]] {:label (str (:account/numeric-code a) " - " n) :value (:db/id a) :location (:account/location a) :warning (when (= :allowance/warn (-> a allowance :db/ident)) "This account is not typically used for this purpose.")})))] {:body (take 10 (if q (if num (->> (dc/q '[:find ?n (pull ?i pattern) :in $ ?numeric-code ?allowance pattern :where [?i :account/numeric-code ?numeric-code] [?i :account/name ?n] (or [?i :account/applicability :account-applicability/global] [?i :account/applicability :account-applicability/optional] [?i :account/applicability :account-applicability/customized])] (dc/db conn) num allowance search-pattern) (sequence xform)) (->> (search- id q client-id) (sequence (comp (map (fn [i] [(:name i) (dc/pull (dc/db conn) search-pattern (:account_id i))])) xform)))) []))})) (def account-search (wrap-json-response (wrap-schema-enforce account-search :query-schema [:map [:q :string] [:client-id {:optional true :default nil} [:maybe entity-id]] [:vendor-id {:optional true} [:maybe entity-id]] [:purpose {:optional true} [:maybe :string]]])))