killbill-cybersource 5.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae2d49fdb4fd4bbe3b9be5e7b79ee0b14e12837a
4
- data.tar.gz: 85d673ad015325da80051feb7bcaf67bbbcf243a
3
+ metadata.gz: 0156e88d591e65a124e91d54707a6c35058e7cf4
4
+ data.tar.gz: 69163de4f9aa3c74d5325a6c561abab2f8e9efc3
5
5
  SHA512:
6
- metadata.gz: b69a139a422956d25ee6651d97e8504a87334d9d405244e74400754de906ffe12df6016363e7c6d8fb9085fe6dcbd98f7f493ef8cb37010ea305e454a243a47e
7
- data.tar.gz: b33fa00be1629c68fa7233108180eabb9dd2e363cd80a2e11a7d1e4fbea8f7fc66281ff3bad33a8d33cb2b743e90c8dbf0f7e6dab23157d21a562fdcdc6c9884
6
+ metadata.gz: c505cfb2f367215a4ec6b42fcc8edb5d33da5732cb9392bb5d862eb45b6f841e648c68fc572bff89b216c52ae169da79efeef80935d4d5b7763e7b2b4b05709c
7
+ data.tar.gz: 8d502c587dfc6a4fd41d28813e92bcc35875d85e68e7ffd8a545df043a0a51aa696716414dd51e4a8bdeee30dd1b49bac8968598671bdf1d7a844257fada10ad
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- killbill-cybersource (5.1.0)
4
+ killbill-cybersource (5.2.0)
5
5
  actionpack (~> 4.1.0)
6
6
  actionview (~> 4.1.0)
7
7
  activemerchant (~> 1.48.0)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 5.1.0
1
+ 5.2.0
@@ -134,6 +134,8 @@ module Killbill #:nodoc:
134
134
  # authorization is very likely nil, as we didn't get an answer from the gateway in the first place
135
135
  order_id ||= authorization.split(';')[0] unless authorization.nil?
136
136
 
137
+ existing_request_ids = transaction_info_plugins.map{|trx_info| trx_info.first_payment_reference_id}.compact
138
+
137
139
  stale = false
138
140
  transaction_info_plugins.each do |transaction_info_plugin|
139
141
  # We only need to fix the UNDEFINED ones
@@ -171,7 +173,7 @@ module Killbill #:nodoc:
171
173
 
172
174
  threshold = (Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :cancel_threshold) || ONE_DAY_AGO).to_i
173
175
  should_cancel_payment = delay_since_transaction >= threshold
174
- if report.empty? && !should_cancel_payment
176
+ if (report.empty? || report_not_match(report, transaction_info_plugin.first_payment_reference_id, existing_request_ids)) && !should_cancel_payment
175
177
  # We'll retry later
176
178
  logger.info("Unable to fix UNDEFINED kb_transaction_id='#{transaction_info_plugin.kb_transaction_payment_id}' (not found in CyberSource)")
177
179
  next
@@ -445,6 +447,11 @@ module Killbill #:nodoc:
445
447
  # We might want a 'util' function to make the conversion Joda DateTime to a Ruby Time object
446
448
  Time.parse(@clock.get_clock.get_utc_now.to_s)
447
449
  end
450
+
451
+ def report_not_match(report, request_id, existing_request_ids)
452
+ # Check if the response's request id is the request_id of a previous request. If so, then this report does not match.
453
+ report.request_id.nil? || (request_id != report.request_id && existing_request_ids.include?(report.request_id))
454
+ end
448
455
  end
449
456
  end
450
457
  end
@@ -94,6 +94,10 @@ module Killbill #:nodoc:
94
94
  @response.params['merchantReferenceCode'].nil?
95
95
  end
96
96
 
97
+ def request_id
98
+ @response.params['requestID']
99
+ end
100
+
97
101
  private
98
102
 
99
103
  def parse
data/pom.xml CHANGED
@@ -25,7 +25,7 @@
25
25
  <groupId>org.kill-bill.billing.plugin.ruby</groupId>
26
26
  <artifactId>cybersource-plugin</artifactId>
27
27
  <packaging>pom</packaging>
28
- <version>5.1.0</version>
28
+ <version>5.2.0</version>
29
29
  <name>cybersource-plugin</name>
30
30
  <url>http://github.com/killbill/killbill-cybersource-plugin</url>
31
31
  <description>Plugin for accessing Cybersource as a payment gateway</description>
@@ -266,7 +266,7 @@ describe Killbill::Cybersource::PaymentPlugin do
266
266
  fix_transaction(0) if with_report_api
267
267
 
268
268
  # Compare the state of the old and new response
269
- check_old_new_response(response, :PURCHASE, 0, initial_auth)
269
+ check_old_new_response(response, :PURCHASE, 0, initial_auth, payment_response.first_payment_reference_id)
270
270
 
271
271
  break unless with_report_api
272
272
 
@@ -280,14 +280,72 @@ describe Killbill::Cybersource::PaymentPlugin do
280
280
  fix_transaction(1)
281
281
 
282
282
  # Compare the state of the old and new response
283
- check_old_new_response(response, :REFUND, 1, initial_auth)
283
+ check_old_new_response(response, :REFUND, 1, initial_auth, refund_response.first_payment_reference_id)
284
+ end
285
+
286
+ it 'should fix UNDEFINED captures' do
287
+ @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
288
+ payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
289
+ check_response(payment_response, @amount, :CAPTURE, :PROCESSED, 'Successful transaction', '100')
290
+
291
+ # Force a transition to :UNDEFINED
292
+ response, initial_auth = transition_last_response_to_UNDEFINED(2)
293
+
294
+ # Skip if the report API isn't configured
295
+ fix_transaction(1) if with_report_api
296
+
297
+ # Compare the state of the old and new response
298
+ check_old_new_response(response, :CAPTURE, 1, initial_auth, payment_response.first_payment_reference_id)
299
+
300
+ break unless with_report_api
301
+
302
+ # Try a full refund
303
+ refund_response = @plugin.refund_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
304
+ check_response(refund_response, @amount, :REFUND, :PROCESSED, 'Successful transaction', '100')
305
+ end
306
+
307
+ it 'should not fix UNDEFINED captures if the report only covers the previous request' do
308
+ @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
309
+
310
+ # Skip gw call so that on_demand report api won't return a record for this call
311
+ skip_gw = Killbill::Plugin::Model::PluginProperty.new
312
+ skip_gw.key = 'skip_gw'
313
+ skip_gw.value = 'true'
314
+ properties_with_skip_gw = @properties.clone
315
+ properties_with_skip_gw << skip_gw
316
+ @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, properties_with_skip_gw, @call_context)
317
+
318
+ # Force a transition to :UNDEFINED
319
+ transition_last_response_to_UNDEFINED(2)
320
+
321
+ # Shouldn't be able to fix the capture because it skipped the gateway call
322
+ fix_transaction(1, :UNDEFINED) if with_report_api
323
+ end
324
+
325
+ it 'should not fix UNDEFINED refunds if the report only covers the previous requests' do
326
+ @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
327
+ @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
328
+
329
+ # Skip gw call so that on_demand report api won't return a record for this call
330
+ skip_gw = Killbill::Plugin::Model::PluginProperty.new
331
+ skip_gw.key = 'skip_gw'
332
+ skip_gw.value = 'true'
333
+ properties_with_skip_gw = @properties.clone
334
+ properties_with_skip_gw << skip_gw
335
+ @plugin.refund_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, properties_with_skip_gw, @call_context)
336
+
337
+ # Force a transition to :UNDEFINED
338
+ transition_last_response_to_UNDEFINED(3)
339
+
340
+ # Shouldn't be able to fix the capture because it skipped the gateway call
341
+ fix_transaction(2, :UNDEFINED) if with_report_api
284
342
  end
285
343
 
286
344
  def transition_last_response_to_UNDEFINED(expected_nb_transactions)
287
345
  Killbill::Cybersource::CybersourceTransaction.last.delete
288
346
  response = Killbill::Cybersource::CybersourceResponse.last
289
347
  initial_auth = response.authorization
290
- response.update(:authorization => nil, :message => {:payment_plugin_status => 'UNDEFINED'}.to_json)
348
+ response.update(:authorization => nil, :params_request_id => nil, :message => {:payment_plugin_status => 'UNDEFINED'}.to_json)
291
349
 
292
350
  skip_gw = Killbill::Plugin::Model::PluginProperty.new
293
351
  skip_gw.key = 'skip_gw'
@@ -303,7 +361,7 @@ describe Killbill::Cybersource::PaymentPlugin do
303
361
  [response, initial_auth]
304
362
  end
305
363
 
306
- def fix_transaction(transaction_nb)
364
+ def fix_transaction(transaction_nb, expected_state=:PROCESSED)
307
365
  # The report API can be delayed
308
366
  await do
309
367
  !@plugin.get_single_transaction_report(report_api, @kb_payment.transactions[0].id, Time.now.utc).empty? ||
@@ -323,7 +381,7 @@ describe Killbill::Cybersource::PaymentPlugin do
323
381
  properties_with_janitor_delay_threshold << janitor_delay_threshold
324
382
  transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_janitor_delay_threshold, @call_context)
325
383
  transaction_info_plugins.size.should == transaction_nb + 1
326
- transaction_info_plugins.last.status.should eq(:PROCESSED)
384
+ transaction_info_plugins.last.status.should eq(expected_state)
327
385
 
328
386
  # Set skip_gw=true, to check the local state
329
387
  skip_gw = Killbill::Plugin::Model::PluginProperty.new
@@ -333,10 +391,10 @@ describe Killbill::Cybersource::PaymentPlugin do
333
391
  properties_with_skip_gw << skip_gw
334
392
  transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_skip_gw, @call_context)
335
393
  transaction_info_plugins.size.should == transaction_nb + 1
336
- transaction_info_plugins.last.status.should eq(:PROCESSED)
394
+ transaction_info_plugins.last.status.should eq(expected_state)
337
395
  end
338
396
 
339
- def check_old_new_response(response, transaction_type, transaction_nb, initial_auth)
397
+ def check_old_new_response(response, transaction_type, transaction_nb, initial_auth, request_id)
340
398
  new_response = Killbill::Cybersource::CybersourceResponse.last
341
399
  new_response.id.should == response.id
342
400
  new_response.api_call.should == transaction_type.to_s.downcase
@@ -354,12 +412,13 @@ describe Killbill::Cybersource::PaymentPlugin do
354
412
  new_response.params_request_token.should == response.params_request_token
355
413
  new_response.params_currency.should == response.params_currency
356
414
  new_response.params_amount.should == response.params_amount
357
- new_response.params_authorization_code.should == response.params_authorization_code
358
- new_response.params_avs_code.should == response.params_avs_code
359
- new_response.params_avs_code_raw.should == response.params_avs_code_raw
415
+ new_response.params_authorization_code.should == response.params_authorization_code unless response.params_authorization_code.nil?
416
+ new_response.params_avs_code.should == response.params_avs_code unless response.params_avs_code.nil?
417
+ new_response.params_avs_code_raw.should == response.params_avs_code_raw unless response.params_avs_code.nil?
360
418
  new_response.params_reconciliation_id.should == response.params_reconciliation_id
361
419
  new_response.success.should be_true
362
420
  new_response.message.should == (with_report_api ? 'Request was processed successfully.' : '{"payment_plugin_status":"UNDEFINED"}')
421
+ new_response.params_request_id.should == request_id if with_report_api
363
422
  end
364
423
  end
365
424
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: killbill-cybersource
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kill Bill core team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-10 00:00:00.000000000 Z
11
+ date: 2017-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement