killbill-cybersource 5.2.0 → 5.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|