killbill-paypal-express 5.0.3 → 5.0.4

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: 588915d1b5f301d56b925a8c75f5f643c2725562
4
- data.tar.gz: c0025ed6f693a9f726645ca22f368d396457ef07
3
+ metadata.gz: 5d00219df8659d8d04add7832192638b8cc94388
4
+ data.tar.gz: ae0902eee81f58d4bc5fe7c3353f9d1bfcb7c628
5
5
  SHA512:
6
- metadata.gz: 9717c0e506aa81b724132330923b2c4778335482ecce4a7f3c1f3f05387598401ba8ad63a196408a1a393fa7e5a2cf8e6861f0090bdc7f4dfc6255f621871fd3
7
- data.tar.gz: 2428403edb96d25c5e373f762e2dd013eb464bd0f6765df1e89b2952984bed239ce3c5062888636fc19fc1a3f6ec6d4e2653964d8d4ac0d9d2045952fb46ee4e
6
+ metadata.gz: f3e647b46904500a810148b4a631a065efe737f3653a84106cb6330883b794c46ed7398d241fadde9c2ec18a7565371cde185e0fdb236c278fb8e9fafb75f8a1
7
+ data.tar.gz: 1a4a5610a2fca9f7b1b6fd23daf5a1cc9e96342c3d54c2945aae3f840d2ad0dbcfb6454f43ee6752a7e9aab76c7174c3ccb3473e72d884c4e74f1af05a1c18d3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- killbill-paypal-express (5.0.3)
4
+ killbill-paypal-express (5.0.4)
5
5
  actionpack (~> 4.1.0)
6
6
  actionview (~> 4.1.0)
7
7
  activemerchant (~> 1.53.0)
@@ -57,7 +57,7 @@ GEM
57
57
  descendants_tracker (~> 0.0.4)
58
58
  ice_nine (~> 0.11.0)
59
59
  thread_safe (~> 0.3, >= 0.3.1)
60
- builder (3.2.2)
60
+ builder (3.2.3)
61
61
  childprocess (0.5.9)
62
62
  ffi (~> 1.0, >= 1.0.11)
63
63
  coercible (1.0.0)
@@ -82,20 +82,20 @@ GEM
82
82
  jdbc-postgres (9.4.1206)
83
83
  jdbc-sqlite3 (3.8.11.2)
84
84
  jruby-openssl (0.9.18-java)
85
- json (1.8.3-java)
86
- killbill (8.3.0)
85
+ json (1.8.6-java)
86
+ killbill (8.3.1)
87
87
  rack (>= 1.5.2)
88
88
  sinatra (~> 1.3.4)
89
89
  typhoeus (~> 0.6.9)
90
90
  tzinfo (~> 1.2.0)
91
91
  maven-tools (1.1.6)
92
92
  virtus (~> 1.0)
93
- minitest (5.9.1)
93
+ minitest (5.10.1)
94
94
  monetize (1.1.0)
95
95
  money (~> 6.5.0)
96
96
  money (6.5.1)
97
97
  i18n (>= 0.6.4, <= 0.7.0)
98
- nokogiri (1.6.8.1-java)
98
+ nokogiri (1.7.0.1-java)
99
99
  offsite_payments (2.1.0)
100
100
  actionpack (>= 3.2.20, < 5.0.0)
101
101
  active_utils (~> 3.0.0)
@@ -157,4 +157,4 @@ DEPENDENCIES
157
157
  selenium-webdriver (~> 2.53.0)
158
158
 
159
159
  BUNDLED WITH
160
- 1.11.2
160
+ 1.14.3
data/VERSION CHANGED
@@ -1 +1 @@
1
- 5.0.3
1
+ 5.0.4
@@ -3,6 +3,7 @@ module Killbill #:nodoc:
3
3
  class PaymentPlugin < ::Killbill::Plugin::ActiveMerchant::PaymentPlugin
4
4
 
5
5
  THREE_HOURS_AGO = (3*3600)
6
+ FIVE_MINUTES_AGO = 300
6
7
 
7
8
  def initialize
8
9
  gateway_builder = Proc.new do |config|
@@ -84,37 +85,32 @@ module Killbill #:nodoc:
84
85
  end
85
86
 
86
87
  def get_payment_info(kb_account_id, kb_payment_id, properties, context)
87
- ignored_api_calls = [:details_for]
88
- responses = @response_model.from_kb_payment_id(@transaction_model, kb_payment_id, context.tenant_id)
89
- responses = responses.reject do |response|
90
- ignored_api_calls.include?(response.api_call.to_sym)
91
- end
92
- t_info_plugins = responses.collect do |response|
93
- response.to_transaction_info_plugin(response.send("#{@identifier}_transaction"))
88
+ filtered_plugin_info, plugin_info, with_only_pending_trx = get_raw_payment_info(kb_payment_id, context)
89
+
90
+ return filtered_plugin_info if filtered_plugin_info.empty?
91
+
92
+ options = properties_to_hash(properties)
93
+ # We won't be in a state where we have both a pending and unknown plugin infos; so we just return here.
94
+ if fix_unknown_transactions(kb_payment_id, plugin_info, options, kb_account_id, context) ||
95
+ cancel_pending_transactions(filtered_plugin_info, with_only_pending_trx)
96
+ return get_raw_payment_info(kb_payment_id, context)[0]
94
97
  end
95
- # Should never happen...
96
- return [] if t_info_plugins.nil?
97
98
 
98
- # Completed purchases/authorizations will have two rows in the responses table (one for api_call 'build_form_descriptor', one for api_call 'purchase/authorize')
99
- # Other transaction types don't support the :PENDING state
100
- target_transaction_types = [:PURCHASE, :AUTHORIZE]
101
- only_pending_transaction = t_info_plugins.find { |t_info_plugin| target_transaction_types.include?(t_info_plugin.transaction_type) && t_info_plugin.status != :PENDING }.nil?
102
- t_info_plugins_without_pending = t_info_plugins.reject { |t_info_plugin| target_transaction_types.include?(t_info_plugin.transaction_type) && t_info_plugin.status == :PENDING }
99
+ filtered_plugin_info
100
+ end
103
101
 
104
- # If its token has expired, cancel the payment and update the response row.
105
- if only_pending_transaction
106
- return t_info_plugins unless token_expired(t_info_plugins.last)
107
- begin
108
- cancel_pending_transaction(t_info_plugins.last).nil?
109
- logger.info("Cancel pending kb_payment_id='#{t_info_plugins.last.kb_payment_id}', kb_payment_transaction_id='#{t_info_plugins.last.kb_transaction_payment_id}'")
110
- super(kb_account_id, kb_payment_id, properties, context)
111
- rescue => e
112
- logger.warn("Unexpected exception while canceling pending kb_payment_id='#{t_info_plugins.last.kb_payment_id}', kb_payment_transaction_id='#{t_info_plugins.last.kb_transaction_payment_id}': #{e.message}\n#{e.backtrace.join("\n")}")
113
- t_info_plugins
114
- end
115
- else
116
- t_info_plugins_without_pending
102
+ def cancel_pending_transactions(t_info_plugins, only_pending_trx)
103
+ return false unless only_pending_trx && token_expired(t_info_plugins.last)
104
+
105
+ begin
106
+ cancel_pending_transaction(t_info_plugins.last).nil?
107
+ logger.info("Cancel pending kb_payment_id='#{t_info_plugins.last.kb_payment_id}', kb_payment_transaction_id='#{t_info_plugins.last.kb_transaction_payment_id}'")
108
+ return true
109
+ rescue => e
110
+ logger.warn("Unexpected exception while canceling pending kb_payment_id='#{t_info_plugins.last.kb_payment_id}', kb_payment_transaction_id='#{t_info_plugins.last.kb_transaction_payment_id}': #{e.message}\n#{e.backtrace.join("\n")}")
117
111
  end
112
+
113
+ false
118
114
  end
119
115
 
120
116
  def search_payments(search_key, offset, limit, properties, context)
@@ -558,6 +554,78 @@ module Killbill #:nodoc:
558
554
  end
559
555
  sub_hash.empty? ? nil : sub_hash
560
556
  end
557
+
558
+ def fix_unknown_transactions(payment_id, trx_plugin_info, options, kb_account_id, context)
559
+ unknown_transactions_info = trx_plugin_info.find_all { |t_info_plugin| t_info_plugin.status == :UNDEFINED }
560
+ now = Time.parse(@clock.get_clock.get_utc_now.to_s)
561
+
562
+ token = trx_plugin_info.map {|plugin_info| find_value_from_properties(plugin_info.properties, 'authorization')}.find {|token| !token.blank?}
563
+ if token.nil?
564
+ logger.warn("Unable to fix UNDEFINED kb_payment_id='#{payment_id}'. Unable to find its token.")
565
+ return false
566
+ end
567
+
568
+ need_refresh = false
569
+ payment_processor_account_id = find_payment_processor_id_from_initial_call(kb_account_id, context.tenant_id, token) || :default
570
+ unknown_transactions_info.each do |unknown_trx_info|
571
+ delay_since_transaction = now - unknown_trx_info.created_date
572
+ delay_since_transaction = 0 if delay_since_transaction < 0
573
+
574
+ # Do nothing before the delayed checking time
575
+ janitor_delay_threshold = (Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :janitor_delay_threshold) || FIVE_MINUTES_AGO).to_i
576
+ next unless delay_since_transaction >= janitor_delay_threshold
577
+
578
+ paypal_response_id = find_value_from_properties(unknown_trx_info.properties, 'paypalExpressResponseId')
579
+ if paypal_response_id.nil?
580
+ logger.warn("Unable to fix UNDEFINED kb_transaction_id='#{unknown_trx_info.kb_transaction_payment_id}' (paypal_response_id not specified)")
581
+ next
582
+ end
583
+ response = PaypalExpressResponse.find_by(:id => paypal_response_id)
584
+
585
+ fixed = false
586
+ begin
587
+ gateway = lookup_gateway(payment_processor_account_id, context.tenant_id)
588
+ fixed = @private_api.fix_unknown_transaction(response, unknown_trx_info, gateway, kb_account_id, context.tenant_id)
589
+ logger.info("Unable to fix UNDEFINED kb_transaction_id='#{unknown_trx_info.kb_transaction_payment_id}' (not found in PayPal)") unless fixed
590
+ rescue => e
591
+ logger.warn("Unable to fix UNDEFINED kb_transaction_id='#{unknown_trx_info.kb_transaction_payment_id}': #{e.message}\n#{e.backtrace.join("\n")}")
592
+ end
593
+
594
+ if !fixed
595
+ # hard expiration limit
596
+ janitor_cancellation_threshold = (Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :cancel_threshold) || THREE_HOURS_AGO).to_i
597
+ if delay_since_transaction >= janitor_cancellation_threshold
598
+ response.transition_to_plugin_failure
599
+ logger.info("Expire UNDEFINED kb_transaction_id='#{unknown_trx_info.kb_transaction_payment_id}' to CANCELED")
600
+ need_refresh = true
601
+ end
602
+ else
603
+ need_refresh = true
604
+ end
605
+ end
606
+
607
+ need_refresh
608
+ end
609
+
610
+ def get_raw_payment_info(kb_payment_id, context)
611
+ ignored_api_calls = [:details_for]
612
+ responses = @response_model.from_kb_payment_id(@transaction_model, kb_payment_id, context.tenant_id)
613
+ responses = responses.reject do |response|
614
+ ignored_api_calls.include?(response.api_call.to_sym)
615
+ end
616
+ t_info_plugins = responses.collect do |response|
617
+ response.to_transaction_info_plugin(response.send("#{@identifier}_transaction"))
618
+ end
619
+
620
+ # Completed purchases/authorizations will have two rows in the responses table (one for api_call 'build_form_descriptor', one for api_call 'purchase/authorize')
621
+ # Other transaction types don't support the :PENDING state
622
+ target_transaction_types = [:PURCHASE, :AUTHORIZE]
623
+ with_only_pending_trx = t_info_plugins.find { |t_info_plugin| target_transaction_types.include?(t_info_plugin.transaction_type) && t_info_plugin.status != :PENDING }.nil?
624
+
625
+ # Filter out the pending transaction if there is already a response tied with the same transaction but indicating a final state
626
+ t_info_plugins_without_pending = t_info_plugins.reject { |t_info_plugin| target_transaction_types.include?(t_info_plugin.transaction_type) && t_info_plugin.status == :PENDING }
627
+ [with_only_pending_trx ? t_info_plugins : t_info_plugins_without_pending, t_info_plugins, with_only_pending_trx]
628
+ end
561
629
  end
562
630
  end
563
631
  end
@@ -146,6 +146,72 @@ module Killbill #:nodoc:
146
146
 
147
147
  t_info_plugin
148
148
  end
149
+
150
+ def transition_to_plugin_failure
151
+ transition_to_failure
152
+ end
153
+
154
+ def transition_to_payment_failure(transaction_id)
155
+ transition_to_failure false, {:authorization => transaction_id}
156
+ end
157
+
158
+ def transition_to_failure(is_plugin_failure = true, params = {})
159
+ begin
160
+ error_details = JSON.parse(message)
161
+ original_message = nil
162
+ rescue
163
+ error_details = {}
164
+ original_message = message
165
+ end
166
+ error_details['original_message'] = original_message unless original_message.blank?
167
+ error_details['payment_plugin_status'] = is_plugin_failure ? 'CANCELED' : 'ERROR'
168
+
169
+ updated_attributes = {
170
+ :message => error_details.to_json,
171
+ :success => false,
172
+ :updated_at => Time.now.utc
173
+ }.merge!(params)
174
+
175
+ # Update the response row
176
+ update!(updated_attributes)
177
+ end
178
+
179
+ def transition_to_success(transaction_id, trx_plugin_info)
180
+ begin
181
+ new_message = JSON.parse(message)
182
+ original_message = nil
183
+ rescue
184
+ new_message = {}
185
+ original_message = message
186
+ end
187
+ new_message['original_message'] = original_message unless original_message.blank?
188
+ new_message['payment_plugin_status'] = 'PROCESSED'
189
+ new_message['janitor'] = 'Janitor transitioned the response to success'
190
+
191
+ updated_attributes = {
192
+ :message => new_message.to_json,
193
+ :authorization => transaction_id,
194
+ :success => true,
195
+ :updated_at => Time.now.utc
196
+ }
197
+
198
+ # Update the response row
199
+ update!(updated_attributes)
200
+
201
+ # Create the transaction row if needed (cannot have been created before or the state wouldn't have been UNDEFINED)
202
+ build_paypal_express_transaction(:kb_account_id => kb_account_id,
203
+ :kb_tenant_id => kb_tenant_id,
204
+ :amount_in_cents => trx_plugin_info.amount,
205
+ :currency => trx_plugin_info.currency,
206
+ :api_call => api_call,
207
+ :kb_payment_id => kb_payment_id,
208
+ :kb_payment_transaction_id => kb_payment_transaction_id,
209
+ :transaction_type => transaction_type,
210
+ :payment_processor_account_id => payment_processor_account_id,
211
+ :txn_id => txn_id,
212
+ :created_at => updated_at,
213
+ :updated_at => updated_at).save!
214
+ end
149
215
  end
150
216
  end
151
217
  end
@@ -1,6 +1,12 @@
1
1
  module Killbill #:nodoc:
2
2
  module PaypalExpress #:nodoc:
3
3
  class PrivatePaymentPlugin < ::Killbill::Plugin::ActiveMerchant::PrivatePaymentPlugin
4
+
5
+ ONE_HOUR_AGO = 3600
6
+ STATUS = {:CAPTURE => {:success_status => 'Completed', :type => 'Payment'},
7
+ :AUTHORIZE => {:success_status => 'Pending', :type => 'Authorization'},
8
+ :REFUND => {:success_status => 'Completed', :type => 'Refund'}}
9
+
4
10
  def initialize(session = {})
5
11
  super(:paypal_express,
6
12
  ::Killbill::PaypalExpress::PaypalExpressPaymentMethod,
@@ -42,6 +48,30 @@ module Killbill #:nodoc:
42
48
  context = kb_apis.create_context(kb_tenant_id)
43
49
  kb_account_ids.map {|id| kb_apis.account_user_api.get_account_by_id(id, context).external_key }
44
50
  end
51
+
52
+ def fix_unknown_transaction(plugin_response, trx_plugin_info, gateway, kb_account_id, kb_tenant_id)
53
+ status, transaction_id, type = search_transaction(trx_plugin_info.created_date - ONE_HOUR_AGO,
54
+ trx_plugin_info.amount,
55
+ trx_plugin_info.currency,
56
+ gateway,
57
+ trx_plugin_info.kb_transaction_payment_id)
58
+ return false if status.blank? || transaction_id.blank? || type.blank?
59
+
60
+ if type == STATUS[trx_plugin_info.transaction_type][:type] &&
61
+ status == STATUS[trx_plugin_info.transaction_type][:success_status]
62
+ plugin_response.transition_to_success transaction_id, trx_plugin_info
63
+ logger.info("Fixed UNDEFINED kb_transaction_id='#{trx_plugin_info.kb_transaction_payment_id}' to PROCESSED")
64
+ return true
65
+ end
66
+
67
+ false
68
+ end
69
+
70
+ def search_transaction(start_time, amount, currency, gateway, kb_payment_transaction_id)
71
+ options = {:start_date => start_time, :invoice_id => kb_payment_transaction_id, :amount => amount, :currency => currency}
72
+ response = gateway.transaction_search options
73
+ [response.params['status'], response.authorization, response.params['type']]
74
+ end
45
75
  end
46
76
  end
47
77
  end
data/pom.xml CHANGED
@@ -26,7 +26,7 @@
26
26
  <groupId>org.kill-bill.billing.plugin.ruby</groupId>
27
27
  <artifactId>paypal-express-plugin</artifactId>
28
28
  <packaging>pom</packaging>
29
- <version>5.0.3</version>
29
+ <version>5.0.4</version>
30
30
  <name>paypal-express-plugin</name>
31
31
  <url>http://github.com/killbill/killbill-paypal-express-plugin</url>
32
32
  <description>Plugin for accessing Paypal Express Checkout as a payment gateway</description>
@@ -13,6 +13,11 @@ shared_examples 'hpp_spec_common' do
13
13
  @plugin.kb_apis.proxied_services[:payment_api].delete_all_payments
14
14
  end
15
15
 
16
+ it 'should return an empty list of plugin info if payment does not exist' do
17
+ payment_plugin_info = @plugin.get_payment_info(@pm.kb_account_id, SecureRandom.uuid, [], @call_context)
18
+ payment_plugin_info.size.should == 0
19
+ end
20
+
16
21
  it 'should generate forms correctly' do
17
22
  ::Killbill::PaypalExpress::PaypalExpressTransaction.count.should == 0
18
23
  ::Killbill::PaypalExpress::PaypalExpressResponse.count.should == 0
@@ -369,6 +374,105 @@ shared_examples 'hpp_spec_common' do
369
374
  payment_infos[0].gateway_error.should == 'Token expired. Payment Canceled by Janitor.'
370
375
  payment_infos[0].gateway_error_code.should be_nil
371
376
  end
377
+
378
+ it 'should fix the unknown transactions to success' do
379
+ [:AUTHORIZE, :CAPTURE, :REFUND].each do |type|
380
+ payment_external_key = SecureRandom.uuid
381
+ properties = @plugin.hash_to_properties(
382
+ :transaction_external_key => payment_external_key,
383
+ :create_pending_payment => true,
384
+ :payment_processor_account_id => @payment_processor_account_id,
385
+ :auth_mode => true
386
+ )
387
+ form = @plugin.build_form_descriptor(@pm.kb_account_id, @form_fields, properties, @call_context)
388
+ kb_payment_id = validate_form_property(form, 'kb_payment_id')
389
+ kb_trx_id = validate_form_property(form, 'kb_transaction_id')
390
+ validate_token(form)
391
+
392
+ @plugin.authorize_payment(@pm.kb_account_id, kb_payment_id, kb_trx_id, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
393
+ nb_plugin_info = 1
394
+ if type == :AUTHORIZE
395
+ verify_janitor_transition nb_plugin_info, type, :PROCESSED, kb_payment_id
396
+ # Be able to capture
397
+ payment_response = @plugin.capture_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
398
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
399
+ payment_response.amount.should == @amount
400
+ payment_response.transaction_type.should == :CAPTURE
401
+ elsif type == :CAPTURE
402
+ nb_plugin_info = 2
403
+ @plugin.capture_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
404
+ verify_janitor_transition nb_plugin_info, type, :PROCESSED, kb_payment_id
405
+ # Be able to refund
406
+ payment_response = @plugin.refund_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
407
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
408
+ payment_response.amount.should == @amount
409
+ payment_response.transaction_type.should == :REFUND
410
+ elsif type == :REFUND
411
+ nb_plugin_info = 3
412
+ @plugin.capture_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
413
+ @plugin.refund_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
414
+ verify_janitor_transition nb_plugin_info, type, :PROCESSED, kb_payment_id
415
+ end
416
+ end
417
+ end
418
+
419
+ it 'should fix the unknown transactions to plugin failure' do
420
+ [:AUTHORIZE, :CAPTURE, :REFUND].each do |type|
421
+ payment_external_key = SecureRandom.uuid
422
+ properties = @plugin.hash_to_properties(
423
+ :transaction_external_key => payment_external_key,
424
+ :create_pending_payment => true,
425
+ :payment_processor_account_id => @payment_processor_account_id,
426
+ :auth_mode => true
427
+ )
428
+ form = @plugin.build_form_descriptor(@pm.kb_account_id, @form_fields, properties, @call_context)
429
+ kb_payment_id = validate_form_property(form, 'kb_payment_id')
430
+ kb_trx_id = validate_form_property(form, 'kb_transaction_id')
431
+ validate_token(form)
432
+
433
+ properties = @plugin.hash_to_properties({:skip_gw => true})
434
+ @plugin.authorize_payment(@pm.kb_account_id, kb_payment_id, kb_trx_id, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
435
+ nb_plugin_info = 1
436
+ if type == :CAPTURE
437
+ nb_plugin_info = 2
438
+ @plugin.capture_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
439
+ elsif type == :REFUND
440
+ nb_plugin_info = 3
441
+ @plugin.capture_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
442
+ @plugin.refund_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
443
+ end
444
+ verify_janitor_transition nb_plugin_info, type, :CANCELED, kb_payment_id
445
+ end
446
+ end
447
+
448
+ it 'should remain in unknown if cancellation period is not reached' do
449
+ [:AUTHORIZE, :CAPTURE, :REFUND].each do |type|
450
+ payment_external_key = SecureRandom.uuid
451
+ properties = @plugin.hash_to_properties(
452
+ :transaction_external_key => payment_external_key,
453
+ :create_pending_payment => true,
454
+ :payment_processor_account_id => @payment_processor_account_id,
455
+ :auth_mode => true
456
+ )
457
+ form = @plugin.build_form_descriptor(@pm.kb_account_id, @form_fields, properties, @call_context)
458
+ kb_payment_id = validate_form_property(form, 'kb_payment_id')
459
+ kb_trx_id = validate_form_property(form, 'kb_transaction_id')
460
+ validate_token(form)
461
+
462
+ properties = @plugin.hash_to_properties({:skip_gw => true})
463
+ @plugin.authorize_payment(@pm.kb_account_id, kb_payment_id, kb_trx_id, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
464
+ nb_plugin_info = 1
465
+ if type == :CAPTURE
466
+ nb_plugin_info = 2
467
+ @plugin.capture_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
468
+ elsif type == :REFUND
469
+ nb_plugin_info = 3
470
+ @plugin.capture_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
471
+ @plugin.refund_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, properties, @call_context)
472
+ end
473
+ verify_janitor_transition nb_plugin_info, type, :UNDEFINED, kb_payment_id, true, 3600*3
474
+ end
475
+ end
372
476
  end
373
477
 
374
478
  describe Killbill::PaypalExpress::PaymentPlugin do
@@ -312,6 +312,41 @@ module Killbill
312
312
  payment_infos[0].gateway_error_code.should == gateway_error_code
313
313
  end
314
314
 
315
+ def transition_last_response_to_UNDEFINED(expected_nb_transactions, kb_payment_id, delete_last_trx = true)
316
+ Killbill::PaypalExpress::PaypalExpressTransaction.last.delete if delete_last_trx
317
+ response = Killbill::PaypalExpress::PaypalExpressResponse.last
318
+ initial_auth = response.authorization
319
+ response.update(:authorization => nil, :message => {:payment_plugin_status => 'UNDEFINED'}.to_json)
320
+
321
+ skip_gw = Killbill::Plugin::Model::PluginProperty.new
322
+ skip_gw.key = 'skip_gw'
323
+ skip_gw.value = 'true'
324
+ properties_with_skip_gw = [skip_gw]
325
+
326
+ # Set skip_gw=true, to avoid calling the report API
327
+ transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, kb_payment_id, properties_with_skip_gw, @call_context)
328
+ transaction_info_plugins.size.should == expected_nb_transactions
329
+ transaction_info_plugins.last.status.should eq(:UNDEFINED)
330
+
331
+ [response, initial_auth]
332
+ end
333
+
334
+ def verify_janitor_transition(nb_trx_plugin_info, trx_type, trx_status, kb_payment_id, delete_last_trx = true, hard_expiration_date = 0, janitor_delay = 0)
335
+ transition_last_response_to_UNDEFINED(nb_trx_plugin_info, kb_payment_id, delete_last_trx)
336
+ # wait 5 sec for PayPal to populate the record in search endpoint
337
+ sleep 5
338
+ janitor_delay_threshold = Killbill::Plugin::Model::PluginProperty.new
339
+ janitor_delay_threshold.key = 'janitor_delay_threshold'
340
+ janitor_delay_threshold.value = janitor_delay
341
+ cancel_threshold = Killbill::Plugin::Model::PluginProperty.new
342
+ cancel_threshold.key = 'cancel_threshold'
343
+ cancel_threshold.value = hard_expiration_date
344
+ transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, kb_payment_id, [janitor_delay_threshold, cancel_threshold], @call_context)
345
+ transaction_info_plugins.size.should == nb_trx_plugin_info
346
+ transaction_info_plugins.last.status.should eq(trx_status)
347
+ transaction_info_plugins.last.transaction_type.should eq(trx_type)
348
+ end
349
+
315
350
  private
316
351
 
317
352
  def verify_payment_method(kb_account_id = nil)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: killbill-paypal-express
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.3
4
+ version: 5.0.4
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-03-29 00:00:00.000000000 Z
11
+ date: 2017-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement