diff options
Diffstat (limited to 'pages/shop/order')
| -rw-r--r-- | pages/shop/order/_id.fnl | 35 | ||||
| -rw-r--r-- | pages/shop/order/index.fnl | 72 | ||||
| -rw-r--r-- | pages/shop/order/list.fnl | 72 | ||||
| -rw-r--r-- | pages/shop/order/state.fnl | 18 |
4 files changed, 197 insertions, 0 deletions
diff --git a/pages/shop/order/_id.fnl b/pages/shop/order/_id.fnl new file mode 100644 index 0000000..5c929a3 --- /dev/null +++ b/pages/shop/order/_id.fnl @@ -0,0 +1,35 @@ +(import-macros {:compile-html HTML} :macros) +(local templates (require :templates)) +(local shop (require :shop)) +(local lib (require :lib)) +(local dicts (require :dicts)) + +(local texts + {:thanks + (lib.improve-typography + "Мы получили оповещение о заказе. В ближайшее время свяжемся с вами + для уточнения деталей.")}) + +(fn content [order-lines authenticated?] + (local total (accumulate [sum 0 _ v (ipairs order-lines)] + (+ sum (* v.quantity v.price-per)))) + + [(HTML [:aside {} + (templates.header "/shop/order" authenticated?)]) + (HTML + [:div {:class "content"} + [:div {:class "back"} [:a {:href "/shop"} "⟵ Обратно к списку"]] + [:section {} + [:h2 {} "Спасибо за заказ!"] + [:p {} texts.thanks] + (templates.order-lines order-lines) + [:div {} "—"] + [:div {} [:strong {} (.. "Итого: " (lib.format-price total) "₽")]]]])]) + +(fn render [request db authenticated?] + (let [order-lines (shop.basket db request.params._id)] + (if (< 0 (# order-lines)) + (values 200 {} (templates.base (content order-lines authenticated?))) + (values 302 {:Location "/shop"} "")))) + +{: render} diff --git a/pages/shop/order/index.fnl b/pages/shop/order/index.fnl new file mode 100644 index 0000000..7d25a40 --- /dev/null +++ b/pages/shop/order/index.fnl @@ -0,0 +1,72 @@ +(import-macros {:compile-html HTML} :macros) +(local forms (require :forms)) +(local lib (require :lib)) +(local shop (require :shop)) +(local templates (require :templates)) + +(local order-form + [{:title "" + :fields [ + (forms.text-input "name" "Как к вам обращаться?" true) + (forms.text-input "contact" "Телеграм или E-mail для связи" true) + (forms.checkbox-input "correct-order" "Данные заказа верны" true) + (forms.checkbox-input "consent" + (.. + "Я даю согласие ИП «Горенкин Владислав Константинович» (ИНН ...)" + " на хранение и обработку предоставленных персональных данных для уточнения деталей заказа.") + true)]}]) + +(fn content-template [db basket data errors] + [(HTML + [:aside {} + (templates.header "/shop/order") + (if (< 0 (# basket)) (templates.basket basket "/shop/order") "")]) + (HTML + [:div {:class "content"} + [:div {:class "back"} [:a {:href "/shop"} "⟵ Обратно к списку"]] + [:section {} + [:h2 {} "Оформление заказа"] + (forms.render-form order-form data errors)]])]) + +(fn check-stocks [db basket] + (var error nil) + + (each [_ line (ipairs basket) &until error] + (local product + (. (_G.must + (luna.db.query-assoc + db "SELECT title, stock FROM products WHERE name = ?" + [line.name])) + 1)) + (when (< (- product.stock line.quantity) 0) + (set error (.. "К сожалению, товар «" product.title "» закончился." + " Пожалуйста, уберите его из корзины и попробуйте оформить заказ снова.")))) + + error) + +(fn render [request db] + (let [order-id (shop.order-id request) + basket (if order-id (shop.basket db order-id) [])] + (if (= request.method "POST") + (let [data (forms.html-form->data order-form request.form) + stock-error (check-stocks db basket)] + (if (not stock-error) + (do + (shop.place-order db order-id data.name data.contact data.consent) + (lib.notify + (.. "Новый заказ " + "<a href=\"https://whitetoad.ru/shop/order/" order-id "\">" + order-id + "</a> от <b>" data.name "</b>.\n\n" + "<a href=\"https://whitetoad.ru/shop/order/list\">Список заказов</a>")) + ;; redirect and clear order cookie + (values 302 {:Location (.. "/shop/order/" order-id) + :Set-Cookie "order=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT"} + "")) + (values 400 {} + (templates.base (content-template db basket data {:consent stock-error}))))) + (if (< 0 (# basket)) + (values 200 {} (templates.base (content-template db basket {} {}))) + (values 302 {:Location "/shop"} ""))))) + +{: render} diff --git a/pages/shop/order/list.fnl b/pages/shop/order/list.fnl new file mode 100644 index 0000000..2f64f7b --- /dev/null +++ b/pages/shop/order/list.fnl @@ -0,0 +1,72 @@ +(import-macros {:compile-html HTML} :macros) +(local lib (require :lib)) +(local templates (require :templates)) +(local dicts (require :dicts)) + +(fn all-orders [db] + (lib.group-by + (_G.must + (luna.db.query-assoc db + "SELECT orders.id, + orders.placement_time AS \"placement-time\", + orders.name \"contact-name\", + orders.contact, + orders.state, + order_lines.id AS \"order-line-id\", + order_lines.quantity, + products.image1, + products.name, + products.type, + products.packaging, + products.title, + products.price_per \"price-per\" + FROM orders + INNER JOIN order_lines ON orders.id = order_lines.order_id + INNER JOIN products ON products.name = order_lines.product_name + WHERE orders.state != 'cart' + ORDER BY orders.placement_time DESC, orders.id" + {})) + [:id :placement-time :state :contact-name :contact])) + +(fn content [orders authenticated?] + [(HTML + [:aside {} + (templates.header "/shop/orders" authenticated?)]) + (HTML + [:section {:class "content"} + [:div {:class "mb-1"} [:a {:href "/"} "⟵ Обратно к списку"]] + [:h2 {:class "product-page-title"} "Список заказов"] + + (table.concat + (icollect [_ order (ipairs orders)] + (let [total (accumulate [sum 0 _ v (ipairs order.rest)] + (+ sum (* v.quantity v.price-per)))] + (HTML + [:section {:class "mb-2 font-size-0-875" } + [:h3 {:class "mb-0-25"} [:a {:href (.. "/shop/order/" order.id)} order.id]] + [:div {:class "mb-0-25 d-flex gap-0-25"} + (templates.order-state order.state) + (if (= "placed" order.state) + (HTML + [:form {:action "/shop/order/state" :method "POST"} + [:select {:name "state" :required true} + [:option {:value ""} "Новое состояние"] + [:option {:value "done"} "Выполнен"] + [:option {:value "canceled"} "Отменен"]] + [:input {:type "hidden" :name "id" :value order.id}] + [:button {:type "submit"} "Применить"]]) + "")] + [:em {:class "d-block mb-0-5"} + "Дата: " order.placement-time + " / " "контакт: " order.contact + " / " "как обращаться: " order.contact-name] + (templates.order-lines order.rest) + [:div {} "—"] + [:div {} [:strong {} (.. "Итого: " (lib.format-price total) "₽")]]]))))])]) + +(fn render [request db authenticated?] + (if authenticated? + (values 200 {} (templates.base (content (all-orders db) authenticated?))) + (values 302 {:Location "/"} ""))) + +{: render} diff --git a/pages/shop/order/state.fnl b/pages/shop/order/state.fnl new file mode 100644 index 0000000..1ff1ca9 --- /dev/null +++ b/pages/shop/order/state.fnl @@ -0,0 +1,18 @@ +(local lib (require :lib)) +(local shop (require :shop)) + +(fn render [request db authenticated?] + (if (and (= request.method "POST") authenticated?) + (let [vals (lib.parse-values request.body)] + (if (and vals vals.id + vals.state (or (= vals.state "done") + (= vals.state "canceled"))) + (do + (if (= "done" vals.state) + (shop.finish-order db vals.id) + (shop.cancel-order db vals.id)) + (values 302 {:Location "/shop/order/list"} "")) + (values 400 {} "bad body"))) + (values 404 {} "not found"))) + +{: render} |
