- Add DuckDB/S3 parquet storage layer (auto-ap.storage.parquet) - Add sales_to_parquet migration script for historical data - Add cleanup_sales for post-migration Datomic cleanup - Add sales_orders_new.clj with DuckDB read layer for SSR views - Add test scaffolding for parquet storage - Add plan document for move-detailed-sales-to-parquet feat(sales): redirect production and read flows to Parquet/DuckDB - U3: Square production (upsert) now buffers to parquet via flatten-order-to-parquet! - U3: EzCater core import-order now buffers to parquet instead of Datomic transact - U3: EzCater XLS upload-xls now buffers to parquet instead of audit-transact - U4: Rewrite sales_orders.clj to read from DuckDB via pq/get-sales-orders - U5: Rewrite sales_summaries to use parquet aggregation functions - get-payment-items-parquet, get-discounts-parquet, get-refund-items-parquet - get-tax-parquet, get-tip-parquet, get-sales-parquet - Add sum-* aggregation functions to storage/sales_summaries.clj - sum-discounts, sum-refunds-by-type, sum-taxes, sum-tips, sum-sales-by-category
86 lines
3.1 KiB
Clojure
86 lines
3.1 KiB
Clojure
(ns auto-ap.datomic.sales-orders
|
|
(:require
|
|
[auto-ap.datomic :refer [conn]]
|
|
[auto-ap.storage.parquet :as pq]
|
|
[clj-time.coerce :as c]
|
|
[clojure.set :as set]
|
|
[com.brunobonacci.mulog :as mu]))
|
|
|
|
(defn <-row
|
|
"Convert a flat parquet row into the shape consumers expect.
|
|
Parquet produces maps of the form:
|
|
{\"external-id\" \"square/order/123\", ...}
|
|
which we transform to:
|
|
{:sales-order/external-id \"square/order/123\", ...}"
|
|
[row]
|
|
(-> row
|
|
(set/rename-keys
|
|
{"external-id" :sales-order/external-id
|
|
"location" :sales-order/location
|
|
"total" :sales-order/total
|
|
"tax" :sales-order/tax
|
|
"tip" :sales-order/tip
|
|
"discount" :sales-order/discount
|
|
"service-charge" :sales-order/service-charge
|
|
"vendor" :sales-order/vendor
|
|
"client-code" :sales-order/client-code
|
|
"date" :sales-order/date})
|
|
(update :sales-order/date #(some-> % str))))
|
|
|
|
(defn build-where-clause [args]
|
|
(let [clauses [(when-let [c (:client-code args)]
|
|
["external_id.client = '" c "'"])
|
|
(when-let [v (:vendor args)]
|
|
["external_id.vendor = '" (name v) "'"])
|
|
(when-let [l (:location args)]
|
|
["location = '" l "'"])]
|
|
(when (seq clauses)
|
|
(str "WHERE " (str/join " AND " clauses)))))
|
|
|
|
(defn build-sort-clause [args]
|
|
(let [sort (or (:sort args) "date")
|
|
order (or (:order args) "DESC")]
|
|
(str "ORDER BY " sort " " order)))
|
|
|
|
(def page-size 100)
|
|
|
|
(defn raw-graphql-ids [args]
|
|
(let [start (some-> (:start (:date-range args)) .toString)
|
|
end (some-> (:end (:date-range args)) .substring 0 10)
|
|
where (build-where-clause args)
|
|
sort (build-sort-clause args)
|
|
limit (or (:limit args) page-size)
|
|
offset (or (:offset args) 0)
|
|
where-str (when where (str " " where))]
|
|
(when start
|
|
(let [result (pq/get-sales-orders start end
|
|
{:client (:client-code args)
|
|
:vendor (:vendor args)
|
|
:location (:location args)
|
|
:sort sort
|
|
:order "DESC"
|
|
:limit limit
|
|
:offset offset})]
|
|
{:ids (mapv #(str (:external_id %)) (:rows result))
|
|
:rows (:rows result)
|
|
:count (:count result)}))))
|
|
|
|
(defn graphql-results [rows _ids _args]
|
|
(mapv <-row rows))
|
|
|
|
(defn summarize-orders [rows]
|
|
(when (seq rows)
|
|
(let [total (reduce + 0.0 (map #(or (:total %) 0.0) rows))
|
|
tax (reduce + 0.0 (map #(or (:tax %) 0.0) rows))]
|
|
{:total total
|
|
:tax tax})))
|
|
|
|
(defn get-graphql [args]
|
|
(let [{:keys [ids rows count]} (mu/trace ::get-sales-order-ids [] (raw-graphql-ids args))]
|
|
[(mu/trace ::get-results [] (graphql-results rows ids args))
|
|
count
|
|
(summarize-orders rows)]))
|
|
|
|
(defn summarize-graphql [args]
|
|
(let [{:keys [rows]} (raw-graphql-ids args)]
|
|
(summarize-orders rows))) |