mirror of
https://github.com/mruwnik/chicken-master.git
synced 2025-06-28 15:14:49 +02:00
customer products
This commit is contained in:
parent
072e0b3f4d
commit
10d9ebe046
@ -20,7 +20,11 @@
|
||||
|
||||
(defn get-customers [user-id] (get-values user-id [:customers]))
|
||||
(defn add-customer [{:keys [body basic-authentication]}]
|
||||
(as-edn (some->> body :name (customers/create! basic-authentication))))
|
||||
(some->> body :name (customers/create! basic-authentication) as-edn))
|
||||
(defn save-product-group [user-id customer-id body]
|
||||
(customers/save-product-group user-id (Integer/parseInt customer-id) body)
|
||||
(get-customers user-id))
|
||||
|
||||
(defn delete-customer [user-id id]
|
||||
(->> id edn/read-string (customers/delete! user-id))
|
||||
(get-values user-id [:orders :customers]))
|
||||
@ -46,6 +50,8 @@
|
||||
(GET "/customers" [:as {user-id :basic-authentication}] (get-customers user-id))
|
||||
(POST "/customers" request (add-customer request))
|
||||
(DELETE "/customers/:id" [id :as {user-id :basic-authentication}] (delete-customer user-id id))
|
||||
(POST "/customers/:id/product-group" [id :as {user-id :basic-authentication body :body}]
|
||||
(save-product-group user-id id body))
|
||||
|
||||
(GET "/products" request (get-products request))
|
||||
(POST "/products" request (save-products request))
|
||||
|
@ -1,13 +1,37 @@
|
||||
(ns chicken-master.customers
|
||||
(:require [next.jdbc :as jdbc]
|
||||
[next.jdbc.sql :as sql]
|
||||
[chicken-master.products :as products]
|
||||
[chicken-master.db :as db]))
|
||||
|
||||
|
||||
|
||||
(defn insert-products [coll {:keys [id name]} products]
|
||||
(->> products
|
||||
(reduce #(assoc %1 (-> %2 :products/name keyword) (:customer_group_products/amount %2)) {})
|
||||
(assoc {:id id} :products)
|
||||
(assoc coll name)))
|
||||
|
||||
(defn extract-product-groups [client products]
|
||||
(if-not products
|
||||
client
|
||||
(->> products
|
||||
(filter :customer_groups/name)
|
||||
(group-by (fn [{:customer_groups/keys [id name]}] {:id id :name name}))
|
||||
(reduce-kv insert-products {})
|
||||
(assoc client :product-groups))))
|
||||
|
||||
(def users-select-query
|
||||
"SELECT * FROM customers c
|
||||
LEFT OUTER JOIN customer_groups cg on c.id = cg.customer_id
|
||||
LEFT OUTER JOIN customer_group_products cgp on cg.id = cgp.customer_group_id
|
||||
LEFT OUTER JOIN products p ON p.id = cgp.product_id
|
||||
WHERE c.deleted IS NULL aND c.user_id = ?")
|
||||
|
||||
(defn get-all [user-id]
|
||||
(->> (sql/query db/db-uri ["select * from customers where deleted is null AND user_id = ?" user-id])
|
||||
(map (fn [{:customers/keys [id name]}] {:id id :name name
|
||||
:product-groups {"bla" {:eggs 2 :carrots 13}
|
||||
"ble" {:eggs 12 :milk 3}}}))))
|
||||
(->> (sql/query db/db-uri [users-select-query user-id])
|
||||
(group-by (fn [{:customers/keys [id name]}] {:id id :name name}))
|
||||
(map (partial apply extract-product-groups))))
|
||||
|
||||
(defn create! [user-id name]
|
||||
(jdbc/execute! db/db-uri
|
||||
@ -27,3 +51,19 @@
|
||||
id
|
||||
(do (create! user-id name)
|
||||
(get-by-name tx user-id name))))
|
||||
|
||||
|
||||
(defn upsert-customer-group! [tx user-id customer-id {:keys [id name]}]
|
||||
(if (jdbc/execute-one! tx ["SELECT * FROM customer_groups WHERE user_id = ? AND customer_id = ? AND id =?"
|
||||
user-id customer-id id])
|
||||
(do (sql/update! tx :customer_groups {:name name} {:id id}) id)
|
||||
(->> {:user_id user-id :name name :customer_id customer-id}
|
||||
(sql/insert! tx :customer_groups)
|
||||
:customer_groups/id)))
|
||||
|
||||
(defn save-product-group [user-id customer-id group]
|
||||
(jdbc/with-transaction [tx db/db-uri]
|
||||
(products/update-products-mapping!
|
||||
tx user-id :customer_group
|
||||
(upsert-customer-group! tx user-id customer-id group)
|
||||
(:products group))))
|
||||
|
@ -26,5 +26,6 @@
|
||||
id user-id])))
|
||||
|
||||
(comment
|
||||
(create-user "bla" "bla")
|
||||
(create-user "siloa" "krach")
|
||||
(valid-user? "siloa" "krach"))
|
||||
|
@ -60,16 +60,10 @@
|
||||
(jdbc/with-transaction [tx db/db-uri]
|
||||
(let [customer-id (or (:id who)
|
||||
(customers/get-or-create-by-name tx user-id (:name 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]))
|
||||
previous-day (some->> order :id (db/get-by-id tx user-id :orders) :orders/order_date (.toInstant))]
|
||||
(products/update-products-mapping! tx user-id :order
|
||||
(upsert-order! tx user-id customer-id order)
|
||||
products)
|
||||
(orders-for-days tx user-id previous-day (some-> order :day t/parse-date)))))
|
||||
|
||||
(defn delete! [user-id id]
|
||||
|
@ -28,3 +28,15 @@
|
||||
(into [(str "name NOT IN " (db/psql-list (keys new-products)))]
|
||||
(->> new-products keys (map name)))))
|
||||
(get-all user-id))
|
||||
|
||||
(defn update-products-mapping! [tx user-id table id products]
|
||||
(let [id-key (-> table name (str "_id") keyword)
|
||||
table (-> table name (str "_products") keyword)
|
||||
products-map (products-map tx user-id products)]
|
||||
(sql/delete! tx table {id-key id})
|
||||
(sql/insert-multi! tx table
|
||||
[id-key :product_id :amount]
|
||||
(for [[n amount] products
|
||||
:let [product-id (-> n name products-map)]
|
||||
:when product-id]
|
||||
[id product-id amount]))))
|
||||
|
@ -3,23 +3,130 @@
|
||||
[next.jdbc :as jdbc]
|
||||
[next.jdbc.sql :as sql]
|
||||
[chicken-master.customers :as sut]
|
||||
[chicken-master.products :as products]
|
||||
[clojure.test :refer [deftest is testing]]))
|
||||
|
||||
(def sample-customers
|
||||
[{:customers/name "klient 1", :customers/id 1
|
||||
:customer_groups/name "group1", :customer_groups/id 1,
|
||||
:customer_group_products/amount 2, :products/name "eggs"}
|
||||
{:customers/name "klient 1", :customers/id 1
|
||||
:customer_groups/name "group1", :customer_groups/id 1,
|
||||
:customer_group_products/amount 32, :products/name "milk"}
|
||||
|
||||
{:customers/name "klient 1", :customers/id 1
|
||||
:customer_groups/name "group 2", :customer_groups/id 2,
|
||||
:customer_group_products/amount 1, :products/name "milk"}
|
||||
{:customers/name "klient 1", :customers/id 1
|
||||
:customer_groups/name "group 2", :customer_groups/id 2,
|
||||
:customer_group_products/amount 6, :products/name "eggs"}
|
||||
{:customers/name "klient 1", :customers/id 1
|
||||
:customer_groups/name "group 2", :customer_groups/id 2,
|
||||
:customer_group_products/amount 89, :products/name "carrots"}
|
||||
|
||||
{:customers/name "klient 2", :customers/id 2
|
||||
:customer_groups/name "group 3", :customer_groups/id 3,
|
||||
:customer_group_products/amount 41, :products/name "milk"}
|
||||
{:customers/name "klient 2", :customers/id 2
|
||||
:customer_groups/name "group 3", :customer_groups/id 3,
|
||||
:customer_group_products/amount 6, :products/name "eggs"}])
|
||||
|
||||
(deftest format-products-tests
|
||||
(testing "products amounts get formatted properly"
|
||||
(is (= (sut/insert-products {} {:id 1 :name "bla"} {})
|
||||
{"bla" {:id 1 :products {}}}))
|
||||
|
||||
(is (= (sut/insert-products {"ble" {:id 32}} {:id 1 :name "bla"} {})
|
||||
{"ble" {:id 32} "bla" {:id 1 :products {}}}))
|
||||
|
||||
(is (= (sut/insert-products {} {:id 1 :name "bla"}
|
||||
[{:products/name "milk" :customer_group_products/amount 1}
|
||||
{:products/name "carrots" :customer_group_products/amount 12}
|
||||
{:products/name "eggs" :customer_group_products/amount 3}])
|
||||
{"bla" {:id 1 :products {:eggs 3 :carrots 12 :milk 1}}})))
|
||||
|
||||
(testing "extracting product groups works"
|
||||
(is (= (sut/extract-product-groups {:ble "ble"} sample-customers)
|
||||
{:ble "ble"
|
||||
:product-groups {"group1" {:id 1, :products {:eggs 2, :milk 32}},
|
||||
"group 2" {:id 2, :products {:milk 1, :eggs 6, :carrots 89}},
|
||||
"group 3" {:id 3, :products {:milk 41, :eggs 6}}}})))
|
||||
|
||||
(testing "extracting product groups stops if no values"
|
||||
(is (= (sut/extract-product-groups {:ble "ble"} nil)
|
||||
{:ble "ble"}))
|
||||
|
||||
(is (= (sut/extract-product-groups {:ble "ble"} [])
|
||||
{:ble "ble" :product-groups {}}))))
|
||||
|
||||
(deftest test-get-all
|
||||
(testing "query is correct"
|
||||
(with-redefs [sql/query (fn [_ query]
|
||||
(is (= query ["select * from customers where deleted is null AND user_id = ?" "1"]))
|
||||
(is (= query [sut/users-select-query "1"]))
|
||||
[])]
|
||||
(sut/get-all "1")))
|
||||
|
||||
(testing "results are mapped correctly"
|
||||
(with-redefs [sql/query (constantly [{:customers/id 1 :customers/name "mr blobby" :bla 123}])]
|
||||
(is (= (sut/get-all 2)
|
||||
[{:id 1 :name "mr blobby" :product-groups {}}]))))
|
||||
|
||||
(testing "customer groups are mapped correctly"
|
||||
(with-redefs [sql/query (constantly sample-customers)]
|
||||
(is (= (sut/get-all "1")
|
||||
[{:id 1 :name "mr blobby"}])))))
|
||||
[{:id 1 :name "klient 1" :product-groups {"group1" {:id 1 :products {:eggs 2 :milk 32}}
|
||||
"group 2" {:id 2 :products {:milk 1 :eggs 6 :carrots 89}}}}
|
||||
{:id 2 :name "klient 2" :product-groups {"group 3" {:id 3 :products {:milk 41 :eggs 6}}}}])))))
|
||||
|
||||
(deftest test-create!
|
||||
(testing "correct format is returned"
|
||||
(with-redefs [jdbc/execute! (constantly [])
|
||||
sql/query (constantly [{:customers/id 1 :customers/name "mr blobby" :bla 123}])]
|
||||
(is (= (sut/create! "1" "mr blobby")
|
||||
{:customers [{:id 1 :name "mr blobby"}]})))))
|
||||
{:customers [{:id 1 :name "mr blobby" :product-groups {}}]})))))
|
||||
|
||||
|
||||
(deftest save-product-group-test
|
||||
(let [user-id 1
|
||||
customer-id 2
|
||||
group-id 123]
|
||||
(with-redefs [jdbc/transact (fn [_ f & args] (apply f args))
|
||||
sql/insert! (constantly {:customer_groups/id group-id})
|
||||
sql/delete! (fn [_tx table id]
|
||||
(is (= table :customer_group_products))
|
||||
(is (= id {:customer_group_id group-id})))
|
||||
|
||||
products/products-map (constantly {"eggs" 1 "milk" 2 "carrots" 3})
|
||||
|
||||
sql/insert-multi! (fn [_tx table cols products]
|
||||
(is (= table :customer_group_products))
|
||||
(is (= cols [:customer_group_id :product_id :amount]))
|
||||
(is (= products [[group-id 1 34]
|
||||
[group-id 2 25]
|
||||
[group-id 3 13]]))
|
||||
:ok)]
|
||||
(testing "the correct query is used to check if group exists"
|
||||
(with-redefs [jdbc/execute-one!
|
||||
(fn [_ query]
|
||||
(is (= query ["SELECT * FROM customer_groups WHERE user_id = ? AND customer_id = ? AND id =?"
|
||||
user-id customer-id nil]))
|
||||
nil)]
|
||||
(sut/save-product-group user-id customer-id {:name "bla" :products {:eggs 34 :milk 25 :carrots 13}})))
|
||||
|
||||
(testing "product groups get created"
|
||||
(with-redefs [jdbc/execute-one! (constantly nil) ; the group doesn't yet exist
|
||||
sql/insert! (fn [_ _ group]
|
||||
(is (= group {:name "bla" :customer_id customer-id :user_id user-id}))
|
||||
{:customer_groups/id group-id}) ; create a new group
|
||||
sql/update! (fn [&args] (is nil "The group shouldn't be updated"))]
|
||||
(sut/save-product-group user-id customer-id {:name "bla" :products {:eggs 34 :milk 25 :carrots 13}})))
|
||||
|
||||
(testing "existing product groups get updated"
|
||||
(with-redefs [jdbc/execute-one! (constantly true) ; the group should exist
|
||||
sql/update! (fn [_tx table item query]
|
||||
(is (= table :customer_groups))
|
||||
(is (= item {:name "bla"}))
|
||||
(is (= query {:id group-id})))
|
||||
sql/insert! (fn [&args] (is nil "The group shouldn't be created"))]
|
||||
(sut/save-product-group user-id customer-id
|
||||
{:id group-id :name "bla" :products {:eggs 34 :milk 25 :carrots 13}}))))))
|
||||
|
@ -72,3 +72,27 @@
|
||||
sql/query (constantly [{:products/name "eggs" :products/amount 12}
|
||||
{:products/name "milk" :products/amount 3}])]
|
||||
(is (= (sut/update! :user-id {:eggs 2 :milk 3 :cows 2}) {:eggs 12 :milk 3})))))
|
||||
|
||||
(deftest update-products-mapping-test
|
||||
(testing "items get removed"
|
||||
(let [item-id 123]
|
||||
(with-redefs [sut/products-map (constantly {"eggs" 1 "milk" 2 "carrots" 3})
|
||||
sql/insert-multi! (constantly :ok)
|
||||
|
||||
sql/delete! (fn [_tx table id]
|
||||
(is (= table :bla_products))
|
||||
(is (= id {:bla_id item-id})))]
|
||||
(sut/update-products-mapping! :tx 123 :bla item-id {:eggs 34 :milk 25 :carrots 13}))))
|
||||
|
||||
(testing "items get removed"
|
||||
(let [item-id 123]
|
||||
(with-redefs [sut/products-map (constantly {"eggs" 1 "milk" 2 "carrots" 3})
|
||||
sql/delete! (constantly :ok)
|
||||
|
||||
sql/insert-multi! (fn [_tx table cols products]
|
||||
(is (= table :bla_products))
|
||||
(is (= cols [:bla_id :product_id :amount]))
|
||||
(is (= products [[item-id 1 34]
|
||||
[item-id 2 25]
|
||||
[item-id 3 13]])))]
|
||||
(sut/update-products-mapping! :tx 123 :bla item-id {:eggs 34 :milk 25 :carrots 13})))))
|
||||
|
@ -3,7 +3,7 @@ clojure -X:depstar uberjar
|
||||
|
||||
cd ../frontend
|
||||
npx shadow-cljs release frontend
|
||||
clojure -A:garden -m chicken-master.css
|
||||
clojure -A:garden -m chicken-master.css compile
|
||||
|
||||
cd ..
|
||||
scp backend/chicken-master.jar chickens:/srv/chickens/chicken-master.jar
|
||||
|
@ -22,7 +22,9 @@
|
||||
:products (prod/collect-products (remove (comp #{"who" "notes"} first) raw-values))})
|
||||
|
||||
(defn get-group-products [customers who]
|
||||
(some->> customers (filter (comp #{who} :name)) first :product-groups))
|
||||
(some->> customers (filter (comp #{who} :name))
|
||||
first :product-groups
|
||||
(reduce-kv #(assoc %1 %2 (:products %3)) {})))
|
||||
|
||||
(defn order-form
|
||||
([order] (order-form order #{:who :day :notes :products :group-products}))
|
||||
|
@ -27,8 +27,8 @@
|
||||
[prod/products-edit (:products @state)
|
||||
:getter-fn #(re-frame/dispatch [::event/save-order (assoc @state :products %)])]])])))
|
||||
|
||||
(defn product-group-adder [who product-group]
|
||||
(let [state (reagent/atom product-group)]
|
||||
(defn product-group-adder [who [name {:keys [id products]}]]
|
||||
(let [state (reagent/atom {:name name :id id :products (or products {})})]
|
||||
(fn []
|
||||
[:div {:class :customer-block}
|
||||
(if-not (:edit @state)
|
||||
@ -68,7 +68,7 @@
|
||||
(for [group (:product-groups who)]
|
||||
[:div {:key (gensym)}
|
||||
[product-group-adder who group]])
|
||||
[product-group-adder {}]]
|
||||
[product-group-adder who []]]
|
||||
|
||||
[:details {:class :client-orders}
|
||||
[:summary "Zamówienia"]
|
||||
|
@ -63,7 +63,8 @@
|
||||
::log-error
|
||||
(fn [_ [_ error]]
|
||||
(.error js/console error)
|
||||
(js/alert "Wystąpił błąd")))
|
||||
(js/alert "Wystąpił błąd")
|
||||
))
|
||||
|
||||
(re-frame/reg-event-fx
|
||||
::failed-request
|
||||
|
@ -81,7 +81,7 @@
|
||||
(let [state (reagent/atom value)]
|
||||
(fn []
|
||||
[:div {:class class :on-click #(.stopPropagation %)}
|
||||
[:input {:type type :name :user-name :default-value value
|
||||
[:input {:type type :name :user-name :default-value value :value @state
|
||||
:on-change #(let [val (-> % .-target .-value)]
|
||||
(reset! state val)
|
||||
(if-not button (callback val)))}]
|
||||
@ -89,7 +89,7 @@
|
||||
[:button {:class :add-product
|
||||
:type :button
|
||||
:disabled (= @state "")
|
||||
:on-click (if callback #(-> state (reset-vals! value) first callback))} button])])))
|
||||
:on-click (if callback #(-> state (reset-vals! "") first callback))} button])])))
|
||||
|
||||
(defn group-products [state]
|
||||
[:div {:class :input-item}
|
||||
|
@ -47,12 +47,12 @@
|
||||
{:who {:name "bla" :id 123} :day "2020-10-10" :notes "ble" :products {:eggs 12 :milk 3.2}}))))
|
||||
|
||||
(def customers
|
||||
[{:id 1 :name "mr blobby" :product-groups [{:name "group 1" :products {:eggs 1 :carrots 2}}
|
||||
{:name "group 2" :products {:eggs 11 :carrots 2}}
|
||||
{:name "group 3" :products {:milk 2 :eggs 12}}]}
|
||||
{:id 2 :name "johnny D" :product-groups [{:name "group 4" :products {:eggs 2}}
|
||||
{:name "group 5" :products {:milk 2}}]}
|
||||
{:id 3 :name "joe" :product-groups []}
|
||||
[{:id 1 :name "mr blobby" :product-groups {"group 1" {:products {:eggs 1 :carrots 2}}
|
||||
"group 2" {:products {:eggs 11 :carrots 2}}
|
||||
"group 3" {:products {:milk 2 :eggs 12}}}}
|
||||
{:id 2 :name "johnny D" :product-groups {"group 4" {:products {:eggs 2}}
|
||||
"group 5" {:products {:milk 2}}}}
|
||||
{:id 3 :name "joe" :product-groups {}}
|
||||
{:id 4 :name "mark"}])
|
||||
|
||||
(deftest get-group-products-test
|
||||
|
Loading…
x
Reference in New Issue
Block a user