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 +4 -4
- data/Gemfile.lock +7 -7
- data/VERSION +1 -1
- data/lib/paypal_express/api.rb +95 -27
- data/lib/paypal_express/models/response.rb +66 -0
- data/lib/paypal_express/private_api.rb +30 -0
- data/pom.xml +1 -1
- data/spec/paypal_express/remote/hpp_spec.rb +104 -0
- data/spec/paypal_express/remote/hpp_spec_helpers.rb +35 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d00219df8659d8d04add7832192638b8cc94388
|
4
|
+
data.tar.gz: ae0902eee81f58d4bc5fe7c3353f9d1bfcb7c628
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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.
|
86
|
-
killbill (8.3.
|
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.
|
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.
|
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.
|
160
|
+
1.14.3
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
5.0.
|
1
|
+
5.0.4
|
data/lib/paypal_express/api.rb
CHANGED
@@ -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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
-
|
99
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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.
|
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.
|
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-
|
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
|