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,276 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Killbill::Cybersource::CyberSourceOnDemand do
|
4
|
-
|
5
|
-
it 'parses a transaction detail report with a single ApplicationReply correctly' do
|
6
|
-
xml_report = <<eos
|
7
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
8
|
-
<!DOCTYPE Report SYSTEM "https://ebctest.cybersource.com/ebctest/reports/dtd/tdr_1_3.dtd">
|
9
|
-
<Report xmlns="https://ebctest.cybersource.com/ebctest/reports/dtd/tdr_1_3.dtd"
|
10
|
-
Name="Transaction Detail"
|
11
|
-
Version="1.3"
|
12
|
-
MerchantID="testMerchant"
|
13
|
-
ReportStartDate="2008-09-10 21:46:41.765-08:00"
|
14
|
-
ReportEndDate="2008-09-10 21:46:41.765-08:00">
|
15
|
-
<Requests>
|
16
|
-
<Request MerchantReferenceNumber="33038191"
|
17
|
-
RequestDate="2008-09-10T14:00:08-08:00"
|
18
|
-
RequestID="2210804330010167904567"
|
19
|
-
SubscriptionID=""
|
20
|
-
Source="SCMP API"
|
21
|
-
User="merchant123"
|
22
|
-
TransactionReferenceNumber="0001094522"
|
23
|
-
PredecessorRequestID="7904567221330010160804">
|
24
|
-
<BillTo>
|
25
|
-
<FirstName>JANE</FirstName>
|
26
|
-
<LastName>Smith</LastName>
|
27
|
-
<Address1>1295 Charleston Rd</Address1>
|
28
|
-
<Address2>Suite 2</Address2>
|
29
|
-
<City>Mountain View</City>
|
30
|
-
<State>CA</State>
|
31
|
-
<Zip>06513</Zip>
|
32
|
-
<Email>null@cybersource.com</Email>
|
33
|
-
<Country>US</Country>
|
34
|
-
</BillTo>
|
35
|
-
<ShipTo>
|
36
|
-
<FirstName>JANE</FirstName>
|
37
|
-
<LastName>SMITH</LastName>
|
38
|
-
<Address1>1295 Charleston Rd</Address1>
|
39
|
-
<Address2>Suite 2</Address2>
|
40
|
-
<City>Mountain View</City>
|
41
|
-
<State>CA</State>
|
42
|
-
<Zip>94043</Zip>
|
43
|
-
<Country>US</Country>
|
44
|
-
</ShipTo>
|
45
|
-
<PaymentMethod>
|
46
|
-
<Card>
|
47
|
-
<AccountSuffix>1111</AccountSuffix>
|
48
|
-
<ExpirationMonth>11</ExpirationMonth>
|
49
|
-
<ExpirationYear>2011</ExpirationYear>
|
50
|
-
<CardType>Visa</CardType>
|
51
|
-
</Card>
|
52
|
-
</PaymentMethod>
|
53
|
-
<LineItems>
|
54
|
-
<LineItem Number="0">
|
55
|
-
<FulfillmentType/>
|
56
|
-
<Quantity>1</Quantity>
|
57
|
-
<UnitPrice>1.56</UnitPrice>
|
58
|
-
<TaxAmount>0.25</TaxAmount>
|
59
|
-
<MerchantProductSKU>testdl</MerchantProductSKU>
|
60
|
-
<ProductName>PName1</ProductName>
|
61
|
-
<ProductCode>electronic_software</ProductCode>
|
62
|
-
</LineItem>
|
63
|
-
</LineItems>
|
64
|
-
<ApplicationReplies>
|
65
|
-
<ApplicationReply Name="ics_bill">
|
66
|
-
<RCode>1</RCode>
|
67
|
-
<RFlag>SOK</RFlag>
|
68
|
-
<RMsg>Request was processed successfully.</RMsg>
|
69
|
-
</ApplicationReply>
|
70
|
-
</ApplicationReplies>
|
71
|
-
<PaymentData>
|
72
|
-
<PaymentProcessor>vital</PaymentProcessor>
|
73
|
-
<Amount>1.81</Amount>
|
74
|
-
<CurrencyCode>eur</CurrencyCode>
|
75
|
-
<TotalTaxAmount>0.25</TotalTaxAmount>
|
76
|
-
<EventType>TRANSMITTED</EventType>
|
77
|
-
</PaymentData>
|
78
|
-
</Request>
|
79
|
-
</Requests>
|
80
|
-
</Report>
|
81
|
-
eos
|
82
|
-
report = Killbill::Cybersource::CyberSourceOnDemand::CyberSourceOnDemandTransactionReport.new(xml_report, Logger.new(STDOUT))
|
83
|
-
response = report.response
|
84
|
-
response.success?.should be_true
|
85
|
-
response.message.should == 'Request was processed successfully.'
|
86
|
-
response.params['merchantReferenceCode'].should == '33038191'
|
87
|
-
response.params['requestID'].should == '2210804330010167904567'
|
88
|
-
response.params['decision'].should be_nil
|
89
|
-
response.params['reasonCode'].should be_nil
|
90
|
-
response.params['requestToken'].should be_nil
|
91
|
-
response.params['currency'].should == 'eur'
|
92
|
-
response.params['amount'].should == '1.81'
|
93
|
-
response.params['authorizationCode'].should be_nil
|
94
|
-
response.params['avsCode'].should be_nil
|
95
|
-
response.params['avsCodeRaw'].should be_nil
|
96
|
-
response.params['cvCode'].should be_nil
|
97
|
-
response.params['authorizedDateTime'].should be_nil
|
98
|
-
response.params['processorResponse'].should be_nil
|
99
|
-
response.params['reconciliationID'].should == '0001094522'
|
100
|
-
response.params['subscriptionID'].should == ''
|
101
|
-
end
|
102
|
-
|
103
|
-
it 'parses a transaction detail report with multiple ApplicationReplies correctly' do
|
104
|
-
xml_report = <<eos
|
105
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
106
|
-
<!DOCTYPE Report SYSTEM "https://ebctest.cybersource.com/ebctest/reports/dtd/tdr_1_6.dtd">
|
107
|
-
<Report xmlns="https://ebctest.cybersource.com/ebctest/reports/dtd/tdr_1_6.dtd"
|
108
|
-
Name="Transaction Detail"
|
109
|
-
Version="1.6"
|
110
|
-
MerchantID="ok_go"
|
111
|
-
ReportStartDate="2009-05-26T18:30:00-08:00"
|
112
|
-
ReportEndDate="2009-05-27T18:30:00-08:00">
|
113
|
-
<Requests>
|
114
|
-
<Request RequestID="2434465504100167904567"
|
115
|
-
RequestDate="2009-05-27T17:49:10+05:30"
|
116
|
-
MerchantReferenceNumber="1234"
|
117
|
-
Source="SCMP API"
|
118
|
-
User=""
|
119
|
-
SubscriptionID=""
|
120
|
-
TransactionReferenceNumber="00013791KV8BZF3P">
|
121
|
-
<BillTo>
|
122
|
-
<FirstName>sample</FirstName>
|
123
|
-
<LastName>merchant</LastName>
|
124
|
-
<Address1>11 Lico Ave</Address1>
|
125
|
-
<City>Big City</City>
|
126
|
-
<State>CA</State>
|
127
|
-
<Zip>99999</Zip>
|
128
|
-
<Email>smerchant@example.com</Email>
|
129
|
-
<Country>US</Country>
|
130
|
-
<Phone/>
|
131
|
-
</BillTo>
|
132
|
-
<ShipTo>
|
133
|
-
<City>xyz</City>
|
134
|
-
<Zip>95117</Zip>
|
135
|
-
</ShipTo>
|
136
|
-
<PaymentMethod>
|
137
|
-
<Card>
|
138
|
-
<AccountSuffix>7392</AccountSuffix>
|
139
|
-
<ExpirationMonth>12</ExpirationMonth>
|
140
|
-
<ExpirationYear>2009</ExpirationYear>
|
141
|
-
<CardType>Visa</CardType>
|
142
|
-
</Card>
|
143
|
-
</PaymentMethod>
|
144
|
-
<LineItems>
|
145
|
-
<LineItem Number="0">
|
146
|
-
<FulfillmentType>P</FulfillmentType>
|
147
|
-
<Quantity>1</Quantity>
|
148
|
-
<UnitPrice>2.00</UnitPrice>
|
149
|
-
<TaxAmount>0.00</TaxAmount>
|
150
|
-
<ProductCode>default</ProductCode>
|
151
|
-
</LineItem>
|
152
|
-
</LineItems>
|
153
|
-
<ApplicationReplies>
|
154
|
-
<ApplicationReply Name="ics_auth">
|
155
|
-
<RCode>1</RCode>
|
156
|
-
<RFlag>SOK</RFlag>
|
157
|
-
<RMsg>Request was processed successfully.</RMsg>
|
158
|
-
</ApplicationReply>
|
159
|
-
<ApplicationReply Name="ics_decision">
|
160
|
-
<RCode>0</RCode>
|
161
|
-
<RFlag>DREVIEW</RFlag>
|
162
|
-
<RMsg>Decision is REVIEW.</RMsg>
|
163
|
-
</ApplicationReply>
|
164
|
-
<ApplicationReply Name="ics_decision_early">
|
165
|
-
<RCode>1</RCode>
|
166
|
-
<RFlag/>
|
167
|
-
</ApplicationReply>
|
168
|
-
<ApplicationReply Name="ics_score">
|
169
|
-
<RCode>1</RCode>
|
170
|
-
<RFlag>DSCORE</RFlag>
|
171
|
-
<RMsg>Score exceeds threshold. Score = 84</RMsg>
|
172
|
-
</ApplicationReply>
|
173
|
-
</ApplicationReplies>
|
174
|
-
<PaymentData>
|
175
|
-
<PaymentRequestID>2434465504100167904567</PaymentRequestID>
|
176
|
-
<PaymentProcessor>smartpay</PaymentProcessor>
|
177
|
-
<Amount>2.00</Amount>
|
178
|
-
<CurrencyCode>USD</CurrencyCode>
|
179
|
-
<TotalTaxAmount>0.00</TotalTaxAmount>
|
180
|
-
<AuthorizationType>O</AuthorizationType>
|
181
|
-
<AuthorizationCode>888888</AuthorizationCode>
|
182
|
-
<AVSResult>I1</AVSResult>
|
183
|
-
<AVSResultMapped>X</AVSResultMapped>
|
184
|
-
<GrandTotal>2.00</GrandTotal>
|
185
|
-
<ACHVerificationResult>100</ACHVerificationResult>
|
186
|
-
</PaymentData>
|
187
|
-
<MerchantDefinedData>
|
188
|
-
<field1 name="mdd1">ca</field1>
|
189
|
-
</MerchantDefinedData>
|
190
|
-
<RiskData>
|
191
|
-
<Factors>C,Y,Z</Factors>
|
192
|
-
<HostSeverity>1</HostSeverity>
|
193
|
-
<Score>84</Score>
|
194
|
-
<TimeLocal>2009-05-27T10:49:10</TimeLocal>
|
195
|
-
<AppliedThreshold>20</AppliedThreshold>
|
196
|
-
<AppliedTimeHedge>normal</AppliedTimeHedge>
|
197
|
-
<AppliedVelocityHedge>high</AppliedVelocityHedge>
|
198
|
-
<AppliedHostHedge>normal</AppliedHostHedge>
|
199
|
-
<AppliedCategoryGift>n</AppliedCategoryGift>
|
200
|
-
<AppliedCategoryTime/>
|
201
|
-
<AppliedAVS>X</AppliedAVS>
|
202
|
-
<BinAccountType>CN</BinAccountType>
|
203
|
-
<BinScheme>Visa Credit</BinScheme>
|
204
|
-
<BinIssuer>Sample issuer</BinIssuer>
|
205
|
-
<BinCountry>us</BinCountry>
|
206
|
-
<InfoCodes>
|
207
|
-
<InfoCode>
|
208
|
-
<CodeType>address</CodeType>
|
209
|
-
<CodeValue>MM-C,MM-Z</CodeValue>
|
210
|
-
</InfoCode>
|
211
|
-
<InfoCode>
|
212
|
-
<CodeType>velocity</CodeType>
|
213
|
-
<CodeValue>VEL-CC</CodeValue>
|
214
|
-
</InfoCode>
|
215
|
-
</InfoCodes>
|
216
|
-
</RiskData>
|
217
|
-
<ProfileList>
|
218
|
-
<Profile Name="Default Profile">
|
219
|
-
<ProfileMode>Active</ProfileMode>
|
220
|
-
<ProfileDecision>ACCEPT</ProfileDecision>
|
221
|
-
<RuleList>
|
222
|
-
<Rule>
|
223
|
-
<RuleName>sample rule name</RuleName>
|
224
|
-
<RuleDecision>IGNORE</RuleDecision>
|
225
|
-
</Rule>
|
226
|
-
</RuleList>
|
227
|
-
</Profile>
|
228
|
-
</ProfileList>
|
229
|
-
<TravelData>
|
230
|
-
<TripInfo>
|
231
|
-
<CompleteRoute>AB-CD:EF-GH</CompleteRoute>
|
232
|
-
<JourneyType>round trip</JourneyType>
|
233
|
-
<DepartureDateTime>sample date & time</DepartureDateTime>
|
234
|
-
</TripInfo>
|
235
|
-
<PassengerInfo>
|
236
|
-
<Passenger Number="0">
|
237
|
-
<PassengerFirstName>jane</PassengerFirstName>
|
238
|
-
<PassengerLastName>doe</PassengerLastName>
|
239
|
-
<PassengerID>Sing-001</PassengerID>
|
240
|
-
</Passenger>
|
241
|
-
<Passenger Number="1">
|
242
|
-
<PassengerFirstName>john</PassengerFirstName>
|
243
|
-
<PassengerLastName>doe</PassengerLastName>
|
244
|
-
<PassengerID>sing-002</PassengerID>
|
245
|
-
<PassengerStatus>Adult</PassengerStatus>
|
246
|
-
<PassengerType>Gold</PassengerType>
|
247
|
-
<PassengerPhone>9995551212</PassengerPhone>
|
248
|
-
<PassengerEmail>jdoe@example.com</PassengerEmail>
|
249
|
-
</Passenger>
|
250
|
-
</PassengerInfo>
|
251
|
-
</TravelData>
|
252
|
-
</Request>
|
253
|
-
</Requests>
|
254
|
-
</Report>
|
255
|
-
eos
|
256
|
-
report = Killbill::Cybersource::CyberSourceOnDemand::CyberSourceOnDemandTransactionReport.new(xml_report, Logger.new(STDOUT))
|
257
|
-
response = report.response
|
258
|
-
response.success?.should be_true
|
259
|
-
response.message.should == 'Score exceeds threshold. Score = 84'
|
260
|
-
response.params['merchantReferenceCode'].should == '1234'
|
261
|
-
response.params['requestID'].should == '2434465504100167904567'
|
262
|
-
response.params['decision'].should == 'ACCEPT'
|
263
|
-
response.params['reasonCode'].should be_nil
|
264
|
-
response.params['requestToken'].should be_nil
|
265
|
-
response.params['currency'].should == 'USD'
|
266
|
-
response.params['amount'].should == '2.00'
|
267
|
-
response.params['authorizationCode'].should == '888888'
|
268
|
-
response.params['avsCode'].should == 'X'
|
269
|
-
response.params['avsCodeRaw'].should == 'I1'
|
270
|
-
response.params['cvCode'].should be_nil
|
271
|
-
response.params['authorizedDateTime'].should be_nil
|
272
|
-
response.params['processorResponse'].should be_nil
|
273
|
-
response.params['reconciliationID'].should == '00013791KV8BZF3P'
|
274
|
-
response.params['subscriptionID'].should == ''
|
275
|
-
end
|
276
|
-
end
|
@@ -1,807 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
ActiveMerchant::Billing::Base.mode = :test
|
4
|
-
|
5
|
-
describe Killbill::Cybersource::PaymentPlugin do
|
6
|
-
|
7
|
-
include ::Killbill::Plugin::ActiveMerchant::RSpec
|
8
|
-
|
9
|
-
before(:each) do
|
10
|
-
@plugin = build_plugin(::Killbill::Cybersource::PaymentPlugin, 'cybersource')
|
11
|
-
@plugin.start_plugin
|
12
|
-
|
13
|
-
::Killbill::Cybersource::CybersourcePaymentMethod.delete_all
|
14
|
-
::Killbill::Cybersource::CybersourceResponse.delete_all
|
15
|
-
::Killbill::Cybersource::CybersourceTransaction.delete_all
|
16
|
-
|
17
|
-
@call_context = build_call_context
|
18
|
-
|
19
|
-
@properties = []
|
20
|
-
@pm = create_payment_method(::Killbill::Cybersource::CybersourcePaymentMethod, nil, @call_context.tenant_id, @properties)
|
21
|
-
@amount = BigDecimal.new('100')
|
22
|
-
@currency = 'USD'
|
23
|
-
|
24
|
-
@kb_payment = setup_kb_payment(6)
|
25
|
-
end
|
26
|
-
|
27
|
-
after(:each) do
|
28
|
-
@plugin.stop_plugin
|
29
|
-
end
|
30
|
-
|
31
|
-
let(:report_api) do
|
32
|
-
@plugin.get_report_api({}, @call_context)
|
33
|
-
end
|
34
|
-
|
35
|
-
let(:with_report_api) do
|
36
|
-
report_api.present?
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'should be able to charge a Credit Card directly and calls should be idempotent' do
|
40
|
-
properties = build_pm_properties
|
41
|
-
|
42
|
-
# We created the payment method, hence the rows
|
43
|
-
Killbill::Cybersource::CybersourceResponse.all.size.should == 1
|
44
|
-
Killbill::Cybersource::CybersourceTransaction.all.size.should == 0
|
45
|
-
|
46
|
-
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)
|
47
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
48
|
-
payment_response.first_payment_reference_id.should_not be_nil
|
49
|
-
payment_response.second_payment_reference_id.should_not be_nil
|
50
|
-
|
51
|
-
responses = Killbill::Cybersource::CybersourceResponse.all
|
52
|
-
responses.size.should == 2
|
53
|
-
responses[0].api_call.should == 'add_payment_method'
|
54
|
-
responses[0].message.should == 'Successful transaction'
|
55
|
-
responses[1].api_call.should == 'purchase'
|
56
|
-
responses[1].message.should == 'Successful transaction'
|
57
|
-
transactions = Killbill::Cybersource::CybersourceTransaction.all
|
58
|
-
transactions.size.should == 1
|
59
|
-
transactions[0].api_call.should == 'purchase'
|
60
|
-
|
61
|
-
# Skip the rest of the test if the report API isn't configured to check for duplicates
|
62
|
-
break unless with_report_api && report_api.check_for_duplicates?
|
63
|
-
|
64
|
-
# The report API can be delayed
|
65
|
-
await { !@plugin.get_single_transaction_report(report_api, @kb_payment.transactions[0].id, Time.now.utc).empty? }
|
66
|
-
|
67
|
-
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)
|
68
|
-
payment_response.amount.should == @amount
|
69
|
-
payment_response.status.should == :PROCESSED
|
70
|
-
payment_response.transaction_type.should == :PURCHASE
|
71
|
-
# No extra data when handling dups - use the get API to retrieve the details (what Kill Bill does internally too)
|
72
|
-
payment_response.first_payment_reference_id.should be_nil
|
73
|
-
payment_response.second_payment_reference_id.should be_nil
|
74
|
-
payment_response.gateway_error_code.should be_nil
|
75
|
-
|
76
|
-
responses = Killbill::Cybersource::CybersourceResponse.all
|
77
|
-
responses.size.should == 3
|
78
|
-
responses[0].api_call.should == 'add_payment_method'
|
79
|
-
responses[0].message.should == 'Successful transaction'
|
80
|
-
responses[1].api_call.should == 'purchase'
|
81
|
-
responses[1].message.should == 'Successful transaction'
|
82
|
-
responses[2].api_call.should == 'purchase'
|
83
|
-
responses[2].message.should == 'Skipped Gateway call'
|
84
|
-
transactions = Killbill::Cybersource::CybersourceTransaction.all
|
85
|
-
transactions.size.should == 2
|
86
|
-
transactions[0].api_call.should == 'purchase'
|
87
|
-
transactions[0].txn_id.should_not be_nil
|
88
|
-
transactions[1].api_call.should == 'purchase'
|
89
|
-
transactions[1].txn_id.should be_nil
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'should be able to verify a Credit Card' do
|
93
|
-
# Valid card
|
94
|
-
properties = build_pm_properties
|
95
|
-
kb_payment = setup_kb_payment(2)
|
96
|
-
payment_response = @plugin.authorize_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, @pm.kb_payment_method_id, 0, @currency, properties, @call_context)
|
97
|
-
check_response(payment_response, 0, :AUTHORIZE, :PROCESSED, 'Successful transaction', '100')
|
98
|
-
payment_response.first_payment_reference_id.should_not be_nil
|
99
|
-
payment_response.second_payment_reference_id.should_not be_nil
|
100
|
-
|
101
|
-
# Note that you won't be able to void the $0 auth
|
102
|
-
payment_response = @plugin.void_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[1].id, @pm.kb_payment_method_id, @properties, @call_context)
|
103
|
-
check_response(payment_response, nil, :VOID, :CANCELED, 'One or more fields contains invalid data', '102')
|
104
|
-
|
105
|
-
# Invalid card
|
106
|
-
# See http://www.cybersource.com/developers/getting_started/test_and_manage/simple_order_api/HTML/General_testing_info/soapi_general_test.html
|
107
|
-
properties = build_pm_properties(nil, { :cc_exp_year => 1998 })
|
108
|
-
kb_payment = setup_kb_payment
|
109
|
-
payment_response = @plugin.authorize_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, @pm.kb_payment_method_id, 0, @currency, properties, @call_context)
|
110
|
-
check_response(payment_response, nil, :AUTHORIZE, :ERROR, 'Expired card', '202')
|
111
|
-
payment_response.first_payment_reference_id.should_not be_nil
|
112
|
-
payment_response.second_payment_reference_id.should be_nil
|
113
|
-
|
114
|
-
# Discover card (doesn't support $0 auth on Paymentech)
|
115
|
-
# See http://www.cybersource.com/developers/other_resources/quick_references/test_cc_numbers/
|
116
|
-
properties = build_pm_properties(nil, { :cc_number => '6011111111111117', :cc_type => :discover })
|
117
|
-
kb_payment = setup_kb_payment
|
118
|
-
payment_response = @plugin.authorize_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, @pm.kb_payment_method_id, 0, @currency, properties, @call_context)
|
119
|
-
check_response(payment_response, nil, :AUTHORIZE, :CANCELED, 'A problem exists with your CyberSource merchant configuration', '234')
|
120
|
-
payment_response.first_payment_reference_id.should_not be_nil
|
121
|
-
payment_response.second_payment_reference_id.should be_nil
|
122
|
-
# Verify the GET path
|
123
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, kb_payment.id, @properties, @call_context)
|
124
|
-
transaction_info_plugins.size.should == 1
|
125
|
-
transaction_info_plugins.first.transaction_type.should eq(:AUTHORIZE)
|
126
|
-
transaction_info_plugins.first.status.should eq(:CANCELED)
|
127
|
-
|
128
|
-
# Force the validation on Discover
|
129
|
-
properties << build_property('force_validation', 'true')
|
130
|
-
kb_payment = setup_kb_payment
|
131
|
-
payment_response = @plugin.authorize_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, @pm.kb_payment_method_id, 0, @currency, properties, @call_context)
|
132
|
-
check_response(payment_response, 1, :AUTHORIZE, :PROCESSED, 'Successful transaction', '100')
|
133
|
-
payment_response.first_payment_reference_id.should_not be_nil
|
134
|
-
payment_response.second_payment_reference_id.should_not be_nil
|
135
|
-
# Verify the GET path
|
136
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, kb_payment.id, @properties, @call_context)
|
137
|
-
transaction_info_plugins.size.should == 3
|
138
|
-
transaction_info_plugins[0].transaction_type.should eq(:AUTHORIZE)
|
139
|
-
transaction_info_plugins[0].status.should eq(:CANCELED)
|
140
|
-
transaction_info_plugins[0].kb_transaction_payment_id.should_not eq(kb_payment.transactions[0].id)
|
141
|
-
transaction_info_plugins[1].transaction_type.should eq(:AUTHORIZE)
|
142
|
-
transaction_info_plugins[1].status.should eq(:PROCESSED)
|
143
|
-
transaction_info_plugins[1].kb_transaction_payment_id.should eq(kb_payment.transactions[0].id)
|
144
|
-
transaction_info_plugins[2].transaction_type.should eq(:VOID)
|
145
|
-
transaction_info_plugins[2].status.should eq(:PROCESSED)
|
146
|
-
transaction_info_plugins[2].kb_transaction_payment_id.should_not eq(kb_payment.transactions[0].id)
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'should be able to bypass AVS and CVV rules with Apple Pay' do
|
150
|
-
properties = build_pm_properties(nil,
|
151
|
-
{
|
152
|
-
:cc_number => 4111111111111111,
|
153
|
-
:cc_type => 'visa',
|
154
|
-
:payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=',
|
155
|
-
:ignore_avs => true,
|
156
|
-
:ignore_cvv => true
|
157
|
-
})
|
158
|
-
kb_payment = setup_kb_payment
|
159
|
-
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)
|
160
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
161
|
-
|
162
|
-
properties = build_pm_properties(nil,
|
163
|
-
{
|
164
|
-
:cc_number => 5555555555554444,
|
165
|
-
:cc_type => 'master',
|
166
|
-
:payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=',
|
167
|
-
:ignore_avs => true,
|
168
|
-
:ignore_cvv => true
|
169
|
-
})
|
170
|
-
kb_payment = setup_kb_payment
|
171
|
-
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)
|
172
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
173
|
-
|
174
|
-
properties = build_pm_properties(nil,
|
175
|
-
{
|
176
|
-
:cc_number => 378282246310005,
|
177
|
-
:cc_type => 'american_express',
|
178
|
-
:payment_cryptogram => 'AAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBB==',
|
179
|
-
:ignore_avs => true,
|
180
|
-
:ignore_cvv => true
|
181
|
-
})
|
182
|
-
kb_payment = setup_kb_payment
|
183
|
-
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)
|
184
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
185
|
-
|
186
|
-
properties = build_pm_properties(nil,
|
187
|
-
{
|
188
|
-
:cc_number => 378282246310005,
|
189
|
-
:cc_type => 'american_express',
|
190
|
-
:payment_cryptogram => 'AAAAAAAAAAAAAAAAAABBBBBBBBB=',
|
191
|
-
:ignore_avs => true,
|
192
|
-
:ignore_cvv => true
|
193
|
-
})
|
194
|
-
kb_payment = setup_kb_payment
|
195
|
-
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)
|
196
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
197
|
-
end
|
198
|
-
|
199
|
-
it 'should be able to pay with Android Pay' do
|
200
|
-
properties = build_pm_properties(nil,
|
201
|
-
{
|
202
|
-
:cc_number => 4895370012003478,
|
203
|
-
:cc_type => 'visa',
|
204
|
-
:payment_cryptogram => 'AgAAAAAABk4DWZ4C28yUQAAAAAA=',
|
205
|
-
:ignore_avs => true,
|
206
|
-
:ignore_cvv => true
|
207
|
-
})
|
208
|
-
properties << build_property('source', 'androidpay')
|
209
|
-
|
210
|
-
kb_payment = setup_kb_payment
|
211
|
-
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)
|
212
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
213
|
-
|
214
|
-
properties = build_pm_properties(nil,
|
215
|
-
{
|
216
|
-
:cc_number => 5555555555554444,
|
217
|
-
:cc_type => 'master',
|
218
|
-
:payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=',
|
219
|
-
:ignore_avs => true,
|
220
|
-
:ignore_cvv => true
|
221
|
-
})
|
222
|
-
properties << build_property('source', 'androidpay')
|
223
|
-
|
224
|
-
kb_payment = setup_kb_payment
|
225
|
-
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)
|
226
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
227
|
-
|
228
|
-
properties = build_pm_properties(nil,
|
229
|
-
{
|
230
|
-
:cc_number => 378282246310005,
|
231
|
-
:cc_type => 'american_express',
|
232
|
-
:payment_cryptogram => 'AAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBB==',
|
233
|
-
:ignore_avs => true,
|
234
|
-
:ignore_cvv => true
|
235
|
-
})
|
236
|
-
properties << build_property('source', 'androidpay')
|
237
|
-
|
238
|
-
kb_payment = setup_kb_payment
|
239
|
-
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)
|
240
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
241
|
-
|
242
|
-
properties = build_pm_properties(nil,
|
243
|
-
{
|
244
|
-
:cc_number => 378282246310005,
|
245
|
-
:cc_type => 'american_express',
|
246
|
-
:payment_cryptogram => 'AAAAAAAAAAAAAAAAAABBBBBBBBB=',
|
247
|
-
:ignore_avs => true,
|
248
|
-
:ignore_cvv => true
|
249
|
-
})
|
250
|
-
properties << build_property('source', 'androidpay')
|
251
|
-
|
252
|
-
kb_payment = setup_kb_payment
|
253
|
-
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)
|
254
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
255
|
-
end
|
256
|
-
|
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')
|
261
|
-
|
262
|
-
# Force a transition to :UNDEFINED
|
263
|
-
response, initial_auth = transition_last_response_to_UNDEFINED(1)
|
264
|
-
|
265
|
-
# Skip if the report API isn't configured
|
266
|
-
fix_transaction(0) if with_report_api
|
267
|
-
|
268
|
-
# Compare the state of the old and new response
|
269
|
-
check_old_new_response(response, :PURCHASE, 0, initial_auth, payment_response.first_payment_reference_id)
|
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, refund_response.first_payment_reference_id)
|
284
|
-
end
|
285
|
-
|
286
|
-
it 'should fix UNDEFINED captures' do
|
287
|
-
@plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
288
|
-
payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
289
|
-
check_response(payment_response, @amount, :CAPTURE, :PROCESSED, 'Successful transaction', '100')
|
290
|
-
|
291
|
-
# Force a transition to :UNDEFINED
|
292
|
-
response, initial_auth = transition_last_response_to_UNDEFINED(2)
|
293
|
-
|
294
|
-
# Skip if the report API isn't configured
|
295
|
-
fix_transaction(1) if with_report_api
|
296
|
-
|
297
|
-
# Compare the state of the old and new response
|
298
|
-
check_old_new_response(response, :CAPTURE, 1, initial_auth, payment_response.first_payment_reference_id)
|
299
|
-
|
300
|
-
break unless with_report_api
|
301
|
-
|
302
|
-
# Try a full refund
|
303
|
-
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)
|
304
|
-
check_response(refund_response, @amount, :REFUND, :PROCESSED, 'Successful transaction', '100')
|
305
|
-
end
|
306
|
-
|
307
|
-
it 'should not fix UNDEFINED captures if the report only covers the previous request' do
|
308
|
-
@plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
309
|
-
|
310
|
-
# Skip gw call so that on_demand report api won't return a record for this call
|
311
|
-
skip_gw = Killbill::Plugin::Model::PluginProperty.new
|
312
|
-
skip_gw.key = 'skip_gw'
|
313
|
-
skip_gw.value = 'true'
|
314
|
-
properties_with_skip_gw = @properties.clone
|
315
|
-
properties_with_skip_gw << skip_gw
|
316
|
-
@plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, properties_with_skip_gw, @call_context)
|
317
|
-
|
318
|
-
# Force a transition to :UNDEFINED
|
319
|
-
transition_last_response_to_UNDEFINED(2)
|
320
|
-
|
321
|
-
# Shouldn't be able to fix the capture because it skipped the gateway call
|
322
|
-
fix_transaction(1, :UNDEFINED) if with_report_api
|
323
|
-
end
|
324
|
-
|
325
|
-
it 'should not fix UNDEFINED refunds if the report only covers the previous requests' do
|
326
|
-
@plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
327
|
-
@plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
328
|
-
|
329
|
-
# Skip gw call so that on_demand report api won't return a record for this call
|
330
|
-
skip_gw = Killbill::Plugin::Model::PluginProperty.new
|
331
|
-
skip_gw.key = 'skip_gw'
|
332
|
-
skip_gw.value = 'true'
|
333
|
-
properties_with_skip_gw = @properties.clone
|
334
|
-
properties_with_skip_gw << skip_gw
|
335
|
-
@plugin.refund_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, properties_with_skip_gw, @call_context)
|
336
|
-
|
337
|
-
# Force a transition to :UNDEFINED
|
338
|
-
transition_last_response_to_UNDEFINED(3)
|
339
|
-
|
340
|
-
# Shouldn't be able to fix the capture because it skipped the gateway call
|
341
|
-
fix_transaction(2, :UNDEFINED) if with_report_api
|
342
|
-
end
|
343
|
-
|
344
|
-
def transition_last_response_to_UNDEFINED(expected_nb_transactions)
|
345
|
-
Killbill::Cybersource::CybersourceTransaction.last.delete
|
346
|
-
response = Killbill::Cybersource::CybersourceResponse.last
|
347
|
-
initial_auth = response.authorization
|
348
|
-
response.update(:authorization => nil, :params_request_id => nil, :message => {:payment_plugin_status => 'UNDEFINED'}.to_json)
|
349
|
-
|
350
|
-
skip_gw = Killbill::Plugin::Model::PluginProperty.new
|
351
|
-
skip_gw.key = 'skip_gw'
|
352
|
-
skip_gw.value = 'true'
|
353
|
-
properties_with_skip_gw = @properties.clone
|
354
|
-
properties_with_skip_gw << skip_gw
|
355
|
-
|
356
|
-
# Set skip_gw=true, to avoid calling the report API
|
357
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_skip_gw, @call_context)
|
358
|
-
transaction_info_plugins.size.should == expected_nb_transactions
|
359
|
-
transaction_info_plugins.last.status.should eq(:UNDEFINED)
|
360
|
-
|
361
|
-
[response, initial_auth]
|
362
|
-
end
|
363
|
-
|
364
|
-
def fix_transaction(transaction_nb, expected_state=:PROCESSED)
|
365
|
-
# The report API can be delayed
|
366
|
-
await do
|
367
|
-
!@plugin.get_single_transaction_report(report_api, @kb_payment.transactions[0].id, Time.now.utc).empty? ||
|
368
|
-
!@plugin.get_single_transaction_report(report_api, @kb_payment.transactions[0].external_key, Time.now.utc).empty?
|
369
|
-
end
|
370
|
-
|
371
|
-
# Plugin delay hasn't been reached yet
|
372
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, @properties, @call_context)
|
373
|
-
transaction_info_plugins.size.should == transaction_nb + 1
|
374
|
-
transaction_info_plugins.last.status.should eq(:UNDEFINED)
|
375
|
-
|
376
|
-
# Fix it
|
377
|
-
janitor_delay_threshold = Killbill::Plugin::Model::PluginProperty.new
|
378
|
-
janitor_delay_threshold.key = 'janitor_delay_threshold'
|
379
|
-
janitor_delay_threshold.value = '0'
|
380
|
-
properties_with_janitor_delay_threshold = @properties.clone
|
381
|
-
properties_with_janitor_delay_threshold << janitor_delay_threshold
|
382
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_janitor_delay_threshold, @call_context)
|
383
|
-
transaction_info_plugins.size.should == transaction_nb + 1
|
384
|
-
transaction_info_plugins.last.status.should eq(expected_state)
|
385
|
-
|
386
|
-
# Set skip_gw=true, to check the local state
|
387
|
-
skip_gw = Killbill::Plugin::Model::PluginProperty.new
|
388
|
-
skip_gw.key = 'skip_gw'
|
389
|
-
skip_gw.value = 'true'
|
390
|
-
properties_with_skip_gw = @properties.clone
|
391
|
-
properties_with_skip_gw << skip_gw
|
392
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_skip_gw, @call_context)
|
393
|
-
transaction_info_plugins.size.should == transaction_nb + 1
|
394
|
-
transaction_info_plugins.last.status.should eq(expected_state)
|
395
|
-
end
|
396
|
-
|
397
|
-
def check_old_new_response(response, transaction_type, transaction_nb, initial_auth, request_id)
|
398
|
-
new_response = Killbill::Cybersource::CybersourceResponse.last
|
399
|
-
new_response.id.should == response.id
|
400
|
-
new_response.api_call.should == transaction_type.to_s.downcase
|
401
|
-
new_response.kb_tenant_id.should == @call_context.tenant_id
|
402
|
-
new_response.kb_account_id.should == @pm.kb_account_id
|
403
|
-
new_response.kb_payment_id.should == @kb_payment.id
|
404
|
-
new_response.kb_payment_transaction_id.should == @kb_payment.transactions[transaction_nb].id
|
405
|
-
new_response.transaction_type.should == transaction_type.to_s
|
406
|
-
new_response.payment_processor_account_id.should == 'default'
|
407
|
-
# The report API doesn't give us the token
|
408
|
-
new_response.authorization.split(';')[0..1].should == initial_auth.split(';')[0..1] if with_report_api
|
409
|
-
new_response.test.should be_true
|
410
|
-
new_response.params_merchant_reference_code.should == response.params_merchant_reference_code
|
411
|
-
new_response.params_decision.should == response.params_decision
|
412
|
-
new_response.params_request_token.should == response.params_request_token
|
413
|
-
new_response.params_currency.should == response.params_currency
|
414
|
-
new_response.params_amount.should == response.params_amount
|
415
|
-
new_response.params_authorization_code.should == response.params_authorization_code unless response.params_authorization_code.nil?
|
416
|
-
new_response.params_avs_code.should == response.params_avs_code unless response.params_avs_code.nil?
|
417
|
-
new_response.params_avs_code_raw.should == response.params_avs_code_raw unless response.params_avs_code.nil?
|
418
|
-
new_response.params_reconciliation_id.should == response.params_reconciliation_id
|
419
|
-
new_response.success.should be_true
|
420
|
-
new_response.message.should == (with_report_api ? 'Request was processed successfully.' : '{"payment_plugin_status":"UNDEFINED"}')
|
421
|
-
new_response.params_request_id.should == request_id if with_report_api
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
describe 'with on demand API' do
|
426
|
-
context 'using defaults' do
|
427
|
-
it_behaves_like 'fix_undefined_payments'
|
428
|
-
end
|
429
|
-
|
430
|
-
context 'using external_key_as_order_id' do
|
431
|
-
before do
|
432
|
-
@properties << build_property('external_key_as_order_id', true)
|
433
|
-
end
|
434
|
-
it_behaves_like 'fix_undefined_payments'
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
|
-
it 'should eventually cancel UNDEFINED payments' do
|
439
|
-
response = Killbill::Cybersource::CybersourceResponse.create(:api_call => 'authorization',
|
440
|
-
:kb_account_id => @pm.kb_account_id,
|
441
|
-
:kb_payment_id => @kb_payment.id,
|
442
|
-
:kb_payment_transaction_id => @kb_payment.transactions[0].id,
|
443
|
-
:kb_tenant_id => @call_context.tenant_id,
|
444
|
-
:message => '{"exception_message":"Timeout","payment_plugin_status":"UNDEFINED"}',
|
445
|
-
:created_at => Time.now,
|
446
|
-
:updated_at => Time.now)
|
447
|
-
|
448
|
-
# Set skip_gw=true, to avoid calling the report API
|
449
|
-
skip_gw = Killbill::Plugin::Model::PluginProperty.new
|
450
|
-
skip_gw.key = 'skip_gw'
|
451
|
-
skip_gw.value = 'true'
|
452
|
-
properties_with_skip_gw = @properties.clone
|
453
|
-
properties_with_skip_gw << skip_gw
|
454
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_skip_gw, @call_context)
|
455
|
-
transaction_info_plugins.size.should == 1
|
456
|
-
transaction_info_plugins.first.status.should eq(:UNDEFINED)
|
457
|
-
|
458
|
-
janitor_delay_threshold = Killbill::Plugin::Model::PluginProperty.new
|
459
|
-
janitor_delay_threshold.key = 'janitor_delay_threshold'
|
460
|
-
janitor_delay_threshold.value = '0'
|
461
|
-
properties_with_janitor_delay_threshold = @properties.clone
|
462
|
-
properties_with_janitor_delay_threshold << janitor_delay_threshold
|
463
|
-
|
464
|
-
# Call the reporting API (if configured) and verify the state still cannot be fixed
|
465
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_janitor_delay_threshold, @call_context)
|
466
|
-
transaction_info_plugins.size.should == 1
|
467
|
-
transaction_info_plugins.first.status.should eq(:UNDEFINED)
|
468
|
-
|
469
|
-
# Transition to CANCEL won't work if the reporting API isn't configured
|
470
|
-
break unless with_report_api
|
471
|
-
|
472
|
-
# Force a transition to CANCEL
|
473
|
-
cancel_threshold = Killbill::Plugin::Model::PluginProperty.new
|
474
|
-
cancel_threshold.key = 'cancel_threshold'
|
475
|
-
cancel_threshold.value = '0'
|
476
|
-
properties_with_cancel_threshold = properties_with_janitor_delay_threshold.clone
|
477
|
-
properties_with_cancel_threshold << cancel_threshold
|
478
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, properties_with_cancel_threshold, @call_context)
|
479
|
-
transaction_info_plugins.size.should == 1
|
480
|
-
transaction_info_plugins.first.status.should eq(:CANCELED)
|
481
|
-
|
482
|
-
# Verify the state is sticky
|
483
|
-
transaction_info_plugins = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, @properties, @call_context)
|
484
|
-
transaction_info_plugins.size.should == 1
|
485
|
-
transaction_info_plugins.first.status.should eq(:CANCELED)
|
486
|
-
end
|
487
|
-
|
488
|
-
it 'should be able to charge and refund' do
|
489
|
-
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)
|
490
|
-
check_response(payment_response, @amount, :PURCHASE, :PROCESSED, 'Successful transaction', '100')
|
491
|
-
|
492
|
-
# Try a full refund
|
493
|
-
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)
|
494
|
-
check_response(refund_response, @amount, :REFUND, :PROCESSED, 'Successful transaction', '100')
|
495
|
-
end
|
496
|
-
|
497
|
-
it 'should be able to auth, capture and refund' do
|
498
|
-
payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
499
|
-
check_response(payment_response, @amount, :AUTHORIZE, :PROCESSED, 'Successful transaction', '100')
|
500
|
-
|
501
|
-
# Try multiple partial captures
|
502
|
-
partial_capture_amount = BigDecimal.new('10')
|
503
|
-
1.upto(3) do |i|
|
504
|
-
payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[i].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
|
505
|
-
check_response(payment_response, partial_capture_amount, :CAPTURE, :PROCESSED, 'Successful transaction', '100')
|
506
|
-
end
|
507
|
-
|
508
|
-
# Try a partial refund
|
509
|
-
refund_response = @plugin.refund_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[4].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
|
510
|
-
check_response(refund_response, partial_capture_amount, :REFUND, :PROCESSED, 'Successful transaction', '100')
|
511
|
-
|
512
|
-
# Try to capture again
|
513
|
-
payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[5].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
|
514
|
-
check_response(payment_response, partial_capture_amount, :CAPTURE, :PROCESSED, 'Successful transaction', '100')
|
515
|
-
end
|
516
|
-
|
517
|
-
it 'should be able to auth and void' do
|
518
|
-
payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
519
|
-
check_response(payment_response, @amount, :AUTHORIZE, :PROCESSED, 'Successful transaction', '100')
|
520
|
-
|
521
|
-
payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @properties, @call_context)
|
522
|
-
check_response(payment_response, nil, :VOID, :PROCESSED, 'Successful transaction', '100')
|
523
|
-
end
|
524
|
-
|
525
|
-
it 'should be able to auth and void in CAD', :ci_skip => true do
|
526
|
-
payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, 'CAD', @properties, @call_context)
|
527
|
-
check_response(payment_response, @amount, :AUTHORIZE, :PROCESSED, 'Successful transaction', '100')
|
528
|
-
|
529
|
-
payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @properties, @call_context)
|
530
|
-
check_response(payment_response, nil, :VOID, :PROCESSED, 'Successful transaction', '100')
|
531
|
-
end
|
532
|
-
|
533
|
-
it 'should be able to auth, partial capture and void' do
|
534
|
-
payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
535
|
-
check_response(payment_response, @amount, :AUTHORIZE, :PROCESSED, 'Successful transaction', '100')
|
536
|
-
|
537
|
-
partial_capture_amount = BigDecimal.new('10')
|
538
|
-
payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
|
539
|
-
check_response(payment_response, partial_capture_amount, :CAPTURE, :PROCESSED, 'Successful transaction', '100')
|
540
|
-
|
541
|
-
payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[2].id, @pm.kb_payment_method_id, @properties, @call_context)
|
542
|
-
check_response(payment_response, nil, :VOID, :PROCESSED, 'Successful transaction', '100')
|
543
|
-
Killbill::Cybersource::CybersourceResponse.last.params_amount.should == '10.00'
|
544
|
-
|
545
|
-
# From the CyberSource documentation:
|
546
|
-
# When you void a capture, a hold remains on the unused credit card funds. If you are not going to re-capture the authorization as described in "Capture After Void," page 71, and if
|
547
|
-
# your processor supports authorization reversal after void as described in "Authorization Reversal After Void," page 39, CyberSource recommends that you request an authorization reversal
|
548
|
-
# to release the hold on the unused credit card funds.
|
549
|
-
payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[3].id, @pm.kb_payment_method_id, @properties, @call_context)
|
550
|
-
check_response(payment_response, nil, :VOID, :PROCESSED, 'Successful transaction', '100')
|
551
|
-
Killbill::Cybersource::CybersourceResponse.last.params_amount.should == '100.00'
|
552
|
-
end
|
553
|
-
|
554
|
-
it 'should be able to credit' do
|
555
|
-
payment_response = @plugin.credit_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
556
|
-
check_response(payment_response, @amount, :CREDIT, :PROCESSED, 'Successful transaction', '100')
|
557
|
-
end
|
558
|
-
|
559
|
-
# See https://github.com/killbill/killbill-cybersource-plugin/issues/4
|
560
|
-
it 'handles 500 errors gracefully' do
|
561
|
-
properties_with_no_expiration_year = build_pm_properties
|
562
|
-
cc_exp_year = properties_with_no_expiration_year.find { |prop| prop.key == 'ccExpirationYear' }
|
563
|
-
cc_exp_year.value = nil
|
564
|
-
|
565
|
-
kb_payment = setup_kb_payment
|
566
|
-
payment_response = @plugin.purchase_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, SecureRandom.uuid, @amount, @currency, properties_with_no_expiration_year, @call_context)
|
567
|
-
check_response(payment_response, nil, :PURCHASE, :CANCELED, '{"exception_message":"soap:Client: \\nXML parse error.\\n","payment_plugin_status":"CANCELED"}', nil)
|
568
|
-
end
|
569
|
-
|
570
|
-
# See http://www.cybersource.com/developers/getting_started/test_and_manage/simple_order_api/HTML/General_testing_info/soapi_general_test.html
|
571
|
-
it 'sets the correct transaction status' do
|
572
|
-
properties = build_pm_properties
|
573
|
-
|
574
|
-
kb_payment = setup_kb_payment
|
575
|
-
payment_response = @plugin.purchase_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, SecureRandom.uuid, -1, @currency, properties, @call_context)
|
576
|
-
check_response(payment_response, nil, :PURCHASE, :CANCELED, 'One or more fields contains invalid data', '102')
|
577
|
-
|
578
|
-
kb_payment = setup_kb_payment
|
579
|
-
payment_response = @plugin.purchase_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, SecureRandom.uuid, 100000000000, @currency, properties, @call_context)
|
580
|
-
check_response(payment_response, nil, :PURCHASE, :CANCELED, 'One or more fields contains invalid data', '102')
|
581
|
-
|
582
|
-
kb_payment = setup_kb_payment
|
583
|
-
bogus_properties = build_pm_properties(nil, {:cc_number => '4111111111111112'})
|
584
|
-
payment_response = @plugin.purchase_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, SecureRandom.uuid, @amount, @currency, bogus_properties, @call_context)
|
585
|
-
check_response(payment_response, nil, :PURCHASE, :ERROR, 'Invalid account number', '231')
|
586
|
-
|
587
|
-
kb_payment = setup_kb_payment
|
588
|
-
bogus_properties = build_pm_properties(nil, {:cc_number => '412345678912345678914'})
|
589
|
-
payment_response = @plugin.purchase_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, SecureRandom.uuid, @amount, @currency, bogus_properties, @call_context)
|
590
|
-
check_response(payment_response, nil, :PURCHASE, :ERROR, 'Invalid account number', '231')
|
591
|
-
|
592
|
-
kb_payment = setup_kb_payment
|
593
|
-
bogus_properties = build_pm_properties(nil, {:cc_exp_month => '13'})
|
594
|
-
payment_response = @plugin.purchase_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, SecureRandom.uuid, @amount, @currency, bogus_properties, @call_context)
|
595
|
-
check_response(payment_response, nil, :PURCHASE, :CANCELED, 'One or more fields contains invalid data', '102')
|
596
|
-
end
|
597
|
-
|
598
|
-
context 'Processors' do
|
599
|
-
|
600
|
-
# See http://www.cybersource.com/developers/getting_started/test_and_manage/simple_order_api/HTML/Paymentech/soapi_ptech_err.html
|
601
|
-
it 'handles Chase Paymentech Solutions errors' do
|
602
|
-
properties = build_pm_properties
|
603
|
-
|
604
|
-
%w(000 236 248 265 266 267 301 519 769 902 905 906).each do |expected_processor_response|
|
605
|
-
kb_payment = setup_kb_payment
|
606
|
-
amount = 2000 + expected_processor_response.to_i
|
607
|
-
payment_response = @plugin.purchase_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, SecureRandom.uuid, amount, @currency, properties, @call_context)
|
608
|
-
check_response(payment_response, nil, :PURCHASE, :CANCELED, 'General failure', '150', expected_processor_response)
|
609
|
-
end
|
610
|
-
|
611
|
-
%w(239 241 249 833).each do |expected_processor_response|
|
612
|
-
kb_payment = setup_kb_payment
|
613
|
-
amount = 2000 + expected_processor_response.to_i
|
614
|
-
payment_response = @plugin.purchase_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, SecureRandom.uuid, amount, @currency, properties, @call_context)
|
615
|
-
check_response(payment_response, nil, :PURCHASE, :CANCELED, 'A problem exists with your CyberSource merchant configuration', '234', expected_processor_response)
|
616
|
-
end
|
617
|
-
|
618
|
-
{'201' => '231',
|
619
|
-
'202' => '233',
|
620
|
-
'203' => '233',
|
621
|
-
# Disable most of the checks by default (test lasts for 7 minutes otherwise)
|
622
|
-
=begin
|
623
|
-
'204' => '233',
|
624
|
-
'205' => '233',
|
625
|
-
'218' => '233',
|
626
|
-
'219' => '233',
|
627
|
-
'220' => '233',
|
628
|
-
'225' => '233',
|
629
|
-
'227' => '233',
|
630
|
-
'231' => '233',
|
631
|
-
'233' => '233',
|
632
|
-
'234' => '233',
|
633
|
-
'238' => '233',
|
634
|
-
'243' => '233',
|
635
|
-
'244' => '233',
|
636
|
-
'245' => '233',
|
637
|
-
'246' => '233',
|
638
|
-
'247' => '233',
|
639
|
-
'253' => '233',
|
640
|
-
'257' => '233',
|
641
|
-
'258' => '233',
|
642
|
-
'261' => '233',
|
643
|
-
'263' => '233',
|
644
|
-
'264' => '233',
|
645
|
-
'268' => '233',
|
646
|
-
'269' => '203',
|
647
|
-
'270' => '203',
|
648
|
-
'271' => '203',
|
649
|
-
'273' => '203',
|
650
|
-
'275' => '203',
|
651
|
-
'302' => '210',
|
652
|
-
'303' => '203',
|
653
|
-
'304' => '231',
|
654
|
-
'401' => '201',
|
655
|
-
'402' => '201',
|
656
|
-
'501' => '205',
|
657
|
-
'502' => '205',
|
658
|
-
'503' => '209',
|
659
|
-
'505' => '203',
|
660
|
-
'508' => '203',
|
661
|
-
'509' => '204',
|
662
|
-
'510' => '203',
|
663
|
-
'521' => '204',
|
664
|
-
'522' => '202',
|
665
|
-
'523' => '233',
|
666
|
-
'524' => '211',
|
667
|
-
'530' => '203',
|
668
|
-
'531' => '211',
|
669
|
-
'540' => '203',
|
670
|
-
'541' => '205',
|
671
|
-
'542' => '203',
|
672
|
-
'543' => '203',
|
673
|
-
'544' => '203',
|
674
|
-
'545' => '203',
|
675
|
-
'546' => '203',
|
676
|
-
'547' => '233',
|
677
|
-
'548' => '233',
|
678
|
-
'549' => '203',
|
679
|
-
'550' => '203',
|
680
|
-
'551' => '233',
|
681
|
-
'560' => '203',
|
682
|
-
'561' => '203',
|
683
|
-
'562' => '203',
|
684
|
-
'563' => '203',
|
685
|
-
'564' => '203',
|
686
|
-
'567' => '203',
|
687
|
-
'570' => '203',
|
688
|
-
'571' => '203',
|
689
|
-
'572' => '203',
|
690
|
-
'591' => '231',
|
691
|
-
'592' => '203',
|
692
|
-
'594' => '203',
|
693
|
-
'595' => '208',
|
694
|
-
'596' => '205',
|
695
|
-
'597' => '233',
|
696
|
-
'602' => '233',
|
697
|
-
'603' => '233',
|
698
|
-
'605' => '233',
|
699
|
-
'606' => '208',
|
700
|
-
'607' => '233',
|
701
|
-
'610' => '231',
|
702
|
-
'617' => '203',
|
703
|
-
'719' => '203',
|
704
|
-
'740' => '233',
|
705
|
-
'741' => '233',
|
706
|
-
'742' => '233',
|
707
|
-
'747' => '233',
|
708
|
-
'750' => '233',
|
709
|
-
'751' => '233',
|
710
|
-
'752' => '233',
|
711
|
-
'753' => '233',
|
712
|
-
'754' => '233',
|
713
|
-
'755' => '233',
|
714
|
-
'756' => '233',
|
715
|
-
'757' => '233',
|
716
|
-
'758' => '233',
|
717
|
-
'759' => '233',
|
718
|
-
'760' => '233',
|
719
|
-
'763' => '233',
|
720
|
-
'764' => '233',
|
721
|
-
'765' => '233',
|
722
|
-
'766' => '233',
|
723
|
-
'767' => '233',
|
724
|
-
'768' => '233',
|
725
|
-
'802' => '203',
|
726
|
-
'806' => '203',
|
727
|
-
=end
|
728
|
-
'811' => '209',
|
729
|
-
'813' => '203',
|
730
|
-
'825' => '231',
|
731
|
-
'834' => '203',
|
732
|
-
'903' => '203',
|
733
|
-
'904' => '203'}.each do |expected_processor_response, expected_reason_code|
|
734
|
-
kb_payment = setup_kb_payment
|
735
|
-
amount = 2000 + expected_processor_response.to_i
|
736
|
-
payment_response = @plugin.purchase_payment(@pm.kb_account_id, kb_payment.id, kb_payment.transactions[0].id, SecureRandom.uuid, amount, @currency, properties, @call_context)
|
737
|
-
expected_error = ::ActiveMerchant::Billing::CyberSourceGateway.class_variable_get(:@@response_codes)[('r' + expected_reason_code).to_sym]
|
738
|
-
check_response(payment_response, nil, :PURCHASE, :ERROR, expected_error, expected_reason_code, expected_processor_response)
|
739
|
-
end
|
740
|
-
end
|
741
|
-
end
|
742
|
-
|
743
|
-
shared_examples 'success_auth_capture_and_refund' do
|
744
|
-
it 'should be able to auth, capture and refund with descriptors' do
|
745
|
-
@pm = create_payment_method(::Killbill::Cybersource::CybersourcePaymentMethod, nil, @call_context.tenant_id, @properties)
|
746
|
-
|
747
|
-
payment_response = @plugin.authorize_payment(@pm.kb_account_id, payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
748
|
-
check_response(payment_response, @amount, :AUTHORIZE, :PROCESSED, 'Successful transaction', '100')
|
749
|
-
|
750
|
-
# Try a capture
|
751
|
-
payment_response = @plugin.capture_payment(@pm.kb_account_id, payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
752
|
-
check_response(payment_response, @amount, :CAPTURE, :PROCESSED, 'Successful transaction', '100')
|
753
|
-
|
754
|
-
# Try a refund
|
755
|
-
refund_response = @plugin.refund_payment(@pm.kb_account_id, payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
|
756
|
-
check_response(refund_response, @amount, :REFUND, :PROCESSED, 'Successful transaction', '100')
|
757
|
-
end
|
758
|
-
end
|
759
|
-
|
760
|
-
describe 'with merchant descriptor' do
|
761
|
-
before do
|
762
|
-
@properties << build_property('merchant_descriptor', {"name"=>"Ray Qiu", "contact"=>"6508883161"}.to_json)
|
763
|
-
end
|
764
|
-
let(:payment_id){ SecureRandom.uuid }
|
765
|
-
|
766
|
-
context 'using cybersource token' do
|
767
|
-
it_behaves_like 'success_auth_capture_and_refund'
|
768
|
-
end
|
769
|
-
|
770
|
-
context 'using credit card' do
|
771
|
-
before do
|
772
|
-
@properties << build_property('email', 'foo@bar.com')
|
773
|
-
@properties << build_property('cc_number', '4111111111111111')
|
774
|
-
end
|
775
|
-
it_behaves_like 'success_auth_capture_and_refund'
|
776
|
-
end
|
777
|
-
end
|
778
|
-
|
779
|
-
private
|
780
|
-
|
781
|
-
def check_response(payment_response, amount, transaction_type, expected_status, expected_error, expected_error_code, expected_processor_response = nil)
|
782
|
-
payment_response.amount.should == amount
|
783
|
-
payment_response.transaction_type.should == transaction_type
|
784
|
-
payment_response.status.should eq(expected_status), payment_response.gateway_error
|
785
|
-
|
786
|
-
gw_response = Killbill::Cybersource::CybersourceResponse.last
|
787
|
-
gw_response.gateway_error.should == expected_error
|
788
|
-
gw_response.gateway_error_code.should == expected_error_code
|
789
|
-
gw_response.params_processor_response.should == expected_processor_response unless expected_processor_response.nil?
|
790
|
-
end
|
791
|
-
|
792
|
-
def setup_kb_payment(nb_transactions=1, kb_payment_id=SecureRandom.uuid)
|
793
|
-
kb_payment = nil
|
794
|
-
1.upto(nb_transactions) do
|
795
|
-
kb_payment = @plugin.kb_apis.proxied_services[:payment_api].add_payment(kb_payment_id)
|
796
|
-
end
|
797
|
-
kb_payment
|
798
|
-
end
|
799
|
-
|
800
|
-
def await(timeout=15)
|
801
|
-
timeout.times do
|
802
|
-
return if block_given? && yield
|
803
|
-
sleep(1)
|
804
|
-
end
|
805
|
-
fail('Timeout')
|
806
|
-
end
|
807
|
-
end
|