dev/core#3063 APIv3 - Fix numeric option matching
[civicrm-core.git] / tests / phpunit / api / v3 / FinancialTypeTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CiviCRM_APIv3
15 */
16 class api_v3_FinancialTypeTest extends CiviUnitTestCase {
17
18 /**
19 * Test Create, Read, Update Financial type with custom field.
20 *
21 * @throws \CRM_Core_Exception
22 */
23 public function testCreateUpdateFinancialTypeCustomField(): void {
24 $this->callAPISuccess('OptionValue', 'create', [
25 'label' => ts('Financial Type'),
26 'name' => 'civicrm_financial_type',
27 'value' => 'FinancialType',
28 'option_group_id' => 'cg_extend_objects',
29 'is_active' => 1,
30 ]);
31 // create custom group and custom field
32 $customFieldIds = $this->CustomGroupMultipleCreateWithFields([
33 'name' => 'Test_Group_Financial_type',
34 'title' => 'Test_Group_Financial_type',
35 'extends' => 'FinancialType',
36 'is_multiple' => FALSE,
37 ]);
38 $financialTypeData = [
39 'Financial Type' . substr(sha1(rand()), 0, 4) => [
40 ['Test-1', 'Test-2', NULL],
41 [NULL, '', 'Test_3'],
42 ],
43 'Financial Type' . substr(sha1(rand()), 0, 4) => [
44 [NULL, NULL, NULL],
45 ['Test_1', NULL, 'Test_3'],
46 ],
47 ];
48 foreach ($financialTypeData as $financialTypeName => $data) {
49 $params = [
50 'name' => $financialTypeName,
51 'is_deductible' => '1',
52 'is_reserved' => '0',
53 'is_active' => '1',
54 ];
55 $customFields = [];
56 foreach ($data[0] as $key => $value) {
57 $customFields['custom_' . $customFieldIds['custom_field_id'][$key]] = $value;
58 }
59
60 // create financial type with custom field
61 $financialType = $this->callAPISuccess('FinancialType', 'create', array_merge($params, $customFields));
62 $this->callAPISuccessGetSingle('FinancialType', ['name' => $financialTypeName]);
63
64 // get financial type to check custom field value
65 $expectedResult = array_filter(array_merge($params, $customFields), function($var) {
66 return (!is_null($var) && $var != '');
67 });
68 $this->callAPISuccessGetSingle('FinancialType', [
69 'id' => $financialType['id'],
70 ], $expectedResult);
71
72 // updated financial type with custom field
73 $updateCustomFields = [];
74 foreach ($data[1] as $key => $value) {
75 $updateCustomFields['custom_' . $customFieldIds['custom_field_id'][$key]] = $value;
76 if (!is_null($value)) {
77 $customFields['custom_' . $customFieldIds['custom_field_id'][$key]] = $value;
78 }
79 }
80 $this->callAPISuccess('FinancialType', 'create', array_merge([
81 'id' => $financialType['id'],
82 ], $updateCustomFields));
83
84 // get financial type to check custom field value
85 $expectedResult = array_filter(array_merge($params, $customFields), function($var) {
86 return (!is_null($var) && $var !== '');
87 });
88 $this->callAPISuccessGetSingle('FinancialType', [
89 'id' => $financialType['id'],
90 ], $expectedResult);
91 $this->callAPISuccess('FinancialType', 'delete', ['id' => $financialType['id']]);
92 }
93 }
94
95 /**
96 * Enforce the creation of an associated financial account when a financial
97 * type is created through the api.
98 * @dataProvider versionThreeAndFour
99 */
100 public function testAssociatedFinancialAccountGetsCreated($apiVersion) {
101 $this->callAPISuccess('FinancialType', 'create', [
102 'version' => $apiVersion,
103 'name' => 'Lottery Tickets',
104 'is_deductible' => FALSE,
105 'is_reserved' => FALSE,
106 'is_active' => TRUE,
107 ]);
108 // There should be an account (as opposed to type) with the same name that gets autocreated.
109 $result = $this->callAPISuccess('FinancialAccount', 'getsingle', [
110 'version' => $apiVersion,
111 'name' => 'Lottery Tickets',
112 ]);
113 $this->assertNotEmpty($result['id'], 'Financial account with same name as type did not get created.');
114 $this->assertEquals('INC', $result['account_type_code'], 'Financial account created is not an income account.');
115 }
116
117 public function testMatchFinancialTypeOptions() {
118 // Just a string name, should be simple to match on
119 $nonNumericOption = $this->callAPISuccess('FinancialType', 'create', [
120 'name' => 'StringName',
121 ])['id'];
122 // A numeric name, but a number that won't match any existing id
123 $numericOptionUnique = $this->callAPISuccess('FinancialType', 'create', [
124 'name' => '999',
125 ])['id'];
126 // Here's the kicker, a numeric name that matches an existing id!
127 $numericOptionMatchingExistingId = $this->callAPISuccess('FinancialType', 'create', [
128 'name' => $nonNumericOption,
129 ])['id'];
130 $cid = $this->individualCreate();
131
132 // Create a contribution matching non-numeric name
133 $contributionWithNonNumericType = $this->callAPISuccess('Contribution', 'create', [
134 'financial_type_id' => 'StringName',
135 'total_amount' => 100,
136 'contact_id' => $cid,
137 'sequential' => TRUE,
138 ]);
139 $this->assertEquals($nonNumericOption, $contributionWithNonNumericType['values'][0]['financial_type_id']);
140
141 // Create a contribution matching unique numeric name
142 $contributionWithUniqueNumericType = $this->callAPISuccess('Contribution', 'create', [
143 'financial_type_id' => '999',
144 'total_amount' => 100,
145 'contact_id' => $cid,
146 'sequential' => TRUE,
147 ]);
148 $this->assertEquals($numericOptionUnique, $contributionWithUniqueNumericType['values'][0]['financial_type_id']);
149
150 // Create a contribution matching the id of the non-numeric option, which is ambiguously the name of another option
151 $contributionWithAmbiguousNumericType = $this->callAPISuccess('Contribution', 'create', [
152 'financial_type_id' => "$nonNumericOption",
153 'total_amount' => 100,
154 'contact_id' => $cid,
155 'sequential' => TRUE,
156 ]);
157 // The id should have taken priority over matching by name
158 $this->assertEquals($nonNumericOption, $contributionWithAmbiguousNumericType['values'][0]['financial_type_id']);
159 }
160
161 }