diff --git a/app/controllers/api/payzen_controller.rb b/app/controllers/api/payzen_controller.rb index 15b8a9251..acc47ea14 100644 --- a/app/controllers/api/payzen_controller.rb +++ b/app/controllers/api/payzen_controller.rb @@ -55,9 +55,8 @@ class API::PayzenController < API::PaymentsController def check_cart cart = shopping_cart - unless cart.valid? - render json: { error: 'unable to pay' }, status: :unprocessable_entity and return - end + render json: { error: 'unable to pay' }, status: :unprocessable_entity and return unless cart.valid? + render json: { cart: 'ok' }, status: :ok end diff --git a/app/controllers/api/reservations_controller.rb b/app/controllers/api/reservations_controller.rb index d0ef06b8c..42cab8487 100644 --- a/app/controllers/api/reservations_controller.rb +++ b/app/controllers/api/reservations_controller.rb @@ -43,6 +43,6 @@ class API::ReservationsController < API::ApiController def reservation_params params.require(:reservation).permit(:message, :reservable_id, :reservable_type, :nb_reserve_places, tickets_attributes: %i[event_price_category_id booked], - slots_attributes: %i[id start_at end_at availability_id offered]) + slots_reservations_attributes: %i[id slot_id offered]) end end diff --git a/app/frontend/src/javascript/controllers/events.js.erb b/app/frontend/src/javascript/controllers/events.js.erb index 07022eae9..afabe1660 100644 --- a/app/frontend/src/javascript/controllers/events.js.erb +++ b/app/frontend/src/javascript/controllers/events.js.erb @@ -360,7 +360,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' reservation: { reservable_id: $scope.event.id, reservable_type: 'Event', - slots_attributes: [], + slots_reservations_attributes: [], nb_reserve_places: $scope.reserve.nbReservePlaces, tickets_attributes: [] } @@ -368,10 +368,8 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' ] } // a single slot is used for events - cartItems.items[0].reservation.slots_attributes.push({ - start_at: $scope.event.start_date, - end_at: $scope.event.end_date, - availability_id: $scope.event.availability.id + cartItems.items[0].reservation.slots_reservations_attributes.push({ + slot_id: $scope.event.slot_id }); // iterate over reservations per prices for (let price_id in $scope.reserve.tickets) { @@ -405,7 +403,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' /** * Callback to cancel a reservation - * @param reservation {{id:number, reservable_id:number, nb_reserve_places:number, slots_attributes:[{id: number, canceled_at: string}], total_booked_seats: number}} + * @param reservation {Reservation} */ $scope.cancelReservation = function(reservation) { dialogs.confirm({ @@ -434,17 +432,17 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' /** * Test if the provided reservation has been cancelled - * @param reservation {{slots_attributes: [{canceled_at: string}]}} + * @param reservation {Reservation} * @returns {boolean} */ $scope.isCancelled = function(reservation) { - return !!(reservation.slots_attributes[0].canceled_at); + return !!(reservation.slots_reservations_attributes[0].canceled_at); } /** * Callback to alter an already booked reservation date. A modal window will be opened to allow the user to choose * a new date for his reservation (if any available) - * @param reservation {{id:number, reservable_id:number, nb_reserve_places:number}} + * @param reservation {Reservation} */ $scope.modifyReservation = function (reservation) { const index = $scope.reservations.indexOf(reservation); @@ -475,9 +473,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' return eventToPlace = e; } }); - $scope.reservation.slots_reservations_attributes[0].start_at = eventToPlace.start_date; - $scope.reservation.slots_reservations_attributes[0].end_at = eventToPlace.end_date; - $scope.reservation.slots_reservations_attributes[0].availability_id = eventToPlace.availability_id; + $scope.reservation.slots_reservations_attributes[0].slot_id = eventToPlace.slot_id; $scope.attempting = true; Reservation.update({ id: reservation.id }, { reservation: $scope.reservation }, function (reservation) { $uibModalInstance.close(reservation); @@ -514,10 +510,10 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' /** * Checks if the provided reservation is able to be moved (date change) - * @param reservation {{slots_attributes:[], total_booked_seats:number}} + * @param reservation {Reservation} */ $scope.reservationCanModify = function (reservation) { - const slotStart = moment(reservation.slots_attributes[0].start_at); + const slotStart = moment(reservation.slots_reservations_attributes[0].slot_attributes.start_at); const now = moment(); let isAble = false; @@ -529,10 +525,10 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' /** * Checks if the provided reservation is able to be cancelled - * @param reservation {{slots_attributes:[]}} + * @param reservation {Reservation} */ $scope.reservationCanCancel = function(reservation) { - const slotStart = moment(reservation.slots_attributes[0].start_at); + const slotStart = moment(reservation.slots_reservations_attributes[0].slot_attributes.start_at); const now = moment(); return $scope.enableBookingCancel && slotStart.diff(now, "hours") >= $scope.cancelBookingDelay; }; @@ -653,22 +649,20 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' * Create a hash map implementing the Reservation specs * @param reserve {Object} Reservation parameters (places...) * @param event {Object} Current event - * @return {{reservation: {reservable_id:number, reservable_type:string, slots_attributes:Array, nb_reserve_places:number}}} + * @return {{reservation: Reservation}} */ const mkReservation = function (reserve, event) { const reservation = { reservable_id: event.id, reservable_type: 'Event', - slots_attributes: [], + slots_reservations_attributes: [], nb_reserve_places: reserve.nbReservePlaces, tickets_attributes: [] }; - reservation.slots_attributes.push({ - start_at: event.start_date, - end_at: event.end_date, - availability_id: event.availability.id, - offered: event.offered || false + reservation.slots_reservations_attributes.push({ + offered: event.offered || false, + slot_id: event.slot_id }); for (let evt_px_cat of Array.from(event.prices)) { diff --git a/app/frontend/src/javascript/directives/cart.js b/app/frontend/src/javascript/directives/cart.js index acfb2145a..d91637b59 100644 --- a/app/frontend/src/javascript/directives/cart.js +++ b/app/frontend/src/javascript/directives/cart.js @@ -705,20 +705,18 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', /** * Create a hash map implementing the Reservation specs * @param slots {Array} Array of fullCalendar events: slots selected on the calendar - * @return {{reservation: {reservable_type: string, reservable_id: string, slots_attributes: []}}} + * @return {{reservation: Reservation}} */ const mkReservation = function (slots) { const reservation = { reservable_id: $scope.reservableId, reservable_type: $scope.reservableType, - slots_attributes: [] + slots_reservations_attributes: [] }; angular.forEach(slots, function (slot) { - reservation.slots_attributes.push({ - start_at: slot.start, - end_at: slot.end, - availability_id: slot.availability_id, - offered: slot.offered || false + reservation.slots_reservations_attributes.push({ + offered: slot.offered || false, + slot_id: slot.slot_id }); }); @@ -728,7 +726,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', /** * Create a hash map implementing the Subscription specs * @param planId {number} - * @return {{subscription: {plan_id: number}}} + * @return {{subscription: SubscriptionRequest}} */ const mkSubscription = function (planId) { return { @@ -740,7 +738,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', /** * Build the ShoppingCart object, from the current reservation - * @param items {Array<{reservation:{reservable_type: string, reservable_id: string, slots_attributes: []}}|{subscription: {plan_id: number}}>} + * @param items {Array} * @param paymentMethod {string} * @return {ShoppingCart} */ diff --git a/app/frontend/src/javascript/models/reservation.ts b/app/frontend/src/javascript/models/reservation.ts index 4e097be88..b3fbe012b 100644 --- a/app/frontend/src/javascript/models/reservation.ts +++ b/app/frontend/src/javascript/models/reservation.ts @@ -7,11 +7,12 @@ export interface SlotsReservation { id?: number, canceled_at?: TDateISO, offered?: boolean, + slot_id?: number, slot_attributes?: { - id?: number, - start_at?: TDateISO, - end_at?: TDateISO, - availability_id?: number + id: number, + start_at: TDateISO, + end_at: TDateISO, + availability_id: number } } // TODO, refactor Reservation for cart_items (in payment) => should use slot_id instead of (start_at + end_at) diff --git a/app/models/cart_item/event_reservation.rb b/app/models/cart_item/event_reservation.rb index 65b8cb964..4e6796243 100644 --- a/app/models/cart_item/event_reservation.rb +++ b/app/models/cart_item/event_reservation.rb @@ -38,7 +38,7 @@ class CartItem::EventReservation < CartItem::Reservation ::Reservation.new( reservable_id: @reservable.id, reservable_type: Event.name, - slots_attributes: slots_params, + slots_reservations_attributes: slots_params, tickets_attributes: tickets_params, nb_reserve_places: @normal_tickets, statistic_profile_id: StatisticProfile.find_by(user: @customer).id diff --git a/app/models/cart_item/machine_reservation.rb b/app/models/cart_item/machine_reservation.rb index 2c2140108..2d0c44e12 100644 --- a/app/models/cart_item/machine_reservation.rb +++ b/app/models/cart_item/machine_reservation.rb @@ -16,7 +16,7 @@ class CartItem::MachineReservation < CartItem::Reservation ::Reservation.new( reservable_id: @reservable.id, reservable_type: Machine.name, - slots_attributes: slots_params, + slots_reservations_attributes: slots_params, statistic_profile_id: StatisticProfile.find_by(user: @customer).id ) end diff --git a/app/models/cart_item/reservation.rb b/app/models/cart_item/reservation.rb index 61b623109..30103f330 100644 --- a/app/models/cart_item/reservation.rb +++ b/app/models/cart_item/reservation.rb @@ -11,7 +11,7 @@ class CartItem::Reservation < CartItem::BaseItem @customer = customer @operator = operator @reservable = reservable - @slots = slots + @slots = slots.map { |s| expand_slot(s) } super end @@ -43,20 +43,24 @@ class CartItem::Reservation < CartItem::BaseItem def valid?(all_items) pending_subscription = all_items.find { |i| i.is_a?(CartItem::Subscription) } @slots.each do |slot| - availability = Availability.find_by(id: slot[:availability_id]) + if Slot.find(slot[:slot_id]).nil? + @errors[:slot] = 'slot does not exist' + return false + end + + availability = Availability.find_by(id: slot[:slot_attributes][:availability_id]) if availability.nil? @errors[:slot] = 'slot availability does not exist' return false end if availability.available_type == 'machines' - s = SlotsReservation.includes(:slot, :reservation) - .where('slots.start_at': slot[:start_at], - 'slots.end_at': slot[:end_at], - 'slots.availability_id': slot[:availability_id], - canceled_at: nil, - 'reservations.reservable': @reservable) - unless s.empty? + same_hour_slots = SlotsReservation.joins(:reservation).where( + reservations: { reservable: @reservable }, + slot_id: slot[:slot_id], + canceled_at: nil + ).count + if same_hour_slots.positive? @errors[:slot] = 'slot is reserved' return false end @@ -93,7 +97,11 @@ class CartItem::Reservation < CartItem::BaseItem def grouped_slots return { all: @slots } unless Setting.get('extended_prices_in_same_day') - @slots.group_by { |slot| slot[:start_at].to_date } + @slots.group_by { |slot| slot[:slot_attributes][:start_at].to_date } + end + + def expand_slot(slot) + slot.merge({ slot_attributes: Slot.find(slot[:slot_id]) }) end ## @@ -104,7 +112,7 @@ class CartItem::Reservation < CartItem::BaseItem def get_slot_price_from_prices(prices, slot, is_privileged, options = {}) options = GET_SLOT_PRICE_DEFAULT_OPTS.merge(options) - slot_minutes = (slot[:end_at].to_time - slot[:start_at].to_time) / SECONDS_PER_MINUTE + slot_minutes = (slot[:slot_attributes][:end_at].to_time - slot[:slot_attributes][:start_at].to_time) / SECONDS_PER_MINUTE price = prices[:prices].find { |p| p[:duration] <= slot_minutes && p[:duration].positive? } price = prices[:prices].first if price.nil? hourly_rate = (price[:price].amount.to_f / price[:price].duration) * MINUTES_PER_HOUR @@ -134,7 +142,7 @@ class CartItem::Reservation < CartItem::BaseItem options = GET_SLOT_PRICE_DEFAULT_OPTS.merge(options) slot_rate = options[:has_credits] || (slot[:offered] && is_privileged) ? 0 : hourly_rate - slot_minutes = (slot[:end_at].to_time - slot[:start_at].to_time) / SECONDS_PER_MINUTE + slot_minutes = (slot[:slot_attributes][:end_at].to_time - slot[:slot_attributes][:start_at].to_time) / SECONDS_PER_MINUTE # apply the base price to the real slot duration real_price = if options[:is_division] (slot_rate / MINUTES_PER_HOUR) * slot_minutes @@ -151,7 +159,7 @@ class CartItem::Reservation < CartItem::BaseItem unless options[:elements].nil? options[:elements][:slots].push( - start_at: slot[:start_at], + start_at: slot[:slot_attributes][:start_at], price: real_price, promo: (slot_rate != hourly_rate) ) @@ -165,7 +173,7 @@ class CartItem::Reservation < CartItem::BaseItem # and the base price (1 hours), we use the 7 hours price, then 3 hours price, and finally the base price twice (7+3+1+1 = 12). # All these prices are returned to be applied to the reservation. def applicable_prices(slots) - total_duration = slots.map { |slot| (slot[:end_at].to_time - slot[:start_at].to_time) / SECONDS_PER_MINUTE }.reduce(:+) + total_duration = slots.map { |slot| (slot[:slot_attributes][:end_at].to_time - slot[:slot_attributes][:start_at].to_time) / SECONDS_PER_MINUTE }.reduce(:+) rates = { prices: [] } remaining_duration = total_duration @@ -201,6 +209,6 @@ class CartItem::Reservation < CartItem::BaseItem end def slots_params - @slots.map { |slot| slot.permit(:id, :start_at, :end_at, :availability_id, :offered) } + @slots.map { |slot| slot.permit(:id, :slot_id, :offered) } end end diff --git a/app/models/cart_item/space_reservation.rb b/app/models/cart_item/space_reservation.rb index 0dd341952..d9e8db730 100644 --- a/app/models/cart_item/space_reservation.rb +++ b/app/models/cart_item/space_reservation.rb @@ -16,7 +16,7 @@ class CartItem::SpaceReservation < CartItem::Reservation ::Reservation.new( reservable_id: @reservable.id, reservable_type: Space.name, - slots_attributes: slots_params, + slots_reservations_attributes: slots_params, statistic_profile_id: StatisticProfile.find_by(user: @customer).id ) end diff --git a/app/models/cart_item/training_reservation.rb b/app/models/cart_item/training_reservation.rb index 9106f9099..bfdc3b528 100644 --- a/app/models/cart_item/training_reservation.rb +++ b/app/models/cart_item/training_reservation.rb @@ -36,7 +36,7 @@ class CartItem::TrainingReservation < CartItem::Reservation ::Reservation.new( reservable_id: @reservable.id, reservable_type: Training.name, - slots_attributes: slots_params, + slots_reservations_attributes: slots_params, statistic_profile_id: StatisticProfile.find_by(user: @customer).id ) end diff --git a/app/models/reservation.rb b/app/models/reservation.rb index d0a3ddd47..04aeba681 100644 --- a/app/models/reservation.rb +++ b/app/models/reservation.rb @@ -12,7 +12,7 @@ class Reservation < ApplicationRecord has_many :slots_reservations, dependent: :destroy has_many :slots, through: :slots_reservations - accepts_nested_attributes_for :slots, allow_destroy: true + accepts_nested_attributes_for :slots_reservations, allow_destroy: true belongs_to :reservable, polymorphic: true has_many :tickets @@ -101,7 +101,7 @@ class Reservation < ApplicationRecord slots_reservations.each do |slot| same_hour_slots = SlotsReservation.joins(:reservation).where( reservations: { reservable_type: reservable_type, reservable_id: reservable_id }, - slot_id: slot_id, + slot_id: slot.slot_id, canceled_at: nil ).count if same_hour_slots.positive? diff --git a/app/models/shopping_cart.rb b/app/models/shopping_cart.rb index 03ee86f73..10e961651 100644 --- a/app/models/shopping_cart.rb +++ b/app/models/shopping_cart.rb @@ -55,13 +55,9 @@ class ShoppingCart list = user_validation_required_list.split(',') errors = [] items.each do |item| - if list.include?(item.type) && !@customer.validated_at? - errors.push("User validation is required for reserve #{item.type}") - end - end - unless errors.empty? - return { success: nil, payment: nil, errors: errors } + errors.push("User validation is required to reserve #{item.type}") if list.include?(item.type) && !@customer.validated_at? end + return { success: nil, payment: nil, errors: errors } unless errors.empty? end end diff --git a/app/models/slot.rb b/app/models/slot.rb index 24347746c..38eb8d2b6 100644 --- a/app/models/slot.rb +++ b/app/models/slot.rb @@ -13,6 +13,13 @@ class Slot < ApplicationRecord attr_accessor :is_reserved, :machine, :space, :title, :can_modify, :current_user_slots_reservations_ids def full? - slots_reservations.where(canceled_at: nil).count >= availability.available_places_per_slot + availability_places = availability.available_places_per_slot + return false if availability_places.nil? + + slots_reservations.where(canceled_at: nil).count >= availability_places + end + + def duration + (end_at - start_at).seconds end end diff --git a/app/services/availabilities/create_availabilities_service.rb b/app/services/availabilities/create_availabilities_service.rb index 3cff26379..5535d05e0 100644 --- a/app/services/availabilities/create_availabilities_service.rb +++ b/app/services/availabilities/create_availabilities_service.rb @@ -7,31 +7,36 @@ class Availabilities::CreateAvailabilitiesService slot_duration = availability.slot_duration || Setting.get('slot_duration').to_i occurrences.each do |o| - next if availability.start_at == o[:start_at] && availability.end_at == o[:end_at] + start_at = Time.zone.parse(o[:start_at]) + end_at = Time.zone.parse(o[:end_at]) - Availability.new( - start_at: o[:start_at], - end_at: o[:end_at], - available_type: availability.available_type, - is_recurrent: availability.is_recurrent, - period: availability.period, - nb_periods: availability.nb_periods, - end_date: availability.end_date, - occurrence_id: availability.occurrence_id, - machine_ids: availability.machine_ids, - training_ids: availability.training_ids, - space_ids: availability.space_ids, - tag_ids: availability.tag_ids, - nb_total_places: availability.nb_total_places, - slot_duration: availability.slot_duration, - plan_ids: availability.plan_ids - ).save! + avail = if availability.start_at == start_at && availability.end_at == end_at + availability + else + Availability.create!( + start_at: start_at, + end_at: end_at, + available_type: availability.available_type, + is_recurrent: availability.is_recurrent, + period: availability.period, + nb_periods: availability.nb_periods, + end_date: availability.end_date, + occurrence_id: availability.occurrence_id, + machine_ids: availability.machine_ids, + training_ids: availability.training_ids, + space_ids: availability.space_ids, + tag_ids: availability.tag_ids, + nb_total_places: availability.nb_total_places, + slot_duration: availability.slot_duration, + plan_ids: availability.plan_ids + ) + end - (o[:end_at] - o[:start_at] / slot_duration.minutes).to_i.times do |i| + ((end_at - start_at) / slot_duration.minutes).to_i.times do |i| Slot.new( - start_at: o[:start_at] + (i * slot_duration).minutes, - end_at: o[:start_at] + (i * slot_duration).minutes + slot_duration.minutes, - availability_id: o.id + start_at: start_at + (i * slot_duration).minutes, + end_at: start_at + (i * slot_duration).minutes + slot_duration.minutes, + availability_id: avail.id ).save! end end diff --git a/app/services/cart_service.rb b/app/services/cart_service.rb index 1c4bb29a1..baa0e5b1b 100644 --- a/app/services/cart_service.rb +++ b/app/services/cart_service.rb @@ -28,7 +28,9 @@ class CartService end coupon = CartItem::Coupon.new(@customer, @operator, cart_items[:coupon_code]) - schedule = CartItem::PaymentSchedule.new(plan_info[:plan], coupon, cart_items[:payment_schedule], @customer, plan_info[:subscription]&.start_at) + schedule = CartItem::PaymentSchedule.new( + plan_info[:plan], coupon, cart_items[:payment_schedule], @customer, plan_info[:subscription]&.start_at + ) ShoppingCart.new( @customer, @@ -108,28 +110,28 @@ class CartService CartItem::MachineReservation.new(@customer, @operator, reservable, - cart_item[:slots_attributes], + cart_item[:slots_reservations_attributes], plan: plan_info[:plan], new_subscription: plan_info[:new_subscription]) when Training CartItem::TrainingReservation.new(@customer, @operator, reservable, - cart_item[:slots_attributes], + cart_item[:slots_reservations_attributes], plan: plan_info[:plan], new_subscription: plan_info[:new_subscription]) when Event CartItem::EventReservation.new(@customer, @operator, reservable, - cart_item[:slots_attributes], + cart_item[:slots_reservations_attributes], normal_tickets: cart_item[:nb_reserve_places], other_tickets: cart_item[:tickets_attributes]) when Space CartItem::SpaceReservation.new(@customer, @operator, reservable, - cart_item[:slots_attributes], + cart_item[:slots_reservations_attributes], plan: plan_info[:plan], new_subscription: plan_info[:new_subscription]) else @@ -145,28 +147,28 @@ class CartService CartItem::MachineReservation.new(@customer, @operator, reservable, - object.reservation.slots, + object.reservation.slots_reservations, plan: plan, new_subscription: true) when Training CartItem::TrainingReservation.new(@customer, @operator, reservable, - object.reservation.slots, + object.reservation.slots_reservations, plan: plan, new_subscription: true) when Event CartItem::EventReservation.new(@customer, @operator, reservable, - object.reservation.slots, + object.reservation.slots_reservations, normal_tickets: object.reservation.nb_reserve_places, other_tickets: object.reservation.tickets) when Space CartItem::SpaceReservation.new(@customer, @operator, reservable, - object.reservation.slots, + object.reservation.slots_reservations, plan: plan, new_subscription: true) else diff --git a/app/services/invoices_service.rb b/app/services/invoices_service.rb index 7d36fbb38..b70688bfc 100644 --- a/app/services/invoices_service.rb +++ b/app/services/invoices_service.rb @@ -121,7 +121,7 @@ class InvoicesService def self.generate_event_item(invoice, reservation, payment_details, main = false) raise TypeError unless reservation.reservable.is_a? Event - reservation.slots.each do |slot| + reservation.slots_reservations.map(&:slot).each do |slot| description = "#{reservation.reservable.name}\n" description += if slot.start_at.to_date != slot.end_at.to_date I18n.t('events.from_STARTDATE_to_ENDDATE', @@ -152,7 +152,7 @@ class InvoicesService def self.generate_reservation_item(invoice, reservation, payment_details, main = false) raise TypeError unless [Space, Machine, Training].include? reservation.reservable.class - reservation.slots.each do |slot| + reservation.slots_reservations.map(&:slot).each do |slot| description = reservation.reservable.name + " #{I18n.l slot.start_at, format: :long} - #{I18n.l slot.end_at, format: :hour_minute}" diff --git a/app/services/subscription_extension_after_reservation.rb b/app/services/subscription_extension_after_reservation.rb index 0fc66d270..5c2d46171 100644 --- a/app/services/subscription_extension_after_reservation.rb +++ b/app/services/subscription_extension_after_reservation.rb @@ -26,7 +26,7 @@ class SubscriptionExtensionAfterReservation def extend_subscription user.subscription.update_columns( - expiration_date: reservation.slots.first.start_at + user.subscribed_plan.duration + expiration_date: reservation.slots_reservations.first.slot.start_at + user.subscribed_plan.duration ) end end diff --git a/app/services/users_credits/manager.rb b/app/services/users_credits/manager.rb index c2e3ad6c5..3653be30b 100644 --- a/app/services/users_credits/manager.rb +++ b/app/services/users_credits/manager.rb @@ -94,16 +94,16 @@ module UsersCredits super will_use_credits, free_hours_count, machine_credit = _will_use_credits? - if will_use_credits - users_credit = user.users_credits.find_or_initialize_by(credit_id: machine_credit.id) + return unless will_use_credits - if users_credit.new_record? - users_credit.hours_used = free_hours_count - else - users_credit.hours_used += free_hours_count - end - users_credit.save! + users_credit = user.users_credits.find_or_initialize_by(credit_id: machine_credit.id) + + if users_credit.new_record? + users_credit.hours_used = free_hours_count + else + users_credit.hours_used += free_hours_count end + users_credit.save! end private @@ -111,19 +111,16 @@ module UsersCredits def _will_use_credits? return false, 0 unless plan - if machine_credit = plan.machine_credits.find_by(creditable_id: reservation.reservable_id) + machine_credit = plan.machine_credits.find_by(creditable_id: reservation.reservable_id) + if machine_credit users_credit = user.users_credits.find_by(credit_id: machine_credit.id) already_used_hours = users_credit ? users_credit.hours_used : 0 remaining_hours = machine_credit.hours - already_used_hours - free_hours_count = [remaining_hours, reservation.slots.size].min + free_hours_count = [remaining_hours, reservation.slots_reservations.size].min - if free_hours_count.positive? - return true, free_hours_count, machine_credit - else - return false, free_hours_count, machine_credit - end + return free_hours_count&.positive?, free_hours_count, machine_credit end [false, 0] end @@ -138,9 +135,8 @@ module UsersCredits def update_credits super will_use_credits, training_credit = _will_use_credits? - if will_use_credits - user.credits << training_credit # we create a new UsersCredit object - end + + user.credits << training_credit if will_use_credits # we create a new UsersCredit object end private @@ -149,11 +145,10 @@ module UsersCredits return false, nil unless plan # if there is a training_credit defined for this plan and this training - if training_credit = plan.training_credits.find_by(creditable_id: reservation.reservable_id) + training_credit = plan.training_credits.find_by(creditable_id: reservation.reservable_id) + if training_credit # if user has not used all the plan credits - if user.training_credits.where(plan: plan).count < plan.training_credit_nb - return true, training_credit - end + return true, training_credit if user.training_credits.where(plan: plan).count < plan.training_credit_nb end [false, nil] end @@ -200,19 +195,16 @@ module UsersCredits def _will_use_credits? return false, 0 unless plan - if space_credit = plan.space_credits.find_by(creditable_id: reservation.reservable_id) + space_credit = plan.space_credits.find_by(creditable_id: reservation.reservable_id) + if space_credit users_credit = user.users_credits.find_by(credit_id: space_credit.id) already_used_hours = users_credit ? users_credit.hours_used : 0 remaining_hours = space_credit.hours - already_used_hours - free_hours_count = [remaining_hours, reservation.slots.size].min + free_hours_count = [remaining_hours, reservation.slots_reservations.size].min - if free_hours_count.positive? - return true, free_hours_count, space_credit - else - return false, free_hours_count, space_credit - end + return free_hours_count&.positive?, free_hours_count, space_credit end [false, 0] end diff --git a/app/validators/subscription_group_validator.rb b/app/validators/subscription_group_validator.rb index 72ec73680..7f04545e5 100644 --- a/app/validators/subscription_group_validator.rb +++ b/app/validators/subscription_group_validator.rb @@ -1,3 +1,6 @@ +# frozen_string_literal: true + +# Check that the current subscription's plan matches the subscribing user's plan class SubscriptionGroupValidator < ActiveModel::Validator def validate(record) return if record.statistic_profile&.group_id == record.plan&.group_id diff --git a/lib/tasks/fablab/fix_invoices.rake b/lib/tasks/fablab/fix_invoices.rake index 74747a2da..fd503f369 100644 --- a/lib/tasks/fablab/fix_invoices.rake +++ b/lib/tasks/fablab/fix_invoices.rake @@ -50,7 +50,7 @@ namespace :fablab do reservation = ::Reservation.create!( reservable_id: reservable.id, reservable_type: reservable.class.name, - slots_attributes: slots_attributes(invoice, reservable), + slots_reservations_attributes: slots_reservations_attributes(invoice, reservable), statistic_profile_id: StatisticProfile.find_by(user: invoice.user).id ) invoice.update_attributes(invoiced: reservation) @@ -118,12 +118,12 @@ namespace :fablab do availability end - def slots_attributes(invoice, reservable) - find_slots(invoice).map do |slot| + def slots_reservations_attributes(invoice, reservable) + find_slots(invoice).map do |slot_dates| + availability = find_availability(reservable, slot_dates) + slot = Slot.find_by(start_at: slot_dates[0], end_at: slot_dates[1], availability_id: availability&.id) { - start_at: slot[0], - end_at: slot[1], - availability_id: find_availability(reservable, slot)&.id, + slot_id: slot&.id, offered: invoice.total.zero? } end diff --git a/lib/tasks/fablab/payzen.rake b/lib/tasks/fablab/payzen.rake index ba956cd5c..89316adb3 100644 --- a/lib/tasks/fablab/payzen.rake +++ b/lib/tasks/fablab/payzen.rake @@ -1,43 +1,51 @@ # frozen_string_literal: true -# Stripe relative tasks +# PayZen relative tasks namespace :fablab do namespace :payzen do - # example: rails fablab:payzen:replay_on_payment_success[54a35f3f6fdd729ac72b6da0,53,57,3,2317,2022-04-27T14:30:34.000+02:00,2022-04-27T17:00:34.000+02:00] + # example: rails fablab:payzen:replay_on_payment_success[54a35f3f6fdd729ac72b6da0,53,57,3,247] # to find the parameters, search the logs, example: # Started POST "/api/payzen/confirm_payment" for 93.27.29.108 at 2022-04-04 20:26:12 +0000 - # Processing by API::PayzenController#confirm_payment as JSON - # Parameters: {"cart_items"=>{"customer_id"=>53, "items"=>[{"reservation"=>{"reservable_id"=>57, "reservable_type"=>"Event", "slots_attributes"=>[{"start_at"=>"2022-04-27T14:30:34.000+02:00", "end_at"=>"2022-04-27T17:00:34.000+02:00", "availability_id"=>2317, "offered"=>false}], "nb_reserve_places"=>3, "tickets_attributes"=>[]}}], "payment_method"=>"card"}, "order_id"=>"704cc55e23f00ac3d238d8de", "payzen"=>{"cart_items"=>{"customer_id"=>53, "items"=>[{"reservation"=>{"reservable_id"=>57, "reservable_type"=>"Event", "slots_attributes"=>[{"start_at"=>"2022-04-27T14:30:34.000+02:00", "end_at"=>"2022-04-27T17:00:34.000+02:00", "availability_id"=>2317, "offered"=>false}], "nb_reserve_places"=>3, "tickets_attributes"=>[]}}], "payment_method"=>"card"}, "order_id"=>"704cc55e23f00ac3d238d8de"}} + # Processing by API::PayzenController#confirm_payment as JSON + # Parameters: {"cart_items"=>{"customer_id"=>53, "items"=>[ + # {"reservation"=>{"reservable_id"=>57, "reservable_type"=>"Event", + # "slots_reservations_attributes"=>[{"slot_id"=>247, "offered"=>false}], + # "nb_reserve_places"=>3, "tickets_attributes"=>[] + # }} + # ], "payment_method"=>"card"}, "order_id"=>"704cc55e23f00ac3d238d8de", + # "payzen"=>{"cart_items"=>{"customer_id"=>53, "items"=>[ + # {"reservation"=>{"reservable_id"=>57, "reservable_type"=>"Event", + # "slots_reservations_attributes"=>[{"slot_id"=>247, "offered"=>false}], + # "nb_reserve_places"=>3, "tickets_attributes"=>[] + # }} + # ], "payment_method"=>"card"}, "order_id"=>"704cc55e23f00ac3d238d8de"}} desc 'replay PayzenController#on_payment_success for a given event' - task :replay_on_payment_success, [:gateway_item_id, :user_id, :event_id, :nb_reserve_places, :availability_id, :slot_start_at, :slot_end_at] => :environment do |_task, args| + task :replay_on_payment_success, %i[gateway_item_id user_id event_id nb_reserve_places slot_id] => :environment do |_task, args| ActiveRecord::Base.logger = Logger.new STDOUT - gateway_item_id, gateway_item_type = args.gateway_item_id, 'PayZen::Order' + gateway_item_type = 'PayZen::Order' ActionController::Parameters.permit_all_parameters = true - params = ActionController::Parameters.new({ - "cart_items" => - { "customer_id" => args.user_id, - "items" => [ - {"reservation" => - { "reservable_id" => args.event_id, "reservable_type" => "Event", - "slots_attributes" =>[ - {"start_at" => args.slot_start_at, "end_at" => args.slot_end_at, "availability_id" => args.availability_id, "offered" => false} - ], - "nb_reserve_places" => args.nb_reserve_places.to_i, "tickets_attributes" =>[] - } - } - ], - "payment_method"=>"card"}, - "order_id"=> gateway_item_id, - } - ) + params = ActionController::Parameters.new( + { 'cart_items' => + { 'customer_id' => args.user_id, + 'items' => [ + { 'reservation' => + { 'reservable_id' => args.event_id, 'reservable_type' => 'Event', + 'slots_reservations_attributes' => [ + { 'slot_id' => args.slot_id, 'offered' => false } + ], + 'nb_reserve_places' => args.nb_reserve_places.to_i, 'tickets_attributes' => [] } } + ], + 'payment_method' => 'card' }, + 'order_id' => args.gateway_item_id } + ) current_user = User.find(args.user_id) cart_service = CartService.new(current_user) cart = cart_service.from_hash(params[:cart_items]) - res = cart.build_and_save(gateway_item_id, gateway_item_type) + cart.build_and_save(args.gateway_item_id, gateway_item_type) end end -end \ No newline at end of file +end diff --git a/test/fixtures/files/invoices/4/FabManager_invoice-10_13072022.pdf b/test/fixtures/files/invoices/4/FabManager_invoice-10_13072022.pdf new file mode 100644 index 000000000..9cf2d893b Binary files /dev/null and b/test/fixtures/files/invoices/4/FabManager_invoice-10_13072022.pdf differ diff --git a/test/fixtures/files/invoices/5/FabManager_invoice-9_13072022.pdf b/test/fixtures/files/invoices/5/FabManager_invoice-9_13072022.pdf new file mode 100644 index 000000000..05064d4f6 Binary files /dev/null and b/test/fixtures/files/invoices/5/FabManager_invoice-9_13072022.pdf differ diff --git a/test/integration/availabilities/as_admin_test.rb b/test/integration/availabilities/as_admin_test.rb index 37b378768..5a9cd5504 100644 --- a/test/integration/availabilities/as_admin_test.rb +++ b/test/integration/availabilities/as_admin_test.rb @@ -26,7 +26,12 @@ module Availabilities test 'get machine availabilities as admin' do m = Machine.find_by(slug: 'decoupeuse-vinyle') - get "/api/availabilities/machines/#{m.id}" + # this simulates a fullCalendar (v2) call + start_date = DateTime.current.utc.strftime('%Y-%m-%d') + end_date = 7.days.from_now.utc.strftime('%Y-%m-%d') + tz = Time.zone.tzinfo.name + + get "/api/availabilities/machines/#{m.id}?start=#{start_date}&end=#{end_date}&timezone=#{tz}&_=1217026492144" # Check response format & status assert_equal 200, response.status @@ -88,6 +93,8 @@ module Availabilities test 'create availabilities' do date = DateTime.current.change(hour: 8, min: 0, sec: 0) + slots_count = Slot.count + post '/api/availabilities', params: { availability: { @@ -122,6 +129,8 @@ module Availabilities assert_equal (availability[:start_at].to_datetime + availability[:slot_duration].minutes * 4).iso8601, availability[:end_at], 'expected end_at = start_at + 4 slots of 90 minutes' + assert_equal (slots_count + 4 * 3), Slot.count, 'expected (4*3) slots of 90 minutes were created' + assert_equal 90.minutes, Availability.find(availability[:id]).slots.first.duration # Check the recurrence assert_equal (availability[:start_at].to_datetime + 2.weeks).to_date, diff --git a/test/integration/availabilities/as_user_test.rb b/test/integration/availabilities/as_user_test.rb index 6c2026fcc..b53ddb478 100644 --- a/test/integration/availabilities/as_user_test.rb +++ b/test/integration/availabilities/as_user_test.rb @@ -9,7 +9,12 @@ class Availabilities::AsUserTest < ActionDispatch::IntegrationTest test 'get machine availabilities as user' do m = Machine.find_by(slug: 'decoupeuse-vinyle') - get "/api/availabilities/machines/#{m.id}" + # this simulates a fullCalendar (v2) call + start_date = DateTime.current.utc.strftime('%Y-%m-%d') + end_date = 7.days.from_now.utc.strftime('%Y-%m-%d') + tz = Time.zone.tzinfo.name + + get "/api/availabilities/machines/#{m.id}?start=#{start_date}&end=#{end_date}&timezone=#{tz}&_=1800145267413" # Check response format & status assert_equal 200, response.status diff --git a/test/integration/events/as_admin_test.rb b/test/integration/events/as_admin_test.rb index 46db34beb..f9607f4a3 100644 --- a/test/integration/events/as_admin_test.rb +++ b/test/integration/events/as_admin_test.rb @@ -74,11 +74,9 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest reservable_id: e.id, reservable_type: 'Event', nb_reserve_places: 2, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: e.availability.start_at, - end_at: e.availability.end_at, - availability_id: e.availability.id, + slot_id: e.availability.slots.first.id, offered: false } ] @@ -158,7 +156,7 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest assert_not_nil e, 'Event was not created in database' # Check the places numbers were set successfully - e = Event.where(id: event[:id]).first + e = Event.find(event[:id]) assert_equal 10, e.nb_total_places, 'Total number of places was not updated' assert_equal 10, e.nb_free_places, 'Number of free places was not updated' @@ -172,11 +170,9 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest reservable_id: e.id, reservable_type: 'Event', nb_reserve_places: 4, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: e.availability.start_at, - end_at: e.availability.end_at, - availability_id: e.availability.id, + slot_id: e.availability.slots.first.id, offered: false } ], diff --git a/test/integration/events/as_user_test.rb b/test/integration/events/as_user_test.rb index 97f5a33a4..2f21b3569 100644 --- a/test/integration/events/as_user_test.rb +++ b/test/integration/events/as_user_test.rb @@ -10,7 +10,7 @@ class Events::AsUserTest < ActionDispatch::IntegrationTest login_as(vlonchamp, scope: :user) radio = Event.find(4) - availability = radio.availability + slot = radio.availability.slots.first reservations_count = Reservation.count invoice_count = Invoice.count @@ -35,11 +35,9 @@ class Events::AsUserTest < ActionDispatch::IntegrationTest reservable_id: radio.id, reservable_type: 'Event', nb_reserve_places: 2, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at, - end_at: availability.end_at, - availability_id: availability.id, + slot_id: slot.id, offered: false } ], diff --git a/test/integration/payzen_test.rb b/test/integration/payzen_test.rb index 42b529b1c..3ac6f6ab5 100644 --- a/test/integration/payzen_test.rb +++ b/test/integration/payzen_test.rb @@ -12,7 +12,7 @@ class PayzenTest < ActionDispatch::IntegrationTest test 'create payment with payzen' do training = Training.first - availability = training.availabilities.first + slot = training.availabilities.first.slots.first plan = Plan.find_by(group_id: @user.group.id, type: 'Plan') VCR.use_cassette('create_payzen_payment_token_success') do @@ -25,11 +25,9 @@ class PayzenTest < ActionDispatch::IntegrationTest reservation: { reservable_id: training.id, reservable_type: training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: availability.end_at.to_s(:iso8601), - availability_id: availability.id + slot_id: slot.id } ] } @@ -57,13 +55,13 @@ class PayzenTest < ActionDispatch::IntegrationTest require 'pay_zen/pci/charge' training = Training.first - availability = training.availabilities.first + slot = training.availabilities.first.slots.first plan = Plan.find_by(group_id: @user.group.id, type: 'Plan') reservations_count = Reservation.count availabilities_count = Availability.count invoices_count = Invoice.count - slots_count = Slot.count + slots_reservation_count = SlotsReservation.count cart_items = { @@ -72,11 +70,9 @@ class PayzenTest < ActionDispatch::IntegrationTest reservation: { reservable_id: training.id, reservable_type: training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: availability.end_at.to_s(:iso8601), - availability_id: availability.id + slot_id: slot.id } ] } @@ -138,7 +134,7 @@ class PayzenTest < ActionDispatch::IntegrationTest assert_equal reservations_count + 1, Reservation.count assert_equal invoices_count + 1, Invoice.count - assert_equal slots_count + 1, Slot.count + assert_equal slots_reservation_count + 1, SlotsReservation.count assert_equal availabilities_count, Availability.count end end diff --git a/test/integration/prices/compute_test.rb b/test/integration/prices/compute_test.rb index 4b30cf9e2..fb63358db 100644 --- a/test/integration/prices/compute_test.rb +++ b/test/integration/prices/compute_test.rb @@ -12,6 +12,7 @@ module Prices test 'compute price for a simple training' do user = User.find_by(username: 'jdupond') availability = Availability.find(2) + slot = Availability.find(2).slots.first printer_training = availability.trainings.first post '/api/prices/compute', @@ -22,12 +23,10 @@ module Prices reservation: { reservable_id: printer_training.id, reservable_type: printer_training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - availability_id: availability.id, - end_at: availability.end_at, - offered: false, - start_at: availability.start_at + slot_id: slot.id, + offered: false } ] } @@ -51,7 +50,7 @@ module Prices user = User.find_by(username: 'jdupond') availability = Availability.find(3) laser = availability.machines.where(id: 1).first - plan = Plan.where(group_id: user.group_id, interval: 'month').first + plan = Plan.find_by(group_id: user.group_id, interval: 'month') post '/api/prices/compute', params: { @@ -61,18 +60,14 @@ module Prices reservation: { reservable_id: laser.id, reservable_type: laser.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - availability_id: availability.id, - end_at: (availability.start_at + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z'), - offered: true, - start_at: availability.start_at.strftime('%Y-%m-%d %H:%M:%S.%9N Z') + slot_id: availability.slots.first.id, + offered: true }, { - availability_id: availability.id, - end_at: (availability.start_at + 2.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z'), - offered: false, - start_at: (availability.start_at + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z') + slot_id: availability.slots.last.id, + offered: false } ] } diff --git a/test/integration/reservations/create_as_admin_test.rb b/test/integration/reservations/create_as_admin_test.rb index a4421dfcd..a13f6b588 100644 --- a/test/integration/reservations/create_as_admin_test.rb +++ b/test/integration/reservations/create_as_admin_test.rb @@ -28,11 +28,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -92,11 +90,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest reservation: { reservable_id: training.id, reservable_type: training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -156,16 +152,12 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id }, { - start_at: (availability.start_at + 1.hour).to_s(:iso8601), - end_at: (availability.start_at + 2.hours).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.last.id } ] } @@ -237,11 +229,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + sslots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -315,11 +305,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -394,11 +382,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -443,12 +429,10 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest reservation: { reservable_id: training.id, reservable_type: training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - offered: false, - availability_id: availability.id + slot_id: availability.slots.first.id, + offered: false } ] } @@ -535,11 +519,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest reservation: { reservable_id: training.id, reservable_type: training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } diff --git a/test/integration/reservations/create_test.rb b/test/integration/reservations/create_test.rb index d918e3997..c4712cccf 100644 --- a/test/integration/reservations/create_test.rb +++ b/test/integration/reservations/create_test.rb @@ -32,11 +32,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -105,11 +103,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -157,11 +153,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: training.id, reservable_type: training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: availability.end_at.to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -229,16 +223,12 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id }, { - start_at: (availability.start_at + 1.hour).to_s(:iso8601), - end_at: (availability.start_at + 2.hours).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.last.id } ] } @@ -314,11 +304,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: training.id, reservable_type: training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: availability.end_at.to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -391,11 +379,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -476,11 +462,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: training.id, reservable_type: training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: availability.end_at.to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -542,7 +526,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest login_as(@user_without_subscription, scope: :user) machine = Machine.find(6) - plan = Plan.where(group_id: @user_without_subscription.group_id).first + plan = Plan.find_by(group_id: @user_without_subscription.group_id) availability = machine.availabilities.first reservations_count = Reservation.count @@ -561,11 +545,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -661,11 +643,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservable_id: training.id, reservable_type: training.class.name, card_token: stripe_payment_method, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -714,11 +694,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: training.id, reservable_type: training.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -802,11 +780,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } @@ -899,11 +875,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest reservation: { reservable_id: space.id, reservable_type: space.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: availability.slots.first.id } ] } diff --git a/test/integration/reservations/restricted_test.rb b/test/integration/reservations/restricted_test.rb index dab2f5ec7..982329f98 100644 --- a/test/integration/reservations/restricted_test.rb +++ b/test/integration/reservations/restricted_test.rb @@ -17,7 +17,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest reservations_count = Reservation.count availabilities_count = Availability.count invoices_count = Invoice.count - slots_count = Slot.count + slots_reservation_count = SlotsReservation.count # first, create the restricted availability date = 4.days.from_now.utc.change(hour: 8, min: 0, sec: 0) @@ -47,6 +47,8 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest # change connected user login_as(@pdurand, scope: :user) + slot = Availability.find(availability[:id]).slots.first + # book a reservation VCR.use_cassette('reservations_create_for_restricted_slot_success') do post '/api/stripe/confirm_payment', @@ -58,11 +60,9 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest reservation: { reservable_id: 2, reservable_type: 'Machine', - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability[:start_at], - end_at: (DateTime.parse(availability[:start_at]) + 1.hour).to_s(:iso8601), - availability_id: availability[:id] + slot_id: slot.id } ] } @@ -76,7 +76,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest assert_equal reservations_count + 1, Reservation.count assert_equal invoices_count + 1, Invoice.count - assert_equal slots_count + 1, Slot.count + assert_equal slots_reservation_count + 1, SlotsReservation.count end test 'unable to reserve slot restricted to subscribers' do @@ -86,6 +86,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest availabilities_count = Availability.count invoices_count = Invoice.count slots_count = Slot.count + slots_reservation_count = SlotsReservation.count # first, create the restricted availability date = 4.days.from_now.utc.change(hour: 8, min: 0, sec: 0) @@ -111,9 +112,11 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest assert_not_nil availability[:id], 'availability ID was unexpectedly nil' assert_equal availabilities_count + 1, Availability.count + assert_equal slots_count + 6, Slot.count # change connected user login_as(@jdupont, scope: :user) + slot = Availability.find(availability[:id]).slots.first # book a reservation VCR.use_cassette('reservations_create_for_restricted_slot_fails') do @@ -126,11 +129,9 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest reservation: { reservable_id: 2, reservable_type: 'Machine', - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability[:start_at], - end_at: (DateTime.parse(availability[:start_at]) + 1.hour).to_s(:iso8601), - availability_id: availability[:id] + slot_id: slot.id } ] } @@ -145,7 +146,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest assert_equal reservations_count, Reservation.count assert_equal invoices_count, Invoice.count - assert_equal slots_count, Slot.count + assert_equal slots_reservation_count, SlotsReservation.count end test 'admin force reservation of a slot restricted to subscribers' do @@ -155,6 +156,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest availabilities_count = Availability.count invoices_count = Invoice.count slots_count = Slot.count + slots_reservation_count = SlotsReservation.count # first, create the restricted availability date = 4.days.from_now.utc.change(hour: 8, min: 0, sec: 0) @@ -180,6 +182,9 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest assert_not_nil availability[:id], 'availability ID was unexpectedly nil' assert_equal availabilities_count + 1, Availability.count + assert_equal slots_count + 6, Slot.count + + slot = Availability.find(availability[:id]).slots.first # book a reservation VCR.use_cassette('reservations_create_for_restricted_slot_forced') do @@ -191,11 +196,9 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest reservation: { reservable_id: 2, reservable_type: 'Machine', - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability[:start_at], - end_at: (DateTime.parse(availability[:start_at]) + 1.hour).to_s(:iso8601), - availability_id: availability[:id] + slot_id: slot.id } ] } @@ -212,7 +215,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest assert_equal reservations_count + 1, Reservation.count assert_equal invoices_count + 1, Invoice.count - assert_equal slots_count + 1, Slot.count + assert_equal slots_reservation_count + 1, SlotsReservation.count end test 'book a slot restricted to subscribers and a subscription at the same time' do @@ -223,6 +226,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest invoices_count = Invoice.count invoice_items_count = InvoiceItem.count slots_count = Slot.count + slots_reservation_count = SlotsReservation.count subscriptions_count = Subscription.count # first, create the restricted availability @@ -249,9 +253,11 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest assert_not_nil availability[:id], 'availability ID was unexpectedly nil' assert_equal availabilities_count + 1, Availability.count + assert_equal slots_count + 6, Slot.count # change connected user login_as(@jdupont, scope: :user) + slot = Availability.find(availability[:id]).slots.first # book a reservation VCR.use_cassette('reservations_and_subscription_create_for_restricted_slot_success') do @@ -264,11 +270,9 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest reservation: { reservable_id: 2, reservable_type: 'Machine', - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability[:start_at], - end_at: (DateTime.parse(availability[:start_at]) + 1.hour).to_s(:iso8601), - availability_id: availability[:id] + slot_id: slot.id } ] } @@ -291,7 +295,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest assert_equal reservations_count + 1, Reservation.count assert_equal invoices_count + 1, Invoice.count - assert_equal slots_count + 1, Slot.count + assert_equal slots_reservation_count + 1, SlotsReservation.count assert_equal subscriptions_count + 1, Subscription.count assert_equal invoice_items_count + 2, InvoiceItem.count end diff --git a/test/services/statistic_service_test.rb b/test/services/statistic_service_test.rb index 680a10232..7434ada90 100644 --- a/test/services/statistic_service_test.rb +++ b/test/services/statistic_service_test.rb @@ -15,7 +15,7 @@ class StatisticServiceTest < ActiveSupport::TestCase # Create a reservation to generate an invoice machine = Machine.find(1) - availability = Availability.find(19) + slot = Availability.find(19).slots.first post '/api/local_payment/confirm_payment', params: { customer_id: @user.id, items: [ @@ -23,11 +23,9 @@ class StatisticServiceTest < ActiveSupport::TestCase reservation: { reservable_id: machine.id, reservable_type: machine.class.name, - slots_attributes: [ + slots_reservations_attributes: [ { - start_at: availability.start_at.to_s(:iso8601), - end_at: (availability.start_at + 1.hour).to_s(:iso8601), - availability_id: availability.id + slot_id: slot.id } ] } diff --git a/test/services/subscription_extension_after_reservation_test.rb b/test/services/subscription_extension_after_reservation_test.rb index a0a5f0607..aa7e45cb6 100644 --- a/test/services/subscription_extension_after_reservation_test.rb +++ b/test/services/subscription_extension_after_reservation_test.rb @@ -14,10 +14,16 @@ class SubscriptionExtensionAfterReservationTest < ActiveSupport::TestCase @user.reservations.destroy_all # ensure no reservations - @availability = @machine.availabilities.first - slot = Slot.new(start_at: @availability.start_at, end_at: @availability.end_at, availability_id: @availability.id) - @reservation_machine = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @machine, slots: [slot]) - @reservation_training = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @training, slots: [slot]) + @reservation_machine = Reservation.new( + statistic_profile: @user.statistic_profile, + reservable: @machine, + slots_reservations: [{ slot_id: @machine.availabilities.first.slots.first.id }] + ) + @reservation_training = Reservation.new( + statistic_profile: @user.statistic_profile, + reservable: @training, + slots_reservations: [{ slot_id: @training.availabilities.first.slots.first.id }] + ) @reservation_training.save! end diff --git a/test/services/users_credits_manager_test.rb b/test/services/users_credits_manager_test.rb index f26ddca9d..729ac18d2 100644 --- a/test/services/users_credits_manager_test.rb +++ b/test/services/users_credits_manager_test.rb @@ -9,16 +9,18 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase @user.users_credits.destroy_all @availability = @machine.availabilities.first @reservation_machine = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @machine) - @reservation_training = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @training) + @reservation_training = Reservation.new( + statistic_profile: @user.statistic_profile, + reservable: @training, + slots_reservations_attributes: [{ slot_id: @training.availabilities.first.slots.first.id }] + ) end ## context machine reservation - test "machine reservation from user without subscribed plan" do + test 'machine reservation from user without subscribed plan' do @user.subscriptions.destroy_all - @reservation_machine.assign_attributes(slots_attributes: [{ - start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id - }]) + @reservation_machine.assign_attributes(slots_reservations_attributes: [{ slot_id: @availability.slots.first }]) manager = UsersCredits::Manager.new(reservation: @reservation_machine) assert_equal false, manager.will_use_credits? @@ -29,12 +31,10 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase end end - test "machine reservation without credit associated" do + test 'machine reservation without credit associated' do Credit.where(creditable: @machine).destroy_all - @reservation_machine.assign_attributes(slots_attributes: [{ - start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id - }]) + @reservation_machine.assign_attributes(slots_reservations_attributes: [{ slot_id: @availability.slots.first }]) manager = UsersCredits::Manager.new(reservation: @reservation_machine) assert_equal false, manager.will_use_credits? @@ -49,14 +49,12 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase end end - test "machine reservation with credit associated and user never used his credit" do + test 'machine reservation with credit associated and user never used his credit' do credit = Credit.find_by!(creditable: @machine, plan: @plan) credit.update!(hours: 2) @user.users_credits.destroy_all - @reservation_machine.assign_attributes(slots_attributes: [{ - start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id - }]) + @reservation_machine.assign_attributes(slots_reservations_attributes: [{ slot_id: @availability.slots.first }]) manager = UsersCredits::Manager.new(reservation: @reservation_machine) assert_equal true, manager.will_use_credits? @@ -71,15 +69,14 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase end end - test "machine reservation with credit associated and user already used partially his credit" do + test 'machine reservation with credit associated and user already used partially his credit' do credit = Credit.find_by!(creditable: @machine, plan: @plan) credit.update!(hours: 2) users_credit = @user.users_credits.create!(credit: credit, hours_used: 1) - @reservation_machine.assign_attributes(slots_attributes: [ - { start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id }, - { start_at: @availability.start_at + 1.hour, end_at: @availability.start_at + 2.hour, availability_id: @availability.id } - ]) + @reservation_machine.assign_attributes(slots_reservations_attributes: + [{ slot_id: @availability.slots.first }, + { slot_id: @availability.slots.last }]) manager = UsersCredits::Manager.new(reservation: @reservation_machine) @@ -94,14 +91,13 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase assert_equal 2, users_credit.hours_used end - test "machine reservation with credit associated and user already used all credit" do + test 'machine reservation with credit associated and user already used all credit' do credit = Credit.find_by!(creditable: @machine, plan: @plan) users_credit = @user.users_credits.create!(credit: credit, hours_used: 1) - @reservation_machine.assign_attributes(slots_attributes: [ - { start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id }, - { start_at: @availability.start_at + 1.hour, end_at: @availability.start_at + 2.hour, availability_id: @availability.id } - ]) + @reservation_machine.assign_attributes(slots_reservations_attributes: + [{ slot_id: @availability.slots.first }, + { slot_id: @availability.slots.last }]) manager = UsersCredits::Manager.new(reservation: @reservation_machine) assert_equal false, manager.will_use_credits? @@ -117,7 +113,7 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase # context training reservation - test "training reservation from user without subscribed plan" do + test 'training reservation from user without subscribed plan' do @user.subscriptions.destroy_all manager = UsersCredits::Manager.new(reservation: @reservation_training) @@ -129,7 +125,7 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase end end - test "training reservation without credit associated" do + test 'training reservation without credit associated' do Credit.where(creditable: @training).destroy_all manager = UsersCredits::Manager.new(reservation: @reservation_training) @@ -145,8 +141,8 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase end end - test "training reservation with credit associated and user didnt use his credit yet" do - credit = Credit.find_or_create_by!(creditable: @training, plan: @plan) + test 'training reservation with credit associated and user didnt use his credit yet' do + Credit.find_or_create_by!(creditable: @training, plan: @plan) @user.users_credits.destroy_all manager = UsersCredits::Manager.new(reservation: @reservation_training) @@ -158,7 +154,7 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase end end - test "training reservation with credit associated but user already used all his credits" do + test 'training reservation with credit associated but user already used all his credits' do @user.users_credits.destroy_all another_training = Training.where.not(id: @training.id).first credit = Credit.find_or_create_by!(creditable: another_training, plan: @plan) @@ -176,9 +172,9 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase # context reset user credits - test "use UsersCredit::Manager to reset users_credits" do + test 'use UsersCredit::Manager to reset users_credits' do credit = Credit.find_by!(creditable: @machine, plan: @plan) - users_credit = @user.users_credits.create!(credit: credit, hours_used: 1) + @user.users_credits.create!(credit: credit, hours_used: 1) assert_not_empty @user.users_credits