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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e5adf0bd139aaa649c6648ee5f0c713eb9dcaab
4
- data.tar.gz: a6fc74fef61a79f9d87ee6ff08b2f47f2c37ade7
3
+ metadata.gz: ae2d49fdb4fd4bbe3b9be5e7b79ee0b14e12837a
4
+ data.tar.gz: 85d673ad015325da80051feb7bcaf67bbbcf243a
5
5
  SHA512:
6
- metadata.gz: 60715d504beab4ba7e4944f961d2c956d5fa2ed55303c54d3ae01ce0ba1e2e04cc96f0ccd20d9761099463e755e9ae6d103b33899c9b38b62172d78c30e4a80e
7
- data.tar.gz: 9fbae06da914dd66e685c318c35880163471c5a7512afbf26977303afd6935fd1d886675206ad8beca30dccf03ba3716633e8d5f3526a0fd27ff9bd068fb2eca
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.1)
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.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.3-java)
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.9.1)
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.6.8.1-java)
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.11.2
151
+ 1.14.3
data/NEWS CHANGED
@@ -1,3 +1,6 @@
1
+ 5.0.2
2
+ Change ddl to be compatible with postgresql
3
+
1
4
  5.0.1
2
5
  Re-use original payment processor by default when crediting
3
6
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 5.0.1
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: mysql
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 `cybersource_payment_methods` (
2
- `id` int(11) NOT NULL AUTO_INCREMENT,
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` tinyint(1) 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
- KEY `index_cybersource_payment_methods_on_kb_account_id` (`kb_account_id`),
30
- KEY `index_cybersource_payment_methods_on_kb_payment_method_id` (`kb_payment_method_id`)
31
- ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
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 `cybersource_transactions` (
34
- `id` int(11) NOT NULL AUTO_INCREMENT,
35
- `cybersource_response_id` int(11) 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(11) 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
- KEY `index_cybersource_transactions_on_kb_payment_id` (`kb_payment_id`),
50
- KEY `index_cybersource_transactions_on_cybersource_response_id` (`cybersource_response_id`)
51
- ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
52
-
53
- CREATE TABLE `cybersource_responses` (
54
- `id` int(11) NOT NULL AUTO_INCREMENT,
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
- `authorization` varchar(255) DEFAULT NULL,
62
- `fraud_review` tinyint(1) DEFAULT NULL,
63
- `test` tinyint(1) 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` 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
@@ -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
- authorization = find_value_from_properties(transaction_info_plugin.properties, 'authorization')
149
+ delay_since_transaction = now - report_date
150
+ delay_since_transaction = 0 if delay_since_transaction < 0
136
151
 
137
- order_id = Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :order_id)
138
- # authorization is very likely nil, as we didn't get an answer from the gateway in the first place
139
- order_id ||= authorization.split(';')[0] unless authorization.nil?
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(transaction_info_plugin.kb_transaction_payment_id, report_date, options, context)
145
- if report.nil?
146
- kb_transaction = get_kb_transaction(kb_payment_id, transaction_info_plugin.kb_transaction_payment_id, context.tenant_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 = (now - report_date) >= threshold
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
- # Assume the report contains a single request
152
- !report.nil? && !report['Requests'].nil? ? report['Requests']['Request'] : nil
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 &&= (application_reply['RCode'].to_s == '1')
167
- # Last message by convention
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.1</version>
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 be_false
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
- it 'should be able to fix UNDEFINED payments' do
258
- 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)
259
- check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
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
- # Force a transition to :UNDEFINED
262
- Killbill::Cybersource::CybersourceTransaction.last.delete
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
- skip_gw = Killbill::Plugin::Model::PluginProperty.new
267
- skip_gw.key = 'skip_gw'
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
- # Set skip_gw=true, to avoid calling the report API
273
- transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_skip_gw, @call_context)
274
- transaction_info_plugins.size.should == 1
275
- transaction_info_plugins.first.status.should eq(:UNDEFINED)
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
- # Skip if the report API isn't configured
278
- if with_report_api
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 { !@plugin.get_single_transaction_report(report_api, @kb_payment.transactions[0].id, Time.now.utc).empty? }
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
- # Fix it
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.first.status.should eq(:PROCESSED)
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.first.status.should eq(:PROCESSED)
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
- # Compare the state of the old and new response
294
- new_response = Killbill::Cybersource::CybersourceResponse.last
295
- new_response.id.should == response.id
296
- new_response.api_call.should == 'purchase'
297
- new_response.kb_tenant_id.should == @call_context.tenant_id
298
- new_response.kb_account_id.should == @pm.kb_account_id
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
- properties_with_cancel_threshold = @properties.clone
334
- properties_with_cancel_threshold << skip_gw
335
- transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_cancel_threshold, @call_context)
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, @properties, @call_context)
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 = @properties.clone
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
- ActiveRecord::Base.establish_connection(
17
- :adapter => 'sqlite3',
18
- :database => 'test.db'
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.1
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: 2016-11-29 00:00:00.000000000 Z
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: []