module ActiveShipping #:nodoc: class RateEstimate attr_reader :origin # Location objects attr_reader :destination attr_reader :package_rates # array of hashes in the form of {:package => , :rate => 500} attr_reader :carrier # Carrier.name ('USPS', 'FedEx', etc.) attr_reader :service_name # name of service ("First Class Ground", etc.) attr_reader :service_code attr_reader :currency # 'USD', 'CAD', etc. # http://en.wikipedia.org/wiki/ISO_4217 attr_reader :shipping_date attr_reader :delivery_date # Usually only available for express shipments attr_reader :delivery_range # Min and max delivery estimate in days attr_reader :negotiated_rate attr_reader :insurance_price def initialize(origin, destination, carrier, service_name, options = {}) @origin, @destination, @carrier, @service_name = origin, destination, carrier, service_name @service_code = options[:service_code] if options[:package_rates] @package_rates = options[:package_rates].map { |p| p.update(:rate => Package.cents_from(p[:rate])) } else @package_rates = Array(options[:packages]).map { |p| {:package => p} } end @total_price = Package.cents_from(options[:total_price]) @negotiated_rate = options[:negotiated_rate] ? Package.cents_from(options[:negotiated_rate]) : nil @currency = ActiveUtils::CurrencyCode.standardize(options[:currency]) @delivery_range = options[:delivery_range] ? options[:delivery_range].map { |date| date_for(date) }.compact : [] @shipping_date = date_for(options[:shipping_date]) @delivery_date = @delivery_range.last @insurance_price = Package.cents_from(options[:insurance_price]) end def total_price @total_price || @package_rates.sum { |p| p[:rate] } rescue NoMethodError raise ArgumentError.new("RateEstimate must have a total_price set, or have a full set of valid package rates.") end alias_method :price, :total_price def add(package, rate = nil) cents = Package.cents_from(rate) raise ArgumentError.new("New packages must have valid rate information since this RateEstimate has no total_price set.") if cents.nil? and total_price.nil? @package_rates << {:package => package, :rate => cents} self end def packages package_rates.map { |p| p[:package] } end def package_count package_rates.length end private def date_for(date) date && DateTime.strptime(date.to_s, "%Y-%m-%d") rescue ArgumentError nil end end end