From 4aa84bb46596f7ede33a870f5f8f727ee15d72f7 Mon Sep 17 00:00:00 2001 From: Daniel O'Connell Date: Thu, 12 May 2022 21:45:28 +0200 Subject: [PATCH] allow deleting from date --- backend/src/chicken_master/orders.clj | 27 ++++++++++++---- backend/src/chicken_master/time.clj | 18 +++++++++-- backend/test/chicken_master/orders_test.clj | 34 +++++++++++++-------- 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/backend/src/chicken_master/orders.clj b/backend/src/chicken_master/orders.clj index 0ae12f9..15ea4d9 100644 --- a/backend/src/chicken_master/orders.clj +++ b/backend/src/chicken_master/orders.clj @@ -173,9 +173,9 @@ (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 get-fortnight [tx user-id & days] + (let [fortnight-after-earliest (t/plus (apply t/earliest days) 14 :days)] + (apply orders-for-days tx user-id fortnight-after-earliest days))) (defn replace! ([user-id order] (jdbc/with-transaction [tx db/db-uri] (replace! tx user-id order))) @@ -185,7 +185,7 @@ (products/update-products-mapping! tx user-id :order (upsert-order! tx user-id customer-id order) products) - (get-fortnight tx user-id (t/earliest day order-date))))) + (get-fortnight tx user-id day order-date)))) (defn change-state! "Update the state of the given order and also modify the number of products available: @@ -214,6 +214,21 @@ (sql/delete! tx :orders {:id id :user_id user-id}) (get-fortnight tx user-id (t/earliest order_date end_date)))) +(defn- delete-from-date [tx user-id id from-date] + (when-let [{:orders/keys [order_date recurrence] :as order} (some->> id (db/get-by-id tx user-id :orders))] + (if (t/same-day order_date from-date) + ;; deleting from the first date just means removing them all + (full-delete tx user-id id) + ;; deleting from a given date should update the recurrence rule to end with the given date and + ;; update the `end_date` field + (do + (sql/update! tx :orders + (set-dates order {:recurrence (t/recur-until order_date recurrence from-date)}) + {:id id}) + (->> (t/plus from-date 14 :days) + (t/dates-between order_date recurrence from-date) + (apply orders-for-days tx user-id)))))) + (defn delete! [user-id day action-type id] (jdbc/with-transaction [tx db/db-uri] (cond @@ -222,8 +237,8 @@ (= "all" action-type)) (full-delete tx user-id id) - (= "from-here" action-type) nil - ;; TODO: handle partial deletions + (= "from-here" action-type) + (delete-from-date tx user-id id day) ;; Only delete the one day :else diff --git a/backend/src/chicken_master/time.clj b/backend/src/chicken_master/time.clj index 83e0ddc..4bfd089 100644 --- a/backend/src/chicken_master/time.clj +++ b/backend/src/chicken_master/time.clj @@ -91,6 +91,13 @@ (repeatedly #(when (.hasNext iterator) (-> iterator (.nextDateTime) (.getTimestamp) (Instant/ofEpochMilli))))))) +(defn dates-between + "Get all dates between `from` and `to` (inclusive)" + [start rule from to] + (->> (recurrence->dates (to-inst start) rule) + (drop-while (partial after (to-inst from))) + (take-while #(not (after % (to-inst to)))))) + (defn next-date "Get the next date after `day`" [start rule day] @@ -161,10 +168,17 @@ :else nil))) +(defn recur-until + "Update the rule to ensure it ends before `date`" + [start rule date] + (if (get-until rule) + (set-until rule date) + (set-count rule (recurrence-pos start rule date)))) + (defn make-rule [{:keys [times until unit every]}] (let [rule (-> nil - (set-freq unit) - (set-interval every))] + (set-freq (or unit "day")) + (set-interval (or every 1)))] (if times (set-count rule times) (set-until rule until)))) diff --git a/backend/test/chicken_master/orders_test.clj b/backend/test/chicken_master/orders_test.clj index 783b6c3..eb41bc1 100644 --- a/backend/test/chicken_master/orders_test.clj +++ b/backend/test/chicken_master/orders_test.clj @@ -102,7 +102,8 @@ (raw-order-row :id 1 :status "waiting") (raw-order-row :id 4)))] (is (= (sut/replace! :user-id order) - {"2020-01-01" [{:id 1, :notes "note", :state :waiting, :day "2020-01-01", + {"2020-01-15" {} + "2020-01-01" [{:id 1, :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}}} {:id 4, :notes "note", :state :waiting, :day "2020-01-01", @@ -126,7 +127,8 @@ sql/query (constantly (concat (raw-order-row :id 1 :status "waiting" :date #inst "2020-01-02") (raw-order-row :id 4)))] - (is (= {"2020-01-02" [{:id 1, :notes "note", :recurrence nil, + (is (= {"2020-01-16" {} + "2020-01-02" [{:id 1, :notes "note", :recurrence nil, :who {:id 2, :name "mr blobby"}, :day "2020-01-02", :state :waiting :products {:eggs {:amount 12, :price nil}, :milk {:amount 3, :price 423}}}]} @@ -150,7 +152,8 @@ (raw-order-row :id 1 :status "waiting") (raw-order-row :id 4)))] (is (= (sut/replace! :user-id order) - {"2020-01-01" [{:id 1, :notes "note", :state :waiting, :day "2020-01-01", + {"2020-01-15" {} + "2020-01-01" [{:id 1, :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}}} {:id 4, :notes "note", :state :waiting, :day "2020-01-01", @@ -165,7 +168,8 @@ (is (= table :orders)) (is (= by {:id 1 :user_id :user-id}))) sql/query (constantly (raw-order-row :id 4))] - (is (= {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", + (is (= {"2020-01-15" {} + "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}}}]} (sut/delete! :user-id nil nil 1))))) @@ -191,7 +195,8 @@ 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 (= {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", + (is (= {"2020-01-15" {} + "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}}}]} (sut/delete! :user-id nil nil 1))) @@ -200,7 +205,8 @@ (testing "a provided date is ignored and will full delete" (reset! invocations []) - (is (= {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", + (is (= {"2020-01-15" {} + "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}}}]} (sut/delete! :user-id "2020-01-01" nil 1))) @@ -213,7 +219,8 @@ {:orders/order_date #inst "2020-01-01"}))] (reset! invocations []) - (is (= {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", + (is (= {"2020-01-15" {} + "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}}}]} (sut/delete! :user-id "2020-01-01" :single 1))) @@ -232,19 +239,20 @@ sql/insert! (fn [_ table values] (swap! invocations conj ["inserting" table values]))] (testing "deleting with \"all\" removes the whole order" (reset! invocations []) - (is (= (sut/delete! :user-id nil "all" 1) - {"2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", + (is (= {"2020-01-15" {} + "2020-01-01" [{:id 4, :notes "note", :state :waiting, :day "2020-01-01", :who {:id 2, :name "mr blobby"}, :recurrence {:times 1, :until nil, :unit "day", :every 1} - :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 "all" 1))) (is (= [["deleting" :orders {:id 1 :user_id :user-id}]] @invocations))) (testing "deleting with a provided date will soft remove a single order by updating it if it exists" (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 {:times 1, :until nil, :unit "day", :every 1} - :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 (= [["updating" :recurrence_exceptions {:status "canceled"} {:order_id 1, :order_date (t/to-db-date "2020-01-01")}]] @invocations)))