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