Skip to content

Commit

Permalink
adding time in transit
Browse files Browse the repository at this point in the history
  • Loading branch information
Sean Harper authored and Zac Williams committed Dec 14, 2010
1 parent 7ee5ac0 commit ca52819
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 7 deletions.
48 changes: 45 additions & 3 deletions app/models/calculator/active_shipping.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,36 @@ def compute(object)
rate = rates[self.class.description].to_f + (Spree::ActiveShipping::Config[:handling_fee].to_f || 0.0)
return nil unless rate
# divide by 100 since active_shipping rates are expressed as cents

return rate/100.0
end

private

def timing(line_items)
order = line_items.first.order
origin = Location.new(:country => Spree::ActiveShipping::Config[:origin_country],
:city => Spree::ActiveShipping::Config[:origin_city],
:state => Spree::ActiveShipping::Config[:origin_state],
:zip => Spree::ActiveShipping::Config[:origin_zip])
addr = order.ship_address
destination = Location.new(:country => addr.country.iso,
:state => (addr.state ? addr.state.abbr : addr.state_name),
:city => addr.city,
:zip => addr.zipcode)
timings = Rails.cache.fetch(cache_key(line_items)+"-timings") do
timings = retrieve_timings(origin, destination, packages(order))
end
return nil if timings.nil? || !timings.is_a?(Hash) || timings.empty?
return timings[self.description]

end

private
def retrieve_rates(origin, destination, packages)
begin
response = carrier.find_rates(origin, destination, packages)
# turn this beastly array into a nice little hash
Hash[*response.rates.collect { |rate| [rate.service_name, rate.price] }.flatten]
rate_hash = Hash[*response.rates.collect { |rate| [rate.service_name, rate.price] }.flatten]
return rate_hash
rescue ActiveMerchant::Shipping::ResponseError => re
params = re.response.params
if params.has_key?("Response") && params["Response"].has_key?("Error") && params["Response"]["Error"].has_key?("ErrorDescription")
Expand All @@ -58,9 +77,32 @@ def retrieve_rates(origin, destination, packages)

Rails.cache.delete @cache_key # delete cache to prevent constant re-lookups
raise Spree::ShippingError, "#{I18n.t('shipping_error')}: #{message}"

end
end


def retrieve_timings(origin, destination, packages)
begin
if carrier.respond_to?(:find_time_in_transit)
response = carrier.find_time_in_transit(origin, destination, packages)
return response
end
rescue ActiveMerchant::Shipping::ResponseError => re
params = re.response.params
if params.has_key?("Response") && params["Response"].has_key?("Error") && params["Response"]["Error"].has_key?("ErrorDescription")
message = params["Response"]["Error"]["ErrorDescription"]
elsee
message = re.message
end
Rails.cache.write @cache_key+'-', {} #write empty hash to cache to prevent constant re-lookups
raise Spree::ShippingError.new("#{I18n.t('shipping_error')}: #{message}")
end
end


private

# Generates an array of Package objects based on the quantities and weights of the variants in the line items
def packages(order)
multiplier = Spree::ActiveShipping::Config[:unit_multiplier]
Expand Down
118 changes: 114 additions & 4 deletions lib/spree/active_shipping/ups_override.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ module ActiveShipping
module UpsOverride
def self.included(base)


base.class_eval do

def build_rate_request(origin, destination, packages, options={})
packages = Array(packages)
xml_request = XmlNode.new('RatingServiceSelectionRequest') do |root_node|
Expand Down Expand Up @@ -99,6 +99,55 @@ def build_rate_request(origin, destination, packages, options={})
xml_request.to_s
end

def build_time_in_transit_request(origin, destination, packages, options={})
packages = Array(packages)
xml_request = XmlNode.new('TimeInTransitRequest') do |root_node|
root_node << XmlNode.new('Request') do |request|
request << XmlNode.new('TransactionReference') do |transaction_reference|
transaction_reference << XmlNode.new('CustomerContext', 'Time in Transit')
transaction_reference << XmlNode.new('XpciVersion', '1.0002')
end
request << XmlNode.new('RequestAction', 'TimeInTransit')
end
root_node << XmlNode.new('TransitFrom') do |transit_from|
transit_from << XmlNode.new('AddressArtifactFormat') do |address_artifact_format|
address_artifact_format << XmlNode.new('PoliticalDivision2',origin.city)
address_artifact_format << XmlNode.new('PoliticalDivision1',origin.state)
address_artifact_format << XmlNode.new('CountryCode',origin.country_code(:alpha2))
address_artifact_format << XmlNode.new('PostcodePrimaryLow',origin.postal_code)
end
end

root_node << XmlNode.new('TransitTo') do |transit_to|
transit_to << XmlNode.new('AddressArtifactFormat') do |address_artifact_format|
address_artifact_format << XmlNode.new('PoliticalDivision2',destination.city)
address_artifact_format << XmlNode.new('PoliticalDivision1',destination.state)
address_artifact_format << XmlNode.new('CountryCode',destination.country_code(:alpha2))
address_artifact_format << XmlNode.new('PostcodePrimaryLow',destination.postal_code)
end
end

root_node << XmlNode.new("ShipmentWeight") do |shipment_weight|
shipment_weight << XmlNode.new("UnitOfMeasurement") do |units|
units << XmlNode.new("Code", 'LBS')
end

value = ((packages[0].lbs).to_f*1000).round/1000.0 # 3 decimals
shipment_weight << XmlNode.new("Weight", [value,0.1].max)
end

root_node << XmlNode.new("InvoiceLineTotal") do |invoice_line_total|
invoice_line_total << XmlNode.new("CurrencyCode","USD")
invoice_line_total << XmlNode.new("MonetaryValue","50")
end

root_node << XmlNode.new("PickupDate",Date.today.strftime("%Y%m%d"))


end
xml_request.to_s
end

def build_location_node(name,location,options={})
# not implemented: * Shipment/Shipper/Name element
# * Shipment/(ShipTo|ShipFrom)/CompanyName element
Expand Down Expand Up @@ -129,17 +178,78 @@ def build_location_node(name,location,options={})
end
end

def parse_rate_response(origin, destination, packages, response, options={})
def find_time_in_transit(origin, destination, packages, options={})
origin, destination = upsified_location(origin), upsified_location(destination)
options = @options.merge(options)
packages = Array(packages)
access_request = build_access_request
rate_request = build_time_in_transit_request(origin, destination, packages, options)
response = ssl_post("https://www.ups.com/ups.app/xml/TimeInTransit", "<?xml version=\"1.0\"?>"+access_request+"<?xml version=\"1.0\"?>"+rate_request)
parse_time_in_transit_response(origin, destination, packages,response, options)
end

def find_rates(origin, destination, packages, options={})
origin, destination = upsified_location(origin), upsified_location(destination)
options = @options.merge(options)
packages = Array(packages)
access_request = build_access_request
rate_request = build_rate_request(origin, destination, packages, options)
response = commit(:rates, save_request(access_request + rate_request), (options[:test] || false))
parse_rate_response(origin, destination, packages, response, options)
end


def parse_time_in_transit_response(origin, destination, packages, response, options={})

time_code_mapping = {
"DA" => "01",
"2DA" => "02",
"GND" => "03",
"01" => "07",
"05" => "08",
"03" => "11",
"3DS" => "12",
"1DP" => "13",
"1DM" => "14",
"21" => "54",
"2DM" => "59"
}

rates = []
xml = REXML::Document.new(response)
success = response_success?(xml)
message = response_message(xml)
if success
rate_estimates = {}
xml.elements.each('/*/TransitResponse/ServiceSummary') do |service_summary|
service_code = service_summary.get_text('Service/Code').to_s
service_code_2 = time_code_mapping[service_code]
service_desc = service_summary.get_text('Service/Description').to_s
guaranteed_code = service_summary.get_text('Guaranteed/Code').to_s
business_transit_days = service_summary.get_text('EstimatedArrival/BusinessTransitDays').to_s
date = service_summary.get_text('EstimatedArrival/Date').to_s
rate_estimates[service_desc] = {:service_code => service_code, :service_code_2 => service_code_2, :service_desc => service_desc,
:guaranteed_code => guaranteed_code, :business_transit_days => business_transit_days,
:date => date}
end
end
return rate_estimates
end



def parse_rate_response(origin, destination, packages, response, options={})
rates = []
xml = REXML::Document.new(response)
success = response_success?(xml)
message = response_message(xml)
transits = options[:transit]
if success
rate_estimates = []

xml.elements.each('/*/RatedShipment') do |rated_shipment|
service_code = rated_shipment.get_text('Service/Code').to_s
service = rated_shipment.get_text('Service/Code').to_s
negotiated_rate = rated_shipment.get_text('NegotiatedRates/NetSummaryCharges/GrandTotal/MonetaryValue').to_s
total_price = negotiated_rate.blank? ? rated_shipment.get_text('TotalCharges/MonetaryValue').to_s.to_f : negotiated_rate.to_f
currency = negotiated_rate.blank? ? rated_shipment.get_text('TotalCharges/CurrencyCode').to_s : rated_shipment.get_text('NegotiatedRates/NetSummaryCharges/GrandTotal/CurrencyCode').to_s
Expand All @@ -149,12 +259,12 @@ def parse_rate_response(origin, destination, packages, response, options={})
:total_price => total_price,
:currency => currency,
:service_code => service_code,
:packages => packages)
:packages => packages
)
end
end
ActiveMerchant::Shipping::RateResponse.new(success, message, Hash.from_xml(response).values.first, :rates => rate_estimates, :xml => response, :request => last_request)
end

end
end

Expand Down

0 comments on commit ca52819

Please sign in to comment.