From dfab94cf8d6f83ef7566298b48d59f967ff64270 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Thu, 19 Feb 2026 11:32:16 +0930 Subject: [PATCH 1/3] test(bookings): [PPT-2346] include_deleted/deleted flags --- spec/controllers/bookings_spec.cr | 90 +++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/spec/controllers/bookings_spec.cr b/spec/controllers/bookings_spec.cr index 0d42476a..f3e50953 100644 --- a/spec/controllers/bookings_spec.cr +++ b/spec/controllers/bookings_spec.cr @@ -552,6 +552,96 @@ describe Bookings do end end end + + context "[include_deleted/deleted flags]", tags: "include-deleted" do + it "returns only non-deleted bookings by default" do + tenant = get_tenant + + booking1 = BookingsHelper.create_booking(tenant.id.not_nil!) + booking2 = BookingsHelper.create_booking(tenant.id.not_nil!) + booking2.deleted = true + booking2.deleted_at = Time.utc.to_unix + booking2.save! + + starting = 5.minutes.from_now.to_unix + ending = 90.minutes.from_now.to_unix + zones_string = "#{booking1.zones.not_nil!.first},#{booking2.zones.not_nil!.first}" + + route = "#{BOOKINGS_BASE}?period_start=#{starting}&period_end=#{ending}&type=desk&zones=#{zones_string}" + response = client.get(route, headers: headers) + response.status_code.should eq(200) + bookings = JSON.parse(response.body).as_a + bookings.size.should eq(1) + bookings.map(&.["id"].as_i64).should contain(booking1.id) + bookings.map(&.["id"].as_i64).should_not contain(booking2.id) + end + + it "returns only deleted bookings when deleted=true" do + tenant = get_tenant + + booking1 = BookingsHelper.create_booking(tenant.id.not_nil!) + booking2 = BookingsHelper.create_booking(tenant.id.not_nil!) + booking2.deleted = true + booking2.deleted_at = Time.utc.to_unix + booking2.save! + + starting = 5.minutes.from_now.to_unix + ending = 90.minutes.from_now.to_unix + zones_string = "#{booking1.zones.not_nil!.first},#{booking2.zones.not_nil!.first}" + + route = "#{BOOKINGS_BASE}?period_start=#{starting}&period_end=#{ending}&type=desk&zones=#{zones_string}&deleted=true" + response = client.get(route, headers: headers) + response.status_code.should eq(200) + bookings = JSON.parse(response.body).as_a + bookings.size.should eq(1) + bookings.map(&.["id"].as_i64).should_not contain(booking1.id) + bookings.map(&.["id"].as_i64).should contain(booking2.id) + end + + it "returns all bookings when include_deleted=true" do + tenant = get_tenant + + booking1 = BookingsHelper.create_booking(tenant.id.not_nil!) + booking2 = BookingsHelper.create_booking(tenant.id.not_nil!) + booking2.deleted = true + booking2.deleted_at = Time.utc.to_unix + booking2.save! + + starting = 5.minutes.from_now.to_unix + ending = 90.minutes.from_now.to_unix + zones_string = "#{booking1.zones.not_nil!.first},#{booking2.zones.not_nil!.first}" + + route = "#{BOOKINGS_BASE}?period_start=#{starting}&period_end=#{ending}&type=desk&zones=#{zones_string}&include_deleted=true" + response = client.get(route, headers: headers) + response.status_code.should eq(200) + bookings = JSON.parse(response.body).as_a + bookings.size.should eq(2) + bookings.map(&.["id"].as_i64).should contain(booking1.id) + bookings.map(&.["id"].as_i64).should contain(booking2.id) + end + + it "returns all bookings when include_deleted=true and deleted=true" do + tenant = get_tenant + + booking1 = BookingsHelper.create_booking(tenant.id.not_nil!) + booking2 = BookingsHelper.create_booking(tenant.id.not_nil!) + booking2.deleted = true + booking2.deleted_at = Time.utc.to_unix + booking2.save! + + starting = 5.minutes.from_now.to_unix + ending = 90.minutes.from_now.to_unix + zones_string = "#{booking1.zones.not_nil!.first},#{booking2.zones.not_nil!.first}" + + route = "#{BOOKINGS_BASE}?period_start=#{starting}&period_end=#{ending}&type=desk&zones=#{zones_string}&include_deleted=true&deleted=true" + response = client.get(route, headers: headers) + response.status_code.should eq(200) + bookings = JSON.parse(response.body).as_a + bookings.size.should eq(2) + bookings.map(&.["id"].as_i64).should contain(booking1.id) + bookings.map(&.["id"].as_i64).should contain(booking2.id) + end + end end describe "#booked" do From 298d2b516c79624949a58a35942c7418bdf373e3 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Thu, 19 Feb 2026 11:32:52 +0930 Subject: [PATCH 2/3] feat(bookings): [PPT-2346] include_deleted flag --- src/controllers/bookings.cr | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/controllers/bookings.cr b/src/controllers/bookings.cr index ecd324b0..7e673a18 100644 --- a/src/controllers/bookings.cr +++ b/src/controllers/bookings.cr @@ -142,7 +142,9 @@ class Bookings < Application ending : Int64 = 1.hours.from_now.to_unix, @[AC::Param::Info(name: "type", description: "the generic name of the asset whose bookings you wish to view", example: "desk")] booking_type : String? = nil, - @[AC::Param::Info(name: "deleted", description: "when true, it returns deleted bookings", example: "true")] + @[AC::Param::Info(description: "when true, returns all bookings including deleted ones", example: "true")] + include_deleted : Bool = false, + @[AC::Param::Info(name: "deleted", description: "when true, only returns deleted bookings, unless `include_deleted=true`", example: "true")] deleted_flag : Bool = false, @[AC::Param::Info(description: "when true, returns all bookings including checked out ones", example: "true")] include_checked_out : Bool = false, @@ -242,7 +244,7 @@ class Bookings < Application end {% end %} - query = query.where(deleted: deleted_flag) + query = query.where(deleted: deleted_flag) unless include_deleted unless include_checked_out # query = checked_out_flag ? query.where("checked_out_at != ?", nil) : query.where(checked_out_at: nil) From 9f619d25b04e4ae93b2283c2809d461cab27e531 Mon Sep 17 00:00:00 2001 From: Mia Bennett Date: Thu, 19 Feb 2026 11:44:08 +0930 Subject: [PATCH 3/3] docs(bookings): [PPT-2346] include_deleted/deleted flags --- OPENAPI_DOC.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OPENAPI_DOC.yml b/OPENAPI_DOC.yml index a8af15ee..b30147f2 100644 --- a/OPENAPI_DOC.yml +++ b/OPENAPI_DOC.yml @@ -37,9 +37,15 @@ paths: schema: type: string nullable: true + - name: include_deleted + in: query + description: when true, returns all bookings including deleted ones + example: "true" + schema: + type: boolean - name: deleted in: query - description: when true, it returns deleted bookings + description: when true, only returns deleted bookings, unless `include_deleted=true` example: "true" schema: type: boolean