killbill-cybersource 5.0.1 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -6
- data/NEWS +3 -0
- data/VERSION +1 -1
- data/cybersource.yml +4 -1
- data/db/ddl.sql +91 -91
- data/killbill-cybersource.gemspec +1 -0
- data/lib/cybersource/api.rb +24 -8
- data/lib/cybersource/cyber_source_on_demand.rb +12 -4
- data/pom.xml +1 -1
- data/spec/cybersource/cyber_source_on_demand_spec.rb +1 -1
- data/spec/cybersource/remote/integration_spec.rb +122 -56
- data/spec/spec_helper.rb +9 -5
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae2d49fdb4fd4bbe3b9be5e7b79ee0b14e12837a
|
4
|
+
data.tar.gz: 85d673ad015325da80051feb7bcaf67bbbcf243a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b69a139a422956d25ee6651d97e8504a87334d9d405244e74400754de906ffe12df6016363e7c6d8fb9085fe6dcbd98f7f493ef8cb37010ea305e454a243a47e
|
7
|
+
data.tar.gz: b33fa00be1629c68fa7233108180eabb9dd2e363cd80a2e11a7d1e4fbea8f7fc66281ff3bad33a8d33cb2b743e90c8dbf0f7e6dab23157d21a562fdcdc6c9884
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
killbill-cybersource (5.0
|
4
|
+
killbill-cybersource (5.1.0)
|
5
5
|
actionpack (~> 4.1.0)
|
6
6
|
actionview (~> 4.1.0)
|
7
7
|
activemerchant (~> 1.48.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
|
coercible (1.0.0)
|
62
62
|
descendants_tracker (~> 0.0.1)
|
63
63
|
descendants_tracker (0.0.4)
|
@@ -77,9 +77,10 @@ GEM
|
|
77
77
|
maven-tools (~> 1.1)
|
78
78
|
ruby-maven (~> 3.3, >= 3.3.8)
|
79
79
|
jdbc-mariadb (1.3.4)
|
80
|
+
jdbc-postgres (9.4.1206)
|
80
81
|
jdbc-sqlite3 (3.8.11.2)
|
81
82
|
jruby-openssl (0.9.18-java)
|
82
|
-
json (1.8.
|
83
|
+
json (1.8.6-java)
|
83
84
|
killbill (8.3.1)
|
84
85
|
rack (>= 1.5.2)
|
85
86
|
sinatra (~> 1.3.4)
|
@@ -87,12 +88,12 @@ GEM
|
|
87
88
|
tzinfo (~> 1.2.0)
|
88
89
|
maven-tools (1.1.6)
|
89
90
|
virtus (~> 1.0)
|
90
|
-
minitest (5.
|
91
|
+
minitest (5.10.1)
|
91
92
|
monetize (1.1.0)
|
92
93
|
money (~> 6.5.0)
|
93
94
|
money (6.5.1)
|
94
95
|
i18n (>= 0.6.4, <= 0.7.0)
|
95
|
-
nokogiri (1.
|
96
|
+
nokogiri (1.7.0.1-java)
|
96
97
|
offsite_payments (2.1.0)
|
97
98
|
actionpack (>= 3.2.20, < 5.0.0)
|
98
99
|
active_utils (~> 3.0.0)
|
@@ -140,10 +141,11 @@ PLATFORMS
|
|
140
141
|
DEPENDENCIES
|
141
142
|
jbundler (~> 0.9.2)
|
142
143
|
jdbc-mariadb (~> 1.1)
|
144
|
+
jdbc-postgres (~> 9.4)
|
143
145
|
jdbc-sqlite3 (~> 3.7)
|
144
146
|
killbill-cybersource!
|
145
147
|
rake (>= 10.0.0)
|
146
148
|
rspec (~> 2.12.0)
|
147
149
|
|
148
150
|
BUNDLED WITH
|
149
|
-
1.
|
151
|
+
1.14.3
|
data/NEWS
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
5.0
|
1
|
+
5.1.0
|
data/cybersource.yml
CHANGED
@@ -13,8 +13,11 @@
|
|
13
13
|
# SQLite (development)
|
14
14
|
:adapter: sqlite3
|
15
15
|
:database: test.db
|
16
|
+
# For PostgreSQL
|
17
|
+
# :adapter: postgresql
|
18
|
+
# :database: 'killbill'
|
16
19
|
# For MySQL
|
17
|
-
# :adapter:
|
20
|
+
# :adapter: mariadb
|
18
21
|
# :username: 'killbill'
|
19
22
|
# :password: 'killbill'
|
20
23
|
# :database: 'killbill' # or set the URL :
|
data/db/ddl.sql
CHANGED
@@ -1,92 +1,92 @@
|
|
1
|
-
CREATE TABLE
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
PRIMARY KEY (
|
29
|
-
|
30
|
-
|
31
|
-
|
1
|
+
CREATE TABLE cybersource_payment_methods (
|
2
|
+
id serial unique,
|
3
|
+
kb_payment_method_id varchar(255) DEFAULT NULL,
|
4
|
+
token varchar(255) DEFAULT NULL,
|
5
|
+
cc_first_name varchar(255) DEFAULT NULL,
|
6
|
+
cc_last_name varchar(255) DEFAULT NULL,
|
7
|
+
cc_type varchar(255) DEFAULT NULL,
|
8
|
+
cc_exp_month varchar(255) DEFAULT NULL,
|
9
|
+
cc_exp_year varchar(255) DEFAULT NULL,
|
10
|
+
cc_number varchar(255) DEFAULT NULL,
|
11
|
+
cc_last_4 varchar(255) DEFAULT NULL,
|
12
|
+
cc_start_month varchar(255) DEFAULT NULL,
|
13
|
+
cc_start_year varchar(255) DEFAULT NULL,
|
14
|
+
cc_issue_number varchar(255) DEFAULT NULL,
|
15
|
+
cc_verification_value varchar(255) DEFAULT NULL,
|
16
|
+
cc_track_data varchar(255) DEFAULT NULL,
|
17
|
+
address1 varchar(255) DEFAULT NULL,
|
18
|
+
address2 varchar(255) DEFAULT NULL,
|
19
|
+
city varchar(255) DEFAULT NULL,
|
20
|
+
state varchar(255) DEFAULT NULL,
|
21
|
+
zip varchar(255) DEFAULT NULL,
|
22
|
+
country varchar(255) DEFAULT NULL,
|
23
|
+
is_deleted boolean NOT NULL DEFAULT '0',
|
24
|
+
created_at datetime NOT NULL,
|
25
|
+
updated_at datetime NOT NULL,
|
26
|
+
kb_account_id varchar(255) DEFAULT NULL,
|
27
|
+
kb_tenant_id varchar(255) DEFAULT NULL,
|
28
|
+
PRIMARY KEY (id)
|
29
|
+
) /*! ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin */;
|
30
|
+
CREATE INDEX index_cybersource_payment_methods_kb_account_id ON cybersource_payment_methods(kb_account_id);
|
31
|
+
CREATE INDEX index_cybersource_payment_methods_kb_payment_method_id ON cybersource_payment_methods(kb_payment_method_id);
|
32
|
+
|
33
|
+
CREATE TABLE cybersource_transactions (
|
34
|
+
id serial unique,
|
35
|
+
cybersource_response_id bigint /*! unsigned */ NOT NULL,
|
36
|
+
api_call varchar(255) NOT NULL,
|
37
|
+
kb_payment_id varchar(255) NOT NULL,
|
38
|
+
kb_payment_transaction_id varchar(255) NOT NULL,
|
39
|
+
transaction_type varchar(255) NOT NULL,
|
40
|
+
payment_processor_account_id varchar(255) DEFAULT NULL,
|
41
|
+
txn_id varchar(255) DEFAULT NULL,
|
42
|
+
amount_in_cents int DEFAULT NULL,
|
43
|
+
currency varchar(255) DEFAULT NULL,
|
44
|
+
created_at datetime NOT NULL,
|
45
|
+
updated_at datetime NOT NULL,
|
46
|
+
kb_account_id varchar(255) NOT NULL,
|
47
|
+
kb_tenant_id varchar(255) NOT NULL,
|
48
|
+
PRIMARY KEY (id)
|
49
|
+
) /*! ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin */;
|
50
|
+
CREATE INDEX index_cybersource_transactions_kb_payment_id ON cybersource_transactions(kb_payment_id);
|
51
|
+
CREATE INDEX index_cybersource_transactions_cybersource_response_id ON cybersource_transactions(cybersource_response_id);
|
32
52
|
|
33
|
-
CREATE TABLE
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
`params_avs_code_raw` varchar(255) DEFAULT NULL,
|
74
|
-
`params_cv_code` varchar(255) DEFAULT NULL,
|
75
|
-
`params_authorized_date_time` varchar(255) DEFAULT NULL,
|
76
|
-
`params_processor_response` varchar(255) DEFAULT NULL,
|
77
|
-
`params_reconciliation_id` varchar(255) DEFAULT NULL,
|
78
|
-
`params_subscription_id` varchar(255) DEFAULT NULL,
|
79
|
-
`avs_result_code` varchar(255) DEFAULT NULL,
|
80
|
-
`avs_result_message` varchar(255) DEFAULT NULL,
|
81
|
-
`avs_result_street_match` varchar(255) DEFAULT NULL,
|
82
|
-
`avs_result_postal_match` varchar(255) DEFAULT NULL,
|
83
|
-
`cvv_result_code` varchar(255) DEFAULT NULL,
|
84
|
-
`cvv_result_message` varchar(255) DEFAULT NULL,
|
85
|
-
`success` tinyint(1) DEFAULT NULL,
|
86
|
-
`created_at` datetime NOT NULL,
|
87
|
-
`updated_at` datetime NOT NULL,
|
88
|
-
`kb_account_id` varchar(255) DEFAULT NULL,
|
89
|
-
`kb_tenant_id` varchar(255) DEFAULT NULL,
|
90
|
-
PRIMARY KEY (`id`),
|
91
|
-
KEY `index_cybersource_responses_on_kb_payment_id_kb_tenant_id` (`kb_payment_id`, `kb_tenant_id`)
|
92
|
-
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
53
|
+
CREATE TABLE cybersource_responses (
|
54
|
+
id serial unique,
|
55
|
+
api_call varchar(255) NOT NULL,
|
56
|
+
kb_payment_id varchar(255) DEFAULT NULL,
|
57
|
+
kb_payment_transaction_id varchar(255) DEFAULT NULL,
|
58
|
+
transaction_type varchar(255) DEFAULT NULL,
|
59
|
+
payment_processor_account_id varchar(255) DEFAULT NULL,
|
60
|
+
message text DEFAULT NULL,
|
61
|
+
authorisation varchar(255) DEFAULT NULL,
|
62
|
+
fraud_review boolean DEFAULT NULL,
|
63
|
+
test boolean DEFAULT NULL,
|
64
|
+
params_merchant_reference_code varchar(255) DEFAULT NULL,
|
65
|
+
params_request_id varchar(255) DEFAULT NULL,
|
66
|
+
params_decision varchar(255) DEFAULT NULL,
|
67
|
+
params_reason_code varchar(255) DEFAULT NULL,
|
68
|
+
params_request_token varchar(255) DEFAULT NULL,
|
69
|
+
params_currency varchar(255) DEFAULT NULL,
|
70
|
+
params_amount varchar(255) DEFAULT NULL,
|
71
|
+
params_authorization_code varchar(255) DEFAULT NULL,
|
72
|
+
params_avs_code varchar(255) DEFAULT NULL,
|
73
|
+
params_avs_code_raw varchar(255) DEFAULT NULL,
|
74
|
+
params_cv_code varchar(255) DEFAULT NULL,
|
75
|
+
params_authorized_date_time varchar(255) DEFAULT NULL,
|
76
|
+
params_processor_response varchar(255) DEFAULT NULL,
|
77
|
+
params_reconciliation_id varchar(255) DEFAULT NULL,
|
78
|
+
params_subscription_id varchar(255) DEFAULT NULL,
|
79
|
+
avs_result_code varchar(255) DEFAULT NULL,
|
80
|
+
avs_result_message varchar(255) DEFAULT NULL,
|
81
|
+
avs_result_street_match varchar(255) DEFAULT NULL,
|
82
|
+
avs_result_postal_match varchar(255) DEFAULT NULL,
|
83
|
+
cvv_result_code varchar(255) DEFAULT NULL,
|
84
|
+
cvv_result_message varchar(255) DEFAULT NULL,
|
85
|
+
success boolean DEFAULT NULL,
|
86
|
+
created_at datetime NOT NULL,
|
87
|
+
updated_at datetime NOT NULL,
|
88
|
+
kb_account_id varchar(255) DEFAULT NULL,
|
89
|
+
kb_tenant_id varchar(255) DEFAULT NULL,
|
90
|
+
PRIMARY KEY (id)
|
91
|
+
) /*! ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin */;
|
92
|
+
CREATE INDEX index_cybersource_responses_kb_payment_id_kb_tenant_id ON cybersource_responses(kb_payment_id, kb_tenant_id);
|
@@ -46,6 +46,7 @@ Gem::Specification.new do |s|
|
|
46
46
|
if defined?(JRUBY_VERSION)
|
47
47
|
s.add_development_dependency 'jdbc-sqlite3', '~> 3.7'
|
48
48
|
s.add_development_dependency 'jdbc-mariadb', '~> 1.1'
|
49
|
+
s.add_development_dependency 'jdbc-postgres', '~> 9.4'
|
49
50
|
else
|
50
51
|
s.add_development_dependency 'sqlite3', '~> 1.3.7'
|
51
52
|
end
|
data/lib/cybersource/api.rb
CHANGED
@@ -2,6 +2,7 @@ module Killbill #:nodoc:
|
|
2
2
|
module Cybersource #:nodoc:
|
3
3
|
class PaymentPlugin < ::Killbill::Plugin::ActiveMerchant::PaymentPlugin
|
4
4
|
|
5
|
+
FIVE_MINUTES_AGO = (1 * 300)
|
5
6
|
ONE_DAY_AGO = (1 * 86400)
|
6
7
|
SIXTY_DAYS_AGO = (60 * 86400)
|
7
8
|
|
@@ -120,6 +121,19 @@ module Killbill #:nodoc:
|
|
120
121
|
|
121
122
|
options = properties_to_hash(properties)
|
122
123
|
|
124
|
+
initial_transaction = nil
|
125
|
+
transaction_info_plugins.each do |transaction_info_plugin|
|
126
|
+
initial_transaction = transaction_info_plugin if transaction_info_plugin.transaction_type == :AUTHORIZE || transaction_info_plugin.transaction_type == :PURCHASE || transaction_info_plugin.transaction_type == :CREDIT
|
127
|
+
end
|
128
|
+
|
129
|
+
# Should never happen (maybe transaction_type wasn't saved?)...
|
130
|
+
initial_transaction = transaction_info_plugins.last if initial_transaction.nil?
|
131
|
+
|
132
|
+
authorization = find_value_from_properties(initial_transaction.properties, 'authorization')
|
133
|
+
order_id = Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :order_id)
|
134
|
+
# authorization is very likely nil, as we didn't get an answer from the gateway in the first place
|
135
|
+
order_id ||= authorization.split(';')[0] unless authorization.nil?
|
136
|
+
|
123
137
|
stale = false
|
124
138
|
transaction_info_plugins.each do |transaction_info_plugin|
|
125
139
|
# We only need to fix the UNDEFINED ones
|
@@ -132,18 +146,20 @@ module Killbill #:nodoc:
|
|
132
146
|
end
|
133
147
|
|
134
148
|
report_date = transaction_info_plugin.created_date
|
135
|
-
|
149
|
+
delay_since_transaction = now - report_date
|
150
|
+
delay_since_transaction = 0 if delay_since_transaction < 0
|
136
151
|
|
137
|
-
|
138
|
-
|
139
|
-
|
152
|
+
# Give some time for CyberSource to update their records
|
153
|
+
janitor_delay_threshold = (Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :janitor_delay_threshold) || FIVE_MINUTES_AGO).to_i
|
154
|
+
should_refresh_status = delay_since_transaction >= janitor_delay_threshold
|
155
|
+
next unless should_refresh_status
|
140
156
|
|
141
157
|
# Retrieve the report from CyberSource
|
142
158
|
if order_id.nil?
|
143
159
|
# order_id undetermined - try the defaults (see PaymentPlugin#dispatch_to_gateways)
|
144
|
-
report = get_report(
|
145
|
-
if report.nil?
|
146
|
-
kb_transaction = get_kb_transaction(kb_payment_id,
|
160
|
+
report = get_report(initial_transaction.kb_transaction_payment_id, report_date, options, context)
|
161
|
+
if report.nil? || report.empty?
|
162
|
+
kb_transaction = get_kb_transaction(kb_payment_id, initial_transaction.kb_transaction_payment_id, context.tenant_id)
|
147
163
|
report = get_report(kb_transaction.external_key, report_date, options, context)
|
148
164
|
end
|
149
165
|
else
|
@@ -154,7 +170,7 @@ module Killbill #:nodoc:
|
|
154
170
|
next if report.nil?
|
155
171
|
|
156
172
|
threshold = (Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :cancel_threshold) || ONE_DAY_AGO).to_i
|
157
|
-
should_cancel_payment =
|
173
|
+
should_cancel_payment = delay_since_transaction >= threshold
|
158
174
|
if report.empty? && !should_cancel_payment
|
159
175
|
# We'll retry later
|
160
176
|
logger.info("Unable to fix UNDEFINED kb_transaction_id='#{transaction_info_plugin.kb_transaction_payment_id}' (not found in CyberSource)")
|
@@ -137,6 +137,9 @@ module Killbill #:nodoc:
|
|
137
137
|
:authorization => authorization,
|
138
138
|
:avs_result => {:code => params['avsCode']},
|
139
139
|
:cvv_result => params['cvCode'])
|
140
|
+
rescue => e
|
141
|
+
@logger.warn "Error '#{e.message}' parsing report: #{@hash_report}\n#{e.backtrace.join("\n")}"
|
142
|
+
raise e
|
140
143
|
end
|
141
144
|
|
142
145
|
def parse_report
|
@@ -148,8 +151,13 @@ module Killbill #:nodoc:
|
|
148
151
|
end
|
149
152
|
|
150
153
|
def parse_request(report)
|
151
|
-
|
152
|
-
|
154
|
+
if !report.nil? && !report['Requests'].nil?
|
155
|
+
requests = report['Requests']['Request']
|
156
|
+
# First one seems to be the last request made, assume it's the one we are looking for (no other easy way to tell unfortunately)
|
157
|
+
requests.is_a?(Hash) ? requests : requests.first
|
158
|
+
else
|
159
|
+
nil
|
160
|
+
end
|
153
161
|
end
|
154
162
|
|
155
163
|
# Note: for now, we only look at the response from CyberSource.
|
@@ -163,8 +171,8 @@ module Killbill #:nodoc:
|
|
163
171
|
|
164
172
|
success = true
|
165
173
|
application_replies.each do |application_reply|
|
166
|
-
success
|
167
|
-
#
|
174
|
+
success = (application_reply['RCode'].to_s == '1')
|
175
|
+
# Assume last entry is the one we are looking for (no other easy way to tell unfortunately)
|
168
176
|
msg = application_reply['RMsg']
|
169
177
|
end
|
170
178
|
[success, msg]
|
data/pom.xml
CHANGED
@@ -25,7 +25,7 @@
|
|
25
25
|
<groupId>org.kill-bill.billing.plugin.ruby</groupId>
|
26
26
|
<artifactId>cybersource-plugin</artifactId>
|
27
27
|
<packaging>pom</packaging>
|
28
|
-
<version>5.0
|
28
|
+
<version>5.1.0</version>
|
29
29
|
<name>cybersource-plugin</name>
|
30
30
|
<url>http://github.com/killbill/killbill-cybersource-plugin</url>
|
31
31
|
<description>Plugin for accessing Cybersource as a payment gateway</description>
|
@@ -255,7 +255,7 @@ eos
|
|
255
255
|
eos
|
256
256
|
report = Killbill::Cybersource::CyberSourceOnDemand::CyberSourceOnDemandTransactionReport.new(xml_report, Logger.new(STDOUT))
|
257
257
|
response = report.response
|
258
|
-
response.success?.should
|
258
|
+
response.success?.should be_true
|
259
259
|
response.message.should == 'Score exceeds threshold. Score = 84'
|
260
260
|
response.params['merchantReferenceCode'].should == '1234'
|
261
261
|
response.params['requestID'].should == '2434465504100167904567'
|
@@ -7,13 +7,13 @@ describe Killbill::Cybersource::PaymentPlugin do
|
|
7
7
|
include ::Killbill::Plugin::ActiveMerchant::RSpec
|
8
8
|
|
9
9
|
before(:each) do
|
10
|
+
@plugin = build_plugin(::Killbill::Cybersource::PaymentPlugin, 'cybersource')
|
11
|
+
@plugin.start_plugin
|
12
|
+
|
10
13
|
::Killbill::Cybersource::CybersourcePaymentMethod.delete_all
|
11
14
|
::Killbill::Cybersource::CybersourceResponse.delete_all
|
12
15
|
::Killbill::Cybersource::CybersourceTransaction.delete_all
|
13
16
|
|
14
|
-
@plugin = build_plugin(::Killbill::Cybersource::PaymentPlugin, 'cybersource')
|
15
|
-
@plugin.start_plugin
|
16
|
-
|
17
17
|
@call_context = build_call_context
|
18
18
|
|
19
19
|
@properties = []
|
@@ -254,66 +254,126 @@ describe Killbill::Cybersource::PaymentPlugin do
|
|
254
254
|
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
255
255
|
end
|
256
256
|
|
257
|
-
|
258
|
-
|
259
|
-
|
257
|
+
shared_examples 'fix_undefined_payments' do
|
258
|
+
it 'should be able to fix UNDEFINED payments' do
|
259
|
+
payment_response = @plugin.purchase_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
260
|
+
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
260
261
|
|
261
|
-
|
262
|
-
|
263
|
-
response = Killbill::Cybersource::CybersourceResponse.last
|
264
|
-
response.update(:message => {:payment_plugin_status => 'UNDEFINED'}.to_json)
|
262
|
+
# Force a transition to :UNDEFINED
|
263
|
+
response, initial_auth = transition_last_response_to_UNDEFINED(1)
|
265
264
|
|
266
|
-
|
267
|
-
|
268
|
-
skip_gw.value = 'true'
|
269
|
-
properties_with_skip_gw = @properties.clone
|
270
|
-
properties_with_skip_gw << skip_gw
|
265
|
+
# Skip if the report API isn't configured
|
266
|
+
fix_transaction(0) if with_report_api
|
271
267
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
268
|
+
# Compare the state of the old and new response
|
269
|
+
check_old_new_response(response, :PURCHASE, 0, initial_auth)
|
270
|
+
|
271
|
+
break unless with_report_api
|
272
|
+
|
273
|
+
# Try a full refund
|
274
|
+
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)
|
275
|
+
check_response(refund_response, @amount, :REFUND, :PROCESSED, 'Successful transaction', '100')
|
276
|
+
|
277
|
+
# Force a transition to :UNDEFINED
|
278
|
+
response, initial_auth = transition_last_response_to_UNDEFINED(2)
|
279
|
+
|
280
|
+
fix_transaction(1)
|
281
|
+
|
282
|
+
# Compare the state of the old and new response
|
283
|
+
check_old_new_response(response, :REFUND, 1, initial_auth)
|
284
|
+
end
|
276
285
|
|
277
|
-
|
278
|
-
|
286
|
+
def transition_last_response_to_UNDEFINED(expected_nb_transactions)
|
287
|
+
Killbill::Cybersource::CybersourceTransaction.last.delete
|
288
|
+
response = Killbill::Cybersource::CybersourceResponse.last
|
289
|
+
initial_auth = response.authorization
|
290
|
+
response.update(:authorization => nil, :message => {:payment_plugin_status => 'UNDEFINED'}.to_json)
|
291
|
+
|
292
|
+
skip_gw = Killbill::Plugin::Model::PluginProperty.new
|
293
|
+
skip_gw.key = 'skip_gw'
|
294
|
+
skip_gw.value = 'true'
|
295
|
+
properties_with_skip_gw = @properties.clone
|
296
|
+
properties_with_skip_gw << skip_gw
|
297
|
+
|
298
|
+
# Set skip_gw=true, to avoid calling the report API
|
299
|
+
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_skip_gw, @call_context)
|
300
|
+
transaction_info_plugins.size.should == expected_nb_transactions
|
301
|
+
transaction_info_plugins.last.status.should eq(:UNDEFINED)
|
302
|
+
|
303
|
+
[response, initial_auth]
|
304
|
+
end
|
305
|
+
|
306
|
+
def fix_transaction(transaction_nb)
|
279
307
|
# The report API can be delayed
|
280
|
-
await
|
308
|
+
await do
|
309
|
+
!@plugin.get_single_transaction_report(report_api, @kb_payment.transactions[0].id, Time.now.utc).empty? ||
|
310
|
+
!@plugin.get_single_transaction_report(report_api, @kb_payment.transactions[0].external_key, Time.now.utc).empty?
|
311
|
+
end
|
281
312
|
|
282
|
-
#
|
313
|
+
# Plugin delay hasn't been reached yet
|
283
314
|
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, @properties, @call_context)
|
284
|
-
transaction_info_plugins.size.should == 1
|
285
|
-
transaction_info_plugins.
|
315
|
+
transaction_info_plugins.size.should == transaction_nb + 1
|
316
|
+
transaction_info_plugins.last.status.should eq(:UNDEFINED)
|
317
|
+
|
318
|
+
# Fix it
|
319
|
+
janitor_delay_threshold = Killbill::Plugin::Model::PluginProperty.new
|
320
|
+
janitor_delay_threshold.key = 'janitor_delay_threshold'
|
321
|
+
janitor_delay_threshold.value = '0'
|
322
|
+
properties_with_janitor_delay_threshold = @properties.clone
|
323
|
+
properties_with_janitor_delay_threshold << janitor_delay_threshold
|
324
|
+
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_janitor_delay_threshold, @call_context)
|
325
|
+
transaction_info_plugins.size.should == transaction_nb + 1
|
326
|
+
transaction_info_plugins.last.status.should eq(:PROCESSED)
|
286
327
|
|
287
328
|
# Set skip_gw=true, to check the local state
|
329
|
+
skip_gw = Killbill::Plugin::Model::PluginProperty.new
|
330
|
+
skip_gw.key = 'skip_gw'
|
331
|
+
skip_gw.value = 'true'
|
332
|
+
properties_with_skip_gw = @properties.clone
|
333
|
+
properties_with_skip_gw << skip_gw
|
288
334
|
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_skip_gw, @call_context)
|
289
|
-
transaction_info_plugins.size.should == 1
|
290
|
-
transaction_info_plugins.
|
335
|
+
transaction_info_plugins.size.should == transaction_nb + 1
|
336
|
+
transaction_info_plugins.last.status.should eq(:PROCESSED)
|
337
|
+
end
|
338
|
+
|
339
|
+
def check_old_new_response(response, transaction_type, transaction_nb, initial_auth)
|
340
|
+
new_response = Killbill::Cybersource::CybersourceResponse.last
|
341
|
+
new_response.id.should == response.id
|
342
|
+
new_response.api_call.should == transaction_type.to_s.downcase
|
343
|
+
new_response.kb_tenant_id.should == @call_context.tenant_id
|
344
|
+
new_response.kb_account_id.should == @pm.kb_account_id
|
345
|
+
new_response.kb_payment_id.should == @kb_payment.id
|
346
|
+
new_response.kb_payment_transaction_id.should == @kb_payment.transactions[transaction_nb].id
|
347
|
+
new_response.transaction_type.should == transaction_type.to_s
|
348
|
+
new_response.payment_processor_account_id.should == 'default'
|
349
|
+
# The report API doesn't give us the token
|
350
|
+
new_response.authorization.split(';')[0..1].should == initial_auth.split(';')[0..1] if with_report_api
|
351
|
+
new_response.test.should be_true
|
352
|
+
new_response.params_merchant_reference_code.should == response.params_merchant_reference_code
|
353
|
+
new_response.params_decision.should == response.params_decision
|
354
|
+
new_response.params_request_token.should == response.params_request_token
|
355
|
+
new_response.params_currency.should == response.params_currency
|
356
|
+
new_response.params_amount.should == response.params_amount
|
357
|
+
new_response.params_authorization_code.should == response.params_authorization_code
|
358
|
+
new_response.params_avs_code.should == response.params_avs_code
|
359
|
+
new_response.params_avs_code_raw.should == response.params_avs_code_raw
|
360
|
+
new_response.params_reconciliation_id.should == response.params_reconciliation_id
|
361
|
+
new_response.success.should be_true
|
362
|
+
new_response.message.should == (with_report_api ? 'Request was processed successfully.' : '{"payment_plugin_status":"UNDEFINED"}')
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
describe 'with on demand API' do
|
367
|
+
context 'using defaults' do
|
368
|
+
it_behaves_like 'fix_undefined_payments'
|
291
369
|
end
|
292
370
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
new_response.kb_payment_id.should == @kb_payment.id
|
300
|
-
new_response.kb_payment_transaction_id.should == @kb_payment.transactions[0].id
|
301
|
-
new_response.transaction_type.should == 'PURCHASE'
|
302
|
-
new_response.payment_processor_account_id.should == 'default'
|
303
|
-
# The report API doesn't give us the token
|
304
|
-
new_response.authorization.split(';')[0..1].should == response.authorization.split(';')[0..1]
|
305
|
-
new_response.test.should be_true
|
306
|
-
new_response.params_merchant_reference_code.should == response.params_merchant_reference_code
|
307
|
-
new_response.params_decision.should == response.params_decision
|
308
|
-
new_response.params_request_token.should == response.params_request_token
|
309
|
-
new_response.params_currency.should == response.params_currency
|
310
|
-
new_response.params_amount.should == response.params_amount
|
311
|
-
new_response.params_authorization_code.should == response.params_authorization_code
|
312
|
-
new_response.params_avs_code.should == response.params_avs_code
|
313
|
-
new_response.params_avs_code_raw.should == response.params_avs_code_raw
|
314
|
-
new_response.params_reconciliation_id.should == response.params_reconciliation_id
|
315
|
-
new_response.success.should be_true
|
316
|
-
new_response.message.should == (with_report_api ? 'Request was processed successfully.' : '{"payment_plugin_status":"UNDEFINED"}')
|
371
|
+
context 'using external_key_as_order_id' do
|
372
|
+
before do
|
373
|
+
@properties << build_property('external_key_as_order_id', true)
|
374
|
+
end
|
375
|
+
it_behaves_like 'fix_undefined_payments'
|
376
|
+
end
|
317
377
|
end
|
318
378
|
|
319
379
|
it 'should eventually cancel UNDEFINED payments' do
|
@@ -330,14 +390,20 @@ describe Killbill::Cybersource::PaymentPlugin do
|
|
330
390
|
skip_gw = Killbill::Plugin::Model::PluginProperty.new
|
331
391
|
skip_gw.key = 'skip_gw'
|
332
392
|
skip_gw.value = 'true'
|
333
|
-
|
334
|
-
|
335
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id,
|
393
|
+
properties_with_skip_gw = @properties.clone
|
394
|
+
properties_with_skip_gw << skip_gw
|
395
|
+
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_skip_gw, @call_context)
|
336
396
|
transaction_info_plugins.size.should == 1
|
337
397
|
transaction_info_plugins.first.status.should eq(:UNDEFINED)
|
338
398
|
|
399
|
+
janitor_delay_threshold = Killbill::Plugin::Model::PluginProperty.new
|
400
|
+
janitor_delay_threshold.key = 'janitor_delay_threshold'
|
401
|
+
janitor_delay_threshold.value = '0'
|
402
|
+
properties_with_janitor_delay_threshold = @properties.clone
|
403
|
+
properties_with_janitor_delay_threshold << janitor_delay_threshold
|
404
|
+
|
339
405
|
# Call the reporting API (if configured) and verify the state still cannot be fixed
|
340
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id,
|
406
|
+
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_janitor_delay_threshold, @call_context)
|
341
407
|
transaction_info_plugins.size.should == 1
|
342
408
|
transaction_info_plugins.first.status.should eq(:UNDEFINED)
|
343
409
|
|
@@ -348,7 +414,7 @@ describe Killbill::Cybersource::PaymentPlugin do
|
|
348
414
|
cancel_threshold = Killbill::Plugin::Model::PluginProperty.new
|
349
415
|
cancel_threshold.key = 'cancel_threshold'
|
350
416
|
cancel_threshold.value = '0'
|
351
|
-
properties_with_cancel_threshold =
|
417
|
+
properties_with_cancel_threshold = properties_with_janitor_delay_threshold.clone
|
352
418
|
properties_with_cancel_threshold << cancel_threshold
|
353
419
|
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_cancel_threshold, @call_context)
|
354
420
|
transaction_info_plugins.size.should == 1
|
data/spec/spec_helper.rb
CHANGED
@@ -12,11 +12,15 @@ RSpec.configure do |config|
|
|
12
12
|
config.formatter = 'documentation'
|
13
13
|
end
|
14
14
|
|
15
|
-
require 'active_record'
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
require defined?(JRUBY_VERSION) ? 'arjdbc' : 'active_record'
|
16
|
+
db_config = {
|
17
|
+
:adapter => ENV['AR_ADAPTER'] || 'sqlite3',
|
18
|
+
:database => ENV['AR_DATABASE'] || 'test.db',
|
19
|
+
}
|
20
|
+
db_config[:username] = ENV['AR_USERNAME'] if ENV['AR_USERNAME']
|
21
|
+
db_config[:password] = ENV['AR_PASSWORD'] if ENV['AR_PASSWORD']
|
22
|
+
ActiveRecord::Base.establish_connection(db_config)
|
23
|
+
|
20
24
|
# For debugging
|
21
25
|
#ActiveRecord::Base.logger = Logger.new(STDOUT)
|
22
26
|
# Create the schema
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: killbill-cybersource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0
|
4
|
+
version: 5.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kill Bill core team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -262,6 +262,20 @@ dependencies:
|
|
262
262
|
- - "~>"
|
263
263
|
- !ruby/object:Gem::Version
|
264
264
|
version: '1.1'
|
265
|
+
- !ruby/object:Gem::Dependency
|
266
|
+
requirement: !ruby/object:Gem::Requirement
|
267
|
+
requirements:
|
268
|
+
- - "~>"
|
269
|
+
- !ruby/object:Gem::Version
|
270
|
+
version: '9.4'
|
271
|
+
name: jdbc-postgres
|
272
|
+
prerelease: false
|
273
|
+
type: :development
|
274
|
+
version_requirements: !ruby/object:Gem::Requirement
|
275
|
+
requirements:
|
276
|
+
- - "~>"
|
277
|
+
- !ruby/object:Gem::Version
|
278
|
+
version: '9.4'
|
265
279
|
description: Kill Bill payment plugin for Cybersource.
|
266
280
|
email: killbilling-users@googlegroups.com
|
267
281
|
executables: []
|