active_shipping 0.12.1 → 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2ce16b6cd295a23479c3166d83d56aa7117b7d4f
4
- data.tar.gz: d8981371fe00396db4680c982fc950a52901fb7c
3
+ metadata.gz: 3b5f032d7b051953da7d9746cc9ef3fce5e272aa
4
+ data.tar.gz: 74890284fd2a7f865cbbc84cbf6edd9f1a1856a8
5
5
  SHA512:
6
- metadata.gz: 3801a0cc69561f9c29149a724bfbd061564c8ae8b3e610902418ab075d957cc1b5bb780433c18c48d6e1da1a4d4fc335ed49506d5961169a25e6843767fbd006
7
- data.tar.gz: d9e00d760ae2dcc3ea18eca3cc744b7aca1427fdb41d24aecf06290df2a324530c0322785146615a404bcd7b15a59f732e1592103a683190b3dcde8afa39efff
6
+ metadata.gz: 3e86722a8a87c0d4f774fe73fed0d2f395bcd5783465031128193283b9012e4eb3746c1df10fb40b6e75e630d0c9006785ca9374003a016fa5abf564249a484a
7
+ data.tar.gz: a50553bdd237ad4da447bbfa7b6e5202eb371b5002c9b8d8eb0231ee29dbbc747fbce844733c4fd142bbce22e0bd94eb9907811ea9d77d69c4dfb3bbcd092683
checksums.yaml.gz.sig ADDED
Binary file
data.tar.gz.sig ADDED
@@ -0,0 +1 @@
1
+ j�bJ��ږT��a���$3�둓@�q�_�1,t+�LI�Կ�'R���Q�� 0jY\׆a�O���͡i�V�'c�ލ'A��휿�p���qg�j�h�{T�������dKS�~�FI�F� �X���1�"��0�S��@H�*���C�?�) eB�/y�{���oS�����t�A-!��e�\?�|9�'$��e˒�vho����4xY����^p��'HXXbiw�4�z<��ɯ)5�y�\[�1:n[�
@@ -531,7 +531,7 @@ module ActiveMerchant
531
531
  break if node
532
532
  end
533
533
 
534
- args = if node
534
+ args = if node && node.elements['CountryCode']
535
535
  {
536
536
  :country => node.get_text('CountryCode').to_s,
537
537
  :province => node.get_text('StateOrProvinceCode').to_s,
@@ -1,3 +1,3 @@
1
1
  module ActiveShipping
2
- VERSION = "0.12.1"
2
+ VERSION = "0.12.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_shipping
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.12.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - James MacAulay
@@ -10,147 +10,169 @@ authors:
10
10
  - Jimmy Baker
11
11
  autorequire:
12
12
  bindir: bin
13
- cert_chain: []
14
- date: 2014-05-20 00:00:00.000000000 Z
13
+ cert_chain:
14
+ - |
15
+ -----BEGIN CERTIFICATE-----
16
+ MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MQ8wDQYDVQQDDAZhZG1p
17
+ bnMxFzAVBgoJkiaJk/IsZAEZFgdzaG9waWZ5MRMwEQYKCZImiZPyLGQBGRYDY29t
18
+ MB4XDTE0MDUxNTIwMzM0OFoXDTE1MDUxNTIwMzM0OFowPzEPMA0GA1UEAwwGYWRt
19
+ aW5zMRcwFQYKCZImiZPyLGQBGRYHc2hvcGlmeTETMBEGCgmSJomT8ixkARkWA2Nv
20
+ bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL0/81O3e1vh5smcwp2G
21
+ MpLQ6q0kejQLa65bPYPxdzWA1SYOKyGfw+yR9LdFzsuKpwWzKq6zX35lj1IckWS4
22
+ bNBEQzxmufUxU0XPM02haFB8fOfDJzdXsWte9Ge4IFwahwn68gpMqN+BvxL+KMYz
23
+ Iut9YmN44d4LZdsENEIO5vmybuG2vYDz7R56qB0PA+Q2P2CdhymsBad2DQs69FBo
24
+ uico9V6VMYYctL9lCYdzu9IXrOYNTt88suKIVzzAlHOKeN0Ng5qdztFoTR8sfxDr
25
+ Ydg3KHl5n47wlpgd8R0f/4b5gGxW+v9pyJCgQnLlRu7DedVSvv7+GMtj3g9r3nhJ
26
+ KqECAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFI/o
27
+ maf34HXbUOQsdoLHacEKQgunMB0GA1UdEQQWMBSBEmFkbWluc0BzaG9waWZ5LmNv
28
+ bTAdBgNVHRIEFjAUgRJhZG1pbnNAc2hvcGlmeS5jb20wDQYJKoZIhvcNAQEFBQAD
29
+ ggEBADkK9aj5T0HPExsov4EoMWFnO+G7RQ28C30VAfKxnL2UxG6i4XMHVs6Xi94h
30
+ qXFw1ec9Y2eDUqaolT3bviOk9BB197+A8Vz/k7MC6ci2NE+yDDB7HAC8zU6LAx8Y
31
+ Iqvw7B/PSZ/pz4bUVFlTATif4mi1vO3lidRkdHRtM7UePSn2rUpOi0gtXBP3bLu5
32
+ YjHJN7wx5cugMEyroKITG5gL0Nxtu21qtOlHX4Hc4KdE2JqzCPOsS4zsZGhgwhPs
33
+ fl3hbtVFTqbOlwL9vy1fudXcolIE/ZTcxQ+er07ZFZdKCXayR9PPs64heamfn0fp
34
+ TConQSX2BnZdhIEYW+cKzEC/bLc=
35
+ -----END CERTIFICATE-----
36
+ date: 2014-05-27 00:00:00.000000000 Z
15
37
  dependencies:
16
38
  - !ruby/object:Gem::Dependency
17
39
  name: activesupport
18
40
  requirement: !ruby/object:Gem::Requirement
19
41
  requirements:
20
- - - '>='
42
+ - - ">="
21
43
  - !ruby/object:Gem::Version
22
44
  version: 2.3.5
23
45
  type: :runtime
24
46
  prerelease: false
25
47
  version_requirements: !ruby/object:Gem::Requirement
26
48
  requirements:
27
- - - '>='
49
+ - - ">="
28
50
  - !ruby/object:Gem::Version
29
51
  version: 2.3.5
30
52
  - !ruby/object:Gem::Dependency
31
53
  name: i18n
32
54
  requirement: !ruby/object:Gem::Requirement
33
55
  requirements:
34
- - - '>='
56
+ - - ">="
35
57
  - !ruby/object:Gem::Version
36
58
  version: '0'
37
59
  type: :runtime
38
60
  prerelease: false
39
61
  version_requirements: !ruby/object:Gem::Requirement
40
62
  requirements:
41
- - - '>='
63
+ - - ">="
42
64
  - !ruby/object:Gem::Version
43
65
  version: '0'
44
66
  - !ruby/object:Gem::Dependency
45
67
  name: active_utils
46
68
  requirement: !ruby/object:Gem::Requirement
47
69
  requirements:
48
- - - ~>
70
+ - - "~>"
49
71
  - !ruby/object:Gem::Version
50
72
  version: 2.2.0
51
73
  type: :runtime
52
74
  prerelease: false
53
75
  version_requirements: !ruby/object:Gem::Requirement
54
76
  requirements:
55
- - - ~>
77
+ - - "~>"
56
78
  - !ruby/object:Gem::Version
57
79
  version: 2.2.0
58
80
  - !ruby/object:Gem::Dependency
59
81
  name: builder
60
82
  requirement: !ruby/object:Gem::Requirement
61
83
  requirements:
62
- - - '>='
84
+ - - ">="
63
85
  - !ruby/object:Gem::Version
64
86
  version: '0'
65
87
  type: :runtime
66
88
  prerelease: false
67
89
  version_requirements: !ruby/object:Gem::Requirement
68
90
  requirements:
69
- - - '>='
91
+ - - ">="
70
92
  - !ruby/object:Gem::Version
71
93
  version: '0'
72
94
  - !ruby/object:Gem::Dependency
73
95
  name: json
74
96
  requirement: !ruby/object:Gem::Requirement
75
97
  requirements:
76
- - - '>='
98
+ - - ">="
77
99
  - !ruby/object:Gem::Version
78
100
  version: 1.5.1
79
101
  type: :runtime
80
102
  prerelease: false
81
103
  version_requirements: !ruby/object:Gem::Requirement
82
104
  requirements:
83
- - - '>='
105
+ - - ">="
84
106
  - !ruby/object:Gem::Version
85
107
  version: 1.5.1
86
108
  - !ruby/object:Gem::Dependency
87
109
  name: minitest
88
110
  requirement: !ruby/object:Gem::Requirement
89
111
  requirements:
90
- - - ~>
112
+ - - "~>"
91
113
  - !ruby/object:Gem::Version
92
114
  version: 4.7.5
93
115
  type: :development
94
116
  prerelease: false
95
117
  version_requirements: !ruby/object:Gem::Requirement
96
118
  requirements:
97
- - - ~>
119
+ - - "~>"
98
120
  - !ruby/object:Gem::Version
99
121
  version: 4.7.5
100
122
  - !ruby/object:Gem::Dependency
101
123
  name: rake
102
124
  requirement: !ruby/object:Gem::Requirement
103
125
  requirements:
104
- - - '>='
126
+ - - ">="
105
127
  - !ruby/object:Gem::Version
106
128
  version: '0'
107
129
  type: :development
108
130
  prerelease: false
109
131
  version_requirements: !ruby/object:Gem::Requirement
110
132
  requirements:
111
- - - '>='
133
+ - - ">="
112
134
  - !ruby/object:Gem::Version
113
135
  version: '0'
114
136
  - !ruby/object:Gem::Dependency
115
137
  name: mocha
116
138
  requirement: !ruby/object:Gem::Requirement
117
139
  requirements:
118
- - - ~>
140
+ - - "~>"
119
141
  - !ruby/object:Gem::Version
120
142
  version: 0.14.0
121
143
  type: :development
122
144
  prerelease: false
123
145
  version_requirements: !ruby/object:Gem::Requirement
124
146
  requirements:
125
- - - ~>
147
+ - - "~>"
126
148
  - !ruby/object:Gem::Version
127
149
  version: 0.14.0
128
150
  - !ruby/object:Gem::Dependency
129
151
  name: timecop
130
152
  requirement: !ruby/object:Gem::Requirement
131
153
  requirements:
132
- - - '>='
154
+ - - ">="
133
155
  - !ruby/object:Gem::Version
134
156
  version: '0'
135
157
  type: :development
136
158
  prerelease: false
137
159
  version_requirements: !ruby/object:Gem::Requirement
138
160
  requirements:
139
- - - '>='
161
+ - - ">="
140
162
  - !ruby/object:Gem::Version
141
163
  version: '0'
142
164
  - !ruby/object:Gem::Dependency
143
165
  name: nokogiri
144
166
  requirement: !ruby/object:Gem::Requirement
145
167
  requirements:
146
- - - '>='
168
+ - - ">="
147
169
  - !ruby/object:Gem::Version
148
170
  version: '0'
149
171
  type: :development
150
172
  prerelease: false
151
173
  version_requirements: !ruby/object:Gem::Requirement
152
174
  requirements:
153
- - - '>='
175
+ - - ">="
154
176
  - !ruby/object:Gem::Version
155
177
  version: '0'
156
178
  description: Get rates and tracking info from various shipping carriers.
@@ -177,9 +199,7 @@ files:
177
199
  - lib/active_shipping/shipping/carriers/shipwire.rb
178
200
  - lib/active_shipping/shipping/carriers/stamps.rb
179
201
  - lib/active_shipping/shipping/carriers/ups.rb
180
- - lib/active_shipping/shipping/carriers/ups.rb.orig
181
202
  - lib/active_shipping/shipping/carriers/usps.rb
182
- - lib/active_shipping/shipping/carriers/usps.rb.orig
183
203
  - lib/active_shipping/shipping/errors.rb
184
204
  - lib/active_shipping/shipping/location.rb
185
205
  - lib/active_shipping/shipping/package.rb
@@ -220,17 +240,17 @@ require_paths:
220
240
  - lib
221
241
  required_ruby_version: !ruby/object:Gem::Requirement
222
242
  requirements:
223
- - - '>='
243
+ - - ">="
224
244
  - !ruby/object:Gem::Version
225
245
  version: '0'
226
246
  required_rubygems_version: !ruby/object:Gem::Requirement
227
247
  requirements:
228
- - - '>='
248
+ - - ">="
229
249
  - !ruby/object:Gem::Version
230
250
  version: 1.3.6
231
251
  requirements: []
232
252
  rubyforge_project: active_shipping
233
- rubygems_version: 2.2.2
253
+ rubygems_version: 2.2.0
234
254
  signing_key:
235
255
  specification_version: 4
236
256
  summary: Shipping API extension for Active Merchant
metadata.gz.sig ADDED
@@ -0,0 +1,3 @@
1
+ �"ʠ�� �N�P �$�{�7���~-U�򐃧φ�� ‘M��#
2
+ ��מZ�"���k{�oe�@��RQ� Е�'�-mU�R!����K�^dM��&F]���u��?n�LiK��A �7�R�U�\�ɴ%c+ ;s���|/Q#~@߯�Y�#����[����`���jwC����˙���*ID���M�Sy�ɝ�
3
+ V�O�r����AOb�sВ
@@ -1,456 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- module ActiveMerchant
4
- module Shipping
5
- class UPS < Carrier
6
- self.retry_safe = true
7
-
8
- cattr_accessor :default_options
9
- cattr_reader :name
10
- @@name = "UPS"
11
-
12
- TEST_URL = 'https://wwwcie.ups.com'
13
- LIVE_URL = 'https://onlinetools.ups.com'
14
-
15
- RESOURCES = {
16
- :rates => 'ups.app/xml/Rate',
17
- :track => 'ups.app/xml/Track'
18
- }
19
-
20
- PICKUP_CODES = HashWithIndifferentAccess.new({
21
- :daily_pickup => "01",
22
- :customer_counter => "03",
23
- :one_time_pickup => "06",
24
- :on_call_air => "07",
25
- :suggested_retail_rates => "11",
26
- :letter_center => "19",
27
- :air_service_center => "20"
28
- })
29
-
30
- CUSTOMER_CLASSIFICATIONS = HashWithIndifferentAccess.new({
31
- :wholesale => "01",
32
- :occasional => "03",
33
- :retail => "04"
34
- })
35
-
36
- # these are the defaults described in the UPS API docs,
37
- # but they don't seem to apply them under all circumstances,
38
- # so we need to take matters into our own hands
39
- DEFAULT_CUSTOMER_CLASSIFICATIONS = Hash.new do |hash,key|
40
- hash[key] = case key.to_sym
41
- when :daily_pickup then :wholesale
42
- when :customer_counter then :retail
43
- else
44
- :occasional
45
- end
46
- end
47
-
48
- DEFAULT_SERVICES = {
49
- "01" => "UPS Next Day Air",
50
- "02" => "UPS Second Day Air",
51
- "03" => "UPS Ground",
52
- "07" => "UPS Worldwide Express",
53
- "08" => "UPS Worldwide Expedited",
54
- "11" => "UPS Standard",
55
- "12" => "UPS Three-Day Select",
56
- "13" => "UPS Next Day Air Saver",
57
- "14" => "UPS Next Day Air Early A.M.",
58
- "54" => "UPS Worldwide Express Plus",
59
- "59" => "UPS Second Day Air A.M.",
60
- "65" => "UPS Saver",
61
- "82" => "UPS Today Standard",
62
- "83" => "UPS Today Dedicated Courier",
63
- "84" => "UPS Today Intercity",
64
- "85" => "UPS Today Express",
65
- "86" => "UPS Today Express Saver"
66
- }
67
-
68
- CANADA_ORIGIN_SERVICES = {
69
- "01" => "UPS Express",
70
- "02" => "UPS Expedited",
71
- "14" => "UPS Express Early A.M."
72
- }
73
-
74
- MEXICO_ORIGIN_SERVICES = {
75
- "07" => "UPS Express",
76
- "08" => "UPS Expedited",
77
- "54" => "UPS Express Plus"
78
- }
79
-
80
- EU_ORIGIN_SERVICES = {
81
- "07" => "UPS Express",
82
- "08" => "UPS Expedited"
83
- }
84
-
85
- OTHER_NON_US_ORIGIN_SERVICES = {
86
- "07" => "UPS Express"
87
- }
88
-
89
- TRACKING_STATUS_CODES = HashWithIndifferentAccess.new({
90
- 'I' => :in_transit,
91
- 'D' => :delivered,
92
- 'X' => :exception,
93
- 'P' => :pickup,
94
- 'M' => :manifest_pickup
95
- })
96
-
97
- # From http://en.wikipedia.org/w/index.php?title=European_Union&oldid=174718707 (Current as of November 30, 2007)
98
- EU_COUNTRY_CODES = ["GB", "AT", "BE", "BG", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL", "PL", "PT", "RO", "SK", "SI", "ES", "SE"]
99
-
100
- US_TERRITORIES_TREATED_AS_COUNTRIES = ["AS", "FM", "GU", "MH", "MP", "PW", "PR", "VI"]
101
-
102
- def requirements
103
- [:key, :login, :password]
104
- end
105
-
106
- def find_rates(origin, destination, packages, options={})
107
- origin, destination = upsified_location(origin), upsified_location(destination)
108
- options = @options.merge(options)
109
- packages = Array(packages)
110
- access_request = build_access_request
111
- rate_request = build_rate_request(origin, destination, packages, options)
112
- response = commit(:rates, save_request(access_request + rate_request), (options[:test] || false))
113
- parse_rate_response(origin, destination, packages, response, options)
114
- end
115
-
116
- def find_tracking_info(tracking_number, options={})
117
- options = @options.update(options)
118
- access_request = build_access_request
119
- tracking_request = build_tracking_request(tracking_number, options)
120
- response = commit(:track, save_request(access_request + tracking_request), (options[:test] || false))
121
- parse_tracking_response(response, options)
122
- end
123
-
124
- protected
125
-
126
- def upsified_location(location)
127
- if location.country_code == 'US' && US_TERRITORIES_TREATED_AS_COUNTRIES.include?(location.state)
128
- atts = {:country => location.state}
129
- [:zip, :city, :address1, :address2, :address3, :phone, :fax, :address_type].each do |att|
130
- atts[att] = location.send(att)
131
- end
132
- Location.new(atts)
133
- else
134
- location
135
- end
136
- end
137
-
138
- def build_access_request
139
- xml_request = XmlNode.new('AccessRequest') do |access_request|
140
- access_request << XmlNode.new('AccessLicenseNumber', @options[:key])
141
- access_request << XmlNode.new('UserId', @options[:login])
142
- access_request << XmlNode.new('Password', @options[:password])
143
- end
144
- xml_request.to_s
145
- end
146
-
147
- def build_rate_request(origin, destination, packages, options={})
148
- packages = Array(packages)
149
- xml_request = XmlNode.new('RatingServiceSelectionRequest') do |root_node|
150
- root_node << XmlNode.new('Request') do |request|
151
- request << XmlNode.new('RequestAction', 'Rate')
152
- request << XmlNode.new('RequestOption', 'Shop')
153
- # not implemented: 'Rate' RequestOption to specify a single service query
154
- # request << XmlNode.new('RequestOption', ((options[:service].nil? or options[:service] == :all) ? 'Shop' : 'Rate'))
155
- end
156
-
157
- pickup_type = options[:pickup_type] || :daily_pickup
158
-
159
- root_node << XmlNode.new('PickupType') do |pickup_type_node|
160
- pickup_type_node << XmlNode.new('Code', PICKUP_CODES[pickup_type])
161
- # not implemented: PickupType/PickupDetails element
162
- end
163
- cc = options[:customer_classification] || DEFAULT_CUSTOMER_CLASSIFICATIONS[pickup_type]
164
- root_node << XmlNode.new('CustomerClassification') do |cc_node|
165
- cc_node << XmlNode.new('Code', CUSTOMER_CLASSIFICATIONS[cc])
166
- end
167
-
168
- root_node << XmlNode.new('Shipment') do |shipment|
169
- # not implemented: Shipment/Description element
170
- shipment << build_location_node('Shipper', (options[:shipper] || origin), options)
171
- shipment << build_location_node('ShipTo', destination, options)
172
- if options[:shipper] and options[:shipper] != origin
173
- shipment << build_location_node('ShipFrom', origin, options)
174
- end
175
-
176
- # not implemented: * Shipment/ShipmentWeight element
177
- # * Shipment/ReferenceNumber element
178
- # * Shipment/Service element
179
- # * Shipment/PickupDate element
180
- # * Shipment/ScheduledDeliveryDate element
181
- # * Shipment/ScheduledDeliveryTime element
182
- # * Shipment/AlternateDeliveryTime element
183
- # * Shipment/DocumentsOnly element
184
-
185
- packages.each do |package|
186
- imperial = ['US','LR','MM'].include?(origin.country_code(:alpha2))
187
-
188
- shipment << XmlNode.new("Package") do |package_node|
189
-
190
- # not implemented: * Shipment/Package/PackagingType element
191
- # * Shipment/Package/Description element
192
-
193
- package_node << XmlNode.new("PackagingType") do |packaging_type|
194
- packaging_type << XmlNode.new("Code", '02')
195
- end
196
-
197
- package_node << XmlNode.new("Dimensions") do |dimensions|
198
- dimensions << XmlNode.new("UnitOfMeasurement") do |units|
199
- units << XmlNode.new("Code", imperial ? 'IN' : 'CM')
200
- end
201
- [:length,:width,:height].each do |axis|
202
- value = ((imperial ? package.inches(axis) : package.cm(axis)).to_f*1000).round/1000.0 # 3 decimals
203
- dimensions << XmlNode.new(axis.to_s.capitalize, [value,0.1].max)
204
- end
205
- end
206
-
207
- package_node << XmlNode.new("PackageWeight") do |package_weight|
208
- package_weight << XmlNode.new("UnitOfMeasurement") do |units|
209
- units << XmlNode.new("Code", imperial ? 'LBS' : 'KGS')
210
- end
211
-
212
- value = ((imperial ? package.lbs : package.kgs).to_f*1000).round/1000.0 # 3 decimals
213
- package_weight << XmlNode.new("Weight", [value,0.1].max)
214
- end
215
-
216
- # not implemented: * Shipment/Package/LargePackageIndicator element
217
- # * Shipment/Package/ReferenceNumber element
218
- # * Shipment/Package/PackageServiceOptions element
219
- # * Shipment/Package/AdditionalHandling element
220
- end
221
-
222
- end
223
-
224
- # not implemented: * Shipment/ShipmentServiceOptions element
225
- if options[:origin_account]
226
- shipment << XmlNode.new("RateInformation") do |rate_info_node|
227
- rate_info_node << XmlNode.new("NegotiatedRatesIndicator")
228
- end
229
- end
230
-
231
- end
232
-
233
- end
234
- xml_request.to_s
235
- end
236
-
237
- def build_tracking_request(tracking_number, options={})
238
- xml_request = XmlNode.new('TrackRequest') do |root_node|
239
- root_node << XmlNode.new('Request') do |request|
240
- request << XmlNode.new('RequestAction', 'Track')
241
- request << XmlNode.new('RequestOption', '1')
242
- end
243
- root_node << XmlNode.new('TrackingNumber', tracking_number.to_s)
244
- end
245
- xml_request.to_s
246
- end
247
-
248
- def build_location_node(name,location,options={})
249
- # not implemented: * Shipment/Shipper/Name element
250
- # * Shipment/(ShipTo|ShipFrom)/CompanyName element
251
- # * Shipment/(Shipper|ShipTo|ShipFrom)/AttentionName element
252
- # * Shipment/(Shipper|ShipTo|ShipFrom)/TaxIdentificationNumber element
253
- location_node = XmlNode.new(name) do |location_node|
254
- location_node << XmlNode.new('PhoneNumber', location.phone.gsub(/[^\d]/,'')) unless location.phone.blank?
255
- location_node << XmlNode.new('FaxNumber', location.fax.gsub(/[^\d]/,'')) unless location.fax.blank?
256
-
257
- if name == 'Shipper' and (origin_account = @options[:origin_account] || options[:origin_account])
258
- location_node << XmlNode.new('ShipperNumber', origin_account)
259
- elsif name == 'ShipTo' and (destination_account = @options[:destination_account] || options[:destination_account])
260
- location_node << XmlNode.new('ShipperAssignedIdentificationNumber', destination_account)
261
- end
262
-
263
- location_node << XmlNode.new('Address') do |address|
264
- address << XmlNode.new("AddressLine1", location.address1) unless location.address1.blank?
265
- address << XmlNode.new("AddressLine2", location.address2) unless location.address2.blank?
266
- address << XmlNode.new("AddressLine3", location.address3) unless location.address3.blank?
267
- address << XmlNode.new("City", location.city) unless location.city.blank?
268
- address << XmlNode.new("StateProvinceCode", location.province) unless location.province.blank?
269
- # StateProvinceCode required for negotiated rates but not otherwise, for some reason
270
- address << XmlNode.new("PostalCode", location.postal_code) unless location.postal_code.blank?
271
- address << XmlNode.new("CountryCode", location.country_code(:alpha2)) unless location.country_code(:alpha2).blank?
272
- 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
273
- # not implemented: Shipment/(Shipper|ShipTo|ShipFrom)/Address/ResidentialAddressIndicator element
274
- end
275
- end
276
- end
277
-
278
- def parse_rate_response(origin, destination, packages, response, options={})
279
- rates = []
280
- File.open('/Users/timmy/code/active_shipping/foo.txt', 'w') {|f| f.write(response) }
281
- xml = REXML::Document.new(response)
282
- success = response_success?(xml)
283
- message = response_message(xml)
284
-
285
- if success
286
- rate_estimates = []
287
-
288
- xml.elements.each('/*/RatedShipment') do |rated_shipment|
289
- service_code = rated_shipment.get_text('Service/Code').to_s
290
- days_to_delivery = rated_shipment.get_text('GuaranteedDaysToDelivery').to_s.to_i
291
- delivery_date = days_to_delivery >= 1 ? days_to_delivery.days.from_now.strftime("%Y-%m-%d") : nil
292
- rate_estimates << RateEstimate.new(origin, destination, @@name,
293
- service_name_for(origin, service_code),
294
- :total_price => rated_shipment.get_text('TotalCharges/MonetaryValue').to_s.to_f,
295
- :currency => rated_shipment.get_text('TotalCharges/CurrencyCode').to_s,
296
- :service_code => service_code,
297
- :packages => packages,
298
- :delivery_range => [delivery_date],
299
- :negotiated_rate => rated_shipment.get_text('NegotiatedRates/NetSummaryCharges/GrandTotal/MonetaryValue').to_s.to_f)
300
- end
301
- end
302
- RateResponse.new(success, message, Hash.from_xml(response).values.first, :rates => rate_estimates, :xml => response, :request => last_request)
303
- end
304
-
305
- def parse_tracking_response(response, options={})
306
- xml = REXML::Document.new(response)
307
- success = response_success?(xml)
308
- message = response_message(xml)
309
-
310
- if success
311
- tracking_number, origin, destination, status_code, status_description = nil
312
- delivered, exception = false
313
- exception_event = nil
314
- shipment_events = []
315
- status = {}
316
- scheduled_delivery_date = nil
317
-
318
- first_shipment = xml.elements['/*/Shipment']
319
- first_package = first_shipment.elements['Package']
320
- tracking_number = first_shipment.get_text('ShipmentIdentificationNumber | Package/TrackingNumber').to_s
321
-
322
- # Build status hash
323
- status_node = first_package.elements['Activity/Status/StatusType']
324
- status_code = status_node.get_text('Code').to_s
325
- status_description = status_node.get_text('Description').to_s
326
- status = TRACKING_STATUS_CODES[status_code]
327
-
328
- if status_description =~ /out.*delivery/i
329
- status = :out_for_delivery
330
- end
331
-
332
- origin, destination = %w{Shipper ShipTo}.map do |location|
333
- location_from_address_node(first_shipment.elements["#{location}/Address"])
334
- end
335
-
336
- # Get scheduled delivery date
337
- unless status == :delivered
338
- scheduled_delivery_date = parse_ups_datetime({
339
- :date => first_shipment.get_text('ScheduledDeliveryDate'),
340
- :time => nil
341
- })
342
- end
343
-
344
- activities = first_package.get_elements('Activity')
345
- unless activities.empty?
346
- shipment_events = activities.map do |activity|
347
- description = activity.get_text('Status/StatusType/Description').to_s
348
- zoneless_time = if (time = activity.get_text('Time')) &&
349
- (date = activity.get_text('Date'))
350
- time, date = time.to_s, date.to_s
351
- hour, minute, second = time.scan(/\d{2}/)
352
- year, month, day = date[0..3], date[4..5], date[6..7]
353
- Time.utc(year, month, day, hour, minute, second)
354
- end
355
- location = location_from_address_node(activity.elements['ActivityLocation/Address'])
356
- ShipmentEvent.new(description, zoneless_time, location)
357
- end
358
-
359
- shipment_events = shipment_events.sort_by(&:time)
360
-
361
- # UPS will sometimes archive a shipment, stripping all shipment activity except for the delivery
362
- # event (see test/fixtures/xml/delivered_shipment_without_events_tracking_response.xml for an example).
363
- # This adds an origin event to the shipment activity in such cases.
364
- if origin && !(shipment_events.count == 1 && status == :delivered)
365
- first_event = shipment_events[0]
366
- same_country = origin.country_code(:alpha2) == first_event.location.country_code(:alpha2)
367
- same_or_blank_city = first_event.location.city.blank? or first_event.location.city == origin.city
368
- origin_event = ShipmentEvent.new(first_event.name, first_event.time, origin)
369
- if same_country and same_or_blank_city
370
- shipment_events[0] = origin_event
371
- else
372
- shipment_events.unshift(origin_event)
373
- end
374
- end
375
-
376
- # Has the shipment been delivered?
377
- if status == :delivered
378
- if !destination
379
- destination = shipment_events[-1].location
380
- end
381
- shipment_events[-1] = ShipmentEvent.new(shipment_events.last.name, shipment_events.last.time, destination)
382
- end
383
- end
384
-
385
- end
386
- TrackingResponse.new(success, message, Hash.from_xml(response).values.first,
387
- :carrier => @@name,
388
- :xml => response,
389
- :request => last_request,
390
- :status => status,
391
- :status_code => status_code,
392
- :status_description => status_description,
393
- :scheduled_delivery_date => scheduled_delivery_date,
394
- :shipment_events => shipment_events,
395
- :delivered => delivered,
396
- :exception => exception,
397
- :exception_event => exception_event,
398
- :origin => origin,
399
- :destination => destination,
400
- :tracking_number => tracking_number)
401
- end
402
-
403
- def location_from_address_node(address)
404
- return nil unless address
405
- Location.new(
406
- :country => node_text_or_nil(address.elements['CountryCode']),
407
- :postal_code => node_text_or_nil(address.elements['PostalCode']),
408
- :province => node_text_or_nil(address.elements['StateProvinceCode']),
409
- :city => node_text_or_nil(address.elements['City']),
410
- :address1 => node_text_or_nil(address.elements['AddressLine1']),
411
- :address2 => node_text_or_nil(address.elements['AddressLine2']),
412
- :address3 => node_text_or_nil(address.elements['AddressLine3'])
413
- )
414
- end
415
-
416
- def parse_ups_datetime(options = {})
417
- time, date = options[:time].to_s, options[:date].to_s
418
- if time.nil?
419
- hour, minute, second = 0
420
- else
421
- hour, minute, second = time.scan(/\d{2}/)
422
- end
423
- year, month, day = date[0..3], date[4..5], date[6..7]
424
-
425
- Time.utc(year, month, day, hour, minute, second)
426
- end
427
-
428
- def response_success?(xml)
429
- xml.get_text('/*/Response/ResponseStatusCode').to_s == '1'
430
- end
431
-
432
- def response_message(xml)
433
- xml.get_text('/*/Response/Error/ErrorDescription | /*/Response/ResponseStatusDescription').to_s
434
- end
435
-
436
- def commit(action, request, test = false)
437
- ssl_post("#{test ? TEST_URL : LIVE_URL}/#{RESOURCES[action]}", request)
438
- end
439
-
440
-
441
- def service_name_for(origin, code)
442
- origin = origin.country_code(:alpha2)
443
-
444
- name = case origin
445
- when "CA" then CANADA_ORIGIN_SERVICES[code]
446
- when "MX" then MEXICO_ORIGIN_SERVICES[code]
447
- when *EU_COUNTRY_CODES then EU_ORIGIN_SERVICES[code]
448
- end
449
-
450
- name ||= OTHER_NON_US_ORIGIN_SERVICES[code] unless name == 'US'
451
- name ||= DEFAULT_SERVICES[code]
452
- end
453
-
454
- end
455
- end
456
- end