3 use Civi\Payment\Exception\PaymentProcessorException
;
6 * Class CRM_Core_Payment_PayPalProIPNTest
9 class CRM_Core_Payment_AuthorizeNetIPNTest
extends CiviUnitTestCase
{
10 use CRMTraits_Financial_OrderTrait
;
12 protected $_contributionID;
13 protected $_invoiceID = 'c2r9c15f7be20b4f3fef1f77e4c37424';
14 protected $_financialTypeID = 1;
15 protected $_contactID;
16 protected $_contributionRecurID;
17 protected $_contributionPageID;
18 protected $_paymentProcessorID;
22 * @throws \CRM_Core_Exception
24 public function setUp() {
26 $this->_paymentProcessorID
= $this->paymentProcessorAuthorizeNetCreate(['is_test' => 0]);
27 $this->_contactID
= $this->individualCreate();
28 $contributionPage = $this->callAPISuccess('contribution_page', 'create', [
29 'title' => 'Test Contribution Page',
30 'financial_type_id' => $this->_financialTypeID
,
32 'payment_processor' => $this->_paymentProcessorID
,
34 'receipt_from_email' => 'gaia@the.cosmos',
35 'receipt_from_name' => 'Pachamama',
36 'is_email_receipt' => TRUE,
38 $this->_contributionPageID
= $contributionPage['id'];
41 public function tearDown() {
42 $this->quickCleanUpFinancialEntities();
46 * Ensure recurring contributions from Contribution Pages
47 * with receipt turned off don't send a receipt.
49 * @throws \CiviCRM_API3_Exception
50 * @throws \CRM_Core_Exception
52 public function testIPNPaymentRecurNoReceipt() {
53 $mut = new CiviMailUtils($this, TRUE);
54 // Turn off receipts in contribution page.
56 'id' => $this->_contributionPageID
,
57 'is_email_receipt' => FALSE,
59 $this->callAPISuccess('contributionPage', 'update', $api_params);
61 // Create initial recurring payment and initial contribution.
62 // Note - we can't use setupRecurringPaymentProcessorTransaction(), which
63 // would be convenient because it does not fully mimic the real user
64 // experience. Using setupRecurringPaymentProcessorTransaction() doesn't
65 // specify is_email_receipt so it is always set to 1. We need to more
66 // closely mimic what happens with a live transaction to test that
67 // is_email_receipt is not set to 1 if the originating contribution page
68 // has is_email_receipt set to 0.
69 $form = new CRM_Contribute_Form_Contribution();
70 $form->_mode
= 'Live';
72 $contribution = $form->testSubmit([
73 'total_amount' => 200,
74 'financial_type_id' => 1,
75 'receive_date' => date('m/d/Y'),
76 'receive_date_time' => date('H:i:s'),
77 'contact_id' => $this->_contactID
,
78 'contribution_status_id' => 1,
79 'credit_card_number' => 4444333322221111,
81 'credit_card_exp_date' => [
85 'credit_card_type' => 'Visa',
86 'billing_first_name' => 'Junko',
87 'billing_middle_name' => '',
88 'billing_last_name' => 'Adams',
89 'billing_street_address-5' => time() . ' Lincoln St S',
90 'billing_city-5' => 'Maryknoll',
91 'billing_state_province_id-5' => 1031,
92 'billing_postal_code-5' => 10545,
93 'billing_country_id-5' => 1228,
94 'frequency_interval' => 1,
95 'frequency_unit' => 'month',
97 'hidden_AdditionalDetail' => 1,
98 'hidden_Premium' => 1,
99 'payment_processor_id' => $this->_paymentProcessorID
,
101 'source' => 'bob sled race',
102 'contribution_page_id' => $this->_contributionPageID
,
104 ], CRM_Core_Action
::ADD
);
106 catch (PaymentProcessorException
$e) {
107 $this->markTestSkipped('Error from A.net - cannot proceed');
109 $this->_contributionID
= $contribution->id
;
110 $this->ids
['Contribution'][0] = $contribution->id
;
111 $this->_contributionRecurID
= $contribution->contribution_recur_id
;
113 'id' => $this->_contributionRecurID
,
114 'return' => 'processor_id',
116 $processor_id = civicrm_api3('ContributionRecur', 'getvalue', $recur_params);
117 // Process the initial one.
118 $IPN = new CRM_Core_Payment_AuthorizeNetIPN(
119 $this->getRecurTransaction(['x_subscription_id' => $processor_id])
123 // Now send a second one (authorize seems to treat first and second contributions
125 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurSubsequentTransaction(
126 ['x_subscription_id' => $processor_id]
130 // There should not be any email.
131 $mut->assertMailLogEmpty();
135 * Test IPN response updates contribution_recur & contribution for first & second contribution
137 * @throws \CRM_Core_Exception
139 public function testIPNPaymentRecurSuccess() {
140 $this->setupRecurringPaymentProcessorTransaction();
141 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction());
143 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['id' => $this->_contributionID
]);
144 $this->assertEquals(1, $contribution['contribution_status_id']);
145 $this->assertEquals('6511143069', $contribution['trxn_id']);
146 // source gets set by processor
147 $this->assertTrue(substr($contribution['contribution_source'], 0, 20) == "Online Contribution:");
148 $contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $this->_contributionRecurID
]);
149 $this->assertEquals(5, $contributionRecur['contribution_status_id']);
150 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurSubsequentTransaction());
152 $contribution = $this->callAPISuccess('contribution', 'get', [
153 'contribution_recur_id' => $this->_contributionRecurID
,
156 $this->assertEquals(2, $contribution['count']);
157 $this->assertEquals('second_one', $contribution['values'][1]['trxn_id']);
158 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contribution['values'][1]['receive_date'])));
162 * Test payment processor is correctly assigned for the IPN payment.
164 public function testIPNPaymentRecurSuccessMultiAuthNetProcessor() {
165 //Create and set up recur payment using second instance of AuthNet Processor.
166 $this->_paymentProcessorID2
= $this->paymentProcessorAuthorizeNetCreate(['name' => 'Authorize2', 'is_test' => 0]);
167 $this->setupRecurringPaymentProcessorTransaction(['payment_processor_id' => $this->_paymentProcessorID2
]);
169 //Call IPN with processor id.
170 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction(['processor_id' => $this->_paymentProcessorID2
]));
172 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['id' => $this->_contributionID
]);
173 $this->assertEquals(1, $contribution['contribution_status_id']);
174 $this->assertEquals('6511143069', $contribution['trxn_id']);
175 // source gets set by processor
176 $this->assertTrue(substr($contribution['contribution_source'], 0, 20) == "Online Contribution:");
177 $contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $this->_contributionRecurID
]);
178 $this->assertEquals(5, $contributionRecur['contribution_status_id']);
182 * Test IPN response updates contribution_recur & contribution for first & second contribution
184 public function testIPNPaymentRecurSuccessSuppliedReceiveDate() {
185 $this->setupRecurringPaymentProcessorTransaction();
186 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction());
188 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['id' => $this->_contributionID
]);
189 $this->assertEquals(1, $contribution['contribution_status_id']);
190 $this->assertEquals('6511143069', $contribution['trxn_id']);
191 // source gets set by processor
192 $this->assertTrue(substr($contribution['contribution_source'], 0, 20) == "Online Contribution:");
193 $contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $this->_contributionRecurID
]);
194 $this->assertEquals(5, $contributionRecur['contribution_status_id']);
195 $IPN = new CRM_Core_Payment_AuthorizeNetIPN(array_merge(['receive_date' => '1 July 2010'], $this->getRecurSubsequentTransaction()));
197 $contribution = $this->callAPISuccess('contribution', 'get', [
198 'contribution_recur_id' => $this->_contributionRecurID
,
201 $this->assertEquals(2, $contribution['count']);
202 $this->assertEquals('second_one', $contribution['values'][1]['trxn_id']);
203 $this->assertEquals('2010-07-01', date('Y-m-d', strtotime($contribution['values'][1]['receive_date'])));
207 * Test IPN response updates contribution_recur & contribution for first & second contribution
209 * @throws \CRM_Core_Exception
211 public function testIPNPaymentMembershipRecurSuccess() {
212 $this->createRepeatMembershipOrder();
213 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction());
215 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['id' => $this->ids
['Contribution'][0]]);
216 $this->assertEquals(1, $contribution['contribution_status_id']);
217 $this->assertEquals('6511143069', $contribution['trxn_id']);
219 // source gets set by processor
220 $this->assertEquals('Online Contribution:', substr($contribution['contribution_source'], 0, 20));
221 $contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $this->_contributionRecurID
]);
222 $this->assertEquals(5, $contributionRecur['contribution_status_id']);
223 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurSubsequentTransaction());
225 $contribution = $this->callAPISuccess('contribution', 'get', [
226 'contribution_recur_id' => $this->_contributionRecurID
,
229 $this->assertEquals(2, $contribution['count']);
230 // Ensure both contributions are coded as credit card contributions.
231 $this->assertEquals(1, $contribution['values'][0]['payment_instrument_id']);
232 $this->assertEquals(1, $contribution['values'][1]['payment_instrument_id']);
233 $this->assertEquals('second_one', $contribution['values'][1]['trxn_id']);
234 $this->callAPISuccessGetSingle('membership_payment', ['contribution_id' => $contribution['values'][1]['id']]);
235 $this->callAPISuccessGetSingle('line_item', [
236 'contribution_id' => $contribution['values'][1]['id'],
237 'entity_table' => 'civicrm_membership',
239 $this->validateAllContributions();
240 $this->validateAllPayments();
244 * Test IPN response mails don't leak.
246 public function testIPNPaymentMembershipRecurSuccessNoLeakage() {
247 $mut = new CiviMailUtils($this, TRUE);
248 $this->setupMembershipRecurringPaymentProcessorTransaction(['is_email_receipt' => TRUE]);
249 $this->addProfile('supporter_profile', $this->_contributionPageID
);
250 $this->addProfile('honoree_individual', $this->_contributionPageID
, 'soft_credit');
252 $this->callAPISuccess('ContributionSoft', 'create', [
253 'contact_id' => $this->individualCreate(),
254 'contribution_id' => $this->_contributionID
,
255 'soft_credit_type_id' => 'in_memory_of',
259 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction());
261 $mut->checkAllMailLog([
262 'Membership Type: General',
263 'Mr. Anthony Anderson II" <anthony_anderson@civicrm.org>',
265 'Membership Start Date:',
267 'First Name: Anthony',
268 'Last Name: Anderson',
269 'Email Address: anthony_anderson@civicrm.org',
271 'This membership will be automatically renewed every',
273 'Thanks for your auto renew membership sign-up',
276 $mut->clearMessages();
277 $this->_contactID
= $this->individualCreate(['first_name' => 'Antonia', 'prefix_id' => 'Mrs.', 'email' => 'antonia_anderson@civicrm.org']);
278 $this->_invoiceID
= uniqid();
280 // Note, the second contribution is not in honor of anyone and the
281 // receipt should not mention honor at all.
282 $this->setupMembershipRecurringPaymentProcessorTransaction(['is_email_receipt' => TRUE]);
283 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction(['x_trans_id' => 'hers']));
286 $mut->checkAllMailLog([
287 'Membership Type: General',
288 'Mrs. Antonia Anderson II',
289 'antonia_anderson@civicrm.org',
291 'Membership Start Date:',
292 'Transaction #: hers',
294 'First Name: Antonia',
295 'Last Name: Anderson',
296 'Email Address: antonia_anderson@civicrm.org',
297 'This membership will be automatically renewed every',
299 'Thanks for your auto renew membership sign-up',
302 $shouldNotBeInMailing = [
306 $mails = $mut->getAllMessages('raw');
307 foreach ($mails as $mail) {
308 $mut->checkMailForStrings([], $shouldNotBeInMailing, '', $mail);
311 $mut->clearMessages();
315 * Test IPN response mails don't leak.
317 public function testIPNPaymentMembershipRecurSuccessNoLeakageOnlineThenOffline() {
318 $mut = new CiviMailUtils($this, TRUE);
319 $this->setupMembershipRecurringPaymentProcessorTransaction(['is_email_receipt' => TRUE]);
320 $this->addProfile('supporter_profile', $this->_contributionPageID
);
321 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction());
323 $mut->checkAllMailLog([
324 'Membership Type: General',
325 'Mr. Anthony Anderson II" <anthony_anderson@civicrm.org>',
327 'Membership Start Date:',
329 'First Name: Anthony',
330 'Last Name: Anderson',
331 'Email Address: anthony_anderson@civicrm.org',
332 'This membership will be automatically renewed every',
334 'Thanks for your auto renew membership sign-up',
337 $this->_contactID
= $this->individualCreate(['first_name' => 'Antonia', 'prefix_id' => 'Mrs.', 'email' => 'antonia_anderson@civicrm.org']);
338 $this->_invoiceID
= uniqid();
339 $this->_contributionPageID
= NULL;
341 $this->setupMembershipRecurringPaymentProcessorTransaction(['is_email_receipt' => TRUE]);
342 $mut->clearMessages();
343 $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction(['x_trans_id' => 'hers']));
346 $mut->checkAllMailLog([
347 'Membership Type: General',
348 'Mrs. Antonia Anderson II',
349 'antonia_anderson@civicrm.org',
351 'Membership Start Date:',
352 'Transaction #: hers',
353 'This membership will be automatically renewed every',
355 'Thanks for your auto renew membership sign-up',
358 'First Name: Anthony',
359 'First Name: Antonia',
360 'Last Name: Anderson',
362 'Email Address: antonia_anderson@civicrm.org',
366 $mut->clearMessages();
370 * Get detail for recurring transaction.
372 * @param array $params
373 * Additional parameters.
376 * Parameters like AuthorizeNet silent post paramters.
378 public function getRecurTransaction($params = []) {
380 "x_amount" => "200.00",
384 "x_email" => "me@gmail.com",
385 "x_description" => "lots of money",
386 "x_type" => "auth_capture",
387 "x_ship_to_first_name" => "",
388 "x_ship_to_last_name" => "",
389 "x_ship_to_company" => "",
390 "x_ship_to_address" => "",
391 "x_ship_to_city" => "",
392 "x_ship_to_state" => "",
393 "x_ship_to_zip" => "",
394 "x_ship_to_country" => "",
397 "x_freight" => "0.00",
398 "x_tax_exempt" => "FALSE",
400 "x_MD5_Hash" => "1B7C0C5B4DEDD9CAD0636E35E22FC594",
401 "x_cvv2_resp_code" => "",
402 "x_cavv_response" => "",
403 "x_test_request" => "false",
404 "x_subscription_id" => $this->_contactID
,
405 "x_subscription_paynum" => "1",
406 'x_first_name' => 'Robert',
409 'x_city' => 'Dallas',
410 'x_address' => '41 My ST',
411 'x_invoice_num' => $this->ids
['Contribution'][0],
412 'x_cust_id' => $this->_contactID
,
413 'x_company' => 'nowhere@civicrm.org',
414 'x_last_name' => 'Roberts',
415 'x_account_number' => 'XXXX5077',
416 'x_card_type' => 'Visa',
418 'x_trans_id' => '6511143069',
419 'x_auth_code' => '123456',
421 'x_response_reason_text' => 'This transaction has been approved.',
422 'x_response_reason_code' => '1',
423 'x_response_code' => '1',
430 public function getRecurSubsequentTransaction($params = []) {
431 return array_merge($this->getRecurTransaction(), [
432 'x_trans_id' => 'second_one',
433 'x_MD5_Hash' => 'EA7A3CD65A85757827F51212CA1486A8',