Commit | Line | Data |
---|---|---|
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 | */ |
42 | class 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 | 966 | Billing Name and Address |
967 | =========================================================== | |
968 | Test | |
969 | 10 Test St | |
970 | Test, AR 90210 | |
971 | US', | |
39b959db | 972 | '=========================================================== |
e9dfe40a | 973 | Membership Information |
974 | =========================================================== | |
975 | Membership Type: AnnualFixed | |
976 | Membership Start Date: ', | |
39b959db | 977 | '=========================================================== |
e9dfe40a | 978 | Credit Card Information |
979 | =========================================================== | |
980 | Visa | |
981 | ************1111 | |
982 | Expires: ', | |
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 | } |