sealink/quicktravel_client

View on GitHub
lib/quick_travel/product_configuration.rb

Summary

Maintainability
A
3 hrs
Test Coverage
require 'quick_travel/adapter'
require 'set'

module QuickTravel
  class ProductConfiguration
    attr_reader :product, :extra_pick_configurations
    delegate :id, :name, to: :product

    def initialize(product)
      @product = product
      @selected = false
      @extra_pick_configurations =
        product.extras.map { |extra_pick| self.class.new(extra_pick) }
    end

    def select!
      @selected = true
    end

    def deselect!
      @selected = false
    end

    def selected?
      @selected
    end

    def available?
      @product.available? &&
        selected_extra_pick_configurations.all?(&:available?)
    end

    def priced?
      @product.try(:pricing_details).present?
    end

    def price
      pricing_details.minimum_price_with_adjustments
    end

    def price_without_rules
      pricing_details_without_rules.minimum_price_with_adjustments
    end

    def price_for_rack_rate
      pricing_details_for_rack_rate.minimum_price_with_adjustments
    end

    def total_price
      price + selected_extra_picks_price
    end

    def total_price_without_rules
      price_without_rules + selected_extra_picks_price_without_rules
    end

    def total_price_for_rack_rate
      price_for_rack_rate + selected_extra_picks_price_for_rack_rate
    end

    def applied_rules
      pricing_details.applied_rules.uniq
    end

    def total_applied_rules
      (applied_rules + selected_extra_picks_applied_rules).uniq
    end

    def price_per_passenger_type(passenger_type_id)
      pricing_details.price_per_pax_type[passenger_type_id]
    end

    def selected_extra_pick_configurations
      @extra_pick_configurations.select(&:selected?)
    end

    def available_extra_pick_configurations
      @extra_pick_configurations.select(&:available?)
    end

    def select_extra_picks(extra_picks)
      extra_picks.each do |extra_pick|
        select_extra_pick(extra_pick)
      end
    end

    def select_extra_pick(extra_pick)
      extra_pick_configuration = configuration_for(extra_pick)

      if extra_pick_configuration.nil?
        fail ArgumentError, 'That extra pick does not belong to the product'
      end

      extra_pick_configuration.select!
    end

    private

    def configuration_for(extra_pick)
      @extra_pick_configurations.find do |extra_pick_configuration|
        extra_pick_configuration.product == extra_pick
      end
    end

    def selected_extra_picks_with_price
      selected_extra_pick_configurations.select(&:priced?)
    end

    def selected_extra_picks_price
      total_money(selected_extra_picks_with_price.map(&:price))
    end

    def selected_extra_picks_price_without_rules
      total_money(selected_extra_picks_with_price.map(&:price_without_rules))
    end

    def selected_extra_picks_price_for_rack_rate
      total_money(selected_extra_picks_with_price.map(&:price_for_rack_rate))
    end

    def selected_extra_picks_applied_rules
      selected_extra_picks_with_price.flat_map(&:applied_rules)
    end

    def total_money(array)
      array.reduce(Money.new(0), :+)
    end

    def pricing_details
      fail 'Unable to calculate pricing details' unless priced?
      @product.pricing_details
    end

    def pricing_details_without_rules
      @product.pricing_details_without_rules || pricing_details
    end

    def pricing_details_for_rack_rate
      @product.pricing_details_for_rack_rate || pricing_details
    end
  end
end