Files
integreat/src/clj/auto_ap/routes/ezcater_xls.clj

217 lines
9.3 KiB
Clojure

(ns auto-ap.routes.ezcater-xls
(:require
[auto-ap.datomic :refer [audit-transact conn]]
[auto-ap.logging :as alog]
[clojure.data.json :as json]
[auto-ap.parse.excel :as excel]
[auto-ap.parse :as parse]
[amazonica.aws.lambda :as lambda]
[config.core :refer [env]]
[auto-ap.shared-views.admin.side-bar :refer [admin-side-bar]]
[auto-ap.ssr-routes :as ssr-routes]
[auto-ap.ssr.ui :refer [base-page]]
[auto-ap.ssr.utils :refer [html-response]]
[auto-ap.time :as atime]
[bidi.bidi :as bidi]
[clj-time.coerce :as coerce]
[clojure.java.io :as io]
[com.brunobonacci.mulog :as mu]
[datomic.api :as dc]
[hiccup2.core :as hiccup]
[amazonica.aws.s3 :as s3]
[auto-ap.ssr.components :as com]))
(defn fmt-amount [a]
(with-precision 2
(some-> a
bigdec
(.setScale 2 java.math.RoundingMode/HALF_UP)
(double))))
(defn rows->maps [rows]
(let [[headers & rows] rows]
(for [r rows]
(into {}
(map vector headers r)))))
(defn map->sales-order [r clients]
(println r)
(let [order-number (get r "Order Number")
event-date (get r "Event Date")
store-name (get r "Store Name")
adjustments (some-> (get r "Adjustments") not-empty (Double/parseDouble))
tax (some-> (get r "Sales Tax") not-empty (Double/parseDouble))
food-total (some-> (get r "Food Total") not-empty (Double/parseDouble))
commission (some-> (get r "Commission") not-empty (Double/parseDouble))
fee (some-> (get r "Payment Transaction Fee") not-empty (Double/parseDouble))
tip (some-> (get r "Tip") not-empty (Double/parseDouble))
caterer-name (get r "Caterer Name")
client (some->> caterer-name
not-empty
(parse/exact-match clients))
client-id (:db/id client)
location (first (:client/locations client))
event-date (some-> (excel/xls-date->date event-date)
coerce/to-date-time
atime/as-local-time
coerce/to-date )]
(cond (and event-date client-id location )
[:order #:sales-order
{:date event-date
:external-id (str "ezcater/order/" client-id "-" location "-" order-number)
:client client-id
:location location
:reference-link (str order-number)
:line-items [#:order-line-item
{:external-id (str "ezcater/order/" client-id "-" location "-" order-number "-" 0)
:item-name "EZCater Catering"
:category "EZCater Catering"
:discount (fmt-amount (or adjustments 0.0))
:tax (fmt-amount tax)
:total (fmt-amount (+ food-total
tax))}]
:charges [#:charge
{:type-name "CARD"
:date event-date
:client client-id
:location location
:external-id (str "ezcater/charge/" client-id "-" location "-" order-number "-" 0)
:processor :ccp-processor/ezcater
:total (fmt-amount (+ food-total
tax
tip))
:tip (fmt-amount tip)}]
:total (fmt-amount (+ food-total
tax
(or adjustments 0.0)))
:discount (fmt-amount (or adjustments 0.0))
:service-charge (fmt-amount (+ fee commission))
:tax (fmt-amount tax)
:tip (fmt-amount tip)
:returns 0.0
:vendor :vendor/ccp-ezcater}]
caterer-name
(do
(alog/warn ::missing-client
:order order-number
:store-name store-name
:caterer-name caterer-name)
[:missing caterer-name])
:else
nil)))
(defn stream->sales-orders [s]
(let [clients (map first (dc/q '[:find (pull ?c [:client/code
:db/id
:client/feature-flags
{:client/location-matches [:location-match/matches :location-match/location]}
:client/name
:client/matches
:client/locations])
:where [?c :client/code]]
(dc/db conn)))
object (str "/ezcater-xls/" (str (java.util.UUID/randomUUID)))]
(mu/log ::writing-temp-xls
:location object)
(s3/put-object {:bucket-name (:data-bucket env)
:key object
:input-stream s})
(into []
(->> (excel/extract-sheet-details (:data-bucket env) object)
rows->maps
(map #(map->sales-order % clients))
(filter identity)))))
(defn import-stuff []
(with-open [s (io/input-stream "/home/brycecovert/Downloads/test_2023-04-01_2023-04-30_2023-05-04.xlsx")]
(stream->sales-orders s)))
(defn page* []
[:div.mt-4
(com/card {}
[:div.px-4.py-3.space-y-4.flex.flex-col
[:h1.text-2xl.mb-3.font-bold "EZCater XLS Import"]
[:p.text-sm.italic
"Please go to "
(com/link {:href "https://www.ezcater.com/ez_manage/reports/new" :target "_blank"} "EZCater's report page")
" to generate a new report. Then drop it below."]
[:div#page-notification.notification.block {:style {:display "none"}}]
[:form.bg-blue-100.border-2.border-dashed.rounded-lg.border-blue-300.p-4.max-w-md.w-md.text-center.cursor-pointer
{:action (bidi/path-for ssr-routes/only-routes
:admin-ezcater-xls)
:method "POST"
:id "ezcater"}
"Drop the ezcater xls here."]
[:script
(hiccup/raw
"
ezcater_dropzone = new Dropzone (\"#ezcater\", {
success: function (file, response) {
document.getElementById(\"page-notification\").innerHTML = response;
document.getElementById(\"page-notification\").style[\"display\"] = \"block\";
},
acceptedFiles: '.xls,.xlsx',
disablePreviews: true
});")]])])
(defn upload-xls [{:keys [identity] :as request}]
(let [file (or (get (:params request) :file)
(get (:params request) "file"))]
(mu/log ::uploading-file
:file file)
(with-open [s (io/input-stream (:tempfile file))]
(try
(let [parse-results (stream->sales-orders s)
new-orders (->> parse-results
(filter (comp #{:order} first))
(map last))
missing-location (->> parse-results
(filter (comp #{:missing} first))
(map last))]
(audit-transact new-orders identity)
(html-response [:div (format "Successfully imported %d orders." (count new-orders))
(when (seq missing-location)
[:div "Missing the following locations"
[:ul.ul
(for [ml (into #{} missing-location)]
[:li ml])]])]))
(catch Exception e
(alog/error ::import-error
:error e)
(html-response [:div (.getMessage e)]))))))
(defn page [{:keys [matched-route request-method] :as request}]
(mu/log ::method
:method request-method)
(if (= :post request-method)
(upload-xls request)
(base-page
request
(com/page {:nav com/admin-aside-nav
:client-selection (:client-selection request)
:client (:client request)
:clients (:clients request)
:identity (:identity request)
:request request
:app-params {:hx-get (bidi/path-for ssr-routes/only-routes
:admin-ezcater-xls)
:hx-trigger "clientSelected from:body"
:hx-select "#app-contents"
:hx-swap "outerHTML swap:300ms"}}
(com/breadcrumbs {}
[:a {:href (bidi/path-for ssr-routes/only-routes
:admin)}
"Admin"]
[:a {:href (bidi/path-for ssr-routes/only-routes
:admin-ezcater-xls)}
"EZCater XLS Import"])
(page*))
"Invoice Glimpse")))