2021-04-22 19:24:08 +02:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# Stores data about a shopping data
|
|
|
|
class ShoppingCart
|
2021-05-21 18:25:18 +02:00
|
|
|
attr_accessor :customer, :operator, :payment_method, :items, :coupon, :payment_schedule
|
2021-04-22 19:24:08 +02:00
|
|
|
|
|
|
|
# @param items {Array<CartItem::BaseItem>}
|
|
|
|
# @param coupon {CartItem::Coupon}
|
|
|
|
# @param payment_schedule {CartItem::PaymentSchedule}
|
|
|
|
# @param customer {User}
|
2021-05-21 18:25:18 +02:00
|
|
|
# @param operator {User}
|
|
|
|
def initialize(customer, operator, coupon, payment_schedule, payment_method = '', items: [])
|
2021-04-26 11:40:26 +02:00
|
|
|
raise TypeError unless customer.is_a? User
|
2021-04-22 19:24:08 +02:00
|
|
|
|
|
|
|
@customer = customer
|
2021-05-21 18:25:18 +02:00
|
|
|
@operator = operator
|
2021-04-22 19:24:08 +02:00
|
|
|
@payment_method = payment_method
|
|
|
|
@items = items
|
|
|
|
@coupon = coupon
|
|
|
|
@payment_schedule = payment_schedule
|
|
|
|
end
|
|
|
|
|
2021-04-23 12:52:06 +02:00
|
|
|
# compute the price details of the current shopping cart
|
2021-04-22 19:24:08 +02:00
|
|
|
def total
|
|
|
|
total_amount = 0
|
|
|
|
all_elements = { slots: [] }
|
|
|
|
|
|
|
|
@items.map(&:price).each do |price|
|
|
|
|
total_amount += price[:amount]
|
2021-04-23 17:54:59 +02:00
|
|
|
all_elements = all_elements.merge(price[:elements]) do |_key, old_val, new_val|
|
2021-04-22 19:24:08 +02:00
|
|
|
old_val | new_val
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
coupon_info = @coupon.price(total_amount)
|
|
|
|
schedule_info = @payment_schedule.schedule(coupon_info[:total_with_coupon], coupon_info[:total_without_coupon])
|
|
|
|
|
|
|
|
# return result
|
|
|
|
{
|
|
|
|
elements: all_elements,
|
|
|
|
total: schedule_info[:total].to_i,
|
|
|
|
before_coupon: coupon_info[:total_without_coupon].to_i,
|
|
|
|
coupon: @coupon.coupon,
|
|
|
|
schedule: schedule_info[:schedule]
|
|
|
|
}
|
|
|
|
end
|
2021-05-21 18:25:18 +02:00
|
|
|
|
2021-05-31 11:52:53 +02:00
|
|
|
# Build the dataset for the current ShoppingCart and save it into the database.
|
|
|
|
# Data integrity is guaranteed: all goes right or nothing is saved.
|
2021-05-28 17:34:20 +02:00
|
|
|
def build_and_save(payment_id, payment_type)
|
2022-03-18 19:44:30 +01:00
|
|
|
user_validation_required = Setting.get('user_validation_required')
|
|
|
|
user_validation_required_list = Setting.get('user_validation_required_list')
|
|
|
|
unless @operator.privileged?
|
|
|
|
if user_validation_required && user_validation_required_list.present?
|
|
|
|
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 }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-05-21 18:25:18 +02:00
|
|
|
price = total
|
|
|
|
objects = []
|
2021-05-28 17:34:20 +02:00
|
|
|
payment = nil
|
2021-05-21 18:25:18 +02:00
|
|
|
ActiveRecord::Base.transaction do
|
|
|
|
items.each do |item|
|
2021-05-31 11:52:53 +02:00
|
|
|
objects.push(save_item(item))
|
2021-05-21 18:25:18 +02:00
|
|
|
end
|
2021-05-31 11:52:53 +02:00
|
|
|
update_credits(objects)
|
2021-06-30 10:53:05 +02:00
|
|
|
update_packs(objects)
|
2021-05-21 18:25:18 +02:00
|
|
|
|
2021-05-31 11:52:53 +02:00
|
|
|
payment = create_payment_document(price, objects, payment_id, payment_type)
|
|
|
|
WalletService.debit_user_wallet(payment, @customer)
|
2021-05-21 18:25:18 +02:00
|
|
|
payment.save
|
2021-10-15 17:31:01 +02:00
|
|
|
payment.post_save(payment_id, payment_type)
|
2021-05-21 18:25:18 +02:00
|
|
|
end
|
|
|
|
|
2021-10-07 17:07:46 +02:00
|
|
|
success = !payment.nil? && objects.map(&:errors).flatten.map(&:empty?).all? && items.map(&:errors).map(&:empty?).all?
|
2021-05-31 15:39:56 +02:00
|
|
|
errors = objects.map(&:errors).flatten.concat(items.map(&:errors))
|
2021-10-07 17:07:46 +02:00
|
|
|
errors.push('Unable to create the PaymentDocument') if payment.nil?
|
2021-05-31 15:39:56 +02:00
|
|
|
{ success: success, payment: payment, errors: errors }
|
2021-05-21 18:25:18 +02:00
|
|
|
end
|
2021-05-31 11:52:53 +02:00
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
# Save the object associated with the provided item or raise and Rollback if something wrong append.
|
|
|
|
def save_item(item)
|
2021-05-31 15:39:56 +02:00
|
|
|
raise ActiveRecord::Rollback unless item.valid?(@items)
|
|
|
|
|
2021-05-31 11:52:53 +02:00
|
|
|
object = item.to_object
|
|
|
|
object.save
|
|
|
|
raise ActiveRecord::Rollback unless object.errors.empty?
|
|
|
|
|
|
|
|
object
|
|
|
|
end
|
|
|
|
|
|
|
|
# Create the PaymentDocument associated with this ShoppingCart and return it
|
|
|
|
def create_payment_document(price, objects, payment_id, payment_type)
|
|
|
|
if price[:schedule]
|
|
|
|
PaymentScheduleService.new.create(
|
|
|
|
objects,
|
|
|
|
price[:before_coupon],
|
2021-10-14 18:20:10 +02:00
|
|
|
@customer,
|
2021-05-31 11:52:53 +02:00
|
|
|
coupon: @coupon.coupon,
|
|
|
|
operator: @operator,
|
|
|
|
payment_method: @payment_method,
|
|
|
|
payment_id: payment_id,
|
|
|
|
payment_type: payment_type
|
|
|
|
)
|
|
|
|
else
|
|
|
|
InvoicesService.create(
|
|
|
|
price,
|
|
|
|
@operator.invoicing_profile.id,
|
|
|
|
objects,
|
|
|
|
@customer,
|
|
|
|
payment_id: payment_id,
|
|
|
|
payment_type: payment_type,
|
|
|
|
payment_method: @payment_method
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Handle the update of the user's credits
|
|
|
|
# If a subscription has been bought, the credits must be reset first.
|
|
|
|
# Then, the credits related to reservation(s) can be deducted.
|
|
|
|
def update_credits(objects)
|
|
|
|
subscription = objects.find { |o| o.is_a? Subscription }
|
|
|
|
UsersCredits::Manager.new(user: @customer).reset_credits if subscription
|
|
|
|
|
|
|
|
reservations = objects.filter { |o| o.is_a? Reservation }
|
|
|
|
reservations.each do |r|
|
|
|
|
UsersCredits::Manager.new(reservation: r).update_credits
|
|
|
|
end
|
|
|
|
end
|
2021-06-30 10:53:05 +02:00
|
|
|
|
|
|
|
# Handle the update of the user's prepaid-packs
|
|
|
|
# The total booked minutes are subtracted from the user's prepaid minutes
|
|
|
|
def update_packs(objects)
|
|
|
|
objects.filter { |o| o.is_a? Reservation }.each do |reservation|
|
|
|
|
PrepaidPackService.update_user_minutes(@customer, reservation)
|
|
|
|
end
|
|
|
|
end
|
2021-04-22 19:24:08 +02:00
|
|
|
end
|