killbill-cybersource 5.2.0 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- metadata +1 -26
- data/.gitignore +0 -35
- data/.travis.yml +0 -41
- data/Gemfile +0 -4
- data/Gemfile.head +0 -5
- data/Gemfile.lock +0 -151
- data/Jarfile +0 -12
- data/Jarfile.lock +0 -66
- data/LICENSE +0 -201
- data/NEWS +0 -85
- data/README.md +0 -163
- data/Rakefile +0 -39
- data/VERSION +0 -1
- data/config.ru +0 -4
- data/cybersource.yml +0 -38
- data/db/ddl.sql +0 -92
- data/db/migrate/20162519092522_enlarge_message.rb +0 -11
- data/db/schema.rb +0 -94
- data/killbill-cybersource.gemspec +0 -53
- data/killbill.properties +0 -3
- data/pom.xml +0 -44
- data/release.sh +0 -61
- data/spec/cybersource/base_plugin_spec.rb +0 -465
- data/spec/cybersource/cyber_source_on_demand_spec.rb +0 -276
- data/spec/cybersource/remote/integration_spec.rb +0 -807
- data/spec/spec_helper.rb +0 -28
@@ -1,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
|