Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NUOPEN-6][Shared dev] Daily rate with fixed start time: create a reservation #4863

Merged
merged 7 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 6 additions & 31 deletions app/assets/javascripts/app/manage_instruments.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,36 +51,11 @@ $(function() {

const dailyBooking = dailyBookingRadioButton.checked;

const reserveIntervalElement = document.querySelector(
".js--reserve-interval"
);
const minReserveMinsElement = document.querySelector(
".js--min-reserve-mins"
);
const maxReserveMinsElement = document.querySelector(
".js--max-reserve-mins"
);
const minReserveDaysElement = document.querySelector(
".js--min-reserve-days"
);
const maxReserveDaysElement = document.querySelector(
".js--max-reserve-days"
);

[minReserveDaysElement, maxReserveDaysElement].forEach((element) => {
if (element) {
element.toggleAttribute("hidden", !dailyBooking);
}
});

[
reserveIntervalElement,
minReserveMinsElement,
maxReserveMinsElement,
].forEach((element) => {
if (element) {
element.toggleAttribute("hidden", dailyBooking);
}
});
document
.querySelectorAll(".js--daily-booking")
.forEach((element) => element.toggleAttribute("hidden", !dailyBooking));
document
.querySelectorAll(".js--normal-booking")
.forEach((element) => element.toggleAttribute("hidden", dailyBooking));
});
});
4 changes: 3 additions & 1 deletion app/controllers/instruments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ def switch
def permitted_params
params = super

(params += %i[min_reserve_days max_reserve_days]) if can?(:create_daily_booking, Instrument)
if can?(:create_daily_booking, Instrument)
params += %i[min_reserve_days max_reserve_days start_time_disabled]
end

params
end
Expand Down
15 changes: 12 additions & 3 deletions app/services/reservation_creator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class ReservationCreator
attr_reader :order, :order_detail, :params, :error

delegate :merged_order?, :instrument_only_order?, to: :status_q
delegate :product, to: :order_detail

def initialize(order, order_detail, params)
@order = order
Expand Down Expand Up @@ -68,7 +69,7 @@ def reservation
private

def reservation_create_params
duration_field = if @order_detail.product.daily_booking?
duration_field = if order_detail.product.daily_booking?
:duration_days
else
:duration_mins
Expand All @@ -86,8 +87,16 @@ def reservation_create_params
:project_id,
duration_field,
).merge(
product: @order_detail.product,
)
product:,
).tap do |reservation_params|
if product.start_time_disabled?
reservation_params.merge!(
reserve_start_hour: 0,
reserve_start_min: 0,
reserve_start_meridian: "AM"
)
end
end
end

def update_order_account
Expand Down
16 changes: 11 additions & 5 deletions app/views/instruments/_instrument_fields.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,33 @@
collection: Instrument::RESERVE_INTERVALS,
label: text("instruments.instrument_fields.reservation.label.reserve_interval"),
hint: text("instruments.instrument_fields.reservation.instruct.reserve_interval"),
wrapper_html: { class: "js--reserve-interval", hidden: daily_booking }
wrapper_html: { class: "js--normal-booking", hidden: daily_booking }

= f.input :min_reserve_mins,
label: text("instruments.instrument_fields.reservation.label.min_reserve_mins"),
hint: text("instruments.instrument_fields.reservation.instruct.min_reserve"),
wrapper_html: { class: "js--min-reserve-mins", hidden: daily_booking }
wrapper_html: { class: "js--normal-booking", hidden: daily_booking }

= f.input :max_reserve_mins,
label: text("instruments.instrument_fields.reservation.label.max_reserve_mins"),
hint: text("instruments.instrument_fields.reservation.instruct.max_reserve"),
wrapper_html: { class: "js--max-reserve-mins", hidden: daily_booking }
wrapper_html: { class: "js--normal-booking", hidden: daily_booking }

= f.input :start_time_disabled, as: :boolean,
label: false,
inline_label: Instrument.human_attribute_name(:start_time_disabled),
hint: text("instruments.instrument_fields.reservation.instruct.start_time_disabled"),
wrapper_html: { class: "js--daily-booking", hidden: !daily_booking }

= f.input :min_reserve_days,
label: text("instruments.instrument_fields.reservation.label.min_reserve_days"),
hint: text("instruments.instrument_fields.reservation.instruct.min_reserve"),
wrapper_html: { class: "js--min-reserve-days", hidden: !daily_booking }
wrapper_html: { class: "js--daily-booking", hidden: !daily_booking }

= f.input :max_reserve_days,
label: text("instruments.instrument_fields.reservation.label.max_reserve_days"),
hint: text("instruments.instrument_fields.reservation.instruct.max_reserve"),
wrapper_html: { class: "js--max-reserve-days", hidden: !daily_booking }
wrapper_html: { class: "js--daily-booking", hidden: !daily_booking }

= f.input :min_cancel_hours,
label: text("instruments.instrument_fields.reservation.label.cancel_hours"),
Expand Down
1 change: 1 addition & 0 deletions app/views/instruments/_instrument_manage_fields.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
= f.input :pricing_mode

- if daily_booking
= f.input :start_time_disabled
= f.input :min_reserve_days, value_method: :to_i, default_value: "None"
= f.input :max_reserve_days, value_method: :to_i, default_value: "None"
- else
Expand Down
26 changes: 17 additions & 9 deletions app/views/reservations/_reservation_fields.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
- start_disabled = start_time_editing_disabled?(f.object)
- instrument = f.object.product

.well.js--reservationValidations
.container
.row
Expand All @@ -9,28 +11,34 @@
= text_field_tag "reservation[reserve_start_date]", f.object.reserve_start_date, class: "datepicker string optional span3", disabled: start_disabled
- if f.object.actual_start_at?
.started-at= "Started: #{l(f.object.actual_start_at, format: :usa)}"
.span4
= time_select f, :reserve_start, { minute_step: f.object.product.reserve_interval }, disabled: start_disabled
- if instrument.start_time_disabled?
= time_select f, :reserve_start, { minute_step: 60 }, disabled: true, hidden: true
- else
.span4
= time_select f, :reserve_start, { minute_step: instrument.reserve_interval }, disabled: start_disabled
= label_tag :reservation_reserve_end_date, "Reserve End", class: "string optional control-label"
.row
- if local_assigns[:daily_booking]
- if instrument.daily_booking?
.span3
= f.text_field :reserve_end_date,
class: "datepicker string optional span3",
disabled: true
.span4
= time_select f, :reserve_end,
{ minute_step: f.object.product.reserve_interval },
disabled: true
- if instrument.start_time_disabled?
= time_select f, :reserve_end, { minute_step: 60 }, disabled: true, hidden: true
- else
.span4
= time_select f, :reserve_end,
{ minute_step: instrument.reserve_interval },
disabled: true
- else
.span3
= text_field_tag "reservation[reserve_end_date]", f.object.reserve_end_date,
class: "datepicker string optional span3"
.span4
= time_select f, :reserve_end, { minute_step: f.object.product.reserve_interval }
= time_select f, :reserve_end, { minute_step: instrument.reserve_interval }

.span5
- if local_assigns[:daily_booking]
- if instrument.daily_booking?
= f.input :duration_days, input_html: { value: f.object.duration_days || 1 }
- else
= f.input :duration_mins, hint: text(".duration_hint"),
Expand Down
4 changes: 2 additions & 2 deletions app/views/reservations/edit.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
required: @order_detail.product.user_notes_field_mode.required?,
hint: t("reservations.account_field.note_hint")

= render "reservation_fields", f: f, daily_booking: @instrument.daily_booking?
= render "reservation_fields", f: f

%ul.inline
%li= f.submit t('shared.save'), class: 'btn'
Expand All @@ -42,7 +42,7 @@
- else
%li= link_to t('shared.cancel'), cart_path

- if @instrument.daily_booking?
- if @instrument.daily_booking? && !@instrument.start_time_disabled?
= render "reservations/open_hours"

#overlay
Expand Down
4 changes: 2 additions & 2 deletions app/views/reservations/new.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
= simple_form_for [@order, @order_detail, @reservation], html: { class: "js--reservationForm js--reservationUpdateCreateAndStart" }, url: @submit_action do |f|
= f.error_messages
= render "reservations/account_field", f: f unless @order_detail.bundled?
= render "reservations/reservation_fields", f: f, daily_booking: @instrument.daily_booking?
= render "reservations/reservation_fields", f: f

- if acting_as?
.row
Expand Down Expand Up @@ -63,7 +63,7 @@
- else
= link_to t("shared.cancel"), facility_path(@instrument.facility)

- if @instrument.daily_booking?
- if @instrument.daily_booking? && !@instrument.start_time_disabled?
= render "reservations/open_hours"

#overlay
Expand Down
1 change: 1 addition & 0 deletions config/locales/en.models.yml
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ en:
product_ids: Products
ungrouped_product_ids: Ungrouped
instrument:
start_time_disabled: Start Time Disabled
min_reserve_mins: Minimum Reservation Minutes
max_reserve_mins: Maximum Reservation Minutes
min_cancel_hours: Reservation Cost Window (hours)
Expand Down
1 change: 1 addition & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,7 @@ en:
When blank or set to 0, the system will not cancel unstarted reservations.
lock_window: "Window of time within which a customer may no longer move their reservation. Cancellations are permitted but may invoke a fee."
cutoff_hours: "Minimum number of hours before instrument can be reserved."
start_time_disabled: Reservations always start at the beginning of the day
label:
restrict: "Reservation Restrictions"
reserve_interval: "Interval (minutes)"
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20241212185208_add_product_start_time_disabled.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddProductStartTimeDisabled < ActiveRecord::Migration[7.0]
def change
add_column :products, :start_time_disabled, :boolean, default: false, null: false
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.0].define(version: 2024_10_22_135335) do
ActiveRecord::Schema[7.0].define(version: 2024_12_12_185208) do
create_table "account_facility_joins", id: :integer, charset: "utf8mb3", force: :cascade do |t|
t.integer "facility_id", null: false
t.integer "account_id", null: false
Expand Down Expand Up @@ -663,6 +663,7 @@
t.boolean "cross_core_ordering_available", default: false, null: false
t.integer "min_reserve_days"
t.integer "max_reserve_days"
t.boolean "start_time_disabled", default: false, null: false
t.index ["dashboard_token"], name: "index_products_on_dashboard_token"
t.index ["facility_account_id"], name: "fk_facility_accounts"
t.index ["facility_id"], name: "fk_rails_0c9fa1afbe"
Expand Down
45 changes: 45 additions & 0 deletions spec/support/shared_examples/reservations_new_daily.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@
#
RSpec.shared_examples "new daily reservation" do |before_submit: nil, after_submit: nil|
it "creates a daily reservation", :js do
expect(instrument.daily_booking?).to be true

visit reservation_path

# Form and open hour table to be axe clean
expect(page).to be_axe_clean.within(".simple_form")
expect(page).to be_axe_clean.within(".open-hours")

expect(page).to have_content("Create Reservation")
expect(page).to have_content("Reserve Start")
expect(page).to have_content("Reserve End")
expect(page).to have_content("Duration Days")

# Start time availability table is present
Expand Down Expand Up @@ -66,3 +70,44 @@
instance_eval(&after_submit) if after_submit.present?
end
end

# Examples that create a reservation with a daily booking
# instrument with start time disabled.
#
# See "new daily reservation" shared examples to
# see requirements
#
RSpec.shared_examples "new daily reservation with start time disabled" do |before_submit: nil, after_submit: nil|
it "creates a reservation" do
expect(instrument.daily_booking?).to be true
expect(instrument.start_time_disabled?).to be true

visit reservation_path

expect(page).to have_content("Reserve Start")
expect(page).to have_content("Reserve End")
expect(page).to have_content("Duration Days")

expect(page).to_not have_field("reservation[reserve_start_hour]")
expect(page).to_not have_field("reservation[reserve_start_min]")
expect(page).to_not have_field("reservation[reserve_start_meridian]")

expect(page).to_not have_content("Start Time Availability")

fill_in("Reserve Start", with: I18n.l(1.day.from_now.to_date, format: :usa))

instance_eval(&before_submit) if before_submit.present?

click_button("Create")

expect(page).to have_content(
if defined?(success_message)
success_message
else
"Reservation created successfully"
end
)

instance_eval(&after_submit) if after_submit.present?
end
end
28 changes: 28 additions & 0 deletions spec/system/admin/creating_an_instrument_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
expect(page).to_not have_element(Instrument::Pricing::SCHEDULE_DAILY)
end
end

context "as administrator" do
let(:user) { create(:user, :administrator) }
let(:instrument) { Instrument.last }

before do
login_as user
Expand All @@ -40,6 +42,7 @@
expect(page).to have_field("Maximum (minutes)")
expect(page).not_to have_field("Minimum (days)")
expect(page).not_to have_field("Maximum (days)")
expect(page).not_to have_field("Start Time Disabled")

expect(page).to have_content(Instrument::Pricing::SCHEDULE_DAILY)

Expand All @@ -50,6 +53,7 @@
expect(page).not_to have_field("Maximum (minutes)")
expect(page).to have_field("Maximum (days)")
expect(page).to have_field("Minimum (days)")
expect(page).to have_field("Start Time Disabled")

fill_in "Minimum (days)", with: "5"
fill_in "Maximum (days)", with: "10"
Expand All @@ -61,9 +65,33 @@
expect(page).to have_content("Schedule Rule (Daily Booking only)")
expect(page).to have_content("Min reserve days")
expect(page).to have_content("Max reserve days")
expect(page).to have_content("Start Time Disabled")
expect(page).not_to have_content("Interval minutes")
expect(page).not_to have_content("Min reserve minutes")
expect(page).not_to have_content("Max reserve minutes")

expect(instrument.min_reserve_days).to eq(5)
expect(instrument.max_reserve_days).to eq(10)
expect(instrument.start_time_disabled).to be false
end

it "can create an instrument with fixed time" do
visit facility_products_path(facility)
click_link "Instruments (0)", exact: true
click_link "Add Instrument"

fill_in "Name", with: "Daily Booking Instrument", match: :first
fill_in "URL Name", with: "daily-booking-instrument"

choose Instrument::Pricing::SCHEDULE_DAILY

check("Start Time Disabled")

click_button "Create"

expect(page).to have_content("Instrument was successfully created")

expect(instrument.start_time_disabled).to be true
end
end
end
Expand Down
Loading
Loading