2020-05-06 12:43:47 +02:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-04-07 12:57:08 +02:00
|
|
|
require 'forwardable'
|
|
|
|
|
|
|
|
module UsersCredits
|
2018-12-06 18:26:01 +01:00
|
|
|
class AlreadyUpdatedError < StandardError; end
|
2016-04-07 12:57:08 +02:00
|
|
|
|
2020-05-06 12:43:47 +02:00
|
|
|
# You must use UsersCredits::Manager to consume the credits of a user or to reset them
|
2016-04-07 12:57:08 +02:00
|
|
|
class Manager
|
|
|
|
extend Forwardable
|
|
|
|
attr_reader :manager
|
|
|
|
|
2016-04-08 10:33:50 +02:00
|
|
|
def initialize(reservation: nil, user: nil, plan: nil)
|
2016-04-07 12:57:08 +02:00
|
|
|
if user
|
|
|
|
@manager = Managers::User.new(user)
|
|
|
|
elsif reservation
|
2017-02-23 17:45:55 +01:00
|
|
|
if reservation.reservable_type == 'Training'
|
2016-04-08 10:33:50 +02:00
|
|
|
@manager = Managers::Training.new(reservation, plan)
|
2017-02-23 17:45:55 +01:00
|
|
|
elsif reservation.reservable_type == 'Machine'
|
2016-04-08 10:33:50 +02:00
|
|
|
@manager = Managers::Machine.new(reservation, plan)
|
2017-02-23 17:45:55 +01:00
|
|
|
elsif reservation.reservable_type == 'Event'
|
2016-04-20 11:24:28 +02:00
|
|
|
@manager = Managers::Event.new(reservation, plan)
|
2017-02-23 17:45:55 +01:00
|
|
|
elsif reservation.reservable_type == 'Space'
|
|
|
|
@manager = Managers::Space.new(reservation, plan)
|
2016-04-08 11:11:42 +02:00
|
|
|
else
|
2017-02-23 17:45:55 +01:00
|
|
|
raise ArgumentError, 'reservation.reservable_type must be Training, Machine, Space or Event'
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
2016-04-08 11:11:42 +02:00
|
|
|
else
|
2017-02-23 17:45:55 +01:00
|
|
|
raise ArgumentError, 'you have to pass either a reservation or a user to initialize a UsersCredits::Manager'
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def_delegators :@manager, :will_use_credits?, :free_hours_count, :update_credits, :reset_credits
|
|
|
|
end
|
|
|
|
|
2020-05-06 12:43:47 +02:00
|
|
|
# The classes contained in UsersCredits::Managers are used by UsersCredits::Manager (no s) to handle the credits for
|
|
|
|
# the various kinds of reservations and for the user
|
2016-04-07 12:57:08 +02:00
|
|
|
module Managers
|
2018-12-06 18:26:01 +01:00
|
|
|
# that class is responsible for resetting users_credits of a user
|
|
|
|
class User
|
2016-04-07 12:57:08 +02:00
|
|
|
attr_reader :user
|
|
|
|
|
|
|
|
def initialize(user)
|
|
|
|
@user = user
|
|
|
|
end
|
|
|
|
|
|
|
|
def reset_credits
|
|
|
|
user.users_credits.destroy_all
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-05-06 12:43:47 +02:00
|
|
|
# Parent class of all reservations managers
|
2016-04-07 12:57:08 +02:00
|
|
|
class Reservation
|
|
|
|
attr_reader :reservation
|
|
|
|
|
2018-12-06 18:26:01 +01:00
|
|
|
# a plan can be passed to do a simulation (if user didn't have a subscription YET)
|
|
|
|
def initialize(reservation, plan)
|
2016-04-07 12:57:08 +02:00
|
|
|
@reservation = reservation
|
|
|
|
@already_updated = false
|
2016-04-08 10:33:50 +02:00
|
|
|
@plan = plan
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def plan
|
2016-04-08 10:33:50 +02:00
|
|
|
@plan || user.subscribed_plan
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def user
|
|
|
|
reservation.user
|
|
|
|
end
|
|
|
|
|
|
|
|
def update_credits
|
|
|
|
if @already_updated
|
|
|
|
raise AlreadyUpdatedError, "update credit is not idempotent ! you can't invoke update_credits method twice."
|
|
|
|
else
|
|
|
|
@already_updated = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
private_constant :Reservation
|
|
|
|
|
|
|
|
|
2018-12-06 18:26:01 +01:00
|
|
|
# that class is responsible for knowing how to update users_credit of a given user for a given reservation
|
|
|
|
class Machine < Reservation
|
|
|
|
# to known if a credit will be used in the context of the given reservation
|
|
|
|
def will_use_credits?
|
2016-04-07 12:57:08 +02:00
|
|
|
_will_use_credits?[0]
|
|
|
|
end
|
|
|
|
|
|
|
|
def free_hours_count
|
|
|
|
_will_use_credits?[1]
|
|
|
|
end
|
|
|
|
|
|
|
|
def update_credits
|
|
|
|
super
|
|
|
|
|
|
|
|
will_use_credits, free_hours_count, machine_credit = _will_use_credits?
|
2022-07-13 16:28:43 +02:00
|
|
|
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.hours_used = free_hours_count
|
|
|
|
else
|
|
|
|
users_credit.hours_used += free_hours_count
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
2022-07-13 16:28:43 +02:00
|
|
|
users_credit.save!
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2016-04-07 16:01:31 +02:00
|
|
|
|
2018-12-06 18:26:01 +01:00
|
|
|
def _will_use_credits?
|
|
|
|
return false, 0 unless plan
|
2016-04-07 12:57:08 +02:00
|
|
|
|
2022-07-13 16:28:43 +02:00
|
|
|
machine_credit = plan.machine_credits.find_by(creditable_id: reservation.reservable_id)
|
|
|
|
if machine_credit
|
2018-12-06 18:26:01 +01:00
|
|
|
users_credit = user.users_credits.find_by(credit_id: machine_credit.id)
|
|
|
|
already_used_hours = users_credit ? users_credit.hours_used : 0
|
2016-04-07 12:57:08 +02:00
|
|
|
|
2018-12-06 18:26:01 +01:00
|
|
|
remaining_hours = machine_credit.hours - already_used_hours
|
2016-04-07 12:57:08 +02:00
|
|
|
|
2022-07-13 16:28:43 +02:00
|
|
|
free_hours_count = [remaining_hours, reservation.slots_reservations.size].min
|
2018-12-06 18:26:01 +01:00
|
|
|
|
2022-07-13 16:28:43 +02:00
|
|
|
return free_hours_count&.positive?, free_hours_count, machine_credit
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
2020-05-06 12:43:47 +02:00
|
|
|
[false, 0]
|
2018-12-06 18:26:01 +01:00
|
|
|
end
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
|
|
|
|
2018-12-06 18:26:01 +01:00
|
|
|
# same as class Machine but for Training reservation
|
|
|
|
class Training < Reservation
|
2016-04-07 12:57:08 +02:00
|
|
|
def will_use_credits?
|
|
|
|
_will_use_credits?[0]
|
|
|
|
end
|
|
|
|
|
|
|
|
def update_credits
|
|
|
|
super
|
|
|
|
will_use_credits, training_credit = _will_use_credits?
|
2022-07-13 16:28:43 +02:00
|
|
|
|
|
|
|
user.credits << training_credit if will_use_credits # we create a new UsersCredit object
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2018-12-06 18:26:01 +01:00
|
|
|
|
|
|
|
def _will_use_credits?
|
|
|
|
return false, nil unless plan
|
|
|
|
|
|
|
|
# if there is a training_credit defined for this plan and this training
|
2022-07-13 16:28:43 +02:00
|
|
|
training_credit = plan.training_credits.find_by(creditable_id: reservation.reservable_id)
|
|
|
|
if training_credit
|
2018-12-06 18:26:01 +01:00
|
|
|
# if user has not used all the plan credits
|
2022-07-13 16:28:43 +02:00
|
|
|
return true, training_credit if user.training_credits.where(plan: plan).count < plan.training_credit_nb
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
2020-05-06 12:43:47 +02:00
|
|
|
[false, nil]
|
2018-12-06 18:26:01 +01:00
|
|
|
end
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
2016-04-20 11:24:28 +02:00
|
|
|
|
2020-05-06 12:43:47 +02:00
|
|
|
# same as class Machine but for Event reservation
|
2016-04-20 11:24:28 +02:00
|
|
|
class Event < Reservation
|
|
|
|
def will_use_credits?
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
2018-12-06 18:26:01 +01:00
|
|
|
def update_credits; end
|
2016-04-20 11:24:28 +02:00
|
|
|
end
|
2017-02-23 17:45:55 +01:00
|
|
|
|
2020-05-06 12:43:47 +02:00
|
|
|
# same as class Machine but for Space reservation
|
2017-02-23 17:45:55 +01:00
|
|
|
class Space < Reservation
|
2018-12-06 18:26:01 +01:00
|
|
|
# to known if a credit will be used in the context of the given reservation
|
|
|
|
def will_use_credits?
|
2017-02-27 17:38:15 +01:00
|
|
|
_will_use_credits?[0]
|
|
|
|
end
|
|
|
|
|
|
|
|
def free_hours_count
|
|
|
|
_will_use_credits?[1]
|
2017-02-23 17:45:55 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def update_credits
|
2017-02-27 17:38:15 +01:00
|
|
|
super
|
|
|
|
|
|
|
|
will_use_credits, free_hours_count, space_credit = _will_use_credits?
|
2018-12-06 18:26:01 +01:00
|
|
|
return unless will_use_credits
|
2017-02-27 17:38:15 +01:00
|
|
|
|
2018-12-06 18:26:01 +01:00
|
|
|
users_credit = user.users_credits.find_or_initialize_by(credit_id: space_credit.id)
|
|
|
|
|
|
|
|
if users_credit.new_record?
|
|
|
|
users_credit.hours_used = free_hours_count
|
|
|
|
else
|
|
|
|
users_credit.hours_used += free_hours_count
|
2017-02-27 17:38:15 +01:00
|
|
|
end
|
2018-12-06 18:26:01 +01:00
|
|
|
users_credit.save!
|
2017-02-27 17:38:15 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2018-12-06 18:26:01 +01:00
|
|
|
|
2017-02-27 17:38:15 +01:00
|
|
|
def _will_use_credits?
|
|
|
|
return false, 0 unless plan
|
|
|
|
|
2022-07-13 16:28:43 +02:00
|
|
|
space_credit = plan.space_credits.find_by(creditable_id: reservation.reservable_id)
|
|
|
|
if space_credit
|
2017-02-27 17:38:15 +01:00
|
|
|
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
|
|
|
|
|
2022-07-13 16:28:43 +02:00
|
|
|
free_hours_count = [remaining_hours, reservation.slots_reservations.size].min
|
2017-02-27 17:38:15 +01:00
|
|
|
|
2022-07-13 16:28:43 +02:00
|
|
|
return free_hours_count&.positive?, free_hours_count, space_credit
|
2017-02-27 17:38:15 +01:00
|
|
|
end
|
2020-05-06 12:43:47 +02:00
|
|
|
[false, 0]
|
2017-02-23 17:45:55 +01:00
|
|
|
end
|
|
|
|
end
|
2016-04-07 12:57:08 +02:00
|
|
|
end
|
|
|
|
end
|