spree_active_shipping 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/README.md +67 -0
- data/Rakefile +45 -0
- data/app/controllers/admin/shipments_controller_decorator.rb +11 -0
- data/app/controllers/admin/shipping_methods_controller_decorator.rb +15 -0
- data/app/controllers/checkout_controller_decorator.rb +11 -0
- data/app/models/calculator/active_shipping.rb +126 -0
- data/app/models/calculator/fedex/base.rb +8 -0
- data/app/models/calculator/fedex/base.rb~ +7 -0
- data/app/models/calculator/fedex/express_saver.rb +5 -0
- data/app/models/calculator/fedex/first_overnight.rb +5 -0
- data/app/models/calculator/fedex/ground.rb +5 -0
- data/app/models/calculator/fedex/ground_home_delivery.rb +5 -0
- data/app/models/calculator/fedex/international_economy.rb +5 -0
- data/app/models/calculator/fedex/international_economy_freight.rb +5 -0
- data/app/models/calculator/fedex/international_first.rb +5 -0
- data/app/models/calculator/fedex/international_ground.rb +5 -0
- data/app/models/calculator/fedex/international_priority.rb +5 -0
- data/app/models/calculator/fedex/international_priority_freight.rb +5 -0
- data/app/models/calculator/fedex/international_priority_saturday_delivery.rb +5 -0
- data/app/models/calculator/fedex/one_day_freight.rb +5 -0
- data/app/models/calculator/fedex/one_day_freight_saturday_delivery.rb +5 -0
- data/app/models/calculator/fedex/priority_overnight.rb +5 -0
- data/app/models/calculator/fedex/priority_overnight_saturday_delivery.rb +5 -0
- data/app/models/calculator/fedex/saver.rb +5 -0
- data/app/models/calculator/fedex/saver.rb~ +5 -0
- data/app/models/calculator/fedex/standard_overnight.rb +5 -0
- data/app/models/calculator/fedex/three_day_freight.rb +5 -0
- data/app/models/calculator/fedex/three_day_freight_saturday_delivery.rb +5 -0
- data/app/models/calculator/fedex/two_day.rb +5 -0
- data/app/models/calculator/fedex/two_day_freight.rb +5 -0
- data/app/models/calculator/fedex/two_day_freight_saturday_delivery.rb +5 -0
- data/app/models/calculator/fedex/two_day_saturday_delivery.rb +5 -0
- data/app/models/calculator/ups/base.rb +15 -0
- data/app/models/calculator/ups/ground.rb +5 -0
- data/app/models/calculator/ups/next_day_air.rb +5 -0
- data/app/models/calculator/ups/next_day_air_early_am.rb +5 -0
- data/app/models/calculator/ups/next_day_air_saver.rb +5 -0
- data/app/models/calculator/ups/saver.rb +5 -0
- data/app/models/calculator/ups/second_day_air.rb +5 -0
- data/app/models/calculator/ups/three_day_select.rb +5 -0
- data/app/models/calculator/ups/worldwide_expedited.rb +5 -0
- data/app/models/calculator/usps/base.rb +5 -0
- data/app/models/calculator/usps/express_mail.rb +5 -0
- data/app/models/calculator/usps/express_mail_international.rb +5 -0
- data/app/models/calculator/usps/media_mail.rb +5 -0
- data/app/models/calculator/usps/priority_mail.rb +5 -0
- data/app/models/calculator/usps/priority_mail_international.rb +5 -0
- data/app/models/calculator/usps/priority_mail_large_flat_rate_box.rb +5 -0
- data/app/models/calculator/usps/priority_mail_regular_medium_flat_rate_boxes.rb +5 -0
- data/app/models/calculator/usps/priority_mail_small_flat_rate_box.rb +5 -0
- data/app/views/admin/shipping_methods/_form.html.erb +42 -0
- data/config/locales/en.yml +3 -0
- data/lib/active_shipping_configuration.rb +25 -0
- data/lib/spree/active_shipping/config.rb +22 -0
- data/lib/spree/active_shipping/ups_override.rb +274 -0
- data/lib/spree/shipping_error.rb +3 -0
- data/lib/spree_active_shipping.rb +74 -0
- data/lib/tasks/active_shipping_extension_tasks.rake +29 -0
- data/spec/lib/spree/bogus_calculator.rb +11 -0
- data/spec/lib/spree/bogus_carrier.rb +15 -0
- data/spec/models/active_shipping_calculator_spec.rb +51 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +33 -0
- data/spree_active_shipping.gemspec +23 -0
- metadata +184 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
class Calculator::Ups::Base < Calculator::ActiveShipping
|
2
|
+
def carrier
|
3
|
+
if Spree::ActiveShipping::Config[:shipper_number].nil?
|
4
|
+
ActiveMerchant::Shipping::UPS.new(:login => Spree::ActiveShipping::Config[:ups_login],
|
5
|
+
:password => Spree::ActiveShipping::Config[:ups_password],
|
6
|
+
:key => Spree::ActiveShipping::Config[:ups_key])
|
7
|
+
else
|
8
|
+
ActiveMerchant::Shipping::UPS.new(:login => Spree::ActiveShipping::Config[:ups_login],
|
9
|
+
:password => Spree::ActiveShipping::Config[:ups_password],
|
10
|
+
:key => Spree::ActiveShipping::Config[:ups_key],
|
11
|
+
:origin_account => Spree::ActiveShipping::Config[:shipper_number])
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<%- locals = {:f => f} %>
|
2
|
+
<%= hook :admin_shipping_method_form_fields, locals do %>
|
3
|
+
<%= f.field_container :name do %>
|
4
|
+
<%= f.label :name, t("name") %><br />
|
5
|
+
<%= f.text_field :name %>
|
6
|
+
<%= error_message_on :shipping_method, :name %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<%= f.field_container :zone_id do %>
|
10
|
+
<%= f.label :zone_id, t("zone") %><br />
|
11
|
+
<%= f.collection_select(:zone_id, @available_zones, :id, :name, {}, {"style" => "width:200px"}) %>
|
12
|
+
<%= error_message_on :shipping_method, :zone_id %>
|
13
|
+
<% end %>
|
14
|
+
<%= f.field_container :display_on do %>
|
15
|
+
<%= f.label :display_on, t("display") %><br />
|
16
|
+
<%= select(:shipping_method, :display_on, ShippingMethod::DISPLAY.collect {|display| [t(display), display == :both ? nil : display.to_s]}) %>
|
17
|
+
<%= error_message_on :shipping_method, :display_on %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<%= hook :admin_shipping_method_form_calculator_fields, locals do %>
|
22
|
+
<fieldset id="calculator_fields">
|
23
|
+
<legend><%= t('calculator') %></legend>
|
24
|
+
<div id="preference-settings">
|
25
|
+
<p>
|
26
|
+
<%= f.label(:calc_type, t("calculator")) %>
|
27
|
+
<%= f.collection_select(:calculator_type, @calculators, :class, :description, {}, {:id => "calc-type"}) %>
|
28
|
+
</p>
|
29
|
+
<% if !@object.new_record? %>
|
30
|
+
<div class="calculator-settings">
|
31
|
+
<%= f.fields_for :calculator do |calculator_form| %>
|
32
|
+
<%= preference_fields(@object.calculator, calculator_form) %>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
35
|
+
<% if @object.calculator.respond_to?(:preferences) %>
|
36
|
+
<div id="calculator-settings-warning"><%= t('calculator_settings_warning')%></div>
|
37
|
+
<% end %>
|
38
|
+
<% end %>
|
39
|
+
</div>
|
40
|
+
</fieldset>
|
41
|
+
<% end %>
|
42
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class ActiveShippingConfiguration < Configuration
|
2
|
+
|
3
|
+
preference :ups_login, :string, :default => "aunt_judy"
|
4
|
+
preference :ups_password, :string, :default => "secret"
|
5
|
+
preference :ups_key, :string, :default => "developer_key"
|
6
|
+
preference :shipper_number, :string, :default => nil
|
7
|
+
|
8
|
+
preference :fedex_login, :string, :default => "meter_no"
|
9
|
+
preference :fedex_password, :string, :default => "special_sha1_looking_thing_sent_via_email"
|
10
|
+
preference :fedex_account, :string, :default => "account_no"
|
11
|
+
preference :fedex_key, :string, :default => "authorization_key"
|
12
|
+
|
13
|
+
preference :usps_login, :string, :default => "aunt_judy"
|
14
|
+
|
15
|
+
preference :origin_country, :string, :default => "US"
|
16
|
+
preference :origin_state, :string, :default => "PA"
|
17
|
+
preference :origin_city, :string, :default => "University Park"
|
18
|
+
preference :origin_zip, :string, :default => "16802"
|
19
|
+
|
20
|
+
preference :units, :string, :default => "imperial"
|
21
|
+
preference :unit_multiplier, :integer, :default => 16 # 16 oz./lb - assumes variant weights are in lbs
|
22
|
+
|
23
|
+
validates_presence_of :name
|
24
|
+
validates_uniqueness_of :name
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Spree
|
2
|
+
module ActiveShipping
|
3
|
+
# Singleton class to access the shipping configuration object (ActiveShippingConfiguration.first by default) and it's preferences.
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
# Spree::ActiveShipping::Config[:foo] # Returns the foo preference
|
7
|
+
# Spree::ActiveShipping::Config[] # Returns a Hash with all the tax preferences
|
8
|
+
# Spree::ActiveShipping::Config.instance # Returns the configuration object (ActiveShippingConfiguration.first)
|
9
|
+
# Spree::ActiveShipping::Config.set(preferences_hash) # Set the active shipping preferences as especified in +preference_hash+
|
10
|
+
class Config
|
11
|
+
include Singleton
|
12
|
+
include PreferenceAccess
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def instance
|
16
|
+
return nil unless ActiveRecord::Base.connection.tables.include?('configurations')
|
17
|
+
ActiveShippingConfiguration.find_or_create_by_name("Default active_shipping configuration")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
module Spree
|
2
|
+
module ActiveShipping
|
3
|
+
module UpsOverride
|
4
|
+
def self.included(base)
|
5
|
+
|
6
|
+
base.class_eval do
|
7
|
+
|
8
|
+
def build_rate_request(origin, destination, packages, options={})
|
9
|
+
packages = Array(packages)
|
10
|
+
xml_request = XmlNode.new('RatingServiceSelectionRequest') do |root_node|
|
11
|
+
root_node << XmlNode.new('Request') do |request|
|
12
|
+
request << XmlNode.new('RequestAction', 'Rate')
|
13
|
+
request << XmlNode.new('RequestOption', 'Shop')
|
14
|
+
# not implemented: 'Rate' RequestOption to specify a single service query
|
15
|
+
# request << XmlNode.new('RequestOption', ((options[:service].nil? or options[:service] == :all) ? 'Shop' : 'Rate'))
|
16
|
+
end
|
17
|
+
|
18
|
+
pickup_type = options[:pickup_type] || :daily_pickup
|
19
|
+
|
20
|
+
root_node << XmlNode.new('PickupType') do |pickup_type_node|
|
21
|
+
pickup_type_node << XmlNode.new('Code', ActiveMerchant::Shipping::UPS::PICKUP_CODES[pickup_type])
|
22
|
+
# not implemented: PickupType/PickupDetails element
|
23
|
+
end
|
24
|
+
cc = options[:customer_classification] || ActiveMerchant::Shipping::UPS::DEFAULT_CUSTOMER_CLASSIFICATIONS[pickup_type]
|
25
|
+
root_node << XmlNode.new('CustomerClassification') do |cc_node|
|
26
|
+
cc_node << XmlNode.new('Code', ActiveMerchant::Shipping::UPS::CUSTOMER_CLASSIFICATIONS[cc])
|
27
|
+
end
|
28
|
+
|
29
|
+
root_node << XmlNode.new('Shipment') do |shipment|
|
30
|
+
# not implemented: Shipment/Description element
|
31
|
+
shipment << build_location_node('Shipper', (options[:shipper] || origin), options)
|
32
|
+
shipment << build_location_node('ShipTo', destination, options)
|
33
|
+
if options[:shipper] and options[:shipper] != origin
|
34
|
+
shipment << build_location_node('ShipFrom', origin, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
# not implemented: * Shipment/ShipmentWeight element
|
38
|
+
# * Shipment/ReferenceNumber element
|
39
|
+
# * Shipment/Service element
|
40
|
+
# * Shipment/PickupDate element
|
41
|
+
# * Shipment/ScheduledDeliveryDate element
|
42
|
+
# * Shipment/ScheduledDeliveryTime element
|
43
|
+
# * Shipment/AlternateDeliveryTime element
|
44
|
+
# * Shipment/DocumentsOnly element
|
45
|
+
|
46
|
+
packages.each do |package|
|
47
|
+
|
48
|
+
|
49
|
+
imperial = ['US','LR','MM'].include?(origin.country_code(:alpha2))
|
50
|
+
|
51
|
+
shipment << XmlNode.new("Package") do |package_node|
|
52
|
+
|
53
|
+
# not implemented: * Shipment/Package/PackagingType element
|
54
|
+
# * Shipment/Package/Description element
|
55
|
+
|
56
|
+
package_node << XmlNode.new("PackagingType") do |packaging_type|
|
57
|
+
packaging_type << XmlNode.new("Code", '02')
|
58
|
+
end
|
59
|
+
|
60
|
+
package_node << XmlNode.new("Dimensions") do |dimensions|
|
61
|
+
dimensions << XmlNode.new("UnitOfMeasurement") do |units|
|
62
|
+
units << XmlNode.new("Code", imperial ? 'IN' : 'CM')
|
63
|
+
end
|
64
|
+
[:length,:width,:height].each do |axis|
|
65
|
+
value = ((imperial ? package.inches(axis) : package.cm(axis)).to_f*1000).round/1000.0 # 3 decimals
|
66
|
+
dimensions << XmlNode.new(axis.to_s.capitalize, [value,0.1].max)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
package_node << XmlNode.new("PackageWeight") do |package_weight|
|
71
|
+
package_weight << XmlNode.new("UnitOfMeasurement") do |units|
|
72
|
+
units << XmlNode.new("Code", imperial ? 'LBS' : 'KGS')
|
73
|
+
end
|
74
|
+
|
75
|
+
value = ((imperial ? package.lbs : package.kgs).to_f*1000).round/1000.0 # 3 decimals
|
76
|
+
package_weight << XmlNode.new("Weight", [value,0.1].max)
|
77
|
+
end
|
78
|
+
|
79
|
+
# not implemented: * Shipment/Package/LargePackageIndicator element
|
80
|
+
# * Shipment/Package/ReferenceNumber element
|
81
|
+
# * Shipment/Package/PackageServiceOptions element
|
82
|
+
# * Shipment/Package/AdditionalHandling element
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
# not implemented: * Shipment/ShipmentServiceOptions element
|
88
|
+
# * Shipment/RateInformation element
|
89
|
+
|
90
|
+
#SPREE OVERRIDE Negotiated Rates
|
91
|
+
if (origin_account = @options[:origin_account] || options[:origin_account])
|
92
|
+
shipment << XmlNode.new("RateInformation") do |rate_information|
|
93
|
+
rate_information << XmlNode.new("NegotiatedRatesIndicator", '')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
xml_request.to_s
|
100
|
+
end
|
101
|
+
|
102
|
+
def build_time_in_transit_request(origin, destination, packages, options={})
|
103
|
+
packages = Array(packages)
|
104
|
+
xml_request = XmlNode.new('TimeInTransitRequest') do |root_node|
|
105
|
+
root_node << XmlNode.new('Request') do |request|
|
106
|
+
request << XmlNode.new('TransactionReference') do |transaction_reference|
|
107
|
+
transaction_reference << XmlNode.new('CustomerContext', 'Time in Transit')
|
108
|
+
transaction_reference << XmlNode.new('XpciVersion', '1.0002')
|
109
|
+
end
|
110
|
+
request << XmlNode.new('RequestAction', 'TimeInTransit')
|
111
|
+
end
|
112
|
+
root_node << XmlNode.new('TransitFrom') do |transit_from|
|
113
|
+
transit_from << XmlNode.new('AddressArtifactFormat') do |address_artifact_format|
|
114
|
+
address_artifact_format << XmlNode.new('PoliticalDivision2',origin.city)
|
115
|
+
address_artifact_format << XmlNode.new('PoliticalDivision1',origin.state)
|
116
|
+
address_artifact_format << XmlNode.new('CountryCode',origin.country_code(:alpha2))
|
117
|
+
address_artifact_format << XmlNode.new('PostcodePrimaryLow',origin.postal_code)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
root_node << XmlNode.new('TransitTo') do |transit_to|
|
122
|
+
transit_to << XmlNode.new('AddressArtifactFormat') do |address_artifact_format|
|
123
|
+
address_artifact_format << XmlNode.new('PoliticalDivision2',destination.city)
|
124
|
+
address_artifact_format << XmlNode.new('PoliticalDivision1',destination.state)
|
125
|
+
address_artifact_format << XmlNode.new('CountryCode',destination.country_code(:alpha2))
|
126
|
+
address_artifact_format << XmlNode.new('PostcodePrimaryLow',destination.postal_code)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
root_node << XmlNode.new("ShipmentWeight") do |shipment_weight|
|
131
|
+
shipment_weight << XmlNode.new("UnitOfMeasurement") do |units|
|
132
|
+
units << XmlNode.new("Code", 'LBS')
|
133
|
+
end
|
134
|
+
|
135
|
+
value = ((packages[0].lbs).to_f*1000).round/1000.0 # 3 decimals
|
136
|
+
shipment_weight << XmlNode.new("Weight", [value,0.1].max)
|
137
|
+
end
|
138
|
+
|
139
|
+
root_node << XmlNode.new("InvoiceLineTotal") do |invoice_line_total|
|
140
|
+
invoice_line_total << XmlNode.new("CurrencyCode","USD")
|
141
|
+
invoice_line_total << XmlNode.new("MonetaryValue","50")
|
142
|
+
end
|
143
|
+
|
144
|
+
root_node << XmlNode.new("PickupDate",Date.today.strftime("%Y%m%d"))
|
145
|
+
|
146
|
+
|
147
|
+
end
|
148
|
+
xml_request.to_s
|
149
|
+
end
|
150
|
+
|
151
|
+
def build_location_node(name,location,options={})
|
152
|
+
# not implemented: * Shipment/Shipper/Name element
|
153
|
+
# * Shipment/(ShipTo|ShipFrom)/CompanyName element
|
154
|
+
# * Shipment/(Shipper|ShipTo|ShipFrom)/AttentionName element
|
155
|
+
# * Shipment/(Shipper|ShipTo|ShipFrom)/TaxIdentificationNumber element
|
156
|
+
location_node = XmlNode.new(name) do |location_node|
|
157
|
+
location_node << XmlNode.new('PhoneNumber', location.phone.gsub(/[^\d]/,'')) unless location.phone.blank?
|
158
|
+
location_node << XmlNode.new('FaxNumber', location.fax.gsub(/[^\d]/,'')) unless location.fax.blank?
|
159
|
+
|
160
|
+
if name == 'Shipper' and (origin_account = @options[:origin_account] || options[:origin_account])
|
161
|
+
location_node << XmlNode.new('ShipperNumber', origin_account)
|
162
|
+
elsif name == 'ShipTo' and (destination_account = @options[:destination_account] || options[:destination_account])
|
163
|
+
location_node << XmlNode.new('ShipperAssignedIdentificationNumber', destination_account)
|
164
|
+
end
|
165
|
+
|
166
|
+
location_node << XmlNode.new('Address') do |address|
|
167
|
+
address << XmlNode.new("AddressLine1", location.address1) unless location.address1.blank?
|
168
|
+
address << XmlNode.new("AddressLine2", location.address2) unless location.address2.blank?
|
169
|
+
address << XmlNode.new("AddressLine3", location.address3) unless location.address3.blank?
|
170
|
+
address << XmlNode.new("City", location.city) unless location.city.blank?
|
171
|
+
address << XmlNode.new("StateProvinceCode", location.state) unless location.state.blank? #SPREE OVERRIDE
|
172
|
+
# StateProvinceCode required for negotiated rates but not otherwise, for some reason
|
173
|
+
address << XmlNode.new("PostalCode", location.postal_code) unless location.postal_code.blank?
|
174
|
+
address << XmlNode.new("CountryCode", location.country_code(:alpha2)) unless location.country_code(:alpha2).blank?
|
175
|
+
address << XmlNode.new("ResidentialAddressIndicator", true) unless location.commercial? # the default should be that UPS returns residential rates for destinations that it doesn't know about
|
176
|
+
# not implemented: Shipment/(Shipper|ShipTo|ShipFrom)/Address/ResidentialAddressIndicator element
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def find_time_in_transit(origin, destination, packages, options={})
|
182
|
+
origin, destination = upsified_location(origin), upsified_location(destination)
|
183
|
+
options = @options.merge(options)
|
184
|
+
packages = Array(packages)
|
185
|
+
access_request = build_access_request
|
186
|
+
rate_request = build_time_in_transit_request(origin, destination, packages, options)
|
187
|
+
response = ssl_post("https://www.ups.com/ups.app/xml/TimeInTransit", "<?xml version=\"1.0\"?>"+access_request+"<?xml version=\"1.0\"?>"+rate_request)
|
188
|
+
parse_time_in_transit_response(origin, destination, packages,response, options)
|
189
|
+
end
|
190
|
+
|
191
|
+
def find_rates(origin, destination, packages, options={})
|
192
|
+
origin, destination = upsified_location(origin), upsified_location(destination)
|
193
|
+
options = @options.merge(options)
|
194
|
+
packages = Array(packages)
|
195
|
+
access_request = build_access_request
|
196
|
+
rate_request = build_rate_request(origin, destination, packages, options)
|
197
|
+
response = commit(:rates, save_request(access_request + rate_request), (options[:test] || false))
|
198
|
+
parse_rate_response(origin, destination, packages, response, options)
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
def parse_time_in_transit_response(origin, destination, packages, response, options={})
|
203
|
+
|
204
|
+
time_code_mapping = {
|
205
|
+
"1DA" => "01",
|
206
|
+
"2DA" => "02",
|
207
|
+
"GND" => "03",
|
208
|
+
"01" => "07",
|
209
|
+
"05" => "08",
|
210
|
+
"03" => "11",
|
211
|
+
"3DS" => "12",
|
212
|
+
"1DP" => "13",
|
213
|
+
"1DM" => "14",
|
214
|
+
"21" => "54",
|
215
|
+
"2DM" => "59"
|
216
|
+
}
|
217
|
+
|
218
|
+
rates = []
|
219
|
+
xml = REXML::Document.new(response)
|
220
|
+
success = response_success?(xml)
|
221
|
+
message = response_message(xml)
|
222
|
+
if success
|
223
|
+
rate_estimates = {}
|
224
|
+
xml.elements.each('/*/TransitResponse/ServiceSummary') do |service_summary|
|
225
|
+
service_code = service_summary.get_text('Service/Code').to_s
|
226
|
+
service_code_2 = time_code_mapping[service_code]
|
227
|
+
service_desc = service_summary.get_text('Service/Description').to_s
|
228
|
+
guaranteed_code = service_summary.get_text('Guaranteed/Code').to_s
|
229
|
+
business_transit_days = service_summary.get_text('EstimatedArrival/BusinessTransitDays').to_s
|
230
|
+
date = service_summary.get_text('EstimatedArrival/Date').to_s
|
231
|
+
rate_estimates[service_name_for(origin, service_code_2)] = {:service_code => service_code, :service_code_2 => service_code_2, :service_desc => service_desc,
|
232
|
+
:guaranteed_code => guaranteed_code, :business_transit_days => business_transit_days,
|
233
|
+
:date => date}
|
234
|
+
end
|
235
|
+
end
|
236
|
+
return rate_estimates
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
def parse_rate_response(origin, destination, packages, response, options={})
|
242
|
+
rates = []
|
243
|
+
xml = REXML::Document.new(response)
|
244
|
+
success = response_success?(xml)
|
245
|
+
message = response_message(xml)
|
246
|
+
transits = options[:transit]
|
247
|
+
if success
|
248
|
+
rate_estimates = []
|
249
|
+
|
250
|
+
xml.elements.each('/*/RatedShipment') do |rated_shipment|
|
251
|
+
service_code = rated_shipment.get_text('Service/Code').to_s
|
252
|
+
service = rated_shipment.get_text('Service/Code').to_s
|
253
|
+
negotiated_rate = rated_shipment.get_text('NegotiatedRates/NetSummaryCharges/GrandTotal/MonetaryValue').to_s
|
254
|
+
total_price = negotiated_rate.blank? ? rated_shipment.get_text('TotalCharges/MonetaryValue').to_s.to_f : negotiated_rate.to_f
|
255
|
+
currency = negotiated_rate.blank? ? rated_shipment.get_text('TotalCharges/CurrencyCode').to_s : rated_shipment.get_text('NegotiatedRates/NetSummaryCharges/GrandTotal/CurrencyCode').to_s
|
256
|
+
|
257
|
+
rate_estimates << ActiveMerchant::Shipping::RateEstimate.new(origin, destination, ActiveMerchant::Shipping::UPS.name,
|
258
|
+
service_name_for(origin, service_code),
|
259
|
+
:total_price => total_price,
|
260
|
+
:currency => currency,
|
261
|
+
:service_code => service_code,
|
262
|
+
:packages => packages
|
263
|
+
)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
ActiveMerchant::Shipping::RateResponse.new(success, message, Hash.from_xml(response).values.first, :rates => rate_estimates, :xml => response, :request => last_request)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|