3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 +--------------------------------------------------------------------+
14 * @package CiviCRM_APIv3
16 class api_v3_FinancialTypeTest
extends CiviUnitTestCase
{
19 * Test Create, Read, Update Financial type with custom field.
21 * @throws \CRM_Core_Exception
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',
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,
38 $financialTypeData = [
39 'Financial Type' . substr(sha1(rand()), 0, 4) => [
40 ['Test-1', 'Test-2', NULL],
43 'Financial Type' . substr(sha1(rand()), 0, 4) => [
45 ['Test_1', NULL, 'Test_3'],
48 foreach ($financialTypeData as $financialTypeName => $data) {
50 'name' => $financialTypeName,
51 'is_deductible' => '1',
56 foreach ($data[0] as $key => $value) {
57 $customFields['custom_' . $customFieldIds['custom_field_id'][$key]] = $value;
60 // create financial type with custom field
61 $financialType = $this->callAPISuccess('FinancialType', 'create', array_merge($params, $customFields));
62 $this->callAPISuccessGetSingle('FinancialType', ['name' => $financialTypeName]);
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 != '');
68 $this->callAPISuccessGetSingle('FinancialType', [
69 'id' => $financialType['id'],
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;
80 $this->callAPISuccess('FinancialType', 'create', array_merge([
81 'id' => $financialType['id'],
82 ], $updateCustomFields));
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 !== '');
88 $this->callAPISuccessGetSingle('FinancialType', [
89 'id' => $financialType['id'],
91 $this->callAPISuccess('FinancialType', 'delete', ['id' => $financialType['id']]);
96 * Enforce the creation of an associated financial account when a financial
97 * type is created through the api.
98 * @dataProvider versionThreeAndFour
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,
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',
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.');
117 public function testMatchFinancialTypeOptions() {
118 // Just a string name, should be simple to match on
119 $nonNumericOption = $this->callAPISuccess('FinancialType', 'create', [
120 'name' => 'StringName',
122 // A numeric name, but a number that won't match any existing id
123 $numericOptionUnique = $this->callAPISuccess('FinancialType', 'create', [
126 // Here's the kicker, a numeric name that matches an existing id!
127 $numericOptionMatchingExistingId = $this->callAPISuccess('FinancialType', 'create', [
128 'name' => $nonNumericOption,
130 $cid = $this->individualCreate();
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,
139 $this->assertEquals($nonNumericOption, $contributionWithNonNumericType['values'][0]['financial_type_id']);
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,
148 $this->assertEquals($numericOptionUnique, $contributionWithUniqueNumericType['values'][0]['financial_type_id']);
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,
157 // The id should have taken priority over matching by name
158 $this->assertEquals($nonNumericOption, $contributionWithAmbiguousNumericType['values'][0]['financial_type_id']);