Remove instances of fatal
[civicrm-core.git] / tests / phpunit / CRM / Member / Form / MembershipRenewalTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 * Test CRM_Member_Form_Membership functions.
14 *
15 * @package CiviCRM
16 * @group headless
17 */
18 class CRM_Member_Form_MembershipRenewalTest extends CiviUnitTestCase {
19
20 protected $_individualId;
21 protected $_contribution;
22 protected $_financialTypeId = 1;
23 protected $_entity = 'Membership';
24 protected $_params;
25 protected $_paymentProcessorID;
26
27 /**
28 * Membership type ID for annual fixed membership.
29 *
30 * @var int
31 */
32 protected $membershipTypeAnnualFixedID;
33
34 /**
35 * Parameters to create payment processor.
36 *
37 * @var array
38 */
39 protected $_processorParams = [];
40
41 /**
42 * ID of created membership.
43 *
44 * @var int
45 */
46 protected $_membershipID;
47
48 /**
49 * Payment instrument mapping.
50 *
51 * @var array
52 */
53 protected $paymentInstruments = [];
54
55
56 /**
57 * @var CiviMailUtils
58 */
59 protected $mut;
60
61 /**
62 * Test setup for every test.
63 *
64 * Connect to the database, truncate the tables that will be used
65 * and redirect stdin to a temporary file.
66 */
67 public function setUp() {
68 parent::setUp();
69
70 $this->_individualId = $this->individualCreate();
71 $this->_paymentProcessorID = $this->processorCreate();
72
73 $this->loadXMLDataSet(dirname(__FILE__) . '/dataset/data.xml');
74 $membershipTypeAnnualFixed = $this->callAPISuccess('membership_type', 'create', [
75 'domain_id' => 1,
76 'name' => "AnnualFixed",
77 'member_of_contact_id' => 23,
78 'duration_unit' => "year",
79 'duration_interval' => 1,
80 'period_type' => "fixed",
81 'fixed_period_start_day' => "101",
82 'fixed_period_rollover_day' => "1231",
83 'relationship_type_id' => 20,
84 'financial_type_id' => 2,
85 ]);
86 $this->membershipTypeAnnualFixedID = $membershipTypeAnnualFixed['id'];
87 $membership = $this->callAPISuccess('Membership', 'create', [
88 'contact_id' => $this->_individualId,
89 'membership_type_id' => $this->membershipTypeAnnualFixedID,
90 ]);
91 $this->_membershipID = $membership['id'];
92
93 $instruments = $this->callAPISuccess('contribution', 'getoptions', ['field' => 'payment_instrument_id']);
94 $this->paymentInstruments = $instruments['values'];
95 }
96
97 /**
98 * Clean up after each test.
99 */
100 public function tearDown() {
101 $this->validateAllPayments();
102 $this->validateAllContributions();
103 $this->quickCleanUpFinancialEntities();
104 $this->quickCleanup(
105 [
106 'civicrm_relationship',
107 'civicrm_membership_type',
108 'civicrm_membership',
109 'civicrm_uf_match',
110 'civicrm_address',
111 ]
112 );
113 foreach ([17, 18, 23, 32] as $contactID) {
114 $this->callAPISuccess('contact', 'delete', ['id' => $contactID, 'skip_undelete' => TRUE]);
115 }
116 $this->callAPISuccess('relationship_type', 'delete', ['id' => 20]);
117 }
118
119 /**
120 * Test the submit function of the membership form.
121 */
122 public function testSubmit() {
123 $form = $this->getForm();
124 $this->createLoggedInUser();
125 $params = [
126 'cid' => $this->_individualId,
127 'join_date' => date('m/d/Y', time()),
128 'start_date' => '',
129 'end_date' => '',
130 // This format reflects the 23 being the organisation & the 25 being the type.
131 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
132 'auto_renew' => '0',
133 'max_related' => '',
134 'num_terms' => '1',
135 'source' => '',
136 'total_amount' => '50.00',
137 //Member dues, see data.xml
138 'financial_type_id' => '2',
139 'soft_credit_type_id' => '',
140 'soft_credit_contact_id' => '',
141 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
142 'receipt_text_signup' => 'Thank you text',
143 'payment_processor_id' => $this->_paymentProcessorID,
144 'credit_card_number' => '4111111111111111',
145 'cvv2' => '123',
146 'credit_card_exp_date' => [
147 'M' => '9',
148 // TODO: Future proof
149 'Y' => '2024',
150 ],
151 'credit_card_type' => 'Visa',
152 'billing_first_name' => 'Test',
153 'billing_middlename' => 'Last',
154 'billing_street_address-5' => '10 Test St',
155 'billing_city-5' => 'Test',
156 'billing_state_province_id-5' => '1003',
157 'billing_postal_code-5' => '90210',
158 'billing_country_id-5' => '1228',
159 ];
160 $form->_contactID = $this->_individualId;
161
162 $form->testSubmit($params);
163 $form->setRenewalMessage();
164 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
165 $this->callAPISuccessGetCount('ContributionRecur', ['contact_id' => $this->_individualId], 0);
166 $contribution = $this->callAPISuccess('Contribution', 'get', [
167 'contact_id' => $this->_individualId,
168 'is_test' => TRUE,
169 ]);
170
171 $this->callAPISuccessGetCount('LineItem', [
172 'entity_id' => $membership['id'],
173 'entity_table' => 'civicrm_membership',
174 'contribution_id' => $contribution['id'],
175 ], 1);
176 $this->_checkFinancialRecords([
177 'id' => $contribution['id'],
178 'total_amount' => 50,
179 'financial_account_id' => 2,
180 'payment_instrument_id' => $this->callAPISuccessGetValue('PaymentProcessor', [
181 'id' => $this->_paymentProcessorID,
182 'return' => 'payment_instrument_id',
183 ]),
184 ], 'online');
185 $this->assertEquals([
186 [
187 'text' => 'AnnualFixed membership for Mr. Anthony Anderson II has been renewed.',
188 'title' => 'Complete',
189 'type' => 'success',
190 'options' => NULL,
191 ],
192 ], CRM_Core_Session::singleton()->getStatus());
193 }
194
195 /**
196 * Test the submit function of the membership form.
197 *
198 * @throws \CRM_Core_Exception
199 */
200 public function testSubmitRecur() {
201 $form = $this->getForm();
202
203 $this->callAPISuccess('MembershipType', 'create', [
204 'id' => $this->membershipTypeAnnualFixedID,
205 'duration_unit' => 'month',
206 'duration_interval' => 1,
207 'auto_renew' => TRUE,
208 ]);
209 $form->preProcess();
210 $this->createLoggedInUser();
211 $params = [
212 'cid' => $this->_individualId,
213 'price_set_id' => 0,
214 'join_date' => date('m/d/Y', time()),
215 'start_date' => '',
216 'end_date' => '',
217 'campaign_id' => '',
218 // This format reflects the 23 being the organisation & the 25 being the type.
219 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
220 'auto_renew' => '1',
221 'is_recur' => 1,
222 'max_related' => 0,
223 'num_terms' => '1',
224 'source' => '',
225 'total_amount' => '77.00',
226 //Member dues, see data.xml
227 'financial_type_id' => '2',
228 'soft_credit_type_id' => 11,
229 'soft_credit_contact_id' => '',
230 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
231 'receipt_text' => 'Thank you text',
232 'payment_processor_id' => $this->_paymentProcessorID,
233 'credit_card_number' => '4111111111111111',
234 'cvv2' => '123',
235 'credit_card_exp_date' => [
236 'M' => '9',
237 'Y' => date('Y') + 1,
238 ],
239 'credit_card_type' => 'Visa',
240 'billing_first_name' => 'Test',
241 'billing_middlename' => 'Last',
242 'billing_street_address-5' => '10 Test St',
243 'billing_city-5' => 'Test',
244 'billing_state_province_id-5' => '1003',
245 'billing_postal_code-5' => '90210',
246 'billing_country_id-5' => '1228',
247 'send_receipt' => 1,
248 ];
249 $form->_mode = 'test';
250 $form->_contactID = $this->_individualId;
251
252 $form->testSubmit($params);
253 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
254 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', ['contact_id' => $this->_individualId]);
255 $this->assertEquals(1, $contributionRecur['is_email_receipt']);
256 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contributionRecur['modified_date'])));
257 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contributionRecur['modified_date'])));
258 $this->assertNotEmpty($contributionRecur['invoice_id']);
259 $this->assertEquals(CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id',
260 'Pending'), $contributionRecur['contribution_status_id']);
261 $this->assertEquals($this->callAPISuccessGetValue('PaymentProcessor', [
262 'id' => $this->_paymentProcessorID,
263 'return' => 'payment_instrument_id',
264 ]), $contributionRecur['payment_instrument_id']);
265
266 $contribution = $this->callAPISuccess('Contribution', 'getsingle', [
267 'contact_id' => $this->_individualId,
268 'is_test' => TRUE,
269 ]);
270
271 $this->assertEquals($this->callAPISuccessGetValue('PaymentProcessor', [
272 'id' => $this->_paymentProcessorID,
273 'return' => 'payment_instrument_id',
274 ]), $contribution['payment_instrument_id']);
275 $this->assertEquals($contributionRecur['id'], $contribution['contribution_recur_id']);
276
277 $this->callAPISuccessGetCount('LineItem', [
278 'entity_id' => $membership['id'],
279 'entity_table' => 'civicrm_membership',
280 'contribution_id' => $contribution['id'],
281 ], 1);
282
283 $this->callAPISuccessGetSingle('address', [
284 'contact_id' => $this->_individualId,
285 'street_address' => '10 Test St',
286 'postal_code' => 90210,
287 ]);
288 }
289
290 /**
291 * Test the submit function of the membership form.
292 */
293 public function testSubmitRecurCompleteInstant() {
294 $form = $this->getForm();
295 /** @var \CRM_Core_Payment_Dummy $processor */
296 $processor = Civi\Payment\System::singleton()->getById($this->_paymentProcessorID);
297 $processor->setDoDirectPaymentResult([
298 'payment_status_id' => 1,
299 'trxn_id' => 'kettles boil water',
300 'fee_amount' => .29,
301 ]);
302
303 $this->callAPISuccess('MembershipType', 'create', [
304 'id' => $this->membershipTypeAnnualFixedID,
305 'duration_unit' => 'month',
306 'duration_interval' => 1,
307 'auto_renew' => TRUE,
308 ]);
309 $this->createLoggedInUser();
310 $form->preProcess();
311
312 $form->_contactID = $this->_individualId;
313 $params = $this->getBaseSubmitParams();
314 $form->_mode = 'test';
315
316 $form->testSubmit($params);
317 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
318 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', ['contact_id' => $this->_individualId]);
319 $this->assertEquals($contributionRecur['id'], $membership['contribution_recur_id']);
320 $this->assertEquals(0, $contributionRecur['is_email_receipt']);
321 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contributionRecur['modified_date'])));
322 $this->assertNotEmpty($contributionRecur['invoice_id']);
323 // @todo fix this part!
324 /*
325 $this->assertEquals(CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id',
326 'In Progress'), $contributionRecur['contribution_status_id']);
327 $this->assertNotEmpty($contributionRecur['next_sched_contribution_date']);
328 */
329 $paymentInstrumentID = $this->callAPISuccessGetValue('PaymentProcessor', [
330 'id' => $this->_paymentProcessorID,
331 'return' => 'payment_instrument_id',
332 ]);
333 $this->assertEquals($paymentInstrumentID, $contributionRecur['payment_instrument_id']);
334
335 $contribution = $this->callAPISuccess('Contribution', 'getsingle', [
336 'contact_id' => $this->_individualId,
337 'is_test' => TRUE,
338 ]);
339 $this->assertEquals($paymentInstrumentID, $contribution['payment_instrument_id']);
340
341 $this->assertEquals('kettles boil water', $contribution['trxn_id']);
342 $this->assertEquals(.29, $contribution['fee_amount']);
343 $this->assertEquals(7800.90, $contribution['total_amount']);
344 $this->assertEquals(7800.61, $contribution['net_amount']);
345
346 $this->callAPISuccessGetCount('LineItem', [
347 'entity_id' => $membership['id'],
348 'entity_table' => 'civicrm_membership',
349 'contribution_id' => $contribution['id'],
350 ], 1);
351 }
352
353 /**
354 * Test the submit function of the membership form.
355 *
356 * @param string $thousandSeparator
357 *
358 * @dataProvider getThousandSeparators
359 *
360 * @throws \CiviCRM_API3_Exception
361 * @throws \CRM_Core_Exception
362 */
363 public function testSubmitRecurCompleteInstantWithMail($thousandSeparator) {
364 $this->setCurrencySeparators($thousandSeparator);
365 $form = $this->getForm();
366 $this->mut = new CiviMailUtils($this, TRUE);
367 /** @var \CRM_Core_Payment_Dummy $processor */
368 $processor = Civi\Payment\System::singleton()->getById($this->_paymentProcessorID);
369 $processor->setDoDirectPaymentResult([
370 'payment_status_id' => 1,
371 'trxn_id' => 'kettles boil water',
372 'fee_amount' => .29,
373 ]);
374
375 $this->callAPISuccess('MembershipType', 'create', [
376 'id' => $this->membershipTypeAnnualFixedID,
377 'duration_unit' => 'month',
378 'duration_interval' => 1,
379 'auto_renew' => TRUE,
380 ]);
381 $this->createLoggedInUser();
382 $form->preProcess();
383
384 $form->_contactID = $this->_individualId;
385 $params = $this->getBaseSubmitParams();
386 $params['send_receipt'] = 1;
387 $form->_mode = 'test';
388
389 $form->testSubmit($params);
390 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', ['contact_id' => $this->_individualId]);
391 $this->assertEquals(1, $contributionRecur['is_email_receipt']);
392 $this->mut->checkMailLog([
393 '$ ' . $this->formatMoneyInput(7800.90),
394 ]);
395 $this->mut->stop();
396 $this->setCurrencySeparators(',');
397 }
398
399 /**
400 * Test the submit function of the membership form.
401 *
402 * @throws \CRM_Core_Exception
403 */
404 public function testSubmitPayLater() {
405 $form = $this->getForm(NULL);
406 $this->createLoggedInUser();
407 $originalMembership = $this->callAPISuccessGetSingle('membership', []);
408 $params = [
409 'cid' => $this->_individualId,
410 'join_date' => date('m/d/Y', time()),
411 'start_date' => '',
412 'end_date' => '',
413 // This format reflects the 23 being the organisation & the 25 being the type.
414 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
415 'auto_renew' => '0',
416 'max_related' => '',
417 'num_terms' => '2',
418 'source' => '',
419 'total_amount' => '50.00',
420 //Member dues, see data.xml
421 'financial_type_id' => '2',
422 'soft_credit_type_id' => '',
423 'soft_credit_contact_id' => '',
424 'payment_instrument_id' => 4,
425 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
426 'receipt_text_signup' => 'Thank you text',
427 'payment_processor_id' => $this->_paymentProcessorID,
428 'record_contribution' => TRUE,
429 'trxn_id' => 777,
430 'contribution_status_id' => 2,
431 ];
432 $form->_contactID = $this->_individualId;
433
434 $form->testSubmit($params);
435 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
436 $this->assertEquals(strtotime($membership['end_date']), strtotime($originalMembership['end_date']));
437 $contribution = $this->callAPISuccessGetSingle('Contribution', [
438 'contact_id' => $this->_individualId,
439 'contribution_status_id' => 2,
440 'return' => ["tax_amount", "trxn_id"],
441 ]);
442 $this->assertEquals($contribution['trxn_id'], 777);
443 $this->assertEquals($contribution['tax_amount'], NULL);
444
445 $this->callAPISuccessGetCount('LineItem', [
446 'entity_id' => $membership['id'],
447 'entity_table' => 'civicrm_membership',
448 'contribution_id' => $contribution['id'],
449 ], 1);
450 }
451
452 /**
453 * Test the submit function of the membership form.
454 *
455 * @throws \CRM_Core_Exception
456 */
457 public function testSubmitPayLaterWithBilling() {
458 $form = $this->getForm(NULL);
459 $this->createLoggedInUser();
460 $originalMembership = $this->callAPISuccessGetSingle('membership', []);
461 $params = [
462 'cid' => $this->_individualId,
463 'join_date' => date('m/d/Y', time()),
464 'start_date' => '',
465 'end_date' => '',
466 // This format reflects the 23 being the organisation & the 25 being the type.
467 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
468 'auto_renew' => '0',
469 'max_related' => '',
470 'num_terms' => '2',
471 'source' => '',
472 'total_amount' => '50.00',
473 //Member dues, see data.xml
474 'financial_type_id' => '2',
475 'soft_credit_type_id' => '',
476 'soft_credit_contact_id' => '',
477 'payment_instrument_id' => 4,
478 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
479 'receipt_text_signup' => 'Thank you text',
480 'payment_processor_id' => $this->_paymentProcessorID,
481 'record_contribution' => TRUE,
482 'trxn_id' => 777,
483 'contribution_status_id' => 2,
484 'billing_first_name' => 'Test',
485 'billing_middlename' => 'Last',
486 'billing_street_address-5' => '10 Test St',
487 'billing_city-5' => 'Test',
488 'billing_state_province_id-5' => '1003',
489 'billing_postal_code-5' => '90210',
490 'billing_country_id-5' => '1228',
491 ];
492 $form->_contactID = $this->_individualId;
493
494 $form->testSubmit($params);
495 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
496 $this->assertEquals(strtotime($membership['end_date']), strtotime($originalMembership['end_date']));
497 $contribution = $this->callAPISuccessGetSingle('Contribution', [
498 'contact_id' => $this->_individualId,
499 'contribution_status_id' => 2,
500 ]);
501 $this->assertEquals($contribution['trxn_id'], 777);
502
503 $this->callAPISuccessGetCount('LineItem', [
504 'entity_id' => $membership['id'],
505 'entity_table' => 'civicrm_membership',
506 'contribution_id' => $contribution['id'],
507 ], 1);
508 $this->callAPISuccessGetSingle('address', [
509 'contact_id' => $this->_individualId,
510 'street_address' => '10 Test St',
511 'postal_code' => 90210,
512 ]);
513 }
514
515 /**
516 * Test the submit function of the membership form.
517 */
518 public function testSubmitComplete() {
519 $form = $this->getForm(NULL);
520 $this->createLoggedInUser();
521 $originalMembership = $this->callAPISuccessGetSingle('membership', []);
522 $params = [
523 'cid' => $this->_individualId,
524 'join_date' => date('m/d/Y', time()),
525 'start_date' => '',
526 'end_date' => '',
527 // This format reflects the 23 being the organisation & the 25 being the type.
528 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
529 'auto_renew' => '0',
530 'max_related' => '',
531 'num_terms' => '2',
532 'source' => '',
533 'total_amount' => '50.00',
534 //Member dues, see data.xml
535 'financial_type_id' => '2',
536 'soft_credit_type_id' => '',
537 'soft_credit_contact_id' => '',
538 'payment_instrument_id' => 4,
539 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
540 'receipt_text_signup' => 'Thank you text',
541 'payment_processor_id' => $this->_paymentProcessorID,
542 'record_contribution' => TRUE,
543 'trxn_id' => 777,
544 'contribution_status_id' => 1,
545 'fee_amount' => .5,
546 ];
547 $form->_contactID = $this->_individualId;
548
549 $form->testSubmit($params);
550 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
551 $this->assertEquals(strtotime($membership['end_date']), strtotime('+ 2 years',
552 strtotime($originalMembership['end_date'])));
553 $contribution = $this->callAPISuccessGetSingle('Contribution', [
554 'contact_id' => $this->_individualId,
555 'contribution_status_id' => 1,
556 ]);
557
558 $this->assertEquals($contribution['trxn_id'], 777);
559 $this->assertEquals(.5, $contribution['fee_amount']);
560 $this->callAPISuccessGetCount('LineItem', [
561 'entity_id' => $membership['id'],
562 'entity_table' => 'civicrm_membership',
563 'contribution_id' => $contribution['id'],
564 ], 1);
565 }
566
567 /**
568 * Get a membership form object.
569 *
570 * We need to instantiate the form to run preprocess, which means we have to trick it about the request method.
571 *
572 * @param string $mode
573 *
574 * @return \CRM_Member_Form_MembershipRenewal
575 */
576 protected function getForm($mode = 'test') {
577 $form = new CRM_Member_Form_MembershipRenewal();
578 $_SERVER['REQUEST_METHOD'] = 'GET';
579 $form->controller = new CRM_Core_Controller();
580 $form->_bltID = 5;
581 $form->_mode = $mode;
582 $form->_id = $this->_membershipID;
583 $form->preProcess();
584 return $form;
585 }
586
587 /**
588 * Get some re-usable parameters for the submit function.
589 *
590 * @return array
591 */
592 protected function getBaseSubmitParams() {
593 $params = [
594 'cid' => $this->_individualId,
595 'price_set_id' => 0,
596 'join_date' => date('m/d/Y', time()),
597 'start_date' => '',
598 'end_date' => '',
599 'campaign_id' => '',
600 // This format reflects the 23 being the organisation & the 25 being the type.
601 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
602 'auto_renew' => '1',
603 'is_recur' => 1,
604 'max_related' => 0,
605 'num_terms' => '1',
606 'source' => '',
607 'total_amount' => $this->formatMoneyInput('7800.90'),
608 //Member dues, see data.xml
609 'financial_type_id' => '2',
610 'soft_credit_type_id' => 11,
611 'soft_credit_contact_id' => '',
612 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
613 'receipt_text' => 'Thank you text',
614 'payment_processor_id' => $this->_paymentProcessorID,
615 'credit_card_number' => '4111111111111111',
616 'cvv2' => '123',
617 'credit_card_exp_date' => [
618 'M' => '9',
619 'Y' => date('Y') + 1,
620 ],
621 'credit_card_type' => 'Visa',
622 'billing_first_name' => 'Test',
623 'billing_middlename' => 'Last',
624 'billing_street_address-5' => '10 Test St',
625 'billing_city-5' => 'Test',
626 'billing_state_province_id-5' => '1003',
627 'billing_postal_code-5' => '90210',
628 'billing_country_id-5' => '1228',
629 ];
630 return $params;
631 }
632
633 }