mirror of
https://github.com/mruwnik/chicken-master.git
synced 2025-06-08 13:24:42 +02:00
98 lines
4.3 KiB
Clojure
98 lines
4.3 KiB
Clojure
(ns chicken-master.orders
|
|
(:require [next.jdbc :as jdbc]
|
|
[next.jdbc.types :as jdbc.types]
|
|
[next.jdbc.sql :as sql]
|
|
[chicken-master.db :as db]
|
|
[chicken-master.products :as products]
|
|
[chicken-master.customers :as customers]
|
|
[chicken-master.time :as t]))
|
|
|
|
(defn upsert-order! [tx user-id customer-id {:keys [id day state notes]}]
|
|
(let [order {:customer_id customer-id
|
|
:notes notes
|
|
:status (some-> (or state "waiting") name jdbc.types/as-other)
|
|
:order_date (some-> day t/parse-date t/inst->timestamp)}]
|
|
(if (db/get-by-id tx user-id :orders id)
|
|
(do (sql/update! tx :orders order {:id id}) id)
|
|
(:orders/id (sql/insert! tx :orders (assoc order :user_id user-id))))))
|
|
|
|
|
|
(defn- structure-order [items]
|
|
{:id (-> items first :orders/id)
|
|
:notes (-> items first :orders/notes)
|
|
:state (-> items first :orders/status keyword)
|
|
:day (-> items first :orders/order_date (.toInstant) str (subs 0 10))
|
|
:who {:id (-> items first :customers/id)
|
|
:name (-> items first :customers/name)}
|
|
:products (into {}
|
|
(for [{:keys [order_products/amount products/name]} items]
|
|
[(keyword name) amount]))})
|
|
|
|
(def orders-query
|
|
"SELECT o.id, o.notes, o.status, o.order_date, c.id, c.name, p.name, op.amount
|
|
FROM orders o JOIN customers c ON o.customer_id = c.id
|
|
JOIN order_products op ON o.id = op.order_id
|
|
JOIN products p on p.id = op.product_id ")
|
|
|
|
(defn- get-orders [tx where params]
|
|
(->> (into [(if where (str orders-query where) orders-query)] params)
|
|
(sql/query tx)
|
|
(group-by :orders/id)
|
|
vals
|
|
(map structure-order)))
|
|
|
|
(defn get-order [tx user-id id]
|
|
(first (get-orders tx "WHERE o.id = ? AND o.user_id = ?" [id user-id])))
|
|
|
|
(defn get-all [user-id] (group-by :day (get-orders db/db-uri "WHERE o.user_id = ?" [user-id])))
|
|
|
|
(defn- orders-for-days [tx user-id & days]
|
|
(let [days (remove nil? days)]
|
|
(->> days
|
|
(map t/inst->timestamp)
|
|
(map jdbc.types/as-date)
|
|
(into [user-id])
|
|
(get-orders tx (str "WHERE o.user_id = ? AND o.order_date::date IN " (db/psql-list days)))
|
|
(group-by :day)
|
|
(merge (reduce #(assoc %1 (t/format-date %2) {}) {} days)))))
|
|
|
|
(defn replace! [user-id {:keys [who products] :as order}]
|
|
(jdbc/with-transaction [tx db/db-uri]
|
|
(let [customer-id (or (:id who)
|
|
(customers/get-by-name tx user-id who))
|
|
products-map (products/products-map tx user-id products)
|
|
previous-day (some->> order :id (db/get-by-id tx user-id :orders) :orders/order_date (.toInstant))
|
|
order-id (upsert-order! tx user-id customer-id order)]
|
|
(sql/delete! tx :order_products {:order_id order-id})
|
|
(sql/insert-multi! tx :order_products
|
|
[:order_id :product_id :amount]
|
|
(for [[n amount] products
|
|
:let [product-id (-> n name products-map)]
|
|
:when product-id]
|
|
[order-id product-id amount]))
|
|
(orders-for-days tx user-id previous-day (some-> order :day t/parse-date)))))
|
|
|
|
(defn delete! [user-id id]
|
|
(jdbc/with-transaction [tx db/db-uri]
|
|
(let [day (some->> id (db/get-by-id tx user-id :orders) :orders/order_date (.toInstant))]
|
|
(sql/delete! tx :orders {:id id :user_id user-id})
|
|
(when day (orders-for-days tx user-id day)))))
|
|
|
|
(defn change-state!
|
|
"Update the state of the given order and also modify the number of products available:
|
|
* when `fulfilled` decrement the number of products
|
|
* when `waiting` increment the number (as this means a previously fulfilled order has been returned)"
|
|
[user-id id state]
|
|
(jdbc/with-transaction [tx db/db-uri]
|
|
(let [order (get-order tx user-id id)
|
|
operator (condp = state
|
|
"fulfilled" "-"
|
|
"waiting" "+")]
|
|
(when (not= (:state order) (keyword state))
|
|
(doseq [[prod amount] (:products order)]
|
|
(jdbc/execute-one! tx
|
|
[(str "UPDATE products SET amount = amount " operator " ? WHERE name = ?")
|
|
amount (name prod)]))
|
|
(sql/update! tx :orders {:status (jdbc.types/as-other state)} {:id id}))
|
|
(orders-for-days tx user-id (-> order :day t/parse-date)))))
|