Merge pull request #15370 from JMAConsulting/core-692-2
[civicrm-core.git] / tests / phpunit / CRM / Member / Form / MembershipTest.php
CommitLineData
6a488035 1<?php
7865d848
EM
2/*
3 +--------------------------------------------------------------------+
2fe49090 4 | CiviCRM version 5 |
7865d848 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
7865d848
EM
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 */
6a488035
TO
27
28/**
29 * File for the MembershipTest class
30 *
31 * (PHP 5)
32 *
6c6e6187 33 * @author Walt Haas <walt@dharmatech.org> (801) 534-1262
6a488035
TO
34 */
35
6a488035 36/**
7865d848 37 * Test CRM_Member_Form_Membership functions.
6a488035 38 *
6c6e6187 39 * @package CiviCRM
acb109b7 40 * @group headless
6a488035
TO
41 */
42class CRM_Member_Form_MembershipTest extends CiviUnitTestCase {
43
7865d848
EM
44 protected $_individualId;
45 protected $_contribution;
46 protected $_financialTypeId = 1;
7865d848
EM
47 protected $_entity = 'Membership';
48 protected $_params;
9099cab3 49 protected $_ids = [];
7865d848
EM
50 protected $_paymentProcessorID;
51
08fd4b45
EM
52 /**
53 * Membership type ID for annual fixed membership.
54 *
55 * @var int
56 */
57 protected $membershipTypeAnnualFixedID;
58
7865d848
EM
59 /**
60 * Parameters to create payment processor.
61 *
62 * @var array
63 */
9099cab3 64 protected $_processorParams = [];
7865d848
EM
65
66 /**
67 * ID of created membership.
68 *
69 * @var int
70 */
71 protected $_membershipID;
72
73 /**
74 * Payment instrument mapping.
75 *
76 * @var array
77 */
9099cab3 78 protected $paymentInstruments = [];
7865d848 79
bbaa79ff
EM
80 /**
81 * @var CiviMailUtils
82 */
83 protected $mut;
84
6a488035 85 /**
41709813 86 * Test setup for every test.
6a488035 87 *
41709813
EM
88 * Connect to the database, truncate the tables that will be used
89 * and redirect stdin to a temporary file.
91786f44 90 *
91 * @throws \CRM_Core_Exception
6a488035
TO
92 */
93 public function setUp() {
cb447e7a 94 $this->_apiversion = 3;
6a488035
TO
95 parent::setUp();
96
cb447e7a 97 $this->_individualId = $this->individualCreate();
8950ecdc 98 $this->_paymentProcessorID = $this->processorCreate();
1d291c60 99
100 $this->loadXMLDataSet(dirname(__FILE__) . '/dataset/data.xml');
101
9099cab3 102 $membershipTypeAnnualFixed = $this->callAPISuccess('membership_type', 'create', [
08fd4b45
EM
103 'domain_id' => 1,
104 'name' => "AnnualFixed",
105 'member_of_contact_id' => 23,
106 'duration_unit' => "year",
268a84f2 107 'minimum_fee' => 50,
08fd4b45
EM
108 'duration_interval' => 1,
109 'period_type' => "fixed",
110 'fixed_period_start_day' => "101",
111 'fixed_period_rollover_day' => "1231",
112 'relationship_type_id' => 20,
113 'financial_type_id' => 2,
9099cab3 114 ]);
08fd4b45 115 $this->membershipTypeAnnualFixedID = $membershipTypeAnnualFixed['id'];
7865d848 116
9099cab3 117 $instruments = $this->callAPISuccess('contribution', 'getoptions', ['field' => 'payment_instrument_id']);
7865d848
EM
118 $this->paymentInstruments = $instruments['values'];
119 }
120
cb447e7a
EM
121 /**
122 * Clean up after each test.
123 */
124 public function tearDown() {
125 $this->quickCleanUpFinancialEntities();
126 $this->quickCleanup(
9099cab3 127 [
cb447e7a
EM
128 'civicrm_relationship',
129 'civicrm_membership_type',
130 'civicrm_membership',
a8215a8d 131 'civicrm_uf_match',
360a0925 132 'civicrm_email',
9099cab3 133 ]
cb447e7a 134 );
9099cab3
CW
135 foreach ([17, 18, 23, 32] as $contactID) {
136 $this->callAPISuccess('contact', 'delete', ['id' => $contactID, 'skip_undelete' => TRUE]);
e2ce0d88 137 }
9099cab3 138 $this->callAPISuccess('relationship_type', 'delete', ['id' => 20]);
cb447e7a
EM
139 }
140
6a488035
TO
141 /**
142 * Test CRM_Member_Form_Membership::formRule() with a parameter
143 * that has an empty contact_select_id value
91786f44 144 *
145 * @throws \CiviCRM_API3_Exception
6a488035 146 */
00be9182 147 public function testFormRuleEmptyContact() {
9099cab3 148 $params = [
6a488035 149 'contact_select_id' => 0,
9099cab3
CW
150 'membership_type_id' => [1 => NULL],
151 ];
152 $files = [];
a130e045 153 $obj = new CRM_Member_Form_Membership();
92915c55 154 $rc = $obj->formRule($params, $files, $obj);
cb447e7a
EM
155 $this->assertType('array', $rc);
156 $this->assertTrue(array_key_exists('membership_type_id', $rc));
6a488035 157
9099cab3 158 $params['membership_type_id'] = [1 => 3];
6a488035 159 $rc = $obj->formRule($params, $files, $obj);
cb447e7a
EM
160 $this->assertType('array', $rc);
161 $this->assertTrue(array_key_exists('join_date', $rc));
6a488035
TO
162 }
163
164 /**
cb447e7a
EM
165 * Test that form rule fails if start date is before join date.
166 *
167 * Test CRM_Member_Form_Membership::formRule() with a parameter
168 * that has an start date before the join date and a rolling
169 * membership type.
6a488035 170 */
00be9182 171 public function testFormRuleRollingEarlyStart() {
92915c55 172 $unixNow = time();
6a488035 173 $unixYesterday = $unixNow - (24 * 60 * 60);
8b408447 174 $ymdYesterday = date('Y-m-d', $unixYesterday);
9099cab3 175 $params = [
8b408447 176 'join_date' => date('Y-m-d'),
6a488035
TO
177 'start_date' => $ymdYesterday,
178 'end_date' => '',
9099cab3
CW
179 'membership_type_id' => ['23', '15'],
180 ];
181 $files = [];
a130e045 182 $obj = new CRM_Member_Form_Membership();
9099cab3 183 $rc = call_user_func(['CRM_Member_Form_Membership', 'formRule'],
6a488035
TO
184 $params, $files, $obj
185 );
cb447e7a
EM
186 $this->assertType('array', $rc);
187 $this->assertTrue(array_key_exists('start_date', $rc));
6a488035
TO
188 }
189
190 /**
191 * Test CRM_Member_Form_Membership::formRule() with a parameter
192 * that has an end date before the start date and a rolling
193 * membership type
194 */
00be9182 195 public function testFormRuleRollingEarlyEnd() {
92915c55 196 $unixNow = time();
6a488035 197 $unixYesterday = $unixNow - (24 * 60 * 60);
8b408447 198 $ymdYesterday = date('Y-m-d', $unixYesterday);
9099cab3 199 $params = [
8b408447 200 'join_date' => date('Y-m-d'),
201 'start_date' => date('Y-m-d'),
6a488035 202 'end_date' => $ymdYesterday,
9099cab3
CW
203 'membership_type_id' => ['23', '15'],
204 ];
205 $files = [];
a130e045 206 $obj = new CRM_Member_Form_Membership();
92915c55 207 $rc = $obj->formRule($params, $files, $obj);
08fd4b45
EM
208 $this->assertType('array', $rc);
209 $this->assertTrue(array_key_exists('end_date', $rc));
6a488035
TO
210 }
211
212 /**
41709813 213 * Test CRM_Member_Form_Membership::formRule() with end date but no start date and a rolling membership type.
6a488035 214 */
00be9182 215 public function testFormRuleRollingEndNoStart() {
92915c55 216 $unixNow = time();
6a488035 217 $unixYearFromNow = $unixNow + (365 * 24 * 60 * 60);
8b408447 218 $ymdYearFromNow = date('Y-m-d', $unixYearFromNow);
9099cab3 219 $params = [
8b408447 220 'join_date' => date('Y-m-d'),
6a488035
TO
221 'start_date' => '',
222 'end_date' => $ymdYearFromNow,
9099cab3
CW
223 'membership_type_id' => ['23', '15'],
224 ];
225 $files = [];
a130e045 226 $obj = new CRM_Member_Form_Membership();
92915c55 227 $rc = $obj->formRule($params, $files, $obj);
08fd4b45
EM
228 $this->assertType('array', $rc);
229 $this->assertTrue(array_key_exists('start_date', $rc));
6a488035
TO
230 }
231
232 /**
233 * Test CRM_Member_Form_Membership::formRule() with a parameter
234 * that has an end date and a lifetime membership type
235 */
00be9182 236 public function testFormRuleRollingLifetimeEnd() {
92915c55 237 $unixNow = time();
6a488035 238 $unixYearFromNow = $unixNow + (365 * 24 * 60 * 60);
9099cab3 239 $params = [
8b408447 240 'join_date' => date('Y-m-d'),
241 'start_date' => date('Y-m-d'),
242 'end_date' => date('Y-m-d',
6a488035
TO
243 $unixYearFromNow
244 ),
9099cab3
CW
245 'membership_type_id' => ['23', '25'],
246 ];
247 $files = [];
a130e045 248 $obj = new CRM_Member_Form_Membership();
92915c55 249 $rc = $obj->formRule($params, $files, $obj);
fada2199
EM
250 $this->assertType('array', $rc);
251 $this->assertTrue(array_key_exists('status_id', $rc));
6a488035
TO
252 }
253
254 /**
255 * Test CRM_Member_Form_Membership::formRule() with a parameter
e136f704 256 * that has permanent override and no status
6a488035 257 */
e136f704 258 public function testFormRulePermanentOverrideWithNoStatus() {
92915c55 259 $unixNow = time();
9099cab3 260 $params = [
8b408447 261 'join_date' => date('Y-m-d'),
9099cab3 262 'membership_type_id' => ['23', '25'],
6a488035 263 'is_override' => TRUE,
9099cab3
CW
264 ];
265 $files = [];
a130e045 266 $obj = new CRM_Member_Form_Membership();
92915c55 267 $rc = $obj->formRule($params, $files, $obj);
41709813
EM
268 $this->assertType('array', $rc);
269 $this->assertTrue(array_key_exists('status_id', $rc));
6a488035
TO
270 }
271
e136f704 272 public function testFormRuleUntilDateOverrideWithValidOverrideEndDate() {
9099cab3 273 $params = [
8b408447 274 'join_date' => date('Y-m-d'),
9099cab3 275 'membership_type_id' => ['23', '25'],
e136f704
O
276 'is_override' => TRUE,
277 'status_id' => 1,
8b408447 278 'status_override_end_date' => date('Y-m-d'),
9099cab3
CW
279 ];
280 $files = [];
e136f704
O
281 $membershipForm = new CRM_Member_Form_Membership();
282 $validationResponse = $membershipForm->formRule($params, $files, $membershipForm);
283 $this->assertTrue($validationResponse);
284 }
285
286 public function testFormRuleUntilDateOverrideWithNoOverrideEndDate() {
9099cab3 287 $params = [
8b408447 288 'join_date' => date('Y-m-d'),
9099cab3 289 'membership_type_id' => ['23', '25'],
e136f704
O
290 'is_override' => CRM_Member_StatusOverrideTypes::UNTIL_DATE,
291 'status_id' => 1,
9099cab3
CW
292 ];
293 $files = [];
e136f704
O
294 $membershipForm = new CRM_Member_Form_Membership();
295 $validationResponse = $membershipForm->formRule($params, $files, $membershipForm);
296 $this->assertType('array', $validationResponse);
297 $this->assertEquals('Please enter the Membership override end date.', $validationResponse['status_override_end_date']);
298 }
299
6a488035
TO
300 /**
301 * Test CRM_Member_Form_Membership::formRule() with a join date
302 * of one month from now and a rolling membership type
303 */
00be9182 304 public function testFormRuleRollingJoin1MonthFromNow() {
92915c55 305 $unixNow = time();
6a488035 306 $unix1MFmNow = $unixNow + (31 * 24 * 60 * 60);
9099cab3 307 $params = [
8b408447 308 'join_date' => date('Y-m-d', $unix1MFmNow),
6a488035
TO
309 'start_date' => '',
310 'end_date' => '',
9099cab3
CW
311 'membership_type_id' => ['23', '15'],
312 ];
313 $files = [];
a130e045 314 $obj = new CRM_Member_Form_Membership();
92915c55 315 $rc = $obj->formRule($params, $files, $obj);
6a488035 316
41709813
EM
317 // Should have found no valid membership status.
318 $this->assertType('array', $rc);
319 $this->assertTrue(array_key_exists('_qf_default', $rc));
6a488035
TO
320 }
321
322 /**
41709813 323 * Test CRM_Member_Form_Membership::formRule() with a join date of today and a rolling membership type.
6a488035 324 */
00be9182 325 public function testFormRuleRollingJoinToday() {
9099cab3 326 $params = [
8b408447 327 'join_date' => date('Y-m-d'),
6a488035
TO
328 'start_date' => '',
329 'end_date' => '',
9099cab3
CW
330 'membership_type_id' => ['23', '15'],
331 ];
332 $files = [];
a130e045 333 $obj = new CRM_Member_Form_Membership();
92915c55 334 $rc = $obj->formRule($params, $files, $obj);
6a488035
TO
335
336 // Should have found New membership status
a15773db 337 $this->assertTrue($rc);
6a488035
TO
338 }
339
340 /**
341 * Test CRM_Member_Form_Membership::formRule() with a join date
342 * of one month ago and a rolling membership type
343 */
00be9182 344 public function testFormRuleRollingJoin1MonthAgo() {
92915c55 345 $unixNow = time();
6a488035 346 $unix1MAgo = $unixNow - (31 * 24 * 60 * 60);
9099cab3 347 $params = [
8b408447 348 'join_date' => date('Y-m-d', $unix1MAgo),
6a488035
TO
349 'start_date' => '',
350 'end_date' => '',
9099cab3
CW
351 'membership_type_id' => ['23', '15'],
352 ];
353 $files = [];
a130e045 354 $obj = new CRM_Member_Form_Membership();
92915c55 355 $rc = $obj->formRule($params, $files, $obj);
6a488035 356
41709813
EM
357 // Should have found New membership status.
358 $this->assertTrue($rc);
6a488035
TO
359 }
360
361 /**
41709813 362 * Test CRM_Member_Form_Membership::formRule() with a join date of six months ago and a rolling membership type.
6a488035 363 */
00be9182 364 public function testFormRuleRollingJoin6MonthsAgo() {
92915c55 365 $unixNow = time();
6a488035 366 $unix6MAgo = $unixNow - (180 * 24 * 60 * 60);
9099cab3 367 $params = [
8b408447 368 'join_date' => date('Y-m-d', $unix6MAgo),
6a488035
TO
369 'start_date' => '',
370 'end_date' => '',
9099cab3
CW
371 'membership_type_id' => ['23', '15'],
372 ];
373 $files = [];
a130e045 374 $obj = new CRM_Member_Form_Membership();
92915c55 375 $rc = $obj->formRule($params, $files, $obj);
6a488035 376
41709813
EM
377 // Should have found Current membership status.
378 $this->assertTrue($rc);
6a488035
TO
379 }
380
381 /**
382 * Test CRM_Member_Form_Membership::formRule() with a join date
383 * of one year+ ago and a rolling membership type
384 */
00be9182 385 public function testFormRuleRollingJoin1YearAgo() {
92915c55 386 $unixNow = time();
6a488035 387 $unix1YAgo = $unixNow - (370 * 24 * 60 * 60);
9099cab3 388 $params = [
8b408447 389 'join_date' => date('Y-m-d', $unix1YAgo),
6a488035
TO
390 'start_date' => '',
391 'end_date' => '',
9099cab3
CW
392 'membership_type_id' => ['23', '15'],
393 ];
394 $files = [];
a130e045 395 $obj = new CRM_Member_Form_Membership();
92915c55 396 $rc = $obj->formRule($params, $files, $obj);
6a488035
TO
397
398 // Should have found Grace membership status
a15773db 399 $this->assertTrue($rc);
6a488035
TO
400 }
401
402 /**
403 * Test CRM_Member_Form_Membership::formRule() with a join date
404 * of two years ago and a rolling membership type
405 */
00be9182 406 public function testFormRuleRollingJoin2YearsAgo() {
92915c55 407 $unixNow = time();
6a488035 408 $unix2YAgo = $unixNow - (2 * 365 * 24 * 60 * 60);
9099cab3 409 $params = [
8b408447 410 'join_date' => date('Y-m-d', $unix2YAgo),
6a488035
TO
411 'start_date' => '',
412 'end_date' => '',
9099cab3
CW
413 'membership_type_id' => ['23', '15'],
414 ];
415 $files = [];
a130e045 416 $obj = new CRM_Member_Form_Membership();
92915c55 417 $rc = $obj->formRule($params, $files, $obj);
6a488035
TO
418
419 // Should have found Expired membership status
a15773db 420 $this->assertTrue($rc);
6a488035
TO
421 }
422
423 /**
424 * Test CRM_Member_Form_Membership::formRule() with a join date
425 * of six months ago and a fixed membership type
426 */
00be9182 427 public function testFormRuleFixedJoin6MonthsAgo() {
92915c55 428 $unixNow = time();
6a488035 429 $unix6MAgo = $unixNow - (180 * 24 * 60 * 60);
9099cab3 430 $params = [
8b408447 431 'join_date' => date('Y-m-d', $unix6MAgo),
6a488035
TO
432 'start_date' => '',
433 'end_date' => '',
9099cab3
CW
434 'membership_type_id' => ['23', '7'],
435 ];
436 $files = [];
a130e045 437 $obj = new CRM_Member_Form_Membership();
92915c55 438 $rc = $obj->formRule($params, $files, $obj);
6a488035
TO
439
440 // Should have found Current membership status
cb447e7a 441 $this->assertTrue($rc);
6a488035 442 }
96025800 443
7865d848
EM
444 /**
445 * Test the submit function of the membership form.
f8df19bb 446 *
447 * @param string $thousandSeparator
448 *
449 * @dataProvider getThousandSeparators
7865d848 450 */
f8df19bb 451 public function testSubmit($thousandSeparator) {
6d5b9c63 452 CRM_Core_Session::singleton()->getStatus(TRUE);
f8df19bb 453 $this->setCurrencySeparators($thousandSeparator);
08fd4b45 454 $form = $this->getForm();
0dc4ef42 455 $form->preProcess();
bbaa79ff 456 $this->mut = new CiviMailUtils($this, TRUE);
08fd4b45 457 $form->_mode = 'test';
c41bfe2b 458 $this->createLoggedInUser();
9099cab3 459 $params = [
7865d848 460 'cid' => $this->_individualId,
6d5b9c63 461 'join_date' => date('2/d/Y', time()),
7865d848
EM
462 'start_date' => '',
463 'end_date' => '',
08fd4b45 464 // This format reflects the 23 being the organisation & the 25 being the type.
9099cab3 465 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
7865d848
EM
466 'auto_renew' => '0',
467 'max_related' => '',
468 'num_terms' => '1',
469 'source' => '',
f8df19bb 470 'total_amount' => $this->formatMoneyInput(1234.56),
39b959db
SL
471 //Member dues, see data.xml
472 'financial_type_id' => '2',
7865d848
EM
473 'soft_credit_type_id' => '',
474 'soft_credit_contact_id' => '',
475 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
7865d848
EM
476 'payment_processor_id' => $this->_paymentProcessorID,
477 'credit_card_number' => '4111111111111111',
478 'cvv2' => '123',
9099cab3 479 'credit_card_exp_date' => [
7865d848 480 'M' => '9',
39b959db
SL
481 // TODO: Future proof
482 'Y' => '2024',
9099cab3 483 ],
41709813
EM
484 'credit_card_type' => 'Visa',
485 'billing_first_name' => 'Test',
486 'billing_middlename' => 'Last',
487 'billing_street_address-5' => '10 Test St',
488 'billing_city-5' => 'Test',
489 'billing_state_province_id-5' => '1003',
490 'billing_postal_code-5' => '90210',
491 'billing_country_id-5' => '1228',
bbaa79ff
EM
492 'send_receipt' => TRUE,
493 'receipt_text' => 'Receipt text',
9099cab3 494 ];
09108d7d 495 $form->_contactID = $this->_individualId;
496 $form->testSubmit($params);
9099cab3
CW
497 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
498 $this->callAPISuccessGetCount('ContributionRecur', ['contact_id' => $this->_individualId], 0);
499 $contribution = $this->callAPISuccess('Contribution', 'get', [
08fd4b45
EM
500 'contact_id' => $this->_individualId,
501 'is_test' => TRUE,
9099cab3 502 ]);
08fd4b45 503
a7f2d5fd 504 //CRM-20264 : Check that CC type and number (last 4 digit) is stored during backoffice membership payment
505 $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
506 $financialTrxn = $this->callAPISuccessGetSingle(
507 'FinancialTrxn',
9099cab3 508 [
a7f2d5fd 509 'id' => $lastFinancialTrxnId['financialTrxnId'],
9099cab3
CW
510 'return' => ['card_type_id', 'pan_truncation'],
511 ]
a7f2d5fd 512 );
513 $this->assertEquals(1, $financialTrxn['card_type_id']);
514 $this->assertEquals(1111, $financialTrxn['pan_truncation']);
515
9099cab3 516 $this->callAPISuccessGetCount('LineItem', [
08fd4b45
EM
517 'entity_id' => $membership['id'],
518 'entity_table' => 'civicrm_membership',
519 'contribution_id' => $contribution['id'],
9099cab3 520 ], 1);
1a1a2f4f 521
9099cab3 522 $this->_checkFinancialRecords([
16f3bd02 523 'id' => $contribution['id'],
f8df19bb 524 'total_amount' => 1234.56,
16f3bd02 525 'financial_account_id' => 2,
9099cab3 526 'payment_instrument_id' => $this->callAPISuccessGetValue('PaymentProcessor', [
16f3bd02 527 'id' => $this->_paymentProcessorID,
528 'return' => 'payment_instrument_id',
9099cab3
CW
529 ]),
530 ], 'online');
531 $this->mut->checkMailLog([
f8df19bb 532 CRM_Utils_Money::format('1234.56'),
bbaa79ff 533 'Receipt text',
9099cab3 534 ]);
bbaa79ff 535 $this->mut->stop();
6d5b9c63 536 $this->assertEquals([
537 [
538 'text' => 'AnnualFixed membership for Mr. Anthony Anderson II has been added. The new membership End Date is December 31st, ' . date('Y') . '. A membership confirmation and receipt has been sent to anthony_anderson@civicrm.org.',
539 'title' => 'Complete',
540 'type' => 'success',
541 'options' => NULL,
542 ],
543 ], CRM_Core_Session::singleton()->getStatus());
7865d848
EM
544 }
545
268a84f2 546 /**
547 * Test the submit function of the membership form on membership type change.
548 * Check if the related contribuion is also updated if the minimum_fee didn't match
549 */
550 public function testContributionUpdateOnMembershipTypeChange() {
551 // Step 1: Create a Membership via backoffice whose with 50.00 payment
552 $form = $this->getForm();
553 $form->preProcess();
554 $this->mut = new CiviMailUtils($this, TRUE);
555 $this->createLoggedInUser();
9099cab3 556 $priceSet = $this->callAPISuccess('PriceSet', 'Get', ["extends" => "CiviMember"]);
268a84f2 557 $form->set('priceSetId', $priceSet['id']);
558 CRM_Price_BAO_PriceSet::buildPriceSet($form);
9099cab3 559 $params = [
268a84f2 560 'cid' => $this->_individualId,
8b408447 561 'join_date' => date('Y-m-d'),
268a84f2 562 'start_date' => '',
563 'end_date' => '',
564 // This format reflects the 23 being the organisation & the 25 being the type.
9099cab3 565 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
268a84f2 566 'record_contribution' => 1,
567 'total_amount' => 50,
553842be 568 'receive_date' => date('Y-m-d', time()) . ' 20:36:00',
268a84f2 569 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
570 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
39b959db
SL
571 //Member dues, see data.xml
572 'financial_type_id' => '2',
268a84f2 573 'payment_processor_id' => $this->_paymentProcessorID,
9099cab3 574 ];
268a84f2 575 $form->_contactID = $this->_individualId;
576 $form->testSubmit($params);
9099cab3 577 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
268a84f2 578 // check the membership status after partial payment, if its Pending
579 $this->assertEquals(array_search('New', CRM_Member_PseudoConstant::membershipStatus()), $membership['status_id']);
9099cab3 580 $contribution = $this->callAPISuccessGetSingle('Contribution', [
268a84f2 581 'contact_id' => $this->_individualId,
9099cab3 582 ]);
268a84f2 583 $this->assertEquals('Completed', $contribution['contribution_status']);
584 $this->assertEquals(50.00, $contribution['total_amount']);
585 $this->assertEquals(50.00, $contribution['net_amount']);
586
587 // Step 2: Change the membership type whose minimum free is less than earlier membership
9099cab3 588 $secondMembershipType = $this->callAPISuccess('membership_type', 'create', [
268a84f2 589 'domain_id' => 1,
590 'name' => "Second Test Membership",
591 'member_of_contact_id' => 23,
592 'duration_unit' => "month",
593 'minimum_fee' => 25,
594 'duration_interval' => 1,
595 'period_type' => "fixed",
596 'fixed_period_start_day' => "101",
597 'fixed_period_rollover_day' => "1231",
598 'relationship_type_id' => 20,
599 'financial_type_id' => 2,
9099cab3 600 ]);
268a84f2 601 Civi::settings()->set('update_contribution_on_membership_type_change', TRUE);
602 $form = $this->getForm();
603 $form->preProcess();
604 $form->_id = $membership['id'];
605 $form->set('priceSetId', $priceSet['id']);
606 CRM_Price_BAO_PriceSet::buildPriceSet($form);
607 $form->_action = CRM_Core_Action::UPDATE;
9099cab3 608 $params = [
268a84f2 609 'cid' => $this->_individualId,
8b408447 610 'join_date' => date('Y-m-d'),
268a84f2 611 'start_date' => '',
612 'end_date' => '',
613 // This format reflects the 23 being the organisation & the 25 being the type.
9099cab3 614 'membership_type_id' => [23, $secondMembershipType['id']],
268a84f2 615 'record_contribution' => 1,
616 'status_id' => 1,
617 'total_amount' => 25,
553842be 618 'receive_date' => date('Y-m-d', time()) . ' 20:36:00',
268a84f2 619 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
39b959db
SL
620 //Member dues, see data.xml
621 'financial_type_id' => '2',
268a84f2 622 'payment_processor_id' => $this->_paymentProcessorID,
9099cab3 623 ];
268a84f2 624 $form->_contactID = $this->_individualId;
625 $form->testSubmit($params);
9099cab3 626 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
268a84f2 627 // check the membership status after partial payment, if its Pending
9099cab3 628 $contribution = $this->callAPISuccessGetSingle('Contribution', [
268a84f2 629 'contact_id' => $this->_individualId,
9099cab3 630 ]);
268a84f2 631 $payment = CRM_Contribute_BAO_Contribution::getPaymentInfo($membership['id'], 'membership', FALSE, TRUE);
632 // Check the contribution status on membership type change whose minimum fee was less than earlier memebership
633 $this->assertEquals('Pending refund', $contribution['contribution_status']);
634 // Earlier paid amount
635 $this->assertEquals(50, $payment['paid']);
636 // balance remaning
637 $this->assertEquals(-25, $payment['balance']);
638 }
639
aec171f3 640 /**
641 * Test the submit function of the membership form for partial payment.
83644f47 642 *
643 * @param string $thousandSeparator
644 * punctuation used to refer to thousands.
645 *
646 * @dataProvider getThousandSeparators
aec171f3 647 */
83644f47 648 public function testSubmitPartialPayment($thousandSeparator) {
649 $this->setCurrencySeparators($thousandSeparator);
aec171f3 650 // Step 1: submit a partial payment for a membership via backoffice
651 $form = $this->getForm();
652 $form->preProcess();
653 $this->mut = new CiviMailUtils($this, TRUE);
654 $this->createLoggedInUser();
9099cab3 655 $priceSet = $this->callAPISuccess('PriceSet', 'Get', ["extends" => "CiviMember"]);
aec171f3 656 $form->set('priceSetId', $priceSet['id']);
657 $partiallyPaidAmount = 25;
658 CRM_Price_BAO_PriceSet::buildPriceSet($form);
9099cab3 659 $params = [
aec171f3 660 'cid' => $this->_individualId,
8b408447 661 'join_date' => date('Y-m-d'),
aec171f3 662 'start_date' => '',
663 'end_date' => '',
664 // This format reflects the 23 being the organisation & the 25 being the type.
9099cab3 665 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
553842be 666 'receive_date' => date('Y-m-d', time()) . ' 20:36:00',
aec171f3 667 'record_contribution' => 1,
83644f47 668 'total_amount' => $this->formatMoneyInput($partiallyPaidAmount),
aec171f3 669 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
670 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Partially paid'),
39b959db
SL
671 //Member dues, see data.xml
672 'financial_type_id' => '2',
aec171f3 673 'payment_processor_id' => $this->_paymentProcessorID,
9099cab3 674 ];
aec171f3 675 $form->_contactID = $this->_individualId;
676 $form->testSubmit($params);
9099cab3 677 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
aec171f3 678 // check the membership status after partial payment, if its Pending
679 $this->assertEquals(array_search('Pending', CRM_Member_PseudoConstant::membershipStatus()), $membership['status_id']);
9099cab3 680 $contribution = $this->callAPISuccessGetSingle('Contribution', [
aec171f3 681 'contact_id' => $this->_individualId,
9099cab3 682 ]);
aec171f3 683 $this->assertEquals('Partially paid', $contribution['contribution_status']);
684 // $this->assertEquals(50.00, $contribution['total_amount']);
685 // $this->assertEquals(25.00, $contribution['net_amount']);
686
687 // Step 2: submit the other half of the partial payment
688 // via AdditionalPayment form to complete the related contribution
689 $form = new CRM_Contribute_Form_AdditionalPayment();
9099cab3 690 $submitParams = [
aec171f3 691 'contribution_id' => $contribution['contribution_id'],
692 'contact_id' => $this->_individualId,
83644f47 693 'total_amount' => $this->formatMoneyInput($partiallyPaidAmount),
aec171f3 694 'currency' => 'USD',
695 'financial_type_id' => 2,
553842be 696 'receive_date' => '2015-04-21 23:27:00',
aec171f3 697 'trxn_date' => '2017-04-11 13:05:11',
698 'payment_processor_id' => 0,
699 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
700 'check_number' => 'check-12345',
9099cab3 701 ];
aec171f3 702 $form->cid = $this->_individualId;
703 $form->testSubmit($submitParams);
9099cab3 704 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
aec171f3 705 // check the membership status after additional payment, if its changed to 'New'
706 $this->assertEquals(array_search('New', CRM_Member_PseudoConstant::membershipStatus()), $membership['status_id']);
707
708 // check the contribution status and net amount after additional payment
9099cab3 709 $contribution = $this->callAPISuccessGetSingle('Contribution', [
aec171f3 710 'contact_id' => $this->_individualId,
9099cab3 711 ]);
aec171f3 712 $this->assertEquals('Completed', $contribution['contribution_status']);
aec171f3 713 // $this->assertEquals(50.00, $contribution['net_amount']);
714 }
715
a8215a8d
EM
716 /**
717 * Test the submit function of the membership form.
91786f44 718 *
719 * @throws \CRM_Core_Exception
a8215a8d
EM
720 */
721 public function testSubmitRecur() {
c26225d2 722 CRM_Core_Session::singleton()->getStatus(TRUE);
9099cab3 723 $pendingVal = $this->callAPISuccessGetValue('OptionValue', [
371e0262
JP
724 'return' => "id",
725 'option_group_id' => "contribution_status",
91786f44 726 'label' => "Pending Label**",
9099cab3 727 ]);
371e0262 728 //Update label for Pending contribution status.
9099cab3 729 $this->callAPISuccess('OptionValue', 'create', [
371e0262
JP
730 'id' => $pendingVal,
731 'label' => "PendingEdited",
9099cab3 732 ]);
371e0262 733
a8215a8d
EM
734 $form = $this->getForm();
735
9099cab3 736 $this->callAPISuccess('MembershipType', 'create', [
08fd4b45 737 'id' => $this->membershipTypeAnnualFixedID,
a8215a8d
EM
738 'duration_unit' => 'month',
739 'duration_interval' => 1,
740 'auto_renew' => TRUE,
9099cab3 741 ]);
a8215a8d
EM
742 $form->preProcess();
743 $this->createLoggedInUser();
3cc61729 744 $params = $this->getBaseSubmitParams();
745 $form->_mode = 'test';
09108d7d 746 $form->_contactID = $this->_individualId;
747 $form->testSubmit($params);
9099cab3
CW
748 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
749 $this->callAPISuccessGetCount('ContributionRecur', ['contact_id' => $this->_individualId], 1);
3cc61729 750
9099cab3 751 $contribution = $this->callAPISuccess('Contribution', 'get', [
3cc61729 752 'contact_id' => $this->_individualId,
753 'is_test' => TRUE,
9099cab3 754 ]);
3cc61729 755
371e0262 756 //Check if Membership Payment is recorded.
9099cab3 757 $this->callAPISuccessGetCount('MembershipPayment', [
371e0262
JP
758 'membership_id' => $membership['id'],
759 'contribution_id' => $contribution['id'],
9099cab3 760 ], 1);
371e0262 761
3cc61729 762 // CRM-16992.
9099cab3 763 $this->callAPISuccessGetCount('LineItem', [
3cc61729 764 'entity_id' => $membership['id'],
765 'entity_table' => 'civicrm_membership',
766 'contribution_id' => $contribution['id'],
9099cab3 767 ], 1);
c26225d2
MWMC
768 $this->assertEquals([
769 [
770 'text' => 'AnnualFixed membership for Mr. Anthony Anderson II has been added. The new membership End Date is ' . date('F jS, Y', strtotime('last day of this month')) . ' 12:00 AM.',
771 'title' => 'Complete',
772 'type' => 'success',
773 'options' => NULL,
774 ],
775 ], CRM_Core_Session::singleton()->getStatus());
3cc61729 776 }
777
e2ce0d88 778 /**
779 * CRM-20946: Test the financial entires especially the reversed amount,
780 * after related Contribution is cancelled
781 */
782 public function testFinancialEntiriesOnCancelledContribution() {
b7e2e1b0
DJ
783 // Create two memberships for individual $this->_individualId, via a price set in the back end.
784 $this->createTwoMembershipsViaPriceSetInBackEnd($this->_individualId);
e2ce0d88 785
786 // cancel the related contribution via API
9099cab3 787 $contribution = $this->callAPISuccessGetSingle('Contribution', [
e2ce0d88 788 'contact_id' => $this->_individualId,
789 'contribution_status_id' => 2,
9099cab3
CW
790 ]);
791 $this->callAPISuccess('Contribution', 'create', [
e2ce0d88 792 'id' => $contribution['id'],
793 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Cancelled'),
9099cab3 794 ]);
e2ce0d88 795
796 // fetch financial_trxn ID of the related contribution
797 $sql = "SELECT financial_trxn_id
798 FROM civicrm_entity_financial_trxn
799 WHERE entity_id = %1 AND entity_table = 'civicrm_contribution'
800 ORDER BY id DESC
801 LIMIT 1
802 ";
9099cab3 803 $financialTrxnID = CRM_Core_DAO::singleValueQuery($sql, [1 => [$contribution['id'], 'Int']]);
e2ce0d88 804
805 // fetch entity_financial_trxn records and compare their cancelled records
9099cab3 806 $result = $this->callAPISuccess('EntityFinancialTrxn', 'Get', [
e2ce0d88 807 'financial_trxn_id' => $financialTrxnID,
808 'entity_table' => 'civicrm_financial_item',
9099cab3 809 ]);
e2ce0d88 810 // compare the reversed amounts of respective memberships after cancelling contribution
9099cab3 811 $cancelledMembershipAmounts = [
e2ce0d88 812 -20.00,
813 -10.00,
9099cab3 814 ];
e2ce0d88 815 $count = 0;
816 foreach ($result['values'] as $record) {
817 $this->assertEquals($cancelledMembershipAmounts[$count], $record['amount']);
818 $count++;
819 }
820 }
821
09108d7d 822 /**
823 * Test the submit function of the membership form.
824 */
825 public function testSubmitPayLaterWithBilling() {
826 $form = $this->getForm(NULL);
0dc4ef42 827 $form->preProcess();
09108d7d 828 $this->createLoggedInUser();
9099cab3 829 $params = [
09108d7d 830 'cid' => $this->_individualId,
8b408447 831 'join_date' => date('Y-m-d'),
09108d7d 832 'start_date' => '',
833 'end_date' => '',
834 // This format reflects the 23 being the organisation & the 25 being the type.
9099cab3 835 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
09108d7d 836 'auto_renew' => '0',
837 'max_related' => '',
838 'num_terms' => '2',
839 'source' => '',
840 'total_amount' => '50.00',
841 //Member dues, see data.xml
842 'financial_type_id' => '2',
843 'soft_credit_type_id' => '',
844 'soft_credit_contact_id' => '',
845 'payment_instrument_id' => 4,
846 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
847 'receipt_text_signup' => 'Thank you text',
848 'payment_processor_id' => $this->_paymentProcessorID,
849 'record_contribution' => TRUE,
850 'trxn_id' => 777,
851 'contribution_status_id' => 2,
852 'billing_first_name' => 'Test',
853 'billing_middlename' => 'Last',
854 'billing_street_address-5' => '10 Test St',
855 'billing_city-5' => 'Test',
856 'billing_state_province_id-5' => '1003',
857 'billing_postal_code-5' => '90210',
858 'billing_country_id-5' => '1228',
9099cab3 859 ];
09108d7d 860 $form->_contactID = $this->_individualId;
861
862 $form->testSubmit($params);
9099cab3
CW
863 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
864 $contribution = $this->callAPISuccessGetSingle('Contribution', [
09108d7d 865 'contact_id' => $this->_individualId,
866 'contribution_status_id' => 2,
9099cab3 867 ]);
09108d7d 868 $this->assertEquals($contribution['trxn_id'], 777);
869
9099cab3 870 $this->callAPISuccessGetCount('LineItem', [
09108d7d 871 'entity_id' => $membership['id'],
872 'entity_table' => 'civicrm_membership',
873 'contribution_id' => $contribution['id'],
9099cab3
CW
874 ], 1);
875 $this->callAPISuccessGetSingle('address', [
09108d7d 876 'contact_id' => $this->_individualId,
877 'street_address' => '10 Test St',
878 'postal_code' => 90210,
9099cab3 879 ]);
09108d7d 880 }
881
494fdf05
JP
882 /**
883 * Test if membership is updated to New after contribution
884 * is updated from Partially paid to Completed.
885 */
886 public function testSubmitUpdateMembershipFromPartiallyPaid() {
887 $memStatus = CRM_Member_BAO_Membership::buildOptions('status_id', 'validate');
888
889 //Perform a pay later membership contribution.
890 $this->testSubmitPayLaterWithBilling();
9099cab3 891 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
494fdf05 892 $this->assertEquals($membership['status_id'], array_search('Pending', $memStatus));
9099cab3 893 $contribution = $this->callAPISuccessGetSingle('MembershipPayment', [
494fdf05 894 'membership_id' => $membership['id'],
9099cab3 895 ]);
494fdf05
JP
896
897 //Update contribution to Partially paid.
9099cab3 898 $prevContribution = $this->callAPISuccess('Contribution', 'create', [
494fdf05 899 'id' => $contribution['contribution_id'],
1e9b7f9f 900 'contribution_status_id' => 'Partially paid',
9099cab3 901 ]);
494fdf05
JP
902 $prevContribution = $prevContribution['values'][1];
903
904 //Complete the contribution from offline form.
905 $form = new CRM_Contribute_Form_Contribution();
9099cab3 906 $submitParams = [
494fdf05 907 'id' => $contribution['contribution_id'],
1e9b7f9f 908 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
494fdf05 909 'price_set_id' => 0,
9099cab3
CW
910 ];
911 $fields = ['total_amount', 'net_amount', 'financial_type_id', 'receive_date', 'contact_id', 'payment_instrument_id'];
494fdf05
JP
912 foreach ($fields as $val) {
913 $submitParams[$val] = $prevContribution[$val];
914 }
915 $form->testSubmit($submitParams, CRM_Core_Action::UPDATE);
916
917 //Check if Membership is updated to New.
9099cab3 918 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
494fdf05
JP
919 $this->assertEquals($membership['status_id'], array_search('New', $memStatus));
920 }
921
bf6ba9fc 922 /**
923 * Test the submit function of the membership form.
924 */
925 public function testSubmitRecurCompleteInstant() {
926 $form = $this->getForm();
e9dfe40a 927 $mut = new CiviMailUtils($this, TRUE);
bf6ba9fc 928 $processor = Civi\Payment\System::singleton()->getById($this->_paymentProcessorID);
9099cab3 929 $processor->setDoDirectPaymentResult([
77623a96 930 'payment_status_id' => 1,
931 'trxn_id' => 'kettles boil water',
932 'fee_amount' => .14,
9099cab3 933 ]);
204efedd 934 $processorDetail = $processor->getPaymentProcessor();
9099cab3 935 $this->callAPISuccess('MembershipType', 'create', [
bf6ba9fc 936 'id' => $this->membershipTypeAnnualFixedID,
937 'duration_unit' => 'month',
938 'duration_interval' => 1,
939 'auto_renew' => TRUE,
9099cab3 940 ]);
bf6ba9fc 941 $form->preProcess();
942 $this->createLoggedInUser();
943 $params = $this->getBaseSubmitParams();
944 $form->_mode = 'test';
09108d7d 945 $form->_contactID = $this->_individualId;
946 $form->testSubmit($params);
9099cab3
CW
947 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
948 $this->callAPISuccessGetCount('ContributionRecur', ['contact_id' => $this->_individualId], 1);
bf6ba9fc 949
9099cab3 950 $contribution = $this->callAPISuccess('Contribution', 'getsingle', [
bf6ba9fc 951 'contact_id' => $this->_individualId,
952 'is_test' => TRUE,
9099cab3 953 ]);
bf6ba9fc 954
77623a96 955 $this->assertEquals(.14, $contribution['fee_amount']);
956 $this->assertEquals('kettles boil water', $contribution['trxn_id']);
204efedd 957 $this->assertEquals($processorDetail['payment_instrument_id'], $contribution['payment_instrument_id']);
77623a96 958
9099cab3 959 $this->callAPISuccessGetCount('LineItem', [
bf6ba9fc 960 'entity_id' => $membership['id'],
961 'entity_table' => 'civicrm_membership',
962 'contribution_id' => $contribution['id'],
9099cab3
CW
963 ], 1);
964 $mut->checkMailLog([
39b959db 965 '===========================================================
e9dfe40a 966Billing Name and Address
967===========================================================
968Test
96910 Test St
970Test, AR 90210
971US',
39b959db 972 '===========================================================
e9dfe40a 973Membership Information
974===========================================================
975Membership Type: AnnualFixed
976Membership Start Date: ',
39b959db 977 '===========================================================
e9dfe40a 978Credit Card Information
979===========================================================
980Visa
981************1111
982Expires: ',
9099cab3 983 ]);
e9dfe40a 984 $mut->stop();
bf6ba9fc 985
986 }
987
1da0f2ec
JP
988 /**
989 * Test membership form with Failed Contribution.
990 */
991 public function testFormWithFailedContribution() {
992 $form = $this->getForm();
0dc4ef42 993 $form->preProcess();
1da0f2ec
JP
994 $this->createLoggedInUser();
995 $params = $this->getBaseSubmitParams();
996 unset($params['price_set_id']);
997 unset($params['credit_card_number']);
998 unset($params['cvv2']);
999 unset($params['credit_card_exp_date']);
1000 unset($params['credit_card_type']);
1001 unset($params['send_receipt']);
1002 unset($params['is_recur']);
1003
1004 $params['record_contribution'] = TRUE;
1005 $params['contribution_status_id'] = array_search('Failed', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'));
1006 $form->_mode = NULL;
1007 $form->_contactID = $this->_individualId;
1008
1009 $form->testSubmit($params);
9099cab3 1010 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
1da0f2ec 1011 $form->testSubmit($params);
9099cab3 1012 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
1da0f2ec
JP
1013 $this->assertEquals($membership['status_id'], array_search('Pending', CRM_Member_PseudoConstant::membershipStatus()));
1014 }
1015
b7e2e1b0
DJ
1016 /**
1017 * CRM-20955, CRM-20966:
1018 * Test creating two memberships with inheritance via price set in the back end,
1019 * checking that the correct primary & secondary memberships, contributions, line items
1020 * & membership_payment records are created.
1021 * Uses some data from tests/phpunit/CRM/Member/Form/dataset/data.xml .
1022 */
1023 public function testTwoInheritedMembershipsViaPriceSetInBackend() {
1024 // Create an organization and give it a "Member of" relationship to $this->_individualId.
74b3a175 1025 $orgID = $this->organizationCreate();
9099cab3 1026 $relationship = $this->callAPISuccess('relationship', 'create', [
b7e2e1b0 1027 'contact_id_a' => $this->_individualId,
74b3a175 1028 'contact_id_b' => $orgID,
b7e2e1b0
DJ
1029 'relationship_type_id' => 20,
1030 'is_active' => 1,
9099cab3 1031 ]);
b7e2e1b0
DJ
1032
1033 // Create two memberships for the organization, via a price set in the back end.
74b3a175 1034 $this->createTwoMembershipsViaPriceSetInBackEnd($orgID);
b7e2e1b0
DJ
1035
1036 // Check the primary memberships on the organization.
9099cab3 1037 $orgMembershipResult = $this->callAPISuccess('membership', 'get', [
74b3a175 1038 'contact_id' => $orgID,
9099cab3 1039 ]);
b7e2e1b0 1040 $this->assertEquals(2, $orgMembershipResult['count'], "2 primary memberships should have been created on the organization.");
9099cab3 1041 $primaryMembershipIds = [];
b7e2e1b0
DJ
1042 foreach ($orgMembershipResult['values'] as $membership) {
1043 $primaryMembershipIds[] = $membership['id'];
1044 $this->assertTrue(empty($membership['owner_membership_id']), "Membership on the organization has owner_membership_id so is inherited.");
1045 }
1046
1047 // CRM-20955: check that correct inherited memberships were created for the individual,
1048 // for both of the primary memberships.
9099cab3 1049 $individualMembershipResult = $this->callAPISuccess('membership', 'get', [
b7e2e1b0 1050 'contact_id' => $this->_individualId,
9099cab3 1051 ]);
b7e2e1b0
DJ
1052 $this->assertEquals(2, $individualMembershipResult['count'], "2 inherited memberships should have been created on the individual.");
1053 foreach ($individualMembershipResult['values'] as $membership) {
1054 $this->assertNotEmpty($membership['owner_membership_id'], "Membership on the individual lacks owner_membership_id so is not inherited.");
1055 $this->assertNotContains($membership['id'], $primaryMembershipIds, "Inherited membership id should not be the id of a primary membership.");
1056 $this->assertContains($membership['owner_membership_id'], $primaryMembershipIds, "Inherited membership owner_membership_id should be the id of a primary membership.");
1057 }
1058
1059 // CRM-20966: check that the correct membership contribution, line items
1060 // & membership_payment records were created for the organization.
9099cab3 1061 $contributionResult = $this->callAPISuccess('contribution', 'get', [
74b3a175 1062 'contact_id' => $orgID,
b7e2e1b0 1063 'sequential' => 1,
9099cab3
CW
1064 'api.line_item.get' => [],
1065 'api.membership_payment.get' => [],
1066 ]);
b7e2e1b0
DJ
1067 $this->assertEquals(1, $contributionResult['count'], "One contribution should have been created for the organization's memberships.");
1068
74b3a175 1069 $this->assertEquals(2, $contributionResult['values'][0]['api.line_item.get']['count'], "2 line items should have been created for the organization's memberships.");
b7e2e1b0 1070 foreach ($contributionResult['values'][0]['api.line_item.get']['values'] as $lineItem) {
74b3a175
DJ
1071 $this->assertEquals('civicrm_membership', $lineItem['entity_table'], "Membership line item's entity_table should be 'civicrm_membership'.");
1072 $this->assertContains($lineItem['entity_id'], $primaryMembershipIds, "Membership line item's entity_id should be the id of a primary membership.");
b7e2e1b0
DJ
1073 }
1074
74b3a175 1075 $this->assertEquals(2, $contributionResult['values'][0]['api.membership_payment.get']['count'], "2 membership payment records should have been created for the organization's memberships.");
b7e2e1b0 1076 foreach ($contributionResult['values'][0]['api.membership_payment.get']['values'] as $membershipPayment) {
74b3a175
DJ
1077 $this->assertEquals($contributionResult['values'][0]['id'], $membershipPayment['contribution_id'], "membership payment's contribution ID should be the ID of the organization's membership contribution.");
1078 $this->assertContains($membershipPayment['membership_id'], $primaryMembershipIds, "membership payment's membership ID should be the ID of a primary membership.");
b7e2e1b0
DJ
1079 }
1080
1081 // CRM-20966: check that deleting relationship used for inheritance does not delete contribution.
9099cab3 1082 $this->callAPISuccess('relationship', 'delete', [
b7e2e1b0 1083 'id' => $relationship['id'],
9099cab3 1084 ]);
b7e2e1b0 1085
9099cab3 1086 $contributionResultAfterRelationshipDelete = $this->callAPISuccess('contribution', 'get', [
b7e2e1b0 1087 'id' => $contributionResult['values'][0]['id'],
74b3a175 1088 'contact_id' => $orgID,
9099cab3 1089 ]);
b7e2e1b0
DJ
1090 $this->assertEquals(1, $contributionResultAfterRelationshipDelete['count'], "Contribution has been wrongly deleted.");
1091 }
1092
53af5ea1
DJ
1093 /**
1094 * dev/core/issues/860:
1095 * Test creating two memberships via price set in the back end with a discount,
1096 * checking that the line items have correct amounts.
1097 */
1098 public function testTwoMembershipsViaPriceSetInBackendWithDiscount() {
1099 // Register buildAmount hook to apply discount.
1100 $this->hookClass->setHook('civicrm_buildAmount', [$this, 'buildAmountMembershipDiscount']);
1101
1102 // Create two memberships for individual $this->_individualId, via a price set in the back end.
1103 $this->createTwoMembershipsViaPriceSetInBackEnd($this->_individualId);
1104 $contribution = $this->callAPISuccessGetSingle('Contribution', [
1105 'contact_id' => $this->_individualId,
1106 ]);
1107 // Note: we can't check for the contribution total being discounted, because the total is set
1108 // when the contribution is created via $form->testSubmit(), but buildAmount isn't called
1109 // until testSubmit() runs. Fixing that might involve making testSubmit() more sophisticated,
1110 // or just hacking total_amount for this case.
1111
1112 $lineItemResult = $this->callAPISuccess('LineItem', 'get', [
1113 'contribution_id' => $contribution['id'],
1114 ]);
1115 $this->assertEquals(2, $lineItemResult['count']);
1116 $discountedItems = 0;
1117 foreach ($lineItemResult['values'] as $lineItem) {
1118 if (CRM_Utils_String::startsWith($lineItem['label'], 'Long Haired Goat')) {
1119 $this->assertEquals(15.0, $lineItem['line_total']);
1120 $this->assertEquals('Long Haired Goat - one leg free!', $lineItem['label']);
1121 $discountedItems++;
1122 }
1123 }
1124 $this->assertEquals(1, $discountedItems);
1125 }
1126
1127 /**
1128 * Implements hook_civicrm_buildAmount() for testTwoMembershipsViaPriceSetInBackendWithDiscount().
1129 */
1130 public function buildAmountMembershipDiscount($pageType, &$form, &$amount) {
1131 foreach ($amount as $id => $priceField) {
1132 if (is_array($priceField['options'])) {
1133 foreach ($priceField['options'] as $optionId => $option) {
1134 if ($option['membership_type_id'] == 15) {
1135 // Long Haired Goat membership discount.
1136 $amount[$id]['options'][$optionId]['amount'] = $option['amount'] * 0.75;
1137 $amount[$id]['options'][$optionId]['label'] = $option['label'] . ' - one leg free!';
1138 }
1139 }
1140 }
1141 }
1142 }
1143
3cc61729 1144 /**
1145 * Get a membership form object.
1146 *
1147 * We need to instantiate the form to run preprocess, which means we have to trick it about the request method.
1148 *
1149 * @return \CRM_Member_Form_Membership
1150 */
1151 protected function getForm() {
b0104807 1152 if (isset($_REQUEST['cid'])) {
1153 unset($_REQUEST['cid']);
1154 }
3cc61729 1155 $form = new CRM_Member_Form_Membership();
1156 $_SERVER['REQUEST_METHOD'] = 'GET';
1157 $form->controller = new CRM_Core_Controller();
3cc61729 1158 return $form;
1159 }
1160
1161 /**
1162 * @return array
1163 */
1164 protected function getBaseSubmitParams() {
9099cab3 1165 $params = [
a8215a8d
EM
1166 'cid' => $this->_individualId,
1167 'price_set_id' => 0,
8b408447 1168 'join_date' => date('Y-m-d'),
a8215a8d
EM
1169 'start_date' => '',
1170 'end_date' => '',
1171 'campaign_id' => '',
08fd4b45 1172 // This format reflects the 23 being the organisation & the 25 being the type.
9099cab3 1173 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
a8215a8d
EM
1174 'auto_renew' => '1',
1175 'is_recur' => 1,
1176 'max_related' => 0,
1177 'num_terms' => '1',
1178 'source' => '',
1179 'total_amount' => '77.00',
39b959db
SL
1180 //Member dues, see data.xml
1181 'financial_type_id' => '2',
a8215a8d
EM
1182 'soft_credit_type_id' => 11,
1183 'soft_credit_contact_id' => '',
1184 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
1185 'receipt_text' => 'Thank you text',
1186 'payment_processor_id' => $this->_paymentProcessorID,
1187 'credit_card_number' => '4111111111111111',
1188 'cvv2' => '123',
9099cab3 1189 'credit_card_exp_date' => [
a8215a8d 1190 'M' => '9',
39b959db
SL
1191 // TODO: Future proof
1192 'Y' => '2019',
9099cab3 1193 ],
a8215a8d
EM
1194 'credit_card_type' => 'Visa',
1195 'billing_first_name' => 'Test',
1196 'billing_middlename' => 'Last',
1197 'billing_street_address-5' => '10 Test St',
1198 'billing_city-5' => 'Test',
1199 'billing_state_province_id-5' => '1003',
1200 'billing_postal_code-5' => '90210',
1201 'billing_country_id-5' => '1228',
e9dfe40a 1202 'send_receipt' => 1,
9099cab3 1203 ];
3cc61729 1204 return $params;
a8215a8d 1205 }
a271822c 1206
b7e2e1b0
DJ
1207 /**
1208 * Scenario builder:
1209 * create two memberships for the same individual, via a price set in the back end.
1210 *
1211 * @param int $contactId Id of contact on which the memberships will be created.
1212 */
1213 protected function createTwoMembershipsViaPriceSetInBackEnd($contactId) {
1214 $form = $this->getForm(NULL);
1215 $form->preProcess();
1216 $this->createLoggedInUser();
1217
1218 // create a price-set of price-field of type checkbox and each price-option corresponds to a membership type
9099cab3 1219 $priceSet = $this->callAPISuccess('price_set', 'create', [
b7e2e1b0
DJ
1220 'is_quick_config' => 0,
1221 'extends' => 'CiviMember',
1222 'financial_type_id' => 1,
1223 'title' => 'my Page',
9099cab3 1224 ]);
b7e2e1b0
DJ
1225 $priceSetID = $priceSet['id'];
1226 // create respective checkbox price-field
9099cab3 1227 $priceField = $this->callAPISuccess('price_field', 'create', [
b7e2e1b0
DJ
1228 'price_set_id' => $priceSetID,
1229 'label' => 'Memberships',
1230 'html_type' => 'Checkbox',
9099cab3 1231 ]);
b7e2e1b0
DJ
1232 $priceFieldID = $priceField['id'];
1233 // create two price options, each represent a membership type of amount 20 and 10 respectively
9099cab3 1234 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
39b959db
SL
1235 'price_set_id' => $priceSetID,
1236 'price_field_id' => $priceField['id'],
1237 'label' => 'Long Haired Goat',
1238 'amount' => 20,
1239 'financial_type_id' => 'Donation',
1240 'membership_type_id' => 15,
1241 'membership_num_terms' => 1,
9099cab3
CW
1242 ]);
1243 $pfvIDs = [$priceFieldValue['id'] => 1];
1244 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
39b959db
SL
1245 'price_set_id' => $priceSetID,
1246 'price_field_id' => $priceField['id'],
1247 'label' => 'Shoe-eating Goat',
1248 'amount' => 10,
1249 'financial_type_id' => 'Donation',
1250 'membership_type_id' => 35,
1251 'membership_num_terms' => 2,
9099cab3 1252 ]);
b7e2e1b0
DJ
1253 $pfvIDs[$priceFieldValue['id']] = 1;
1254
1255 // register for both of these memberships via backoffice membership form submission
9099cab3 1256 $params = [
b7e2e1b0 1257 'cid' => $contactId,
8b408447 1258 'join_date' => date('Y-m-d'),
b7e2e1b0
DJ
1259 'start_date' => '',
1260 'end_date' => '',
1261 // This format reflects the 23 being the organisation & the 25 being the type.
1262 "price_$priceFieldID" => $pfvIDs,
1263 "price_set_id" => $priceSetID,
9099cab3 1264 'membership_type_id' => [1 => 0],
b7e2e1b0
DJ
1265 'auto_renew' => '0',
1266 'max_related' => '',
1267 'num_terms' => '2',
1268 'source' => '',
1269 'total_amount' => '30.00',
1270 //Member dues, see data.xml
1271 'financial_type_id' => '2',
1272 'soft_credit_type_id' => '',
1273 'soft_credit_contact_id' => '',
1274 'payment_instrument_id' => 4,
1275 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
1276 'receipt_text_signup' => 'Thank you text',
1277 'payment_processor_id' => $this->_paymentProcessorID,
1278 'record_contribution' => TRUE,
1279 'trxn_id' => 777,
1280 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Pending'),
1281 'billing_first_name' => 'Test',
1282 'billing_middlename' => 'Last',
1283 'billing_street_address-5' => '10 Test St',
1284 'billing_city-5' => 'Test',
1285 'billing_state_province_id-5' => '1003',
1286 'billing_postal_code-5' => '90210',
1287 'billing_country_id-5' => '1228',
9099cab3 1288 ];
b7e2e1b0
DJ
1289 $form->testSubmit($params);
1290 }
1291
de5b5c6c
JP
1292 /**
1293 * Test membership status overrides when contribution is cancelled.
1294 */
1295 public function testContributionFormStatusUpdate() {
1296 $form = new CRM_Contribute_Form_Contribution();
1297
1298 //Create a membership with status = 'New'.
1299 $this->_individualId = $this->createLoggedInUser();
9099cab3 1300 $memParams = [
de5b5c6c
JP
1301 'contact_id' => $this->_individualId,
1302 'membership_type_id' => $this->membershipTypeAnnualFixedID,
1303 'status_id' => array_search('New', CRM_Member_PseudoConstant::membershipStatus()),
9099cab3
CW
1304 ];
1305 $cancelledStatusId = $this->callAPISuccessGetValue('OptionValue', [
de5b5c6c
JP
1306 'return' => "value",
1307 'option_group_id' => "contribution_status",
1308 'name' => "Cancelled",
9099cab3
CW
1309 ]);
1310 $params = [
de5b5c6c
JP
1311 'total_amount' => 50,
1312 'financial_type_id' => 2,
1313 'contact_id' => $this->_individualId,
1314 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
1315 'contribution_status_id' => $cancelledStatusId,
9099cab3 1316 ];
de5b5c6c
JP
1317 $membershipId = $this->contactMembershipCreate($memParams);
1318
9099cab3 1319 $contriParams = [
de5b5c6c
JP
1320 'membership_id' => $membershipId,
1321 'total_amount' => 50,
1322 'financial_type_id' => 2,
1323 'contact_id' => $this->_individualId,
9099cab3 1324 ];
de5b5c6c
JP
1325 $contribution = CRM_Member_BAO_Membership::recordMembershipContribution($contriParams);
1326
1327 //Update Contribution to Cancelled.
1328 $form->_id = $params['id'] = $contribution->id;
1329 $form->_mode = NULL;
1330 $form->_contactID = $this->_individualId;
1331 $form->testSubmit($params, CRM_Core_Action::UPDATE);
9099cab3 1332 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
de5b5c6c
JP
1333
1334 //Assert membership status overrides when the contribution cancelled.
1335 $this->assertEquals($membership['is_override'], TRUE);
9099cab3 1336 $this->assertEquals($membership['status_id'], $this->callAPISuccessGetValue('MembershipStatus', [
de5b5c6c
JP
1337 'return' => "id",
1338 'name' => "Cancelled",
9099cab3 1339 ]));
de5b5c6c
JP
1340 }
1341
f436577a 1342 /**
ddfe1cb1
K
1343 * CRM-21656: Test the submit function of the membership form if Sales Tax is enabled.
1344 * This test simulates what happens when one hits Edit on a Contribution that has both LineItems and Sales Tax components
1345 * Without making any Edits -> check that the LineItem data remain the same
1346 * In addition (a data-integrity check) -> check that the LineItem data add up to the data at the Contribution level
f436577a 1347 */
ddfe1cb1 1348 public function testLineItemAmountOnSalesTax() {
f436577a 1349 $this->enableTaxAndInvoicing();
1350 $this->relationForFinancialTypeWithFinancialAccount(2);
1351 $form = $this->getForm();
1352 $form->preProcess();
1353 $this->mut = new CiviMailUtils($this, TRUE);
1354 $this->createLoggedInUser();
9099cab3 1355 $priceSet = $this->callAPISuccess('PriceSet', 'Get', ["extends" => "CiviMember"]);
f436577a 1356 $form->set('priceSetId', $priceSet['id']);
dcdfd53d 1357 // we are simulating the creation of a Price Set in Administer -> CiviContribute -> Manage Price Sets so set is_quick_config = 0
9099cab3 1358 $this->callAPISuccess('PriceSet', 'Create', ["id" => $priceSet['id'], 'is_quick_config' => 0]);
f436577a 1359 // clean the price options static variable to repopulate the options, in order to fetch tax information
1360 \Civi::$statics['CRM_Price_BAO_PriceField']['priceOptions'] = NULL;
1361 CRM_Price_BAO_PriceSet::buildPriceSet($form);
1362 // rebuild the price set form variable to include the tax information against each price options
1363 $form->_priceSet = current(CRM_Price_BAO_PriceSet::getSetDetail($priceSet['id']));
9099cab3 1364 $params = [
f436577a 1365 'cid' => $this->_individualId,
8b408447 1366 'join_date' => date('Y-m-d'),
f436577a 1367 'start_date' => '',
1368 'end_date' => '',
1369 // This format reflects the 23 being the organisation & the 25 being the type.
9099cab3 1370 'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
f436577a 1371 'record_contribution' => 1,
1372 'total_amount' => 55,
553842be 1373 'receive_date' => date('Y-m-d', time()) . ' 20:36:00',
f436577a 1374 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
1375 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
39b959db
SL
1376 //Member dues, see data.xml
1377 'financial_type_id' => 2,
f436577a 1378 'payment_processor_id' => $this->_paymentProcessorID,
9099cab3 1379 ];
f436577a 1380 $form->_contactID = $this->_individualId;
1381 $form->testSubmit($params);
1382
9099cab3
CW
1383 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
1384 $lineItem = $this->callAPISuccessGetSingle('LineItem', ['entity_id' => $membership['id'], 'entity_table' => 'civicrm_membership']);
f436577a 1385 $this->assertEquals(1, $lineItem['qty']);
1386 $this->assertEquals(50.00, $lineItem['unit_price']);
1387 $this->assertEquals(50.00, $lineItem['line_total']);
1388 $this->assertEquals(5.00, $lineItem['tax_amount']);
1389
c6000ff3 1390 // Simply save the 'Edit Contribution' form
1391 $form = new CRM_Contribute_Form_Contribution();
1392 $form->_context = 'membership';
9099cab3
CW
1393 $form->_values = $this->callAPISuccessGetSingle('Contribution', ['id' => $lineItem['contribution_id'], 'return' => ['total_amount', 'net_amount', 'fee_amount', 'tax_amount']]);
1394 $form->testSubmit([
c6000ff3 1395 'contact_id' => $this->_individualId,
1396 'id' => $lineItem['contribution_id'],
1397 'financial_type_id' => 2,
4a413eb6 1398 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
9099cab3 1399 ],
c6000ff3 1400 CRM_Core_Action::UPDATE);
1401
ddfe1cb1 1402 // ensure that the LineItem data remain the same
9099cab3 1403 $lineItem = $this->callAPISuccessGetSingle('LineItem', ['entity_id' => $membership['id'], 'entity_table' => 'civicrm_membership']);
c6000ff3 1404 $this->assertEquals(1, $lineItem['qty']);
dcdfd53d
K
1405 $this->assertEquals(50.00, $lineItem['unit_price']);
1406 $this->assertEquals(50.00, $lineItem['line_total']);
1407 $this->assertEquals(5.00, $lineItem['tax_amount']);
c6000ff3 1408
ddfe1cb1 1409 // ensure that the LineItem data add up to the data at the Contribution level
9a1b6474 1410 $contribution = $this->callAPISuccessGetSingle('Contribution',
9099cab3 1411 [
02b29d41 1412 'contribution_id' => 1,
9099cab3
CW
1413 'return' => ['tax_amount', 'total_amount'],
1414 ]
9a1b6474 1415 );
dcdfd53d 1416 $this->assertEquals($contribution['total_amount'], $lineItem['line_total'] + $lineItem['tax_amount']);
9a1b6474
K
1417 $this->assertEquals($contribution['tax_amount'], $lineItem['tax_amount']);
1418
9099cab3 1419 $financialItems = $this->callAPISuccess('FinancialItem', 'get', []);
b4940518
K
1420 $financialItems_sum = 0;
1421 foreach ($financialItems['values'] as $financialItem) {
1422 $financialItems_sum += $financialItem['amount'];
1423 }
1424 $this->assertEquals($contribution['total_amount'], $financialItems_sum);
1425
f436577a 1426 // reset the price options static variable so not leave any dummy data, that might hamper other unit tests
1427 \Civi::$statics['CRM_Price_BAO_PriceField']['priceOptions'] = NULL;
1428 $this->disableTaxAndInvoicing();
1429 }
1430
7365dd7f
AP
1431 /**
1432 * Test that membership end_date is correct for multiple terms for pending contribution
1433 *
1434 * @throws CiviCRM_API3_Exception
1435 * @throws \CRM_Core_Exception
1436 */
1437 public function testCreatePendingWithMultipleTerms() {
1438 CRM_Core_Session::singleton()->getStatus(TRUE);
1439 $form = $this->getForm();
1440 $form->preProcess();
1441 $this->mut = new CiviMailUtils($this, TRUE);
1442 $this->createLoggedInUser();
1443 $membershipTypeAnnualRolling = $this->callAPISuccess('membership_type', 'create', [
1444 'domain_id' => 1,
1445 'name' => "AnnualRollingNew",
1446 'member_of_contact_id' => 23,
1447 'duration_unit' => "year",
1448 'minimum_fee' => 50,
1449 'duration_interval' => 1,
1450 'period_type' => "rolling",
1451 'relationship_type_id' => 20,
1452 'relationship_direction' => 'b_a',
1453 'financial_type_id' => 2,
1454 ]);
1455 $params = [
1456 'cid' => $this->_individualId,
1457 'join_date' => date('Y-m-d'),
1458 'start_date' => '',
1459 'end_date' => '',
1460 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'),
1461 'membership_type_id' => [23, $membershipTypeAnnualRolling['id']],
1462 'max_related' => '',
1463 'num_terms' => '3',
1464 'record_contribution' => 1,
1465 'source' => '',
1466 'total_amount' => $this->formatMoneyInput(150.00),
1467 'financial_type_id' => '2',
1468 'soft_credit_type_id' => '11',
1469 'soft_credit_contact_id' => '',
1470 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
1471 'receipt_text' => '',
1472 ];
1473 $form->_contactID = $this->_individualId;
1474 $form->testSubmit($params);
1475 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
1476 $contribution = $this->callAPISuccess('Contribution', 'get', [
1477 'contact_id' => $this->_individualId,
1478 ]);
1479 $endDate = (new DateTime(date('Y-m-d')))->modify("+3 years")->modify("-1 day");
1480 $endDate = $endDate->format("Y-m-d");
1481
1482 $this->assertEquals($endDate, $membership['end_date'], 'Membership end date should be ' . $endDate);
1483 $this->assertEquals(1, count($contribution['values']), 'Pending contribution should be created.');
1484 $contribution = $contribution['values'][$contribution['id']];
1485 $additionalPaymentForm = new CRM_Contribute_Form_AdditionalPayment();
1486 $additionalPaymentForm->testSubmit([
1487 'total_amount' => 150.00,
1488 'trxn_date' => date("Y-m-d H:i:s"),
1489 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
1490 'check_number' => 'check-12345',
1491 'trxn_id' => '',
1492 'currency' => 'USD',
1493 'fee_amount' => '',
1494 'financial_type_id' => 1,
1495 'net_amount' => '',
1496 'payment_processor_id' => 0,
1497 'contact_id' => $this->_individualId,
1498 'contribution_id' => $contribution['id'],
1499 ]);
1500 $membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
1501 $contribution = $this->callAPISuccess('Contribution', 'get', [
1502 'contact_id' => $this->_individualId,
1503 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
1504 ]);
1505 $this->assertEquals($endDate, $membership['end_date'], 'Membership end date should be same (' . $endDate . ') after payment');
1506 $this->assertEquals(1, count($contribution['values']), 'Completed contribution should be fetched.');
1507 }
1508
6a488035 1509}