active_fulfillment 2.1.9 → 3.0.0.pre2

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -0
  3. data/lib/active_fulfillment.rb +5 -5
  4. data/lib/active_fulfillment/base.rb +10 -0
  5. data/lib/active_fulfillment/response.rb +26 -0
  6. data/lib/active_fulfillment/service.rb +56 -0
  7. data/lib/active_fulfillment/services.rb +5 -0
  8. data/lib/active_fulfillment/services/amazon_mws.rb +473 -0
  9. data/lib/active_fulfillment/services/james_and_james.rb +122 -0
  10. data/lib/active_fulfillment/services/shipwire.rb +266 -0
  11. data/lib/active_fulfillment/services/shopify_api.rb +125 -0
  12. data/lib/active_fulfillment/services/webgistix.rb +334 -0
  13. data/lib/active_fulfillment/version.rb +4 -0
  14. data/test/remote/amazon_mws_test.rb +20 -17
  15. data/test/remote/james_and_james_test.rb +77 -0
  16. data/test/remote/shipwire_test.rb +25 -25
  17. data/test/remote/webgistix_test.rb +21 -21
  18. data/test/test_helper.rb +27 -52
  19. data/test/unit/base_test.rb +4 -4
  20. data/test/unit/services/amazon_mws_test.rb +56 -26
  21. data/test/unit/services/james_and_james_test.rb +90 -0
  22. data/test/unit/services/shipwire_test.rb +18 -18
  23. data/test/unit/services/shopify_api_test.rb +7 -20
  24. data/test/unit/services/webgistix_test.rb +35 -35
  25. metadata +32 -114
  26. data/CHANGELOG +0 -62
  27. data/lib/active_fulfillment/fulfillment/base.rb +0 -12
  28. data/lib/active_fulfillment/fulfillment/response.rb +0 -28
  29. data/lib/active_fulfillment/fulfillment/service.rb +0 -58
  30. data/lib/active_fulfillment/fulfillment/services.rb +0 -5
  31. data/lib/active_fulfillment/fulfillment/services/amazon.rb +0 -389
  32. data/lib/active_fulfillment/fulfillment/services/amazon_mws.rb +0 -454
  33. data/lib/active_fulfillment/fulfillment/services/shipwire.rb +0 -268
  34. data/lib/active_fulfillment/fulfillment/services/shopify_api.rb +0 -125
  35. data/lib/active_fulfillment/fulfillment/services/webgistix.rb +0 -338
  36. data/lib/active_fulfillment/fulfillment/version.rb +0 -6
  37. data/test/fixtures.yml +0 -16
  38. data/test/fixtures/xml/amazon/inventory_get_response.xml +0 -17
  39. data/test/fixtures/xml/amazon/inventory_list_response.xml +0 -29
  40. data/test/fixtures/xml/amazon/inventory_list_response_with_next_1.xml +0 -30
  41. data/test/fixtures/xml/amazon/inventory_list_response_with_next_2.xml +0 -29
  42. data/test/fixtures/xml/amazon/tracking_response_1.xml +0 -56
  43. data/test/fixtures/xml/amazon/tracking_response_2.xml +0 -38
  44. data/test/fixtures/xml/amazon/tracking_response_error.xml +0 -13
  45. data/test/fixtures/xml/amazon/tracking_response_not_found.xml +0 -13
  46. data/test/fixtures/xml/amazon_mws/fulfillment_get_fulfillment_order.xml +0 -114
  47. data/test/fixtures/xml/amazon_mws/fulfillment_get_fulfillment_order_2.xml +0 -90
  48. data/test/fixtures/xml/amazon_mws/fulfillment_get_fullfillment_order_with_multiple_tracking_numbers.xml +0 -121
  49. data/test/fixtures/xml/amazon_mws/fulfillment_list_all_fulfillment_orders.xml +0 -70
  50. data/test/fixtures/xml/amazon_mws/inventory_list_inventory_item_supply.xml +0 -32
  51. data/test/fixtures/xml/amazon_mws/inventory_list_inventory_supply.xml +0 -75
  52. data/test/fixtures/xml/amazon_mws/inventory_list_inventory_supply_by_next_token.xml +0 -38
  53. data/test/fixtures/xml/amazon_mws/tracking_response_error.xml +0 -9
  54. data/test/fixtures/xml/amazon_mws/tracking_response_not_found.xml +0 -9
  55. data/test/fixtures/xml/shipwire/fulfillment_failure_response.xml +0 -7
  56. data/test/fixtures/xml/shipwire/invalid_login_response.xml +0 -7
  57. data/test/fixtures/xml/shipwire/inventory_get_response.xml +0 -44
  58. data/test/fixtures/xml/shipwire/successful_empty_tracking_response.xml +0 -8
  59. data/test/fixtures/xml/shipwire/successful_live_tracking_response.xml +0 -53
  60. data/test/fixtures/xml/shipwire/successful_tracking_response.xml +0 -16
  61. data/test/fixtures/xml/shipwire/successful_tracking_response_with_tracking_urls.xml +0 -31
  62. data/test/fixtures/xml/webgistix/multiple_tracking_response.xml +0 -21
  63. data/test/fixtures/xml/webgistix/tracking_response.xml +0 -14
  64. data/test/remote/amazon_test.rb +0 -124
  65. data/test/unit/services/amazon_test.rb +0 -271
@@ -0,0 +1,334 @@
1
+ module ActiveFulfillment
2
+ class WebgistixService < Service
3
+ SERVICE_URLS = {
4
+ :fulfillment => 'https://www.webgistix.com/XML/CreateOrder.asp',
5
+ :inventory => 'https://www.webgistix.com/XML/GetInventory.asp',
6
+ :tracking => 'https://www.webgistix.com/XML/GetTracking.asp'
7
+ }
8
+ TEST_URLS = SERVICE_URLS.merge({
9
+ :fulfillment => 'https://www.webgistix.com/XML/CreateOrderTest.asp'
10
+ })
11
+
12
+ SUCCESS, DUPLICATE, FAILURE = 'True', 'Duplicate', 'False'
13
+
14
+ SUCCESS_MESSAGE = 'Successfully submitted the order'
15
+ FAILURE_MESSAGE = 'Failed to submit the order'
16
+ DUPLICATE_MESSAGE = 'This order has already been successfully submitted'
17
+
18
+ INVALID_LOGIN = 'Invalid Credentials'
19
+ NOT_SHIPPED = 'Not Shipped'
20
+
21
+ TRACKING_COMPANIES = %w(UPS FedEx USPS)
22
+
23
+ # If a request is detected as a duplicate only the original data will be
24
+ # used by Webgistix, and the subsequent responses will have a
25
+ # :duplicate parameter set in the params hash.
26
+ self.retry_safe = true
27
+
28
+ # The first is the label, and the last is the code
29
+ def self.shipping_methods
30
+ [
31
+ ["UPS Ground Shipping", "Ground"],
32
+ ["UPS Ground", "Ground"],
33
+ ["UPS Standard Shipping (Canada Only)", "Standard"],
34
+ ["UPS Standard Shipping (CA & MX Only)", "Standard"],
35
+ ["UPS 3-Business Day", "3-Day Select"],
36
+ ["UPS 2-Business Day", "2nd Day Air"],
37
+ ["UPS 2-Business Day AM", "2nd Day Air AM"],
38
+ ["UPS Next Day", "Next Day Air"],
39
+ ["UPS Next Day Saver", "Next Day Air Saver"],
40
+ ["UPS Next Day Early AM", "Next Day Air Early AM"],
41
+ ["UPS Worldwide Express (Next Day)", "Worldwide Express"],
42
+ ["UPS Worldwide Expedited (2nd Day)", "Worldwide Expedited"],
43
+ ["UPS Worldwide Express Saver", "Worldwide Express Saver"],
44
+ ["FedEx Priority Overnight", "FedEx Priority Overnight"],
45
+ ["FedEx Standard Overnight", "FedEx Standard Overnight"],
46
+ ["FedEx First Overnight", "FedEx First Overnight"],
47
+ ["FedEx 2nd Day", "FedEx 2nd Day"],
48
+ ["FedEx Express Saver", "FedEx Express Saver"],
49
+ ["FedEx International Priority", "FedEx International Priority"],
50
+ ["FedEx International Economy", "FedEx International Economy"],
51
+ ["FedEx International First", "FedEx International First"],
52
+ ["FedEx Ground", "FedEx Ground"],
53
+ ["USPS Priority Mail", "Priority Mail"],
54
+ ["USPS Priority Mail International", "Priority Mail International"],
55
+ ["USPS Priority Mail Small Flat Rate Box", "Priority Mail Small Flat Rate Box"],
56
+ ["USPS Priority Mail Medium Flat Rate Box", "Priority Mail Medium Flat Rate Box"],
57
+ ["USPS Priority Mail Large Flat Rate Box", "Priority Mail Large Flat Rate Box"],
58
+ ["USPS Priority Mail Flat Rate Envelope", "Priority Mail Flat Rate Envelope"],
59
+ ["USPS First Class Mail", "First Class"],
60
+ ["USPS First Class International", "First Class International"],
61
+ ["USPS Express Mail", "Express"],
62
+ ["USPS Express Mail International", "Express Mail International"],
63
+ ["USPS Parcel Post", "Parcel"],
64
+ ["USPS Media Mail", "Media Mail"]
65
+ ].inject({}){|h, (k,v)| h[k] = v; h}
66
+ end
67
+
68
+ # Pass in the login and password for the shipwire account.
69
+ # Optionally pass in the :test => true to force test mode
70
+ def initialize(options = {})
71
+ requires!(options, :login, :password)
72
+ super
73
+ end
74
+
75
+ def fulfill(order_id, shipping_address, line_items, options = {})
76
+ requires!(options, :shipping_method)
77
+ commit :fulfillment, build_fulfillment_request(order_id, shipping_address, line_items, options)
78
+ end
79
+
80
+ def fetch_stock_levels(options = {})
81
+ commit :inventory, build_inventory_request(options)
82
+ end
83
+
84
+ def fetch_tracking_data(order_ids, options = {})
85
+ commit :tracking, build_tracking_request(order_ids, options)
86
+ end
87
+
88
+ def valid_credentials?
89
+ response = fulfill('', {}, [], :shipping_method => '')
90
+ response.message != INVALID_LOGIN
91
+ end
92
+
93
+ def test_mode?
94
+ true
95
+ end
96
+
97
+ private
98
+ #<?xml version="1.0"?>
99
+ # <OrderXML>
100
+ # <Password>Webgistix</Password>
101
+ # <CustomerID>3</CustomerID>
102
+ # <Order>
103
+ # <ReferenceNumber></ReferenceNumber>
104
+ # <Company>Test Company</Company>
105
+ # <Name>Joe Smith</Name>
106
+ # <Address1>123 Main St.</Address1>
107
+ # <Address2></Address2>
108
+ # <Address3></Address3>
109
+ # <City>Olean</City>
110
+ # <State>NY</State>
111
+ # <ZipCode>14760</ZipCode>
112
+ # <Country>United States</Country>
113
+ # <Email>info@webgistix.com</Email>
114
+ # <Phone>1-123-456-7890</Phone>
115
+ # <ShippingInstructions>Ground</ShippingInstructions>
116
+ # <OrderComments>Test Order</OrderComments>
117
+ # <Approve>0</Approve>
118
+ # <Item>
119
+ # <ItemID>testitem</ItemID>
120
+ # <ItemQty>2</ItemQty>
121
+ # </Item>
122
+ # </Order>
123
+ # </OrderXML>
124
+ def build_fulfillment_request(order_id, shipping_address, line_items, options)
125
+ xml = Builder::XmlMarkup.new :indent => 2
126
+ xml.instruct!
127
+ xml.tag! 'OrderXML' do
128
+ add_credentials(xml)
129
+ add_order(xml, order_id, shipping_address, line_items, options)
130
+ end
131
+ xml.target!
132
+ end
133
+
134
+ #<?xml version="1.0"?>
135
+ # <InventoryXML>
136
+ # <Password>Webgistix</Password>
137
+ # <CustomerID>3</CustomerID>
138
+ # </InventoryXML>
139
+ def build_inventory_request(options)
140
+ xml = Builder::XmlMarkup.new :indent => 2
141
+ xml.instruct!
142
+ xml.tag! 'InventoryXML' do
143
+ add_credentials(xml)
144
+ end
145
+ end
146
+
147
+ #<?xml version="1.0"?>
148
+ # <TrackingXML>
149
+ # <Password>Webgistix</Password>
150
+ # <CustomerID>3</CustomerID>
151
+ # <Tracking>
152
+ # <Order>AB12345</Order>
153
+ # </Tracking>
154
+ # <Tracking>
155
+ # <Order>XY4567</Order>
156
+ # </Tracking>
157
+ # </TrackingXML>
158
+ def build_tracking_request(order_ids, options)
159
+ xml = Builder::XmlMarkup.new :indent => 2
160
+ xml.instruct!
161
+ xml.tag! 'TrackingXML' do
162
+ add_credentials(xml)
163
+
164
+ order_ids.each do |o_id|
165
+ xml.tag! 'Tracking' do
166
+ xml.tag! 'Order', o_id
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ def add_credentials(xml)
173
+ xml.tag! 'CustomerID', @options[:login]
174
+ xml.tag! 'Password', @options[:password]
175
+ end
176
+
177
+ def add_order(xml, order_id, shipping_address, line_items, options)
178
+ xml.tag! 'Order' do
179
+ xml.tag! 'ReferenceNumber', order_id
180
+ xml.tag! 'ShippingInstructions', options[:shipping_method]
181
+ xml.tag! 'Approve', 1
182
+ xml.tag! 'OrderComments', options[:comment] unless options[:comment].blank?
183
+
184
+ add_address(xml, shipping_address, options)
185
+
186
+ Array(line_items).each_with_index do |line_item, index|
187
+ add_item(xml, line_item, index)
188
+ end
189
+ end
190
+ end
191
+
192
+ def add_address(xml, address, options)
193
+ xml.tag! 'Name', address[:name]
194
+ xml.tag! 'Address1', address[:address1]
195
+ xml.tag! 'Address2', address[:address2] unless address[:address2].blank?
196
+ xml.tag! 'Address3', address[:address3] unless address[:address3].blank?
197
+ xml.tag! 'City', address[:city]
198
+ xml.tag! 'State', address[:state]
199
+ xml.tag! 'ZipCode', address[:zip]
200
+ xml.tag! 'Company', address[:company]
201
+
202
+ unless address[:country].blank?
203
+ country = ActiveUtils::Country.find(address[:country])
204
+ xml.tag! 'Country', country.name
205
+ end
206
+
207
+ xml.tag! 'Phone', address[:phone]
208
+ xml.tag! 'Email', options[:email] unless options[:email].blank?
209
+ end
210
+
211
+ def add_item(xml, item, index)
212
+ xml.tag! 'Item' do
213
+ xml.tag! 'ItemID', item[:sku] unless item[:sku].blank?
214
+ xml.tag! 'ItemQty', item[:quantity] unless item[:quantity].blank?
215
+ end
216
+ end
217
+
218
+ def commit(action, request)
219
+ url = test? ? TEST_URLS[action] : SERVICE_URLS[action]
220
+
221
+ data = ssl_post(url, request,
222
+ 'EndPointURL' => url,
223
+ 'Content-Type' => 'text/xml; charset="utf-8"'
224
+ )
225
+
226
+ response = parse_response(action, data)
227
+ Response.new(success?(response), message_from(response), response, :test => test?)
228
+ end
229
+
230
+ def success?(response)
231
+ response[:success] == SUCCESS || response[:success] == DUPLICATE
232
+ end
233
+
234
+ def message_from(response)
235
+ if response[:duplicate]
236
+ DUPLICATE_MESSAGE
237
+ elsif success?(response)
238
+ SUCCESS_MESSAGE
239
+ elsif response[:error_0] == INVALID_LOGIN
240
+ INVALID_LOGIN
241
+ else
242
+ FAILURE_MESSAGE
243
+ end
244
+ end
245
+
246
+ def parse_response(action, xml)
247
+ begin
248
+ document = REXML::Document.new("<response>#{xml}</response>")
249
+ rescue REXML::ParseException
250
+ return {:success => FAILURE}
251
+ end
252
+
253
+ case action
254
+ when :fulfillment
255
+ parse_fulfillment_response(document)
256
+ when :inventory
257
+ parse_inventory_response(document)
258
+ when :tracking
259
+ parse_tracking_response(document)
260
+ else
261
+ raise ArgumentError, "Unknown action #{action}"
262
+ end
263
+ end
264
+
265
+ def parse_fulfillment_response(document)
266
+ response = parse_errors(document)
267
+
268
+ # Check if completed
269
+ if completed = REXML::XPath.first(document, '//Completed')
270
+ completed.elements.each do |e|
271
+ response[e.name.underscore.to_sym] = e.text
272
+ end
273
+ else
274
+ response[:success] = FAILURE
275
+ end
276
+
277
+ response[:duplicate] = response[:success] == DUPLICATE
278
+
279
+ response
280
+ end
281
+
282
+ def parse_inventory_response(document)
283
+ response = parse_errors(document)
284
+ response[:stock_levels] = {}
285
+
286
+ document.root.each_element('//Item') do |node|
287
+ # {ItemID => 'SOME-ID', ItemQty => '101'}
288
+ params = node.elements.to_a.each_with_object({}) {|elem, hash| hash[elem.name] = elem.text}
289
+
290
+ response[:stock_levels][params['ItemID']] = params['ItemQty'].to_i
291
+ end
292
+
293
+ response
294
+ end
295
+
296
+ def parse_tracking_response(document)
297
+ response = parse_errors(document)
298
+ response[:tracking_numbers] = {}
299
+ response[:tracking_companies] = {}
300
+ response[:tracking_urls] = {}
301
+
302
+ document.root.each_element('//Shipment') do |node|
303
+ # {InvoiceNumber => 'SOME-ID', ShipmentTrackingNumber => 'SOME-TRACKING-NUMBER'}
304
+ params = node.elements.to_a.each_with_object({}) {|elem, hash| hash[elem.name] = elem.text}
305
+
306
+ tracking = params['ShipmentTrackingNumber']
307
+
308
+ unless tracking == NOT_SHIPPED
309
+ response[:tracking_numbers][params['InvoiceNumber']] ||= []
310
+ response[:tracking_numbers][params['InvoiceNumber']] << tracking
311
+ end
312
+
313
+ company = params['Method'].split[0] if params['Method']
314
+ if TRACKING_COMPANIES.include? company
315
+ response[:tracking_companies][params['InvoiceNumber']] ||= []
316
+ response[:tracking_companies][params['InvoiceNumber']] << company
317
+ end
318
+ end
319
+
320
+ response
321
+ end
322
+
323
+ def parse_errors(document)
324
+ response = {}
325
+
326
+ REXML::XPath.match(document, "//Errors/Error").to_a.each_with_index do |e, i|
327
+ response["error_#{i}".to_sym] = e.text
328
+ end
329
+
330
+ response[:success] = response.empty? ? SUCCESS : FAILURE
331
+ response
332
+ end
333
+ end
334
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: utf-8
2
+ module ActiveFulfillment
3
+ VERSION = "3.0.0.pre2"
4
+ end
@@ -1,9 +1,10 @@
1
1
  require 'test_helper'
2
2
 
3
- class RemoteAmazonMarketplaceWebservicesTest < Test::Unit::TestCase
3
+ class RemoteAmazonMarketplaceWebservicesTest < Minitest::Test
4
+ include ActiveFulfillment::Test::Fixtures
4
5
 
5
6
  def setup
6
- @service = AmazonMarketplaceWebService.new( fixtures(:amazon_mws) )
7
+ @service = ActiveFulfillment::AmazonMarketplaceWebService.new(fixtures(:amazon_mws))
7
8
 
8
9
  @options = {
9
10
  :shipping_method => 'Standard',
@@ -30,9 +31,9 @@ class RemoteAmazonMarketplaceWebservicesTest < Test::Unit::TestCase
30
31
  end
31
32
 
32
33
  def test_successful_order_submission
33
- response = @service.fulfill(ActiveMerchant::Utils.generate_unique_id, @address, @line_items, @options)
34
+ response = @service.fulfill(SecureRandom.uuid, @address, @line_items, @options)
34
35
  assert response.success?
35
- assert !response.test?
36
+ refute response.test?
36
37
  end
37
38
 
38
39
  def test_order_multiple_line_items
@@ -41,17 +42,17 @@ class RemoteAmazonMarketplaceWebservicesTest < Test::Unit::TestCase
41
42
  :quantity => 2
42
43
  })
43
44
 
44
- response = @service.fulfill(ActiveMerchant::Utils.generate_unique_id, @address, @line_items, @options)
45
+ response = @service.fulfill(SecureRandom.uuid, @address, @line_items, @options)
45
46
  assert response.success?
46
47
  end
47
48
 
48
49
  def test_invalid_credentials_during_fulfillment
49
- service = AmazonMarketplaceWebService.new(
50
+ service = ActiveFulfillment::AmazonMarketplaceWebService.new(
50
51
  :login => 'y',
51
52
  :password => 'p',
52
53
  :seller_id => 'o')
53
54
 
54
- response = service.fulfill(ActiveMerchant::Utils.generate_unique_id, @address, @line_items, @options)
55
+ response = service.fulfill(SecureRandom.uuid, @address, @line_items, @options)
55
56
  assert !response.success?
56
57
 
57
58
  assert_equal "InvalidAccessKeyId: The AWS Access Key Id you provided does not exist in our records.", response.response_comment
@@ -98,23 +99,25 @@ class RemoteAmazonMarketplaceWebservicesTest < Test::Unit::TestCase
98
99
  end
99
100
 
100
101
  def test_invalid_credentials
101
- service = AmazonMarketplaceWebService.new(
102
+ service = ActiveFulfillment::AmazonMarketplaceWebService.new(
102
103
  :login => 'your@email.com',
103
- :password => 'password',
104
+ :password => 'wrong',
104
105
  :seller_id => 'SellerNumber1')
105
- assert !service.valid_credentials?
106
+ refute service.valid_credentials?
106
107
  end
107
108
 
108
- def test_get_status_does_not_require_valid_credentials
109
- service = AmazonMarketplaceWebService.new(
110
- :login => 'your@email.com',
111
- :password => 'password')
112
- response = service.status
109
+ def test_get_status
110
+ response = @service.status
113
111
  assert response.success?
114
112
  end
115
113
 
116
- def test_get_status
117
- service = AmazonMarketplaceWebService.new(fixtures(:amazon))
114
+ def test_get_status_does_not_require_valid_credentials
115
+ service = ActiveFulfillment::AmazonMarketplaceWebService.new(
116
+ :login => 'your@email.com',
117
+ :password => 'wrong',
118
+ :seller_id => 'SellerNumber1'
119
+ )
120
+
118
121
  response = service.status
119
122
  assert response.success?
120
123
  end
@@ -0,0 +1,77 @@
1
+ require 'test_helper'
2
+
3
+ class RemoteJamesAndJamesTest < Minitest::Test
4
+ include ActiveFulfillment::Test::Fixtures
5
+
6
+ def setup
7
+ ActiveFulfillment::Base.mode = :test
8
+
9
+ @service = ActiveFulfillment::JamesAndJamesService.new(fixtures(:james_and_james))
10
+
11
+ @options = {
12
+ shipping_method: 'Ground',
13
+ email: 'buyer@jadedpallet.com'
14
+ }
15
+
16
+ @address = {
17
+ name: 'Fred Brooks',
18
+ address1: '1234 Penny Lane',
19
+ city: 'Jonsetown',
20
+ state: 'NC',
21
+ country: 'US',
22
+ zip: '23456'
23
+ }
24
+
25
+ @line_items = [
26
+ {
27
+ sku: 'SBLK8',
28
+ quantity: 2,
29
+ price: 10
30
+ }
31
+ ]
32
+
33
+ end
34
+
35
+ def test_successful_order_submission
36
+ @options[:billing_address] = @address
37
+ response = @service.fulfill('123456', @address, @line_items, @options)
38
+ assert response.success?
39
+ assert response.test?
40
+ end
41
+
42
+ def test_order_multiple_line_items
43
+ @line_items.push({
44
+ sku: 'SWHT8',
45
+ quantity: 3,
46
+ price: 10
47
+ })
48
+ @options[:billing_address] = @address
49
+ response = @service.fulfill('123456', @address, @line_items, @options)
50
+ assert response.success?
51
+ assert response.test?
52
+ end
53
+
54
+ def test_invalid_sku_during_fulfillment
55
+ line_items = [{sku: 'invalid', quantity: 1}]
56
+ @options[:billing_address] = @address
57
+ response = @service.fulfill('123456', @address, line_items, @options)
58
+ assert !response.success?
59
+ assert response.test?
60
+ end
61
+
62
+ def test_invalid_credentials_during_fulfillment
63
+ service = ActiveFulfillment::JamesAndJamesService.new(subdomain: 'test', key: 'test')
64
+ @options[:billing_address] = @address
65
+ response = service.fulfill('123456', @address, @line_items, @options)
66
+ refute response.success?
67
+ assert_equal "Not Found", response.message
68
+ end
69
+
70
+ def test_get_inventory
71
+ response = @service.fetch_stock_levels
72
+ assert response.success?
73
+ assert response.test?
74
+ assert_equal 99, response.stock['SBLK8']
75
+ end
76
+
77
+ end