Merge pull request #13283 from aydun/token_note_fix
[civicrm-core.git] / tests / phpunit / CRM / Contribute / Form / SearchTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 * Include parent class definition
30 */
31
32 /**
33 * Test Contribution Search form filters
34 *
35 * @package CiviCRM
36 */
37 class CRM_Contribute_Form_SearchTest extends CiviUnitTestCase {
38
39 protected $_individual;
40 protected $_tablesToTruncate = ['civicrm_contribution', 'civicrm_line_item'];
41
42 public function setUp() {
43 parent::setUp();
44 $this->_individual = $this->individualCreate();
45 }
46
47 public function tearDown() {
48 }
49
50 /**
51 * CRM-19325: Test CRM_Contribute_Form_Search batch filters
52 */
53 public function testBatchFilter() {
54 $this->quickCleanup($this->_tablesToTruncate);
55 $contactID1 = $this->individualCreate([], 1);
56 $contactID2 = $this->individualCreate([], 2);
57 $batchTitle = CRM_Batch_BAO_Batch::generateBatchName();
58
59 // create batch
60 $batch = $this->callAPISuccess('Batch', 'create', [
61 'created_id' => $this->_individual,
62 'created_date' => CRM_Utils_Date::processDate(date("Y-m-d"), date("H:i:s")),
63 'status_id' => CRM_Core_Pseudoconstant::getKey('CRM_Batch_BAO_Batch', 'status_id', 'Data Entry'),
64 'title' => $batchTitle,
65 'item_count' => 2,
66 'total' => 100,
67 'type_id' => array_search('Contribution', CRM_Batch_BAO_Batch::buildOptions('type_id')),
68 ]);
69 $batchID = $batch['id'];
70
71 $batchEntry = [
72 'primary_profiles' => [1 => NULL, 2 => NULL, 3 => NULL],
73 'primary_contact_id' => [
74 1 => $contactID1,
75 2 => $contactID2,
76 ],
77 'field' => [
78 1 => [
79 'financial_type' => 1,
80 'total_amount' => 70,
81 'receive_date' => '2013-07-24',
82 'receive_date_time' => NULL,
83 'payment_instrument' => 1,
84 'check_number' => NULL,
85 'contribution_status_id' => 1,
86 ],
87 2 => [
88 'financial_type' => 1,
89 'total_amount' => 30,
90 'receive_date' => '2014-07-24',
91 'receive_date_time' => NULL,
92 'payment_instrument' => 1,
93 'check_number' => NULL,
94 'contribution_status_id' => 1,
95 ],
96 ],
97 'actualBatchTotal' => 100,
98 ];
99
100 // create random contribution to check IS NULL filter more precisely
101 $nonBatchContri = $this->callAPISuccess('Contribution', 'create', [
102 'financial_type_id' => 1,
103 'total_amount' => 123,
104 'receive_date' => '2014-07-24',
105 'receive_date_time' => NULL,
106 'payment_instrument' => 1,
107 'check_number' => NULL,
108 'contribution_status_id' => 1,
109 'contact_id' => $this->_individual,
110 ]);
111 $nonBatchContriID = $nonBatchContri['id'];
112
113 // process batch entries
114 $form = new CRM_Batch_Form_Entry();
115 $form->setBatchID($batchID);
116 $form->testProcessContribution($batchEntry);
117
118 // fetch created contributions
119 $entities = $this->callAPISuccess('EntityBatch', 'get', array('batch_id' => $batchID));
120 $ids = [];
121 foreach ($entities['values'] as $value) {
122 $ids[] = $value['entity_id'];
123 }
124 list($batchContriID1, $batchContriID2) = $ids;
125
126 $useCases = [
127 // Case 1: Search for ONLY those contributions which are created from batch
128 [
129 'form_value' => array('contribution_batch_id' => 'IS NOT NULL'),
130 'expected_count' => 2,
131 'expected_contribution' => array($batchContriID1, $batchContriID2),
132 'expected_qill' => 'Batch Name Not Null',
133 ],
134 // Case 2: Search for ONLY those contributions which are NOT created from batch
135 [
136 'form_value' => array('contribution_batch_id' => 'IS NULL'),
137 'expected_count' => 1,
138 'expected_contribution' => array($nonBatchContriID),
139 'expected_qill' => 'Batch Name Is Null',
140 ],
141 // Case 3: Search for ONLY those contributions which are created from batch ID - $batchID
142 [
143 'form_value' => array('contribution_batch_id' => $batchID),
144 'expected_count' => 2,
145 'expected_contribution' => array($batchContriID1, $batchContriID2),
146 'expected_qill' => 'Batch Name = ' . $batchTitle,
147 ],
148 ];
149 foreach ($useCases as $case) {
150 $fv = $case['form_value'];
151 CRM_Contact_BAO_Query::processSpecialFormValue($fv, array('contribution_batch_id'));
152 $query = new CRM_Contact_BAO_Query(CRM_Contact_BAO_Query::convertFormValues($fv));
153 list($select, $from, $where) = $query->query();
154
155 // get and assert contribution count
156 $contributions = CRM_Core_DAO::executeQuery(sprintf('SELECT DISTINCT civicrm_contribution.id %s %s AND civicrm_contribution.id IS NOT NULL', $from, $where))->fetchAll();
157 foreach ($contributions as $key => $value) {
158 $contributions[$key] = $value['id'];
159 }
160 // assert the contribution count
161 $this->assertEquals($case['expected_count'], count($contributions));
162 // assert the contribution IDs
163 $this->checkArrayEquals($case['expected_contribution'], $contributions);
164 // get and assert qill string
165 $qill = trim(implode($query->getOperator(), CRM_Utils_Array::value(0, $query->qill())));
166 $this->assertEquals($case['expected_qill'], $qill);
167 }
168 }
169
170 /**
171 * CRM-20286: Test CRM_Contribute_Form_Search Card type filters
172 */
173 public function testCardTypeFilter() {
174 $this->quickCleanup($this->_tablesToTruncate);
175 $contactID1 = $this->individualCreate(array(), 1);
176 $contactID2 = $this->individualCreate(array(), 2);
177 $Contribution1 = $this->callAPISuccess('Contribution', 'create', array(
178 'financial_type_id' => 1,
179 'total_amount' => 100,
180 'receive_date' => date('Ymd'),
181 'receive_date_time' => NULL,
182 'payment_instrument' => 1,
183 'contribution_status_id' => 1,
184 'contact_id' => $contactID1,
185 ));
186 $params = array(
187 'to_financial_account_id' => 1,
188 'status_id' => 1,
189 'contribution_id' => $Contribution1['id'],
190 'payment_instrument_id' => 1,
191 'card_type_id' => 1,
192 'total_amount' => 100,
193 );
194 CRM_Core_BAO_FinancialTrxn::create($params);
195 $this->callAPISuccess('Contribution', 'create', array(
196 'financial_type_id' => 1,
197 'total_amount' => 150,
198 'receive_date' => date('Ymd'),
199 'receive_date_time' => NULL,
200 'payment_instrument' => 1,
201 'contribution_status_id' => 1,
202 'contact_id' => $contactID1,
203 ));
204 $Contribution3 = $this->callAPISuccess('Contribution', 'create', array(
205 'financial_type_id' => 1,
206 'total_amount' => 200,
207 'receive_date' => date('Ymd'),
208 'receive_date_time' => NULL,
209 'payment_instrument' => 1,
210 'contribution_status_id' => 1,
211 'contact_id' => $contactID2,
212 ));
213 $params = array(
214 'to_financial_account_id' => 1,
215 'status_id' => 1,
216 'contribution_id' => $Contribution3['id'],
217 'payment_instrument_id' => 1,
218 'card_type_id' => 2,
219 'total_amount' => 200,
220 );
221 CRM_Core_BAO_FinancialTrxn::create($params);
222
223 $useCases = array(
224 // Case 1: Search for ONLY those contributions which have card type
225 array(
226 'form_value' => array('financial_trxn_card_type_id' => 'IS NOT NULL'),
227 'expected_count' => 2,
228 'expected_contribution' => array($Contribution1['id'], $Contribution3['id']),
229 'expected_qill' => 'Card Type Not Null',
230 ),
231 // Case 2: Search for ONLY those contributions which have Card Type as Visa
232 array(
233 'form_value' => array('financial_trxn_card_type_id' => array(1)),
234 'expected_count' => 1,
235 'expected_contribution' => array($Contribution1['id']),
236 'expected_qill' => 'Card Type In Visa',
237 ),
238 // Case 3: Search for ONLY those contributions which have Card Type as Amex
239 array(
240 'form_value' => array('financial_trxn_card_type_id' => array(3)),
241 'expected_count' => 0,
242 'expected_contribution' => array(),
243 'expected_qill' => 'Card Type In Amex',
244 ),
245 // Case 4: Search for ONLY those contributions which have Card Type as Visa or MasterCard
246 array(
247 'form_value' => array('financial_trxn_card_type_id' => array(1, 2)),
248 'expected_count' => 2,
249 'expected_contribution' => array($Contribution1['id'], $Contribution3['id']),
250 'expected_qill' => 'Card Type In Visa, MasterCard',
251 ),
252 );
253
254 foreach ($useCases as $case) {
255 $fv = $case['form_value'];
256 CRM_Contact_BAO_Query::processSpecialFormValue($fv, array('financial_trxn_card_type_id'));
257 $query = new CRM_Contact_BAO_Query(CRM_Contact_BAO_Query::convertFormValues($fv));
258 list($select, $from, $where) = $query->query();
259
260 // get and assert contribution count
261 $contributions = CRM_Core_DAO::executeQuery(sprintf('SELECT DISTINCT civicrm_contribution.id %s %s AND civicrm_contribution.id IS NOT NULL', $from, $where))->fetchAll();
262 foreach ($contributions as $key => $value) {
263 $contributions[$key] = $value['id'];
264 }
265 // assert the contribution count
266 //$this->assertEquals($case['expected_count'], count($contributions));
267 // assert the contribution IDs
268 $this->checkArrayEquals($case['expected_contribution'], $contributions);
269 // get and assert qill string
270 $qill = trim(implode($query->getOperator(), CRM_Utils_Array::value(0, $query->qill())));
271 $this->assertEquals($case['expected_qill'], $qill);
272 }
273 }
274
275 /**
276 * CRM-20391: Test CRM_Contribute_Form_Search Card Number filters
277 */
278 public function testCardNumberFilter() {
279 $this->quickCleanup($this->_tablesToTruncate);
280 $contactID1 = $this->individualCreate(array(), 1);
281 $contactID2 = $this->individualCreate(array(), 2);
282 $Contribution1 = $this->callAPISuccess('Contribution', 'create', array(
283 'financial_type_id' => 1,
284 'total_amount' => 100,
285 'receive_date' => date('Ymd'),
286 'receive_date_time' => NULL,
287 'payment_instrument' => 1,
288 'contribution_status_id' => 1,
289 'contact_id' => $contactID1,
290 ));
291 $params = array(
292 'to_financial_account_id' => 1,
293 'status_id' => 1,
294 'contribution_id' => $Contribution1['id'],
295 'payment_instrument_id' => 1,
296 'card_type_id' => 1,
297 'total_amount' => 100,
298 'pan_truncation' => 1234,
299 );
300 CRM_Core_BAO_FinancialTrxn::create($params);
301 $this->callAPISuccess('Contribution', 'create', array(
302 'financial_type_id' => 1,
303 'total_amount' => 150,
304 'receive_date' => date('Ymd'),
305 'receive_date_time' => NULL,
306 'payment_instrument' => 1,
307 'contribution_status_id' => 1,
308 'contact_id' => $contactID1,
309 ));
310 $Contribution3 = $this->callAPISuccess('Contribution', 'create', array(
311 'financial_type_id' => 1,
312 'total_amount' => 200,
313 'receive_date' => date('Ymd'),
314 'receive_date_time' => NULL,
315 'payment_instrument' => 1,
316 'contribution_status_id' => 1,
317 'contact_id' => $contactID2,
318 ));
319 $params = array(
320 'to_financial_account_id' => 1,
321 'status_id' => 1,
322 'contribution_id' => $Contribution3['id'],
323 'payment_instrument_id' => 1,
324 'card_type_id' => 2,
325 'total_amount' => 200,
326 'pan_truncation' => 5678,
327 );
328 CRM_Core_BAO_FinancialTrxn::create($params);
329
330 $useCases = array(
331 // Case 1: Search for ONLY those contributions which have card number
332 array(
333 'form_value' => array('financial_trxn_pan_truncation' => 'IS NOT NULL'),
334 'expected_count' => 2,
335 'expected_contribution' => array($Contribution1['id'], $Contribution3['id']),
336 'expected_qill' => 'Card Number Not Null',
337 ),
338 // Case 2: Search for ONLY those contributions which have Card Number as 1234
339 array(
340 'form_value' => array('financial_trxn_pan_truncation' => 1234),
341 'expected_count' => 1,
342 'expected_contribution' => array($Contribution1['id']),
343 'expected_qill' => 'Card Number Like %1234%',
344 ),
345 // Case 3: Search for ONLY those contributions which have Card Number as 8888
346 array(
347 'form_value' => array('financial_trxn_pan_truncation' => 8888),
348 'expected_count' => 0,
349 'expected_contribution' => array(),
350 'expected_qill' => 'Card Number Like %8888%',
351 ),
352 );
353
354 foreach ($useCases as $case) {
355 $fv = $case['form_value'];
356 CRM_Contact_BAO_Query::processSpecialFormValue($fv, array('financial_trxn_pan_truncation'));
357 $query = new CRM_Contact_BAO_Query(CRM_Contact_BAO_Query::convertFormValues($fv));
358 list($select, $from, $where) = $query->query();
359
360 // get and assert contribution count
361 $contributions = CRM_Core_DAO::executeQuery(sprintf('SELECT DISTINCT civicrm_contribution.id %s %s AND civicrm_contribution.id IS NOT NULL', $from, $where))->fetchAll();
362 foreach ($contributions as $key => $value) {
363 $contributions[$key] = $value['id'];
364 }
365 // assert the contribution count
366 $this->assertEquals($case['expected_count'], count($contributions));
367 // assert the contribution IDs
368 $this->checkArrayEquals($case['expected_contribution'], $contributions);
369 // get and assert qill string
370 $qill = trim(implode($query->getOperator(), CRM_Utils_Array::value(0, $query->qill())));
371 $this->assertEquals($case['expected_qill'], $qill);
372 }
373 }
374
375 /**
376 * Test CRM_Contribute_Form_Search Recurring Contribution Status Id filters
377 */
378 public function testContributionRecurStatusFilter() {
379 $this->quickCleanup($this->_tablesToTruncate);
380 $contactID1 = $this->individualCreate([], 1);
381 $contactID2 = $this->individualCreate([], 2);
382 // "In Progress" recurring contribution for contactID1
383 $ContributionRecur1 = $this->callAPISuccess('ContributionRecur', 'create', [
384 'sequential' => 1,
385 'contact_id' => $contactID1,
386 'frequency_interval' => 1,
387 'frequency_unit' => "month",
388 'amount' => 11,
389 'currency' => "CAD",
390 'payment_instrument_id' => 1,
391 'contribution_status_id' => 5,
392 'financial_type_id' => "Donation",
393 ]);
394 $Contribution1 = $this->callAPISuccess('Contribution', 'create', [
395 'financial_type_id' => 'Donation',
396 'total_amount' => 11,
397 'receive_date' => date('Ymd'),
398 'receive_date_time' => NULL,
399 'payment_instrument_id' => 1,
400 'contribution_status_id' => 1,
401 'contact_id' => $contactID1,
402 'contribution_recur_id' => $ContributionRecur1['id'],
403 ]);
404 $params = [
405 'to_financial_account_id' => 1,
406 'status_id' => 1,
407 'contribution_id' => $Contribution1['id'],
408 'payment_instrument_id' => 1,
409 'card_type_id' => 1,
410 'total_amount' => 11,
411 ];
412 CRM_Core_BAO_FinancialTrxn::create($params);
413 // "Completed" recurring contribution for contactID2
414 $ContributionRecur2 = $this->callAPISuccess('ContributionRecur', 'create', [
415 'sequential' => 1,
416 'contact_id' => $contactID2,
417 'frequency_interval' => 1,
418 'frequency_unit' => "month",
419 'amount' => 22,
420 'currency' => "CAD",
421 'payment_instrument_id' => 1,
422 'contribution_status_id' => 1,
423 'financial_type_id' => "Donation",
424 ]);
425 $Contribution2 = $this->callAPISuccess('Contribution', 'create', [
426 'financial_type_id' => 'Donation',
427 'total_amount' => 22,
428 'receive_date' => date('Ymd'),
429 'receive_date_time' => NULL,
430 'payment_instrument' => 1,
431 'contribution_status_id' => 1,
432 'contact_id' => $contactID2,
433 'contribution_recur_id' => $ContributionRecur2['id'],
434 ]);
435 $params = [
436 'to_financial_account_id' => 1,
437 'status_id' => 1,
438 'contribution_id' => $Contribution2['id'],
439 'payment_instrument_id' => 1,
440 'card_type_id' => 1,
441 'total_amount' => 22,
442 ];
443 CRM_Core_BAO_FinancialTrxn::create($params);
444
445 $useCases = [
446 // Case 1: Search for ONLY those recurring contributions with status "In Progress"
447 [
448 'form_value' => ['contribution_recur_contribution_status_id' => 5],
449 'expected_count' => 1,
450 'expected_contact' => [$contactID1],
451 'expected_qill' => "Recurring Contribution Status = 'In Progress'",
452 ],
453 // Case 2: Search for ONLY those recurring contributions with status "Completed"
454 [
455 'form_value' => ['contribution_recur_contribution_status_id' => 1],
456 'expected_count' => 1,
457 'expected_contact' => [$contactID2],
458 'expected_qill' => "Recurring Contribution Status = 'Completed'",
459 ],
460 // Case 3: Search for ONLY those recurring contributions with status "Cancelled"
461 [
462 'form_value' => ['contribution_recur_contribution_status_id' => 3],
463 'expected_count' => 0,
464 'expected_contact' => [],
465 'expected_qill' => "Recurring Contribution Status = 'Cancelled'",
466 ],
467 ];
468
469 foreach ($useCases as $case) {
470 $fv = $case['form_value'];
471 $query = new CRM_Contact_BAO_Query(CRM_Contact_BAO_Query::convertFormValues($fv));
472 list($select, $from, $where, $having) = $query->query();
473
474 // get and assert contribution count
475 $contacts = CRM_Core_DAO::executeQuery(sprintf('SELECT DISTINCT contact_a.id %s %s AND contact_a.id IS NOT NULL', $from, $where))->fetchAll();
476 foreach ($contacts as $key => $value) {
477 $contacts[$key] = $value['id'];
478 }
479 // assert the contribution count
480 $this->assertEquals($case['expected_count'], count($contacts));
481 // assert the contribution IDs
482 $this->checkArrayEquals($case['expected_contact'], $contacts);
483 // get and assert qill string
484 $qill = trim(implode($query->getOperator(), CRM_Utils_Array::value(0, $query->qill())));
485 $this->assertEquals($case['expected_qill'], $qill);
486 }
487 }
488
489 /**
490 * CRM-21343: Test CRM_Contribute_Form_Search Cancelled filters
491 */
492 public function testCancelledFilter() {
493 $this->quickCleanup($this->_tablesToTruncate);
494 $contactID1 = $this->individualCreate([], 1);
495 $contactID2 = $this->individualCreate([], 2);
496 $Contribution1 = $this->callAPISuccess('Contribution', 'create', [
497 'financial_type_id' => 1,
498 'total_amount' => 100,
499 'receive_date' => date('Ymd'),
500 'receive_date_time' => NULL,
501 'payment_instrument' => 1,
502 'contribution_status_id' => 3,
503 'cancel_date' => date('Ymd'),
504 'cancel_reason' => 'Insufficient funds',
505 'contact_id' => $contactID1,
506 ]);
507 $this->callAPISuccess('Contribution', 'create', [
508 'financial_type_id' => 1,
509 'total_amount' => 150,
510 'receive_date' => date('Ymd', strtotime(date('Y-m-d') . ' - 1 days')),
511 'receive_date_time' => NULL,
512 'payment_instrument' => 1,
513 'contribution_status_id' => 3,
514 'cancel_date' => date('Ymd', strtotime(date('Y-m-d') . ' - 1 days')),
515 'cancel_reason' => 'Insufficient funds',
516 'contact_id' => $contactID2,
517 ]);
518 $Contribution3 = $this->callAPISuccess('Contribution', 'create', [
519 'financial_type_id' => 1,
520 'total_amount' => 200,
521 'receive_date' => date('Ymd'),
522 'receive_date_time' => NULL,
523 'payment_instrument' => 1,
524 'contribution_status_id' => 3,
525 'cancel_date' => date('Ymd'),
526 'cancel_reason' => 'Invalid Credit Card Number',
527 'contact_id' => $contactID1,
528 ]);
529
530 $useCases = [
531 // Case 1: Search for Cancelled Date
532 [
533 'form_value' => ['cancel_date' => date('Y-m-d')],
534 'expected_count' => 2,
535 'expected_contribution' => [$Contribution1['id'], $Contribution3['id']],
536 'expected_qill' => "Cancel Date Like '%" . date('Y-m-d') . "%'",
537 ],
538 // Case 2: Search for Cancelled Reason
539 [
540 'form_value' => ['cancel_reason' => 'Invalid Credit Card Number'],
541 'expected_count' => 1,
542 'expected_contribution' => [$Contribution3['id']],
543 'expected_qill' => "Cancellation / Refund Reason Like '%Invalid Credit Card Number%'",
544 ],
545 // Case 3: Search for Cancelled Date and Cancelled Reason
546 [
547 'form_value' => ['cancel_date' => date('Y-m-d'), 'cancel_reason' => 'Insufficient funds'],
548 'expected_count' => 1,
549 'expected_contribution' => [$Contribution1['id']],
550 'expected_qill' => "Cancel Date Like '%" . date('Y-m-d') . "%'ANDCancellation / Refund Reason Like '%Insufficient funds%'",
551 ],
552 ];
553
554 foreach ($useCases as $case) {
555 $fv = $case['form_value'];
556 CRM_Contact_BAO_Query::processSpecialFormValue($fv, ['cancel_date', 'cancel_reason']);
557 $query = new CRM_Contact_BAO_Query(CRM_Contact_BAO_Query::convertFormValues($fv));
558 list($select, $from, $where) = $query->query();
559
560 // get and assert contribution count
561 $contributions = CRM_Core_DAO::executeQuery(sprintf('SELECT DISTINCT civicrm_contribution.id %s %s AND civicrm_contribution.id IS NOT NULL AND civicrm_contribution.contribution_status_id = 3', $from, $where))->fetchAll();
562 foreach ($contributions as $key => $value) {
563 $contributions[$key] = $value['id'];
564 }
565 // assert the contribution count
566 $this->assertEquals($case['expected_count'], count($contributions));
567 // assert the contribution IDs
568 $this->checkArrayEquals($case['expected_contribution'], $contributions);
569 // get and assert qill string
570 $qill = trim(implode($query->getOperator(), CRM_Utils_Array::value(0, $query->qill())));
571 $this->assertEquals($case['expected_qill'], $qill);
572 }
573 }
574
575 }