active_fulfillment 1.0.0 → 1.0.1

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.
data/CHANGELOG CHANGED
@@ -1,5 +1,11 @@
1
1
  = ActiveFulfillment CHANGELOG
2
2
 
3
+ == Version 1.0.1 (Dec 13, 2010)
4
+
5
+ * Updated common files with changes from activemerchant [Dennis Theisen]
6
+ * Updated Webgistix USPS shipping methods (4 added, 1 removed) [Dennis Theisen]
7
+ * Changed Webgistix to treat a duplicate response as success instead of failure and to retry failed connection errors. [Dennis Theisen]
8
+
3
9
  == Version 1.0.0 (July 12, 2010)
4
10
 
5
11
  * Add inventory support to Amazon and Webgistix [Adrian Irving-Beer]
data/Rakefile CHANGED
@@ -47,13 +47,14 @@ begin
47
47
  gemspec.email = "cody@shopify.com"
48
48
  gemspec.homepage = "http://github.com/shopify/active_fulfillment"
49
49
  gemspec.authors = ["Cody Fauser", "James MacAulay"]
50
- gemspec.add_dependency('activesupport', '~> 2.3.2')
50
+ gemspec.add_dependency('activesupport', '>= 2.3.2')
51
51
  gemspec.add_dependency('builder', '>= 2.0.0')
52
52
  end
53
53
  rescue LoadError
54
54
  puts "Jeweler not available. Install it with: gem install jeweler"
55
55
  end
56
56
 
57
+ desc "Update common files from active_merchant directory"
57
58
  task :update_common do
58
59
  STDERR.puts "Updating common include from ../active_merchant. Please make sure this is up-to-date"
59
60
  system("diff -u lib/active_merchant/common.rb ../active_merchant/lib/active_merchant/common.rb | patch -p0")
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.0.1
@@ -1,68 +1,72 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{active_fulfillment}
8
- s.version = "1.0.0"
8
+ s.version = "1.0.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Cody Fauser", "James MacAulay"]
12
- s.date = %q{2010-07-12}
12
+ s.date = %q{2010-12-13}
13
13
  s.email = %q{cody@shopify.com}
14
14
  s.files = [
15
15
  "CHANGELOG",
16
- "Rakefile",
17
- "VERSION",
18
- "active_fulfillment.gemspec",
19
- "init.rb",
20
- "lib/active_fulfillment.rb",
21
- "lib/active_fulfillment/fulfillment/base.rb",
22
- "lib/active_fulfillment/fulfillment/response.rb",
23
- "lib/active_fulfillment/fulfillment/service.rb",
24
- "lib/active_fulfillment/fulfillment/services.rb",
25
- "lib/active_fulfillment/fulfillment/services/amazon.rb",
26
- "lib/active_fulfillment/fulfillment/services/shipwire.rb",
27
- "lib/active_fulfillment/fulfillment/services/webgistix.rb",
28
- "lib/active_merchant/common.rb",
29
- "lib/active_merchant/common/connection.rb",
30
- "lib/active_merchant/common/country.rb",
31
- "lib/active_merchant/common/error.rb",
32
- "lib/active_merchant/common/post_data.rb",
33
- "lib/active_merchant/common/posts_data.rb",
34
- "lib/active_merchant/common/requires_parameters.rb",
35
- "lib/active_merchant/common/utils.rb",
36
- "lib/active_merchant/common/validateable.rb",
37
- "lib/certs/cacert.pem",
38
- "test/fixtures.yml",
39
- "test/fixtures/xml/amazon/inventory_get_response.xml",
40
- "test/fixtures/xml/amazon/inventory_list_response.xml",
41
- "test/fixtures/xml/amazon/inventory_list_response_with_next_1.xml",
42
- "test/fixtures/xml/amazon/inventory_list_response_with_next_2.xml",
43
- "test/remote/amazon_test.rb",
44
- "test/remote/shipwire_test.rb",
45
- "test/remote/webgistix_test.rb",
46
- "test/test_helper.rb",
47
- "test/unit/base_test.rb",
48
- "test/unit/services/amazon_test.rb",
49
- "test/unit/services/shipwire_test.rb",
50
- "test/unit/services/webgistix_test.rb"
16
+ "Rakefile",
17
+ "VERSION",
18
+ "active_fulfillment.gemspec",
19
+ "init.rb",
20
+ "lib/active_fulfillment.rb",
21
+ "lib/active_fulfillment/fulfillment/base.rb",
22
+ "lib/active_fulfillment/fulfillment/response.rb",
23
+ "lib/active_fulfillment/fulfillment/service.rb",
24
+ "lib/active_fulfillment/fulfillment/services.rb",
25
+ "lib/active_fulfillment/fulfillment/services/amazon.rb",
26
+ "lib/active_fulfillment/fulfillment/services/shipwire.rb",
27
+ "lib/active_fulfillment/fulfillment/services/webgistix.rb",
28
+ "lib/active_merchant/common.rb",
29
+ "lib/active_merchant/common/connection.rb",
30
+ "lib/active_merchant/common/country.rb",
31
+ "lib/active_merchant/common/error.rb",
32
+ "lib/active_merchant/common/post_data.rb",
33
+ "lib/active_merchant/common/posts_data.rb",
34
+ "lib/active_merchant/common/requires_parameters.rb",
35
+ "lib/active_merchant/common/utils.rb",
36
+ "lib/active_merchant/common/validateable.rb",
37
+ "lib/certs/cacert.pem",
38
+ "test/fixtures.yml",
39
+ "test/fixtures/xml/amazon/inventory_get_response.xml",
40
+ "test/fixtures/xml/amazon/inventory_list_response.xml",
41
+ "test/fixtures/xml/amazon/inventory_list_response_with_next_1.xml",
42
+ "test/fixtures/xml/amazon/inventory_list_response_with_next_2.xml",
43
+ "test/fixtures/xml/amazon/tracking_response_1.xml",
44
+ "test/fixtures/xml/amazon/tracking_response_2.xml",
45
+ "test/fixtures/xml/amazon/tracking_response_error.xml",
46
+ "test/fixtures/xml/amazon/tracking_response_not_found.xml",
47
+ "test/fixtures/xml/webgistix/tracking_response.xml",
48
+ "test/remote/amazon_test.rb",
49
+ "test/remote/shipwire_test.rb",
50
+ "test/remote/webgistix_test.rb",
51
+ "test/test_helper.rb",
52
+ "test/unit/base_test.rb",
53
+ "test/unit/services/amazon_test.rb",
54
+ "test/unit/services/shipwire_test.rb",
55
+ "test/unit/services/webgistix_test.rb"
51
56
  ]
52
57
  s.homepage = %q{http://github.com/shopify/active_fulfillment}
53
- s.rdoc_options = ["--charset=UTF-8"]
54
58
  s.require_paths = ["lib"]
55
59
  s.rubygems_version = %q{1.3.7}
56
60
  s.summary = %q{Framework and tools for dealing with shipping, tracking and order fulfillment services.}
57
61
  s.test_files = [
58
62
  "test/remote/amazon_test.rb",
59
- "test/remote/shipwire_test.rb",
60
- "test/remote/webgistix_test.rb",
61
- "test/test_helper.rb",
62
- "test/unit/base_test.rb",
63
- "test/unit/services/amazon_test.rb",
64
- "test/unit/services/shipwire_test.rb",
65
- "test/unit/services/webgistix_test.rb"
63
+ "test/remote/shipwire_test.rb",
64
+ "test/remote/webgistix_test.rb",
65
+ "test/test_helper.rb",
66
+ "test/unit/base_test.rb",
67
+ "test/unit/services/amazon_test.rb",
68
+ "test/unit/services/shipwire_test.rb",
69
+ "test/unit/services/webgistix_test.rb"
66
70
  ]
67
71
 
68
72
  if s.respond_to? :specification_version then
@@ -70,14 +74,14 @@ Gem::Specification.new do |s|
70
74
  s.specification_version = 3
71
75
 
72
76
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
73
- s.add_runtime_dependency(%q<activesupport>, ["~> 2.3.2"])
77
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.2"])
74
78
  s.add_runtime_dependency(%q<builder>, [">= 2.0.0"])
75
79
  else
76
- s.add_dependency(%q<activesupport>, ["~> 2.3.2"])
80
+ s.add_dependency(%q<activesupport>, [">= 2.3.2"])
77
81
  s.add_dependency(%q<builder>, [">= 2.0.0"])
78
82
  end
79
83
  else
80
- s.add_dependency(%q<activesupport>, ["~> 2.3.2"])
84
+ s.add_dependency(%q<activesupport>, [">= 2.3.2"])
81
85
  s.add_dependency(%q<builder>, [">= 2.0.0"])
82
86
  end
83
87
  end
@@ -30,6 +30,16 @@ rescue LoadError
30
30
  require 'active_support'
31
31
  end
32
32
 
33
+ require 'active_support/core_ext/class/inheritable_attributes'
34
+ require 'active_support/core_ext/class/delegating_attributes'
35
+ require 'active_support/core_ext/time/calculations'
36
+ require 'active_support/core_ext/numeric/time'
37
+ require 'active_support/core_ext/enumerable'
38
+ begin
39
+ require 'active_support/core_ext/time/acts_like'
40
+ rescue LoadError
41
+ end
42
+
33
43
  begin
34
44
  require 'builder'
35
45
  rescue LoadError
@@ -54,7 +54,8 @@ module ActiveMerchant
54
54
  :outbound => {
55
55
  :status => 'GetServiceStatus',
56
56
  :create => 'CreateFulfillmentOrder',
57
- :list => 'ListAllFulfillmentOrders'
57
+ :list => 'ListAllFulfillmentOrders',
58
+ :tracking => 'GetFulfillmentOrder'
58
59
  },
59
60
  :inventory => {
60
61
  :get => 'GetInventorySupply',
@@ -113,6 +114,26 @@ module ActiveMerchant
113
114
  response
114
115
  end
115
116
  end
117
+
118
+ def fetch_tracking_numbers(order_ids, options = {})
119
+ order_ids.inject(nil) do |previous, o_id|
120
+ response = commit :outbound, :tracking, build_tracking_request(o_id, options)
121
+
122
+ if !response.success?
123
+ if response.faultstring =~ /Reason: requested order not found./
124
+ response = Response.new(true, nil, {
125
+ :status => SUCCESS,
126
+ :tracking_numbers => {}
127
+ })
128
+ else
129
+ return response
130
+ end
131
+ end
132
+
133
+ response.tracking_numbers.merge!(previous.tracking_numbers) if previous
134
+ response
135
+ end
136
+ end
116
137
 
117
138
  def valid_credentials?
118
139
  status.success?
@@ -202,6 +223,15 @@ module ActiveMerchant
202
223
  end
203
224
  end
204
225
 
226
+ def build_tracking_request(order_id, options)
227
+ request = OPERATIONS[:outbound][:tracking]
228
+ soap_request(request) do |xml|
229
+ xml.tag! request, { 'xmlns' => SERVICES[:outbound][:xmlns] } do
230
+ xml.tag! "MerchantFulfillmentOrderId", order_id
231
+ end
232
+ end
233
+ end
234
+
205
235
  def add_credentials(xml, request)
206
236
  login = @options[:login]
207
237
  timestamp = "#{Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S")}Z"
@@ -264,7 +294,12 @@ module ActiveMerchant
264
294
 
265
295
  case service
266
296
  when :outbound
267
- parse_fulfillment_response(op, document)
297
+ case op
298
+ when :tracking
299
+ parse_tracking_response(document)
300
+ else
301
+ parse_fulfillment_response(op, document)
302
+ end
268
303
  when :inventory
269
304
  parse_inventory_response(document)
270
305
  else
@@ -288,7 +323,7 @@ module ActiveMerchant
288
323
 
289
324
  document.each_element('//ns1:MerchantSKUSupply') do |node|
290
325
  # {MerchantSKU => 'SOME-ID', InStockSupplyQuantity => '101', ...}
291
- params = node.elements.to_a.inject(Hash.new) {|h, k| h[k.name] = k.text; h}
326
+ params = node.elements.to_a.each_with_object({}) {|elem, hash| hash[elem.name] = elem.text}
292
327
 
293
328
  response[:stock_levels][params['MerchantSKU']] = params['InStockSupplyQuantity'].to_i
294
329
  end
@@ -300,6 +335,20 @@ module ActiveMerchant
300
335
  response
301
336
  end
302
337
 
338
+ def parse_tracking_response(document)
339
+ response = {}
340
+ response[:tracking_numbers] = {}
341
+
342
+ track_node = REXML::XPath.first(document, '//ns1:FulfillmentShipmentPackage/ns1:TrackingNumber')
343
+ if track_node
344
+ id_node = REXML::XPath.first(document, '//ns1:MerchantFulfillmentOrderId')
345
+ response[:tracking_numbers][id_node.text] = track_node.text
346
+ end
347
+
348
+ response[:response_status] = SUCCESS
349
+ response
350
+ end
351
+
303
352
  def parse_error(http_response)
304
353
  response = {}
305
354
  response[:http_code] = http_response.code
@@ -54,12 +54,12 @@ module ActiveMerchant
54
54
  commit :inventory, build_inventory_request(options)
55
55
  end
56
56
 
57
- def fetch_tracking_numbers(options = {})
58
- commit :tracking, build_tracking_request(options)
57
+ def fetch_tracking_numbers(order_ids)
58
+ commit :tracking, build_tracking_request(order_ids)
59
59
  end
60
60
 
61
61
  def valid_credentials?
62
- response = fetch_tracking_numbers
62
+ response = fetch_tracking_numbers([])
63
63
  response.message !~ INVALID_LOGIN
64
64
  end
65
65
 
@@ -91,14 +91,16 @@ module ActiveMerchant
91
91
  end
92
92
  end
93
93
 
94
- def build_tracking_request(options)
94
+ def build_tracking_request(order_ids)
95
95
  xml = Builder::XmlMarkup.new
96
96
  xml.instruct!
97
97
  xml.declare! :DOCTYPE, :InventoryStatus, :SYSTEM, SCHEMA_URLS[:inventory]
98
98
  xml.tag! 'TrackingUpdate' do
99
99
  add_credentials(xml)
100
100
  xml.tag! 'Server', test? ? 'Test' : 'Production'
101
- xml.tag! 'Bookmark', '3'
101
+ order_ids.each do |o_id|
102
+ xml.tag! 'OrderNo', o_id
103
+ end
102
104
  end
103
105
  end
104
106
 
@@ -3,16 +3,26 @@ module ActiveMerchant
3
3
  class WebgistixService < Service
4
4
  SERVICE_URLS = {
5
5
  :fulfillment => 'https://www.webgistix.com/XML/CreateOrder.asp',
6
- :inventory => 'https://www.webgistix.com/XML/GetInventory.asp'
6
+ :inventory => 'https://www.webgistix.com/XML/GetInventory.asp',
7
+ :tracking => 'https://www.webgistix.com/XML/GetTracking.asp'
7
8
  }
8
9
  TEST_URLS = SERVICE_URLS.merge({
9
10
  :fulfillment => 'https://www.webgistix.com/XML/CreateOrderTest.asp'
10
11
  })
12
+
13
+ SUCCESS, DUPLICATE, FAILURE = 'True', 'Duplicate', 'False'
11
14
 
12
- SUCCESS, FAILURE = 'True', 'False'
13
15
  SUCCESS_MESSAGE = 'Successfully submitted the order'
14
16
  FAILURE_MESSAGE = 'Failed to submit the order'
15
- INVALID_LOGIN = 'Access Denied'
17
+ DUPLICATE_MESSAGE = 'This order has already been successfully submitted'
18
+
19
+ INVALID_LOGIN = 'Invalid Credentials'
20
+ NOT_SHIPPED = 'Not Shipped'
21
+
22
+ # If a request is detected as a duplicate only the original data will be
23
+ # used by Webgistix, and the subsequent responses will have a
24
+ # :duplicate parameter set in the params hash.
25
+ self.retry_safe = true
16
26
 
17
27
  # The first is the label, and the last is the code
18
28
  def self.shipping_methods
@@ -37,16 +47,18 @@ module ActiveMerchant
37
47
  ["FedEx International Economy", "FedEx International Economy"],
38
48
  ["FedEx International First", "FedEx International First"],
39
49
  ["FedEx Ground", "FedEx Ground"],
40
- ["USPS Priority Mail & Global Priority Mail", "Priority"],
41
- ["USPS Priority Mail & Global Priority Mail (flat rate)", "Flat Rate Priority"],
50
+ ["USPS Priority Mail", "Priority Mail"],
51
+ ["USPS Priority Mail International", "Priority Mail International"],
52
+ ["USPS Priority Mail Small Flat Rate Box", "Priority Mail Small Flat Rate Box"],
53
+ ["USPS Priority Mail Medium Flat Rate Box", "Priority Mail Medium Flat Rate Box"],
54
+ ["USPS Priority Mail Large Flat Rate Box", "Priority Mail Large Flat Rate Box"],
55
+ ["USPS Priority Mail Flat Rate Envelope", "Priority Mail Flat Rate Envelope"],
42
56
  ["USPS First Class Mail", "First Class"],
43
- ["USPS Express Mail & Global Express Mail", "Express"],
44
- ["USPS Flat Rate Global Express Mail", "Global Express Mail Flat Rate"],
45
- ["USPS Parcel Post", "Parcel"],
46
57
  ["USPS First Class International", "First Class International"],
47
- ["USPS Media Mail", "Media Mail"],
48
- ["USPS Economy Parcel Post", "Economy Parcel"],
49
- ["USPS Economy Air Letter Post", "Economy Letter"],
58
+ ["USPS Express Mail", "Express"],
59
+ ["USPS Express Mail International", "Express Mail International"],
60
+ ["USPS Parcel Post", "Parcel"],
61
+ ["USPS Media Mail", "Media Mail"]
50
62
  ].inject(ActiveSupport::OrderedHash.new){|h, (k,v)| h[k] = v; h}
51
63
  end
52
64
 
@@ -65,6 +77,10 @@ module ActiveMerchant
65
77
  def fetch_stock_levels(options = {})
66
78
  commit :inventory, build_inventory_request(options)
67
79
  end
80
+
81
+ def fetch_tracking_numbers(order_ids, options = {})
82
+ commit :tracking, build_tracking_request(order_ids, options)
83
+ end
68
84
 
69
85
  def valid_credentials?
70
86
  response = fulfill('', {}, [], :shipping_method => '')
@@ -124,7 +140,32 @@ module ActiveMerchant
124
140
  add_credentials(xml)
125
141
  end
126
142
  end
127
-
143
+
144
+ #<?xml version="1.0"?>
145
+ # <TrackingXML>
146
+ # <Password>Webgistix</Password>
147
+ # <CustomerID>3</CustomerID>
148
+ # <Tracking>
149
+ # <Order>AB12345</Order>
150
+ # </Tracking>
151
+ # <Tracking>
152
+ # <Order>XY4567</Order>
153
+ # </Tracking>
154
+ # </TrackingXML>
155
+ def build_tracking_request(order_ids, options)
156
+ xml = Builder::XmlMarkup.new :indent => 2
157
+ xml.instruct!
158
+ xml.tag! 'TrackingXML' do
159
+ add_credentials(xml)
160
+
161
+ order_ids.each do |o_id|
162
+ xml.tag! 'Tracking' do
163
+ xml.tag! 'Order', o_id
164
+ end
165
+ end
166
+ end
167
+ end
168
+
128
169
  def add_credentials(xml)
129
170
  xml.tag! 'CustomerID', @options[:login]
130
171
  xml.tag! 'Password', @options[:password]
@@ -184,13 +225,15 @@ module ActiveMerchant
184
225
  end
185
226
 
186
227
  def success?(response)
187
- response[:success] == SUCCESS
228
+ response[:success] == SUCCESS || response[:success] == DUPLICATE
188
229
  end
189
230
 
190
231
  def message_from(response)
191
- return SUCCESS_MESSAGE if success?(response)
192
-
193
- if response[:error_0] == INVALID_LOGIN
232
+ if response[:duplicate]
233
+ DUPLICATE_MESSAGE
234
+ elsif success?(response)
235
+ SUCCESS_MESSAGE
236
+ elsif response[:error_0] == INVALID_LOGIN
194
237
  INVALID_LOGIN
195
238
  else
196
239
  FAILURE_MESSAGE
@@ -209,18 +252,15 @@ module ActiveMerchant
209
252
  parse_fulfillment_response(document)
210
253
  when :inventory
211
254
  parse_inventory_response(document)
255
+ when :tracking
256
+ parse_tracking_response(document)
212
257
  else
213
258
  raise ArgumentError, "Unknown action #{action}"
214
259
  end
215
260
  end
216
261
 
217
262
  def parse_fulfillment_response(document)
218
- response = {}
219
-
220
- # Fetch the errors
221
- document.root.elements.to_a("Error").each_with_index do |e, i|
222
- response["error_#{i}".to_sym] = e.text
223
- end
263
+ response = parse_errors(document)
224
264
 
225
265
  # Check if completed
226
266
  if completed = REXML::XPath.first(document, '//Completed')
@@ -231,23 +271,50 @@ module ActiveMerchant
231
271
  response[:success] = FAILURE
232
272
  end
233
273
 
274
+ response[:duplicate] = response[:success] == DUPLICATE
275
+
234
276
  response
235
277
  end
236
278
 
237
279
  def parse_inventory_response(document)
238
- response = {}
280
+ response = parse_errors(document)
239
281
  response[:stock_levels] = {}
240
282
 
241
283
  document.root.each_element('//Item') do |node|
242
284
  # {ItemID => 'SOME-ID', ItemQty => '101'}
243
- params = node.elements.to_a.inject(Hash.new) {|h, k| h[k.name] = k.text; h}
285
+ params = node.elements.to_a.each_with_object({}) {|elem, hash| hash[elem.name] = elem.text}
244
286
 
245
287
  response[:stock_levels][params['ItemID']] = params['ItemQty'].to_i
246
288
  end
247
289
 
248
- response[:success] = SUCCESS
249
290
  response
250
291
  end
292
+
293
+ def parse_tracking_response(document)
294
+ response = parse_errors(document)
295
+ response[:tracking_numbers] = {}
296
+
297
+ document.root.each_element('//Shipment') do |node|
298
+ # {InvoiceNumber => 'SOME-ID', ShipmentTrackingNumber => 'SOME-TRACKING-NUMBER'}
299
+ params = node.elements.to_a.each_with_object({}) {|elem, hash| hash[elem.name] = elem.text}
300
+
301
+ tracking = params['ShipmentTrackingNumber']
302
+ response[:tracking_numbers][params['InvoiceNumber']] = tracking unless tracking == NOT_SHIPPED
303
+ end
304
+
305
+ response
306
+ end
307
+
308
+ def parse_errors(document)
309
+ response = {}
310
+
311
+ REXML::XPath.match(document, "//Errors/Error").to_a.each_with_index do |e, i|
312
+ response["error_#{i}".to_sym] = e.text
313
+ end
314
+
315
+ response[:success] = response.empty? ? SUCCESS : FAILURE
316
+ response
317
+ end
251
318
  end
252
319
  end
253
320
  end
@@ -71,9 +71,8 @@ module ActiveMerchant
71
71
  end
72
72
 
73
73
  info "--> %d %s (%d %.4fs)" % [result.code, result.message, result.body ? result.body.length : 0, realtime], tag
74
- response = handle_response(result)
75
- debug response
76
- response
74
+ debug result.body
75
+ result
77
76
  rescue EOFError => e
78
77
  raise ConnectionError, "The remote server dropped the connection"
79
78
  rescue Errno::ECONNRESET => e
@@ -147,15 +146,6 @@ module ActiveMerchant
147
146
  end
148
147
  end
149
148
 
150
- def handle_response(response)
151
- case response.code.to_i
152
- when 200...300
153
- response.body
154
- else
155
- raise ResponseError.new(response)
156
- end
157
- end
158
-
159
149
  def debug(message, tag = nil)
160
150
  log(:debug, message, tag)
161
151
  end
@@ -169,4 +159,4 @@ module ActiveMerchant
169
159
  logger.send(level, message) if logger
170
160
  end
171
161
  end
172
- end
162
+ end
@@ -46,7 +46,16 @@ module ActiveMerchant #:nodoc:
46
46
  end
47
47
 
48
48
  def code(format)
49
- @codes.select{|c| c.format == format}
49
+ @codes.detect{|c| c.format == format}
50
+ end
51
+
52
+ def ==(other)
53
+ (@name == other.name)
54
+ end
55
+ alias eql? ==
56
+
57
+ def hash
58
+ @name.hash
50
59
  end
51
60
 
52
61
  def to_s
@@ -67,7 +76,6 @@ module ActiveMerchant #:nodoc:
67
76
  { :alpha2 => 'AW', :name => 'Aruba', :alpha3 => 'ABW', :numeric => '533' },
68
77
  { :alpha2 => 'AU', :name => 'Australia', :alpha3 => 'AUS', :numeric => '036' },
69
78
  { :alpha2 => 'AT', :name => 'Austria', :alpha3 => 'AUT', :numeric => '040' },
70
- { :alpha2 => 'AX', :name => 'Åland Islands', :alpha3 => 'ALA', :numeric => '248' },
71
79
  { :alpha2 => 'AZ', :name => 'Azerbaijan', :alpha3 => 'AZE', :numeric => '031' },
72
80
  { :alpha2 => 'BS', :name => 'Bahamas', :alpha3 => 'BHS', :numeric => '044' },
73
81
  { :alpha2 => 'BH', :name => 'Bahrain', :alpha3 => 'BHR', :numeric => '048' },
@@ -84,8 +92,8 @@ module ActiveMerchant #:nodoc:
84
92
  { :alpha2 => 'BW', :name => 'Botswana', :alpha3 => 'BWA', :numeric => '072' },
85
93
  { :alpha2 => 'BV', :name => 'Bouvet Island', :alpha3 => 'BVD', :numeric => '074' },
86
94
  { :alpha2 => 'BR', :name => 'Brazil', :alpha3 => 'BRA', :numeric => '076' },
87
- { :alpha2 => 'BN', :name => 'Brunei Darussalam', :alpha3 => 'BRN', :numeric => '096' },
88
95
  { :alpha2 => 'IO', :name => 'British Indian Ocean Territory', :alpha3 => 'IOT', :numeric => '086' },
96
+ { :alpha2 => 'BN', :name => 'Brunei Darussalam', :alpha3 => 'BRN', :numeric => '096' },
89
97
  { :alpha2 => 'BG', :name => 'Bulgaria', :alpha3 => 'BGR', :numeric => '100' },
90
98
  { :alpha2 => 'BF', :name => 'Burkina Faso', :alpha3 => 'BFA', :numeric => '854' },
91
99
  { :alpha2 => 'BI', :name => 'Burundi', :alpha3 => 'BDI', :numeric => '108' },
@@ -142,15 +150,15 @@ module ActiveMerchant #:nodoc:
142
150
  { :alpha2 => 'GP', :name => 'Guadeloupe', :alpha3 => 'GLP', :numeric => '312' },
143
151
  { :alpha2 => 'GU', :name => 'Guam', :alpha3 => 'GUM', :numeric => '316' },
144
152
  { :alpha2 => 'GT', :name => 'Guatemala', :alpha3 => 'GTM', :numeric => '320' },
153
+ { :alpha2 => 'GG', :name => 'Guernsey', :alpha3 => 'GGY', :numeric => '831' },
145
154
  { :alpha2 => 'GN', :name => 'Guinea', :alpha3 => 'GIN', :numeric => '324' },
146
155
  { :alpha2 => 'GW', :name => 'Guinea-Bissau', :alpha3 => 'GNB', :numeric => '624' },
147
156
  { :alpha2 => 'GY', :name => 'Guyana', :alpha3 => 'GUY', :numeric => '328' },
148
- { :alpha2 => 'GG', :name => 'Guernsey', :alpha3 => 'GGY', :numeric => '831' },
149
157
  { :alpha2 => 'HT', :name => 'Haiti', :alpha3 => 'HTI', :numeric => '332' },
158
+ { :alpha2 => 'HM', :name => 'Heard Island And Mcdonald Islands', :alpha3 => 'HMD', :numeric => '334' },
150
159
  { :alpha2 => 'VA', :name => 'Holy See (Vatican City State)', :alpha3 => 'VAT', :numeric => '336' },
151
160
  { :alpha2 => 'HN', :name => 'Honduras', :alpha3 => 'HND', :numeric => '340' },
152
161
  { :alpha2 => 'HK', :name => 'Hong Kong', :alpha3 => 'HKG', :numeric => '344' },
153
- { :alpha2 => 'HM', :name => 'Heard Island And Mcdonald Islands', :alpha3 => 'HMD', :numeric => '334' },
154
162
  { :alpha2 => 'HU', :name => 'Hungary', :alpha3 => 'HUN', :numeric => '348' },
155
163
  { :alpha2 => 'IS', :name => 'Iceland', :alpha3 => 'ISL', :numeric => '352' },
156
164
  { :alpha2 => 'IN', :name => 'India', :alpha3 => 'IND', :numeric => '356' },
@@ -298,7 +306,8 @@ module ActiveMerchant #:nodoc:
298
306
  { :alpha2 => 'EH', :name => 'Western Sahara', :alpha3 => 'ESH', :numeric => '732' },
299
307
  { :alpha2 => 'YE', :name => 'Yemen', :alpha3 => 'YEM', :numeric => '887' },
300
308
  { :alpha2 => 'ZM', :name => 'Zambia', :alpha3 => 'ZMB', :numeric => '894' },
301
- { :alpha2 => 'ZW', :name => 'Zimbabwe', :alpha3 => 'ZWE', :numeric => '716' }
309
+ { :alpha2 => 'ZW', :name => 'Zimbabwe', :alpha3 => 'ZWE', :numeric => '716' },
310
+ { :alpha2 => 'AX', :name => 'Åland Islands', :alpha3 => 'ALA', :numeric => '248' }
302
311
  ]
303
312
 
304
313
  def self.find(name)
@@ -25,9 +25,12 @@ module ActiveMerchant #:nodoc:
25
25
  def ssl_post(endpoint, data, headers = {})
26
26
  ssl_request(:post, endpoint, data, headers)
27
27
  end
28
-
29
- private
30
- def ssl_request(method, endpoint, data, headers = {})
28
+
29
+ def ssl_request(method, endpoint, data, headers)
30
+ handle_response(raw_ssl_request(method, endpoint, data, headers))
31
+ end
32
+
33
+ def raw_ssl_request(method, endpoint, data, headers = {})
31
34
  connection = Connection.new(endpoint)
32
35
  connection.open_timeout = open_timeout
33
36
  connection.read_timeout = read_timeout
@@ -42,6 +45,17 @@ module ActiveMerchant #:nodoc:
42
45
 
43
46
  connection.request(method, data, headers)
44
47
  end
48
+
49
+ private
50
+
51
+ def handle_response(response)
52
+ case response.code.to_i
53
+ when 200...300
54
+ response.body
55
+ else
56
+ raise ResponseError.new(response)
57
+ end
58
+ end
45
59
 
46
60
  end
47
- end
61
+ end
@@ -0,0 +1,56 @@
1
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
2
+ <soapenv:Body>
3
+ <ns1:GetFulfillmentOrderResponse
4
+ xmlns:ns1="http://fba-outbound.amazonaws.com/doc/2007-08-02/">
5
+ <ns1:GetFulfillmentOrderResult>
6
+ <ns1:FulfillmentOrder>
7
+ <ns1:MerchantFulfillmentOrderId>TEST-00000001</ns1:MerchantFulfillmentOrderId>
8
+ <ns1:ReceivedDateTime>2007-08-02T08:00:00Z</ns1:ReceivedDateTime>
9
+ <ns1:ShippingSpeedCategory>Standard</ns1:ShippingSpeedCategory>
10
+ <ns1:DisplayableOrderDateTime>2007-08-02T00:00:00Z</ns1:DisplayableOrderDateTime>
11
+ <ns1:DisplayableOrderComment>Thank you for your order!</ns1:DisplayableOrderComment>
12
+ <ns1:DisplayableOrderId>TEST-00000001</ns1:DisplayableOrderId>
13
+ <ns1:DestinationAddress>
14
+ <ns1:Name>John Smith</ns1:Name>
15
+ <ns1:Line1>2412 25th Ave NW.</ns1:Line1>
16
+ <ns1:City>Seattle</ns1:City>
17
+ <ns1:StateOrProvinceCode>WA</ns1:StateOrProvinceCode>
18
+ <ns1:CountryCode>US</ns1:CountryCode>
19
+ <ns1:PostalCode>98104</ns1:PostalCode>
20
+ <ns1:PhoneNumber>206-266-1000</ns1:PhoneNumber>
21
+ </ns1:DestinationAddress>
22
+ <ns1:FulfillmentOrderStatus>Complete</ns1:FulfillmentOrderStatus>
23
+ <ns1:StatusUpdatedDateTime>2007-08-03T16:00:00Z</ns1:StatusUpdatedDateTime>
24
+ </ns1:FulfillmentOrder>
25
+ <ns1:FulfillmentOrderItem>
26
+ <ns1:MerchantSKU>MSKU-00000001</ns1:MerchantSKU>
27
+ <ns1:MerchantFulfillmentOrderItemId>TEST-00000001-1</ns1:MerchantFulfillmentOrderItemId>
28
+ <ns1:Quantity>2</ns1:Quantity>
29
+ <ns1:CancelledQuantity>0</ns1:CancelledQuantity>
30
+ <ns1:UnfulfillableQuantity>0</ns1:UnfulfillableQuantity>
31
+ </ns1:FulfillmentOrderItem>
32
+ <ns1:FulfillmentShipment>
33
+ <ns1:AmazonShipmentId>TEST00000001</ns1:AmazonShipmentId>
34
+ <ns1:FulfillmentCenterId>TST1</ns1:FulfillmentCenterId>
35
+ <ns1:FulfillmentShipmentStatus>Shipped</ns1:FulfillmentShipmentStatus>
36
+ <ns1:ShippingDateTime>2007-08-03T16:00:00Z</ns1:ShippingDateTime>
37
+ <ns1:EstimatedArrivalDateTime>2007-08-10T16:00:00Z</ns1:EstimatedArrivalDateTime>
38
+ <ns1:FulfillmentShipmentItem>
39
+ <ns1:MerchantSKU>MSKU-00000001</ns1:MerchantSKU>
40
+ <ns1:MerchantFulfillmentOrderItemId>TEST-00000001-1</ns1:MerchantFulfillmentOrderItemId>
41
+ <ns1:Quantity>2</ns1:Quantity>
42
+ <ns1:PackageNumber>1</ns1:PackageNumber>
43
+ </ns1:FulfillmentShipmentItem>
44
+ <ns1:FulfillmentShipmentPackage>
45
+ <ns1:PackageNumber>1</ns1:PackageNumber>
46
+ <ns1:CarrierCode>UPS</ns1:CarrierCode>
47
+ <ns1:TrackingNumber>UPS00000001</ns1:TrackingNumber>
48
+ </ns1:FulfillmentShipmentPackage>
49
+ </ns1:FulfillmentShipment>
50
+ </ns1:GetFulfillmentOrderResult>
51
+ <ns1:ResponseMetadata>
52
+ <ns1:RequestId>963215ec-bec6-4ae0-84e0-19f5823ee33a</ns1:RequestId>
53
+ </ns1:ResponseMetadata>
54
+ </ns1:GetFulfillmentOrderResponse>
55
+ </soapenv:Body>
56
+ </soapenv:Envelope>
@@ -0,0 +1,38 @@
1
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
2
+ <soapenv:Body>
3
+ <ns1:GetFulfillmentOrderResponse
4
+ xmlns:ns1="http://fba-outbound.amazonaws.com/doc/2007-08-02/">
5
+ <ns1:GetFulfillmentOrderResult>
6
+ <ns1:FulfillmentOrder>
7
+ <ns1:MerchantFulfillmentOrderId>TEST-00000002</ns1:MerchantFulfillmentOrderId>
8
+ <ns1:ReceivedDateTime>2007-08-02T08:00:00Z</ns1:ReceivedDateTime>
9
+ <ns1:ShippingSpeedCategory>Standard</ns1:ShippingSpeedCategory>
10
+ <ns1:DisplayableOrderDateTime>2007-08-02T00:00:00Z</ns1:DisplayableOrderDateTime>
11
+ <ns1:DisplayableOrderComment>Thank you for your order!</ns1:DisplayableOrderComment>
12
+ <ns1:DisplayableOrderId>TEST-00000001</ns1:DisplayableOrderId>
13
+ <ns1:DestinationAddress>
14
+ <ns1:Name>John Smith</ns1:Name>
15
+ <ns1:Line1>2412 25th Ave NW.</ns1:Line1>
16
+ <ns1:City>Seattle</ns1:City>
17
+ <ns1:StateOrProvinceCode>WA</ns1:StateOrProvinceCode>
18
+ <ns1:CountryCode>US</ns1:CountryCode>
19
+ <ns1:PostalCode>98104</ns1:PostalCode>
20
+ <ns1:PhoneNumber>206-266-1000</ns1:PhoneNumber>
21
+ </ns1:DestinationAddress>
22
+ <ns1:FulfillmentOrderStatus>Complete</ns1:FulfillmentOrderStatus>
23
+ <ns1:StatusUpdatedDateTime>2007-08-03T16:00:00Z</ns1:StatusUpdatedDateTime>
24
+ </ns1:FulfillmentOrder>
25
+ <ns1:FulfillmentOrderItem>
26
+ <ns1:MerchantSKU>MSKU-00000001</ns1:MerchantSKU>
27
+ <ns1:MerchantFulfillmentOrderItemId>TEST-00000001-1</ns1:MerchantFulfillmentOrderItemId>
28
+ <ns1:Quantity>2</ns1:Quantity>
29
+ <ns1:CancelledQuantity>0</ns1:CancelledQuantity>
30
+ <ns1:UnfulfillableQuantity>0</ns1:UnfulfillableQuantity>
31
+ </ns1:FulfillmentOrderItem>
32
+ </ns1:GetFulfillmentOrderResult>
33
+ <ns1:ResponseMetadata>
34
+ <ns1:RequestId>963215ec-bec6-4ae0-84e0-19f5823ee33a</ns1:RequestId>
35
+ </ns1:ResponseMetadata>
36
+ </ns1:GetFulfillmentOrderResponse>
37
+ </soapenv:Body>
38
+ </soapenv:Envelope>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0"?>
2
+ <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
3
+ xmlns:aws="http://webservices.amazon.com/AWSFault/2005-15-09">
4
+ <env:Body>
5
+ <env:Fault>
6
+ <faultcode>aws:Client.UnknownError</faultcode>
7
+ <faultstring>Something bad happened!</faultstring>
8
+ <detail>
9
+ <aws:RequestId xmlns:aws="http://webservices.amazon.com/AWSFault/2005-15-09">145b969c-23ec-41e4-a552-30e57fc2684f</aws:RequestId>
10
+ </detail>
11
+ </env:Fault>
12
+ </env:Body>
13
+ </env:Envelope>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0"?>
2
+ <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
3
+ xmlns:aws="http://webservices.amazon.com/AWSFault/2005-15-09">
4
+ <env:Body>
5
+ <env:Fault>
6
+ <faultcode>aws:Client.InvalidParameterValue</faultcode>
7
+ <faultstring>Value #1337-1 for parameter MerchantFulfillmentOrderId is invalid. Reason: requested order not found.</faultstring>
8
+ <detail>
9
+ <aws:RequestId xmlns:aws="http://webservices.amazon.com/AWSFault/2005-15-09">145b969c-23ec-41e4-a552-30e57fc2684f</aws:RequestId>
10
+ </detail>
11
+ </env:Fault>
12
+ </env:Body>
13
+ </env:Envelope>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Orders>
3
+ <Shipment>
4
+ <InvoiceNumber>AB12345</InvoiceNumber>
5
+ <WebgistixOrderNumber>67891</WebgistixOrderNumber>
6
+ <Method>UPS Ground</Method>
7
+ <DateShipped>10/25/2009</DateShipped>
8
+ <ShipmentTrackingNumber>1Z8E5A380396682872</ShipmentTrackingNumber>
9
+ </Shipment>
10
+ <Shipment>
11
+ <InvoiceNumber>XY4567</InvoiceNumber>
12
+ <ShipmentTrackingNumber>Not Shipped</ShipmentTrackingNumber>
13
+ </Shipment>
14
+ </Orders>
@@ -76,6 +76,18 @@ class RemoteAmazonTest < Test::Unit::TestCase
76
76
  assert_equal 0, response.stock_levels['SETTLERS']
77
77
  end
78
78
 
79
+ def test_fetch_tracking_numbers
80
+ response = @service.fetch_tracking_numbers(['123456']) # an actual order
81
+ assert response.success?
82
+ assert_equal Hash.new, response.tracking_numbers # no tracking numbers in testing
83
+ end
84
+
85
+ def test_fetch_tracking_numbers_ignores_not_found
86
+ response = @service.fetch_tracking_numbers(['#1337-1'])
87
+ assert response.success?
88
+ assert_equal Hash.new, response.tracking_numbers
89
+ end
90
+
79
91
  def test_valid_credentials
80
92
  assert @service.valid_credentials?
81
93
  end
@@ -125,10 +125,10 @@ class RemoteShipwireTest < Test::Unit::TestCase
125
125
  end
126
126
 
127
127
  def test_fetch_tracking_numbers
128
- response = @shipwire.fetch_tracking_numbers
128
+ response = @shipwire.fetch_tracking_numbers(['123456'])
129
129
  assert response.success?
130
130
  assert response.test?
131
- assert_equal Hash.new, response.tracking_numbers
131
+ assert_equal Hash.new, response.tracking_numbers # no tracking numbers in testing
132
132
  end
133
133
 
134
134
  def test_valid_credentials
@@ -63,15 +63,25 @@ class RemoteWebgistixTest < Test::Unit::TestCase
63
63
  response = service.fulfill('123456', @address, @line_items, @options)
64
64
  assert !response.success?
65
65
  assert response.test?
66
- assert_equal "Access Denied", response.message
66
+ assert_equal "Invalid Credentials", response.message
67
67
  end
68
68
 
69
69
  def test_get_inventory
70
70
  response = @service.fetch_stock_levels
71
71
  assert response.success?
72
72
  assert response.test?
73
- assert_equal 95, response.stock_levels['GN-600-46']
74
- assert_equal 97, response.stock_levels['GN-800-09']
73
+ assert_equal 90, response.stock_levels['WX-01-3022']
74
+ assert_equal 140, response.stock_levels['WX-04-1080']
75
+ end
76
+
77
+ def test_fetch_tracking_numbers
78
+ response = @service.fetch_tracking_numbers([
79
+ '1254658', 'FAItest123', 'Flat Rate Test Order 4'
80
+ ])
81
+ assert response.success?
82
+ assert_equal '4209073191018052136352154', response.tracking_numbers['1254658']
83
+ assert_equal '9101805213907472080032', response.tracking_numbers['Flat Rate Test Order 4']
84
+ assert_nil response.tracking_numbers['FAItest123'] # 'Not Shipped'
75
85
  end
76
86
 
77
87
  def test_valid_credentials
@@ -90,6 +90,49 @@ class AmazonTest < Test::Unit::TestCase
90
90
  assert_equal 555, response.stock_levels['GN-02-02A']
91
91
  end
92
92
 
93
+ def test_fetch_tracking_numbers
94
+ @service.expects(:ssl_post).twice.returns(
95
+ xml_fixture('amazon/tracking_response_1'),
96
+ xml_fixture('amazon/tracking_response_2')
97
+ )
98
+
99
+ response = @service.fetch_tracking_numbers(['TEST-00000001', 'TEST-00000002'])
100
+ assert response.success?
101
+ assert_equal 'UPS00000001', response.tracking_numbers['TEST-00000001']
102
+ assert_nil response.tracking_numbers['TEST-00000002']
103
+ end
104
+
105
+ def test_fetch_tracking_numbers_ignores_not_found
106
+ response = mock('response')
107
+ response.stubs(:code).returns(500)
108
+ response.stubs(:message).returns('Internal Server Error')
109
+ response.stubs(:body).returns(xml_fixture('amazon/tracking_response_not_found'))
110
+
111
+ @service.expects(:ssl_post).times(3).
112
+ returns(xml_fixture('amazon/tracking_response_1')).
113
+ raises(ActiveMerchant::ResponseError.new(response)).
114
+ returns(xml_fixture('amazon/tracking_response_2'))
115
+
116
+ response = @service.fetch_tracking_numbers(['TEST-00000001', '#1337-1', 'TEST-00000002'])
117
+ assert response.success?
118
+ assert_equal 'UPS00000001', response.tracking_numbers['TEST-00000001']
119
+ end
120
+
121
+ def test_fetch_tracking_numbers_aborts_on_error
122
+ response = mock('response')
123
+ response.stubs(:code).returns(500)
124
+ response.stubs(:message).returns('Internal Server Error')
125
+ response.stubs(:body).returns(xml_fixture('amazon/tracking_response_error'))
126
+
127
+ @service.expects(:ssl_post).twice.
128
+ returns(xml_fixture('amazon/tracking_response_1')).
129
+ raises(ActiveMerchant::ResponseError.new(response))
130
+
131
+ response = @service.fetch_tracking_numbers(['TEST-00000001', 'ERROR', 'TEST-00000002'])
132
+ assert !response.success?
133
+ assert_equal 'Something bad happened!', response.faultstring
134
+ end
135
+
93
136
  def test_404_error
94
137
  http_response = build_mock_response(response_from_404, "Not Found", "404")
95
138
  @service.expects(:ssl_post).raises(ActiveMerchant::ResponseError.new(http_response))
@@ -62,10 +62,9 @@ class ShipwireTest < Test::Unit::TestCase
62
62
 
63
63
  def test_no_tracking_numbers_available
64
64
  @shipwire.expects(:ssl_post).returns(successful_empty_tracking_response)
65
- response = @shipwire.fetch_tracking_numbers
65
+ response = @shipwire.fetch_tracking_numbers(['1234'])
66
66
  assert response.success?
67
67
  assert_equal Hash.new, response.tracking_numbers
68
-
69
68
  end
70
69
 
71
70
  def test_successful_tracking
@@ -73,7 +72,7 @@ class ShipwireTest < Test::Unit::TestCase
73
72
  "2987" => "1ZW682E90326795080" }
74
73
 
75
74
  @shipwire.expects(:ssl_post).returns(successful_tracking_response)
76
- response = @shipwire.fetch_tracking_numbers
75
+ response = @shipwire.fetch_tracking_numbers(["2986", "2987"])
77
76
  assert response.success?
78
77
  assert_equal "3", response.params["total_orders"]
79
78
  assert_equal "Test", response.params["status"]
@@ -84,7 +83,11 @@ class ShipwireTest < Test::Unit::TestCase
84
83
 
85
84
  def test_successful_tracking_with_live_data
86
85
  @shipwire.expects(:ssl_post).returns(successful_live_tracking_response)
87
- response = @shipwire.fetch_tracking_numbers
86
+ response = @shipwire.fetch_tracking_numbers([
87
+ '21', '22', '23', '24', '25',
88
+ '26', '2581', '2576', '2593', '2598',
89
+ '2610', '2611', '2613', '2616', '2631'
90
+ ])
88
91
  assert response.success?
89
92
  assert_equal "15", response.params["total_orders"]
90
93
  assert_equal "0", response.params["status"]
@@ -99,6 +99,16 @@ class WebgistixTest < Test::Unit::TestCase
99
99
  assert_equal 202, response.stock_levels['GN-00-01A']
100
100
  assert_equal 199, response.stock_levels['GN-00-02A']
101
101
  end
102
+
103
+ def test_tracking_numbers
104
+ @service.expects(:ssl_post).returns(xml_fixture('webgistix/tracking_response'))
105
+
106
+ response = @service.fetch_tracking_numbers(['AB12345', 'XY4567'])
107
+ assert response.success?
108
+ assert_equal WebgistixService::SUCCESS_MESSAGE, response.message
109
+ assert_equal '1Z8E5A380396682872', response.tracking_numbers['AB12345']
110
+ assert_nil response.tracking_numbers['XY4567']
111
+ end
102
112
 
103
113
  def test_failed_login
104
114
  @service.expects(:ssl_post).returns(invalid_login_response)
@@ -106,10 +116,10 @@ class WebgistixTest < Test::Unit::TestCase
106
116
  response = @service.fulfill('123456', @address, @line_items, @options)
107
117
  assert !response.success?
108
118
  assert response.test?
109
- assert_equal 'Access Denied', response.message
119
+ assert_equal 'Invalid Credentials', response.message
110
120
  assert_nil response.params['order_id']
111
121
 
112
- assert_equal 'Access Denied', response.params['error_0']
122
+ assert_equal 'Invalid Credentials', response.params['error_0']
113
123
  end
114
124
 
115
125
  def test_garbage_response
@@ -132,6 +142,22 @@ class WebgistixTest < Test::Unit::TestCase
132
142
  assert !@service.valid_credentials?
133
143
  end
134
144
 
145
+ def test_duplicate_response_is_treated_as_success
146
+ response = stub(:code => 200, :body => duplicate_response, :message => '')
147
+ Net::HTTP.any_instance.stubs(:post).raises(ActiveMerchant::ConnectionError).returns(response)
148
+
149
+ response = @service.fulfill('123456', @address, @line_items, @options)
150
+ assert response.success?
151
+ assert response.test?
152
+ assert_equal WebgistixService::DUPLICATE_MESSAGE, response.message
153
+ assert response.params['duplicate']
154
+ assert_nil response.params['order_id']
155
+ end
156
+
157
+ def test_ensure_gateway_uses_safe_retry
158
+ assert @service.retry_safe
159
+ end
160
+
135
161
  private
136
162
  def minimal_successful_response
137
163
  '<Completed><Success>True</Success></Completed>'
@@ -142,11 +168,11 @@ class WebgistixTest < Test::Unit::TestCase
142
168
  end
143
169
 
144
170
  def invalid_login_response
145
- '<Error>Access Denied</Error>'
171
+ '<Errors><Error>Invalid Credentials</Error></Errors>'
146
172
  end
147
173
 
148
174
  def failure_response
149
- '<Error>No Address Line 1</Error><Error>Unknown ItemID: testitem</Error><Error>Unknown ItemID: WX-01-1000</Error>'
175
+ '<Errors><Error>No Address Line 1</Error><Error>Unknown ItemID: testitem</Error><Error>Unknown ItemID: WX-01-1000</Error></Errors>'
150
176
  end
151
177
 
152
178
  def garbage_response
@@ -159,4 +185,8 @@ class WebgistixTest < Test::Unit::TestCase
159
185
  '<Item><ItemID>GN-00-02A</ItemID><ItemQty>199</ItemQty></Item>' +
160
186
  '</InventoryXML>'
161
187
  end
188
+
189
+ def duplicate_response
190
+ '<Completed><Success>Duplicate</Success></Completed>'
191
+ end
162
192
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_fulfillment
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 0
10
- version: 1.0.0
9
+ - 1
10
+ version: 1.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Cody Fauser
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-07-12 00:00:00 -04:00
19
+ date: 2010-12-13 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -25,7 +25,7 @@ dependencies:
25
25
  requirement: &id001 !ruby/object:Gem::Requirement
26
26
  none: false
27
27
  requirements:
28
- - - ~>
28
+ - - ">="
29
29
  - !ruby/object:Gem::Version
30
30
  hash: 7
31
31
  segments:
@@ -88,6 +88,11 @@ files:
88
88
  - test/fixtures/xml/amazon/inventory_list_response.xml
89
89
  - test/fixtures/xml/amazon/inventory_list_response_with_next_1.xml
90
90
  - test/fixtures/xml/amazon/inventory_list_response_with_next_2.xml
91
+ - test/fixtures/xml/amazon/tracking_response_1.xml
92
+ - test/fixtures/xml/amazon/tracking_response_2.xml
93
+ - test/fixtures/xml/amazon/tracking_response_error.xml
94
+ - test/fixtures/xml/amazon/tracking_response_not_found.xml
95
+ - test/fixtures/xml/webgistix/tracking_response.xml
91
96
  - test/remote/amazon_test.rb
92
97
  - test/remote/shipwire_test.rb
93
98
  - test/remote/webgistix_test.rb
@@ -101,8 +106,8 @@ homepage: http://github.com/shopify/active_fulfillment
101
106
  licenses: []
102
107
 
103
108
  post_install_message:
104
- rdoc_options:
105
- - --charset=UTF-8
109
+ rdoc_options: []
110
+
106
111
  require_paths:
107
112
  - lib
108
113
  required_ruby_version: !ruby/object:Gem::Requirement