active_shipping 0.12.1 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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