killbill-paypal-express 4.1.2 → 4.1.3
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 +11 -2
- data/NEWS +4 -0
- data/README.md +2 -1
- data/VERSION +1 -1
- data/killbill-paypal-express.gemspec +1 -0
- data/lib/paypal_express/api.rb +142 -103
- data/lib/paypal_express/models/response.rb +10 -0
- data/pom.xml +1 -1
- data/spec/paypal_express/remote/baid_spec.rb +52 -56
- data/spec/paypal_express/remote/baid_spec_helpers.rb +55 -0
- data/spec/paypal_express/remote/browser_helpers.rb +72 -0
- data/spec/paypal_express/remote/build_plugin_helpers.rb +33 -0
- data/spec/paypal_express/remote/hpp_spec.rb +189 -123
- data/spec/paypal_express/remote/hpp_spec_helpers.rb +364 -0
- data/spec/spec_helper.rb +14 -1
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d005c1bdd9b05742e9898d5fef94c1f72c0eb81
|
4
|
+
data.tar.gz: 683c9b2837efe00ff16d65f62c964b9e46020540
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8c9c42cb7e253e38338107f86efdd8dbc27d762c2590dd7bc5f9718de8e9b1acf3b82c186930d1dd8f85fe1698aec7d7ede4ced070a3a0ea2d37730399f35fb
|
7
|
+
data.tar.gz: 03da6bfa63eaaa3631f48a40c07c99fff32ce0e58ff97a28b67a2bf2166bee83ca0546ab599e1cc91a0e6b8c0ef706631e5c35c5ae2e877b15dce200f8baf447
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
killbill-paypal-express (4.1.
|
4
|
+
killbill-paypal-express (4.1.3)
|
5
5
|
actionpack (~> 4.1.0)
|
6
6
|
actionview (~> 4.1.0)
|
7
7
|
activemerchant (~> 1.53.0)
|
@@ -58,6 +58,8 @@ GEM
|
|
58
58
|
ice_nine (~> 0.11.0)
|
59
59
|
thread_safe (~> 0.3, >= 0.3.1)
|
60
60
|
builder (3.2.2)
|
61
|
+
childprocess (0.5.9)
|
62
|
+
ffi (~> 1.0, >= 1.0.11)
|
61
63
|
coercible (1.0.0)
|
62
64
|
descendants_tracker (~> 0.0.1)
|
63
65
|
descendants_tracker (0.0.4)
|
@@ -65,7 +67,7 @@ GEM
|
|
65
67
|
diff-lcs (1.1.3)
|
66
68
|
equalizer (0.0.11)
|
67
69
|
erubis (2.7.0)
|
68
|
-
ethon (0.
|
70
|
+
ethon (0.9.0)
|
69
71
|
ffi (>= 1.3.0)
|
70
72
|
ffi (1.9.10-java)
|
71
73
|
i18n (0.7.0)
|
@@ -119,6 +121,11 @@ GEM
|
|
119
121
|
ruby-maven (3.3.8)
|
120
122
|
ruby-maven-libs (~> 3.3.1)
|
121
123
|
ruby-maven-libs (3.3.3)
|
124
|
+
rubyzip (1.2.0)
|
125
|
+
selenium-webdriver (2.53.0)
|
126
|
+
childprocess (~> 0.5)
|
127
|
+
rubyzip (~> 1.0)
|
128
|
+
websocket (~> 1.0)
|
122
129
|
sinatra (1.3.6)
|
123
130
|
rack (~> 1.4)
|
124
131
|
rack-protection (~> 1.3)
|
@@ -134,6 +141,7 @@ GEM
|
|
134
141
|
coercible (~> 1.0)
|
135
142
|
descendants_tracker (~> 0.0, >= 0.0.3)
|
136
143
|
equalizer (~> 0.0, >= 0.0.9)
|
144
|
+
websocket (1.2.3)
|
137
145
|
|
138
146
|
PLATFORMS
|
139
147
|
java
|
@@ -146,6 +154,7 @@ DEPENDENCIES
|
|
146
154
|
killbill-paypal-express!
|
147
155
|
rake (>= 10.0.0)
|
148
156
|
rspec (~> 2.12.0)
|
157
|
+
selenium-webdriver (~> 2.53.0)
|
149
158
|
|
150
159
|
BUNDLED WITH
|
151
160
|
1.11.2
|
data/NEWS
CHANGED
data/README.md
CHANGED
@@ -217,4 +217,5 @@ Plugin properties
|
|
217
217
|
| zip | Billing address zip code |
|
218
218
|
| state | Billing address state |
|
219
219
|
| country | Billing address country |
|
220
|
-
| max_amount | Maximum amount parameter (optional) for SetExpressCheckout call |
|
220
|
+
| max_amount | Maximum amount parameter (optional) for SetExpressCheckout call |
|
221
|
+
| auth_mode | If true, [Authorization Payment Action](https://developer.paypal.com/docs/classic/express-checkout/integration-guide/ECRelatedAPIOps/) is adopted. Otherwise, Sale Payment Action is used.|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.1.
|
1
|
+
4.1.3
|
@@ -42,6 +42,7 @@ Gem::Specification.new do |s|
|
|
42
42
|
s.add_development_dependency 'jbundler', '~> 0.9.2'
|
43
43
|
s.add_development_dependency 'rake', '>= 10.0.0'
|
44
44
|
s.add_development_dependency 'rspec', '~> 2.12.0'
|
45
|
+
s.add_development_dependency 'selenium-webdriver', '~>2.53.0'
|
45
46
|
if defined?(JRUBY_VERSION)
|
46
47
|
s.add_development_dependency 'jdbc-sqlite3', '~> 3.7'
|
47
48
|
s.add_development_dependency 'jdbc-mariadb', '~> 1.1'
|
data/lib/paypal_express/api.rb
CHANGED
@@ -29,20 +29,7 @@ module Killbill #:nodoc:
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def authorize_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
32
|
-
|
33
|
-
options = {}
|
34
|
-
|
35
|
-
add_required_options(kb_payment_transaction_id, kb_payment_method_id, context, options)
|
36
|
-
|
37
|
-
properties = merge_properties(properties, options)
|
38
|
-
|
39
|
-
# Can't use default implementation: the authorize signature is for one-off payments only
|
40
|
-
#super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
41
|
-
gateway_call_proc = Proc.new do |gateway, linked_transaction, payment_source, amount_in_cents, options|
|
42
|
-
gateway.authorize_reference_transaction(amount_in_cents, options)
|
43
|
-
end
|
44
|
-
|
45
|
-
dispatch_to_gateways(:authorize, kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context, gateway_call_proc)
|
32
|
+
authorize_or_purchase_payment kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context, true
|
46
33
|
end
|
47
34
|
|
48
35
|
def capture_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
@@ -58,73 +45,8 @@ module Killbill #:nodoc:
|
|
58
45
|
end
|
59
46
|
|
60
47
|
def purchase_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
|
61
|
-
|
62
|
-
|
63
|
-
# Callback from the plugin itself (HPP flow)
|
64
|
-
if find_value_from_properties(properties, 'from_hpp') == 'true'
|
65
|
-
token = find_value_from_properties(properties, 'token')
|
66
|
-
|
67
|
-
response = @response_model.create(:api_call => :build_form_descriptor,
|
68
|
-
:kb_account_id => kb_account_id,
|
69
|
-
:kb_payment_id => kb_payment_id,
|
70
|
-
:kb_payment_transaction_id => kb_payment_transaction_id,
|
71
|
-
:transaction_type => :PURCHASE,
|
72
|
-
:authorization => token,
|
73
|
-
:payment_processor_account_id => payment_processor_account_id,
|
74
|
-
:kb_tenant_id => context.tenant_id,
|
75
|
-
:success => true,
|
76
|
-
:created_at => Time.now.utc,
|
77
|
-
:updated_at => Time.now.utc,
|
78
|
-
:message => { :payment_plugin_status => :PENDING }.to_json)
|
79
|
-
transaction = response.to_transaction_info_plugin(nil)
|
80
|
-
transaction.amount = amount
|
81
|
-
transaction.currency = currency
|
82
|
-
transaction
|
83
|
-
else
|
84
|
-
options = {}
|
85
|
-
add_required_options(kb_payment_transaction_id, kb_payment_method_id, context, options)
|
86
|
-
|
87
|
-
# We have a baid on file
|
88
|
-
if options[:token]
|
89
|
-
gateway_call_proc = Proc.new do |gateway, linked_transaction, payment_source, amount_in_cents, options|
|
90
|
-
# Can't use default implementation: the purchase signature is for one-off payments only
|
91
|
-
gateway.reference_transaction(amount_in_cents, options)
|
92
|
-
end
|
93
|
-
else
|
94
|
-
# One-off payment
|
95
|
-
options[:token] = find_value_from_properties(properties, 'token') || find_last_token(kb_account_id, context.tenant_id)
|
96
|
-
gateway_call_proc = Proc.new do |gateway, linked_transaction, payment_source, amount_in_cents, options|
|
97
|
-
gateway.purchase(amount_in_cents, options)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Populate the Payer id if missing
|
102
|
-
options[:payer_id] = find_value_from_properties(properties, 'payer_id')
|
103
|
-
begin
|
104
|
-
options[:payer_id] ||= find_payer_id(options[:token],
|
105
|
-
kb_account_id,
|
106
|
-
context.tenant_id,
|
107
|
-
properties_to_hash(properties))
|
108
|
-
rescue => e
|
109
|
-
# Maybe invalid token?
|
110
|
-
response = @response_model.create(:api_call => :purchase,
|
111
|
-
:kb_account_id => kb_account_id,
|
112
|
-
:kb_payment_id => kb_payment_id,
|
113
|
-
:kb_payment_transaction_id => kb_payment_transaction_id,
|
114
|
-
:transaction_type => :PURCHASE,
|
115
|
-
:authorization => nil,
|
116
|
-
:payment_processor_account_id => payment_processor_account_id,
|
117
|
-
:kb_tenant_id => context.tenant_id,
|
118
|
-
:success => false,
|
119
|
-
:created_at => Time.now.utc,
|
120
|
-
:updated_at => Time.now.utc,
|
121
|
-
:message => { :payment_plugin_status => :CANCELED, :exception_class => e.class.to_s, :exception_message => e.message }.to_json)
|
122
|
-
return response.to_transaction_info_plugin(nil)
|
123
|
-
end
|
124
|
-
|
125
|
-
properties = merge_properties(properties, options)
|
126
|
-
dispatch_to_gateways(:purchase, kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context, gateway_call_proc)
|
127
|
-
end
|
48
|
+
# by default, this call will purchase a payment
|
49
|
+
authorize_or_purchase_payment kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context
|
128
50
|
end
|
129
51
|
|
130
52
|
def void_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, properties, context)
|
@@ -151,7 +73,7 @@ module Killbill #:nodoc:
|
|
151
73
|
linked_transaction_type = @transaction_model.purchases_from_kb_payment_id(kb_payment_id, context.tenant_id).size > 0 ? :PURCHASE : :CAPTURE
|
152
74
|
|
153
75
|
# Pass extra parameters for the gateway here
|
154
|
-
options
|
76
|
+
options = {
|
155
77
|
:linked_transaction_type => linked_transaction_type
|
156
78
|
}
|
157
79
|
|
@@ -162,12 +84,14 @@ module Killbill #:nodoc:
|
|
162
84
|
def get_payment_info(kb_account_id, kb_payment_id, properties, context)
|
163
85
|
t_info_plugins = super(kb_account_id, kb_payment_id, properties, context)
|
164
86
|
|
165
|
-
# Completed purchases will have two rows in the responses table (one for api_call 'build_form_descriptor', one for api_call 'purchase')
|
87
|
+
# Completed purchases/authorizations will have two rows in the responses table (one for api_call 'build_form_descriptor', one for api_call 'purchase/authorize')
|
166
88
|
# Other transaction types don't support the :PENDING state
|
167
|
-
|
168
|
-
|
89
|
+
target_transaction_types = [:PURCHASE, :AUTHORIZE]
|
90
|
+
is_transaction_pending = t_info_plugins.find { |t_info_plugin| target_transaction_types.include?(t_info_plugin.transaction_type) && t_info_plugin.status != :PENDING }.nil?
|
91
|
+
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 }
|
169
92
|
|
170
|
-
|
93
|
+
# If only pending transactions exist, return the pending one. Otherwise, only return those non-pending transaction.
|
94
|
+
is_transaction_pending ? t_info_plugins: t_info_plugins_without_pending
|
171
95
|
end
|
172
96
|
|
173
97
|
def search_payments(search_key, offset, limit, properties, context)
|
@@ -189,10 +113,13 @@ module Killbill #:nodoc:
|
|
189
113
|
}
|
190
114
|
else
|
191
115
|
# Go to Paypal to get the Payer id (GetExpressCheckoutDetails call)
|
192
|
-
|
116
|
+
payment_processor_account_id = find_value_from_properties(properties, :payment_processor_account_id)
|
117
|
+
payment_processor_account_id ||= find_payment_processor_id_from_initial_call(kb_account_id, context.tenant_id, token)
|
118
|
+
payer_id = find_payer_id(token, kb_account_id, context.tenant_id, payment_processor_account_id)
|
193
119
|
options = {
|
194
|
-
:paypal_express_token
|
195
|
-
:paypal_express_payer_id
|
120
|
+
:paypal_express_token => token,
|
121
|
+
:paypal_express_payer_id => payer_id,
|
122
|
+
:payment_processor_account_id => payment_processor_account_id
|
196
123
|
}
|
197
124
|
end
|
198
125
|
|
@@ -260,22 +187,40 @@ module Killbill #:nodoc:
|
|
260
187
|
# By default, pending payments are not created for HPP
|
261
188
|
create_pending_payment = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :create_pending_payment)
|
262
189
|
if create_pending_payment
|
263
|
-
|
264
|
-
|
190
|
+
payment_processor_account_id = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :payment_processor_account_id)
|
191
|
+
custom_props = hash_to_properties(:from_hpp => true,
|
192
|
+
:token => response.token,
|
193
|
+
:payment_processor_account_id => payment_processor_account_id)
|
265
194
|
payment_external_key = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :payment_external_key)
|
266
195
|
transaction_external_key = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :transaction_external_key)
|
267
196
|
|
268
197
|
kb_payment_method = (@kb_apis.payment_api.get_account_payment_methods(kb_account_id, false, [], jcontext).find { |pm| pm.plugin_name == 'killbill-paypal-express' })
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
198
|
+
|
199
|
+
auth_mode = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :auth_mode)
|
200
|
+
# By default, the SALE mode is used.
|
201
|
+
if auth_mode
|
202
|
+
payment = @kb_apis.payment_api
|
203
|
+
.create_authorization(kb_account.send(:__instance_object__),
|
204
|
+
kb_payment_method.id,
|
205
|
+
nil,
|
206
|
+
amount,
|
207
|
+
currency,
|
208
|
+
payment_external_key,
|
209
|
+
transaction_external_key,
|
210
|
+
custom_props,
|
211
|
+
jcontext)
|
212
|
+
else
|
213
|
+
payment = @kb_apis.payment_api
|
214
|
+
.create_purchase(kb_account.send(:__instance_object__),
|
215
|
+
kb_payment_method.id,
|
216
|
+
nil,
|
217
|
+
amount,
|
218
|
+
currency,
|
219
|
+
payment_external_key,
|
220
|
+
transaction_external_key,
|
221
|
+
custom_props,
|
222
|
+
jcontext)
|
223
|
+
end
|
279
224
|
|
280
225
|
descriptor.properties << build_property('kb_payment_id', payment.id)
|
281
226
|
descriptor.properties << build_property('kb_payment_external_key', payment.external_key)
|
@@ -318,11 +263,11 @@ module Killbill #:nodoc:
|
|
318
263
|
@response_model.last_token(kb_account_id, kb_tenant_id)
|
319
264
|
end
|
320
265
|
|
321
|
-
def find_payer_id(token, kb_account_id, kb_tenant_id,
|
266
|
+
def find_payer_id(token, kb_account_id, kb_tenant_id, payment_processor_account_id)
|
322
267
|
raise 'Could not find the payer_id: the token is missing' if token.blank?
|
323
268
|
|
324
269
|
# Go to Paypal to get the Payer id (GetExpressCheckoutDetails call)
|
325
|
-
payment_processor_account_id =
|
270
|
+
payment_processor_account_id = payment_processor_account_id || :default
|
326
271
|
gateway = lookup_gateway(payment_processor_account_id, kb_tenant_id)
|
327
272
|
gw_response = gateway.details_for(token)
|
328
273
|
response, transaction = save_response_and_transaction(gw_response, :details_for, kb_account_id, kb_tenant_id, payment_processor_account_id)
|
@@ -353,6 +298,7 @@ module Killbill #:nodoc:
|
|
353
298
|
options = {}
|
354
299
|
options[:return_url] = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :return_url)
|
355
300
|
options[:cancel_return_url] = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :cancel_return_url)
|
301
|
+
options[:payment_processor_account_id] = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :payment_processor_account_id)
|
356
302
|
|
357
303
|
max_amount_value = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :max_amount)
|
358
304
|
if max_amount_value
|
@@ -373,6 +319,99 @@ module Killbill #:nodoc:
|
|
373
319
|
|
374
320
|
response
|
375
321
|
end
|
322
|
+
|
323
|
+
def authorize_or_purchase_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context, is_authorize = false)
|
324
|
+
payment_processor_account_id = find_value_from_properties(properties, 'payment_processor_account_id')
|
325
|
+
transaction_type = is_authorize ? :AUTHORIZE : :PURCHASE
|
326
|
+
api_call_type = is_authorize ? :authorize : :purchase
|
327
|
+
|
328
|
+
# Callback from the plugin itself (HPP flow)
|
329
|
+
if find_value_from_properties(properties, 'from_hpp') == 'true'
|
330
|
+
token = find_value_from_properties(properties, 'token')
|
331
|
+
|
332
|
+
response = @response_model.create(:api_call => :build_form_descriptor,
|
333
|
+
:kb_account_id => kb_account_id,
|
334
|
+
:kb_payment_id => kb_payment_id,
|
335
|
+
:kb_payment_transaction_id => kb_payment_transaction_id,
|
336
|
+
:transaction_type => transaction_type,
|
337
|
+
:authorization => token,
|
338
|
+
:payment_processor_account_id => payment_processor_account_id,
|
339
|
+
:kb_tenant_id => context.tenant_id,
|
340
|
+
:success => true,
|
341
|
+
:created_at => Time.now.utc,
|
342
|
+
:updated_at => Time.now.utc,
|
343
|
+
:message => { :payment_plugin_status => :PENDING }.to_json)
|
344
|
+
transaction = response.to_transaction_info_plugin(nil)
|
345
|
+
transaction.amount = amount
|
346
|
+
transaction.currency = currency
|
347
|
+
transaction
|
348
|
+
else
|
349
|
+
options = {}
|
350
|
+
add_required_options(kb_payment_transaction_id, kb_payment_method_id, context, options)
|
351
|
+
|
352
|
+
# We have a baid on file
|
353
|
+
if options[:token]
|
354
|
+
if is_authorize
|
355
|
+
gateway_call_proc = Proc.new do |gateway, linked_transaction, payment_source, amount_in_cents, options|
|
356
|
+
# Can't use default implementation: the purchase signature is for one-off payments only
|
357
|
+
gateway.authorize_reference_transaction(amount_in_cents, options)
|
358
|
+
end
|
359
|
+
else
|
360
|
+
gateway_call_proc = Proc.new do |gateway, linked_transaction, payment_source, amount_in_cents, options|
|
361
|
+
# Can't use default implementation: the purchase signature is for one-off payments only
|
362
|
+
gateway.reference_transaction(amount_in_cents, options)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
else
|
366
|
+
# One-off payment
|
367
|
+
options[:token] = find_value_from_properties(properties, 'token') || find_last_token(kb_account_id, context.tenant_id)
|
368
|
+
if is_authorize
|
369
|
+
gateway_call_proc = Proc.new do |gateway, linked_transaction, payment_source, amount_in_cents, options|
|
370
|
+
gateway.authorize(amount_in_cents, options)
|
371
|
+
end
|
372
|
+
else
|
373
|
+
gateway_call_proc = Proc.new do |gateway, linked_transaction, payment_source, amount_in_cents, options|
|
374
|
+
gateway.purchase(amount_in_cents, options)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
# Find the payment_processor_id if not provided
|
380
|
+
payment_processor_account_id ||= find_payment_processor_id_from_initial_call(kb_account_id, context.tenant_id, options[:token])
|
381
|
+
options[:payment_processor_account_id] = payment_processor_account_id
|
382
|
+
|
383
|
+
# Populate the Payer id if missing
|
384
|
+
options[:payer_id] = find_value_from_properties(properties, 'payer_id')
|
385
|
+
begin
|
386
|
+
options[:payer_id] ||= find_payer_id(options[:token],
|
387
|
+
kb_account_id,
|
388
|
+
context.tenant_id,
|
389
|
+
payment_processor_account_id)
|
390
|
+
rescue => e
|
391
|
+
# Maybe invalid token?
|
392
|
+
response = @response_model.create(:api_call => api_call_type,
|
393
|
+
:kb_account_id => kb_account_id,
|
394
|
+
:kb_payment_id => kb_payment_id,
|
395
|
+
:kb_payment_transaction_id => kb_payment_transaction_id,
|
396
|
+
:transaction_type => transaction_type,
|
397
|
+
:authorization => nil,
|
398
|
+
:payment_processor_account_id => payment_processor_account_id,
|
399
|
+
:kb_tenant_id => context.tenant_id,
|
400
|
+
:success => false,
|
401
|
+
:created_at => Time.now.utc,
|
402
|
+
:updated_at => Time.now.utc,
|
403
|
+
:message => { :payment_plugin_status => :CANCELED, :exception_class => e.class.to_s, :exception_message => e.message }.to_json)
|
404
|
+
return response.to_transaction_info_plugin(nil)
|
405
|
+
end
|
406
|
+
|
407
|
+
properties = merge_properties(properties, options)
|
408
|
+
dispatch_to_gateways(api_call_type, kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context, gateway_call_proc)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def find_payment_processor_id_from_initial_call(kb_account_id, kb_tenant_id, token)
|
413
|
+
@response_model.initial_payment_account_processor_id kb_account_id, kb_tenant_id, token
|
414
|
+
end
|
376
415
|
end
|
377
416
|
end
|
378
417
|
end
|
@@ -67,6 +67,16 @@ module Killbill #:nodoc:
|
|
67
67
|
response.nil? ? nil : response.token
|
68
68
|
end
|
69
69
|
|
70
|
+
def self.initial_payment_account_processor_id(kb_account_id, kb_tenant_id, token)
|
71
|
+
return nil if token.blank?
|
72
|
+
response = where(:api_call => 'initiate_express_checkout',
|
73
|
+
:success => true,
|
74
|
+
:kb_account_id => kb_account_id,
|
75
|
+
:kb_tenant_id => kb_tenant_id,
|
76
|
+
:token => token).last
|
77
|
+
response.nil? ? nil : response.payment_processor_account_id
|
78
|
+
end
|
79
|
+
|
70
80
|
def to_transaction_info_plugin(transaction=nil)
|
71
81
|
t_info_plugin = super(transaction)
|
72
82
|
|
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>4.1.
|
29
|
+
<version>4.1.3</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>
|
@@ -1,53 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require_relative 'build_plugin_helpers'
|
3
|
+
require_relative 'baid_spec_helpers'
|
2
4
|
|
3
5
|
ActiveMerchant::Billing::Base.mode = :test
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
include ::Killbill::Plugin::ActiveMerchant::RSpec
|
8
|
-
|
9
|
-
# Share the BAID
|
10
|
-
before(:all) do
|
11
|
-
@plugin = build_plugin(::Killbill::PaypalExpress::PaymentPlugin, 'paypal_express')
|
12
|
-
svcs = @plugin.kb_apis.proxied_services
|
13
|
-
svcs[:payment_api] = PaypalExpressJavaPaymentApi.new(@plugin)
|
14
|
-
@plugin.kb_apis = ::Killbill::Plugin::KillbillApi.new('paypal_express', svcs)
|
15
|
-
@plugin.start_plugin
|
16
|
-
|
17
|
-
@call_context = build_call_context
|
18
|
-
|
19
|
-
@properties = []
|
20
|
-
@amount = BigDecimal.new('100')
|
21
|
-
@currency = 'USD'
|
22
|
-
|
23
|
-
kb_account_id = SecureRandom.uuid
|
24
|
-
external_key, kb_account_id = create_kb_account(kb_account_id, @plugin.kb_apis.proxied_services[:account_user_api])
|
25
|
-
|
26
|
-
# Initiate the setup process
|
27
|
-
response = create_token(kb_account_id, @call_context.tenant_id)
|
28
|
-
token = response.token
|
29
|
-
print "\nPlease go to #{@plugin.to_express_checkout_url(response, @call_context.tenant_id)} to proceed and press any key to continue...
|
30
|
-
Note: you need to log-in with a paypal sandbox account (create one here: https://developer.paypal.com/webapps/developer/applications/accounts)\n"
|
31
|
-
$stdin.gets
|
32
|
-
|
33
|
-
# Complete the setup process
|
34
|
-
@properties << build_property('token', token)
|
35
|
-
@pm = create_payment_method(::Killbill::PaypalExpress::PaypalExpressPaymentMethod, kb_account_id, @call_context.tenant_id, @properties)
|
36
|
-
|
37
|
-
# Verify our table directly. Note that @pm.token is the baid
|
38
|
-
payment_methods = ::Killbill::PaypalExpress::PaypalExpressPaymentMethod.from_kb_account_id_and_token(@pm.token, kb_account_id, @call_context.tenant_id)
|
39
|
-
payment_methods.size.should == 1
|
40
|
-
payment_method = payment_methods.first
|
41
|
-
payment_method.should_not be_nil
|
42
|
-
payment_method.paypal_express_payer_id.should_not be_nil
|
43
|
-
payment_method.token.should == @pm.token
|
44
|
-
payment_method.kb_payment_method_id.should == @pm.kb_payment_method_id
|
45
|
-
end
|
46
|
-
|
7
|
+
shared_examples 'baid_spec_common' do
|
47
8
|
before(:each) do
|
48
9
|
::Killbill::PaypalExpress::PaypalExpressTransaction.delete_all
|
49
|
-
::Killbill::PaypalExpress::PaypalExpressResponse.delete_all
|
50
|
-
|
51
10
|
kb_payment_id = SecureRandom.uuid
|
52
11
|
1.upto(6) do
|
53
12
|
@kb_payment = @plugin.kb_apis.proxied_services[:payment_api].add_payment(kb_payment_id)
|
@@ -70,6 +29,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
70
29
|
payment_infos[0].status.should == :PROCESSED
|
71
30
|
payment_infos[0].gateway_error.should == 'Success'
|
72
31
|
payment_infos[0].gateway_error_code.should be_nil
|
32
|
+
find_value_from_properties(payment_infos[0].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
73
33
|
|
74
34
|
# Try a full refund
|
75
35
|
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)
|
@@ -87,6 +47,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
87
47
|
payment_infos[0].status.should == :PROCESSED
|
88
48
|
payment_infos[0].gateway_error.should == 'Success'
|
89
49
|
payment_infos[0].gateway_error_code.should be_nil
|
50
|
+
find_value_from_properties(payment_infos[0].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
90
51
|
payment_infos[1].kb_payment_id.should == @kb_payment.id
|
91
52
|
payment_infos[1].transaction_type.should == :REFUND
|
92
53
|
payment_infos[1].amount.should == @amount
|
@@ -94,6 +55,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
94
55
|
payment_infos[1].status.should == :PROCESSED
|
95
56
|
payment_infos[1].gateway_error.should == 'Success'
|
96
57
|
payment_infos[1].gateway_error_code.should be_nil
|
58
|
+
find_value_from_properties(payment_infos[1].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
97
59
|
end
|
98
60
|
|
99
61
|
it 'should be able to auth, capture and refund' do
|
@@ -112,6 +74,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
112
74
|
payment_infos[0].status.should == :PROCESSED
|
113
75
|
payment_infos[0].gateway_error.should == 'Success'
|
114
76
|
payment_infos[0].gateway_error_code.should be_nil
|
77
|
+
find_value_from_properties(payment_infos[0].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
115
78
|
|
116
79
|
# Try multiple partial captures
|
117
80
|
partial_capture_amount = BigDecimal.new('10')
|
@@ -131,6 +94,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
131
94
|
payment_infos[i].status.should == :PROCESSED
|
132
95
|
payment_infos[i].gateway_error.should == 'Success'
|
133
96
|
payment_infos[i].gateway_error_code.should be_nil
|
97
|
+
find_value_from_properties(payment_infos[i].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
134
98
|
end
|
135
99
|
|
136
100
|
# Try a partial refund
|
@@ -149,6 +113,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
149
113
|
payment_infos[4].status.should == :PROCESSED
|
150
114
|
payment_infos[4].gateway_error.should == 'Success'
|
151
115
|
payment_infos[4].gateway_error_code.should be_nil
|
116
|
+
find_value_from_properties(payment_infos[4].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
152
117
|
|
153
118
|
# Try to capture again
|
154
119
|
payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[5].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
|
@@ -166,6 +131,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
166
131
|
payment_infos[5].status.should == :PROCESSED
|
167
132
|
payment_infos[5].gateway_error.should == 'Success'
|
168
133
|
payment_infos[5].gateway_error_code.should be_nil
|
134
|
+
find_value_from_properties(payment_infos[5].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
169
135
|
end
|
170
136
|
|
171
137
|
it 'should be able to auth and void' do
|
@@ -184,6 +150,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
184
150
|
payment_infos[0].status.should == :PROCESSED
|
185
151
|
payment_infos[0].gateway_error.should == 'Success'
|
186
152
|
payment_infos[0].gateway_error_code.should be_nil
|
153
|
+
find_value_from_properties(payment_infos[0].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
187
154
|
|
188
155
|
payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @properties, @call_context)
|
189
156
|
payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
|
@@ -199,6 +166,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
199
166
|
payment_infos[0].status.should == :PROCESSED
|
200
167
|
payment_infos[0].gateway_error.should == 'Success'
|
201
168
|
payment_infos[0].gateway_error_code.should be_nil
|
169
|
+
find_value_from_properties(payment_infos[0].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
202
170
|
payment_infos[1].kb_payment_id.should == @kb_payment.id
|
203
171
|
payment_infos[1].transaction_type.should == :VOID
|
204
172
|
payment_infos[1].amount.should be_nil
|
@@ -206,6 +174,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
206
174
|
payment_infos[1].status.should == :PROCESSED
|
207
175
|
payment_infos[1].gateway_error.should == 'Success'
|
208
176
|
payment_infos[1].gateway_error_code.should be_nil
|
177
|
+
find_value_from_properties(payment_infos[1].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
209
178
|
end
|
210
179
|
|
211
180
|
it 'should be able to auth, partial capture and void' do
|
@@ -224,6 +193,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
224
193
|
payment_infos[0].status.should == :PROCESSED
|
225
194
|
payment_infos[0].gateway_error.should == 'Success'
|
226
195
|
payment_infos[0].gateway_error_code.should be_nil
|
196
|
+
find_value_from_properties(payment_infos[0].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
227
197
|
|
228
198
|
partial_capture_amount = BigDecimal.new('10')
|
229
199
|
payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
|
@@ -241,6 +211,7 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
241
211
|
payment_infos[1].status.should == :PROCESSED
|
242
212
|
payment_infos[1].gateway_error.should == 'Success'
|
243
213
|
payment_infos[1].gateway_error_code.should be_nil
|
214
|
+
find_value_from_properties(payment_infos[1].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
244
215
|
|
245
216
|
payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[2].id, @pm.kb_payment_method_id, @properties, @call_context)
|
246
217
|
payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
|
@@ -256,32 +227,57 @@ Note: you need to log-in with a paypal sandbox account (create one here: https:/
|
|
256
227
|
payment_infos[2].status.should == :PROCESSED
|
257
228
|
payment_infos[2].gateway_error.should == 'Success'
|
258
229
|
payment_infos[2].gateway_error_code.should be_nil
|
230
|
+
find_value_from_properties(payment_infos[2].properties, 'payment_processor_account_id').should == @payment_processor_account_id
|
259
231
|
end
|
260
232
|
|
261
233
|
it 'should generate forms correctly' do
|
262
234
|
context = @plugin.kb_apis.create_context(@call_context.tenant_id)
|
263
|
-
fields
|
264
|
-
|
265
|
-
|
266
|
-
|
235
|
+
fields = @plugin.hash_to_properties(
|
236
|
+
:order_id => '1234',
|
237
|
+
:amount => 12
|
238
|
+
)
|
267
239
|
|
268
240
|
properties = @plugin.hash_to_properties(
|
269
|
-
|
241
|
+
:create_pending_payment => false
|
270
242
|
)
|
271
243
|
|
272
244
|
form = @plugin.build_form_descriptor(@pm.kb_account_id, fields, properties, context)
|
273
245
|
|
274
246
|
form.kb_account_id.should == @pm.kb_account_id
|
275
|
-
form.form_method.should
|
247
|
+
form.form_method.should == 'GET'
|
276
248
|
form.form_url.should start_with('https://www.sandbox.paypal.com/cgi-bin/webscr')
|
277
249
|
end
|
278
250
|
|
279
|
-
|
251
|
+
end
|
252
|
+
|
253
|
+
describe Killbill::PaypalExpress::PaymentPlugin do
|
254
|
+
include ::Killbill::Plugin::ActiveMerchant::RSpec
|
255
|
+
include ::Killbill::PaypalExpress::BuildPluginHelpers
|
256
|
+
include ::Killbill::PaypalExpress::BaidSpecHelpers
|
257
|
+
|
258
|
+
context 'baid test with a single account' do
|
259
|
+
# Share the BAID
|
260
|
+
before(:all) do
|
261
|
+
# delete once here because we need to keep the initial response for later tests to find the payment processor account id
|
262
|
+
::Killbill::PaypalExpress::PaypalExpressResponse.delete_all
|
263
|
+
@payment_processor_account_id = 'default'
|
264
|
+
@plugin = build_start_paypal_plugin
|
265
|
+
baid_setup
|
266
|
+
end
|
267
|
+
|
268
|
+
include_examples 'baid_spec_common'
|
269
|
+
end
|
270
|
+
|
271
|
+
context 'baid tests with multiple accounts' do
|
272
|
+
# Share the BAID
|
273
|
+
before(:all) do
|
274
|
+
# delete once here because we need to keep the initial response for later tests to find the payment processor account id
|
275
|
+
::Killbill::PaypalExpress::PaypalExpressResponse.delete_all
|
276
|
+
@payment_processor_account_id = 'paypal_test_account'
|
277
|
+
@plugin = build_start_paypal_plugin @payment_processor_account_id
|
278
|
+
baid_setup @payment_processor_account_id
|
279
|
+
end
|
280
280
|
|
281
|
-
|
282
|
-
private_plugin = ::Killbill::PaypalExpress::PrivatePaymentPlugin.new
|
283
|
-
response = private_plugin.initiate_express_checkout(kb_account_id, kb_tenant_id)
|
284
|
-
response.success.should be_true
|
285
|
-
response
|
281
|
+
include_examples 'baid_spec_common'
|
286
282
|
end
|
287
283
|
end
|