diff --git a/backend/src/chicken_master/orders.clj b/backend/src/chicken_master/orders.clj index 12cb969..0ae12f9 100644 --- a/backend/src/chicken_master/orders.clj +++ b/backend/src/chicken_master/orders.clj @@ -173,6 +173,10 @@ (group-by :day) (merge (reduce #(assoc %1 (t/format-date %2) {}) {} days))))) +(defn get-fortnight [tx user-id from] + (->> (get-orders tx from (t/plus from 14 :days) "o.user_id = ?" [user-id]) + (group-by :day))) + (defn replace! ([user-id order] (jdbc/with-transaction [tx db/db-uri] (replace! tx user-id order))) ([tx user-id {:keys [who products day order-date] :as order}] @@ -181,7 +185,7 @@ (products/update-products-mapping! tx user-id :order (upsert-order! tx user-id customer-id order) products) - (orders-for-days tx user-id day order-date)))) + (get-fortnight tx user-id (t/earliest day order-date))))) (defn change-state! "Update the state of the given order and also modify the number of products available: @@ -208,7 +212,7 @@ (defn- full-delete [tx user-id id] (when-let [{:orders/keys [order_date end_date]} (some->> id (db/get-by-id tx user-id :orders))] (sql/delete! tx :orders {:id id :user_id user-id}) - (orders-for-days tx user-id order_date end_date))) + (get-fortnight tx user-id (t/earliest order_date end_date)))) (defn delete! [user-id day action-type id] (jdbc/with-transaction [tx db/db-uri] diff --git a/backend/src/chicken_master/time.clj b/backend/src/chicken_master/time.clj index cb85c61..83e0ddc 100644 --- a/backend/src/chicken_master/time.clj +++ b/backend/src/chicken_master/time.clj @@ -2,6 +2,7 @@ (:require [clojure.set :as set]) (:import [java.time Instant LocalDate ZoneOffset] [java.time.format DateTimeFormatter] + (java.time.temporal ChronoUnit) [java.sql Timestamp] [org.dmfs.rfc5545.recur RecurrenceRule Freq] [org.dmfs.rfc5545 DateTime])) @@ -11,12 +12,31 @@ (-> date (LocalDate/parse) (.atStartOfDay) (.toInstant ZoneOffset/UTC)) (Instant/parse date))) +(def chrono-units {:centuries ChronoUnit/CENTURIES + :days ChronoUnit/DAYS + :decades ChronoUnit/DECADES + :eras ChronoUnit/ERAS + :forever ChronoUnit/FOREVER + :half-days ChronoUnit/HALF_DAYS + :hours ChronoUnit/HOURS + :micros ChronoUnit/MICROS + :millennia ChronoUnit/MILLENNIA + :millis ChronoUnit/MILLIS + :minutes ChronoUnit/MINUTES + :months ChronoUnit/MONTHS + :nanos ChronoUnit/NANOS + :seconds ChronoUnit/SECONDS + :weeks ChronoUnit/WEEKS + :years ChronoUnit/YEARS}) + (defprotocol TimeHelpers (to-inst [d]) (to-db-date [d]) (format-date [date]) (before [d1 d2]) - (after [d1 d2])) + (after [d1 d2]) + (minus [d amount unit]) + (plus [d amount unit])) (extend-type Instant TimeHelpers @@ -27,7 +47,9 @@ (.withZone ZoneOffset/UTC) (.format date))) (before [d1 d2] (.isBefore d1 d2)) - (after [d1 d2] (.isBefore d2 d1))) + (after [d1 d2] (.isBefore d2 d1)) + (plus [d amount unit] (.plus d amount (chrono-units unit))) + (minus [d amount unit] (.minus d amount (chrono-units unit)))) (extend-type java.util.Date TimeHelpers @@ -35,7 +57,9 @@ (to-db-date [d] (-> d to-inst to-db-date)) (format-date [date] (format-date (to-inst date))) (before [d1 d2] (< (.compareTo d1 d2) 0)) - (after [d1 d2] (> (.compareTo d1 d2) 0))) + (after [d1 d2] (> (.compareTo d1 d2) 0)) + (plus [d amount unit] (plus (to-inst d) amount unit)) + (minus [d amount unit] (minus (to-inst d) amount unit))) (extend-type java.lang.String TimeHelpers @@ -43,10 +67,12 @@ (to-db-date [d] (-> d to-inst to-db-date)) (format-date [date] (format-date (to-inst date))) (before [d1 d2] (before (to-inst d1) (to-inst d2))) - (after [d1 d2] (after (to-inst d1) (to-inst d2)))) + (after [d1 d2] (after (to-inst d1) (to-inst d2))) + (plus [d amount unit] (plus (to-inst d) amount unit)) + (minus [d amount unit] (minus (to-inst d) amount unit))) -(defn earliest [& ds] (->> ds (map to-inst) (sort before) first)) -(defn latest [& ds] (->> ds (map to-inst) (sort after) first)) +(defn earliest [& ds] (->> ds (remove nil?) (map to-inst) (sort before) first)) +(defn latest [& ds] (->> ds (remove nil?) (map to-inst) (sort after) first)) (defn between [d1 d2 d3] (and (not (before d2 d1)) (not (after d2 d3)))) (defn same-day [d1 d2] (when (and d1 d2) @@ -86,6 +112,7 @@ (keep-indexed (fn [i d] (when (same-day d day) i))) first)) +;; Recurrence handlers (def freq-units {"day" Freq/DAILY "week" Freq/WEEKLY "month" Freq/MONTHLY "year" Freq/YEARLY}) (defn set-freq [rule freq] (.toString diff --git a/backend/test/chicken_master/orders_test.clj b/backend/test/chicken_master/orders_test.clj index 01e3dc7..783b6c3 100644 --- a/backend/test/chicken_master/orders_test.clj +++ b/backend/test/chicken_master/orders_test.clj @@ -165,10 +165,10 @@ (is (= table :orders)) (is (= by {:id 1 :user_id :user-id}))) sql/query (constantly (raw-order-row :id 4))] - (is (= (sut/delete! :user-id nil nil 1) - {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", + (is (= {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", :who {:id 2, :name "mr blobby"}, :recurrence nil - :products {:eggs {:amount 12 :price nil} :milk {:amount 3 :price 423}}}]})))) + :products {:eggs {:amount 12 :price nil} :milk {:amount 3 :price 423}}}]} + (sut/delete! :user-id nil nil 1))))) (testing "nothing returned if no date set for the given order" (with-redefs [jdbc/transact (fn [_ f & args] (apply f args)) @@ -191,19 +191,19 @@ sql/insert! (fn [_ table values] (swap! invocations conj ["inserting" table values]))] (testing "deleting without provided a date will remove the whole order" (reset! invocations []) - (is (= (sut/delete! :user-id nil nil 1) - {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", + (is (= {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", :who {:id 2, :name "mr blobby"}, :recurrence nil - :products {:eggs {:amount 12 :price nil} :milk {:amount 3 :price 423}}}]})) + :products {:eggs {:amount 12 :price nil} :milk {:amount 3 :price 423}}}]} + (sut/delete! :user-id nil nil 1))) (is (= [["deleting" :orders {:id 1 :user_id :user-id}]] @invocations))) (testing "a provided date is ignored and will full delete" (reset! invocations []) - (is (= (sut/delete! :user-id "2020-01-01" nil 1) - {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", + (is (= {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", :who {:id 2, :name "mr blobby"}, :recurrence nil - :products {:eggs {:amount 12 :price nil} :milk {:amount 3 :price 423}}}]})) + :products {:eggs {:amount 12 :price nil} :milk {:amount 3 :price 423}}}]} + (sut/delete! :user-id "2020-01-01" nil 1))) (is (= [["deleting" :orders {:id 1 :user_id :user-id}]] @invocations))) @@ -213,10 +213,10 @@ {:orders/order_date #inst "2020-01-01"}))] (reset! invocations []) - (is (= (sut/delete! :user-id "2020-01-01" :single 1) - {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", + (is (= {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", :who {:id 2, :name "mr blobby"}, :recurrence nil - :products {:eggs {:amount 12 :price nil} :milk {:amount 3 :price 423}}}]})) + :products {:eggs {:amount 12 :price nil} :milk {:amount 3 :price 423}}}]} + (sut/delete! :user-id "2020-01-01" :single 1))) (is (= [["deleting" :orders {:id 1 :user_id :user-id}]] @invocations))))))) diff --git a/frontend/src/chicken_master/calendar.cljs b/frontend/src/chicken_master/calendar.cljs index 4a37ce1..c98288d 100644 --- a/frontend/src/chicken_master/calendar.cljs +++ b/frontend/src/chicken_master/calendar.cljs @@ -117,7 +117,7 @@ :order-type-edit [:div (html/input :single "tylko to" {:type :radio :name :type-choose :defaultChecked true}) - ;; (html/input :from-here "od tego" {:type :radio :name :type-choose}) + (html/input :from-here "od tego" {:type :radio :name :type-choose}) (html/input :all "wszystkie" {:type :radio :name :type-choose})] ;; On success :on-submit (fn [form] (re-frame/dispatch (conj event (form "type-choose" "single"))) :close-modal))))