killbill-paypal-express 5.0.3 → 5.0.4

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.
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