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
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

View File

@ -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

View File

@ -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<Object>, 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)) {

View File

@ -705,20 +705,18 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
/**
* Create a hash map implementing the Reservation specs
* @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 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<CartItem>}
* @param paymentMethod {string}
* @return {ShoppingCart}
*/

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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?

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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}"

View File

@ -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

View File

@ -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

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
def validate(record)
return if record.statistic_profile&.group_id == record.plan&.group_id

View File

@ -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

View File

@ -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
end

Binary file not shown.

Binary file not shown.

View File

@ -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,

View File

@ -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

View File

@ -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
}
],

View File

@ -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
}
],

View File

@ -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

View File

@ -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
}
]
}

View File

@ -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
}
]
}

View File

@ -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
}
]
}

View File

@ -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

View File

@ -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
}
]
}

View File

@ -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

View File

@ -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