dev/core#2493 Default to not cleaning money for order.create api
[civicrm-core.git] / tests / phpunit / CRM / Contribute / BAO / ContributionTest.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7d61e75f 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 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 |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6e902643 11use Civi\Api4\Activity;
e26d0d27 12use Civi\Api4\PledgePayment;
6a488035 13
4cbe18b8
EM
14/**
15 * Class CRM_Contribute_BAO_ContributionTest
acb109b7 16 * @group headless
4cbe18b8 17 */
6a488035 18class CRM_Contribute_BAO_ContributionTest extends CiviUnitTestCase {
6a488035 19
6b60d32c 20 use CRMTraits_Financial_FinancialACLTrait;
53666099 21 use CRMTraits_Financial_PriceSetTrait;
6b60d32c 22
6a488035 23 /**
2449fe69 24 * Clean up after tests.
25 */
594a9328 26 public function tearDown(): void {
2449fe69 27 $this->quickCleanUpFinancialEntities();
2449fe69 28 parent::tearDown();
29 }
30
31 /**
32 * Test create method (create and update modes).
3fc37a30 33 *
34 * @throws \CRM_Core_Exception
6a488035 35 */
00be9182 36 public function testCreate() {
2449fe69 37 $contactId = $this->individualCreate();
6a488035 38
9099cab3 39 $params = [
6a488035
TO
40 'contact_id' => $contactId,
41 'currency' => 'USD',
92915c55 42 'financial_type_id' => 1,
6a488035
TO
43 'contribution_status_id' => 1,
44 'payment_instrument_id' => 1,
45 'source' => 'STUDENT',
46 'receive_date' => '20080522000000',
47 'receipt_date' => '20080522000000',
48 'non_deductible_amount' => 0.00,
49 'total_amount' => 200.00,
50 'fee_amount' => 5,
51 'net_amount' => 195,
52 'trxn_id' => '22ereerwww444444',
53 'invoice_id' => '86ed39c9e9ee6ef6031621ce0eafe7eb81',
54 'thankyou_date' => '20080522',
d0c97775 55 'sequential' => TRUE,
9099cab3 56 ];
6a488035 57
d0c97775 58 $contribution = $this->callAPISuccess('Contribution', 'create', $params)['values'][0];
6a488035 59
d0c97775 60 $this->assertEquals($params['trxn_id'], $contribution['trxn_id'], 'Check for transaction id creation.');
61 $this->assertEquals($contactId, $contribution['contact_id'], 'Check for contact id creation.');
6a488035
TO
62
63 //update contribution amount
d0c97775 64 $params['id'] = $contribution['id'];
6a488035
TO
65 $params['fee_amount'] = 10;
66 $params['net_amount'] = 190;
67
d0c97775 68 $contribution = $this->callAPISuccess('Contribution', 'create', $params)['values'][0];
6a488035 69
d0c97775 70 $this->assertEquals($params['trxn_id'], $contribution['trxn_id'], 'Check for transcation id .');
71 $this->assertEquals($params['net_amount'], $contribution['net_amount'], 'Check for Amount updation.');
6a488035
TO
72 }
73
74 /**
f43ac8d8 75 * Create() method with custom data.
6a488035 76 */
00be9182 77 public function testCreateWithCustomData() {
2449fe69 78 $contactId = $this->individualCreate();
6a488035
TO
79
80 //create custom data
9099cab3 81 $customGroup = $this->customGroupCreate(['extends' => 'Contribution']);
2449fe69 82 $customGroupID = $customGroup['id'];
83 $customGroup = $customGroup['values'][$customGroupID];
84
9099cab3 85 $fields = [
6a488035
TO
86 'label' => 'testFld',
87 'data_type' => 'String',
88 'html_type' => 'Text',
89 'is_active' => 1,
2449fe69 90 'custom_group_id' => $customGroupID,
9099cab3 91 ];
6a488035
TO
92 $customField = CRM_Core_BAO_CustomField::create($fields);
93
9099cab3 94 $params = [
6a488035
TO
95 'contact_id' => $contactId,
96 'currency' => 'USD',
92915c55 97 'financial_type_id' => 1,
6a488035
TO
98 'contribution_status_id' => 1,
99 'payment_instrument_id' => 1,
100 'source' => 'STUDENT',
101 'receive_date' => '20080522000000',
102 'receipt_date' => '20080522000000',
103 'id' => NULL,
104 'non_deductible_amount' => 0.00,
105 'total_amount' => 200.00,
106 'fee_amount' => 5,
107 'net_amount' => 195,
108 'trxn_id' => '22ereerwww322323',
109 'invoice_id' => '22ed39c9e9ee6ef6031621ce0eafe6da70',
110 'thankyou_date' => '20080522',
d0c97775 111 'skipCleanMoney' => TRUE,
9099cab3 112 ];
6a488035 113
9099cab3
CW
114 $params['custom'] = [
115 $customField->id => [
116 -1 => [
6a488035
TO
117 'value' => 'Test custom value',
118 'type' => 'String',
119 'custom_field_id' => $customField->id,
2449fe69 120 'custom_group_id' => $customGroupID,
121 'table_name' => $customGroup['table_name'],
6a488035
TO
122 'column_name' => $customField->column_name,
123 'file_id' => NULL,
9099cab3
CW
124 ],
125 ],
126 ];
6a488035 127
2449fe69 128 $contribution = CRM_Contribute_BAO_Contribution::create($params);
6a488035
TO
129
130 // Check that the custom field value is saved
9099cab3 131 $customValueParams = [
6a488035
TO
132 'entityID' => $contribution->id,
133 'custom_' . $customField->id => 1,
9099cab3 134 ];
6a488035
TO
135 $values = CRM_Core_BAO_CustomValueTable::getValues($customValueParams);
136 $this->assertEquals('Test custom value', $values['custom_' . $customField->id], 'Check the custom field value');
137
138 $this->assertEquals($params['trxn_id'], $contribution->trxn_id, 'Check for transcation id creation.');
139 $this->assertEquals($contactId, $contribution->contact_id, 'Check for contact id for Conribution.');
6a488035
TO
140 }
141
d73f286e
SL
142 /**
143 * CRM-21026 Test ContributionCount after contribution created with disabled FT
144 */
145 public function testContributionCountDisabledFinancialType() {
146 $contactId = $this->individualCreate();
9099cab3 147 $financialType = [
d73f286e
SL
148 'name' => 'grassvariety1' . substr(sha1(rand()), 0, 7),
149 'is_reserved' => 0,
150 'is_active' => 0,
9099cab3 151 ];
d73f286e 152 $finType = $this->callAPISuccess('financial_type', 'create', $financialType);
9099cab3 153 $params = [
d73f286e
SL
154 'contact_id' => $contactId,
155 'currency' => 'USD',
156 'financial_type_id' => $finType['id'],
157 'contribution_status_id' => 1,
158 'payment_instrument_id' => 1,
159 'source' => 'STUDENT',
160 'receive_date' => '20080522000000',
161 'receipt_date' => '20080522000000',
162 'id' => NULL,
163 'non_deductible_amount' => 0.00,
164 'total_amount' => 200.00,
165 'fee_amount' => 5,
166 'net_amount' => 195,
167 'trxn_id' => '22ereerwww322323',
168 'invoice_id' => '22ed39c9e9ee6ef6031621ce0eafe6da70',
169 'thankyou_date' => '20080522',
9099cab3 170 ];
d0c97775 171 $this->callAPISuccess('Contribution', 'create', $params);
9099cab3 172 $this->callAPISuccess('financial_type', 'create', ['is_active' => 0, 'id' => $finType['id']]);
d73f286e
SL
173 $contributionCount = CRM_Contribute_BAO_Contribution::contributionCount($contactId);
174 $this->assertEquals(1, $contributionCount);
175 }
176
6a488035 177 /**
100fef9d 178 * DeleteContribution() method
6a488035 179 */
00be9182 180 public function testDeleteContribution() {
2449fe69 181 $contactId = $this->individualCreate();
6a488035 182
9099cab3 183 $params = [
6a488035
TO
184 'contact_id' => $contactId,
185 'currency' => 'USD',
92915c55 186 'financial_type_id' => 1,
6a488035
TO
187 'contribution_status_id' => 1,
188 'payment_instrument_id' => 1,
189 'source' => 'STUDENT',
190 'receive_date' => '20080522000000',
191 'receipt_date' => '20080522000000',
192 'id' => NULL,
193 'non_deductible_amount' => 0.00,
194 'total_amount' => 200.00,
195 'fee_amount' => 5,
196 'net_amount' => 195,
197 'trxn_id' => '33ereerwww322323',
198 'invoice_id' => '33ed39c9e9ee6ef6031621ce0eafe6da70',
199 'thankyou_date' => '20080522',
55ee9063 200 'sequential' => TRUE,
9099cab3 201 ];
6a488035 202
55ee9063 203 $contribution = $this->callAPISuccess('Contribution', 'create', $params)['values'][0];
6a488035 204
55ee9063 205 CRM_Contribute_BAO_Contribution::deleteContribution($contribution['id']);
6a488035 206
55ee9063 207 $this->assertDBNull('CRM_Contribute_DAO_Contribution', $contribution['trxn_id'],
6a488035
TO
208 'id', 'trxn_id', 'Database check for deleted Contribution.'
209 );
6a488035
TO
210 }
211
212 /**
2449fe69 213 * Create honor-contact method.
6a488035 214 */
2449fe69 215 public function testCreateAndGetHonorContact() {
6a488035 216 $firstName = 'John_' . substr(sha1(rand()), 0, 7);
92915c55
TO
217 $lastName = 'Smith_' . substr(sha1(rand()), 0, 7);
218 $email = "{$firstName}.{$lastName}@example.com";
6a488035 219
8381af80 220 //Get profile id of name honoree_individual used to create profileContact
221 $honoreeProfileId = NULL;
222 $ufGroupDAO = new CRM_Core_DAO_UFGroup();
223 $ufGroupDAO->name = 'honoree_individual';
224 if ($ufGroupDAO->find(TRUE)) {
225 $honoreeProfileId = $ufGroupDAO->id;
226 }
227
9099cab3 228 $params = [
8381af80 229 'prefix_id' => 3,
230 'first_name' => $firstName,
231 'last_name' => $lastName,
232 'email-1' => $email,
9099cab3
CW
233 ];
234 $softParam = ['soft_credit_type_id' => 1];
8381af80 235
7b4b0b68
SL
236 $null = [];
237 $honoreeContactId = CRM_Contact_BAO_Contact::createProfileContact($params, $null,
92915c55
TO
238 NULL, NULL, $honoreeProfileId
239 );
6a488035 240
8381af80 241 $this->assertDBCompareValue('CRM_Contact_DAO_Contact', $honoreeContactId, 'first_name', 'id', $firstName,
6a488035
TO
242 'Database check for created honor contact record.'
243 );
244 //create contribution on behalf of honary.
245
9099cab3 246 $contactId = $this->individualCreate(['first_name' => 'John', 'last_name' => 'Doe']);
6a488035 247
9099cab3 248 $param = [
6a488035
TO
249 'contact_id' => $contactId,
250 'currency' => 'USD',
92915c55 251 'financial_type_id' => 4,
6a488035
TO
252 'contribution_status_id' => 1,
253 'receive_date' => date('Ymd'),
254 'total_amount' => 66,
d0c97775 255 'sequential' => 1,
9099cab3 256 ];
6a488035 257
d0c97775 258 $contribution = $this->callAPISuccess('Contribution', 'create', $param)['values'][0];
259 $id = $contribution['id'];
2449fe69 260 $softParam['contact_id'] = $honoreeContactId;
8381af80 261 $softParam['contribution_id'] = $id;
d0c97775 262 $softParam['currency'] = $contribution['currency'];
263 $softParam['amount'] = $contribution['total_amount'];
8381af80 264
265 //Create Soft Contribution for honoree contact
266 CRM_Contribute_BAO_ContributionSoft::add($softParam);
267
268 $this->assertDBCompareValue('CRM_Contribute_DAO_ContributionSoft', $id, 'contact_id',
269 'contribution_id', $honoreeContactId, 'Check DB for honor contact of the contribution'
6a488035 270 );
e4f46be0 271 //get honorary information
8381af80 272 $getHonorContact = CRM_Contribute_BAO_Contribution::getHonorContacts($honoreeContactId);
9099cab3
CW
273 $this->assertEquals([
274 $id => [
4ff25fbb 275 'honor_type' => 'In Honor of',
2449fe69 276 'honorId' => $contactId,
277 'display_name' => 'Mr. John Doe II',
4ff25fbb 278 'type' => 'Event Fee',
279 'type_id' => '4',
280 'amount' => '$ 66.00',
281 'source' => NULL,
755ca72c 282 'receive_date' => date('Y-m-d 00:00:00'),
4ff25fbb 283 'contribution_status' => 'Completed',
9099cab3
CW
284 ],
285 ], $getHonorContact);
6a488035 286
8381af80 287 $this->assertDBCompareValue('CRM_Contact_DAO_Contact', $honoreeContactId, 'first_name', 'id', $firstName,
6a488035
TO
288 'Database check for created honor contact record.'
289 );
290
291 //get annual contribution information
292 $annual = CRM_Contribute_BAO_Contribution::annual($contactId);
293
d0c97775 294 $currencySymbol = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_Currency', CRM_Core_Config::singleton()->defaultCurrency, 'symbol', 'name');
6a488035
TO
295 $this->assertDBCompareValue('CRM_Contribute_DAO_Contribution', $id, 'total_amount',
296 'id', ltrim($annual[2], $currencySymbol), 'Check DB for total amount of the contribution'
297 );
6a488035
TO
298 }
299
6b60d32c 300 /**
301 * Test that financial type data is not added to the annual query if acls not enabled.
302 */
303 public function testAnnualQueryWithFinancialACLsEnabled() {
304 $this->enableFinancialACLs();
305 $this->createLoggedInUserWithFinancialACL();
306 $permittedFinancialType = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'financial_type_id', 'Donation');
307 $sql = CRM_Contribute_BAO_Contribution::getAnnualQuery([1, 2, 3]);
308 $this->assertContains('SUM(total_amount) as amount,', $sql);
309 $this->assertContains('WHERE b.contact_id IN (1,2,3)', $sql);
310 $this->assertContains('b.financial_type_id IN (' . $permittedFinancialType . ')', $sql);
311
312 // Run it to make sure it's not bad sql.
313 CRM_Core_DAO::executeQuery($sql);
314 $this->disableFinancialACLs();
315 }
316
53666099 317 /**
318 * Test the annual query returns a correct result when multiple line items are present.
319 */
320 public function testAnnualWithMultipleLineItems() {
321 $contactID = $this->createLoggedInUserWithFinancialACL();
322 $this->createContributionWithTwoLineItemsAgainstPriceSet([
39b959db
SL
323 'contact_id' => $contactID,
324 ]
53666099 325 );
326 $this->enableFinancialACLs();
327 $sql = CRM_Contribute_BAO_Contribution::getAnnualQuery([$contactID]);
328 $result = CRM_Core_DAO::executeQuery($sql);
329 $result->fetch();
330 $this->assertEquals(300, $result->amount);
331 $this->assertEquals(1, $result->count);
332 $this->disableFinancialACLs();
333 }
334
6b60d32c 335 /**
336 * Test that financial type data is not added to the annual query if acls not enabled.
337 */
338 public function testAnnualQueryWithFinancialACLsDisabled() {
339 $sql = CRM_Contribute_BAO_Contribution::getAnnualQuery([1, 2, 3]);
340 $this->assertContains('SUM(total_amount) as amount,', $sql);
341 $this->assertContains('WHERE b.contact_id IN (1,2,3)', $sql);
342 $this->assertNotContains('b.financial_type_id', $sql);
343 //$this->assertNotContains('line_item', $sql);
344 // Run it to make sure it's not bad sql.
345 CRM_Core_DAO::executeQuery($sql);
346 }
347
c77f8667 348 /**
349 * Test that financial type data is not added to the annual query if acls not enabled.
350 */
351 public function testAnnualQueryWithFinancialHook() {
9099cab3 352 $this->hookClass->setHook('civicrm_selectWhereClause', [$this, 'aclIdNoZero']);
c77f8667 353 $sql = CRM_Contribute_BAO_Contribution::getAnnualQuery([1, 2, 3]);
354 $this->assertContains('SUM(total_amount) as amount,', $sql);
355 $this->assertContains('WHERE b.contact_id IN (1,2,3)', $sql);
356 $this->assertContains('b.id NOT IN (0)', $sql);
357 $this->assertNotContains('b.financial_type_id', $sql);
358 CRM_Core_DAO::executeQuery($sql);
359 }
360
361 /**
362 * Add ACL denying values LIKE '0'.
363 *
364 * @param string $entity
365 * @param string $clauses
366 */
367 public function aclIdNoZero($entity, &$clauses) {
368 if ($entity != 'Contribution') {
369 return;
370 }
371 $clauses['id'] = "NOT IN (0)";
372 }
373
6a488035 374 /**
eceb18cc 375 * Display sort name during.
b581842f 376 * Update multiple contributions
6a488035
TO
377 * sortName();
378 */
00be9182 379 public function testsortName() {
9099cab3 380 $params = [
6a488035
TO
381 'first_name' => 'Shane',
382 'last_name' => 'Whatson',
383 'contact_type' => 'Individual',
9099cab3 384 ];
6a488035
TO
385
386 $contact = CRM_Contact_BAO_Contact::add($params);
387
388 //Now check $contact is object of contact DAO..
389 $this->assertInstanceOf('CRM_Contact_DAO_Contact', $contact, 'Check for created object');
390
391 $contactId = $contact->id;
9099cab3 392 $param = [
6a488035
TO
393 'contact_id' => $contactId,
394 'currency' => 'USD',
92915c55 395 'financial_type_id' => 1,
6a488035
TO
396 'contribution_status_id' => 1,
397 'payment_instrument_id' => 1,
398 'source' => 'STUDENT',
399 'receive_date' => '20080522000000',
400 'receipt_date' => '20080522000000',
401 'id' => NULL,
402 'non_deductible_amount' => 0.00,
403 'total_amount' => 300.00,
404 'fee_amount' => 5,
405 'net_amount' => 295,
406 'trxn_id' => '22ereerwww323',
407 'invoice_id' => '22ed39c9e9ee621ce0eafe6da70',
408 'thankyou_date' => '20080522',
d0c97775 409 'sequential' => TRUE,
9099cab3 410 ];
6a488035 411
d0c97775 412 $contribution = $this->callAPISuccess('Contribution', 'create', $param)['values'][0];
6a488035 413
d0c97775 414 $this->assertEquals($param['trxn_id'], $contribution['trxn_id'], 'Check for transcation id creation.');
415 $this->assertEquals($contactId, $contribution['contact_id'], 'Check for contact id creation.');
6a488035 416
b581842f 417 //display sort name during Update multiple contributions
d0c97775 418 $sortName = CRM_Contribute_BAO_Contribution::sortName($contribution['id']);
6a488035
TO
419
420 $this->assertEquals('Whatson, Shane', $sortName, 'Check for sort name.');
6a488035
TO
421 }
422
423 /**
eceb18cc 424 * Add premium during online Contribution.
6a488035
TO
425 *
426 * AddPremium();
427 */
00be9182 428 public function testAddPremium() {
2449fe69 429 $contactId = $this->individualCreate();
6a488035 430
9099cab3 431 $params = [
6a488035
TO
432 'name' => 'TEST Premium',
433 'sku' => 111,
434 'imageOption' => 'noImage',
435 'MAX_FILE_SIZE' => 2097152,
436 'price' => 100.00,
437 'cost' => 90.00,
438 'min_contribution' => 100,
439 'is_active' => 1,
9099cab3 440 ];
32f27499 441 $premium = CRM_Contribute_BAO_Product::create($params);
6a488035
TO
442
443 $this->assertEquals('TEST Premium', $premium->name, 'Check for premium name.');
444
9099cab3 445 $contributionParams = [
6a488035
TO
446 'contact_id' => $contactId,
447 'currency' => 'USD',
92915c55 448 'financial_type_id' => 1,
6a488035
TO
449 'contribution_status_id' => 1,
450 'payment_instrument_id' => 1,
451 'source' => 'STUDENT',
452 'receive_date' => '20080522000000',
453 'receipt_date' => '20080522000000',
454 'id' => NULL,
455 'non_deductible_amount' => 0.00,
456 'total_amount' => 300.00,
457 'fee_amount' => 5,
458 'net_amount' => 295,
459 'trxn_id' => '33erdfrwvw434',
460 'invoice_id' => '98ed34f7u9hh672ce0eafe8fb92',
461 'thankyou_date' => '20080522',
d0c97775 462 'sequential' => TRUE,
9099cab3 463 ];
a275d4b6 464 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams)['values'][0];
6a488035 465
a275d4b6 466 $this->assertEquals($contributionParams['trxn_id'], $contribution['trxn_id'], 'Check for transcation id creation.');
d0c97775 467 $this->assertEquals($contactId, $contribution['contact_id'], 'Check for contact id creation.');
6a488035
TO
468
469 //parameter for adding premium to contribution
9099cab3 470 $data = [
6a488035 471 'product_id' => $premium->id,
d0c97775 472 'contribution_id' => $contribution['id'],
6a488035
TO
473 'product_option' => NULL,
474 'quantity' => 1,
9099cab3 475 ];
6a488035
TO
476 $contributionProduct = CRM_Contribute_BAO_Contribution::addPremium($data);
477 $this->assertEquals($contributionProduct->product_id, $premium->id, 'Check for Product id .');
478
479 //Delete Product
37828d4f 480 CRM_Contribute_BAO_Product::del($premium->id);
6a488035
TO
481 $this->assertDBNull('CRM_Contribute_DAO_Product', $premium->name,
482 'id', 'name', 'Database check for deleted Product.'
483 );
6a488035
TO
484 }
485
486 /**
fe482240 487 * Check duplicate contribution id.
6a488035
TO
488 * during the contribution import
489 * checkDuplicateIds();
490 */
00be9182 491 public function testcheckDuplicateIds() {
2449fe69 492 $contactId = $this->individualCreate();
6a488035 493
9099cab3 494 $param = [
6a488035
TO
495 'contact_id' => $contactId,
496 'currency' => 'USD',
92915c55 497 'financial_type_id' => 1,
6a488035
TO
498 'contribution_status_id' => 1,
499 'payment_instrument_id' => 1,
500 'source' => 'STUDENT',
501 'receive_date' => '20080522000000',
502 'receipt_date' => '20080522000000',
503 'id' => NULL,
504 'non_deductible_amount' => 0.00,
505 'total_amount' => 300.00,
506 'fee_amount' => 5,
507 'net_amount' => 295,
508 'trxn_id' => '76ereeswww835',
509 'invoice_id' => '93ed39a9e9hd621bs0eafe3da82',
510 'thankyou_date' => '20080522',
d0c97775 511 'sequential' => TRUE,
9099cab3 512 ];
6a488035 513
d0c97775 514 $contribution = $this->callAPISuccess('Contribution', 'create', $param)['values'][0];
6a488035 515
d0c97775 516 $this->assertEquals($param['trxn_id'], $contribution['trxn_id'], 'Check for transcation id creation.');
517 $this->assertEquals($contactId, $contribution['contact_id'], 'Check for contact id creation.');
9099cab3 518 $data = [
d0c97775 519 'id' => $contribution['id'],
520 'trxn_id' => $contribution['trxn_id'],
521 'invoice_id' => $contribution['invoice_id'],
9099cab3 522 ];
6a488035 523 $contributionID = CRM_Contribute_BAO_Contribution::checkDuplicateIds($data);
d0c97775 524 $this->assertEquals($contributionID, $contribution['id'], 'Check for duplicate transcation id .');
6a488035 525 }
96025800 526
b04e4b11
PN
527 /**
528 * Create() method (create and update modes).
529 */
530 public function testIsPaymentFlag() {
2449fe69 531 $contactId = $this->individualCreate();
b04e4b11 532
d0c97775 533 $params = [
b04e4b11
PN
534 'contact_id' => $contactId,
535 'currency' => 'USD',
536 'financial_type_id' => 1,
537 'contribution_status_id' => 1,
538 'payment_instrument_id' => 1,
539 'source' => 'STUDENT',
540 'receive_date' => '20080522000000',
541 'receipt_date' => '20080522000000',
542 'non_deductible_amount' => 0.00,
543 'total_amount' => 200.00,
544 'fee_amount' => 5,
545 'net_amount' => 195,
546 'trxn_id' => '22ereerwww4444xx',
547 'invoice_id' => '86ed39c9e9ee6ef6541621ce0eafe7eb81',
548 'thankyou_date' => '20080522',
d0c97775 549 'sequential' => TRUE,
550 ];
551 $contribution = $this->callAPISuccess('Contribution', 'create', $params)['values'][0];
b04e4b11 552
d0c97775 553 $this->assertEquals($params['trxn_id'], $contribution['trxn_id'], 'Check for transcation id creation.');
554 $this->assertEquals($contactId, $contribution['contact_id'], 'Check for contact id creation.');
b04e4b11 555
9099cab3 556 $trxnArray = [
b04e4b11
PN
557 'trxn_id' => $params['trxn_id'],
558 'is_payment' => 1,
9099cab3
CW
559 ];
560 $defaults = [];
b04e4b11 561 $financialTrxn = CRM_Core_BAO_FinancialTrxn::retrieve($trxnArray, $defaults);
4ba3c75f 562 $this->assertEquals(1, $financialTrxn->N, 'Mismatch count for is payment flag.');
b04e4b11 563 //update contribution amount
d0c97775 564 $params['id'] = $contribution['id'];
b04e4b11 565 $params['total_amount'] = 150;
d0c97775 566 $contribution = $this->callAPISuccess('Contribution', 'create', $params)['values'][0];
b04e4b11 567
d0c97775 568 $this->assertEquals($params['trxn_id'], $contribution['trxn_id'], 'Check for transcation id .');
569 $this->assertEquals($params['total_amount'], $contribution['total_amount'], 'Check for Amount updation.');
9099cab3 570 $trxnArray = [
b04e4b11
PN
571 'trxn_id' => $params['trxn_id'],
572 'is_payment' => 1,
9099cab3
CW
573 ];
574 $defaults = [];
b04e4b11 575 $financialTrxn = CRM_Core_BAO_FinancialTrxn::retrieve($trxnArray, $defaults);
4ba3c75f 576 $this->assertEquals(2, $financialTrxn->N, 'Mismatch count for is payment flag.');
b04e4b11
PN
577 $trxnArray['is_payment'] = 0;
578 $financialTrxn = CRM_Core_BAO_FinancialTrxn::retrieve($trxnArray, $defaults);
4ba3c75f 579 $this->assertEquals(1, $financialTrxn->N, 'Mismatch count for is payment flag.');
b04e4b11
PN
580 }
581
a387acc9
PN
582 /**
583 * Create() method (create and update modes).
584 */
585 public function testIsPaymentFlagForPending() {
2449fe69 586 $contactId = $this->individualCreate();
a387acc9 587
9099cab3 588 $params = [
a387acc9
PN
589 'contact_id' => $contactId,
590 'currency' => 'USD',
591 'financial_type_id' => 1,
592 'contribution_status_id' => 2,
593 'payment_instrument_id' => 1,
594 'source' => 'STUDENT',
595 'is_pay_later' => 1,
596 'receive_date' => '20080522000000',
597 'receipt_date' => '20080522000000',
598 'non_deductible_amount' => 0.00,
599 'total_amount' => 200.00,
600 'fee_amount' => 5,
601 'net_amount' => 195,
602 'trxn_id' => '22ereerwww4444yy',
603 'invoice_id' => '86ed39c9e9yy6ef6541621ce0eafe7eb81',
604 'thankyou_date' => '20080522',
d0c97775 605 'sequential' => TRUE,
9099cab3 606 ];
a387acc9 607
d0c97775 608 $contribution = $this->callAPISuccess('Contribution', 'create', $params)['values'][0];
a387acc9 609
d0c97775 610 $this->assertEquals($params['trxn_id'], $contribution['trxn_id'], 'Check for transaction id creation.');
611 $this->assertEquals($contactId, $contribution['contact_id'], 'Check for contact id creation.');
a387acc9 612
9099cab3 613 $trxnArray = [
a387acc9
PN
614 'trxn_id' => $params['trxn_id'],
615 'is_payment' => 0,
9099cab3
CW
616 ];
617 $defaults = [];
a387acc9
PN
618 $financialTrxn = CRM_Core_BAO_FinancialTrxn::retrieve($trxnArray, $defaults);
619 $this->assertEquals(2, $financialTrxn->N, 'Mismatch count for is payment flag.');
620 $trxnArray['is_payment'] = 1;
621 $financialTrxn = CRM_Core_BAO_FinancialTrxn::retrieve($trxnArray, $defaults);
622 $this->assertEquals(NULL, $financialTrxn, 'Mismatch count for is payment flag.');
623 //update contribution amount
d0c97775 624 $params['id'] = $contribution['id'];
a387acc9
PN
625 $params['contribution_status_id'] = 1;
626
d0c97775 627 $contribution = $this->callAPISuccess('Contribution', 'create', $params)['values'][0];
a387acc9 628
d0c97775 629 $this->assertEquals($params['trxn_id'], $contribution['trxn_id'], 'Check for transcation id .');
630 $this->assertEquals($params['contribution_status_id'], $contribution['contribution_status_id'], 'Check for status updation.');
9099cab3 631 $trxnArray = [
a387acc9
PN
632 'trxn_id' => $params['trxn_id'],
633 'is_payment' => 1,
9099cab3
CW
634 ];
635 $defaults = [];
a387acc9
PN
636 $financialTrxn = CRM_Core_BAO_FinancialTrxn::retrieve($trxnArray, $defaults);
637 $this->assertEquals(1, $financialTrxn->N, 'Mismatch count for is payment flag.');
638 $trxnArray['is_payment'] = 0;
639 $financialTrxn = CRM_Core_BAO_FinancialTrxn::retrieve($trxnArray, $defaults);
640 $this->assertEquals(2, $financialTrxn->N, 'Mismatch count for is payment flag.');
a387acc9
PN
641 }
642
0a5651eb
PN
643 /**
644 * checks db values for financial item
645 */
624195c8 646 public function checkItemValues($contribution) {
876b8ab0 647 $toFinancialAccount = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount(4, 'Accounts Receivable Account is');
2449fe69 648 $query = "SELECT eft1.entity_id, ft.total_amount, eft1.amount FROM civicrm_financial_trxn ft INNER JOIN civicrm_entity_financial_trxn eft ON (eft.financial_trxn_id = ft.id AND eft.entity_table = 'civicrm_contribution')
eec619df
PN
649INNER JOIN civicrm_entity_financial_trxn eft1 ON (eft1.financial_trxn_id = eft.financial_trxn_id AND eft1.entity_table = 'civicrm_financial_item')
650WHERE eft.entity_id = %1 AND ft.to_financial_account_id <> %2";
651
9099cab3
CW
652 $queryParams[1] = [$contribution->id, 'Integer'];
653 $queryParams[2] = [$toFinancialAccount, 'Integer'];
eec619df
PN
654
655 $dao = CRM_Core_DAO::executeQuery($query, $queryParams);
9099cab3 656 $amounts = [100.00, 50.00];
eec619df
PN
657 while ($dao->fetch()) {
658 $this->assertEquals(150.00, $dao->total_amount, 'Mismatch of total amount paid.');
19084b68 659 $this->assertEquals($dao->amount, array_pop($amounts), 'Mismatch of amount proportionally assigned to financial item');
eec619df 660 }
eec619df
PN
661 }
662
0a5651eb
PN
663 /**
664 * assignProportionalLineItems() method (add and edit modes of participant)
3fc37a30 665 *
666 * @throws \CRM_Core_Exception
667 * @throws \CiviCRM_API3_Exception
0a5651eb
PN
668 */
669 public function testAssignProportionalLineItems() {
3fc37a30 670 $contribution = $this->addParticipantWithContribution();
671 // Delete existing financial_trxns. This is because we are testing a code flow we
672 // want to deprecate & remove & the test relies on bad data asa starting point.
673 // End goal is the Order.create->Payment.create flow.
674 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_entity_financial_trxn WHERE entity_table = "civicrm_financial_item"');
9099cab3 675 $params = [
0a5651eb
PN
676 'contribution_id' => $contribution->id,
677 'total_amount' => 150.00,
9099cab3 678 ];
0a5651eb
PN
679 $trxn = new CRM_Financial_DAO_FinancialTrxn();
680 $trxn->orderBy('id DESC');
681 $trxn->find(TRUE);
8de1ade9 682 CRM_Contribute_BAO_Contribution::assignProportionalLineItems($params, $trxn->id, $contribution->total_amount);
0a5651eb
PN
683 $this->checkItemValues($contribution);
684 }
685
eec619df
PN
686 /**
687 * Add participant with contribution
688 *
57a7aa8a 689 * @return CRM_Contribute_BAO_Contribution
3fc37a30 690 *
691 * @throws \CRM_Core_Exception
692 * @throws \CiviCRM_API3_Exception
eec619df 693 */
78c99516 694 public function addParticipantWithContribution() {
eec619df 695 // creating price set, price field
2449fe69 696 $this->_contactId = $this->individualCreate();
3fc37a30 697 $event = $this->eventCreatePaid([]);
2449fe69 698 $this->_eventId = $event['id'];
57a7aa8a 699 $priceSetID = $this->ids['PriceSet']['event'];
9099cab3 700 $paramsField = [
eec619df
PN
701 'label' => 'Price Field',
702 'name' => CRM_Utils_String::titleToVar('Price Field'),
703 'html_type' => 'CheckBox',
9099cab3
CW
704 'option_label' => ['1' => 'Price Field 1', '2' => 'Price Field 2'],
705 'option_value' => ['1' => 100, '2' => 200],
706 'option_name' => ['1' => 'Price Field 1', '2' => 'Price Field 2'],
707 'option_weight' => ['1' => 1, '2' => 2],
708 'option_amount' => ['1' => 100, '2' => 200],
eec619df
PN
709 'is_display_amounts' => 1,
710 'weight' => 1,
711 'options_per_line' => 1,
9099cab3 712 'is_active' => ['1' => 1, '2' => 1],
57a7aa8a 713 'price_set_id' => $priceSetID,
eec619df
PN
714 'is_enter_qty' => 1,
715 'financial_type_id' => CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', 'Event Fee', 'id', 'name'),
9099cab3 716 ];
eec619df 717 $priceField = CRM_Price_BAO_PriceField::create($paramsField);
9099cab3 718 $eventParams = [
eec619df
PN
719 'id' => $this->_eventId,
720 'financial_type_id' => 4,
721 'is_monetary' => 1,
9099cab3 722 ];
eec619df 723 CRM_Event_BAO_Event::create($eventParams);
57a7aa8a 724 CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $priceSetID);
e4ba8498 725
9099cab3
CW
726 $priceFields = $this->callAPISuccess('PriceFieldValue', 'get', ['price_field_id' => $priceField->id]);
727 $participantParams = [
eec619df
PN
728 'financial_type_id' => 4,
729 'event_id' => $this->_eventId,
730 'role_id' => 1,
731 'status_id' => 14,
732 'fee_currency' => 'USD',
733 'contact_id' => $this->_contactId,
9099cab3 734 ];
eec619df 735 $participant = CRM_Event_BAO_Participant::add($participantParams);
9099cab3 736 $contributionParams = [
3fc37a30 737 'total_amount' => 300,
eec619df
PN
738 'currency' => 'USD',
739 'contact_id' => $this->_contactId,
740 'financial_type_id' => 4,
3fc37a30 741 'contribution_status_id' => 'Pending',
eec619df
PN
742 'contribution_mode' => 'participant',
743 'participant_id' => $participant->id,
d0c97775 744 'sequential' => TRUE,
3fc37a30 745 'api.Payment.create' => ['total_amount' => 150],
9099cab3 746 ];
eec619df
PN
747
748 foreach ($priceFields['values'] as $key => $priceField) {
9099cab3 749 $lineItems[1][$key] = [
eec619df
PN
750 'price_field_id' => $priceField['price_field_id'],
751 'price_field_value_id' => $priceField['id'],
752 'label' => $priceField['label'],
753 'field_title' => $priceField['label'],
754 'qty' => 1,
755 'unit_price' => $priceField['amount'],
756 'line_total' => $priceField['amount'],
757 'financial_type_id' => $priceField['financial_type_id'],
9099cab3 758 ];
eec619df
PN
759 }
760 $contributionParams['line_item'] = $lineItems;
d0c97775 761 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams)['values'][0];
eec619df 762
9099cab3 763 $paymentParticipant = [
eec619df 764 'participant_id' => $participant->id,
d0c97775 765 'contribution_id' => $contribution['id'],
9099cab3 766 ];
a5750507 767 CRM_Event_BAO_ParticipantPayment::create($paymentParticipant);
eec619df 768
d0c97775 769 $contributionObject = new CRM_Contribute_BAO_Contribution();
770 $contributionObject->id = $contribution['id'];
771 $contributionObject->find(TRUE);
772
3fc37a30 773 return $contributionObject;
eec619df
PN
774 }
775
5c8b902b 776 /**
a4a31ffe 777 * checkLineItems() check if total amount matches the sum of line total
5c8b902b
PN
778 */
779 public function testcheckLineItems() {
9099cab3 780 $params = [
5c8b902b
PN
781 'contact_id' => 202,
782 'receive_date' => '2010-01-20',
783 'total_amount' => 100,
784 'financial_type_id' => 3,
9099cab3
CW
785 'line_items' => [
786 [
787 'line_item' => [
788 [
5c8b902b
PN
789 'entity_table' => 'civicrm_contribution',
790 'price_field_id' => 8,
791 'price_field_value_id' => 16,
792 'label' => 'test 1',
793 'qty' => 1,
794 'unit_price' => 100,
795 'line_total' => 100,
9099cab3
CW
796 ],
797 [
5c8b902b
PN
798 'entity_table' => 'civicrm_contribution',
799 'price_field_id' => 8,
800 'price_field_value_id' => 17,
801 'label' => 'Test 2',
802 'qty' => 1,
803 'unit_price' => 200,
804 'line_total' => 200,
805 'financial_type_id' => 1,
9099cab3
CW
806 ],
807 ],
808 'params' => [],
809 ],
810 ],
811 ];
c16c6ad8 812
af004c04 813 try {
2449fe69 814 CRM_Contribute_BAO_Contribution::checkLineItems($params);
af004c04
PN
815 $this->fail("Missed expected exception");
816 }
c16c6ad8
CR
817 catch (CRM_Contribute_Exception_CheckLineItemsException $e) {
818 $this->assertEquals(
819 CRM_Contribute_Exception_CheckLineItemsException::LINE_ITEM_DIFFERRING_TOTAL_EXCEPTON_MSG,
820 $e->getMessage()
821 );
af004c04 822 }
c16c6ad8 823
5c8b902b
PN
824 $this->assertEquals(3, $params['line_items'][0]['line_item'][0]['financial_type_id']);
825 $params['total_amount'] = 300;
c16c6ad8 826
af004c04 827 CRM_Contribute_BAO_Contribution::checkLineItems($params);
5c8b902b
PN
828 }
829
c16c6ad8
CR
830 /**
831 * Tests CRM_Contribute_BAO_Contribution::checkLineItems() method works with
832 * floating point values.
833 */
834 public function testCheckLineItemsWithFloatingPointValues() {
9099cab3 835 $params = [
c16c6ad8
CR
836 'contact_id' => 202,
837 'receive_date' => date('Y-m-d'),
838 'total_amount' => 16.67,
839 'financial_type_id' => 3,
9099cab3
CW
840 'line_items' => [
841 [
842 'line_item' => [
843 [
c16c6ad8
CR
844 'entity_table' => 'civicrm_contribution',
845 'price_field_id' => 8,
846 'price_field_value_id' => 16,
847 'label' => 'test 1',
848 'qty' => 1,
849 'unit_price' => 14.85,
850 'line_total' => 14.85,
9099cab3
CW
851 ],
852 [
c16c6ad8
CR
853 'entity_table' => 'civicrm_contribution',
854 'price_field_id' => 8,
855 'price_field_value_id' => 17,
856 'label' => 'Test 2',
857 'qty' => 1,
858 'unit_price' => 1.66,
859 'line_total' => 1.66,
860 'financial_type_id' => 1,
9099cab3
CW
861 ],
862 [
c16c6ad8
CR
863 'entity_table' => 'civicrm_contribution',
864 'price_field_id' => 8,
865 'price_field_value_id' => 17,
866 'label' => 'Test 2',
867 'qty' => 1,
868 'unit_price' => 0.16,
869 'line_total' => 0.16,
870 'financial_type_id' => 1,
9099cab3
CW
871 ],
872 ],
873 'params' => [],
874 ],
875 ],
876 ];
c16c6ad8
CR
877
878 $foundException = FALSE;
879
880 try {
881 CRM_Contribute_BAO_Contribution::checkLineItems($params);
882 }
883 catch (CRM_Contribute_Exception_CheckLineItemsException $e) {
884 $foundException = TRUE;
885 }
886
887 $this->assertFalse($foundException);
888 }
889
88f7a518 890 /**
6e902643 891 * Test activity amount updates activity subject.
88f7a518
E
892 */
893 public function testActivityCreate() {
894 $contactId = $this->individualCreate();
88f7a518 895
9099cab3 896 $params = [
88f7a518
E
897 'contact_id' => $contactId,
898 'currency' => 'USD',
899 'financial_type_id' => 1,
900 'contribution_status_id' => 1,
901 'payment_instrument_id' => 1,
902 'source' => 'STUDENT',
903 'receive_date' => '20080522000000',
904 'receipt_date' => '20080522000000',
905 'non_deductible_amount' => 0.00,
906 'total_amount' => 100.00,
88f7a518
E
907 'invoice_id' => '86ed39c9e9ee6ef6031621ce0eafe7eb81',
908 'thankyou_date' => '20160519',
d0c97775 909 'sequential' => 1,
9099cab3 910 ];
88f7a518 911
d0c97775 912 $contribution = $this->callAPISuccess('Contribution', 'create', $params)['values'][0];
88f7a518 913
d0c97775 914 $this->assertEquals($params['total_amount'], $contribution['total_amount'], 'Check for total amount in contribution.');
915 $this->assertEquals($contactId, $contribution['contact_id'], 'Check for contact id creation.');
6e902643 916 $activityWhere = [
917 ['source_record_id', '=', $contribution['id']],
918 ['activity_type_id:name', '=', 'Contribution'],
9099cab3 919 ];
6e902643 920 $activity = Activity::get()->setWhere($activityWhere)->setSelect(['source_record_id', 'subject'])->execute()->first();
88f7a518 921
6e902643 922 $this->assertEquals($contribution['id'], $activity['source_record_id'], 'Check for activity associated with contribution.');
923 $this->assertEquals('$ 100.00 - STUDENT', $activity['subject'], 'Check for total amount in activity.');
88f7a518 924
d0c97775 925 $params['id'] = $contribution['id'];
88f7a518 926 $params['total_amount'] = 200;
6e902643 927 $params['campaign_id'] = $this->campaignCreate();
88f7a518 928
d0c97775 929 $contribution = $this->callAPISuccess('Contribution', 'create', $params)['values'][0];
88f7a518 930
d0c97775 931 $this->assertEquals($params['total_amount'], $contribution['total_amount'], 'Check for total amount in contribution.');
932 $this->assertEquals($contactId, $contribution['contact_id'], 'Check for contact id creation.');
88f7a518
E
933
934 // Retrieve activity again.
6e902643 935 $activity = Activity::get()->setWhere($activityWhere)->setSelect(['source_record_id', 'subject', 'campaign_id'])->execute()->first();
88f7a518 936
6e902643 937 $this->assertEquals($contribution['id'], $activity['source_record_id'], 'Check for activity associated with contribution.');
938 $this->assertEquals('$ 200.00 - STUDENT', $activity['subject'], 'Check for total amount in activity.');
939 $this->assertEquals($params['campaign_id'], $activity['campaign_id']);
88f7a518
E
940 }
941
5c3d600f
PN
942 /**
943 * Test allowUpdateRevenueRecognitionDate.
af595ac2 944 *
945 * @throws \CRM_Core_Exception
5c3d600f
PN
946 */
947 public function testAllowUpdateRevenueRecognitionDate() {
948 $contactId = $this->individualCreate();
9099cab3 949 $params = [
5c3d600f
PN
950 'contact_id' => $contactId,
951 'receive_date' => '2010-01-20',
952 'total_amount' => 100,
4303ea89 953 'financial_type_id' => 4,
af595ac2 954 'contribution_status_id' => 'Pending',
9099cab3 955 ];
af595ac2 956 $order = $this->callAPISuccess('Order', 'create', $params);
5c3d600f
PN
957 $allowUpdate = CRM_Contribute_BAO_Contribution::allowUpdateRevenueRecognitionDate($order['id']);
958 $this->assertTrue($allowUpdate);
959
960 $event = $this->eventCreate();
9099cab3 961 $params = [
5c3d600f
PN
962 'contact_id' => $contactId,
963 'receive_date' => '2010-01-20',
964 'total_amount' => 300,
8484a5f0 965 'financial_type_id' => $this->getFinancialTypeId('Event Fee'),
af595ac2 966 'contribution_status_id' => 'Pending',
9099cab3 967 ];
5c3d600f
PN
968 $priceFields = $this->createPriceSet('event', $event['id']);
969 foreach ($priceFields['values'] as $key => $priceField) {
9099cab3 970 $lineItems[$key] = [
5c3d600f
PN
971 'price_field_id' => $priceField['price_field_id'],
972 'price_field_value_id' => $priceField['id'],
973 'label' => $priceField['label'],
974 'field_title' => $priceField['label'],
975 'qty' => 1,
976 'unit_price' => $priceField['amount'],
977 'line_total' => $priceField['amount'],
978 'financial_type_id' => $priceField['financial_type_id'],
979 'entity_table' => 'civicrm_participant',
9099cab3 980 ];
5c3d600f 981 }
9099cab3 982 $params['line_items'][] = [
5c3d600f 983 'line_item' => $lineItems,
9099cab3 984 'params' => [
5c3d600f
PN
985 'contact_id' => $contactId,
986 'event_id' => $event['id'],
987 'status_id' => 1,
988 'role_id' => 1,
989 'register_date' => '2007-07-21 00:00:00',
990 'source' => 'Online Event Registration: API Testing',
9099cab3
CW
991 ],
992 ];
af595ac2 993 $order = $this->callAPISuccess('Order', 'create', $params);
5c3d600f
PN
994 $allowUpdate = CRM_Contribute_BAO_Contribution::allowUpdateRevenueRecognitionDate($order['id']);
995 $this->assertFalse($allowUpdate);
996
9099cab3 997 $params = [
5c3d600f
PN
998 'contact_id' => $contactId,
999 'receive_date' => '2010-01-20',
1000 'total_amount' => 200,
8484a5f0 1001 'financial_type_id' => $this->getFinancialTypeId('Member Dues'),
af595ac2 1002 'contribution_status_id' => 'Pending',
9099cab3 1003 ];
5c3d600f
PN
1004 $membershipType = $this->membershipTypeCreate();
1005 $priceFields = $this->createPriceSet();
9099cab3 1006 $lineItems = [];
5c3d600f 1007 foreach ($priceFields['values'] as $key => $priceField) {
9099cab3 1008 $lineItems[$key] = [
5c3d600f
PN
1009 'price_field_id' => $priceField['price_field_id'],
1010 'price_field_value_id' => $priceField['id'],
1011 'label' => $priceField['label'],
1012 'field_title' => $priceField['label'],
1013 'qty' => 1,
1014 'unit_price' => $priceField['amount'],
1015 'line_total' => $priceField['amount'],
1016 'financial_type_id' => $priceField['financial_type_id'],
1017 'entity_table' => 'civicrm_membership',
1018 'membership_type_id' => $membershipType,
9099cab3 1019 ];
5c3d600f 1020 }
9099cab3
CW
1021 $params['line_items'][] = [
1022 'line_item' => [array_pop($lineItems)],
1023 'params' => [
5c3d600f
PN
1024 'contact_id' => $contactId,
1025 'membership_type_id' => $membershipType,
1026 'join_date' => '2006-01-21',
1027 'start_date' => '2006-01-21',
1028 'end_date' => '2006-12-21',
1029 'source' => 'Payment',
1030 'is_override' => 1,
1031 'status_id' => 1,
9099cab3
CW
1032 ],
1033 ];
af595ac2 1034 $order = $this->callAPISuccess('Order', 'create', $params);
5c3d600f
PN
1035 $allowUpdate = CRM_Contribute_BAO_Contribution::allowUpdateRevenueRecognitionDate($order['id']);
1036 $this->assertFalse($allowUpdate);
1037 }
1038
d9553c2e
PN
1039 /**
1040 * Test calculateFinancialItemAmount().
1041 */
1042 public function testcalculateFinancialItemAmount() {
9099cab3
CW
1043 $testParams = [
1044 [
1045 'params' => [],
1046 'amountParams' => [
d9553c2e
PN
1047 'line_total' => 100,
1048 'previous_line_total' => 300,
1049 'diff' => 1,
9099cab3 1050 ],
d9553c2e
PN
1051 'context' => 'changedAmount',
1052 'expectedItemAmount' => -200,
9099cab3
CW
1053 ],
1054 [
1055 'params' => [],
1056 'amountParams' => [
d9553c2e
PN
1057 'line_total' => 100,
1058 'previous_line_total' => 100,
1059 'diff' => -1,
9099cab3 1060 ],
efb16c63 1061 // Most contexts are ignored. Removing refs to change payment instrument so placeholder.
1062 'context' => 'not null',
d9553c2e 1063 'expectedItemAmount' => -100,
9099cab3
CW
1064 ],
1065 [
1066 'params' => [
d9553c2e
PN
1067 'is_quick_config' => TRUE,
1068 'total_amount' => 110,
1069 'tax_amount' => 10,
9099cab3
CW
1070 ],
1071 'amountParams' => [
d9553c2e 1072 'item_amount' => 100,
9099cab3 1073 ],
d9553c2e
PN
1074 'context' => 'changedAmount',
1075 'expectedItemAmount' => 100,
9099cab3
CW
1076 ],
1077 [
1078 'params' => [
d9553c2e
PN
1079 'is_quick_config' => TRUE,
1080 'total_amount' => 110,
1081 'tax_amount' => 10,
9099cab3
CW
1082 ],
1083 'amountParams' => [
d9553c2e 1084 'item_amount' => NULL,
9099cab3 1085 ],
d9553c2e
PN
1086 'context' => 'changedAmount',
1087 'expectedItemAmount' => 110,
9099cab3
CW
1088 ],
1089 [
1090 'params' => [
d9553c2e
PN
1091 'is_quick_config' => TRUE,
1092 'total_amount' => 110,
1093 'tax_amount' => 10,
9099cab3
CW
1094 ],
1095 'amountParams' => [
d9553c2e 1096 'item_amount' => NULL,
9099cab3 1097 ],
d9553c2e
PN
1098 'context' => NULL,
1099 'expectedItemAmount' => 100,
9099cab3
CW
1100 ],
1101 ];
d9553c2e
PN
1102 foreach ($testParams as $params) {
1103 $itemAmount = CRM_Contribute_BAO_Contribution::calculateFinancialItemAmount($params['params'], $params['amountParams'], $params['context']);
1104 $this->assertEquals($itemAmount, $params['expectedItemAmount'], 'Invalid Financial Item amount.');
1105 }
1106 }
1107
d934a732
PN
1108 /**
1109 * Test recording of amount with comma separator.
b4c48831 1110 *
1111 * @throws \CRM_Core_Exception
d934a732
PN
1112 */
1113 public function testCommaSeparatorAmount() {
1114 $contactId = $this->individualCreate();
1115
9099cab3 1116 $params = [
d934a732
PN
1117 'contact_id' => $contactId,
1118 'currency' => 'USD',
1119 'financial_type_id' => 1,
b4c48831 1120 'contribution_status_id' => 'Pending',
d934a732
PN
1121 'payment_instrument_id' => 1,
1122 'receive_date' => '20080522000000',
1123 'receipt_date' => '20080522000000',
b4c48831 1124 'total_amount' => '20,000.00',
1125 'api.Payment.create' => ['total_amount' => '8,000.00'],
2c35902f 1126 'skipCleanMoney' => FALSE,
9099cab3 1127 ];
d934a732 1128
b4c48831 1129 $contribution = $this->callAPISuccess('Order', 'create', $params);
d0c97775 1130 $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
d934a732
PN
1131 $financialTrxn = $this->callAPISuccessGetSingle(
1132 'FinancialTrxn',
9099cab3 1133 [
d934a732 1134 'id' => $lastFinancialTrxnId['financialTrxnId'],
9099cab3
CW
1135 'return' => ['total_amount'],
1136 ]
d934a732 1137 );
b4c48831 1138 $this->assertEquals($financialTrxn['total_amount'], 8000, 'Invalid amount.');
d934a732
PN
1139 }
1140
adbc354b
PN
1141 /**
1142 * Test for function getSalesTaxFinancialAccounts().
1143 */
1144 public function testgetSalesTaxFinancialAccounts() {
1145 $this->enableTaxAndInvoicing();
1146 $financialType = $this->createFinancialType();
28d44c71 1147 $financialAccount = $this->addTaxAccountToFinancialType($financialType['id']);
9099cab3 1148 $expectedResult = [$financialAccount->financial_account_id => $financialAccount->financial_account_id];
adbc354b 1149 $financialType = $this->createFinancialType();
28d44c71 1150 $financialAccount = $this->addTaxAccountToFinancialType($financialType['id']);
adbc354b
PN
1151 $expectedResult[$financialAccount->financial_account_id] = $financialAccount->financial_account_id;
1152 $salesTaxFinancialAccount = CRM_Contribute_BAO_Contribution::getSalesTaxFinancialAccounts();
1153 $this->assertTrue(($salesTaxFinancialAccount == $expectedResult), 'Function returned wrong values.');
1154 }
1155
0409b821
PN
1156 /**
1157 * Test for function createProportionalEntry().
83644f47 1158 *
1159 * @param string $thousandSeparator
1160 * punctuation used to refer to thousands.
1161 *
1162 * @dataProvider getThousandSeparators
0409b821 1163 */
83644f47 1164 public function testCreateProportionalEntry($thousandSeparator) {
1165 $this->setCurrencySeparators($thousandSeparator);
2a4a2f00 1166 list($contribution, $financialAccount) = $this->createContributionWithTax();
9099cab3 1167 $params = [
0409b821
PN
1168 'total_amount' => 55,
1169 'to_financial_account_id' => $financialAccount->financial_account_id,
1170 'payment_instrument_id' => 1,
1171 'trxn_date' => date('Ymd'),
1172 'status_id' => 1,
0409b821 1173 'entity_id' => $contribution['id'],
9099cab3 1174 ];
3137781d 1175 $financialTrxn = $this->callAPISuccess('FinancialTrxn', 'create', $params);
9099cab3 1176 $entityParams = [
0409b821
PN
1177 'contribution_total_amount' => $contribution['total_amount'],
1178 'trxn_total_amount' => 55,
1179 'line_item_amount' => 100,
9099cab3 1180 ];
0409b821 1181 $previousLineItem = CRM_Financial_BAO_FinancialItem::getPreviousFinancialItem($contribution['id']);
9099cab3 1182 $eftParams = [
0409b821 1183 'entity_table' => 'civicrm_financial_item',
cf28d075 1184 'entity_id' => $previousLineItem['id'],
3137781d 1185 'financial_trxn_id' => (string) $financialTrxn['id'],
9099cab3 1186 ];
0409b821 1187 CRM_Contribute_BAO_Contribution::createProportionalEntry($entityParams, $eftParams);
9099cab3 1188 $trxnTestArray = array_merge($eftParams, [
3137781d 1189 'amount' => '50.00',
9099cab3 1190 ]);
cf28d075 1191 $this->callAPISuccessGetSingle('EntityFinancialTrxn', $eftParams, $trxnTestArray);
0409b821
PN
1192 }
1193
c364c544
MW
1194 /**
1195 * Test for function createProportionalEntry with zero amount().
1196 *
1197 * @param string $thousandSeparator
1198 * punctuation used to refer to thousands.
1199 *
1200 * @dataProvider getThousandSeparators
1201 */
1202 public function testCreateProportionalEntryZeroAmount($thousandSeparator) {
1203 $this->setCurrencySeparators($thousandSeparator);
9099cab3
CW
1204 list($contribution, $financialAccount) = $this->createContributionWithTax(['total_amount' => 0]);
1205 $params = [
c364c544
MW
1206 'total_amount' => 0,
1207 'to_financial_account_id' => $financialAccount->financial_account_id,
1208 'payment_instrument_id' => 1,
1209 'trxn_date' => date('Ymd'),
1210 'status_id' => 1,
1211 'entity_id' => $contribution['id'],
9099cab3 1212 ];
c364c544 1213 $financialTrxn = $this->callAPISuccess('FinancialTrxn', 'create', $params);
9099cab3 1214 $entityParams = [
c364c544
MW
1215 'contribution_total_amount' => $contribution['total_amount'],
1216 'trxn_total_amount' => 0,
1217 'line_item_amount' => 0,
9099cab3 1218 ];
c364c544 1219 $previousLineItem = CRM_Financial_BAO_FinancialItem::getPreviousFinancialItem($contribution['id']);
9099cab3 1220 $eftParams = [
c364c544
MW
1221 'entity_table' => 'civicrm_financial_item',
1222 'entity_id' => $previousLineItem['id'],
1223 'financial_trxn_id' => (string) $financialTrxn['id'],
9099cab3 1224 ];
c364c544 1225 CRM_Contribute_BAO_Contribution::createProportionalEntry($entityParams, $eftParams);
9099cab3 1226 $trxnTestArray = array_merge($eftParams, [
c364c544 1227 'amount' => '0.00',
9099cab3 1228 ]);
c364c544
MW
1229 $this->callAPISuccessGetSingle('EntityFinancialTrxn', $eftParams, $trxnTestArray);
1230 }
1231
646bc565
PN
1232 /**
1233 * Test for function getLastFinancialItemIds().
1234 */
1235 public function testgetLastFinancialItemIds() {
2a4a2f00 1236 list($contribution, $financialAccount) = $this->createContributionWithTax();
646bc565
PN
1237 list($ftIds, $taxItems) = CRM_Contribute_BAO_Contribution::getLastFinancialItemIds($contribution['id']);
1238 $this->assertEquals(count($ftIds), 1, 'Invalid count.');
1239 $this->assertEquals(count($taxItems), 1, 'Invalid count.');
1240 foreach ($taxItems as $value) {
1241 $this->assertEquals($value['amount'], 10, 'Invalid tax amount.');
1242 }
1243 }
1244
2a4a2f00 1245 /**
97c818fd 1246 * Test to ensure proportional entries are creating when adding a payment..
1247 *
1248 * In this test we create a pending contribution for $110 consisting of $100 contribution and $10 tax.
1249 *
1250 * We pay $50, resulting in it being allocated as $45.45 paymnt & $4.55 tax. This is in equivalent proportions
1251 * to the original payment - ie. .0909 of the $110 is 10 & that * 50 is $4.54 (note the rounding seems wrong as it should be
1252 * saved un-rounded).
2a4a2f00 1253 */
97c818fd 1254 public function testCreateProportionalFinancialEntriesViaPaymentCreate() {
1255 list($contribution, $financialAccount) = $this->createContributionWithTax([], FALSE);
1256 $params = [
3137781d 1257 'total_amount' => 50,
2a4a2f00
PN
1258 'to_financial_account_id' => $financialAccount->financial_account_id,
1259 'payment_instrument_id' => 1,
1260 'trxn_date' => date('Ymd'),
1261 'status_id' => 1,
2a4a2f00 1262 'entity_id' => $contribution['id'],
97c818fd 1263 'contribution_id' => $contribution['id'],
1264 ];
1265 $financialTrxn = $this->callAPISuccess('Payment', 'create', $params);
1266 $eftParams = [
2a4a2f00
PN
1267 'entity_table' => 'civicrm_financial_item',
1268 'financial_trxn_id' => $financialTrxn['id'],
97c818fd 1269 ];
2a4a2f00
PN
1270 $entityFinancialTrxn = $this->callAPISuccess('EntityFinancialTrxn', 'Get', $eftParams);
1271 $this->assertEquals($entityFinancialTrxn['count'], 2, 'Invalid count.');
97c818fd 1272 $testAmount = [4.55, 45.45];
2a4a2f00 1273 foreach ($entityFinancialTrxn['values'] as $value) {
97c818fd 1274 $this->assertEquals(array_pop($testAmount), $value['amount'], 'Invalid amount stored in civicrm_entity_financial_trxn.');
77641de4
PN
1275 }
1276 }
1277
1278 /**
1279 * Test to check if amount is proportionally asigned for PI change.
1280 */
1281 public function testProportionallyAssignedForPIChange() {
1282 list($contribution, $financialAccount) = $this->createContributionWithTax();
9099cab3 1283 $params = [
77641de4
PN
1284 'id' => $contribution['id'],
1285 'payment_instrument_id' => 3,
9099cab3 1286 ];
77641de4
PN
1287 $this->callAPISuccess('Contribution', 'create', $params);
1288 $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
9099cab3 1289 $eftParams = [
77641de4
PN
1290 'entity_table' => 'civicrm_financial_item',
1291 'financial_trxn_id' => $lastFinancialTrxnId['financialTrxnId'],
9099cab3 1292 ];
77641de4
PN
1293 $entityFinancialTrxn = $this->callAPISuccess('EntityFinancialTrxn', 'Get', $eftParams);
1294 $this->assertEquals($entityFinancialTrxn['count'], 2, 'Invalid count.');
9099cab3 1295 $testAmount = [10, 100];
77641de4
PN
1296 foreach ($entityFinancialTrxn['values'] as $value) {
1297 $this->assertEquals($value['amount'], array_pop($testAmount), 'Invalid amount stored in civicrm_entity_financial_trxn.');
2a4a2f00
PN
1298 }
1299 }
1300
646bc565
PN
1301 /**
1302 * Function to create contribution with tax.
1303 */
9099cab3 1304 public function createContributionWithTax($params = [], $isCompleted = TRUE) {
c364c544
MW
1305 if (!isset($params['total_amount'])) {
1306 $params['total_amount'] = 100;
1307 }
646bc565
PN
1308 $contactId = $this->individualCreate();
1309 $this->enableTaxAndInvoicing();
1310 $financialType = $this->createFinancialType();
28d44c71 1311 $financialAccount = $this->addTaxAccountToFinancialType($financialType['id']);
646bc565
PN
1312 $form = new CRM_Contribute_Form_Contribution();
1313
9099cab3 1314 $form->testSubmit([
39b959db
SL
1315 'total_amount' => $params['total_amount'],
1316 'financial_type_id' => $financialType['id'],
1317 'contact_id' => $contactId,
97c818fd 1318 'contribution_status_id' => $isCompleted ? 1 : 2,
39b959db 1319 'price_set_id' => 0,
9099cab3 1320 ], CRM_Core_Action::ADD);
646bc565 1321 $contribution = $this->callAPISuccessGetSingle('Contribution',
9099cab3 1322 [
646bc565 1323 'contact_id' => $contactId,
9099cab3
CW
1324 'return' => ['tax_amount', 'total_amount'],
1325 ]
646bc565 1326 );
9099cab3 1327 return [$contribution, $financialAccount];
646bc565
PN
1328 }
1329
75c07fde
JP
1330 /**
1331 * Test processOnBehalfOrganization() function.
1332 */
1333 public function testProcessOnBehalfOrganization() {
9099cab3 1334 $orgInfo = [
75c07fde
JP
1335 'phone' => '11111111',
1336 'email' => 'testorg@gmail.com',
1337 'street_address' => 'test Street',
1338 'city' => 'test City',
1339 'state_province' => 'AA',
1340 'postal_code' => '222222',
1341 'country' => 'United States',
9099cab3 1342 ];
e4addeb2 1343 $originalContactId = $contactID = $this->individualCreate();
9099cab3
CW
1344 $orgId = $this->organizationCreate(['organization_name' => 'testorg1']);
1345 $orgCount = $this->callAPISuccessGetCount('Contact', [
75c07fde
JP
1346 'contact_type' => "Organization",
1347 'organization_name' => "testorg1",
9099cab3 1348 ]);
75c07fde
JP
1349 $this->assertEquals($orgCount, 1);
1350
9099cab3 1351 $values = $params = [];
e4addeb2 1352 $originalBehalfOrganization = $behalfOrganization = [
75c07fde 1353 'organization_name' => 'testorg1',
9099cab3
CW
1354 'phone' => [
1355 1 => [
75c07fde
JP
1356 'phone' => $orgInfo['phone'],
1357 'is_primary' => 1,
9099cab3
CW
1358 ],
1359 ],
1360 'email' => [
1361 1 => [
75c07fde
JP
1362 'email' => $orgInfo['email'],
1363 'is_primary' => 1,
9099cab3
CW
1364 ],
1365 ],
1366 'address' => [
1367 3 => [
75c07fde
JP
1368 'street_address' => $orgInfo['street_address'],
1369 'city' => $orgInfo['city'],
1370 'location_type_id' => 3,
1371 'postal_code' => $orgInfo['postal_code'],
1372 'country' => 'US',
1373 'state_province' => 'AA',
1374 'is_primary' => 1,
9099cab3
CW
1375 ],
1376 ],
1377 ];
1378 $fields = [
75c07fde
JP
1379 'organization_name' => 1,
1380 'phone-3-1' => 1,
1381 'email-3' => 1,
1382 'street_address-3' => 1,
1383 'city-3' => 1,
1384 'postal_code-3' => 1,
1385 'country-3' => 1,
1386 'state_province-3' => 1,
9099cab3 1387 ];
e4addeb2
JG
1388 $empty = [];
1389 CRM_Contribute_Form_Contribution_Confirm::processOnBehalfOrganization($behalfOrganization, $contactID, $empty, $empty, $empty);
75c07fde 1390
e4addeb2 1391 //Check whether new organisation is created.
9099cab3 1392 $result = $this->callAPISuccess('Contact', 'get', [
75c07fde
JP
1393 'contact_type' => "Organization",
1394 'organization_name' => "testorg1",
9099cab3 1395 ]);
75c07fde
JP
1396 $this->assertEquals($result['count'], 1);
1397
1398 //Assert all org values are updated.
1399 foreach ($orgInfo as $key => $val) {
1400 $this->assertEquals($result['values'][$orgId][$key], $val);
1401 }
1402
1403 //Check if alert is assigned to params if more than 1 dupe exists.
9099cab3 1404 $orgId = $this->organizationCreate(['organization_name' => 'testorg1', 'email' => 'testorg@gmail.com']);
e4addeb2 1405 CRM_Contribute_Form_Contribution_Confirm::processOnBehalfOrganization($originalBehalfOrganization, $originalContactId, $values, $params, $fields);
75c07fde
JP
1406 $this->assertEquals($params['onbehalf_dupe_alert'], 1);
1407 }
1408
7e2ec997
E
1409 /**
1410 * Test for replaceContributionTokens.
1411 * This function tests whether the contribution tokens are replaced with values from contribution.
1412 */
1413 public function testReplaceContributionTokens() {
9945400a 1414 $customGroup = $this->customGroupCreate(['extends' => 'Contribution', 'title' => 'contribution stuff']);
875e076b 1415 $customField = $this->customFieldOptionValueCreate($customGroup, 'myCustomField');
7e2ec997 1416 $contactId1 = $this->individualCreate();
9099cab3 1417 $params = [
7e2ec997
E
1418 'contact_id' => $contactId1,
1419 'receive_date' => '20120511',
1420 'total_amount' => 100.00,
1421 'financial_type_id' => 1,
1422 'trxn_id' => 12345,
1423 'invoice_id' => 67890,
1424 'source' => 'SSF',
1425 'contribution_status_id' => 2,
875e076b 1426 "custom_{$customField['id']}" => 'value1',
6fc6274e 1427 'currency' => 'EUR',
9099cab3 1428 ];
7e2ec997
E
1429 $contribution1 = $this->contributionCreate($params);
1430 $contactId2 = $this->individualCreate();
9099cab3 1431 $params = [
7e2ec997
E
1432 'contact_id' => $contactId2,
1433 'receive_date' => '20150511',
1434 'total_amount' => 200.00,
1435 'financial_type_id' => 1,
1436 'trxn_id' => 6789,
1437 'invoice_id' => 12345,
1438 'source' => 'ABC',
1439 'contribution_status_id' => 1,
875e076b 1440 "custom_{$customField['id']}" => 'value2',
9099cab3 1441 ];
7e2ec997 1442 $contribution2 = $this->contributionCreate($params);
9099cab3 1443 $ids = [$contribution1, $contribution2];
7e2ec997
E
1444
1445 $subject = "This is a test for contribution ID: {contribution.contribution_id}";
1446 $text = "Contribution Amount: {contribution.total_amount}";
1447 $html = "<p>Contribution Source: {contribution.contribution_source}</p></br>
1448 <p>Contribution Invoice ID: {contribution.invoice_id}</p></br>
875e076b 1449 <p>Contribution Receive Date: {contribution.receive_date}</p></br>
596a28fc 1450 <p>Contribution Custom Field: {contribution.custom_{$customField['id']}}</p></br>";
7e2ec997
E
1451
1452 $subjectToken = CRM_Utils_Token::getTokens($subject);
1453 $messageToken = CRM_Utils_Token::getTokens($text);
1454 $messageToken = array_merge($messageToken, CRM_Utils_Token::getTokens($html));
1455
1456 $contributionDetails = CRM_Contribute_BAO_Contribution::replaceContributionTokens(
1457 $ids,
1458 $subject,
1459 $subjectToken,
1460 $text,
1461 $html,
1462 $messageToken,
1463 TRUE
1464 );
1465
6fc6274e 1466 $this->assertEquals("Contribution Amount: € 100.00", $contributionDetails[$contactId1]['text'], "The text does not match");
7e2ec997
E
1467 $this->assertEquals("<p>Contribution Source: ABC</p></br>
1468 <p>Contribution Invoice ID: 12345</p></br>
a1d274b9 1469 <p>Contribution Receive Date: May 11th, 2015 12:00 AM</p></br>
596a28fc 1470 <p>Contribution Custom Field: Label2</p></br>", $contributionDetails[$contactId2]['html'], "The html does not match");
7e2ec997
E
1471 }
1472
7b5169d0
PN
1473 /**
1474 * Test for contribution with deferred revenue.
1475 */
1476 public function testContributionWithDeferredRevenue() {
1477 $contactId = $this->individualCreate();
1478 Civi::settings()->set('deferred_revenue_enabled', TRUE);
9099cab3 1479 $params = [
7b5169d0
PN
1480 'contact_id' => $contactId,
1481 'receive_date' => '20120511',
1482 'total_amount' => 100.00,
1483 'financial_type_id' => 'Event Fee',
1484 'trxn_id' => 12345,
1485 'invoice_id' => 67890,
1486 'source' => 'SSF',
1487 'contribution_status_id' => 'Completed',
1488 'revenue_recognition_date' => date('Ymd', strtotime("+3 month")),
9099cab3 1489 ];
7b5169d0
PN
1490 $contribution = $this->callAPISuccess('contribution', 'create', $params);
1491
9099cab3 1492 $this->callAPISuccessGetCount('EntityFinancialTrxn', [
7b5169d0
PN
1493 'entity_table' => "civicrm_contribution",
1494 'entity_id' => $contribution['id'],
9099cab3 1495 ], 2);
7b5169d0 1496
9099cab3 1497 $checkAgainst = [
7b5169d0
PN
1498 'financial_trxn_id.to_financial_account_id.name' => 'Deferred Revenue - Event Fee',
1499 'financial_trxn_id.from_financial_account_id.name' => 'Event Fee',
f818aed5 1500 'financial_trxn_id' => '2',
9099cab3
CW
1501 ];
1502 $result = $this->callAPISuccessGetSingle('EntityFinancialTrxn', [
1503 'return' => [
7b5169d0
PN
1504 "financial_trxn_id.from_financial_account_id.name",
1505 "financial_trxn_id.to_financial_account_id.name",
1506 "financial_trxn_id",
9099cab3 1507 ],
7b5169d0
PN
1508 'entity_table' => "civicrm_contribution",
1509 'entity_id' => $contribution['id'],
1510 'financial_trxn_id.is_payment' => 0,
9099cab3 1511 ], $checkAgainst);
7b5169d0 1512
9099cab3 1513 $result = $this->callAPISuccessGetSingle('EntityFinancialTrxn', [
7b5169d0
PN
1514 'entity_table' => "civicrm_financial_item",
1515 'financial_trxn_id' => $result['financial_trxn_id'],
9099cab3
CW
1516 'return' => ['entity_id'],
1517 ]);
7b5169d0 1518
9099cab3 1519 $checkAgainst = [
7b5169d0
PN
1520 'financial_account_id.name' => 'Deferred Revenue - Event Fee',
1521 'id' => $result['entity_id'],
9099cab3
CW
1522 ];
1523 $result = $this->callAPISuccessGetSingle('FinancialItem', [
7b5169d0 1524 'id' => $result['entity_id'],
9099cab3
CW
1525 'return' => ["financial_account_id.name"],
1526 ], $checkAgainst);
7b5169d0
PN
1527 }
1528
a495d83a
PN
1529 /**
1530 * https://lab.civicrm.org/dev/financial/issues/56
1531 * Changing financial type on a contribution records correct financial items
1532 */
1533 public function testChangingFinancialTypeWithoutTax() {
1534 $ids = $values = [];
1535 $contactId = $this->individualCreate();
9099cab3 1536 $params = [
a495d83a
PN
1537 'contact_id' => $contactId,
1538 'receive_date' => date('YmdHis'),
1539 'total_amount' => 100.00,
1540 'financial_type_id' => 'Donation',
1541 'contribution_status_id' => 'Completed',
9099cab3 1542 ];
a495d83a
PN
1543 /* first test the scenario when sending an email */
1544 $contributionId = $this->callAPISuccess(
1545 'contribution',
1546 'create',
1547 $params
1548 )['id'];
1549
1550 // Update Financial Type.
1551 $this->callAPISuccess('contribution', 'create', [
1552 'id' => $contributionId,
1553 'financial_type_id' => 'Event Fee',
1554 ]);
1555
1556 // Get line item
1557 $lineItem = $this->callAPISuccessGetSingle('LineItem', [
1558 'contribution_id' => $contributionId,
1559 'return' => ["financial_type_id.name", "line_total"],
1560 ]);
1561
1562 $this->assertEquals(
1563 $lineItem['line_total'],
1564 100.00,
1565 'Invalid line amount.'
1566 );
1567
1568 $this->assertEquals(
1569 $lineItem['financial_type_id.name'],
1570 'Event Fee',
1571 'Invalid Financial Type stored.'
1572 );
1573
1574 // Get Financial Items.
1575 $financialItems = $this->callAPISuccess('FinancialItem', 'get', [
1576 'entity_id' => $lineItem['id'],
1577 'sequential' => 1,
1578 'entity_table' => 'civicrm_line_item',
1579 'options' => ['sort' => "id"],
1580 'return' => ["financial_account_id.name", "amount", "description"],
1581 ]);
1582
1583 $this->assertEquals($financialItems['count'], 3, 'Count mismatch.');
1584
1585 $toCheck = [
1586 ['Donation', 100.00],
1587 ['Donation', -100.00],
1588 ['Event Fee', 100.00],
1589 ];
1590
1591 foreach ($financialItems['values'] as $key => $values) {
1592 $this->assertEquals(
1593 $values['financial_account_id.name'],
1594 $toCheck[$key][0],
1595 'Invalid Financial Account stored.'
1596 );
1597 $this->assertEquals(
1598 $values['amount'],
1599 $toCheck[$key][1],
1600 'Amount mismatch.'
1601 );
1602 $this->assertEquals(
1603 $values['description'],
1604 'Contribution Amount',
1605 'Description mismatch.'
1606 );
1607 }
1608
1609 // Check transactions.
1610 $financialTransactions = $this->callAPISuccess('EntityFinancialTrxn', 'get', [
1611 'return' => ["financial_trxn_id"],
1612 'entity_table' => "civicrm_contribution",
1613 'entity_id' => $contributionId,
1614 'sequential' => 1,
1615 ]);
1616 $this->assertEquals($financialTransactions['count'], 3, 'Count mismatch.');
1617
1618 foreach ($financialTransactions['values'] as $key => $values) {
1619 $this->callAPISuccessGetCount('EntityFinancialTrxn', [
1620 'financial_trxn_id' => $values['financial_trxn_id'],
1621 'amount' => $toCheck[$key][1],
1622 'financial_trxn_id.total_amount' => $toCheck[$key][1],
1623 ], 2);
1624 }
1625 }
1626
1db3ddea
KE
1627 /**
1628 * CRM-21424 Check if the receipt update is set after composing the receipt message
1629 */
1630 public function testSendMailUpdateReceiptDate() {
9099cab3 1631 $ids = $values = [];
1db3ddea 1632 $contactId = $this->individualCreate();
9099cab3 1633 $params = [
1db3ddea
KE
1634 'contact_id' => $contactId,
1635 'receive_date' => '20120511',
1636 'total_amount' => 100.00,
1637 'financial_type_id' => 'Donation',
1638 'source' => 'SSF',
1639 'contribution_status_id' => 'Completed',
9099cab3 1640 ];
1db3ddea
KE
1641 /* first test the scenario when sending an email */
1642 $contribution = $this->callAPISuccess('contribution', 'create', $params);
1643 $contributionId = $contribution['id'];
1644 $this->assertDBNull('CRM_Contribute_BAO_Contribution', $contributionId, 'receipt_date', 'id', 'After creating receipt date must be null');
9099cab3 1645 $input = ['receipt_update' => 0];
1db3ddea
KE
1646 CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $contributionId, $values);
1647 $this->assertDBNull('CRM_Contribute_BAO_Contribution', $contributionId, 'receipt_date', 'id', 'After sendMail, with the explicit instruction not to update receipt date stays null');
9099cab3 1648 $input = ['receipt_update' => 1];
1db3ddea
KE
1649 CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $contributionId, $values);
1650 $this->assertDBNotNull('CRM_Contribute_BAO_Contribution', $contributionId, 'receipt_date', 'id', 'After sendMail with the permission to allow update receipt date must be set');
1651
1652 /* repeat the same scenario for downloading a pdf */
1653 $contribution = $this->callAPISuccess('contribution', 'create', $params);
1654 $contributionId = $contribution['id'];
1655 $this->assertDBNull('CRM_Contribute_BAO_Contribution', $contributionId, 'receipt_date', 'id', 'After creating receipt date must be null');
9099cab3 1656 $input = ['receipt_update' => 0];
1db3ddea
KE
1657 /* setting the lasast parameter (returnmessagetext) to TRUE is done by the download of the pdf */
1658 CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $contributionId, $values, TRUE);
1659 $this->assertDBNull('CRM_Contribute_BAO_Contribution', $contributionId, 'receipt_date', 'id', 'After sendMail, with the explicit instruction not to update receipt date stays null');
9099cab3 1660 $input = ['receipt_update' => 1];
1db3ddea
KE
1661 CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $contributionId, $values, TRUE);
1662 $this->assertDBNotNull('CRM_Contribute_BAO_Contribution', $contributionId, 'receipt_date', 'id', 'After sendMail with the permission to allow update receipt date must be set');
1663 }
1664
e26d0d27 1665 /**
1666 * Test cancel order api when a pledge is linked.
1667 *
1668 * The pledge status should be updated. I believe the contribution should
1669 * also be unlinked but the goal at this point is no change.
1670 *
1671 * @throws CRM_Core_Exception
1672 * @throws \CiviCRM_API3_Exception
1673 * @throws \API_Exception
1674 */
1675 public function testCancelOrderWithPledge(): void {
1676 $this->ids['contact'][0] = $this->individualCreate();
1677 $pledgeID = (int) $this->callAPISuccess('Pledge', 'create', ['contact_id' => $this->ids['contact'][0], 'amount' => 4, 'installments' => 2, 'frequency_unit' => 'month', 'original_installment_amount' => 2, 'create_date' => 'now', 'financial_type_id' => 'Donation', 'start_date' => '+5 days'])['id'];
1678 $orderID = (int) $this->callAPISuccess('Order', 'create', ['contact_id' => $this->ids['contact'][0], 'total_amount' => 2, 'financial_type_id' => 'Donation', 'api.Payment.create' => ['total_amount' => 2]])['id'];
1679 $pledgePayments = $this->callAPISuccess('PledgePayment', 'get')['values'];
1680 $this->callAPISuccess('PledgePayment', 'create', ['id' => key($pledgePayments), 'pledge_id' => $pledgeID, 'contribution_id' => $orderID, 'status_id' => 'Completed', 'actual_amount' => 2]);
1681 $beforePledge = $this->callAPISuccessGetSingle('Pledge', ['id' => $pledgeID]);
1682 $this->assertEquals(2, $beforePledge['pledge_total_paid']);
1683 $this->callAPISuccess('Order', 'cancel', ['contribution_id' => $orderID]);
1684
1685 $this->callAPISuccessGetSingle('Contribution', ['contribution_status_id' => 'Cancelled']);
1686 $afterPledge = $this->callAPISuccessGetSingle('Pledge', ['id' => $pledgeID]);
1687 $this->assertEquals('', $afterPledge['pledge_total_paid']);
1688 $payments = PledgePayment::get(FALSE)->addWhere('contribution_id', 'IS NOT NULL')->execute();
1689 $this->assertCount(0, $payments);
1690 }
1691
df43ca01
PN
1692 /**
1693 * Test contribution update when more than one quick
1694 * config line item is linked to contribution.
1695 *
1696 * @throws CRM_Core_Exception
1697 * @throws \CiviCRM_API3_Exception
1698 * @throws \API_Exception
1699 */
1700 public function testContributionQuickConfigTwoLineItems(): void {
1701 $contactId1 = $this->individualCreate();
1702 $contactId2 = $this->individualCreate();
1703 $membershipOrganizationId = $this->organizationCreate();
1704
1705 // Created new contribution to bypass the deprecated error
1706 // 'Per https://lab.civicrm.org/dev/core/issues/15 this data fix should not be required.'
1707 // in CRM_Price_BAO_LineItem::processPriceSet();
1708 $this->callAPISuccess('Contribution', 'create', [
1709 'contact_id' => $contactId1,
1710 'receive_date' => '2010-01-20',
1711 'financial_type_id' => 'Member Dues',
1712 'contribution_status_id' => 'Completed',
1713 'total_amount' => 150,
1714 ]);
1715 $this->callAPISuccess('Contribution', 'create', [
1716 'contact_id' => $contactId1,
1717 'receive_date' => '2010-01-20',
1718 'financial_type_id' => 'Member Dues',
1719 'contribution_status_id' => 'Completed',
1720 'total_amount' => 150,
1721 ]);
1722
1723 // create membership type
1724 $membershipTypeId1 = $this->callAPISuccess('MembershipType', 'create', [
1725 'domain_id' => 1,
1726 'member_of_contact_id' => $membershipOrganizationId,
1727 'financial_type_id' => 'Member Dues',
1728 'duration_unit' => 'month',
1729 'duration_interval' => 1,
1730 'period_type' => 'rolling',
1731 'minimum_fee' => 100,
1732 'name' => 'Parent',
1733 ])['id'];
1734
1735 $membershipTypeId2 = $this->callAPISuccess('MembershipType', 'create', [
1736 'domain_id' => 1,
1737 'member_of_contact_id' => $membershipOrganizationId,
1738 'financial_type_id' => 'Member Dues',
1739 'duration_unit' => 'month',
1740 'duration_interval' => 1,
1741 'period_type' => 'rolling',
1742 'minimum_fee' => 50,
1743 'name' => 'Child',
1744 ])['id'];
1745
1746 $contactIds = [
1747 $contactId1 => $membershipTypeId1,
1748 $contactId2 => $membershipTypeId2,
1749 ];
1750
1751 $priceFields = CRM_Price_BAO_PriceSet::getDefaultPriceSet('membership');
1752
1753 // prepare order api params.
1754 $p = [
1755 'contact_id' => $contactId1,
1756 'receive_date' => '2010-01-20',
1757 'financial_type_id' => 'Member Dues',
1758 'contribution_status_id' => 'Pending',
1759 'total_amount' => 150,
1760 'api.Payment.create' => ['total_amount' => 150],
1761 ];
1762
1763 $now = date('Ymd');
1764 foreach ($priceFields as $priceField) {
1765 $lineItems = [];
1766 $contactId = array_search($priceField['membership_type_id'], $contactIds);
1767 $lineItems[1] = [
1768 'price_field_id' => $priceField['priceFieldID'],
1769 'price_field_value_id' => $priceField['priceFieldValueID'],
1770 'label' => $priceField['label'],
1771 'field_title' => $priceField['label'],
1772 'qty' => 1,
1773 'unit_price' => $priceField['amount'],
1774 'line_total' => $priceField['amount'],
1775 'financial_type_id' => $priceField['financial_type_id'],
1776 'entity_table' => 'civicrm_membership',
1777 'membership_type_id' => $priceField['membership_type_id'],
1778 ];
1779 $p['line_items'][] = [
1780 'line_item' => $lineItems,
1781 'params' => [
1782 'contact_id' => $contactId,
1783 'membership_type_id' => $priceField['membership_type_id'],
1784 'source' => 'Payment',
1785 'join_date' => '2020-04-28',
1786 'start_date' => '2020-04-28',
1787 'status_id' => 'Pending',
1788 'is_override' => 1,
1789 ],
1790 ];
1791 }
1792 $order = $this->callAPISuccess('order', 'create', $p);
1793 $contributionId = $order['id'];
1794
1795 $count = CRM_Core_DAO::singleValueQuery('
1796 SELECT count(*), total_amount
1797 FROM civicrm_contribution cc
1798 INNER JOIN civicrm_line_item cli
1799 ON cli.contribution_id = cc.id
1800 AND cc.id = %1
1801 GROUP BY cc.id, total_amount
1802 HAVING SUM(cli.line_total) != total_amount
1803 ', [1 => [$contributionId, 'Integer']]);
1804
1805 $this->assertEquals(0, $count);
1806
1807 $this->callAPISuccess('Contribution', 'create', [
1808 'id' => $contributionId,
1809 'total_amount' => 150,
1810 ]);
1811 $count = CRM_Core_DAO::singleValueQuery('
1812 SELECT count(*), total_amount
1813 FROM civicrm_contribution cc
1814 INNER JOIN civicrm_line_item cli
1815 ON cli.contribution_id = cc.id
1816 AND cc.id = %1
1817 GROUP BY cc.id, total_amount
1818 HAVING SUM(cli.line_total) != total_amount
1819 ', [1 => [$contributionId, 'Integer']]);
1820
1821 $this->assertEquals(0, $count);
1822 }
1823
6b5e6603
MF
1824 /**
1825 * Test activity contact is updated when contribution contact is changed
1826 */
1827 public function testUpdateActivityContactOnContributionContactChange(): void {
1828 $contactId_1 = $this->individualCreate();
1829 $contactId_2 = $this->individualCreate();
1830 $contactId_3 = $this->individualCreate();
1831
1832 $contributionParams = [
1833 'financial_type_id' => 'Donation',
1834 'receive_date' => date('Y-m-d H:i:s'),
1835 'sequential' => TRUE,
1836 'total_amount' => 50,
1837 ];
1838
1839 // Case 1: Only source contact, no target contact
1840
1841 $contribution = $this->callAPISuccess('Contribution', 'create', array_merge(
1842 $contributionParams,
1843 ['contact_id' => $contactId_1]
1844 ))['values'][0];
1845
1846 $activity = $this->callAPISuccessGetSingle('Activity', ['source_record_id' => $contribution['id']]);
1847
1848 $activityContactParams = [
1849 'activity_id' => $activity['id'],
1850 'record_type_id' => 'Activity Source',
1851 ];
1852
1853 $activityContact = $this->callAPISuccessGetSingle('ActivityContact', $activityContactParams);
1854
1855 $this->assertEquals($activityContact['contact_id'], $contactId_1, 'Check source contact ID matches the first contact');
1856
1857 $contribution = $this->callAPISuccess('Contribution', 'create', array_merge(
1858 $contributionParams,
1859 [
1860 'id' => $contribution['id'],
1861 'contact_id' => $contactId_2,
1862 ]
1863 ))['values'][0];
1864
1865 $activityContact = $this->callAPISuccessGetSingle('ActivityContact', $activityContactParams);
1866
1867 $this->assertEquals($activityContact['contact_id'], $contactId_2, 'Check source contact ID matches the second contact');
1868
1869 // Case 2: Source and target contact
1870
1871 $contribution = $this->callAPISuccess('Contribution', 'create', array_merge(
1872 $contributionParams,
1873 [
1874 'contact_id' => $contactId_1,
1875 'source_contact_id' => $contactId_3,
1876 ]
1877 ))['values'][0];
1878
1879 $activity = $this->callAPISuccessGetSingle('Activity', ['source_record_id' => $contribution['id']]);
1880
1881 $activityContactParams = [
1882 'activity_id' => $activity['id'],
1883 'record_type_id' => 'Activity Targets',
1884 ];
1885
1886 $activityContact = $this->callAPISuccessGetSingle('ActivityContact', $activityContactParams);
1887
1888 $this->assertEquals($activityContact['contact_id'], $contactId_1, 'Check target contact ID matches first contact');
1889
1890 $contribution = $this->callAPISuccess('Contribution', 'create', array_merge(
1891 $contributionParams,
1892 [
1893 'id' => $contribution['id'],
1894 'contact_id' => $contactId_2,
1895 ]
1896 ))['values'][0];
1897
1898 $activityContact = $this->callAPISuccessGetSingle('ActivityContact', $activityContactParams);
1899
1900 $this->assertEquals($activityContact['contact_id'], $contactId_2, 'Check target contact ID matches the second contact');
1901 }
1902
6a488035 1903}