active_fulfillment 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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