1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-18 07:52:23 +01:00

refactor shopping_cart/reservation

Previsouly, the reservation was expecting parameters like:
slots_attributes: [{start_at: date, end_at: date, availability_id: number}]

Now, the reservation is expecting simpler parameters like:
slots_reservations_attributes:[{slot_id: number}]
This commit is contained in:
Sylvain 2022-07-13 16:28:43 +02:00
parent 66d1348b06
commit b68e47a0ea
35 changed files with 325 additions and 353 deletions

View File

@ -55,9 +55,8 @@ class API::PayzenController < API::PaymentsController
def check_cart def check_cart
cart = shopping_cart cart = shopping_cart
unless cart.valid? render json: { error: 'unable to pay' }, status: :unprocessable_entity and return unless cart.valid?
render json: { error: 'unable to pay' }, status: :unprocessable_entity and return
end
render json: { cart: 'ok' }, status: :ok render json: { cart: 'ok' }, status: :ok
end end

View File

@ -43,6 +43,6 @@ class API::ReservationsController < API::ApiController
def reservation_params def reservation_params
params.require(:reservation).permit(:message, :reservable_id, :reservable_type, :nb_reserve_places, params.require(:reservation).permit(:message, :reservable_id, :reservable_type, :nb_reserve_places,
tickets_attributes: %i[event_price_category_id booked], 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
end end

View File

@ -360,7 +360,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
reservation: { reservation: {
reservable_id: $scope.event.id, reservable_id: $scope.event.id,
reservable_type: 'Event', reservable_type: 'Event',
slots_attributes: [], slots_reservations_attributes: [],
nb_reserve_places: $scope.reserve.nbReservePlaces, nb_reserve_places: $scope.reserve.nbReservePlaces,
tickets_attributes: [] tickets_attributes: []
} }
@ -368,10 +368,8 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
] ]
} }
// a single slot is used for events // a single slot is used for events
cartItems.items[0].reservation.slots_attributes.push({ cartItems.items[0].reservation.slots_reservations_attributes.push({
start_at: $scope.event.start_date, slot_id: $scope.event.slot_id
end_at: $scope.event.end_date,
availability_id: $scope.event.availability.id
}); });
// iterate over reservations per prices // iterate over reservations per prices
for (let price_id in $scope.reserve.tickets) { for (let price_id in $scope.reserve.tickets) {
@ -405,7 +403,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
/** /**
* Callback to cancel a reservation * 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) { $scope.cancelReservation = function(reservation) {
dialogs.confirm({ dialogs.confirm({
@ -434,17 +432,17 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
/** /**
* Test if the provided reservation has been cancelled * Test if the provided reservation has been cancelled
* @param reservation {{slots_attributes: [{canceled_at: string}]}} * @param reservation {Reservation}
* @returns {boolean} * @returns {boolean}
*/ */
$scope.isCancelled = function(reservation) { $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 * 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) * 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) { $scope.modifyReservation = function (reservation) {
const index = $scope.reservations.indexOf(reservation); const index = $scope.reservations.indexOf(reservation);
@ -475,9 +473,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
return eventToPlace = e; return eventToPlace = e;
} }
}); });
$scope.reservation.slots_reservations_attributes[0].start_at = eventToPlace.start_date; $scope.reservation.slots_reservations_attributes[0].slot_id = eventToPlace.slot_id;
$scope.reservation.slots_reservations_attributes[0].end_at = eventToPlace.end_date;
$scope.reservation.slots_reservations_attributes[0].availability_id = eventToPlace.availability_id;
$scope.attempting = true; $scope.attempting = true;
Reservation.update({ id: reservation.id }, { reservation: $scope.reservation }, function (reservation) { Reservation.update({ id: reservation.id }, { reservation: $scope.reservation }, function (reservation) {
$uibModalInstance.close(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) * 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) { $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(); const now = moment();
let isAble = false; let isAble = false;
@ -529,10 +525,10 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', '
/** /**
* Checks if the provided reservation is able to be cancelled * Checks if the provided reservation is able to be cancelled
* @param reservation {{slots_attributes:[]}} * @param reservation {Reservation}
*/ */
$scope.reservationCanCancel = function(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(); const now = moment();
return $scope.enableBookingCancel && slotStart.diff(now, "hours") >= $scope.cancelBookingDelay; 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 * Create a hash map implementing the Reservation specs
* @param reserve {Object} Reservation parameters (places...) * @param reserve {Object} Reservation parameters (places...)
* @param event {Object} Current event * @param event {Object} Current event
* @return {{reservation: {reservable_id:number, reservable_type:string, slots_attributes:Array<Object>, nb_reserve_places:number}}} * @return {{reservation: Reservation}}
*/ */
const mkReservation = function (reserve, event) { const mkReservation = function (reserve, event) {
const reservation = { const reservation = {
reservable_id: event.id, reservable_id: event.id,
reservable_type: 'Event', reservable_type: 'Event',
slots_attributes: [], slots_reservations_attributes: [],
nb_reserve_places: reserve.nbReservePlaces, nb_reserve_places: reserve.nbReservePlaces,
tickets_attributes: [] tickets_attributes: []
}; };
reservation.slots_attributes.push({ reservation.slots_reservations_attributes.push({
start_at: event.start_date, offered: event.offered || false,
end_at: event.end_date, slot_id: event.slot_id
availability_id: event.availability.id,
offered: event.offered || false
}); });
for (let evt_px_cat of Array.from(event.prices)) { for (let evt_px_cat of Array.from(event.prices)) {

View File

@ -705,20 +705,18 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
/** /**
* Create a hash map implementing the Reservation specs * Create a hash map implementing the Reservation specs
* @param slots {Array<Object>} Array of fullCalendar events: slots selected on the calendar * @param slots {Array<Object>} 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 mkReservation = function (slots) {
const reservation = { const reservation = {
reservable_id: $scope.reservableId, reservable_id: $scope.reservableId,
reservable_type: $scope.reservableType, reservable_type: $scope.reservableType,
slots_attributes: [] slots_reservations_attributes: []
}; };
angular.forEach(slots, function (slot) { angular.forEach(slots, function (slot) {
reservation.slots_attributes.push({ reservation.slots_reservations_attributes.push({
start_at: slot.start, offered: slot.offered || false,
end_at: slot.end, slot_id: slot.slot_id
availability_id: slot.availability_id,
offered: slot.offered || false
}); });
}); });
@ -728,7 +726,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
/** /**
* Create a hash map implementing the Subscription specs * Create a hash map implementing the Subscription specs
* @param planId {number} * @param planId {number}
* @return {{subscription: {plan_id: number}}} * @return {{subscription: SubscriptionRequest}}
*/ */
const mkSubscription = function (planId) { const mkSubscription = function (planId) {
return { return {
@ -740,7 +738,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
/** /**
* Build the ShoppingCart object, from the current reservation * 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<CartItem>}
* @param paymentMethod {string} * @param paymentMethod {string}
* @return {ShoppingCart} * @return {ShoppingCart}
*/ */

View File

@ -7,11 +7,12 @@ export interface SlotsReservation {
id?: number, id?: number,
canceled_at?: TDateISO, canceled_at?: TDateISO,
offered?: boolean, offered?: boolean,
slot_id?: number,
slot_attributes?: { slot_attributes?: {
id?: number, id: number,
start_at?: TDateISO, start_at: TDateISO,
end_at?: TDateISO, end_at: TDateISO,
availability_id?: number availability_id: number
} }
} }
// TODO, refactor Reservation for cart_items (in payment) => should use slot_id instead of (start_at + end_at) // TODO, refactor Reservation for cart_items (in payment) => should use slot_id instead of (start_at + end_at)

View File

@ -38,7 +38,7 @@ class CartItem::EventReservation < CartItem::Reservation
::Reservation.new( ::Reservation.new(
reservable_id: @reservable.id, reservable_id: @reservable.id,
reservable_type: Event.name, reservable_type: Event.name,
slots_attributes: slots_params, slots_reservations_attributes: slots_params,
tickets_attributes: tickets_params, tickets_attributes: tickets_params,
nb_reserve_places: @normal_tickets, nb_reserve_places: @normal_tickets,
statistic_profile_id: StatisticProfile.find_by(user: @customer).id statistic_profile_id: StatisticProfile.find_by(user: @customer).id

View File

@ -16,7 +16,7 @@ class CartItem::MachineReservation < CartItem::Reservation
::Reservation.new( ::Reservation.new(
reservable_id: @reservable.id, reservable_id: @reservable.id,
reservable_type: Machine.name, reservable_type: Machine.name,
slots_attributes: slots_params, slots_reservations_attributes: slots_params,
statistic_profile_id: StatisticProfile.find_by(user: @customer).id statistic_profile_id: StatisticProfile.find_by(user: @customer).id
) )
end end

View File

@ -11,7 +11,7 @@ class CartItem::Reservation < CartItem::BaseItem
@customer = customer @customer = customer
@operator = operator @operator = operator
@reservable = reservable @reservable = reservable
@slots = slots @slots = slots.map { |s| expand_slot(s) }
super super
end end
@ -43,20 +43,24 @@ class CartItem::Reservation < CartItem::BaseItem
def valid?(all_items) def valid?(all_items)
pending_subscription = all_items.find { |i| i.is_a?(CartItem::Subscription) } pending_subscription = all_items.find { |i| i.is_a?(CartItem::Subscription) }
@slots.each do |slot| @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? if availability.nil?
@errors[:slot] = 'slot availability does not exist' @errors[:slot] = 'slot availability does not exist'
return false return false
end end
if availability.available_type == 'machines' if availability.available_type == 'machines'
s = SlotsReservation.includes(:slot, :reservation) same_hour_slots = SlotsReservation.joins(:reservation).where(
.where('slots.start_at': slot[:start_at], reservations: { reservable: @reservable },
'slots.end_at': slot[:end_at], slot_id: slot[:slot_id],
'slots.availability_id': slot[:availability_id], canceled_at: nil
canceled_at: nil, ).count
'reservations.reservable': @reservable) if same_hour_slots.positive?
unless s.empty?
@errors[:slot] = 'slot is reserved' @errors[:slot] = 'slot is reserved'
return false return false
end end
@ -93,7 +97,11 @@ class CartItem::Reservation < CartItem::BaseItem
def grouped_slots def grouped_slots
return { all: @slots } unless Setting.get('extended_prices_in_same_day') 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 end
## ##
@ -104,7 +112,7 @@ class CartItem::Reservation < CartItem::BaseItem
def get_slot_price_from_prices(prices, slot, is_privileged, options = {}) def get_slot_price_from_prices(prices, slot, is_privileged, options = {})
options = GET_SLOT_PRICE_DEFAULT_OPTS.merge(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].find { |p| p[:duration] <= slot_minutes && p[:duration].positive? }
price = prices[:prices].first if price.nil? price = prices[:prices].first if price.nil?
hourly_rate = (price[:price].amount.to_f / price[:price].duration) * MINUTES_PER_HOUR 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) options = GET_SLOT_PRICE_DEFAULT_OPTS.merge(options)
slot_rate = options[:has_credits] || (slot[:offered] && is_privileged) ? 0 : hourly_rate 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 # apply the base price to the real slot duration
real_price = if options[:is_division] real_price = if options[:is_division]
(slot_rate / MINUTES_PER_HOUR) * slot_minutes (slot_rate / MINUTES_PER_HOUR) * slot_minutes
@ -151,7 +159,7 @@ class CartItem::Reservation < CartItem::BaseItem
unless options[:elements].nil? unless options[:elements].nil?
options[:elements][:slots].push( options[:elements][:slots].push(
start_at: slot[:start_at], start_at: slot[:slot_attributes][:start_at],
price: real_price, price: real_price,
promo: (slot_rate != hourly_rate) 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). # 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. # All these prices are returned to be applied to the reservation.
def applicable_prices(slots) 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: [] } rates = { prices: [] }
remaining_duration = total_duration remaining_duration = total_duration
@ -201,6 +209,6 @@ class CartItem::Reservation < CartItem::BaseItem
end end
def slots_params 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
end end

View File

@ -16,7 +16,7 @@ class CartItem::SpaceReservation < CartItem::Reservation
::Reservation.new( ::Reservation.new(
reservable_id: @reservable.id, reservable_id: @reservable.id,
reservable_type: Space.name, reservable_type: Space.name,
slots_attributes: slots_params, slots_reservations_attributes: slots_params,
statistic_profile_id: StatisticProfile.find_by(user: @customer).id statistic_profile_id: StatisticProfile.find_by(user: @customer).id
) )
end end

View File

@ -36,7 +36,7 @@ class CartItem::TrainingReservation < CartItem::Reservation
::Reservation.new( ::Reservation.new(
reservable_id: @reservable.id, reservable_id: @reservable.id,
reservable_type: Training.name, reservable_type: Training.name,
slots_attributes: slots_params, slots_reservations_attributes: slots_params,
statistic_profile_id: StatisticProfile.find_by(user: @customer).id statistic_profile_id: StatisticProfile.find_by(user: @customer).id
) )
end end

View File

@ -12,7 +12,7 @@ class Reservation < ApplicationRecord
has_many :slots_reservations, dependent: :destroy has_many :slots_reservations, dependent: :destroy
has_many :slots, through: :slots_reservations 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 belongs_to :reservable, polymorphic: true
has_many :tickets has_many :tickets
@ -101,7 +101,7 @@ class Reservation < ApplicationRecord
slots_reservations.each do |slot| slots_reservations.each do |slot|
same_hour_slots = SlotsReservation.joins(:reservation).where( same_hour_slots = SlotsReservation.joins(:reservation).where(
reservations: { reservable_type: reservable_type, reservable_id: reservable_id }, reservations: { reservable_type: reservable_type, reservable_id: reservable_id },
slot_id: slot_id, slot_id: slot.slot_id,
canceled_at: nil canceled_at: nil
).count ).count
if same_hour_slots.positive? if same_hour_slots.positive?

View File

@ -55,13 +55,9 @@ class ShoppingCart
list = user_validation_required_list.split(',') list = user_validation_required_list.split(',')
errors = [] errors = []
items.each do |item| items.each do |item|
if list.include?(item.type) && !@customer.validated_at? errors.push("User validation is required to reserve #{item.type}") 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 }
end end
return { success: nil, payment: nil, errors: errors } unless errors.empty?
end end
end end

View File

@ -13,6 +13,13 @@ class Slot < ApplicationRecord
attr_accessor :is_reserved, :machine, :space, :title, :can_modify, :current_user_slots_reservations_ids attr_accessor :is_reserved, :machine, :space, :title, :can_modify, :current_user_slots_reservations_ids
def full? 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
end end

View File

@ -7,31 +7,36 @@ class Availabilities::CreateAvailabilitiesService
slot_duration = availability.slot_duration || Setting.get('slot_duration').to_i slot_duration = availability.slot_duration || Setting.get('slot_duration').to_i
occurrences.each do |o| 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( avail = if availability.start_at == start_at && availability.end_at == end_at
start_at: o[:start_at], availability
end_at: o[:end_at], else
available_type: availability.available_type, Availability.create!(
is_recurrent: availability.is_recurrent, start_at: start_at,
period: availability.period, end_at: end_at,
nb_periods: availability.nb_periods, available_type: availability.available_type,
end_date: availability.end_date, is_recurrent: availability.is_recurrent,
occurrence_id: availability.occurrence_id, period: availability.period,
machine_ids: availability.machine_ids, nb_periods: availability.nb_periods,
training_ids: availability.training_ids, end_date: availability.end_date,
space_ids: availability.space_ids, occurrence_id: availability.occurrence_id,
tag_ids: availability.tag_ids, machine_ids: availability.machine_ids,
nb_total_places: availability.nb_total_places, training_ids: availability.training_ids,
slot_duration: availability.slot_duration, space_ids: availability.space_ids,
plan_ids: availability.plan_ids tag_ids: availability.tag_ids,
).save! 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( Slot.new(
start_at: o[:start_at] + (i * slot_duration).minutes, start_at: start_at + (i * slot_duration).minutes,
end_at: o[:start_at] + (i * slot_duration).minutes + slot_duration.minutes, end_at: start_at + (i * slot_duration).minutes + slot_duration.minutes,
availability_id: o.id availability_id: avail.id
).save! ).save!
end end
end end

View File

@ -28,7 +28,9 @@ class CartService
end end
coupon = CartItem::Coupon.new(@customer, @operator, cart_items[:coupon_code]) 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( ShoppingCart.new(
@customer, @customer,
@ -108,28 +110,28 @@ class CartService
CartItem::MachineReservation.new(@customer, CartItem::MachineReservation.new(@customer,
@operator, @operator,
reservable, reservable,
cart_item[:slots_attributes], cart_item[:slots_reservations_attributes],
plan: plan_info[:plan], plan: plan_info[:plan],
new_subscription: plan_info[:new_subscription]) new_subscription: plan_info[:new_subscription])
when Training when Training
CartItem::TrainingReservation.new(@customer, CartItem::TrainingReservation.new(@customer,
@operator, @operator,
reservable, reservable,
cart_item[:slots_attributes], cart_item[:slots_reservations_attributes],
plan: plan_info[:plan], plan: plan_info[:plan],
new_subscription: plan_info[:new_subscription]) new_subscription: plan_info[:new_subscription])
when Event when Event
CartItem::EventReservation.new(@customer, CartItem::EventReservation.new(@customer,
@operator, @operator,
reservable, reservable,
cart_item[:slots_attributes], cart_item[:slots_reservations_attributes],
normal_tickets: cart_item[:nb_reserve_places], normal_tickets: cart_item[:nb_reserve_places],
other_tickets: cart_item[:tickets_attributes]) other_tickets: cart_item[:tickets_attributes])
when Space when Space
CartItem::SpaceReservation.new(@customer, CartItem::SpaceReservation.new(@customer,
@operator, @operator,
reservable, reservable,
cart_item[:slots_attributes], cart_item[:slots_reservations_attributes],
plan: plan_info[:plan], plan: plan_info[:plan],
new_subscription: plan_info[:new_subscription]) new_subscription: plan_info[:new_subscription])
else else
@ -145,28 +147,28 @@ class CartService
CartItem::MachineReservation.new(@customer, CartItem::MachineReservation.new(@customer,
@operator, @operator,
reservable, reservable,
object.reservation.slots, object.reservation.slots_reservations,
plan: plan, plan: plan,
new_subscription: true) new_subscription: true)
when Training when Training
CartItem::TrainingReservation.new(@customer, CartItem::TrainingReservation.new(@customer,
@operator, @operator,
reservable, reservable,
object.reservation.slots, object.reservation.slots_reservations,
plan: plan, plan: plan,
new_subscription: true) new_subscription: true)
when Event when Event
CartItem::EventReservation.new(@customer, CartItem::EventReservation.new(@customer,
@operator, @operator,
reservable, reservable,
object.reservation.slots, object.reservation.slots_reservations,
normal_tickets: object.reservation.nb_reserve_places, normal_tickets: object.reservation.nb_reserve_places,
other_tickets: object.reservation.tickets) other_tickets: object.reservation.tickets)
when Space when Space
CartItem::SpaceReservation.new(@customer, CartItem::SpaceReservation.new(@customer,
@operator, @operator,
reservable, reservable,
object.reservation.slots, object.reservation.slots_reservations,
plan: plan, plan: plan,
new_subscription: true) new_subscription: true)
else else

View File

@ -121,7 +121,7 @@ class InvoicesService
def self.generate_event_item(invoice, reservation, payment_details, main = false) def self.generate_event_item(invoice, reservation, payment_details, main = false)
raise TypeError unless reservation.reservable.is_a? Event 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 = "#{reservation.reservable.name}\n"
description += if slot.start_at.to_date != slot.end_at.to_date description += if slot.start_at.to_date != slot.end_at.to_date
I18n.t('events.from_STARTDATE_to_ENDDATE', I18n.t('events.from_STARTDATE_to_ENDDATE',
@ -152,7 +152,7 @@ class InvoicesService
def self.generate_reservation_item(invoice, reservation, payment_details, main = false) def self.generate_reservation_item(invoice, reservation, payment_details, main = false)
raise TypeError unless [Space, Machine, Training].include? reservation.reservable.class 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 + description = reservation.reservable.name +
" #{I18n.l slot.start_at, format: :long} - #{I18n.l slot.end_at, format: :hour_minute}" " #{I18n.l slot.start_at, format: :long} - #{I18n.l slot.end_at, format: :hour_minute}"

View File

@ -26,7 +26,7 @@ class SubscriptionExtensionAfterReservation
def extend_subscription def extend_subscription
user.subscription.update_columns( 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
end end

View File

@ -94,16 +94,16 @@ module UsersCredits
super super
will_use_credits, free_hours_count, machine_credit = _will_use_credits? will_use_credits, free_hours_count, machine_credit = _will_use_credits?
if will_use_credits return unless will_use_credits
users_credit = user.users_credits.find_or_initialize_by(credit_id: machine_credit.id)
if users_credit.new_record? users_credit = user.users_credits.find_or_initialize_by(credit_id: machine_credit.id)
users_credit.hours_used = free_hours_count
else if users_credit.new_record?
users_credit.hours_used += free_hours_count users_credit.hours_used = free_hours_count
end else
users_credit.save! users_credit.hours_used += free_hours_count
end end
users_credit.save!
end end
private private
@ -111,19 +111,16 @@ module UsersCredits
def _will_use_credits? def _will_use_credits?
return false, 0 unless plan 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) users_credit = user.users_credits.find_by(credit_id: machine_credit.id)
already_used_hours = users_credit ? users_credit.hours_used : 0 already_used_hours = users_credit ? users_credit.hours_used : 0
remaining_hours = machine_credit.hours - already_used_hours 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 free_hours_count&.positive?, free_hours_count, machine_credit
return true, free_hours_count, machine_credit
else
return false, free_hours_count, machine_credit
end
end end
[false, 0] [false, 0]
end end
@ -138,9 +135,8 @@ module UsersCredits
def update_credits def update_credits
super super
will_use_credits, training_credit = _will_use_credits? will_use_credits, training_credit = _will_use_credits?
if will_use_credits
user.credits << training_credit # we create a new UsersCredit object user.credits << training_credit if will_use_credits # we create a new UsersCredit object
end
end end
private private
@ -149,11 +145,10 @@ module UsersCredits
return false, nil unless plan return false, nil unless plan
# if there is a training_credit defined for this plan and this training # 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 has not used all the plan credits
if user.training_credits.where(plan: plan).count < plan.training_credit_nb return true, training_credit if user.training_credits.where(plan: plan).count < plan.training_credit_nb
return true, training_credit
end
end end
[false, nil] [false, nil]
end end
@ -200,19 +195,16 @@ module UsersCredits
def _will_use_credits? def _will_use_credits?
return false, 0 unless plan 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) users_credit = user.users_credits.find_by(credit_id: space_credit.id)
already_used_hours = users_credit ? users_credit.hours_used : 0 already_used_hours = users_credit ? users_credit.hours_used : 0
remaining_hours = space_credit.hours - already_used_hours 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 free_hours_count&.positive?, free_hours_count, space_credit
return true, free_hours_count, space_credit
else
return false, free_hours_count, space_credit
end
end end
[false, 0] [false, 0]
end end

View File

@ -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 class SubscriptionGroupValidator < ActiveModel::Validator
def validate(record) def validate(record)
return if record.statistic_profile&.group_id == record.plan&.group_id return if record.statistic_profile&.group_id == record.plan&.group_id

View File

@ -50,7 +50,7 @@ namespace :fablab do
reservation = ::Reservation.create!( reservation = ::Reservation.create!(
reservable_id: reservable.id, reservable_id: reservable.id,
reservable_type: reservable.class.name, 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 statistic_profile_id: StatisticProfile.find_by(user: invoice.user).id
) )
invoice.update_attributes(invoiced: reservation) invoice.update_attributes(invoiced: reservation)
@ -118,12 +118,12 @@ namespace :fablab do
availability availability
end end
def slots_attributes(invoice, reservable) def slots_reservations_attributes(invoice, reservable)
find_slots(invoice).map do |slot| 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], slot_id: slot&.id,
end_at: slot[1],
availability_id: find_availability(reservable, slot)&.id,
offered: invoice.total.zero? offered: invoice.total.zero?
} }
end end

View File

@ -1,43 +1,51 @@
# frozen_string_literal: true # frozen_string_literal: true
# Stripe relative tasks # PayZen relative tasks
namespace :fablab do namespace :fablab do
namespace :payzen 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: # 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 # 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 # 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"}} # 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' 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 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 ActionController::Parameters.permit_all_parameters = true
params = ActionController::Parameters.new({ params = ActionController::Parameters.new(
"cart_items" => { 'cart_items' =>
{ "customer_id" => args.user_id, { 'customer_id' => args.user_id,
"items" => [ 'items' => [
{"reservation" => { 'reservation' =>
{ "reservable_id" => args.event_id, "reservable_type" => "Event", { 'reservable_id' => args.event_id, 'reservable_type' => 'Event',
"slots_attributes" =>[ 'slots_reservations_attributes' => [
{"start_at" => args.slot_start_at, "end_at" => args.slot_end_at, "availability_id" => args.availability_id, "offered" => false} { 'slot_id' => args.slot_id, 'offered' => false }
], ],
"nb_reserve_places" => args.nb_reserve_places.to_i, "tickets_attributes" =>[] 'nb_reserve_places' => args.nb_reserve_places.to_i, 'tickets_attributes' => [] } }
} ],
} 'payment_method' => 'card' },
], 'order_id' => args.gateway_item_id }
"payment_method"=>"card"}, )
"order_id"=> gateway_item_id,
}
)
current_user = User.find(args.user_id) current_user = User.find(args.user_id)
cart_service = CartService.new(current_user) cart_service = CartService.new(current_user)
cart = cart_service.from_hash(params[:cart_items]) 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 end
end end

Binary file not shown.

Binary file not shown.

View File

@ -26,7 +26,12 @@ module Availabilities
test 'get machine availabilities as admin' do test 'get machine availabilities as admin' do
m = Machine.find_by(slug: 'decoupeuse-vinyle') 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 # Check response format & status
assert_equal 200, response.status assert_equal 200, response.status
@ -88,6 +93,8 @@ module Availabilities
test 'create availabilities' do test 'create availabilities' do
date = DateTime.current.change(hour: 8, min: 0, sec: 0) date = DateTime.current.change(hour: 8, min: 0, sec: 0)
slots_count = Slot.count
post '/api/availabilities', post '/api/availabilities',
params: { params: {
availability: { availability: {
@ -122,6 +129,8 @@ module Availabilities
assert_equal (availability[:start_at].to_datetime + availability[:slot_duration].minutes * 4).iso8601, assert_equal (availability[:start_at].to_datetime + availability[:slot_duration].minutes * 4).iso8601,
availability[:end_at], availability[:end_at],
'expected end_at = start_at + 4 slots of 90 minutes' '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 # Check the recurrence
assert_equal (availability[:start_at].to_datetime + 2.weeks).to_date, assert_equal (availability[:start_at].to_datetime + 2.weeks).to_date,

View File

@ -9,7 +9,12 @@ class Availabilities::AsUserTest < ActionDispatch::IntegrationTest
test 'get machine availabilities as user' do test 'get machine availabilities as user' do
m = Machine.find_by(slug: 'decoupeuse-vinyle') 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 # Check response format & status
assert_equal 200, response.status assert_equal 200, response.status

View File

@ -74,11 +74,9 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest
reservable_id: e.id, reservable_id: e.id,
reservable_type: 'Event', reservable_type: 'Event',
nb_reserve_places: 2, nb_reserve_places: 2,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: e.availability.start_at, slot_id: e.availability.slots.first.id,
end_at: e.availability.end_at,
availability_id: e.availability.id,
offered: false offered: false
} }
] ]
@ -158,7 +156,7 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest
assert_not_nil e, 'Event was not created in database' assert_not_nil e, 'Event was not created in database'
# Check the places numbers were set successfully # 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_total_places, 'Total number of places was not updated'
assert_equal 10, e.nb_free_places, 'Number of free 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_id: e.id,
reservable_type: 'Event', reservable_type: 'Event',
nb_reserve_places: 4, nb_reserve_places: 4,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: e.availability.start_at, slot_id: e.availability.slots.first.id,
end_at: e.availability.end_at,
availability_id: e.availability.id,
offered: false offered: false
} }
], ],

View File

@ -10,7 +10,7 @@ class Events::AsUserTest < ActionDispatch::IntegrationTest
login_as(vlonchamp, scope: :user) login_as(vlonchamp, scope: :user)
radio = Event.find(4) radio = Event.find(4)
availability = radio.availability slot = radio.availability.slots.first
reservations_count = Reservation.count reservations_count = Reservation.count
invoice_count = Invoice.count invoice_count = Invoice.count
@ -35,11 +35,9 @@ class Events::AsUserTest < ActionDispatch::IntegrationTest
reservable_id: radio.id, reservable_id: radio.id,
reservable_type: 'Event', reservable_type: 'Event',
nb_reserve_places: 2, nb_reserve_places: 2,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at, slot_id: slot.id,
end_at: availability.end_at,
availability_id: availability.id,
offered: false offered: false
} }
], ],

View File

@ -12,7 +12,7 @@ class PayzenTest < ActionDispatch::IntegrationTest
test 'create payment with payzen' do test 'create payment with payzen' do
training = Training.first training = Training.first
availability = training.availabilities.first slot = training.availabilities.first.slots.first
plan = Plan.find_by(group_id: @user.group.id, type: 'Plan') plan = Plan.find_by(group_id: @user.group.id, type: 'Plan')
VCR.use_cassette('create_payzen_payment_token_success') do VCR.use_cassette('create_payzen_payment_token_success') do
@ -25,11 +25,9 @@ class PayzenTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: slot.id
end_at: availability.end_at.to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -57,13 +55,13 @@ class PayzenTest < ActionDispatch::IntegrationTest
require 'pay_zen/pci/charge' require 'pay_zen/pci/charge'
training = Training.first training = Training.first
availability = training.availabilities.first slot = training.availabilities.first.slots.first
plan = Plan.find_by(group_id: @user.group.id, type: 'Plan') plan = Plan.find_by(group_id: @user.group.id, type: 'Plan')
reservations_count = Reservation.count reservations_count = Reservation.count
availabilities_count = Availability.count availabilities_count = Availability.count
invoices_count = Invoice.count invoices_count = Invoice.count
slots_count = Slot.count slots_reservation_count = SlotsReservation.count
cart_items = { cart_items = {
@ -72,11 +70,9 @@ class PayzenTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: slot.id
end_at: availability.end_at.to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -138,7 +134,7 @@ class PayzenTest < ActionDispatch::IntegrationTest
assert_equal reservations_count + 1, Reservation.count assert_equal reservations_count + 1, Reservation.count
assert_equal invoices_count + 1, Invoice.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 assert_equal availabilities_count, Availability.count
end end
end end

View File

@ -12,6 +12,7 @@ module Prices
test 'compute price for a simple training' do test 'compute price for a simple training' do
user = User.find_by(username: 'jdupond') user = User.find_by(username: 'jdupond')
availability = Availability.find(2) availability = Availability.find(2)
slot = Availability.find(2).slots.first
printer_training = availability.trainings.first printer_training = availability.trainings.first
post '/api/prices/compute', post '/api/prices/compute',
@ -22,12 +23,10 @@ module Prices
reservation: { reservation: {
reservable_id: printer_training.id, reservable_id: printer_training.id,
reservable_type: printer_training.class.name, reservable_type: printer_training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
availability_id: availability.id, slot_id: slot.id,
end_at: availability.end_at, offered: false
offered: false,
start_at: availability.start_at
} }
] ]
} }
@ -51,7 +50,7 @@ module Prices
user = User.find_by(username: 'jdupond') user = User.find_by(username: 'jdupond')
availability = Availability.find(3) availability = Availability.find(3)
laser = availability.machines.where(id: 1).first 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', post '/api/prices/compute',
params: { params: {
@ -61,18 +60,14 @@ module Prices
reservation: { reservation: {
reservable_id: laser.id, reservable_id: laser.id,
reservable_type: laser.class.name, reservable_type: laser.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
availability_id: availability.id, slot_id: availability.slots.first.id,
end_at: (availability.start_at + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z'), offered: true
offered: true,
start_at: availability.start_at.strftime('%Y-%m-%d %H:%M:%S.%9N Z')
}, },
{ {
availability_id: availability.id, slot_id: availability.slots.last.id,
end_at: (availability.start_at + 2.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z'), offered: false
offered: false,
start_at: (availability.start_at + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z')
} }
] ]
} }

View File

@ -28,11 +28,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -92,11 +90,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -156,16 +152,12 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
}, },
{ {
start_at: (availability.start_at + 1.hour).to_s(:iso8601), slot_id: availability.slots.last.id
end_at: (availability.start_at + 2.hours).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -237,11 +229,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ sslots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -315,11 +305,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -394,11 +382,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -443,12 +429,10 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id,
end_at: (availability.start_at + 1.hour).to_s(:iso8601), offered: false
offered: false,
availability_id: availability.id
} }
] ]
} }
@ -535,11 +519,9 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }

View File

@ -32,11 +32,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -105,11 +103,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -157,11 +153,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: availability.end_at.to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -229,16 +223,12 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
}, },
{ {
start_at: (availability.start_at + 1.hour).to_s(:iso8601), slot_id: availability.slots.last.id
end_at: (availability.start_at + 2.hours).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -314,11 +304,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: availability.end_at.to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -391,11 +379,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -476,11 +462,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: availability.end_at.to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -542,7 +526,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
login_as(@user_without_subscription, scope: :user) login_as(@user_without_subscription, scope: :user)
machine = Machine.find(6) 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 availability = machine.availabilities.first
reservations_count = Reservation.count reservations_count = Reservation.count
@ -561,11 +545,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -661,11 +643,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
card_token: stripe_payment_method, card_token: stripe_payment_method,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -714,11 +694,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: training.id, reservable_id: training.id,
reservable_type: training.class.name, reservable_type: training.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -802,11 +780,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }
@ -899,11 +875,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: space.id, reservable_id: space.id,
reservable_type: space.class.name, reservable_type: space.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: availability.slots.first.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }

View File

@ -17,7 +17,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
reservations_count = Reservation.count reservations_count = Reservation.count
availabilities_count = Availability.count availabilities_count = Availability.count
invoices_count = Invoice.count invoices_count = Invoice.count
slots_count = Slot.count slots_reservation_count = SlotsReservation.count
# first, create the restricted availability # first, create the restricted availability
date = 4.days.from_now.utc.change(hour: 8, min: 0, sec: 0) 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 # change connected user
login_as(@pdurand, scope: :user) login_as(@pdurand, scope: :user)
slot = Availability.find(availability[:id]).slots.first
# book a reservation # book a reservation
VCR.use_cassette('reservations_create_for_restricted_slot_success') do VCR.use_cassette('reservations_create_for_restricted_slot_success') do
post '/api/stripe/confirm_payment', post '/api/stripe/confirm_payment',
@ -58,11 +60,9 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: 2, reservable_id: 2,
reservable_type: 'Machine', reservable_type: 'Machine',
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability[:start_at], slot_id: slot.id
end_at: (DateTime.parse(availability[:start_at]) + 1.hour).to_s(:iso8601),
availability_id: availability[:id]
} }
] ]
} }
@ -76,7 +76,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
assert_equal reservations_count + 1, Reservation.count assert_equal reservations_count + 1, Reservation.count
assert_equal invoices_count + 1, Invoice.count assert_equal invoices_count + 1, Invoice.count
assert_equal slots_count + 1, Slot.count assert_equal slots_reservation_count + 1, SlotsReservation.count
end end
test 'unable to reserve slot restricted to subscribers' do test 'unable to reserve slot restricted to subscribers' do
@ -86,6 +86,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
availabilities_count = Availability.count availabilities_count = Availability.count
invoices_count = Invoice.count invoices_count = Invoice.count
slots_count = Slot.count slots_count = Slot.count
slots_reservation_count = SlotsReservation.count
# first, create the restricted availability # first, create the restricted availability
date = 4.days.from_now.utc.change(hour: 8, min: 0, sec: 0) 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_not_nil availability[:id], 'availability ID was unexpectedly nil'
assert_equal availabilities_count + 1, Availability.count assert_equal availabilities_count + 1, Availability.count
assert_equal slots_count + 6, Slot.count
# change connected user # change connected user
login_as(@jdupont, scope: :user) login_as(@jdupont, scope: :user)
slot = Availability.find(availability[:id]).slots.first
# book a reservation # book a reservation
VCR.use_cassette('reservations_create_for_restricted_slot_fails') do VCR.use_cassette('reservations_create_for_restricted_slot_fails') do
@ -126,11 +129,9 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: 2, reservable_id: 2,
reservable_type: 'Machine', reservable_type: 'Machine',
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability[:start_at], slot_id: slot.id
end_at: (DateTime.parse(availability[:start_at]) + 1.hour).to_s(:iso8601),
availability_id: availability[:id]
} }
] ]
} }
@ -145,7 +146,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
assert_equal reservations_count, Reservation.count assert_equal reservations_count, Reservation.count
assert_equal invoices_count, Invoice.count assert_equal invoices_count, Invoice.count
assert_equal slots_count, Slot.count assert_equal slots_reservation_count, SlotsReservation.count
end end
test 'admin force reservation of a slot restricted to subscribers' do test 'admin force reservation of a slot restricted to subscribers' do
@ -155,6 +156,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
availabilities_count = Availability.count availabilities_count = Availability.count
invoices_count = Invoice.count invoices_count = Invoice.count
slots_count = Slot.count slots_count = Slot.count
slots_reservation_count = SlotsReservation.count
# first, create the restricted availability # first, create the restricted availability
date = 4.days.from_now.utc.change(hour: 8, min: 0, sec: 0) 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_not_nil availability[:id], 'availability ID was unexpectedly nil'
assert_equal availabilities_count + 1, Availability.count assert_equal availabilities_count + 1, Availability.count
assert_equal slots_count + 6, Slot.count
slot = Availability.find(availability[:id]).slots.first
# book a reservation # book a reservation
VCR.use_cassette('reservations_create_for_restricted_slot_forced') do VCR.use_cassette('reservations_create_for_restricted_slot_forced') do
@ -191,11 +196,9 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: 2, reservable_id: 2,
reservable_type: 'Machine', reservable_type: 'Machine',
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability[:start_at], slot_id: slot.id
end_at: (DateTime.parse(availability[:start_at]) + 1.hour).to_s(:iso8601),
availability_id: availability[:id]
} }
] ]
} }
@ -212,7 +215,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
assert_equal reservations_count + 1, Reservation.count assert_equal reservations_count + 1, Reservation.count
assert_equal invoices_count + 1, Invoice.count assert_equal invoices_count + 1, Invoice.count
assert_equal slots_count + 1, Slot.count assert_equal slots_reservation_count + 1, SlotsReservation.count
end end
test 'book a slot restricted to subscribers and a subscription at the same time' do 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 invoices_count = Invoice.count
invoice_items_count = InvoiceItem.count invoice_items_count = InvoiceItem.count
slots_count = Slot.count slots_count = Slot.count
slots_reservation_count = SlotsReservation.count
subscriptions_count = Subscription.count subscriptions_count = Subscription.count
# first, create the restricted availability # 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_not_nil availability[:id], 'availability ID was unexpectedly nil'
assert_equal availabilities_count + 1, Availability.count assert_equal availabilities_count + 1, Availability.count
assert_equal slots_count + 6, Slot.count
# change connected user # change connected user
login_as(@jdupont, scope: :user) login_as(@jdupont, scope: :user)
slot = Availability.find(availability[:id]).slots.first
# book a reservation # book a reservation
VCR.use_cassette('reservations_and_subscription_create_for_restricted_slot_success') do VCR.use_cassette('reservations_and_subscription_create_for_restricted_slot_success') do
@ -264,11 +270,9 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
reservation: { reservation: {
reservable_id: 2, reservable_id: 2,
reservable_type: 'Machine', reservable_type: 'Machine',
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability[:start_at], slot_id: slot.id
end_at: (DateTime.parse(availability[:start_at]) + 1.hour).to_s(:iso8601),
availability_id: availability[:id]
} }
] ]
} }
@ -291,7 +295,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
assert_equal reservations_count + 1, Reservation.count assert_equal reservations_count + 1, Reservation.count
assert_equal invoices_count + 1, Invoice.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 subscriptions_count + 1, Subscription.count
assert_equal invoice_items_count + 2, InvoiceItem.count assert_equal invoice_items_count + 2, InvoiceItem.count
end end

View File

@ -15,7 +15,7 @@ class StatisticServiceTest < ActiveSupport::TestCase
# Create a reservation to generate an invoice # Create a reservation to generate an invoice
machine = Machine.find(1) machine = Machine.find(1)
availability = Availability.find(19) slot = Availability.find(19).slots.first
post '/api/local_payment/confirm_payment', params: { post '/api/local_payment/confirm_payment', params: {
customer_id: @user.id, customer_id: @user.id,
items: [ items: [
@ -23,11 +23,9 @@ class StatisticServiceTest < ActiveSupport::TestCase
reservation: { reservation: {
reservable_id: machine.id, reservable_id: machine.id,
reservable_type: machine.class.name, reservable_type: machine.class.name,
slots_attributes: [ slots_reservations_attributes: [
{ {
start_at: availability.start_at.to_s(:iso8601), slot_id: slot.id
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
} }
] ]
} }

View File

@ -14,10 +14,16 @@ class SubscriptionExtensionAfterReservationTest < ActiveSupport::TestCase
@user.reservations.destroy_all # ensure no reservations @user.reservations.destroy_all # ensure no reservations
@availability = @machine.availabilities.first @reservation_machine = Reservation.new(
slot = Slot.new(start_at: @availability.start_at, end_at: @availability.end_at, availability_id: @availability.id) statistic_profile: @user.statistic_profile,
@reservation_machine = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @machine, slots: [slot]) reservable: @machine,
@reservation_training = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @training, slots: [slot]) 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! @reservation_training.save!
end end

View File

@ -9,16 +9,18 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
@user.users_credits.destroy_all @user.users_credits.destroy_all
@availability = @machine.availabilities.first @availability = @machine.availabilities.first
@reservation_machine = Reservation.new(statistic_profile: @user.statistic_profile, reservable: @machine) @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 end
## context machine reservation ## 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 @user.subscriptions.destroy_all
@reservation_machine.assign_attributes(slots_attributes: [{ @reservation_machine.assign_attributes(slots_reservations_attributes: [{ slot_id: @availability.slots.first }])
start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id
}])
manager = UsersCredits::Manager.new(reservation: @reservation_machine) manager = UsersCredits::Manager.new(reservation: @reservation_machine)
assert_equal false, manager.will_use_credits? assert_equal false, manager.will_use_credits?
@ -29,12 +31,10 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
end end
end end
test "machine reservation without credit associated" do test 'machine reservation without credit associated' do
Credit.where(creditable: @machine).destroy_all Credit.where(creditable: @machine).destroy_all
@reservation_machine.assign_attributes(slots_attributes: [{ @reservation_machine.assign_attributes(slots_reservations_attributes: [{ slot_id: @availability.slots.first }])
start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id
}])
manager = UsersCredits::Manager.new(reservation: @reservation_machine) manager = UsersCredits::Manager.new(reservation: @reservation_machine)
assert_equal false, manager.will_use_credits? assert_equal false, manager.will_use_credits?
@ -49,14 +49,12 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
end end
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 = Credit.find_by!(creditable: @machine, plan: @plan)
credit.update!(hours: 2) credit.update!(hours: 2)
@user.users_credits.destroy_all @user.users_credits.destroy_all
@reservation_machine.assign_attributes(slots_attributes: [{ @reservation_machine.assign_attributes(slots_reservations_attributes: [{ slot_id: @availability.slots.first }])
start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id
}])
manager = UsersCredits::Manager.new(reservation: @reservation_machine) manager = UsersCredits::Manager.new(reservation: @reservation_machine)
assert_equal true, manager.will_use_credits? assert_equal true, manager.will_use_credits?
@ -71,15 +69,14 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
end end
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 = Credit.find_by!(creditable: @machine, plan: @plan)
credit.update!(hours: 2) credit.update!(hours: 2)
users_credit = @user.users_credits.create!(credit: credit, hours_used: 1) users_credit = @user.users_credits.create!(credit: credit, hours_used: 1)
@reservation_machine.assign_attributes(slots_attributes: [ @reservation_machine.assign_attributes(slots_reservations_attributes:
{ start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id }, [{ slot_id: @availability.slots.first },
{ start_at: @availability.start_at + 1.hour, end_at: @availability.start_at + 2.hour, availability_id: @availability.id } { slot_id: @availability.slots.last }])
])
manager = UsersCredits::Manager.new(reservation: @reservation_machine) manager = UsersCredits::Manager.new(reservation: @reservation_machine)
@ -94,14 +91,13 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
assert_equal 2, users_credit.hours_used assert_equal 2, users_credit.hours_used
end 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) credit = Credit.find_by!(creditable: @machine, plan: @plan)
users_credit = @user.users_credits.create!(credit: credit, hours_used: 1) users_credit = @user.users_credits.create!(credit: credit, hours_used: 1)
@reservation_machine.assign_attributes(slots_attributes: [ @reservation_machine.assign_attributes(slots_reservations_attributes:
{ start_at: @availability.start_at, end_at: @availability.start_at + 1.hour, availability_id: @availability.id }, [{ slot_id: @availability.slots.first },
{ start_at: @availability.start_at + 1.hour, end_at: @availability.start_at + 2.hour, availability_id: @availability.id } { slot_id: @availability.slots.last }])
])
manager = UsersCredits::Manager.new(reservation: @reservation_machine) manager = UsersCredits::Manager.new(reservation: @reservation_machine)
assert_equal false, manager.will_use_credits? assert_equal false, manager.will_use_credits?
@ -117,7 +113,7 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
# context training reservation # 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 @user.subscriptions.destroy_all
manager = UsersCredits::Manager.new(reservation: @reservation_training) manager = UsersCredits::Manager.new(reservation: @reservation_training)
@ -129,7 +125,7 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
end end
end end
test "training reservation without credit associated" do test 'training reservation without credit associated' do
Credit.where(creditable: @training).destroy_all Credit.where(creditable: @training).destroy_all
manager = UsersCredits::Manager.new(reservation: @reservation_training) manager = UsersCredits::Manager.new(reservation: @reservation_training)
@ -145,8 +141,8 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
end end
end end
test "training reservation with credit associated and user didnt use his credit yet" do test 'training reservation with credit associated and user didnt use his credit yet' do
credit = Credit.find_or_create_by!(creditable: @training, plan: @plan) Credit.find_or_create_by!(creditable: @training, plan: @plan)
@user.users_credits.destroy_all @user.users_credits.destroy_all
manager = UsersCredits::Manager.new(reservation: @reservation_training) manager = UsersCredits::Manager.new(reservation: @reservation_training)
@ -158,7 +154,7 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
end end
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 @user.users_credits.destroy_all
another_training = Training.where.not(id: @training.id).first another_training = Training.where.not(id: @training.id).first
credit = Credit.find_or_create_by!(creditable: another_training, plan: @plan) credit = Credit.find_or_create_by!(creditable: another_training, plan: @plan)
@ -176,9 +172,9 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase
# context reset user credits # 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) 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 assert_not_empty @user.users_credits