killbill-cybersource 5.2.0 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- metadata +1 -26
- data/.gitignore +0 -35
- data/.travis.yml +0 -41
- data/Gemfile +0 -4
- data/Gemfile.head +0 -5
- data/Gemfile.lock +0 -151
- data/Jarfile +0 -12
- data/Jarfile.lock +0 -66
- data/LICENSE +0 -201
- data/NEWS +0 -85
- data/README.md +0 -163
- data/Rakefile +0 -39
- data/VERSION +0 -1
- data/config.ru +0 -4
- data/cybersource.yml +0 -38
- data/db/ddl.sql +0 -92
- data/db/migrate/20162519092522_enlarge_message.rb +0 -11
- data/db/schema.rb +0 -94
- data/killbill-cybersource.gemspec +0 -53
- data/killbill.properties +0 -3
- data/pom.xml +0 -44
- data/release.sh +0 -61
- data/spec/cybersource/base_plugin_spec.rb +0 -465
- data/spec/cybersource/cyber_source_on_demand_spec.rb +0 -276
- data/spec/cybersource/remote/integration_spec.rb +0 -807
- data/spec/spec_helper.rb +0 -28
@@ -1,53 +0,0 @@
|
|
1
|
-
version = File.read(File.expand_path('../VERSION', __FILE__)).strip
|
2
|
-
|
3
|
-
Gem::Specification.new do |s|
|
4
|
-
s.name = 'killbill-cybersource'
|
5
|
-
s.version = version
|
6
|
-
s.summary = 'Plugin to use Cybersource as a gateway.'
|
7
|
-
s.description = 'Kill Bill payment plugin for Cybersource.'
|
8
|
-
|
9
|
-
s.required_ruby_version = '>= 1.9.3'
|
10
|
-
|
11
|
-
s.license = 'Apache License (2.0)'
|
12
|
-
|
13
|
-
s.author = 'Kill Bill core team'
|
14
|
-
s.email = 'killbilling-users@googlegroups.com'
|
15
|
-
s.homepage = 'http://killbill.io'
|
16
|
-
|
17
|
-
s.files = `git ls-files`.split("\n")
|
18
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
-
s.bindir = 'bin'
|
20
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
21
|
-
s.require_paths = ['lib']
|
22
|
-
|
23
|
-
s.rdoc_options << '--exclude' << '.'
|
24
|
-
|
25
|
-
s.add_dependency 'killbill', '~> 8.0'
|
26
|
-
|
27
|
-
s.add_dependency 'sinatra', '~> 1.3.4'
|
28
|
-
s.add_dependency 'thread_safe', '~> 0.3.4'
|
29
|
-
s.add_dependency 'activerecord', '~> 4.1.0'
|
30
|
-
if defined?(JRUBY_VERSION)
|
31
|
-
s.add_dependency 'activerecord-bogacs', '~> 0.3'
|
32
|
-
s.add_dependency 'activerecord-jdbc-adapter', '~> 1.3'
|
33
|
-
# Required to avoid errors like java.lang.NoClassDefFoundError: org/bouncycastle/asn1/DERBoolean
|
34
|
-
s.add_dependency 'jruby-openssl', '~> 0.9.6'
|
35
|
-
end
|
36
|
-
s.add_dependency 'actionpack', '~> 4.1.0'
|
37
|
-
s.add_dependency 'actionview', '~> 4.1.0'
|
38
|
-
s.add_dependency 'activemerchant', '~> 1.48.0'
|
39
|
-
s.add_dependency 'offsite_payments', '~> 2.1.0'
|
40
|
-
s.add_dependency 'monetize', '~> 1.1.0'
|
41
|
-
s.add_dependency 'money', '~> 6.5.1'
|
42
|
-
|
43
|
-
s.add_development_dependency 'jbundler', '~> 0.9.2'
|
44
|
-
s.add_development_dependency 'rake', '>= 10.0.0'
|
45
|
-
s.add_development_dependency 'rspec', '~> 2.12.0'
|
46
|
-
if defined?(JRUBY_VERSION)
|
47
|
-
s.add_development_dependency 'jdbc-sqlite3', '~> 3.7'
|
48
|
-
s.add_development_dependency 'jdbc-mariadb', '~> 1.1'
|
49
|
-
s.add_development_dependency 'jdbc-postgres', '~> 9.4'
|
50
|
-
else
|
51
|
-
s.add_development_dependency 'sqlite3', '~> 1.3.7'
|
52
|
-
end
|
53
|
-
end
|
data/killbill.properties
DELETED
data/pom.xml
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<!--
|
3
|
-
~ Copyright 2014-2015 The Billing Project, LLC
|
4
|
-
~
|
5
|
-
~ The Billing Project licenses this file to you under the Apache License, version 2.0
|
6
|
-
~ (the "License"); you may not use this file except in compliance with the
|
7
|
-
~ License. You may obtain a copy of the License at:
|
8
|
-
~
|
9
|
-
~ http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
~
|
11
|
-
~ Unless required by applicable law or agreed to in writing, software
|
12
|
-
~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
13
|
-
~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
14
|
-
~ License for the specific language governing permissions and limitations
|
15
|
-
~ under the License.
|
16
|
-
-->
|
17
|
-
|
18
|
-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
19
|
-
<parent>
|
20
|
-
<groupId>org.sonatype.oss</groupId>
|
21
|
-
<artifactId>oss-parent</artifactId>
|
22
|
-
<version>5</version>
|
23
|
-
</parent>
|
24
|
-
<modelVersion>4.0.0</modelVersion>
|
25
|
-
<groupId>org.kill-bill.billing.plugin.ruby</groupId>
|
26
|
-
<artifactId>cybersource-plugin</artifactId>
|
27
|
-
<packaging>pom</packaging>
|
28
|
-
<version>5.2.0</version>
|
29
|
-
<name>cybersource-plugin</name>
|
30
|
-
<url>http://github.com/killbill/killbill-cybersource-plugin</url>
|
31
|
-
<description>Plugin for accessing Cybersource as a payment gateway</description>
|
32
|
-
<licenses>
|
33
|
-
<license>
|
34
|
-
<name>Apache License 2.0</name>
|
35
|
-
<url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
|
36
|
-
<distribution>repo</distribution>
|
37
|
-
</license>
|
38
|
-
</licenses>
|
39
|
-
<scm>
|
40
|
-
<connection>scm:git:git://github.com/killbill/killbill-cybersource-plugin.git</connection>
|
41
|
-
<url>https://github.com/killbill/killbill-cybersource-plugin/</url>
|
42
|
-
<developerConnection>scm:git:git@github.com:killbill/killbill-cybersource-plugin.git</developerConnection>
|
43
|
-
</scm>
|
44
|
-
</project>
|
data/release.sh
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
set -e
|
2
|
-
|
3
|
-
BUNDLE=${BUNDLE-"bundle exec"}
|
4
|
-
MVN=${MVN-"mvn"}
|
5
|
-
|
6
|
-
if [ 'GNU' != "$(tar --help | grep GNU | head -1 | awk '{print $1}')" ]; then
|
7
|
-
echo 'Unable to release: make sure to use GNU tar'
|
8
|
-
exit 1
|
9
|
-
fi
|
10
|
-
|
11
|
-
if $(ruby -e'require "java"'); then
|
12
|
-
# Good
|
13
|
-
echo 'Detected JRuby'
|
14
|
-
else
|
15
|
-
echo 'Unable to release: make sure to use JRuby'
|
16
|
-
exit 1
|
17
|
-
fi
|
18
|
-
|
19
|
-
VERSION=`grep -E '<version>([0-9]+\.[0-9]+\.[0-9]+)</version>' pom.xml | sed 's/[\t \n]*<version>\(.*\)<\/version>[\t \n]*/\1/'`
|
20
|
-
if [[ -z "$NO_RELEASE" && "$VERSION" != "$(cat $PWD/VERSION)" ]]; then
|
21
|
-
echo 'Unable to release: make sure the versions in pom.xml and VERSION match'
|
22
|
-
exit 1
|
23
|
-
fi
|
24
|
-
|
25
|
-
echo 'Cleaning up'
|
26
|
-
$BUNDLE rake killbill:clean
|
27
|
-
|
28
|
-
echo 'Building gem'
|
29
|
-
$BUNDLE rake build
|
30
|
-
|
31
|
-
if [[ -z "$NO_RELEASE" ]]; then
|
32
|
-
echo 'Pushing the gem to Rubygems'
|
33
|
-
$BUNDLE rake release
|
34
|
-
fi
|
35
|
-
|
36
|
-
echo 'Building artifact'
|
37
|
-
$BUNDLE rake killbill:package
|
38
|
-
|
39
|
-
ARTIFACT="$PWD/pkg/killbill-cybersource-$VERSION.tar.gz"
|
40
|
-
echo "Pushing $ARTIFACT to Maven Central"
|
41
|
-
|
42
|
-
if [[ -z "$NO_RELEASE" ]]; then
|
43
|
-
GOAL=gpg:sign-and-deploy-file
|
44
|
-
REPOSITORY_ID=ossrh-releases
|
45
|
-
URL=https://oss.sonatype.org/service/local/staging/deploy/maven2/
|
46
|
-
else
|
47
|
-
GOAL=deploy:deploy-file
|
48
|
-
REPOSITORY_ID=sonatype-nexus-snapshots
|
49
|
-
URL=https://oss.sonatype.org/content/repositories/snapshots/
|
50
|
-
VERSION="$VERSION-SNAPSHOT"
|
51
|
-
fi
|
52
|
-
|
53
|
-
$MVN $GOAL \
|
54
|
-
-DgroupId=org.kill-bill.billing.plugin.ruby \
|
55
|
-
-DartifactId=cybersource-plugin \
|
56
|
-
-Dversion=$VERSION \
|
57
|
-
-Dpackaging=tar.gz \
|
58
|
-
-DrepositoryId=$REPOSITORY_ID \
|
59
|
-
-Durl=$URL \
|
60
|
-
-Dfile=$ARTIFACT \
|
61
|
-
-DpomFile=pom.xml
|
@@ -1,465 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Killbill::Cybersource::PaymentPlugin do
|
4
|
-
|
5
|
-
include ::Killbill::Plugin::ActiveMerchant::RSpec
|
6
|
-
|
7
|
-
before(:each) do
|
8
|
-
Dir.mktmpdir do |dir|
|
9
|
-
file = File.new(File.join(dir, 'cybersource.yml'), 'w+')
|
10
|
-
file.write(<<-eos)
|
11
|
-
:cybersource:
|
12
|
-
:test: true
|
13
|
-
# As defined by spec_helper.rb
|
14
|
-
:database:
|
15
|
-
:adapter: 'sqlite3'
|
16
|
-
:database: 'test.db'
|
17
|
-
eos
|
18
|
-
file.close
|
19
|
-
|
20
|
-
@plugin = build_plugin(::Killbill::Cybersource::PaymentPlugin, 'cybersource', File.dirname(file))
|
21
|
-
|
22
|
-
# Start the plugin here - since the config file will be deleted
|
23
|
-
@plugin.start_plugin
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
let(:expected_successful_params) do
|
28
|
-
{
|
29
|
-
:params_merchant_reference_code => 'b0a6cf9aa07f1a8495f89c364bbd6a9a',
|
30
|
-
:params_request_id => '2004333231260008401927',
|
31
|
-
:params_decision => 'ACCEPT',
|
32
|
-
:params_reason_code => '100',
|
33
|
-
:params_request_token => 'Afvvj7Ke2Fmsbq0wHFE2sM6R4GAptYZ0jwPSA+R9PhkyhFTb0KRjoE4+ynthZrG6tMBwjAtT',
|
34
|
-
:params_currency => 'USD',
|
35
|
-
:params_amount => '1.00',
|
36
|
-
:params_authorization_code => '123456',
|
37
|
-
:params_avs_code => 'Y',
|
38
|
-
:params_avs_code_raw => 'Y',
|
39
|
-
:params_cv_code => 'M',
|
40
|
-
:params_authorized_date_time => '2008-01-15T21:42:03Z',
|
41
|
-
:params_processor_response => '00',
|
42
|
-
:params_reconciliation_id => 'ABCDEF',
|
43
|
-
:params_subscription_id => 'XXYYZZ'
|
44
|
-
}
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'should start and stop correctly' do
|
48
|
-
@plugin.stop_plugin
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'should detect when to credit refunds' do
|
52
|
-
context = build_call_context
|
53
|
-
kb_payment_id = SecureRandom.uuid
|
54
|
-
|
55
|
-
@plugin.should_credit?(SecureRandom.uuid, context).should be_false
|
56
|
-
|
57
|
-
with_transaction(kb_payment_id, :AUTHORIZE, 60.days.ago, build_call_context(SecureRandom.uuid)) { @plugin.should_credit?(kb_payment_id, context).should be_false }
|
58
|
-
with_transaction(kb_payment_id, :AUTHORIZE, 59.days.ago, context) { @plugin.should_credit?(kb_payment_id, context).should be_false }
|
59
|
-
with_transaction(kb_payment_id, :VOID, 60.days.ago, context) { @plugin.should_credit?(kb_payment_id, context).should be_false }
|
60
|
-
with_transaction(SecureRandom.uuid, :AUTHORIZE, 60.days.ago, context) { @plugin.should_credit?(kb_payment_id, context).should be_false }
|
61
|
-
|
62
|
-
with_transaction(kb_payment_id, :AUTHORIZE, 61.days.ago, context) do
|
63
|
-
@plugin.should_credit?(kb_payment_id, context, {:disable_auto_credit => true}).should be_false
|
64
|
-
@plugin.should_credit?(kb_payment_id, context, {:auto_credit_threshold => 61 * 86400 + 3600 + 10}).should be_false
|
65
|
-
|
66
|
-
options = {}
|
67
|
-
@plugin.should_credit?(kb_payment_id, context, options).should be_true
|
68
|
-
options[:payment_processor_account_id].should == 'GOOD'
|
69
|
-
|
70
|
-
options = {:payment_processor_account_id => 'OVERRIDDEN'}
|
71
|
-
@plugin.should_credit?(kb_payment_id, context, options).should be_true
|
72
|
-
options[:payment_processor_account_id].should == 'OVERRIDDEN'
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
context 'Business Rules' do
|
77
|
-
|
78
|
-
it 'does not ignore AVS nor CVN' do
|
79
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |host, request_body|
|
80
|
-
request_body.should_not match('<ignoreAVSResult>')
|
81
|
-
request_body.should_not match('<ignoreCVResult>')
|
82
|
-
successful_purchase_response
|
83
|
-
end
|
84
|
-
purchase_with_token(:PROCESSED, [], expected_successful_params)
|
85
|
-
purchase_with_token(:PROCESSED, [build_property('ignore_avs', 'false'), build_property('ignore_cvv', 'false')], expected_successful_params)
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'ignores AVS and CVN' do
|
89
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |host, request_body|
|
90
|
-
request_body.should match('<ignoreAVSResult>')
|
91
|
-
request_body.should match('<ignoreCVResult>')
|
92
|
-
successful_purchase_response
|
93
|
-
end
|
94
|
-
purchase_with_token(:PROCESSED, [build_property('ignore_avs', 'true'), build_property('ignore_cvv', 'true')], expected_successful_params)
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'ignores AVS but not CVN' do
|
98
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |host, request_body|
|
99
|
-
request_body.should match('<ignoreAVSResult>')
|
100
|
-
request_body.should_not match('<ignoreCVResult>')
|
101
|
-
successful_purchase_response
|
102
|
-
end
|
103
|
-
purchase_with_token(:PROCESSED, [build_property('ignore_avs', 'true')], expected_successful_params)
|
104
|
-
purchase_with_token(:PROCESSED, [build_property('ignore_avs', 'true'), build_property('ignore_cvv', 'false')], expected_successful_params)
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'ignores CVN but not AVS' do
|
108
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |host, request_body|
|
109
|
-
request_body.should_not match('<ignoreAVSResult>')
|
110
|
-
request_body.should match('<ignoreCVResult>')
|
111
|
-
successful_purchase_response
|
112
|
-
end
|
113
|
-
purchase_with_token(:PROCESSED, [build_property('ignore_cvv', 'true')], expected_successful_params)
|
114
|
-
purchase_with_token(:PROCESSED, [build_property('ignore_avs', 'false'), build_property('ignore_cvv', 'true')], expected_successful_params)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
context 'Override parameters' do
|
119
|
-
|
120
|
-
it 'has a default commerceIndicator' do
|
121
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |host, request_body|
|
122
|
-
request_body.should_not match('<commerceIndicator>')
|
123
|
-
successful_purchase_response
|
124
|
-
end
|
125
|
-
purchase_with_token(:PROCESSED, [], expected_successful_params)
|
126
|
-
end
|
127
|
-
|
128
|
-
it 'can override commerceIndicator for card-on-file' do
|
129
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |host, request_body|
|
130
|
-
request_body.should match('<commerceIndicator>recurring</commerceIndicator>')
|
131
|
-
successful_purchase_response
|
132
|
-
end
|
133
|
-
purchase_with_card(:PROCESSED, [build_property('commerce_indicator', 'recurring')], expected_successful_params)
|
134
|
-
end
|
135
|
-
|
136
|
-
it 'has a default commerceIndicator for Apple Pay' do
|
137
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |host, request_body|
|
138
|
-
request_body.should_not match('<commerceIndicator>internet</commerceIndicator>')
|
139
|
-
request_body.should match('<commerceIndicator>vbv</commerceIndicator>')
|
140
|
-
successful_purchase_response
|
141
|
-
end
|
142
|
-
purchase_with_network_tokenization(:PROCESSED, [], expected_successful_params)
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'can override commerceIndicator for Apple Pay' do
|
146
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |host, request_body|
|
147
|
-
request_body.should_not match('<commerceIndicator>vbv</commerceIndicator>')
|
148
|
-
request_body.should match('<commerceIndicator>internet</commerceIndicator>')
|
149
|
-
successful_purchase_response
|
150
|
-
end
|
151
|
-
purchase_with_network_tokenization(:PROCESSED, [build_property('commerce_indicator', 'internet')], expected_successful_params)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
context 'Errors handling' do
|
156
|
-
|
157
|
-
it 'handles proxy errors as UNDEFINED transactions' do
|
158
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |_, _|
|
159
|
-
raise ::ActiveMerchant::ResponseError.new(OpenStruct.new(:body => 'Oops', :code => 502))
|
160
|
-
end
|
161
|
-
purchase_with_token(:UNDEFINED).gateway_error.should == 'Failed with 502 '
|
162
|
-
end
|
163
|
-
|
164
|
-
it 'handles generic 500 errors as UNDEFINED transactions' do
|
165
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |_, _|
|
166
|
-
raise ::ActiveMerchant::ResponseError.new(OpenStruct.new(:body => nil, :code => 500))
|
167
|
-
end
|
168
|
-
purchase_with_token(:UNDEFINED).gateway_error.should == 'Failed with 500 '
|
169
|
-
end
|
170
|
-
|
171
|
-
it 'handles CyberSource errors as CANCELED transactions' do
|
172
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |_, _|
|
173
|
-
raise ::ActiveMerchant::ResponseError.new(OpenStruct.new(:body => one_or_more_fields_contains_invalid_data, :code => 500))
|
174
|
-
end
|
175
|
-
purchase_with_token(:CANCELED).gateway_error.should == 'One or more fields contains invalid data'
|
176
|
-
end
|
177
|
-
|
178
|
-
it 'handles expired passwords as CANCELED transactions' do
|
179
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post).and_return(password_expired_response)
|
180
|
-
purchase_with_token(:CANCELED).gateway_error.should == 'wsse:FailedCheck: Security Data : Merchant password has expired.'
|
181
|
-
end
|
182
|
-
|
183
|
-
it 'handles bad passwords as CANCELED transactions' do
|
184
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post).and_return(bad_password_response)
|
185
|
-
purchase_with_token(:CANCELED).gateway_error.should == 'wsse:FailedCheck: Security Data : UsernameToken authentication failed.'
|
186
|
-
end
|
187
|
-
|
188
|
-
it 'handles unsuccessful authorizations as ERROR transactions' do
|
189
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post).and_return(unsuccessful_authorization_response)
|
190
|
-
purchase_with_token(:ERROR).gateway_error.should == 'Invalid account number'
|
191
|
-
end
|
192
|
-
|
193
|
-
it 'parses correctly authorization reversal errors' do
|
194
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post).and_return(unsuccessful_auth_reversal_response)
|
195
|
-
payment_response = purchase_with_token(:CANCELED)
|
196
|
-
payment_response.gateway_error.should == 'One or more fields contains invalid data'
|
197
|
-
payment_response.gateway_error_code.should == '102'
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'cancels UNDEFINED transactions with a JSON message' do
|
201
|
-
response = Killbill::Cybersource::CybersourceResponse.create(:api_call => 'authorization',
|
202
|
-
:message => '{"exception_message":"Timeout","payment_plugin_status":"UNDEFINED"}',
|
203
|
-
:created_at => Time.now,
|
204
|
-
:updated_at => Time.now)
|
205
|
-
response.cancel
|
206
|
-
response.message.should == '{"exception_message":"Timeout","payment_plugin_status":"CANCELED"}'
|
207
|
-
end
|
208
|
-
|
209
|
-
it 'cancels UNDEFINED transactions with a plain test message' do
|
210
|
-
response = Killbill::Cybersource::CybersourceResponse.create(:api_call => 'authorization',
|
211
|
-
:message => 'Internal error',
|
212
|
-
:created_at => Time.now,
|
213
|
-
:updated_at => Time.now)
|
214
|
-
response.cancel
|
215
|
-
response.message.should == '{"original_message":"Internal error","payment_plugin_status":"CANCELED"}'
|
216
|
-
end
|
217
|
-
|
218
|
-
it 'cancels UNDEFINED transactions with no message' do
|
219
|
-
response = Killbill::Cybersource::CybersourceResponse.create(:api_call => 'authorization',
|
220
|
-
:created_at => Time.now,
|
221
|
-
:updated_at => Time.now)
|
222
|
-
response.cancel
|
223
|
-
response.message.should == '{"payment_plugin_status":"CANCELED"}'
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def stub_gateway_for_invoice_header(invoice_match_status)
|
228
|
-
::ActiveMerchant::Billing::CyberSourceGateway.any_instance.stub(:ssl_post) do |host, request_body|
|
229
|
-
case(invoice_match_status)
|
230
|
-
when :none
|
231
|
-
request_body.should_not match('<invoiceHeader>')
|
232
|
-
when :all
|
233
|
-
request_body.should match('<invoiceHeader>\n <merchantDescriptor>Ray Qiu </merchantDescriptor>\n <merchantDescriptorContact>650-888-3161</merchantDescriptorContact>\n </invoiceHeader>')
|
234
|
-
when :except_authorize
|
235
|
-
if request_body.index('ccAuthService').present?
|
236
|
-
request_body.should_not match('<invoiceHeader>\n <amexDataTAA1>Ray Qiu</amexDataTAA1>\n <amexDataTAA2>6508883161</amexDataTAA2>')
|
237
|
-
else
|
238
|
-
request_body.should match('<invoiceHeader>\n <amexDataTAA1>Ray Qiu</amexDataTAA1>\n <amexDataTAA2>6508883161</amexDataTAA2>')
|
239
|
-
end
|
240
|
-
end
|
241
|
-
successful_purchase_response
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
shared_examples 'full payment' do
|
246
|
-
before do
|
247
|
-
send(add_payment_properties, txn_properties, card_type)
|
248
|
-
stub_gateway_for_invoice_header(invoice_match_status)
|
249
|
-
end
|
250
|
-
|
251
|
-
it 'should met expectations' do
|
252
|
-
auth_responses = create_transaction(card_type, :authorize, nil, :PROCESSED, txn_properties, expected_successful_params)
|
253
|
-
capture_responses = create_transaction(card_type, :capture, auth_responses, :PROCESSED, txn_properties, expected_successful_params)
|
254
|
-
create_transaction(card_type, :refund, capture_responses, :PROCESSED, txn_properties, expected_successful_params)
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
shared_examples 'invoice header example' do
|
259
|
-
let(:card_type){ :visa }
|
260
|
-
let(:txn_properties){ [] }
|
261
|
-
|
262
|
-
context 'while no descriptor provided' do
|
263
|
-
let(:invoice_match_status){ :none }
|
264
|
-
|
265
|
-
context 'visa' do
|
266
|
-
it_behaves_like 'full payment'
|
267
|
-
end
|
268
|
-
|
269
|
-
context 'amex' do
|
270
|
-
let(:card_type){ :amex }
|
271
|
-
it_behaves_like 'full payment'
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
context 'while descriptor provided' do
|
276
|
-
before{ txn_properties << build_property('merchant_descriptor', {"name"=>"Ray Qiu", "contact"=>"6508883161"}.to_json) }
|
277
|
-
|
278
|
-
context 'visa' do
|
279
|
-
let(:invoice_match_status){ :all }
|
280
|
-
it_behaves_like 'full payment'
|
281
|
-
end
|
282
|
-
|
283
|
-
context 'amex' do
|
284
|
-
let(:card_type){ :amex }
|
285
|
-
let(:invoice_match_status){ :except_authorize }
|
286
|
-
it_behaves_like 'full payment'
|
287
|
-
end
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
context 'Invoice Header' do
|
292
|
-
context 'payments with card' do
|
293
|
-
let(:add_payment_properties){ :add_card_property }
|
294
|
-
it_behaves_like 'invoice header example'
|
295
|
-
end
|
296
|
-
|
297
|
-
context 'payments with network tokenization' do
|
298
|
-
let(:add_payment_properties){ :add_network_tokenization_properties }
|
299
|
-
it_behaves_like 'invoice header example'
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
private
|
304
|
-
|
305
|
-
def with_transaction(kb_payment_id, transaction_type, created_at, context)
|
306
|
-
t = ::Killbill::Cybersource::CybersourceTransaction.create(:kb_payment_id => kb_payment_id,
|
307
|
-
:transaction_type => transaction_type,
|
308
|
-
:kb_tenant_id => context.tenant_id,
|
309
|
-
:created_at => created_at,
|
310
|
-
:payment_processor_account_id => 'GOOD',
|
311
|
-
# The data below doesn't matter
|
312
|
-
:updated_at => created_at,
|
313
|
-
:kb_account_id => SecureRandom.uuid,
|
314
|
-
:kb_payment_transaction_id => SecureRandom.uuid,
|
315
|
-
:api_call => :refund,
|
316
|
-
:cybersource_response_id => 1)
|
317
|
-
t.should_not be_nil
|
318
|
-
yield t if block_given?
|
319
|
-
ensure
|
320
|
-
t.destroy! unless t.nil?
|
321
|
-
end
|
322
|
-
|
323
|
-
def add_card_property(properties, card_type = :visa)
|
324
|
-
properties << build_property('email', 'foo@bar.com')
|
325
|
-
if card_type == :amex
|
326
|
-
properties << build_property('cc_number', '378282246310005')
|
327
|
-
else
|
328
|
-
properties << build_property('cc_number', '4111111111111111')
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
def add_token_property(properties)
|
333
|
-
properties << build_property('email', 'foo@bar.com')
|
334
|
-
properties << build_property('token', '1234')
|
335
|
-
end
|
336
|
-
|
337
|
-
def add_network_tokenization_properties(properties, card_type = :visa)
|
338
|
-
if card_type == :amex
|
339
|
-
properties << build_property('cc_number', '378282246310005')
|
340
|
-
properties << build_property('brand', 'american_express')
|
341
|
-
properties << build_property('payment_cryptogram', Base64.encode64('111111111100cryptogram'))
|
342
|
-
else
|
343
|
-
properties << build_property('cc_number', '4111111111111111')
|
344
|
-
properties << build_property('brand', 'visa')
|
345
|
-
properties << build_property('payment_cryptogram', '111111111100cryptogram')
|
346
|
-
end
|
347
|
-
properties << build_property('email', 'foo@bar.com')
|
348
|
-
properties << build_property('eci', '05')
|
349
|
-
end
|
350
|
-
|
351
|
-
def purchase_with_card(expected_status = :PROCESSED, properties = [], expected_params = {})
|
352
|
-
add_card_property(properties)
|
353
|
-
purchase(expected_status, properties, expected_params)
|
354
|
-
end
|
355
|
-
|
356
|
-
def purchase_with_token(expected_status = :PROCESSED, properties = [], expected_params = {})
|
357
|
-
add_token_property(properties)
|
358
|
-
purchase(expected_status, properties, expected_params)
|
359
|
-
end
|
360
|
-
|
361
|
-
def purchase_with_network_tokenization(expected_status = :PROCESSED, properties = [], expected_params = {})
|
362
|
-
add_network_tokenization_properties(properties)
|
363
|
-
purchase(expected_status, properties, expected_params)
|
364
|
-
end
|
365
|
-
|
366
|
-
def verify_response(payment_response, expected_status, expected_params)
|
367
|
-
payment_response.status.should eq(expected_status), payment_response.gateway_error
|
368
|
-
|
369
|
-
gw_response = Killbill::Cybersource::CybersourceResponse.last
|
370
|
-
expected_params.each do |k, v|
|
371
|
-
gw_response.send(k.to_sym).should == v
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
def create_transaction(card_type = :visa, txn_type = :authorize, previous_response = nil, expected_status = :PROCESSED, properties = [], expected_params = {})
|
376
|
-
if txn_type == :authorize
|
377
|
-
authorize(expected_status, properties, expected_params)
|
378
|
-
else
|
379
|
-
previous_response.shift
|
380
|
-
send(txn_type, *previous_response, expected_status, properties, expected_params)
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
def authorize(expected_status = :PROCESSED, properties = [], expected_params = {})
|
385
|
-
kb_account_id = SecureRandom.uuid
|
386
|
-
kb_payment_method_id = SecureRandom.uuid
|
387
|
-
kb_payment_id = SecureRandom.uuid
|
388
|
-
kb_payment = @plugin.kb_apis.proxied_services[:payment_api].add_payment(kb_payment_id)
|
389
|
-
kb_transaction_id = kb_payment.transactions[0].id
|
390
|
-
|
391
|
-
payment_response = @plugin.authorize_payment(kb_account_id, kb_payment_id, kb_transaction_id, kb_payment_method_id, BigDecimal.new('100'), 'USD', properties, build_call_context)
|
392
|
-
verify_response(payment_response, expected_status, expected_params)
|
393
|
-
return payment_response, kb_account_id, kb_payment_id, kb_transaction_id, kb_payment_method_id
|
394
|
-
end
|
395
|
-
|
396
|
-
def capture(kb_account_id, kb_payment_id, kb_transaction_id, kb_payment_method_id, expected_status = :PROCESSED, properties = [], expected_params = {})
|
397
|
-
payment_response = @plugin.capture_payment(kb_account_id, kb_payment_id, kb_transaction_id, kb_payment_method_id, BigDecimal.new('100'), 'USD', properties, build_call_context)
|
398
|
-
verify_response(payment_response, expected_status, expected_params)
|
399
|
-
return payment_response, kb_account_id, kb_payment_id, kb_transaction_id, kb_payment_method_id
|
400
|
-
end
|
401
|
-
|
402
|
-
def refund(kb_account_id, kb_payment_id, kb_transaction_id, kb_payment_method_id, expected_status = :PROCESSED, properties = [], expected_params = {})
|
403
|
-
payment_response = @plugin.refund_payment(kb_account_id, kb_payment_id, kb_transaction_id, kb_payment_method_id, BigDecimal.new('100'), 'USD', properties, build_call_context)
|
404
|
-
verify_response(payment_response, expected_status, expected_params)
|
405
|
-
return payment_response, kb_account_id, kb_payment_id, kb_transaction_id, kb_payment_method_id
|
406
|
-
end
|
407
|
-
|
408
|
-
def purchase(expected_status = :PROCESSED, properties = [], expected_params = {})
|
409
|
-
kb_payment_id = SecureRandom.uuid
|
410
|
-
kb_payment = @plugin.kb_apis.proxied_services[:payment_api].add_payment(kb_payment_id)
|
411
|
-
kb_transaction_id = kb_payment.transactions[0].id
|
412
|
-
|
413
|
-
payment_response = @plugin.purchase_payment(SecureRandom.uuid, kb_payment_id, kb_transaction_id, SecureRandom.uuid, BigDecimal.new('100'), 'USD', properties, build_call_context)
|
414
|
-
verify_response(payment_response, expected_status, expected_params)
|
415
|
-
payment_response
|
416
|
-
end
|
417
|
-
|
418
|
-
def successful_purchase_response
|
419
|
-
<<-XML
|
420
|
-
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
421
|
-
<soap:Header>
|
422
|
-
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-2636690"><wsu:Created>2008-01-15T21:42:03.343Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><c:replyMessage xmlns:c="urn:schemas-cybersource-com:transaction-data-1.26"><c:merchantReferenceCode>b0a6cf9aa07f1a8495f89c364bbd6a9a</c:merchantReferenceCode><c:requestID>2004333231260008401927</c:requestID><c:decision>ACCEPT</c:decision><c:reasonCode>100</c:reasonCode><c:requestToken>Afvvj7Ke2Fmsbq0wHFE2sM6R4GAptYZ0jwPSA+R9PhkyhFTb0KRjoE4+ynthZrG6tMBwjAtT</c:requestToken><c:purchaseTotals><c:currency>USD</c:currency></c:purchaseTotals><c:ccAuthReply><c:reasonCode>100</c:reasonCode><c:amount>1.00</c:amount><c:authorizationCode>123456</c:authorizationCode><c:avsCode>Y</c:avsCode><c:avsCodeRaw>Y</c:avsCodeRaw><c:cvCode>M</c:cvCode><c:cvCodeRaw>M</c:cvCodeRaw><c:authorizedDateTime>2008-01-15T21:42:03Z</c:authorizedDateTime><c:processorResponse>00</c:processorResponse><c:reconciliationID>ABCDEF</c:reconciliationID><c:authFactorCode>U</c:authFactorCode></c:ccAuthReply><c:paySubscriptionCreateReply><c:reasonCode>100</c:reasonCode><c:subscriptionID>XXYYZZ</c:subscriptionID></c:paySubscriptionCreateReply></c:replyMessage></soap:Body></soap:Envelope>
|
423
|
-
XML
|
424
|
-
end
|
425
|
-
|
426
|
-
def password_expired_response
|
427
|
-
<<-XML
|
428
|
-
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
429
|
-
<soap:Header>
|
430
|
-
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-2636690"><wsu:Created>2008-01-15T21:42:03.343Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><soap:Fault xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:c="urn:schemas-cybersource-com:transaction-data-1.0"><faultcode>wsse:FailedCheck</faultcode><faultstring>Security Data : Merchant password has expired.</faultstring></soap:Fault></soap:Body></soap:Envelope>
|
431
|
-
XML
|
432
|
-
end
|
433
|
-
|
434
|
-
def bad_password_response
|
435
|
-
<<-XML
|
436
|
-
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
437
|
-
<soap:Header>
|
438
|
-
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-2636690"><wsu:Created>2008-01-15T21:42:03.343Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><soap:Fault xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:c="urn:schemas-cybersource-com:transaction-data-1.0"><faultcode>wsse:FailedCheck</faultcode><faultstring>Security Data : UsernameToken authentication failed.</faultstring></soap:Fault></soap:Body></soap:Envelope>
|
439
|
-
XML
|
440
|
-
end
|
441
|
-
|
442
|
-
def unsuccessful_authorization_response
|
443
|
-
<<-XML
|
444
|
-
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
445
|
-
<soap:Header>
|
446
|
-
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-28121162"><wsu:Created>2008-01-15T21:50:41.580Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><c:replyMessage xmlns:c="urn:schemas-cybersource-com:transaction-data-1.26"><c:merchantReferenceCode>a1efca956703a2a5037178a8a28f7357</c:merchantReferenceCode><c:requestID>2004338415330008402434</c:requestID><c:decision>REJECT</c:decision><c:reasonCode>231</c:reasonCode><c:requestToken>Afvvj7KfIgU12gooCFE2/DanQIApt+G1OgTSA+R9PTnyhFTb0KRjgFY+ynyIFNdoKKAghwgx</c:requestToken><c:ccAuthReply><c:reasonCode>231</c:reasonCode></c:ccAuthReply></c:replyMessage></soap:Body></soap:Envelope>
|
447
|
-
XML
|
448
|
-
end
|
449
|
-
|
450
|
-
def unsuccessful_auth_reversal_response
|
451
|
-
<<-XML
|
452
|
-
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
453
|
-
<soap:Header>
|
454
|
-
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-28121162"><wsu:Created>2008-01-15T21:50:41.580Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><c:replyMessage xmlns:c="urn:schemas-cybersource-com:transaction-data-1.26"><c:merchantReferenceCode>a1efca956703a2a5037178a8a28f7357</c:merchantReferenceCode><c:requestID>2004338415330008402434</c:requestID><c:decision>REJECT</c:decision><c:reasonCode>102</c:reasonCode><c:requestToken>Afvvj7KfIgU12gooCFE2/DanQIApt+G1OgTSA+R9PTnyhFTb0KRjgFY+ynyIFNdoKKAghwgx</c:requestToken><c:ccAuthReversalReply><c:reasonCode>102</c:reasonCode></c:ccAuthReversalReply><c:originalTransaction><c:amount>0.00</c:amount><c:reasonCode>100</c:reasonCode></c:originalTransaction></c:replyMessage></soap:Body></soap:Envelope>
|
455
|
-
XML
|
456
|
-
end
|
457
|
-
|
458
|
-
def one_or_more_fields_contains_invalid_data
|
459
|
-
<<-XML
|
460
|
-
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
461
|
-
<soap:Header>
|
462
|
-
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-28121162"><wsu:Created>2008-01-15T21:50:41.580Z</wsu:Created></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><c:replyMessage xmlns:c="urn:schemas-cybersource-com:transaction-data-1.26"><c:requestID>12345</c:requestID><c:decision>REJECT</c:decision><c:reasonCode>102</c:reasonCode><c:invalidField>c:billTo/c:state</c:invalidField><c:requestToken>Afvvj7KfIgU12gooCFE2/DanQIApt+G1OgTSA+R9PTnyhFTb0KRjgFY+ynyIFNdoKKAghwgx</c:requestToken></c:replyMessage></soap:Body></soap:Envelope>
|
463
|
-
XML
|
464
|
-
end
|
465
|
-
end
|