mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-29 18:52:22 +01:00
improved slot price calculation
This commit is contained in:
parent
6091cec82e
commit
2d807e6c94
@ -16,7 +16,6 @@ class CartItem::Reservation < CartItem::BaseItem
|
||||
end
|
||||
|
||||
def price
|
||||
base_amount = hourly_rate
|
||||
is_privileged = @operator.privileged? && @operator.id != @customer.id
|
||||
prepaid = { minutes: PrepaidPackService.minutes_available(@customer, @reservable) }
|
||||
|
||||
@ -25,10 +24,10 @@ class CartItem::Reservation < CartItem::BaseItem
|
||||
|
||||
hours_available = credits
|
||||
@slots.each_with_index do |slot, index|
|
||||
amount += get_slot_price(base_amount, slot, is_privileged,
|
||||
elements: elements,
|
||||
has_credits: (index < hours_available),
|
||||
prepaid: prepaid)
|
||||
amount += get_slot_price_from_prices(applicable_prices, slot, is_privileged,
|
||||
elements: elements,
|
||||
has_credits: (index < hours_available),
|
||||
prepaid: prepaid)
|
||||
end
|
||||
|
||||
{ elements: elements, amount: amount }
|
||||
@ -61,6 +60,27 @@ class CartItem::Reservation < CartItem::BaseItem
|
||||
0
|
||||
end
|
||||
|
||||
##
|
||||
# Compute the price of a single slot, according to the list of applicable prices.
|
||||
# @param prices {{ prices: Array<{price: Price, duration: number}> }} list of prices to use with the current reservation
|
||||
# @see get_slot_price
|
||||
##
|
||||
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
|
||||
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
|
||||
|
||||
# apply the base price to the real slot duration
|
||||
real_price = get_slot_price(hourly_rate, slot, is_privileged, options)
|
||||
|
||||
price[:duration] -= slot_minutes
|
||||
|
||||
real_price
|
||||
end
|
||||
|
||||
##
|
||||
# Compute the price of a single slot, according to the base price and the ability for an admin
|
||||
# to offer the slot.
|
||||
@ -103,15 +123,14 @@ class CartItem::Reservation < CartItem::BaseItem
|
||||
real_price
|
||||
end
|
||||
|
||||
# We compute the hourly rate according to the prices of the current reservation
|
||||
# If there are prices for durations longer than 1 hour, but shorter than the total duration,
|
||||
# we use these prices before using the hourly rate.
|
||||
# We determine the list of prices applicable to current reservation
|
||||
# The longest available price is always used in priority.
|
||||
# Eg. If the reservation is for 12 hours, and there are prices for 3 hours, 7 hours,
|
||||
# and the base price (1 hours), we use the 7 hours price, then 3 hours price, and finally the base price.
|
||||
# Then we divide the total price by the total duration to get the hourly rate.
|
||||
def hourly_rate
|
||||
# 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
|
||||
total_duration = @slots.map { |slot| (slot[:end_at].to_time - slot[:start_at].to_time) / SECONDS_PER_MINUTE }.reduce(:+)
|
||||
price = 0
|
||||
rates = { prices: [] }
|
||||
|
||||
remaining_duration = total_duration
|
||||
while remaining_duration.positive?
|
||||
@ -119,15 +138,16 @@ class CartItem::Reservation < CartItem::BaseItem
|
||||
.where(Price.arel_table[:duration].lteq(remaining_duration))
|
||||
.maximum(:duration)
|
||||
max_duration = 60 if max_duration.nil?
|
||||
max_duration_amount = @reservable.prices.find_by(group_id: @customer.group_id, plan_id: @plan.try(:id), duration: max_duration)
|
||||
.amount
|
||||
max_duration_price = @reservable.prices.find_by(group_id: @customer.group_id, plan_id: @plan.try(:id), duration: max_duration)
|
||||
|
||||
current_duration = [remaining_duration, max_duration].min
|
||||
price += (max_duration_amount / max_duration) * current_duration
|
||||
remaining_duration -= max_duration
|
||||
rates[:prices].push(price: max_duration_price, duration: current_duration)
|
||||
|
||||
remaining_duration -= current_duration
|
||||
end
|
||||
|
||||
price / (total_duration / MINUTES_PER_HOUR)
|
||||
rates[:prices].sort! { |a, b| b[:duration] <=> a[:duration] }
|
||||
rates
|
||||
end
|
||||
|
||||
##
|
||||
|
Loading…
x
Reference in New Issue
Block a user