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.
@@ -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 &amp; 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