killbill-cybersource 5.0.1 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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: []