Merge pull request #15699 from mattwire/participant_cleanup_completeOrderPBRef
[civicrm-core.git] / tests / phpunit / api / v3 / OptionValueTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2020 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 * Class api_v3_OptionValueTest
30 * @group headless
31 */
32 class api_v3_OptionValueTest extends CiviUnitTestCase {
33 protected $_apiversion = 3;
34
35 public function setUp() {
36 parent::setUp();
37 $this->useTransaction(TRUE);
38 }
39
40 public function testGetCount() {
41 $result = $this->callAPISuccess('option_value', 'getcount', []);
42 $this->assertGreaterThan(100, $result);
43 }
44
45 public function testGetOptionValueByID() {
46 $result = $this->callAPISuccess('option_value', 'get', ['id' => 1]);
47 $this->assertEquals(1, $result['count']);
48 $this->assertEquals(1, $result['id']);
49 }
50
51 public function testGetOptionValueByValue() {
52 $result = $this->callAPISuccess('option_value', 'get', ['option_group_id' => 1, 'value' => '1']);
53 $this->assertEquals(1, $result['count']);
54 $this->assertEquals(1, $result['id']);
55 }
56
57 /**
58 * Test limit param.
59 */
60 public function testGetOptionValueLimit() {
61 $params = [];
62 $result = $this->callAPISuccess('option_value', 'get', $params);
63 $this->assertGreaterThan(1, $result['count'], "Check more than one exists In line " . __LINE__);
64 $params['options']['limit'] = 1;
65 $result = $this->callAPISuccess('option_value', 'get', $params);
66 $this->assertEquals(1, $result['count'], "Check only 1 retrieved " . __LINE__);
67 }
68
69 /**
70 * Test offset param.
71 */
72 public function testGetOptionValueOffSet() {
73
74 $result = $this->callAPISuccess('option_value', 'get', [
75 'option_group_id' => 1,
76 'value' => '1',
77 ]);
78 $result2 = $this->callAPISuccess('option_value', 'get', [
79 'option_group_id' => 1,
80 'value' => '1',
81 'options' => ['offset' => 1],
82 ]);
83 $this->assertGreaterThan($result2['count'], $result['count']);
84 }
85
86 /**
87 * Test offset param.
88 */
89 public function testGetSingleValueOptionValueSort() {
90 $description = "Demonstrates use of Sort param (available in many api functions). Also, getsingle.";
91 $subfile = 'SortOption';
92 $result = $this->callAPISuccess('option_value', 'getsingle', [
93 'option_group_id' => 1,
94 'options' => [
95 'sort' => 'label ASC',
96 'limit' => 1,
97 ],
98 ]);
99 $params = [
100 'option_group_id' => 1,
101 'options' => [
102 'sort' => 'label DESC',
103 'limit' => 1,
104 ],
105 ];
106 $result2 = $this->callAPIAndDocument('option_value', 'getsingle', $params, __FUNCTION__, __FILE__, $description, $subfile);
107 $this->assertGreaterThan($result['label'], $result2['label']);
108 }
109
110 /**
111 * Try to emulate a pagination: fetch the first page of 10 options, then fetch the second page with an offset of 9 (instead of 10) and check the start of the second page is the end of the 1st one.
112 */
113 public function testGetValueOptionPagination() {
114 $pageSize = 10;
115 $page1 = $this->callAPISuccess('option_value', 'get', ['options' => ['limit' => $pageSize]]);
116 $page2 = $this->callAPISuccess('option_value', 'get', [
117 'options' => [
118 'limit' => $pageSize,
119 // if you use it for pagination, option.offset=pageSize*pageNumber
120 'offset' => $pageSize - 1,
121 ],
122 ]);
123 $this->assertEquals($pageSize, $page1['count'], "Check only 10 retrieved in the 1st page " . __LINE__);
124 $this->assertEquals($pageSize, $page2['count'], "Check only 10 retrieved in the 2nd page " . __LINE__);
125
126 $last = array_pop($page1['values']);
127 $first = array_shift($page2['values']);
128
129 $this->assertEquals($first, $last, "the first item of the second page should be the last of the 1st page" . __LINE__);
130 }
131
132 public function testGetOptionGroup() {
133 $params = ['option_group_id' => 1];
134 $result = $this->callAPIAndDocument('option_value', 'get', $params, __FUNCTION__, __FILE__);
135 $this->assertGreaterThan(1, $result['count']);
136 }
137
138 /**
139 * Test that using option_group_name returns more than 1 & less than all
140 */
141 public function testGetOptionGroupByName() {
142 $activityTypesParams = ['option_group_name' => 'activity_type', 'option.limit' => 100];
143 $params = ['option.limit' => 100];
144 $activityTypes = $this->callAPISuccess('option_value', 'get', $activityTypesParams);
145 $result = $this->callAPISuccess('option_value', 'get', $params);
146 $this->assertGreaterThan(1, $activityTypes['count']);
147 $this->assertGreaterThan($activityTypes['count'], $result['count']);
148 }
149
150 public function testGetOptionDoesNotExist() {
151 $result = $this->callAPISuccess('option_value', 'get', ['label' => 'FSIGUBSFGOMUUBSFGMOOUUBSFGMOOBUFSGMOOIIB']);
152 $this->assertEquals(0, $result['count']);
153 }
154
155 /**
156 * Check that domain_id is honoured.
157 */
158 public function testCreateOptionSpecifyDomain() {
159 $result = $this->callAPISuccess('option_group', 'get', [
160 'name' => 'from_email_address',
161 'sequential' => 1,
162 'api.option_value.create' => ['domain_id' => 2, 'name' => 'my@y.com', 'value' => '10'],
163 ]);
164
165 $optionValueId = $result['values'][0]['api.option_value.create']['id'];
166 $domain_id = $this->callAPISuccess('option_value', 'getvalue', [
167 'id' => $optionValueId,
168 'return' => 'domain_id',
169 ]);
170 $this->assertEquals(2, $domain_id);
171 $this->callAPISuccess('option_value', 'delete', ['id' => $optionValueId]);
172 }
173
174 /**
175 * Check that component_id is honoured.
176 */
177 public function testCreateOptionSpecifyComponentID() {
178 $result = $this->callAPISuccess('option_group', 'get', [
179 'name' => 'from_email_address',
180 'sequential' => 1,
181 'api.option_value.create' => ['component_id' => 2, 'name' => 'my@y.com'],
182 ]);
183 $this->assertAPISuccess($result);
184 $optionValueId = $result['values'][0]['api.option_value.create']['id'];
185 $component_id = $this->callAPISuccess('option_value', 'getvalue', [
186 'id' => $optionValueId,
187 'return' => 'component_id',
188 ]);
189 $this->assertEquals(2, $component_id);
190 $this->callAPISuccess('option_value', 'delete', ['id' => $optionValueId]);
191 }
192
193 /**
194 * Check that component string is honoured.
195 */
196 public function testCreateOptionSpecifyComponentString() {
197 $result = $this->callAPISuccess('option_group', 'get', [
198 'name' => 'from_email_address',
199 'sequential' => 1,
200 'api.option_value.create' => [
201 'component_id' => 'CiviContribute',
202 'name' => 'my@y.com',
203 ],
204 ]);
205 $this->assertAPISuccess($result);
206 $optionValueId = $result['values'][0]['api.option_value.create']['id'];
207 $component_id = $this->callAPISuccess('option_value', 'getvalue', [
208 'id' => $optionValueId,
209 'return' => 'component_id',
210 ]);
211 $this->assertEquals(2, $component_id);
212 $this->callAPISuccess('option_value', 'delete', ['id' => $optionValueId]);
213 }
214
215 /**
216 * Check that component is honoured when fetching options.
217 */
218 public function testGetOptionWithComponent() {
219 $components = Civi::settings()->get('enable_components');
220 CRM_Core_BAO_ConfigSetting::enableComponent('CiviContribute');
221 $this->callAPISuccess('option_group', 'get', [
222 'name' => 'gender',
223 'api.option_value.create' => [
224 'component_id' => 'CiviContribute',
225 'name' => 'Contrib',
226 ],
227 ]);
228 // Verify new option is present
229 $genders = $this->callAPISuccess('contact', 'getoptions', [
230 'field' => 'gender_id',
231 'context' => 'create',
232 ]);
233 $this->assertContains('Contrib', $genders['values']);
234
235 // Disable relevant component
236 CRM_Core_BAO_ConfigSetting::disableComponent('CiviContribute');
237 CRM_Core_PseudoConstant::flush();
238 // New option should now be hidden for "create" context
239 $genders = $this->callAPISuccess('contact', 'getoptions', [
240 'field' => 'gender_id',
241 'context' => 'create',
242 ]);
243 $this->assertNotContains('Contrib', $genders['values']);
244 // New option should be visible for "get" context even with component disabled
245 $genders = $this->callAPISuccess('contact', 'getoptions', [
246 'field' => 'gender_id',
247 'context' => 'get',
248 ]);
249 $this->assertContains('Contrib', $genders['values']);
250
251 // Now disable all components and ensure we can still fetch options with no errors
252 CRM_Core_BAO_ConfigSetting::setEnabledComponents([]);
253 CRM_Core_PseudoConstant::flush();
254 // New option should still be hidden for "create" context
255 $genders = $this->callAPISuccess('contact', 'getoptions', [
256 'field' => 'gender_id',
257 'context' => 'create',
258 ]);
259 $this->assertNotContains('Contrib', $genders['values']);
260
261 // Restore original state
262 CRM_Core_BAO_ConfigSetting::setEnabledComponents($components);
263 }
264
265 /**
266 * Check that domain_id is honoured.
267 */
268 public function testCRM12133CreateOptionWeightNoValue() {
269 $optionGroup = $this->callAPISuccess(
270 'option_group', 'get', [
271 'name' => 'gender',
272 'sequential' => 1,
273 ]
274 );
275 $this->assertAPISuccess($optionGroup);
276 $params = [
277 'option_group_id' => $optionGroup['id'],
278 'label' => 'my@y.com',
279 'weight' => 3,
280 ];
281 $optionValue = $this->callAPISuccess('option_value', 'create', $params);
282 $this->assertAPISuccess($optionValue);
283 $params['weight'] = 4;
284 $optionValue2 = $this->callAPISuccess('option_value', 'create', $params);
285 $this->assertAPISuccess($optionValue2);
286 $options = $this->callAPISuccess('option_value', 'get', ['option_group_id' => $optionGroup['id']]);
287 $this->assertNotEquals($options['values'][$optionValue['id']]['value'], $options['values'][$optionValue2['id']]['value']);
288
289 //cleanup
290 $this->callAPISuccess('option_value', 'delete', ['id' => $optionValue['id']]);
291 $this->callAPISuccess('option_value', 'delete', ['id' => $optionValue2['id']]);
292 }
293
294 /**
295 * Check that domain_id is honoured.
296 */
297 public function testCreateOptionNoName() {
298 $optionGroup = $this->callAPISuccess('option_group', 'get', [
299 'name' => 'gender',
300 'sequential' => 1,
301 ]);
302
303 $params = ['option_group_id' => $optionGroup['id'], 'label' => 'my@y.com'];
304 $optionValue = $this->callAPISuccess('option_value', 'create', $params);
305 $this->assertAPISuccess($optionValue);
306 $this->getAndCheck($params, $optionValue['id'], 'option_value');
307 }
308
309 /**
310 * Check that pseudoconstant reflects new value added.
311 */
312 public function testCRM11876CreateOptionPseudoConstantUpdated() {
313 $optionGroupID = $this->callAPISuccess('option_group', 'getvalue', [
314 'name' => 'payment_instrument',
315 'return' => 'id',
316 ]);
317 $newOption = (string) time();
318 $apiResult = $this->callAPISuccess('option_value', 'create', [
319 'option_group_id' => $optionGroupID,
320 'label' => $newOption,
321 ]);
322
323 $fields = $this->callAPISuccess('contribution', 'getoptions', ['field' => 'payment_instrument_id']);
324 $this->assertTrue(in_array($newOption, $fields['values']));
325
326 $this->callAPISuccess('option_value', 'delete', ['id' => $apiResult['id']]);
327
328 $fields = $this->callAPISuccess('contribution', 'getoptions', ['field' => 'payment_instrument_id']);
329 $this->assertFalse(in_array($newOption, $fields['values']));
330 }
331
332 /**
333 * Update option value with 'id' parameter and the value to update
334 * and not passing option group id
335 */
336 public function testUpdateOptionValueNoGroupId() {
337 // create a option group
338 $og = $this->callAPISuccess('option_group', 'create', ['name' => 'our test Option Group', 'is_active' => 1]);
339 // create a option value
340 $ov = $this->callAPISuccess('option_value', 'create',
341 ['option_group_id' => $og['id'], 'label' => 'test option value']
342 );
343 // update option value without 'option_group_id'
344 $res = $this->callAPISuccess('option_value', 'create', ['id' => $ov['id'], 'is_active' => 0]);
345 $val = $this->callAPISuccess('option_value', 'getvalue', [
346 'id' => $ov['id'],
347 'return' => 'is_active',
348 ]);
349 $this->assertEquals($val, 0, "update with no group id is not proper" . __LINE__);
350 }
351
352 /**
353 * Update option value with 'id' parameter and the value to update
354 * and as well as option group id
355 */
356 public function testUpdateOptionValueWithGroupId() {
357 // create a option group
358 $og = $this->callAPISuccess('option_group', 'create', [
359 'name' => 'our test Option Group for with group id',
360 'is_active' => 1,
361 ]);
362 // create a option value
363 $ov = $this->callAPISuccess('option_value', 'create',
364 ['option_group_id' => $og['id'], 'label' => 'test option value']
365 );
366 // update option value without 'option_group_id'
367 $this->callAPISuccess('option_value', 'create', [
368 'id' => $ov['id'],
369 'option_group_id' => $og['id'],
370 'is_active' => 0,
371 ]);
372 $val = $this->callAPISuccess('option_value', 'getvalue', [
373 'id' => $ov['id'],
374 'return' => 'is_active',
375 ]);
376 $this->assertEquals($val, 0, "update with group id is not proper " . __LINE__);
377 }
378
379 /**
380 * CRM-19346 Ensure that Option Values cannot share same value in the same option value group
381 */
382 public function testCreateOptionValueWithSameValue() {
383 $og = $this->callAPISuccess('option_group', 'create', [
384 'name' => 'our test Option Group for with group id',
385 'is_active' => 1,
386 ]);
387 // create a option value
388 $ov = $this->callAPISuccess('option_value', 'create',
389 ['option_group_id' => $og['id'], 'label' => 'test option value']
390 );
391 // update option value without 'option_group_id'
392 $this->callAPIFailure('option_value', 'create',
393 ['option_group_id' => $og['id'], 'label' => 'Test 2nd option value', 'value' => $ov['values'][$ov['id']]['value']]
394 );
395 }
396
397 /**
398 * CRM-21737 Ensure that language Option Values CAN share same value.
399 */
400 public function testCreateOptionValueWithSameValueLanguagesException() {
401 $this->callAPISuccess('option_value', 'create',
402 ['option_group_id' => 'languages', 'label' => 'Quasi English', 'name' => 'en_Qu', 'value' => 'en']
403 );
404 $this->callAPISuccess('option_value', 'create',
405 ['option_group_id' => 'languages', 'label' => 'Semi English', 'name' => 'en_Se', 'value' => 'en']
406 );
407
408 }
409
410 public function testCreateOptionValueWithSameValueDiffOptionGroup() {
411 $og = $this->callAPISuccess('option_group', 'create', [
412 'name' => 'our test Option Group for with group id',
413 'is_active' => 1,
414 ]);
415 // create a option value
416 $ov = $this->callAPISuccess('option_value', 'create',
417 ['option_group_id' => $og['id'], 'label' => 'test option value']
418 );
419 $og2 = $this->callAPISuccess('option_group', 'create', [
420 'name' => 'our test Option Group for with group id 2',
421 'is_active' => 1,
422 ]);
423 // update option value without 'option_group_id'
424 $ov2 = $this->callAPISuccess('option_value', 'create',
425 ['option_group_id' => $og2['id'], 'label' => 'Test 2nd option value', 'value' => $ov['values'][$ov['id']]['value']]
426 );
427 }
428
429 /**
430 * Test to create and update payment method with financial account.
431 */
432 public function testCreateUpdateOptionValueForPaymentInstrument() {
433 $assetFinancialAccountId = $this->callAPISuccessGetValue('FinancialAccount', [
434 'return' => "id",
435 'financial_account_type_id' => "Asset",
436 'options' => ['limit' => 1],
437 ]);
438 // create new payment method with financial account
439 $ov = $this->callAPISuccess('OptionValue', 'create', [
440 'financial_account_id' => $assetFinancialAccountId,
441 'option_group_id' => "payment_instrument",
442 'label' => "Dummy Payment Method",
443 ]);
444
445 //check if relationship is created between Payment method and Financial Account
446 $this->checkPaymentMethodFinancialAccountRelationship($ov['id'], $assetFinancialAccountId);
447
448 // update payment method to have different non-asset financial Account
449 $nonAssetFinancialAccountId = $this->callAPISuccessGetValue('FinancialAccount', [
450 'return' => "id",
451 'financial_account_type_id' => ['NOT IN' => ["Asset"]],
452 'options' => ['limit' => 1],
453 ]);
454 try {
455 $result = $this->callAPISuccess('OptionValue', 'create', [
456 'financial_account_id' => $nonAssetFinancialAccountId,
457 'id' => $ov['id'],
458 ]);
459 throw new API_Exception(ts('Should throw error.'));
460 }
461 catch (Exception $e) {
462 try {
463 $assetAccountRelValue = $this->callAPISuccessGetValue('EntityFinancialAccount', [
464 'return' => "account_relationship",
465 'entity_table' => "civicrm_option_value",
466 'entity_id' => $ov['id'],
467 'financial_account_id' => $nonAssetFinancialAccountId,
468 ]);
469 throw new API_Exception(ts('Should throw error.'));
470 }
471 catch (Exception $e) {
472 $this->checkPaymentMethodFinancialAccountRelationship($ov['id'], $assetFinancialAccountId);
473 }
474 }
475 // update payment method to have different asset financial Account
476 $assetFinancialAccountId = $this->callAPISuccessGetValue('FinancialAccount', [
477 'return' => "id",
478 'financial_account_type_id' => "Asset",
479 'options' => ['limit' => 1],
480 'id' => ['NOT IN' => [$assetFinancialAccountId]],
481 ]);
482 $result = $this->callAPISuccess('OptionValue', 'create', [
483 'financial_account_id' => $assetFinancialAccountId,
484 'id' => $ov['id'],
485 ]);
486 //check if relationship is updated between Payment method and Financial Account
487 $this->checkPaymentMethodFinancialAccountRelationship($ov['id'], $assetFinancialAccountId);
488 }
489
490 /**
491 * Function to check relationship between FA and Payment method.
492 *
493 * @param int $paymentMethodId
494 * @param int $financialAccountId
495 */
496 protected function checkPaymentMethodFinancialAccountRelationship($paymentMethodId, $financialAccountId) {
497 $assetAccountRelValue = $this->callAPISuccessGetValue('EntityFinancialAccount', [
498 'return' => "account_relationship",
499 'entity_table' => "civicrm_option_value",
500 'entity_id' => $paymentMethodId,
501 'financial_account_id' => $financialAccountId,
502 ]);
503 $checkAssetAccountIs = $this->callAPISuccessGetValue('OptionValue', [
504 'return' => "id",
505 'option_group_id' => "account_relationship",
506 'name' => "Asset Account is",
507 'value' => $assetAccountRelValue,
508 ]);
509 }
510
511 }