Merge pull request #18348 from eileenmcnaughton/kg
[civicrm-core.git] / tests / phpunit / api / v3 / 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 */
6a488035 11
b2250d14 12use Civi\Api4\Contribution;
13
6a488035
TO
14/**
15 * Test APIv3 civicrm_contribute_* functions
16 *
6c6e6187
TO
17 * @package CiviCRM_APIv3
18 * @subpackage API_Contribution
acb109b7 19 * @group headless
6a488035 20 */
6a488035
TO
21class api_v3_ContributionTest extends CiviUnitTestCase {
22
ed7e2e99 23 use CRMTraits_Profile_ProfileTrait;
2ac10e87 24 use CRMTraits_Custom_CustomDataTrait;
ed7e2e99 25
6a488035
TO
26 protected $_individualId;
27 protected $_contribution;
4ab7d517 28 protected $_financialTypeId = 1;
562e4fb8 29 protected $entity = 'Contribution';
6a488035 30 protected $_params;
9099cab3
CW
31 protected $_ids = [];
32 protected $_pageParams = [];
1eade77d 33 /**
34 * Payment processor ID (dummy processor).
35 *
36 * @var int
37 */
38 protected $paymentProcessorID;
b7c9bc4c 39
1e52837d
EM
40 /**
41 * Parameters to create payment processor.
42 *
43 * @var array
44 */
9099cab3 45 protected $_processorParams = [];
1e52837d
EM
46
47 /**
48 * ID of created event.
49 *
50 * @var int
51 */
52 protected $_eventID;
53
ec7e3954
E
54 /**
55 * @var CiviMailUtils
56 */
57 protected $mut;
58
22f80e87
EM
59 /**
60 * Setup function.
923dfabb 61 *
62 * @throws \CRM_Core_Exception
22f80e87 63 */
00be9182 64 public function setUp() {
6a488035
TO
65 parent::setUp();
66
67 $this->_apiversion = 3;
68 $this->_individualId = $this->individualCreate();
9099cab3 69 $this->_params = [
6a488035
TO
70 'contact_id' => $this->_individualId,
71 'receive_date' => '20120511',
72 'total_amount' => 100.00,
5896d037 73 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
74 'non_deductible_amount' => 10.00,
75 'fee_amount' => 5.00,
76 'net_amount' => 95.00,
77 'source' => 'SSF',
78 'contribution_status_id' => 1,
9099cab3
CW
79 ];
80 $this->_processorParams = [
6a488035
TO
81 'domain_id' => 1,
82 'name' => 'Dummy',
97502bac 83 'payment_processor_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Financial_BAO_PaymentProcessor', 'payment_processor_type_id', 'Dummy'),
6a488035
TO
84 'financial_account_id' => 12,
85 'is_active' => 1,
86 'user_name' => '',
87 'url_site' => 'http://dummy.com',
88 'url_recur' => 'http://dummy.com',
89 'billing_mode' => 1,
9099cab3 90 ];
1eade77d 91 $this->paymentProcessorID = $this->processorCreate();
9099cab3 92 $this->_pageParams = [
6a488035
TO
93 'title' => 'Test Contribution Page',
94 'financial_type_id' => 1,
95 'currency' => 'USD',
96 'financial_account_id' => 1,
1eade77d 97 'payment_processor' => $this->paymentProcessorID,
6a488035
TO
98 'is_active' => 1,
99 'is_allow_other_amount' => 1,
100 'min_amount' => 10,
101 'max_amount' => 1000,
9099cab3 102 ];
6a488035
TO
103 }
104
22f80e87
EM
105 /**
106 * Clean up after each test.
f736929b 107 *
108 * @throws \CRM_Core_Exception
22f80e87 109 */
00be9182 110 public function tearDown() {
39d632fd 111 $this->quickCleanUpFinancialEntities();
b2250d14 112 $this->quickCleanup(['civicrm_uf_match'], TRUE);
9099cab3 113 $financialAccounts = $this->callAPISuccess('FinancialAccount', 'get', []);
83644f47 114 foreach ($financialAccounts['values'] as $financialAccount) {
f736929b 115 if ($financialAccount['name'] === 'Test Tax financial account ' || $financialAccount['name'] === 'Test taxable financial Type') {
9099cab3 116 $entityFinancialTypes = $this->callAPISuccess('EntityFinancialAccount', 'get', [
83644f47 117 'financial_account_id' => $financialAccount['id'],
9099cab3 118 ]);
83644f47 119 foreach ($entityFinancialTypes['values'] as $entityFinancialType) {
9099cab3 120 $this->callAPISuccess('EntityFinancialAccount', 'delete', ['id' => $entityFinancialType['id']]);
83644f47 121 }
9099cab3 122 $this->callAPISuccess('FinancialAccount', 'delete', ['id' => $financialAccount['id']]);
83644f47 123 }
124 }
f736929b 125 $this->restoreUFGroupOne();
6a488035
TO
126 }
127
22f80e87
EM
128 /**
129 * Test Get.
923dfabb 130 *
131 * @throws \CRM_Core_Exception
22f80e87 132 */
00be9182 133 public function testGetContribution() {
5d288dc4 134 $this->enableTaxAndInvoicing();
9099cab3 135 $p = [
6a488035
TO
136 'contact_id' => $this->_individualId,
137 'receive_date' => '2010-01-20',
138 'total_amount' => 100.00,
4ab7d517 139 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
140 'non_deductible_amount' => 10.00,
141 'fee_amount' => 5.00,
142 'net_amount' => 95.00,
143 'trxn_id' => 23456,
144 'invoice_id' => 78910,
145 'source' => 'SSF',
562e4fb8 146 'contribution_status_id' => 'Completed',
9099cab3 147 ];
2f45e1c2 148 $this->_contribution = $this->callAPISuccess('contribution', 'create', $p);
6a488035 149
9099cab3 150 $params = [
6a488035 151 'contribution_id' => $this->_contribution['id'],
9099cab3 152 ];
e0e3c51b 153
3af96592 154 $contributions = $this->callAPIAndDocument('contribution', 'get', $params, __FUNCTION__, __FILE__);
4ab7d517 155 $financialParams['id'] = $this->_financialTypeId;
6c6e6187 156 $default = NULL;
858d0bf8 157 CRM_Financial_BAO_FinancialType::retrieve($financialParams, $default);
2f45e1c2 158
3af96592 159 $this->assertEquals(1, $contributions['count']);
160 $contribution = $contributions['values'][$contributions['id']];
161 $this->assertEquals($contribution['contact_id'], $this->_individualId);
22f80e87
EM
162 // Note there was an assertion converting financial_type_id to 'Donation' which wasn't working.
163 // Passing back a string rather than an id seems like an error/cruft.
164 // If it is to be introduced we should discuss.
3af96592 165 $this->assertEquals($contribution['financial_type_id'], 1);
166 $this->assertEquals($contribution['total_amount'], 100.00);
167 $this->assertEquals($contribution['non_deductible_amount'], 10.00);
168 $this->assertEquals($contribution['fee_amount'], 5.00);
169 $this->assertEquals($contribution['net_amount'], 95.00);
170 $this->assertEquals($contribution['trxn_id'], 23456);
171 $this->assertEquals($contribution['invoice_id'], 78910);
5d288dc4 172 $this->assertEquals($contribution['invoice_number'], 'INV_' . $contributions['id']);
3af96592 173 $this->assertEquals($contribution['contribution_source'], 'SSF');
174 $this->assertEquals($contribution['contribution_status'], 'Completed');
22f80e87 175 // Create a second contribution - we are testing that 'id' gets the right contribution id (not the contact id).
6a488035
TO
176 $p['trxn_id'] = '3847';
177 $p['invoice_id'] = '3847';
178
2f45e1c2 179 $contribution2 = $this->callAPISuccess('contribution', 'create', $p);
180
22f80e87 181 // Now we have 2 - test getcount.
5d4c1098 182 $contribution = $this->callAPISuccess('contribution', 'getcount');
6a488035 183 $this->assertEquals(2, $contribution);
22f80e87 184 // Test id only format.
9099cab3 185 $contribution = $this->callAPISuccess('contribution', 'get', [
4ab7d517 186 'id' => $this->_contribution['id'],
187 'format.only_id' => 1,
9099cab3 188 ]);
22f80e87
EM
189 $this->assertEquals($this->_contribution['id'], $contribution, print_r($contribution, TRUE));
190 // Test id only format.
9099cab3 191 $contribution = $this->callAPISuccess('contribution', 'get', [
4ab7d517 192 'id' => $contribution2['id'],
193 'format.only_id' => 1,
9099cab3 194 ]);
4ab7d517 195 $this->assertEquals($contribution2['id'], $contribution);
22f80e87 196 // Test id as field.
9099cab3 197 $contribution = $this->callAPISuccess('contribution', 'get', [
4ab7d517 198 'id' => $this->_contribution['id'],
9099cab3 199 ]);
2bfae985 200 $this->assertEquals(1, $contribution['count']);
4ab7d517 201
22f80e87 202 // Test get by contact id works.
9099cab3 203 $contribution = $this->callAPISuccess('contribution', 'get', ['contact_id' => $this->_individualId]);
6a488035 204
2bfae985 205 $this->assertEquals(2, $contribution['count']);
9099cab3 206 $this->callAPISuccess('Contribution', 'Delete', [
6a488035 207 'id' => $this->_contribution['id'],
9099cab3
CW
208 ]);
209 $this->callAPISuccess('Contribution', 'Delete', [
6a488035 210 'id' => $contribution2['id'],
9099cab3 211 ]);
6a488035
TO
212 }
213
71d5a412 214 /**
215 * Test that test contributions can be retrieved.
923dfabb 216 *
217 * @throws \CRM_Core_Exception
71d5a412 218 */
219 public function testGetTestContribution() {
9099cab3
CW
220 $this->callAPISuccess('Contribution', 'create', array_merge($this->_params, ['is_test' => 1]));
221 $this->callAPISuccessGetSingle('Contribution', ['is_test' => 1]);
71d5a412 222 }
223
7d96cec3
SL
224 /**
225 * Test Creating a check contribution with original check_number field
226 */
227 public function testCreateCheckContribution() {
228 $params = $this->_params;
229 $params['contribution_check_number'] = 'bouncer';
230 $params['payment_instrument_id'] = 'Check';
231 $params['cancel_date'] = 'yesterday';
232 $params['receipt_date'] = 'yesterday';
233 $params['thankyou_date'] = 'yesterday';
234 $params['revenue_recognition_date'] = 'yesterday';
235 $params['amount_level'] = 'Unreasonable';
236 $params['cancel_reason'] = 'You lose sucker';
237 $params['creditnote_id'] = 'sudo rm -rf';
238 $params['tax_amount'] = '1';
239 $address = $this->callAPISuccess('Address', 'create', [
240 'street_address' => 'Knockturn Alley',
241 'contact_id' => $this->_individualId,
242 'location_type_id' => 'Home',
243 ]);
244 $params['address_id'] = $address['id'];
245 $contributionPage = $this->contributionPageCreate();
246 $params['contribution_page_id'] = $contributionPage['id'];
247 $params['campaign_id'] = $this->campaignCreate();
248 $contributionID = $this->contributionCreate($params);
249 $getResult = $this->callAPISuccess('Contribution', 'get', ['id' => $contributionID]);
250 $this->assertEquals('bouncer', $getResult['values'][$contributionID]['check_number']);
251 $entityFinancialTrxn = $this->callAPISuccess('EntityFinancialTrxn', 'get', ['entity_id' => $contributionID, 'entity_table' => 'civicrm_contribution']);
252 foreach ($entityFinancialTrxn['values'] as $eft) {
253 $financialTrxn = $this->callAPISuccess('FinancialTrxn', 'get', ['id' => $eft['financial_trxn_id']]);
254 $this->assertEquals('bouncer', $financialTrxn['values'][$financialTrxn['id']]['check_number']);
255 }
256 }
257
59f9e5a6 258 /**
259 * Test the 'return' param works for all fields.
1807fca4 260 *
261 * @throws \CRM_Core_Exception
59f9e5a6 262 */
263 public function testGetContributionReturnFunctionality() {
264 $params = $this->_params;
7d96cec3 265 $params['contribution_check_number'] = 'bouncer';
59f9e5a6 266 $params['payment_instrument_id'] = 'Check';
267 $params['cancel_date'] = 'yesterday';
268 $params['receipt_date'] = 'yesterday';
269 $params['thankyou_date'] = 'yesterday';
270 $params['revenue_recognition_date'] = 'yesterday';
271 $params['amount_level'] = 'Unreasonable';
272 $params['cancel_reason'] = 'You lose sucker';
273 $params['creditnote_id'] = 'sudo rm -rf';
274 $params['tax_amount'] = '1';
9099cab3 275 $address = $this->callAPISuccess('Address', 'create', [
59f9e5a6 276 'street_address' => 'Knockturn Alley',
277 'contact_id' => $this->_individualId,
278 'location_type_id' => 'Home',
9099cab3 279 ]);
59f9e5a6 280 $params['address_id'] = $address['id'];
281 $contributionPage = $this->contributionPageCreate();
282 $params['contribution_page_id'] = $contributionPage['id'];
9099cab3 283 $contributionRecur = $this->callAPISuccess('ContributionRecur', 'create', [
59f9e5a6 284 'contact_id' => $this->_individualId,
285 'frequency_interval' => 1,
286 'amount' => 5,
9099cab3 287 ]);
59f9e5a6 288 $params['contribution_recur_id'] = $contributionRecur['id'];
289
290 $params['campaign_id'] = $this->campaignCreate();
291
292 $contributionID = $this->contributionCreate($params);
9cad3ff4
CW
293
294 // update contribution with invoice number
9099cab3 295 $params = array_merge($params, [
9cad3ff4
CW
296 'id' => $contributionID,
297 'invoice_number' => CRM_Utils_Array::value('invoice_prefix', Civi::settings()->get('contribution_invoice_settings')) . "" . $contributionID,
360a0925 298 'trxn_id' => 12345,
299 'invoice_id' => 6789,
9099cab3 300 ]);
9cad3ff4
CW
301 $contributionID = $this->contributionCreate($params);
302
9099cab3 303 $contribution = $this->callAPISuccessGetSingle('Contribution', ['id' => $contributionID]);
59f9e5a6 304 $this->assertEquals('bouncer', $contribution['check_number']);
305 $this->assertEquals('bouncer', $contribution['contribution_check_number']);
306
307 $fields = CRM_Contribute_BAO_Contribution::fields();
3123273f 308 // Re-add these 2 to the fields to check. They were locked in but the metadata changed so we
309 // need to specify them.
310 $fields['address_id'] = $fields['contribution_address_id'];
311 $fields['check_number'] = $fields['contribution_check_number'];
312
9099cab3 313 $fieldsLockedIn = [
59f9e5a6 314 'contribution_id', 'contribution_contact_id', 'financial_type_id', 'contribution_page_id',
315 'payment_instrument_id', 'receive_date', 'non_deductible_amount', 'total_amount',
6e7cc0f5 316 'fee_amount', 'net_amount', 'trxn_id', 'invoice_id', 'currency', 'contribution_cancel_date', 'cancel_reason',
59f9e5a6 317 'receipt_date', 'thankyou_date', 'contribution_source', 'amount_level', 'contribution_recur_id',
318 'is_test', 'is_pay_later', 'contribution_status_id', 'address_id', 'check_number', 'contribution_campaign_id',
319 'creditnote_id', 'tax_amount', 'revenue_recognition_date', 'decoy',
9099cab3 320 ];
59f9e5a6 321 $missingFields = array_diff($fieldsLockedIn, array_keys($fields));
322 // If any of the locked in fields disappear from the $fields array we need to make sure it is still
323 // covered as the test contract now guarantees them in the return array.
9099cab3 324 $this->assertEquals($missingFields, [29 => 'decoy'], 'A field which was covered by the test contract has changed.');
59f9e5a6 325 foreach ($fields as $fieldName => $fieldSpec) {
9099cab3 326 $contribution = $this->callAPISuccessGetSingle('Contribution', ['id' => $contributionID, 'return' => $fieldName]);
59f9e5a6 327 $returnField = $fieldName;
328 if ($returnField == 'contribution_contact_id') {
329 $returnField = 'contact_id';
330 }
331 $this->assertTrue((!empty($contribution[$returnField]) || $contribution[$returnField] === "0"), $returnField);
332 }
7d96cec3
SL
333 $entityFinancialTrxn = $this->callAPISuccess('EntityFinancialTrxn', 'get', ['entity_id' => $contributionID, 'entity_table' => 'civicrm_contribution']);
334 foreach ($entityFinancialTrxn['values'] as $eft) {
335 $financialTrxn = $this->callAPISuccess('FinancialTrxn', 'get', ['id' => $eft['financial_trxn_id']]);
336 $this->assertEquals('bouncer', $financialTrxn['values'][$financialTrxn['id']]['check_number']);
337 }
59f9e5a6 338 }
339
927898c5 340 /**
341 * Test cancel reason works as a filter.
342 */
343 public function testFilterCancelReason() {
344 $params = $this->_params;
345 $params['cancel_date'] = 'yesterday';
346 $params['cancel_reason'] = 'You lose sucker';
347 $this->callAPISuccess('Contribution', 'create', $params);
348 $params = $this->_params;
349 $params['cancel_date'] = 'yesterday';
350 $params['cancel_reason'] = 'You are a winner';
351 $this->callAPISuccess('Contribution', 'create', $params);
352 $this->callAPISuccessGetCount('Contribution', ['cancel_reason' => 'You are a winner'], 1);
353 }
354
6c6e6187 355 /**
22f80e87 356 * We need to ensure previous tested behaviour still works as part of the api contract.
6c6e6187 357 */
00be9182 358 public function testGetContributionLegacyBehaviour() {
9099cab3 359 $p = [
6a488035
TO
360 'contact_id' => $this->_individualId,
361 'receive_date' => '2010-01-20',
362 'total_amount' => 100.00,
4ab7d517 363 'contribution_type_id' => $this->_financialTypeId,
6a488035
TO
364 'non_deductible_amount' => 10.00,
365 'fee_amount' => 5.00,
366 'net_amount' => 95.00,
367 'trxn_id' => 23456,
368 'invoice_id' => 78910,
369 'source' => 'SSF',
370 'contribution_status_id' => 1,
9099cab3 371 ];
71d5a412 372 $this->_contribution = $this->callAPISuccess('Contribution', 'create', $p);
6a488035 373
9099cab3 374 $params = [
6a488035 375 'contribution_id' => $this->_contribution['id'],
9099cab3 376 ];
5be22f39 377 $contribution = $this->callAPISuccess('contribution', 'get', $params);
4ab7d517 378 $financialParams['id'] = $this->_financialTypeId;
6c6e6187 379 $default = NULL;
858d0bf8 380 CRM_Financial_BAO_FinancialType::retrieve($financialParams, $default);
2f45e1c2 381
6c6e6187 382 $this->assertEquals(1, $contribution['count']);
2bfae985 383 $this->assertEquals($contribution['values'][$contribution['id']]['contact_id'], $this->_individualId);
4ab7d517 384 $this->assertEquals($contribution['values'][$contribution['id']]['financial_type_id'], $this->_financialTypeId);
385 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_type_id'], $this->_financialTypeId);
2bfae985
EM
386 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
387 $this->assertEquals($contribution['values'][$contribution['id']]['non_deductible_amount'], 10.00);
388 $this->assertEquals($contribution['values'][$contribution['id']]['fee_amount'], 5.00);
389 $this->assertEquals($contribution['values'][$contribution['id']]['net_amount'], 95.00);
390 $this->assertEquals($contribution['values'][$contribution['id']]['trxn_id'], 23456);
391 $this->assertEquals($contribution['values'][$contribution['id']]['invoice_id'], 78910);
392 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_source'], 'SSF');
393 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed');
22f80e87
EM
394
395 // Create a second contribution - we are testing that 'id' gets the right contribution id (not the contact id).
6a488035
TO
396 $p['trxn_id'] = '3847';
397 $p['invoice_id'] = '3847';
398
2f45e1c2 399 $contribution2 = $this->callAPISuccess('contribution', 'create', $p);
6a488035 400
6a488035 401 // now we have 2 - test getcount
9099cab3 402 $contribution = $this->callAPISuccess('contribution', 'getcount', []);
6a488035
TO
403 $this->assertEquals(2, $contribution);
404 //test id only format
9099cab3 405 $contribution = $this->callAPISuccess('contribution', 'get', [
4ab7d517 406 'id' => $this->_contribution['id'],
407 'format.only_id' => 1,
9099cab3 408 ]);
22f80e87 409 $this->assertEquals($this->_contribution['id'], $contribution, print_r($contribution, TRUE));
6a488035 410 //test id only format
9099cab3 411 $contribution = $this->callAPISuccess('contribution', 'get', [
4ab7d517 412 'id' => $contribution2['id'],
413 'format.only_id' => 1,
9099cab3 414 ]);
6a488035 415 $this->assertEquals($contribution2['id'], $contribution);
9099cab3 416 $contribution = $this->callAPISuccess('contribution', 'get', [
6a488035 417 'id' => $this->_contribution['id'],
9099cab3 418 ]);
6a488035 419 //test id as field
2bfae985 420 $this->assertEquals(1, $contribution['count']);
6a488035
TO
421 // $this->assertEquals($this->_contribution['id'], $contribution['id'] ) ;
422 //test get by contact id works
9099cab3 423 $contribution = $this->callAPISuccess('contribution', 'get', ['contact_id' => $this->_individualId]);
6a488035 424
2bfae985 425 $this->assertEquals(2, $contribution['count']);
9099cab3 426 $this->callAPISuccess('Contribution', 'Delete', [
5896d037 427 'id' => $this->_contribution['id'],
9099cab3
CW
428 ]);
429 $this->callAPISuccess('Contribution', 'Delete', [
5896d037 430 'id' => $contribution2['id'],
9099cab3 431 ]);
6a488035 432 }
5896d037 433
a1a2a83d
TO
434 /**
435 * Create an contribution_id=FALSE and financial_type_id=Donation.
436 */
00be9182 437 public function testCreateEmptyContributionIDUseDonation() {
9099cab3 438 $params = [
6a488035
TO
439 'contribution_id' => FALSE,
440 'contact_id' => 1,
441 'total_amount' => 1,
6c6e6187 442 'check_permissions' => FALSE,
6a488035 443 'financial_type_id' => 'Donation',
9099cab3 444 ];
858d0bf8 445 $this->callAPISuccess('contribution', 'create', $params);
6c6e6187 446 }
6a488035 447
6a488035 448 /**
1e52837d
EM
449 * Check with complete array + custom field.
450 *
6a488035
TO
451 * Note that the test is written on purpose without any
452 * variables specific to participant so it can be replicated into other entities
453 * and / or moved to the automated test suite
562e4fb8 454 *
455 * @throws \CRM_Core_Exception
6a488035 456 */
00be9182 457 public function testCreateWithCustom() {
6a488035
TO
458 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
459
460 $params = $this->_params;
461 $params['custom_' . $ids['custom_field_id']] = "custom string";
462
562e4fb8 463 $result = $this->callAPIAndDocument($this->entity, 'create', $params, __FUNCTION__, __FILE__);
6a488035 464 $this->assertEquals($result['id'], $result['values'][$result['id']]['id']);
562e4fb8 465 $check = $this->callAPISuccess($this->entity, 'get', [
4ab7d517 466 'return.custom_' . $ids['custom_field_id'] => 1,
467 'id' => $result['id'],
9099cab3 468 ]);
0397bf47
SL
469 $group = $this->callAPISuccess('CustomGroup', 'getsingle', ['id' => $ids['custom_group_id']]);
470 $field = $this->callAPISuccess('CustomField', 'getsingle', ['id' => $ids['custom_field_id']]);
471 $contribution = \Civi\Api4\Contribution::get()
472 ->setSelect([
473 'id',
474 'total_amount',
475 $group['name'] . '.' . $field['name'],
476 ])
477 ->addWhere('id', '=', $result['id'])
478 ->execute()
479 ->first();
6a488035
TO
480 $this->customFieldDelete($ids['custom_field_id']);
481 $this->customGroupDelete($ids['custom_group_id']);
562e4fb8 482 $this->assertEquals('custom string', $check['values'][$check['id']]['custom_' . $ids['custom_field_id']]);
6a488035
TO
483 }
484
485 /**
fd786d03
EM
486 * Check with complete array + custom field.
487 *
6a488035
TO
488 * Note that the test is written on purpose without any
489 * variables specific to participant so it can be replicated into other entities
490 * and / or moved to the automated test suite
491 */
00be9182 492 public function testCreateGetFieldsWithCustom() {
5896d037 493 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
6a488035 494 $idsContact = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ContactTest.php');
9099cab3 495 $result = $this->callAPISuccess('Contribution', 'getfields', []);
6a488035
TO
496 $this->assertArrayHasKey('custom_' . $ids['custom_field_id'], $result['values']);
497 $this->assertArrayNotHasKey('custom_' . $idsContact['custom_field_id'], $result['values']);
498 $this->customFieldDelete($ids['custom_field_id']);
499 $this->customGroupDelete($ids['custom_group_id']);
500 $this->customFieldDelete($idsContact['custom_field_id']);
501 $this->customGroupDelete($idsContact['custom_group_id']);
502 }
503
00be9182 504 public function testCreateContributionNoLineItems() {
6a488035 505
9099cab3 506 $params = [
6a488035
TO
507 'contact_id' => $this->_individualId,
508 'receive_date' => '20120511',
509 'total_amount' => 100.00,
5896d037 510 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
511 'payment_instrument_id' => 1,
512 'non_deductible_amount' => 10.00,
513 'fee_amount' => 50.00,
514 'net_amount' => 90.00,
515 'trxn_id' => 12345,
516 'invoice_id' => 67890,
517 'source' => 'SSF',
518 'contribution_status_id' => 1,
6a488035 519 'skipLineItem' => 1,
9099cab3 520 ];
6a488035 521
2f45e1c2 522 $contribution = $this->callAPISuccess('contribution', 'create', $params);
83a30437
SL
523 $financialItems = $this->callAPISuccess('FinancialItem', 'get', []);
524 foreach ($financialItems['values'] as $financialItem) {
525 $this->assertEquals(date('Y-m-d H:i:s', strtotime($contribution['values'][$contribution['id']]['receive_date'])), date('Y-m-d H:i:s', strtotime($financialItem['transaction_date'])));
526 }
9099cab3 527 $lineItems = $this->callAPISuccess('line_item', 'get', [
6a488035
TO
528 'entity_id' => $contribution['id'],
529 'entity_table' => 'civicrm_contribution',
530 'sequential' => 1,
9099cab3 531 ]);
6a488035
TO
532 $this->assertEquals(0, $lineItems['count']);
533 }
5896d037 534
a1a2a83d 535 /**
eceb18cc 536 * Test checks that passing in line items suppresses the create mechanism.
6a488035 537 */
00be9182 538 public function testCreateContributionChainedLineItems() {
9099cab3 539 $params = [
6a488035
TO
540 'contact_id' => $this->_individualId,
541 'receive_date' => '20120511',
542 'total_amount' => 100.00,
4ab7d517 543 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
544 'payment_instrument_id' => 1,
545 'non_deductible_amount' => 10.00,
546 'fee_amount' => 50.00,
547 'net_amount' => 90.00,
548 'trxn_id' => 12345,
549 'invoice_id' => 67890,
550 'source' => 'SSF',
551 'contribution_status_id' => 1,
6a488035 552 'skipLineItem' => 1,
9099cab3
CW
553 'api.line_item.create' => [
554 [
6a488035
TO
555 'price_field_id' => 1,
556 'qty' => 2,
557 'line_total' => '20',
558 'unit_price' => '10',
9099cab3
CW
559 ],
560 [
6a488035
TO
561 'price_field_id' => 1,
562 'qty' => 1,
563 'line_total' => '80',
564 'unit_price' => '80',
9099cab3
CW
565 ],
566 ],
567 ];
6a488035 568
5c49fee0 569 $description = "Create Contribution with Nested Line Items.";
6a488035 570 $subfile = "CreateWithNestedLineItems";
6c6e6187 571 $contribution = $this->callAPIAndDocument('contribution', 'create', $params, __FUNCTION__, __FILE__, $description, $subfile);
2f45e1c2 572
9099cab3 573 $lineItems = $this->callAPISuccess('line_item', 'get', [
6a488035 574 'entity_id' => $contribution['id'],
4ede4532 575 'contribution_id' => $contribution['id'],
6a488035
TO
576 'entity_table' => 'civicrm_contribution',
577 'sequential' => 1,
9099cab3 578 ]);
6a488035
TO
579 $this->assertEquals(2, $lineItems['count']);
580 }
581
00be9182 582 public function testCreateContributionOffline() {
9099cab3 583 $params = [
6a488035
TO
584 'contact_id' => $this->_individualId,
585 'receive_date' => '20120511',
586 'total_amount' => 100.00,
587 'financial_type_id' => 1,
588 'trxn_id' => 12345,
589 'invoice_id' => 67890,
590 'source' => 'SSF',
591 'contribution_status_id' => 1,
9099cab3 592 ];
6a488035 593
5be22f39 594 $contribution = $this->callAPISuccess('contribution', 'create', $params);
2bfae985
EM
595 $this->assertEquals($contribution['values'][$contribution['id']]['contact_id'], $this->_individualId);
596 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
5896d037 597 $this->assertEquals($contribution['values'][$contribution['id']]['financial_type_id'], 1);
2bfae985
EM
598 $this->assertEquals($contribution['values'][$contribution['id']]['trxn_id'], 12345);
599 $this->assertEquals($contribution['values'][$contribution['id']]['invoice_id'], 67890);
600 $this->assertEquals($contribution['values'][$contribution['id']]['source'], 'SSF');
601 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status_id'], 1);
9099cab3 602 $lineItems = $this->callAPISuccess('line_item', 'get', [
6a488035 603 'entity_id' => $contribution['id'],
4ede4532 604 'contribution_id' => $contribution['id'],
6a488035
TO
605 'entity_table' => 'civicrm_contribution',
606 'sequential' => 1,
9099cab3 607 ]);
6a488035
TO
608 $this->assertEquals(1, $lineItems['count']);
609 $this->assertEquals($contribution['id'], $lineItems['values'][0]['entity_id']);
4ede4532 610 $this->assertEquals($contribution['id'], $lineItems['values'][0]['contribution_id']);
6a488035
TO
611 $this->_checkFinancialRecords($contribution, 'offline');
612 $this->contributionGetnCheck($params, $contribution['id']);
613 }
5896d037 614
f70a6752 615 /**
28de42d1 616 * Test create with valid payment instrument.
6a488035 617 */
00be9182 618 public function testCreateContributionWithPaymentInstrument() {
9099cab3 619 $params = $this->_params + ['payment_instrument' => 'EFT'];
53191813 620 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 621 $contribution = $this->callAPISuccess('contribution', 'get', [
53191813 622 'sequential' => 1,
21dfd5f5 623 'id' => $contribution['id'],
9099cab3 624 ]);
6a488035 625 $this->assertArrayHasKey('payment_instrument', $contribution['values'][0]);
53191813
CW
626 $this->assertEquals('EFT', $contribution['values'][0]['payment_instrument']);
627
9099cab3 628 $this->callAPISuccess('contribution', 'create', [
92915c55
TO
629 'id' => $contribution['id'],
630 'payment_instrument' => 'Credit Card',
9099cab3
CW
631 ]);
632 $contribution = $this->callAPISuccess('contribution', 'get', [
53191813 633 'sequential' => 1,
21dfd5f5 634 'id' => $contribution['id'],
9099cab3 635 ]);
53191813
CW
636 $this->assertArrayHasKey('payment_instrument', $contribution['values'][0]);
637 $this->assertEquals('Credit Card', $contribution['values'][0]['payment_instrument']);
6a488035
TO
638 }
639
00be9182 640 public function testGetContributionByPaymentInstrument() {
9099cab3
CW
641 $params = $this->_params + ['payment_instrument' => 'EFT'];
642 $params2 = $this->_params + ['payment_instrument' => 'Cash'];
6c6e6187
TO
643 $this->callAPISuccess('contribution', 'create', $params);
644 $this->callAPISuccess('contribution', 'create', $params2);
9099cab3 645 $contribution = $this->callAPISuccess('contribution', 'get', [
92915c55 646 'sequential' => 1,
7d543448 647 'contribution_payment_instrument' => 'Cash',
9099cab3 648 ]);
6a488035 649 $this->assertArrayHasKey('payment_instrument', $contribution['values'][0]);
ff977830
EM
650 $this->assertEquals('Cash', $contribution['values'][0]['payment_instrument']);
651 $this->assertEquals(1, $contribution['count']);
9099cab3 652 $contribution = $this->callAPISuccess('contribution', 'get', ['sequential' => 1, 'payment_instrument' => 'Cash']);
6a488035 653 $this->assertArrayHasKey('payment_instrument', $contribution['values'][0]);
868e247d 654 $this->assertEquals('Cash', $contribution['values'][0]['payment_instrument']);
6a488035 655 $this->assertEquals(1, $contribution['count']);
9099cab3 656 $contribution = $this->callAPISuccess('contribution', 'get', [
92915c55
TO
657 'sequential' => 1,
658 'payment_instrument_id' => 5,
9099cab3 659 ]);
6a488035 660 $this->assertArrayHasKey('payment_instrument', $contribution['values'][0]);
6c6e6187
TO
661 $this->assertEquals('EFT', $contribution['values'][0]['payment_instrument']);
662 $this->assertEquals(1, $contribution['count']);
9099cab3 663 $contribution = $this->callAPISuccess('contribution', 'get', [
92915c55
TO
664 'sequential' => 1,
665 'payment_instrument' => 'EFT',
9099cab3 666 ]);
6a488035 667 $this->assertArrayHasKey('payment_instrument', $contribution['values'][0]);
53191813
CW
668 $this->assertEquals('EFT', $contribution['values'][0]['payment_instrument']);
669 $this->assertEquals(1, $contribution['count']);
9099cab3 670 $contribution = $this->callAPISuccess('contribution', 'create', [
92915c55
TO
671 'id' => $contribution['id'],
672 'payment_instrument' => 'Credit Card',
9099cab3
CW
673 ]);
674 $contribution = $this->callAPISuccess('contribution', 'get', ['sequential' => 1, 'id' => $contribution['id']]);
6a488035 675 $this->assertArrayHasKey('payment_instrument', $contribution['values'][0]);
6c6e6187
TO
676 $this->assertEquals('Credit Card', $contribution['values'][0]['payment_instrument']);
677 $this->assertEquals(1, $contribution['count']);
6a488035
TO
678 }
679
b5a37491
EM
680 /**
681 * CRM-16227 introduces invoice_id as a parameter.
682 */
683 public function testGetContributionByInvoice() {
9099cab3
CW
684 $this->callAPISuccess('Contribution', 'create', array_merge($this->_params, ['invoice_id' => 'curly']));
685 $this->callAPISuccess('Contribution', 'create', array_merge($this->_params), ['invoice_id' => 'churlish']);
686 $this->callAPISuccessGetCount('Contribution', [], 2);
687 $this->callAPISuccessGetSingle('Contribution', ['invoice_id' => 'curly']);
b5a37491
EM
688 // The following don't work. They are the format we are trying to introduce but although the form uses this format
689 // CRM_Contact_BAO_Query::convertFormValues puts them into the other format & the where only supports that.
690 // ideally the where clause would support this format (as it does on contact_BAO_Query) and those lines would
691 // come out of convertFormValues
692 // $this->callAPISuccessGetSingle('Contribution', array('invoice_id' => array('LIKE' => '%ish%')));
693 // $this->callAPISuccessGetSingle('Contribution', array('invoice_id' => array('NOT IN' => array('curly'))));
694 // $this->callAPISuccessGetCount('Contribution', array('invoice_id' => array('LIKE' => '%ly%')), 2);
695 // $this->callAPISuccessGetCount('Contribution', array('invoice_id' => array('IN' => array('curly', 'churlish'))),
696 // 2);
697 }
698
2b3e31ac 699 /**
700 * Check the credit note retrieval is case insensitive.
701 */
702 public function testGetCreditNoteCaseInsensitive() {
9099cab3
CW
703 $this->contributionCreate(['contact_id' => $this->_individualId]);
704 $this->contributionCreate(['creditnote_id' => 'cN1234', 'contact_id' => $this->_individualId, 'invoice_id' => rand(), 'trxn_id' => rand()]);
705 $contribution = $this->callAPISuccess('Contribution', 'getsingle', ['creditnote_id' => 'CN1234']);
2b3e31ac 706 $this->assertEquals($contribution['creditnote_id'], 'cN1234');
707 }
708
e58a3abb 709 /**
710 * Test retrieval by total_amount works.
711 *
712 * @throws Exception
713 */
714 public function testGetContributionByTotalAmount() {
9099cab3
CW
715 $this->callAPISuccess('Contribution', 'create', array_merge($this->_params, ['total_amount' => '5']));
716 $this->callAPISuccess('Contribution', 'create', array_merge($this->_params, ['total_amount' => '10']));
717 $this->callAPISuccessGetCount('Contribution', ['total_amount' => 10], 1);
718 $this->callAPISuccessGetCount('Contribution', ['total_amount' => ['>' => 6]], 1);
719 $this->callAPISuccessGetCount('Contribution', ['total_amount' => ['>' => 0]], 2);
720 $this->callAPISuccessGetCount('Contribution', ['total_amount' => ['>' => -5]], 2);
721 $this->callAPISuccessGetCount('Contribution', ['total_amount' => ['<' => 0]], 0);
722 $this->callAPISuccessGetCount('Contribution', [], 2);
e58a3abb 723 }
724
dff93dda
JJ
725 /**
726 * @dataProvider createLocalizedContributionDataProvider
80da79bb 727 * @param $totalAmount
dff93dda
JJ
728 * @param $decimalPoint
729 * @param $thousandSeparator
730 * @param $currency
731 * @param $expectedResult
732 * @throws \Exception
733 */
734 public function testCreateLocalizedContribution($totalAmount, $decimalPoint, $thousandSeparator, $currency, $expectedResult) {
735 $this->setDefaultCurrency($currency);
736 $this->setMonetaryDecimalPoint($decimalPoint);
737 $this->setMonetaryThousandSeparator($thousandSeparator);
738
739 $_params = [
740 'contact_id' => $this->_individualId,
741 'receive_date' => '20120511',
742 'total_amount' => $totalAmount,
743 'financial_type_id' => $this->_financialTypeId,
744 'contribution_status_id' => 1,
745 ];
746
747 if ($expectedResult) {
748 $this->callAPISuccess('Contribution', 'create', $_params);
80da79bb
JJ
749 }
750 else {
dff93dda
JJ
751 $this->callAPIFailure('Contribution', 'create', $_params);
752 }
753 }
754
755 /**
756 * @return array
757 */
758 public function createLocalizedContributionDataProvider() {
759 return [
760 [10, '.', ',', 'USD', TRUE],
761 ['145.0E+3', '.', ',', 'USD', FALSE],
762 ['10', '.', ',', 'USD', TRUE],
763 [-10, '.', ',', 'USD', TRUE],
764 ['-10', '.', ',', 'USD', TRUE],
765 ['-10foo', '.', ',', 'USD', FALSE],
766 ['-10.0345619', '.', ',', 'USD', TRUE],
767 ['-10.010,4345619', '.', ',', 'USD', TRUE],
768 ['10.0104345619', '.', ',', 'USD', TRUE],
769 ['-0', '.', ',', 'USD', TRUE],
770 ['-.1', '.', ',', 'USD', TRUE],
771 ['.1', '.', ',', 'USD', TRUE],
772 // Test currency symbols too, default locale uses $, so if we wanted to test others we'd need to reconfigure locale
773 ['$1,234,567.89', '.', ',', 'USD', TRUE],
774 ['-$1,234,567.89', '.', ',', 'USD', TRUE],
775 ['$-1,234,567.89', '.', ',', 'USD', TRUE],
80da79bb
JJ
776 // This is the float format. Encapsulated in strings
777 ['1234567.89', '.', ',', 'USD', TRUE],
778 // This is the float format.
779 [1234567.89, '.', ',', 'USD', TRUE],
dff93dda
JJ
780 // Test EURO currency
781 ['€1,234,567.89', '.', ',', 'EUR', TRUE],
782 ['-€1,234,567.89', '.', ',', 'EUR', TRUE],
783 ['€-1,234,567.89', '.', ',', 'EUR', TRUE],
80da79bb
JJ
784 // This is the float format. Encapsulated in strings
785 ['1234567.89', '.', ',', 'EUR', TRUE],
786 // This is the float format.
787 [1234567.89, '.', ',', 'EUR', TRUE],
dff93dda
JJ
788 // Test Norwegian KR currency
789 ['kr1,234,567.89', '.', ',', 'NOK', TRUE],
790 ['kr 1,234,567.89', '.', ',', 'NOK', TRUE],
791 ['-kr1,234,567.89', '.', ',', 'NOK', TRUE],
792 ['-kr 1,234,567.89', '.', ',', 'NOK', TRUE],
793 ['kr-1,234,567.89', '.', ',', 'NOK', TRUE],
794 ['kr -1,234,567.89', '.', ',', 'NOK', TRUE],
80da79bb
JJ
795 // This is the float format. Encapsulated in strings
796 ['1234567.89', '.', ',', 'NOK', TRUE],
797 // This is the float format.
798 [1234567.89, '.', ',', 'NOK', TRUE],
dff93dda
JJ
799 // Test different localization options: , as decimal separator and dot as thousand separator
800 ['$1.234.567,89', ',', '.', 'USD', TRUE],
801 ['-$1.234.567,89', ',', '.', 'USD', TRUE],
802 ['$-1.234.567,89', ',', '.', 'USD', TRUE],
803 ['1.234.567,89', ',', '.', 'USD', TRUE],
80da79bb
JJ
804 // This is the float format. Encapsulated in strings
805 ['1234567.89', ',', '.', 'USD', TRUE],
806 // This is the float format.
807 [1234567.89, ',', '.', 'USD', TRUE],
dff93dda
JJ
808 ['$1,234,567.89', ',', '.', 'USD', FALSE],
809 ['-$1,234,567.89', ',', '.', 'USD', FALSE],
810 ['$-1,234,567.89', ',', '.', 'USD', FALSE],
811 // Now with a space as thousand separator
812 ['$1 234 567,89', ',', ' ', 'USD', TRUE],
813 ['-$1 234 567,89', ',', ' ', 'USD', TRUE],
814 ['$-1 234 567,89', ',', ' ', 'USD', TRUE],
815 ['1 234 567,89', ',', ' ', 'USD', TRUE],
80da79bb
JJ
816 // This is the float format. Encapsulated in strings
817 ['1234567.89', ',', ' ', 'USD', TRUE],
818 // This is the float format.
819 [1234567.89, ',', ' ', 'USD', TRUE],
dff93dda
JJ
820 ];
821 }
822
c490a46a 823 /**
eceb18cc 824 * Create test with unique field name on source.
c490a46a 825 */
00be9182 826 public function testCreateContributionSource() {
6a488035 827
9099cab3 828 $params = [
6a488035
TO
829 'contact_id' => $this->_individualId,
830 'receive_date' => date('Ymd'),
831 'total_amount' => 100.00,
4ab7d517 832 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
833 'payment_instrument_id' => 1,
834 'non_deductible_amount' => 10.00,
835 'fee_amount' => 50.00,
836 'net_amount' => 90.00,
837 'trxn_id' => 12345,
838 'invoice_id' => 67890,
839 'contribution_source' => 'SSF',
840 'contribution_status_id' => 1,
9099cab3 841 ];
6a488035 842
4ab7d517 843 $contribution = $this->callAPISuccess('contribution', 'create', $params);
2bfae985
EM
844 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
845 $this->assertEquals($contribution['values'][$contribution['id']]['source'], 'SSF');
6a488035 846 }
d5d148ab 847
d424ffde 848 /**
eceb18cc 849 * Create test with unique field name on source.
4750ab01 850 *
851 * @param string $thousandSeparator
852 * punctuation used to refer to thousands.
853 *
854 * @dataProvider getThousandSeparators
d424ffde 855 */
4750ab01 856 public function testCreateDefaultNow($thousandSeparator) {
857 $this->setCurrencySeparators($thousandSeparator);
d5d148ab 858 $params = $this->_params;
4750ab01 859 unset($params['receive_date'], $params['net_amount']);
860
861 $params['total_amount'] = $this->formatMoneyInput(5000.77);
862 $params['fee_amount'] = $this->formatMoneyInput(.77);
25ac4ffa 863 $params['skipCleanMoney'] = FALSE;
d5d148ab
EM
864
865 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 866 $contribution = $this->callAPISuccessGetSingle('contribution', ['id' => $contribution['id']]);
d5d148ab 867 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contribution['receive_date'])));
4750ab01 868 $this->assertEquals(5000.77, $contribution['total_amount'], 'failed to handle ' . $this->formatMoneyInput(5000.77));
869 $this->assertEquals(.77, $contribution['fee_amount']);
870 $this->assertEquals(5000, $contribution['net_amount']);
d5d148ab
EM
871 }
872
325033b9 873 /**
874 * Create test with unique field name on source.
875 */
876 public function testCreateContributionNullOutThankyouDate() {
877
878 $params = $this->_params;
879 $params['thankyou_date'] = 'yesterday';
880
881 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 882 $contribution = $this->callAPISuccessGetSingle('contribution', ['id' => $contribution['id']]);
325033b9 883 $this->assertEquals(date('Y-m-d', strtotime('yesterday')), date('Y-m-d', strtotime($contribution['thankyou_date'])));
884
885 $params['thankyou_date'] = 'null';
886 $contribution = $this->callAPISuccess('contribution', 'create', $params);
887 $contribution = $this->assertTrue(empty($contribution['thankyou_date']));
888 }
889
c490a46a 890 /**
55d2c6f1 891 * Create test with unique field name on source.
c490a46a 892 */
55d2c6f1 893 public function testCreateContributionSourceInvalidContact() {
6a488035 894
9099cab3 895 $params = [
6a488035
TO
896 'contact_id' => 999,
897 'receive_date' => date('Ymd'),
898 'total_amount' => 100.00,
4ab7d517 899 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
900 'payment_instrument_id' => 1,
901 'non_deductible_amount' => 10.00,
902 'fee_amount' => 50.00,
903 'net_amount' => 90.00,
904 'trxn_id' => 12345,
905 'invoice_id' => 67890,
906 'contribution_source' => 'SSF',
907 'contribution_status_id' => 1,
9099cab3 908 ];
6a488035 909
858d0bf8 910 $this->callAPIFailure('contribution', 'create', $params, 'contact_id is not valid : 999');
6a488035
TO
911 }
912
00be9182 913 public function testCreateContributionSourceInvalidContContact() {
6a488035 914
9099cab3 915 $params = [
6a488035
TO
916 'contribution_contact_id' => 999,
917 'receive_date' => date('Ymd'),
918 'total_amount' => 100.00,
4ab7d517 919 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
920 'payment_instrument_id' => 1,
921 'non_deductible_amount' => 10.00,
922 'fee_amount' => 50.00,
923 'net_amount' => 90.00,
924 'trxn_id' => 12345,
925 'invoice_id' => 67890,
926 'contribution_source' => 'SSF',
927 'contribution_status_id' => 1,
9099cab3 928 ];
6a488035 929
33139905 930 $this->callAPIFailure('contribution', 'create', $params);
6a488035
TO
931 }
932
858d0bf8 933 /**
442cf836 934 * Test note created correctly.
858d0bf8 935 */
00be9182 936 public function testCreateContributionWithNote() {
5c49fee0 937 $description = "Demonstrates creating contribution with Note Entity.";
5896d037 938 $subfile = "ContributionCreateWithNote";
9099cab3 939 $params = [
6a488035
TO
940 'contact_id' => $this->_individualId,
941 'receive_date' => '2012-01-01',
942 'total_amount' => 100.00,
4ab7d517 943 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
944 'payment_instrument_id' => 1,
945 'non_deductible_amount' => 10.00,
946 'fee_amount' => 50.00,
947 'net_amount' => 90.00,
948 'trxn_id' => 12345,
949 'invoice_id' => 67890,
950 'source' => 'SSF',
951 'contribution_status_id' => 1,
6a488035 952 'note' => 'my contribution note',
9099cab3 953 ];
6a488035 954
4ab7d517 955 $contribution = $this->callAPIAndDocument('contribution', 'create', $params, __FUNCTION__, __FILE__, $description, $subfile);
9099cab3 956 $result = $this->callAPISuccess('note', 'get', [
92915c55
TO
957 'entity_table' => 'civicrm_contribution',
958 'entity_id' => $contribution['id'],
959 'sequential' => 1,
9099cab3 960 ]);
6a488035 961 $this->assertEquals('my contribution note', $result['values'][0]['note']);
9099cab3 962 $this->callAPISuccess('contribution', 'delete', ['id' => $contribution['id']]);
6a488035
TO
963 }
964
00be9182 965 public function testCreateContributionWithNoteUniqueNameAliases() {
9099cab3 966 $params = [
6a488035
TO
967 'contact_id' => $this->_individualId,
968 'receive_date' => '2012-01-01',
969 'total_amount' => 100.00,
4ab7d517 970 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
971 'payment_instrument_id' => 1,
972 'non_deductible_amount' => 10.00,
973 'fee_amount' => 50.00,
974 'net_amount' => 90.00,
975 'trxn_id' => 12345,
976 'invoice_id' => 67890,
977 'source' => 'SSF',
978 'contribution_status_id' => 1,
6a488035 979 'contribution_note' => 'my contribution note',
9099cab3 980 ];
6a488035 981
4ab7d517 982 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 983 $result = $this->callAPISuccess('note', 'get', [
92915c55
TO
984 'entity_table' => 'civicrm_contribution',
985 'entity_id' => $contribution['id'],
986 'sequential' => 1,
9099cab3 987 ]);
6a488035 988 $this->assertEquals('my contribution note', $result['values'][0]['note']);
9099cab3 989 $this->callAPISuccess('contribution', 'delete', ['id' => $contribution['id']]);
6a488035 990 }
c490a46a
CW
991
992 /**
55d2c6f1 993 * This is the test for creating soft credits.
c490a46a 994 */
55d2c6f1 995 public function testCreateContributionWithSoftCredit() {
5c49fee0 996 $description = "Demonstrates creating contribution with SoftCredit.";
5896d037 997 $subfile = "ContributionCreateWithSoftCredit";
9099cab3 998 $contact2 = $this->callAPISuccess('Contact', 'create', [
92915c55
TO
999 'display_name' => 'superman',
1000 'contact_type' => 'Individual',
9099cab3
CW
1001 ]);
1002 $softParams = [
bcc03b98 1003 'contact_id' => $contact2['id'],
1004 'amount' => 50,
21dfd5f5 1005 'soft_credit_type_id' => 3,
9099cab3 1006 ];
6a488035 1007
9099cab3 1008 $params = $this->_params + ['soft_credit' => [1 => $softParams]];
4ab7d517 1009 $contribution = $this->callAPIAndDocument('contribution', 'create', $params, __FUNCTION__, __FILE__, $description, $subfile);
9099cab3 1010 $result = $this->callAPISuccess('contribution', 'get', ['return' => 'soft_credit', 'sequential' => 1]);
a1c68fd2 1011
55d2c6f1
EM
1012 $this->assertEquals($softParams['contact_id'], $result['values'][0]['soft_credit'][1]['contact_id']);
1013 $this->assertEquals($softParams['amount'], $result['values'][0]['soft_credit'][1]['amount']);
1014 $this->assertEquals($softParams['soft_credit_type_id'], $result['values'][0]['soft_credit'][1]['soft_credit_type']);
6a516bd6 1015
9099cab3
CW
1016 $this->callAPISuccess('contribution', 'delete', ['id' => $contribution['id']]);
1017 $this->callAPISuccess('contact', 'delete', ['id' => $contact2['id']]);
6a516bd6
DG
1018 }
1019
00be9182 1020 public function testCreateContributionWithSoftCreditDefaults() {
5c49fee0 1021 $description = "Demonstrates creating contribution with Soft Credit defaults for amount and type.";
5896d037 1022 $subfile = "ContributionCreateWithSoftCreditDefaults";
9099cab3 1023 $contact2 = $this->callAPISuccess('Contact', 'create', [
92915c55
TO
1024 'display_name' => 'superman',
1025 'contact_type' => 'Individual',
9099cab3
CW
1026 ]);
1027 $params = $this->_params + [
442cf836 1028 'soft_credit_to' => $contact2['id'],
9099cab3 1029 ];
6a516bd6 1030 $contribution = $this->callAPIAndDocument('contribution', 'create', $params, __FUNCTION__, __FILE__, $description, $subfile);
9099cab3 1031 $result = $this->callAPISuccess('contribution', 'get', ['return' => 'soft_credit', 'sequential' => 1]);
6a516bd6
DG
1032
1033 $this->assertEquals($contact2['id'], $result['values'][0]['soft_credit'][1]['contact_id']);
1034 // Default soft credit amount = contribution.total_amount
1035 $this->assertEquals($this->_params['total_amount'], $result['values'][0]['soft_credit'][1]['amount']);
1036 $this->assertEquals(CRM_Core_OptionGroup::getDefaultValue("soft_credit_type"), $result['values'][0]['soft_credit'][1]['soft_credit_type']);
1037
9099cab3
CW
1038 $this->callAPISuccess('contribution', 'delete', ['id' => $contribution['id']]);
1039 $this->callAPISuccess('contact', 'delete', ['id' => $contact2['id']]);
6a516bd6
DG
1040 }
1041
6c266de6 1042 /**
1043 * Test creating contribution with Soft Credit by passing in honor_contact_id.
1044 */
00be9182 1045 public function testCreateContributionWithHonoreeContact() {
5c49fee0 1046 $description = "Demonstrates creating contribution with Soft Credit by passing in honor_contact_id.";
5896d037 1047 $subfile = "ContributionCreateWithHonoreeContact";
9099cab3 1048 $contact2 = $this->callAPISuccess('Contact', 'create', [
92915c55
TO
1049 'display_name' => 'superman',
1050 'contact_type' => 'Individual',
9099cab3
CW
1051 ]);
1052 $params = $this->_params + [
442cf836 1053 'honor_contact_id' => $contact2['id'],
9099cab3 1054 ];
6a516bd6 1055 $contribution = $this->callAPIAndDocument('contribution', 'create', $params, __FUNCTION__, __FILE__, $description, $subfile);
9099cab3 1056 $result = $this->callAPISuccess('contribution', 'get', ['return' => 'soft_credit', 'sequential' => 1]);
6a516bd6
DG
1057
1058 $this->assertEquals($contact2['id'], $result['values'][0]['soft_credit'][1]['contact_id']);
1059 // Default soft credit amount = contribution.total_amount
1060 // Legacy mode in create api (honor_contact_id param) uses the standard "In Honor of" soft credit type
1061 $this->assertEquals($this->_params['total_amount'], $result['values'][0]['soft_credit'][1]['amount']);
6c266de6 1062 $softCreditValueTypeID = $result['values'][0]['soft_credit'][1]['soft_credit_type'];
1063 $this->assertEquals('in_honor_of', CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_ContributionSoft', 'soft_credit_type_id', $softCreditValueTypeID));
6a488035 1064
9099cab3
CW
1065 $this->callAPISuccess('contribution', 'delete', ['id' => $contribution['id']]);
1066 $this->callAPISuccess('contact', 'delete', ['id' => $contact2['id']]);
6a488035
TO
1067 }
1068
1069 /**
92c99a4a 1070 * Test using example code.
6a488035 1071 */
00be9182 1072 public function testContributionCreateExample() {
6a488035 1073 //make sure at least on page exists since there is a truncate in tear down
8be629ac 1074 $this->callAPISuccess('contribution_page', 'create', $this->_pageParams);
be44cfcb 1075 require_once 'api/v3/examples/Contribution/Create.ex.php';
5896d037 1076 $result = contribution_create_example();
006d6361 1077 $id = $result['id'];
6a488035 1078 $expectedResult = contribution_create_expectedresult();
8e342a79 1079 $this->checkArrayEquals($expectedResult, $result);
006d6361 1080 $this->contributionDelete($id);
6a488035
TO
1081 }
1082
a1a2a83d 1083 /**
f55c5fa8 1084 * Function tests that additional financial records are created when fee amount is recorded.
6a488035 1085 */
00be9182 1086 public function testCreateContributionWithFee() {
9099cab3 1087 $params = [
6a488035
TO
1088 'contact_id' => $this->_individualId,
1089 'receive_date' => '20120511',
1090 'total_amount' => 100.00,
1091 'fee_amount' => 50,
1092 'financial_type_id' => 1,
1093 'trxn_id' => 12345,
1094 'invoice_id' => 67890,
1095 'source' => 'SSF',
1096 'contribution_status_id' => 1,
9099cab3 1097 ];
6a488035 1098
5be22f39 1099 $contribution = $this->callAPISuccess('contribution', 'create', $params);
2bfae985
EM
1100 $this->assertEquals($contribution['values'][$contribution['id']]['contact_id'], $this->_individualId);
1101 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
e0e3c51b
EM
1102 $this->assertEquals($contribution['values'][$contribution['id']]['fee_amount'], 50.00);
1103 $this->assertEquals($contribution['values'][$contribution['id']]['net_amount'], 50.00);
5896d037 1104 $this->assertEquals($contribution['values'][$contribution['id']]['financial_type_id'], 1);
2bfae985
EM
1105 $this->assertEquals($contribution['values'][$contribution['id']]['trxn_id'], 12345);
1106 $this->assertEquals($contribution['values'][$contribution['id']]['invoice_id'], 67890);
1107 $this->assertEquals($contribution['values'][$contribution['id']]['source'], 'SSF');
1108 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status_id'], 1);
e0e3c51b 1109
9099cab3 1110 $lineItems = $this->callAPISuccess('line_item', 'get', [
4ab7d517 1111
6a488035
TO
1112 'entity_id' => $contribution['id'],
1113 'entity_table' => 'civicrm_contribution',
1114 'sequential' => 1,
9099cab3 1115 ]);
6a488035
TO
1116 $this->assertEquals(1, $lineItems['count']);
1117 $this->assertEquals($contribution['id'], $lineItems['values'][0]['entity_id']);
4ede4532 1118 $this->assertEquals($contribution['id'], $lineItems['values'][0]['contribution_id']);
9099cab3 1119 $lineItems = $this->callAPISuccess('line_item', 'get', [
4ab7d517 1120
5896d037
TO
1121 'entity_id' => $contribution['id'],
1122 'contribution_id' => $contribution['id'],
1123 'entity_table' => 'civicrm_contribution',
1124 'sequential' => 1,
9099cab3 1125 ]);
6a488035
TO
1126 $this->assertEquals(1, $lineItems['count']);
1127 $this->_checkFinancialRecords($contribution, 'feeAmount');
1128 }
1129
f70a6752 1130 /**
442cf836 1131 * Function tests that additional financial records are created when online contribution is created.
6a488035 1132 */
00be9182 1133 public function testCreateContributionOnline() {
858d0bf8 1134 CRM_Financial_BAO_PaymentProcessor::create($this->_processorParams);
5896d037 1135 $contributionPage = $this->callAPISuccess('contribution_page', 'create', $this->_pageParams);
fc928539 1136 $this->assertAPISuccess($contributionPage);
9099cab3 1137 $params = [
6a488035
TO
1138 'contact_id' => $this->_individualId,
1139 'receive_date' => '20120511',
1140 'total_amount' => 100.00,
1141 'financial_type_id' => 1,
1142 'contribution_page_id' => $contributionPage['id'],
16f3bd02 1143 'payment_processor' => $this->paymentProcessorID,
6a488035
TO
1144 'trxn_id' => 12345,
1145 'invoice_id' => 67890,
1146 'source' => 'SSF',
1147 'contribution_status_id' => 1,
4ab7d517 1148
9099cab3 1149 ];
6a488035 1150
5be22f39 1151 $contribution = $this->callAPISuccess('contribution', 'create', $params);
2bfae985
EM
1152 $this->assertEquals($contribution['values'][$contribution['id']]['contact_id'], $this->_individualId);
1153 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
5896d037 1154 $this->assertEquals($contribution['values'][$contribution['id']]['financial_type_id'], 1);
2bfae985
EM
1155 $this->assertEquals($contribution['values'][$contribution['id']]['trxn_id'], 12345);
1156 $this->assertEquals($contribution['values'][$contribution['id']]['invoice_id'], 67890);
1157 $this->assertEquals($contribution['values'][$contribution['id']]['source'], 'SSF');
1158 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status_id'], 1);
9099cab3 1159 $contribution['payment_instrument_id'] = $this->callAPISuccessGetValue('PaymentProcessor', [
16f3bd02 1160 'id' => $this->paymentProcessorID,
1161 'return' => 'payment_instrument_id',
9099cab3 1162 ]);
6a488035
TO
1163 $this->_checkFinancialRecords($contribution, 'online');
1164 }
1165
f70a6752 1166 /**
442cf836
EM
1167 * Check handling of financial type.
1168 *
100fef9d 1169 * In the interests of removing financial type / contribution type checks from
f70a6752 1170 * legacy format function lets test that the api is doing this for us
1171 */
00be9182 1172 public function testCreateInvalidFinancialType() {
f70a6752 1173 $params = $this->_params;
1174 $params['financial_type_id'] = 99999;
562e4fb8 1175 $this->callAPIFailure($this->entity, 'create', $params, "'99999' is not a valid option for field financial_type_id");
f70a6752 1176 }
1177
4302618d 1178 /**
442cf836
EM
1179 * Check handling of financial type.
1180 *
100fef9d 1181 * In the interests of removing financial type / contribution type checks from
4302618d 1182 * legacy format function lets test that the api is doing this for us
562e4fb8 1183 *
1184 * @throws \CRM_Core_Exception
4302618d 1185 */
00be9182 1186 public function testValidNamedFinancialType() {
4302618d 1187 $params = $this->_params;
1188 $params['financial_type_id'] = 'Donation';
562e4fb8 1189 $this->callAPISuccess($this->entity, 'create', $params);
4302618d 1190 }
1191
f70a6752 1192 /**
92c99a4a
EM
1193 * Tests that additional financial records are created.
1194 *
1195 * Checks when online contribution with pay later option is created
562e4fb8 1196 *
1197 * @throws \CRM_Core_Exception
6a488035 1198 */
00be9182 1199 public function testCreateContributionPayLaterOnline() {
6a488035 1200 $this->_pageParams['is_pay_later'] = 1;
5896d037 1201 $contributionPage = $this->callAPISuccess('contribution_page', 'create', $this->_pageParams);
fc928539 1202 $this->assertAPISuccess($contributionPage);
9099cab3 1203 $params = [
6a488035
TO
1204 'contact_id' => $this->_individualId,
1205 'receive_date' => '20120511',
1206 'total_amount' => 100.00,
1207 'financial_type_id' => 1,
1208 'contribution_page_id' => $contributionPage['id'],
1209 'trxn_id' => 12345,
1210 'is_pay_later' => 1,
1211 'invoice_id' => 67890,
1212 'source' => 'SSF',
562e4fb8 1213 'contribution_status_id' => 'Pending',
4ab7d517 1214
9099cab3 1215 ];
6a488035 1216
562e4fb8 1217 $contribution = $this->callAPIAndDocument('Contribution', 'create', $params, __FUNCTION__, __FILE__);
1218 $contribution = $contribution['values'][$contribution['id']];
1219 $this->assertEquals($contribution['contact_id'], $this->_individualId);
1220 $this->assertEquals($contribution['total_amount'], 100.00);
1221 $this->assertEquals($contribution['financial_type_id'], 1);
1222 $this->assertEquals($contribution['trxn_id'], 12345);
1223 $this->assertEquals($contribution['invoice_id'], 67890);
1224 $this->assertEquals($contribution['source'], 'SSF');
1225 $this->assertEquals($contribution['contribution_status_id'], 2);
6a488035
TO
1226 $this->_checkFinancialRecords($contribution, 'payLater');
1227 }
1228
a1a2a83d 1229 /**
1e52837d 1230 * Function tests that additional financial records are created for online contribution with pending option.
6a488035 1231 */
00be9182 1232 public function testCreateContributionPendingOnline() {
8a40179e 1233 CRM_Financial_BAO_PaymentProcessor::create($this->_processorParams);
5896d037 1234 $contributionPage = $this->callAPISuccess('contribution_page', 'create', $this->_pageParams);
fc928539 1235 $this->assertAPISuccess($contributionPage);
9099cab3 1236 $params = [
6a488035
TO
1237 'contact_id' => $this->_individualId,
1238 'receive_date' => '20120511',
1239 'total_amount' => 100.00,
1240 'financial_type_id' => 1,
1241 'contribution_page_id' => $contributionPage['id'],
1242 'trxn_id' => 12345,
1243 'invoice_id' => 67890,
1244 'source' => 'SSF',
1245 'contribution_status_id' => 2,
9099cab3 1246 ];
6a488035 1247
5be22f39 1248 $contribution = $this->callAPISuccess('contribution', 'create', $params);
2bfae985
EM
1249 $this->assertEquals($contribution['values'][$contribution['id']]['contact_id'], $this->_individualId);
1250 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
5896d037 1251 $this->assertEquals($contribution['values'][$contribution['id']]['financial_type_id'], 1);
2bfae985
EM
1252 $this->assertEquals($contribution['values'][$contribution['id']]['trxn_id'], 12345);
1253 $this->assertEquals($contribution['values'][$contribution['id']]['invoice_id'], 67890);
1254 $this->assertEquals($contribution['values'][$contribution['id']]['source'], 'SSF');
1255 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status_id'], 2);
6a488035
TO
1256 $this->_checkFinancialRecords($contribution, 'pending');
1257 }
1258
e748bf60 1259 /**
92c99a4a 1260 * Test that BAO defaults work.
562e4fb8 1261 *
1262 * @throws \CRM_Core_Exception
e748bf60 1263 */
00be9182 1264 public function testCreateBAODefaults() {
e748bf60 1265 unset($this->_params['contribution_source_id'], $this->_params['payment_instrument_id']);
562e4fb8 1266 $contribution = $this->callAPISuccess('Contribution', 'create', $this->_params);
1267 $contribution = $this->callAPISuccess('Contribution', 'getsingle', [
92915c55
TO
1268 'id' => $contribution['id'],
1269 'api.contribution.delete' => 1,
9099cab3 1270 ]);
e748bf60 1271 $this->assertEquals(1, $contribution['contribution_status_id']);
12879069 1272 $this->assertEquals('Check', $contribution['payment_instrument']);
8744e9ce 1273 $this->callAPISuccessGetCount('Contribution', ['id' => $contribution['id']], 0);
1274 }
1275
1276 /**
1277 * Test that getsingle can be chained with delete.
562e4fb8 1278 *
1279 * @throws CRM_Core_Exception
8744e9ce 1280 */
1281 public function testDeleteChainedGetSingle() {
562e4fb8 1282 $contribution = $this->callAPISuccess('Contribution', 'create', $this->_params);
1283 $contribution = $this->callAPISuccess('Contribution', 'getsingle', [
8744e9ce 1284 'id' => $contribution['id'],
1285 'api.contribution.delete' => 1,
9099cab3 1286 ]);
8744e9ce 1287 $this->callAPISuccessGetCount('Contribution', ['id' => $contribution['id']], 0);
e748bf60
EM
1288 }
1289
a1a2a83d 1290 /**
1e52837d 1291 * Function tests that line items, financial records are updated when contribution amount is changed.
562e4fb8 1292 *
1293 * @throws \CRM_Core_Exception
6a488035 1294 */
00be9182 1295 public function testCreateUpdateContributionChangeTotal() {
4ab7d517 1296 $contribution = $this->callAPISuccess('contribution', 'create', $this->_params);
9099cab3 1297 $lineItems = $this->callAPISuccess('line_item', 'getvalue', [
4ab7d517 1298
6a488035
TO
1299 'entity_id' => $contribution['id'],
1300 'entity_table' => 'civicrm_contribution',
1301 'sequential' => 1,
1302 'return' => 'line_total',
9099cab3 1303 ]);
6a488035
TO
1304 $this->assertEquals('100.00', $lineItems);
1305 $trxnAmount = $this->_getFinancialTrxnAmount($contribution['id']);
1306 // Financial trxn SUM = 100 + 5 (fee)
1307 $this->assertEquals('105.00', $trxnAmount);
9099cab3 1308 $newParams = [
4ab7d517 1309
6a488035 1310 'id' => $contribution['id'],
21dfd5f5 1311 'total_amount' => '125',
9099cab3 1312 ];
562e4fb8 1313 $contribution = $this->callAPISuccess('Contribution', 'create', $newParams);
4ab7d517 1314
9099cab3 1315 $lineItems = $this->callAPISuccess('line_item', 'getvalue', [
6a488035 1316
5896d037
TO
1317 'entity_id' => $contribution['id'],
1318 'entity_table' => 'civicrm_contribution',
1319 'sequential' => 1,
1320 'return' => 'line_total',
9099cab3 1321 ]);
6a488035
TO
1322
1323 $this->assertEquals('125.00', $lineItems);
1324 $trxnAmount = $this->_getFinancialTrxnAmount($contribution['id']);
28de42d1
EM
1325
1326 // Financial trxn SUM = 125 + 5 (fee).
6a488035 1327 $this->assertEquals('130.00', $trxnAmount);
28de42d1 1328 $this->assertEquals('125.00', $this->_getFinancialItemAmount($contribution['id']));
6a488035
TO
1329 }
1330
a1a2a83d 1331 /**
1e52837d 1332 * Function tests that line items, financial records are updated when pay later contribution is received.
6a488035 1333 */
00be9182 1334 public function testCreateUpdateContributionPayLater() {
9099cab3 1335 $contribParams = [
6a488035
TO
1336 'contact_id' => $this->_individualId,
1337 'receive_date' => '2012-01-01',
1338 'total_amount' => 100.00,
4ab7d517 1339 'financial_type_id' => $this->_financialTypeId,
6a488035 1340 'payment_instrument_id' => 1,
8f39a111 1341 'contribution_status_id' => 2,
1342 'is_pay_later' => 1,
4ab7d517 1343
9099cab3 1344 ];
4ab7d517 1345 $contribution = $this->callAPISuccess('contribution', 'create', $contribParams);
6a488035 1346
9099cab3 1347 $newParams = array_merge($contribParams, [
39b959db
SL
1348 'id' => $contribution['id'],
1349 'contribution_status_id' => 1,
9099cab3 1350 ]);
694769da 1351 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
6a488035 1352 $contribution = $contribution['values'][$contribution['id']];
6c6e6187 1353 $this->assertEquals($contribution['contribution_status_id'], '1');
6a488035
TO
1354 $this->_checkFinancialItem($contribution['id'], 'paylater');
1355 $this->_checkFinancialTrxn($contribution, 'payLater');
1356 }
1357
a1a2a83d 1358 /**
eceb18cc 1359 * Function tests that financial records are updated when Payment Instrument is changed.
6a488035 1360 */
00be9182 1361 public function testCreateUpdateContributionPaymentInstrument() {
6a488035 1362 $instrumentId = $this->_addPaymentInstrument();
9099cab3 1363 $contribParams = [
6a488035
TO
1364 'contact_id' => $this->_individualId,
1365 'total_amount' => 100.00,
4ab7d517 1366 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
1367 'payment_instrument_id' => 4,
1368 'contribution_status_id' => 1,
4ab7d517 1369
9099cab3 1370 ];
4ab7d517 1371 $contribution = $this->callAPISuccess('contribution', 'create', $contribParams);
6a488035 1372
9099cab3 1373 $newParams = array_merge($contribParams, [
39b959db
SL
1374 'id' => $contribution['id'],
1375 'payment_instrument_id' => $instrumentId,
9099cab3 1376 ]);
694769da 1377 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
fc928539 1378 $this->assertAPISuccess($contribution);
b0e806fa 1379 $this->checkFinancialTrxnPaymentInstrumentChange($contribution['id'], 4, $instrumentId);
02a9c0a4 1380
1381 // cleanup - delete created payment instrument
1382 $this->_deletedAddedPaymentInstrument();
6a488035
TO
1383 }
1384
122250ec
SL
1385 /**
1386 * Function tests that financial records are updated when Payment Instrument is changed when amount is negative.
1387 */
1388 public function testCreateUpdateNegativeContributionPaymentInstrument() {
1389 $instrumentId = $this->_addPaymentInstrument();
9099cab3 1390 $contribParams = [
122250ec
SL
1391 'contact_id' => $this->_individualId,
1392 'total_amount' => -100.00,
1393 'financial_type_id' => $this->_financialTypeId,
1394 'payment_instrument_id' => 4,
1395 'contribution_status_id' => 1,
1396
9099cab3 1397 ];
122250ec
SL
1398 $contribution = $this->callAPISuccess('contribution', 'create', $contribParams);
1399
9099cab3 1400 $newParams = array_merge($contribParams, [
39b959db
SL
1401 'id' => $contribution['id'],
1402 'payment_instrument_id' => $instrumentId,
9099cab3 1403 ]);
122250ec
SL
1404 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
1405 $this->assertAPISuccess($contribution);
b0e806fa 1406 $this->checkFinancialTrxnPaymentInstrumentChange($contribution['id'], 4, $instrumentId, -100);
02a9c0a4 1407
1408 // cleanup - delete created payment instrument
1409 $this->_deletedAddedPaymentInstrument();
122250ec
SL
1410 }
1411
a1a2a83d 1412 /**
eceb18cc 1413 * Function tests that financial records are added when Contribution is Refunded.
05a42c4a 1414 *
1415 * @throws \CRM_Core_Exception
6a488035 1416 */
00be9182 1417 public function testCreateUpdateContributionRefund() {
9099cab3 1418 $contributionParams = [
6a488035
TO
1419 'contact_id' => $this->_individualId,
1420 'receive_date' => '2012-01-01',
1421 'total_amount' => 100.00,
4ab7d517 1422 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
1423 'payment_instrument_id' => 4,
1424 'contribution_status_id' => 1,
797d4c52 1425 'trxn_id' => 'original_payment',
9099cab3 1426 ];
562e4fb8 1427 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
9099cab3 1428 $newParams = array_merge($contributionParams, [
39b959db
SL
1429 'id' => $contribution['id'],
1430 'contribution_status_id' => 'Refunded',
1431 'cancel_date' => '2015-01-01 09:00',
1432 'refund_trxn_id' => 'the refund',
9099cab3 1433 ]);
797d4c52 1434
1435 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
1436 $this->_checkFinancialTrxn($contribution, 'refund');
1437 $this->_checkFinancialItem($contribution['id'], 'refund');
9099cab3 1438 $this->assertEquals('original_payment', $this->callAPISuccessGetValue('Contribution', [
797d4c52 1439 'id' => $contribution['id'],
1440 'return' => 'trxn_id',
9099cab3 1441 ]));
797d4c52 1442 }
4ab7d517 1443
52da5b1e 1444 /**
1445 * Refund a contribution for a financial type with a contra account.
1446 *
1447 * CRM-17951 the contra account is a financial account with a relationship to a
1448 * financial type. It is not always configured but should be reflected
1449 * in the financial_trxn & financial_item table if it is.
f0d18278 1450 *
1451 * @throws \CRM_Core_Exception
52da5b1e 1452 */
1453 public function testCreateUpdateChargebackContributionDefaultAccount() {
1454 $contribution = $this->callAPISuccess('Contribution', 'create', $this->_params);
9099cab3 1455 $this->callAPISuccess('Contribution', 'create', [
52da5b1e 1456 'id' => $contribution['id'],
1457 'contribution_status_id' => 'Chargeback',
9099cab3
CW
1458 ]);
1459 $this->callAPISuccessGetSingle('Contribution', ['contribution_status_id' => 'Chargeback']);
52da5b1e 1460
9099cab3 1461 $lineItems = $this->callAPISuccessGetSingle('LineItem', [
52da5b1e 1462 'contribution_id' => $contribution['id'],
9099cab3
CW
1463 'api.FinancialItem.getsingle' => ['amount' => ['<' => 0]],
1464 ]);
52da5b1e 1465 $this->assertEquals(1, $lineItems['api.FinancialItem.getsingle']['financial_account_id']);
9099cab3 1466 $this->callAPISuccessGetSingle('FinancialTrxn', [
52da5b1e 1467 'total_amount' => -100,
1468 'status_id' => 'Chargeback',
1469 'to_financial_account_id' => 6,
9099cab3 1470 ]);
52da5b1e 1471 }
1472
1473 /**
1474 * Refund a contribution for a financial type with a contra account.
1475 *
1476 * CRM-17951 the contra account is a financial account with a relationship to a
1477 * financial type. It is not always configured but should be reflected
1478 * in the financial_trxn & financial_item table if it is.
05a42c4a 1479 *
1480 * @throws \CRM_Core_Exception
52da5b1e 1481 */
1482 public function testCreateUpdateChargebackContributionCustomAccount() {
9099cab3 1483 $financialAccount = $this->callAPISuccess('FinancialAccount', 'create', [
52da5b1e 1484 'name' => 'Chargeback Account',
1485 'is_active' => TRUE,
9099cab3 1486 ]);
52da5b1e 1487
9099cab3 1488 $entityFinancialAccount = $this->callAPISuccess('EntityFinancialAccount', 'create', [
52da5b1e 1489 'entity_id' => $this->_financialTypeId,
1490 'entity_table' => 'civicrm_financial_type',
1491 'account_relationship' => 'Chargeback Account is',
1492 'financial_account_id' => 'Chargeback Account',
9099cab3 1493 ]);
52da5b1e 1494
1495 $contribution = $this->callAPISuccess('Contribution', 'create', $this->_params);
9099cab3 1496 $this->callAPISuccess('Contribution', 'create', [
52da5b1e 1497 'id' => $contribution['id'],
1498 'contribution_status_id' => 'Chargeback',
9099cab3
CW
1499 ]);
1500 $this->callAPISuccessGetSingle('Contribution', ['contribution_status_id' => 'Chargeback']);
52da5b1e 1501
9099cab3 1502 $lineItems = $this->callAPISuccessGetSingle('LineItem', [
52da5b1e 1503 'contribution_id' => $contribution['id'],
9099cab3
CW
1504 'api.FinancialItem.getsingle' => ['amount' => ['<' => 0]],
1505 ]);
52da5b1e 1506 $this->assertEquals($financialAccount['id'], $lineItems['api.FinancialItem.getsingle']['financial_account_id']);
1507
9099cab3
CW
1508 $this->callAPISuccess('Contribution', 'delete', ['id' => $contribution['id']]);
1509 $this->callAPISuccess('EntityFinancialAccount', 'delete', ['id' => $entityFinancialAccount['id']]);
1510 $this->callAPISuccess('FinancialAccount', 'delete', ['id' => $financialAccount['id']]);
52da5b1e 1511 }
1512
bf2cf926 1513 /**
1514 * Refund a contribution for a financial type with a contra account.
1515 *
1516 * CRM-17951 the contra account is a financial account with a relationship to a
1517 * financial type. It is not always configured but should be reflected
1518 * in the financial_trxn & financial_item table if it is.
1519 */
1520 public function testCreateUpdateRefundContributionConfiguredContraAccount() {
9099cab3 1521 $financialAccount = $this->callAPISuccess('FinancialAccount', 'create', [
bf2cf926 1522 'name' => 'Refund Account',
1523 'is_active' => TRUE,
9099cab3 1524 ]);
bf2cf926 1525
9099cab3 1526 $entityFinancialAccount = $this->callAPISuccess('EntityFinancialAccount', 'create', [
bf2cf926 1527 'entity_id' => $this->_financialTypeId,
1528 'entity_table' => 'civicrm_financial_type',
1529 'account_relationship' => 'Credit/Contra Revenue Account is',
1530 'financial_account_id' => 'Refund Account',
9099cab3 1531 ]);
bf2cf926 1532
1533 $contribution = $this->callAPISuccess('Contribution', 'create', $this->_params);
9099cab3 1534 $this->callAPISuccess('Contribution', 'create', [
bf2cf926 1535 'id' => $contribution['id'],
1536 'contribution_status_id' => 'Refunded',
9099cab3 1537 ]);
bf2cf926 1538
9099cab3 1539 $lineItems = $this->callAPISuccessGetSingle('LineItem', [
bf2cf926 1540 'contribution_id' => $contribution['id'],
9099cab3
CW
1541 'api.FinancialItem.getsingle' => ['amount' => ['<' => 0]],
1542 ]);
bf2cf926 1543 $this->assertEquals($financialAccount['id'], $lineItems['api.FinancialItem.getsingle']['financial_account_id']);
1544
9099cab3
CW
1545 $this->callAPISuccess('Contribution', 'delete', ['id' => $contribution['id']]);
1546 $this->callAPISuccess('EntityFinancialAccount', 'delete', ['id' => $entityFinancialAccount['id']]);
1547 $this->callAPISuccess('FinancialAccount', 'delete', ['id' => $financialAccount['id']]);
bf2cf926 1548 }
1549
797d4c52 1550 /**
1551 * Function tests that trxn_id is set when passed in.
1552 *
1553 * Here we ensure that the civicrm_financial_trxn.trxn_id & the civicrm_contribution.trxn_id are set
1554 * when trxn_id is passed in.
1555 */
1556 public function testCreateUpdateContributionRefundTrxnIDPassedIn() {
9099cab3 1557 $contributionParams = [
797d4c52 1558 'contact_id' => $this->_individualId,
1559 'receive_date' => '2012-01-01',
1560 'total_amount' => 100.00,
1561 'financial_type_id' => $this->_financialTypeId,
1562 'payment_instrument_id' => 4,
1563 'contribution_status_id' => 1,
1564 'trxn_id' => 'original_payment',
9099cab3 1565 ];
797d4c52 1566 $contribution = $this->callAPISuccess('contribution', 'create', $contributionParams);
9099cab3 1567 $newParams = array_merge($contributionParams, [
39b959db
SL
1568 'id' => $contribution['id'],
1569 'contribution_status_id' => 'Refunded',
1570 'cancel_date' => '2015-01-01 09:00',
1571 'trxn_id' => 'the refund',
9099cab3 1572 ]);
797d4c52 1573
1574 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
1575 $this->_checkFinancialTrxn($contribution, 'refund');
1576 $this->_checkFinancialItem($contribution['id'], 'refund');
9099cab3 1577 $this->assertEquals('the refund', $this->callAPISuccessGetValue('Contribution', [
797d4c52 1578 'id' => $contribution['id'],
1579 'return' => 'trxn_id',
9099cab3 1580 ]));
797d4c52 1581 }
1582
1583 /**
1584 * Function tests that trxn_id is set when passed in.
1585 *
1586 * Here we ensure that the civicrm_contribution.trxn_id is set
1587 * when trxn_id is passed in but if refund_trxn_id is different then that
1588 * is kept for the refund transaction.
1589 */
1590 public function testCreateUpdateContributionRefundRefundAndTrxnIDPassedIn() {
9099cab3 1591 $contributionParams = [
797d4c52 1592 'contact_id' => $this->_individualId,
1593 'receive_date' => '2012-01-01',
1594 'total_amount' => 100.00,
1595 'financial_type_id' => $this->_financialTypeId,
1596 'payment_instrument_id' => 4,
1597 'contribution_status_id' => 1,
1598 'trxn_id' => 'original_payment',
9099cab3 1599 ];
797d4c52 1600 $contribution = $this->callAPISuccess('contribution', 'create', $contributionParams);
9099cab3 1601 $newParams = array_merge($contributionParams, [
39b959db
SL
1602 'id' => $contribution['id'],
1603 'contribution_status_id' => 'Refunded',
1604 'cancel_date' => '2015-01-01 09:00',
1605 'trxn_id' => 'cont id',
1606 'refund_trxn_id' => 'the refund',
9099cab3 1607 ]);
6a488035 1608
694769da 1609 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
6a488035
TO
1610 $this->_checkFinancialTrxn($contribution, 'refund');
1611 $this->_checkFinancialItem($contribution['id'], 'refund');
9099cab3 1612 $this->assertEquals('cont id', $this->callAPISuccessGetValue('Contribution', [
797d4c52 1613 'id' => $contribution['id'],
1614 'return' => 'trxn_id',
9099cab3 1615 ]));
797d4c52 1616 }
1617
1618 /**
1619 * Function tests that refund_trxn_id is set when passed in empty.
1620 *
1621 * Here we ensure that the civicrm_contribution.trxn_id is set
1622 * when trxn_id is passed in but if refund_trxn_id isset but empty then that
1623 * is kept for the refund transaction.
1624 */
1625 public function testCreateUpdateContributionRefundRefundNullTrxnIDPassedIn() {
9099cab3 1626 $contributionParams = [
797d4c52 1627 'contact_id' => $this->_individualId,
1628 'receive_date' => '2012-01-01',
1629 'total_amount' => 100.00,
1630 'financial_type_id' => $this->_financialTypeId,
1631 'payment_instrument_id' => 4,
1632 'contribution_status_id' => 1,
1633 'trxn_id' => 'original_payment',
9099cab3 1634 ];
797d4c52 1635 $contribution = $this->callAPISuccess('contribution', 'create', $contributionParams);
9099cab3 1636 $newParams = array_merge($contributionParams, [
39b959db
SL
1637 'id' => $contribution['id'],
1638 'contribution_status_id' => 'Refunded',
1639 'cancel_date' => '2015-01-01 09:00',
1640 'trxn_id' => 'cont id',
1641 'refund_trxn_id' => '',
9099cab3 1642 ]);
797d4c52 1643
1644 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
9099cab3 1645 $this->_checkFinancialTrxn($contribution, 'refund', NULL, ['trxn_id' => NULL]);
797d4c52 1646 $this->_checkFinancialItem($contribution['id'], 'refund');
9099cab3 1647 $this->assertEquals('cont id', $this->callAPISuccessGetValue('Contribution', [
797d4c52 1648 'id' => $contribution['id'],
1649 'return' => 'trxn_id',
9099cab3 1650 ]));
8f39a111 1651 }
c71ae314 1652
a1a2a83d 1653 /**
eceb18cc 1654 * Function tests invalid contribution status change.
c71ae314 1655 */
00be9182 1656 public function testCreateUpdateContributionInValidStatusChange() {
9099cab3 1657 $contribParams = [
c71ae314
PN
1658 'contact_id' => 1,
1659 'receive_date' => '2012-01-01',
1660 'total_amount' => 100.00,
1661 'financial_type_id' => 1,
1662 'payment_instrument_id' => 1,
1663 'contribution_status_id' => 1,
9099cab3 1664 ];
4ab7d517 1665 $contribution = $this->callAPISuccess('contribution', 'create', $contribParams);
9099cab3 1666 $newParams = array_merge($contribParams, [
39b959db
SL
1667 'id' => $contribution['id'],
1668 'contribution_status_id' => 2,
9099cab3 1669 ]);
6c6e6187 1670 $this->callAPIFailure('contribution', 'create', $newParams, ts('Cannot change contribution status from Completed to Pending.'));
c71ae314 1671
6a488035
TO
1672 }
1673
a1a2a83d 1674 /**
eceb18cc 1675 * Function tests that financial records are added when Pending Contribution is Canceled.
fbc465d7 1676 *
1677 * @throws \CRM_Core_Exception
6a488035 1678 */
00be9182 1679 public function testCreateUpdateContributionCancelPending() {
9099cab3 1680 $contribParams = [
6a488035
TO
1681 'contact_id' => $this->_individualId,
1682 'receive_date' => '2012-01-01',
1683 'total_amount' => 100.00,
4ab7d517 1684 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
1685 'payment_instrument_id' => 1,
1686 'contribution_status_id' => 2,
c71ae314 1687 'is_pay_later' => 1,
4ab7d517 1688
9099cab3 1689 ];
4ab7d517 1690 $contribution = $this->callAPISuccess('contribution', 'create', $contribParams);
9099cab3 1691 $newParams = array_merge($contribParams, [
39b959db
SL
1692 'id' => $contribution['id'],
1693 'contribution_status_id' => 3,
1694 'cancel_date' => '2012-02-02 09:00',
9099cab3 1695 ]);
0a8160e8 1696 //Check if trxn_date is same as cancel_date.
9099cab3 1697 $checkTrxnDate = [
0a8160e8 1698 'trxn_date' => '2012-02-02 09:00:00',
9099cab3 1699 ];
694769da 1700 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
0a8160e8 1701 $this->_checkFinancialTrxn($contribution, 'cancelPending', NULL, $checkTrxnDate);
6a488035
TO
1702 $this->_checkFinancialItem($contribution['id'], 'cancelPending');
1703 }
1704
a1a2a83d 1705 /**
eceb18cc 1706 * Function tests that financial records are added when Financial Type is Changed.
592a64a0 1707 *
1708 * @throws \CRM_Core_Exception
6a488035 1709 */
00be9182 1710 public function testCreateUpdateContributionChangeFinancialType() {
9099cab3 1711 $contribParams = [
6a488035
TO
1712 'contact_id' => $this->_individualId,
1713 'receive_date' => '2012-01-01',
1714 'total_amount' => 100.00,
1715 'financial_type_id' => 1,
1716 'payment_instrument_id' => 1,
1717 'contribution_status_id' => 1,
4ab7d517 1718
9099cab3 1719 ];
4ab7d517 1720 $contribution = $this->callAPISuccess('contribution', 'create', $contribParams);
9099cab3 1721 $newParams = array_merge($contribParams, [
39b959db
SL
1722 'id' => $contribution['id'],
1723 'financial_type_id' => 3,
9099cab3 1724 ]);
694769da 1725 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
6a488035
TO
1726 $this->_checkFinancialTrxn($contribution, 'changeFinancial');
1727 $this->_checkFinancialItem($contribution['id'], 'changeFinancial');
1728 }
1729
1a3d69b0
SL
1730 /**
1731 * Function tets that financial records are correctly added when financial type is changed
1732 *
1733 * @throws \CRM_Core_Exception
1734 */
1735 public function testCreateUpdateContributionWithFeeAmountChangeFinancialType() {
1736 $contribParams = [
1737 'contact_id' => $this->_individualId,
1738 'receive_date' => '2012-01-01',
1739 'total_amount' => 100.00,
1740 'fee_amount' => 0.57,
1741 'financial_type_id' => 1,
1742 'payment_instrument_id' => 1,
1743 'contribution_status_id' => 1,
1744
1745 ];
1746 $contribution = $this->callAPISuccess('contribution', 'create', $contribParams);
1747 $newParams = array_merge($contribParams, [
1748 'id' => $contribution['id'],
1749 'financial_type_id' => 3,
1750 ]);
1751 $contribution = $this->callAPISuccess('contribution', 'create', $newParams);
1752 $this->_checkFinancialTrxn($contribution, 'changeFinancial', NULL, ['fee_amount' => '-0.57', 'net_amount' => '-99.43']);
1753 $this->_checkFinancialItem($contribution['id'], 'changeFinancial');
1754 }
1755
694769da 1756 /**
1e52837d 1757 * Test that update does not change status id CRM-15105.
694769da 1758 */
00be9182 1759 public function testCreateUpdateWithoutChangingPendingStatus() {
9099cab3
CW
1760 $contribution = $this->callAPISuccess('contribution', 'create', array_merge($this->_params, ['contribution_status_id' => 2]));
1761 $this->callAPISuccess('contribution', 'create', ['id' => $contribution['id'], 'source' => 'new source']);
1762 $contribution = $this->callAPISuccess('contribution', 'getsingle', [
92915c55
TO
1763 'id' => $contribution['id'],
1764 'api.contribution.delete' => 1,
9099cab3 1765 ]);
694769da
VU
1766 $this->assertEquals(2, $contribution['contribution_status_id']);
1767 }
a1a2a83d
TO
1768
1769 /**
28de42d1
EM
1770 * Test Updating a Contribution.
1771 *
a1a2a83d
TO
1772 * CHANGE: we require the API to do an incremental update
1773 */
00be9182 1774 public function testCreateUpdateContribution() {
9099cab3 1775 $contributionID = $this->contributionCreate([
78ab0ca4 1776 'contact_id' => $this->_individualId,
1777 'trxn_id' => 212355,
1778 'financial_type_id' => $this->_financialTypeId,
1779 'invoice_id' => 'old_invoice',
9099cab3
CW
1780 ]);
1781 $old_params = [
6a488035 1782 'contribution_id' => $contributionID,
9099cab3 1783 ];
4ab7d517 1784 $original = $this->callAPISuccess('contribution', 'get', $old_params);
2bfae985 1785 $this->assertEquals($original['id'], $contributionID);
6a488035
TO
1786 //set up list of old params, verify
1787
1788 //This should not be required on update:
1789 $old_contact_id = $original['values'][$contributionID]['contact_id'];
7d543448 1790 $old_payment_instrument = $original['values'][$contributionID]['instrument_id'];
6a488035
TO
1791 $old_fee_amount = $original['values'][$contributionID]['fee_amount'];
1792 $old_source = $original['values'][$contributionID]['contribution_source'];
1793
6a488035
TO
1794 $old_trxn_id = $original['values'][$contributionID]['trxn_id'];
1795 $old_invoice_id = $original['values'][$contributionID]['invoice_id'];
1796
1797 //check against values in CiviUnitTestCase::createContribution()
2bfae985
EM
1798 $this->assertEquals($old_contact_id, $this->_individualId);
1799 $this->assertEquals($old_fee_amount, 5.00);
1800 $this->assertEquals($old_source, 'SSF');
1801 $this->assertEquals($old_trxn_id, 212355);
78ab0ca4 1802 $this->assertEquals($old_invoice_id, 'old_invoice');
9099cab3 1803 $params = [
6a488035
TO
1804 'id' => $contributionID,
1805 'contact_id' => $this->_individualId,
09201732
K
1806 'total_amount' => 105.00,
1807 'fee_amount' => 7.00,
4ab7d517 1808 'financial_type_id' => $this->_financialTypeId,
09201732 1809 'non_deductible_amount' => 22.00,
6a488035 1810 'contribution_status_id' => 1,
ef32adff 1811 'note' => 'Donating for Noble Cause',
9099cab3 1812 ];
6a488035 1813
4ab7d517 1814 $contribution = $this->callAPISuccess('contribution', 'create', $params);
6a488035 1815
9099cab3 1816 $new_params = [
6a488035 1817 'contribution_id' => $contribution['id'],
9099cab3 1818 ];
ef32adff 1819 $contribution = $this->callAPISuccessGetSingle('contribution', $new_params);
1820
1821 $this->assertEquals($contribution['contact_id'], $this->_individualId);
09201732 1822 $this->assertEquals($contribution['total_amount'], 105.00);
ef32adff 1823 $this->assertEquals($contribution['financial_type_id'], $this->_financialTypeId);
1824 $this->assertEquals($contribution['financial_type'], 'Donation');
1825 $this->assertEquals($contribution['instrument_id'], $old_payment_instrument);
09201732
K
1826 $this->assertEquals($contribution['non_deductible_amount'], 22.00);
1827 $this->assertEquals($contribution['fee_amount'], 7.00);
ef32adff 1828 $this->assertEquals($contribution['trxn_id'], $old_trxn_id);
1829 $this->assertEquals($contribution['invoice_id'], $old_invoice_id);
1830 $this->assertEquals($contribution['contribution_source'], $old_source);
1831 $this->assertEquals($contribution['contribution_status'], 'Completed');
09201732
K
1832
1833 $this->assertEquals($contribution['net_amount'], $contribution['total_amount'] - $contribution['fee_amount']);
1834
9099cab3 1835 $params = [
6a488035 1836 'contribution_id' => $contributionID,
9099cab3 1837 ];
4ab7d517 1838 $result = $this->callAPISuccess('contribution', 'delete', $params);
22f80e87 1839 $this->assertAPISuccess($result);
6a488035
TO
1840 }
1841
a3c2cbe6 1842 /**
1843 * Check that net_amount is updated when a contribution is updated.
1844 *
1845 * Update fee amount AND total amount, just fee amount, just total amount
1846 * and neither to check that net_amount is keep updated.
1847 */
1848 public function testUpdateContributionNetAmountVariants() {
1849 $contributionID = $this->contributionCreate(['contact_id' => $this->individualCreate()]);
1850
1851 $this->callAPISuccess('Contribution', 'create', [
1852 'id' => $contributionID,
1853 'total_amount' => 90,
1854 'fee_amount' => 6,
1855 ]);
1856 $contribution = $this->callAPISuccessGetSingle('Contribution', [
1857 'id' => $contributionID,
1858 'return' => ['net_amount', 'fee_amount', 'total_amount'],
1859 ]);
1860 $this->assertEquals(6, $contribution['fee_amount']);
1861 $this->assertEquals(90, $contribution['total_amount']);
1862 $this->assertEquals(84, $contribution['net_amount']);
1863
1864 $this->callAPISuccess('Contribution', 'create', [
1865 'id' => $contributionID,
1866 'fee_amount' => 3,
1867 ]);
1868 $contribution = $this->callAPISuccessGetSingle('Contribution', [
1869 'id' => $contributionID,
1870 'return' => ['net_amount', 'fee_amount', 'total_amount'],
1871 ]);
1872 $this->assertEquals(3, $contribution['fee_amount']);
1873 $this->assertEquals(90, $contribution['total_amount']);
1874 $this->assertEquals(87, $contribution['net_amount']);
1875
1876 $this->callAPISuccess('Contribution', 'create', [
1877 'id' => $contributionID,
1878 'total_amount' => 200,
1879 ]);
1880 $contribution = $this->callAPISuccessGetSingle('Contribution', [
1881 'id' => $contributionID,
1882 'return' => ['net_amount', 'fee_amount', 'total_amount'],
1883 ]);
1884 $this->assertEquals(3, $contribution['fee_amount']);
1885 $this->assertEquals(200, $contribution['total_amount']);
1886 $this->assertEquals(197, $contribution['net_amount']);
1887
1888 $this->callAPISuccess('Contribution', 'create', [
1889 'id' => $contributionID,
39b959db 1890 'payment_instrument' => 'Cash',
a3c2cbe6 1891 ]);
1892 $contribution = $this->callAPISuccessGetSingle('Contribution', [
1893 'id' => $contributionID,
1894 'return' => ['net_amount', 'fee_amount', 'total_amount'],
1895 ]);
1896 $this->assertEquals(3, $contribution['fee_amount']);
1897 $this->assertEquals(200, $contribution['total_amount']);
1898 $this->assertEquals(197, $contribution['net_amount']);
1899 }
1900
a1a2a83d
TO
1901 /**
1902 * Attempt (but fail) to delete a contribution without parameters.
1903 */
00be9182 1904 public function testDeleteEmptyParamsContribution() {
9099cab3 1905 $params = [];
858d0bf8 1906 $this->callAPIFailure('contribution', 'delete', $params);
6a488035
TO
1907 }
1908
00be9182 1909 public function testDeleteParamsNotArrayContribution() {
3241b690 1910 $this->expectException(TypeError::class);
6a488035 1911 $params = 'contribution_id= 1';
d0e1eff2 1912 $contribution = $this->callAPIFailure('contribution', 'delete', $params);
6a488035
TO
1913 }
1914
00be9182 1915 public function testDeleteWrongParamContribution() {
9099cab3 1916 $params = [
6a488035 1917 'contribution_source' => 'SSF',
9099cab3 1918 ];
858d0bf8 1919 $this->callAPIFailure('contribution', 'delete', $params);
6a488035
TO
1920 }
1921
00be9182 1922 public function testDeleteContribution() {
9099cab3 1923 $contributionID = $this->contributionCreate([
78ab0ca4 1924 'contact_id' => $this->_individualId,
1925 'financial_type_id' => $this->_financialTypeId,
9099cab3
CW
1926 ]);
1927 $params = [
6a488035 1928 'id' => $contributionID,
9099cab3 1929 ];
4ab7d517 1930 $this->callAPIAndDocument('contribution', 'delete', $params, __FUNCTION__, __FILE__);
6a488035
TO
1931 }
1932
1933 /**
d177a2a6 1934 * Test civicrm_contribution_search with empty params.
1e52837d 1935 *
d177a2a6 1936 * All available contributions expected.
6a488035 1937 */
00be9182 1938 public function testSearchEmptyParams() {
9099cab3 1939 $params = [];
6a488035 1940
9099cab3 1941 $p = [
6a488035
TO
1942 'contact_id' => $this->_individualId,
1943 'receive_date' => date('Ymd'),
1944 'total_amount' => 100.00,
4ab7d517 1945 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
1946 'non_deductible_amount' => 10.00,
1947 'fee_amount' => 5.00,
1948 'net_amount' => 95.00,
1949 'trxn_id' => 23456,
1950 'invoice_id' => 78910,
1951 'source' => 'SSF',
1952 'contribution_status_id' => 1,
9099cab3 1953 ];
4ab7d517 1954 $contribution = $this->callAPISuccess('contribution', 'create', $p);
6a488035 1955
4ab7d517 1956 $result = $this->callAPISuccess('contribution', 'get', $params);
6a488035
TO
1957 // We're taking the first element.
1958 $res = $result['values'][$contribution['id']];
1959
2bfae985
EM
1960 $this->assertEquals($p['contact_id'], $res['contact_id']);
1961 $this->assertEquals($p['total_amount'], $res['total_amount']);
5896d037 1962 $this->assertEquals($p['financial_type_id'], $res['financial_type_id']);
2bfae985
EM
1963 $this->assertEquals($p['net_amount'], $res['net_amount']);
1964 $this->assertEquals($p['non_deductible_amount'], $res['non_deductible_amount']);
1965 $this->assertEquals($p['fee_amount'], $res['fee_amount']);
1966 $this->assertEquals($p['trxn_id'], $res['trxn_id']);
1967 $this->assertEquals($p['invoice_id'], $res['invoice_id']);
1968 $this->assertEquals($p['source'], $res['contribution_source']);
6a488035 1969 // contribution_status_id = 1 => Completed
2bfae985 1970 $this->assertEquals('Completed', $res['contribution_status']);
6a488035
TO
1971
1972 $this->contributionDelete($contribution['id']);
1973 }
1974
1975 /**
d177a2a6 1976 * Test civicrm_contribution_search. Success expected.
6a488035 1977 */
00be9182 1978 public function testSearch() {
9099cab3 1979 $p1 = [
6a488035
TO
1980 'contact_id' => $this->_individualId,
1981 'receive_date' => date('Ymd'),
1982 'total_amount' => 100.00,
4ab7d517 1983 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
1984 'non_deductible_amount' => 10.00,
1985 'contribution_status_id' => 1,
9099cab3 1986 ];
4ab7d517 1987 $contribution1 = $this->callAPISuccess('contribution', 'create', $p1);
6a488035 1988
9099cab3 1989 $p2 = [
6a488035
TO
1990 'contact_id' => $this->_individualId,
1991 'receive_date' => date('Ymd'),
1992 'total_amount' => 200.00,
4ab7d517 1993 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
1994 'non_deductible_amount' => 20.00,
1995 'trxn_id' => 5454565,
1996 'invoice_id' => 1212124,
1997 'fee_amount' => 50.00,
1998 'net_amount' => 60.00,
1999 'contribution_status_id' => 2,
9099cab3 2000 ];
2f45e1c2 2001 $contribution2 = $this->callAPISuccess('contribution', 'create', $p2);
6a488035 2002
9099cab3 2003 $params = [
6a488035 2004 'contribution_id' => $contribution2['id'],
9099cab3 2005 ];
2f45e1c2 2006 $result = $this->callAPISuccess('contribution', 'get', $params);
6a488035
TO
2007 $res = $result['values'][$contribution2['id']];
2008
2bfae985
EM
2009 $this->assertEquals($p2['contact_id'], $res['contact_id']);
2010 $this->assertEquals($p2['total_amount'], $res['total_amount']);
5896d037 2011 $this->assertEquals($p2['financial_type_id'], $res['financial_type_id']);
2bfae985
EM
2012 $this->assertEquals($p2['net_amount'], $res['net_amount']);
2013 $this->assertEquals($p2['non_deductible_amount'], $res['non_deductible_amount']);
2014 $this->assertEquals($p2['fee_amount'], $res['fee_amount']);
2015 $this->assertEquals($p2['trxn_id'], $res['trxn_id']);
2016 $this->assertEquals($p2['invoice_id'], $res['invoice_id']);
91786f44 2017 $this->assertEquals(CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'), $res['contribution_status_id']);
6a488035
TO
2018
2019 $this->contributionDelete($contribution1['id']);
2020 $this->contributionDelete($contribution2['id']);
2021 }
2f45e1c2 2022
0efa8efe 2023 /**
eceb18cc 2024 * Test completing a transaction via the API.
0efa8efe 2025 *
2026 * Note that we are creating a logged in user because email goes out from
2027 * that person
2028 */
00be9182 2029 public function testCompleteTransaction() {
5896d037 2030 $mut = new CiviMailUtils($this, TRUE);
ec7e3954 2031 $this->swapMessageTemplateForTestTemplate();
0efa8efe 2032 $this->createLoggedInUser();
9099cab3 2033 $params = array_merge($this->_params, ['contribution_status_id' => 2]);
6c6e6187 2034 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 2035 $this->callAPISuccess('contribution', 'completetransaction', [
0efa8efe 2036 'id' => $contribution['id'],
9099cab3
CW
2037 ]);
2038 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['id' => $contribution['id']]);
d5580ed4 2039 $this->assertEquals('SSF', $contribution['contribution_source']);
cc7b912f 2040 $this->assertEquals('Completed', $contribution['contribution_status']);
2041 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contribution['receipt_date'])));
9099cab3 2042 $mut->checkMailLog([
ec7e3954
E
2043 'email:::anthony_anderson@civicrm.org',
2044 'is_monetary:::1',
2045 'amount:::100.00',
2046 'currency:::USD',
2047 'receive_date:::' . date('Ymd', strtotime($contribution['receive_date'])),
76e8d9c4 2048 "receipt_date:::\n",
8a40179e 2049 'contributeMode:::notify',
2050 'title:::Contribution',
2051 'displayName:::Mr. Anthony Anderson II',
2052 'contributionStatus:::Completed',
9099cab3 2053 ]);
8a40179e 2054 $mut->stop();
2055 $this->revertTemplateToReservedTemplate();
2056 }
2057
2058 /**
2059 * Test completing a transaction via the API with a non-USD transaction.
2060 */
2061 public function testCompleteTransactionEuro() {
2062 $mut = new CiviMailUtils($this, TRUE);
2063 $this->swapMessageTemplateForTestTemplate();
2064 $this->createLoggedInUser();
9099cab3 2065 $params = array_merge($this->_params, ['contribution_status_id' => 2, 'currency' => 'EUR']);
8a40179e 2066 $contribution = $this->callAPISuccess('contribution', 'create', $params);
2067
9099cab3 2068 $this->callAPISuccess('contribution', 'completetransaction', [
8a40179e 2069 'id' => $contribution['id'],
9099cab3 2070 ]);
8a40179e 2071
9099cab3 2072 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['id' => $contribution['id']]);
8a40179e 2073 $this->assertEquals('SSF', $contribution['contribution_source']);
2074 $this->assertEquals('Completed', $contribution['contribution_status']);
2075 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contribution['receipt_date'])));
2076
2077 $entityFinancialTransactions = $this->getFinancialTransactionsForContribution($contribution['id']);
2078 $entityFinancialTransaction = reset($entityFinancialTransactions);
9099cab3 2079 $financialTrxn = $this->callAPISuccessGetSingle('FinancialTrxn', ['id' => $entityFinancialTransaction['financial_trxn_id']]);
8a40179e 2080 $this->assertEquals('EUR', $financialTrxn['currency']);
2081
9099cab3 2082 $mut->checkMailLog([
8a40179e 2083 'email:::anthony_anderson@civicrm.org',
2084 'is_monetary:::1',
2085 'amount:::100.00',
2086 'currency:::EUR',
2087 'receive_date:::' . date('Ymd', strtotime($contribution['receive_date'])),
2088 "receipt_date:::\n",
ec7e3954
E
2089 'contributeMode:::notify',
2090 'title:::Contribution',
2091 'displayName:::Mr. Anthony Anderson II',
3b28799d 2092 'contributionStatus:::Completed',
9099cab3 2093 ]);
46fa5206 2094 $mut->stop();
ec7e3954 2095 $this->revertTemplateToReservedTemplate();
46fa5206
EM
2096 }
2097
e05d2e11 2098 /**
2099 * Test to ensure mail is sent on chosing pay later
2100 */
58315149 2101 public function testPayLater() {
e05d2e11 2102 $mut = new CiviMailUtils($this, TRUE);
2103 $this->swapMessageTemplateForTestTemplate();
2104 $this->createLoggedInUser();
2105
2106 // create contribution page first
9099cab3 2107 $contributionPageParams = [
e05d2e11 2108 'title' => 'Help Support CiviCRM!',
2109 'financial_type_id' => 1,
2110 'is_monetary' => TRUE,
2111 'is_pay_later' => 1,
2112 'is_quick_config' => TRUE,
2113 'pay_later_text' => 'I will send payment by check',
2114 'pay_later_receipt' => 'This is a pay later reciept',
2115 'is_allow_other_amount' => 1,
2116 'min_amount' => 10.00,
2117 'max_amount' => 10000.00,
2118 'goal_amount' => 100000.00,
2119 'is_email_receipt' => 1,
2120 'is_active' => 1,
2121 'amount_block_is_active' => 1,
2122 'currency' => 'USD',
2123 'is_billing_required' => 0,
9099cab3 2124 ];
e05d2e11 2125 $contributionPageResult = $this->callAPISuccess('contribution_page', 'create', $contributionPageParams);
2126
2127 // submit form values
9099cab3
CW
2128 $priceSet = $this->callAPISuccess('price_set', 'getsingle', ['name' => 'default_contribution_amount']);
2129 $params = [
e05d2e11 2130 'id' => $contributionPageResult['id'],
2131 'contact_id' => $this->_individualId,
2132 'email-5' => 'anthony_anderson@civicrm.org',
2133 'payment_processor_id' => 0,
2134 'amount' => 100.00,
2135 'tax_amount' => '',
2136 'currencyID' => 'USD',
2137 'is_pay_later' => 1,
2138 'invoiceID' => 'f28e1ddc86f8c4a0ff5bcf46393e4bc8',
2139 'is_quick_config' => 1,
2140 'description' => 'Online Contribution: Help Support CiviCRM!',
2141 'price_set_id' => $priceSet['id'],
9099cab3 2142 ];
58315149 2143 $this->callAPISuccess('ContributionPage', 'submit', $params);
e05d2e11 2144
9099cab3 2145 $mut->checkMailLog([
e05d2e11 2146 'is_pay_later:::1',
2147 'email:::anthony_anderson@civicrm.org',
2148 'pay_later_receipt:::' . $contributionPageParams['pay_later_receipt'],
2149 'displayName:::Mr. Anthony Anderson II',
2150 'contributionPageId:::' . $contributionPageResult['id'],
2151 'title:::' . $contributionPageParams['title'],
8beee0e8 2152 'amount:::' . $params['amount'],
9099cab3 2153 ]);
e05d2e11 2154 $mut->stop();
2155 $this->revertTemplateToReservedTemplate();
2156 }
2157
2a0df9d9 2158 /**
2159 * Test to check whether contact billing address is used when no contribution address
2160 */
2161 public function testBillingAddress() {
2162 $mut = new CiviMailUtils($this, TRUE);
2163 $this->swapMessageTemplateForTestTemplate();
2164 $this->createLoggedInUser();
2165
2166 //Scenario 1: When Contact don't have any address
9099cab3 2167 $params = array_merge($this->_params, ['contribution_status_id' => 2]);
2a0df9d9 2168 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 2169 $this->callAPISuccess('contribution', 'completetransaction', [
2a0df9d9 2170 'id' => $contribution['id'],
9099cab3
CW
2171 ]);
2172 $mut->checkMailLog([
2a0df9d9 2173 'address:::',
9099cab3 2174 ]);
2a0df9d9 2175
2176 // Scenario 2: Contribution using address
9099cab3 2177 $address = $this->callAPISuccess('address', 'create', [
2a0df9d9 2178 'street_address' => 'contribution billing st',
2179 'location_type_id' => 2,
2180 'contact_id' => $this->_params['contact_id'],
9099cab3
CW
2181 ]);
2182 $params = array_merge($this->_params, [
76e8d9c4 2183 'contribution_status_id' => 2,
2a0df9d9 2184 'address_id' => $address['id'],
9099cab3 2185 ]
2a0df9d9 2186 );
2187 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 2188 $this->callAPISuccess('contribution', 'completetransaction', [
2a0df9d9 2189 'id' => $contribution['id'],
9099cab3
CW
2190 ]);
2191 $mut->checkMailLog([
2a0df9d9 2192 'address:::contribution billing st',
9099cab3 2193 ]);
2a0df9d9 2194
2195 // Scenario 3: Contribution wtth no address but contact has a billing address
9099cab3 2196 $this->callAPISuccess('address', 'create', [
2a0df9d9 2197 'id' => $address['id'],
2198 'street_address' => 'is billing st',
2199 'contact_id' => $this->_params['contact_id'],
9099cab3
CW
2200 ]);
2201 $params = array_merge($this->_params, ['contribution_status_id' => 2]);
2a0df9d9 2202 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 2203 $this->callAPISuccess('contribution', 'completetransaction', [
2a0df9d9 2204 'id' => $contribution['id'],
9099cab3
CW
2205 ]);
2206 $mut->checkMailLog([
2a0df9d9 2207 'address:::is billing st',
9099cab3 2208 ]);
2a0df9d9 2209
2210 $mut->stop();
2211 $this->revertTemplateToReservedTemplate();
2212 }
2213
080a561b 2214 /**
2215 * Test completing a transaction via the API.
2216 *
2217 * Note that we are creating a logged in user because email goes out from
2218 * that person
2219 */
2220 public function testCompleteTransactionFeeAmount() {
2221 $this->createLoggedInUser();
9099cab3 2222 $params = array_merge($this->_params, ['contribution_status_id' => 2]);
080a561b 2223 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 2224 $this->callAPISuccess('contribution', 'completetransaction', [
080a561b 2225 'id' => $contribution['id'],
2226 'fee_amount' => '.56',
2227 'trxn_id' => '7778888',
9099cab3
CW
2228 ]);
2229 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['id' => $contribution['id'], 'sequential' => 1]);
080a561b 2230 $this->assertEquals('Completed', $contribution['contribution_status']);
2231 $this->assertEquals('7778888', $contribution['trxn_id']);
2f3d0664 2232 $this->assertEquals('0.56', $contribution['fee_amount']);
080a561b 2233 $this->assertEquals('99.44', $contribution['net_amount']);
2234 }
2235
effb4d85 2236 /**
83644f47 2237 * CRM-19126 Add test to verify when complete transaction is called tax amount is not changed.
2238 *
2239 * @param string $thousandSeparator
2240 * punctuation used to refer to thousands.
2241 *
2242 * @dataProvider getThousandSeparators
effb4d85 2243 */
83644f47 2244 public function testCheckTaxAmount($thousandSeparator) {
2245 $this->setCurrencySeparators($thousandSeparator);
effb4d85 2246 $contact = $this->createLoggedInUser();
9099cab3 2247 $financialType = $this->callAPISuccess('financial_type', 'create', [
effb4d85
SL
2248 'name' => 'Test taxable financial Type',
2249 'is_reserved' => 0,
2250 'is_active' => 1,
9099cab3
CW
2251 ]);
2252 $financialAccount = $this->callAPISuccess('financial_account', 'create', [
39b959db
SL
2253 'name' => 'Test Tax financial account ',
2254 'contact_id' => $contact,
2255 'financial_account_type_id' => 2,
2256 'is_tax' => 1,
2257 'tax_rate' => 5.00,
2258 'is_reserved' => 0,
2259 'is_active' => 1,
2260 'is_default' => 0,
9099cab3 2261 ]);
effb4d85
SL
2262 $financialTypeId = $financialType['id'];
2263 $financialAccountId = $financialAccount['id'];
9099cab3 2264 $financialAccountParams = [
effb4d85
SL
2265 'entity_table' => 'civicrm_financial_type',
2266 'entity_id' => $financialTypeId,
2267 'account_relationship' => 10,
2268 'financial_account_id' => $financialAccountId,
9099cab3 2269 ];
a76b8bd8 2270 CRM_Financial_BAO_FinancialTypeAccount::add($financialAccountParams);
f527e012 2271
9099cab3 2272 $params = array_merge($this->_params, ['contribution_status_id' => 2, 'financial_type_id' => $financialTypeId]);
effb4d85 2273 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3
CW
2274 $contribution1 = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id'], 'return' => 'tax_amount', 'sequential' => 1]);
2275 $this->callAPISuccess('contribution', 'completetransaction', [
39b959db
SL
2276 'id' => $contribution['id'],
2277 'trxn_id' => '777788888',
2278 'fee_amount' => '6.00',
9099cab3
CW
2279 ]);
2280 $contribution2 = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id'], 'return' => ['tax_amount', 'fee_amount', 'net_amount'], 'sequential' => 1]);
effb4d85 2281 $this->assertEquals($contribution1['values'][0]['tax_amount'], $contribution2['values'][0]['tax_amount']);
99a4cd32 2282 $this->assertEquals('6.00', $contribution2['values'][0]['fee_amount']);
f836984d 2283 $this->assertEquals('99.00', $contribution2['values'][0]['net_amount']);
effb4d85
SL
2284 }
2285
d97c96dc 2286 /**
0e6ccb2e 2287 * Test repeat contribution successfully creates line item.
cc9f2882 2288 *
2289 * @throws \CRM_Core_Exception
d97c96dc 2290 */
1e52837d 2291 public function testRepeatTransaction() {
9099cab3
CW
2292 $originalContribution = $this->setUpRepeatTransaction($recurParams = [], 'single');
2293 $this->callAPISuccess('contribution', 'repeattransaction', [
d97c96dc
EM
2294 'original_contribution_id' => $originalContribution['id'],
2295 'contribution_status_id' => 'Completed',
2296 'trxn_id' => uniqid(),
9099cab3
CW
2297 ]);
2298 $lineItemParams = [
d97c96dc
EM
2299 'entity_id' => $originalContribution['id'],
2300 'sequential' => 1,
9099cab3 2301 'return' => [
d97c96dc
EM
2302 'entity_table',
2303 'qty',
2304 'unit_price',
2305 'line_total',
2306 'label',
2307 'financial_type_id',
2308 'deductible_amount',
2309 'price_field_value_id',
2310 'price_field_id',
9099cab3
CW
2311 ],
2312 ];
2313 $lineItem1 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
d97c96dc 2314 'entity_id' => $originalContribution['id'],
9099cab3
CW
2315 ]));
2316 $lineItem2 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
d97c96dc 2317 'entity_id' => $originalContribution['id'] + 1,
9099cab3 2318 ]));
d97c96dc
EM
2319 unset($lineItem1['values'][0]['id'], $lineItem1['values'][0]['entity_id']);
2320 unset($lineItem2['values'][0]['id'], $lineItem2['values'][0]['entity_id']);
2321 $this->assertEquals($lineItem1['values'][0], $lineItem2['values'][0]);
9099cab3 2322 $this->_checkFinancialRecords([
f69a9ac3 2323 'id' => $originalContribution['id'] + 1,
9099cab3 2324 'payment_instrument_id' => $this->callAPISuccessGetValue('PaymentProcessor', [
f69a9ac3 2325 'id' => $originalContribution['payment_processor_id'],
2326 'return' => 'payment_instrument_id',
9099cab3
CW
2327 ]),
2328 ], 'online');
d97c96dc
EM
2329 }
2330
b2250d14 2331 /**
2332 * Test custom data is copied over from the template transaction.
2333 *
2334 * (Over time various discussions have deemed this to be the most recent one, allowing
2335 * users to alter custom data going forwards. This is implemented for line items already.
2336 *
2337 * @throws \API_Exception
2338 * @throws \CRM_Core_Exception
2339 */
2340 public function testRepeatTransactionWithCustomData() {
2341 $this->createCustomGroupWithFieldOfType(['extends' => 'Contribution', 'name' => 'Repeat'], 'text');
2342 $originalContribution = $this->setUpRepeatTransaction([], 'single', [$this->getCustomFieldName('text') => 'first']);
2343 $this->callAPISuccess('contribution', 'repeattransaction', [
2344 'contribution_recur_id' => $originalContribution['contribution_recur_id'],
2345 'contribution_status_id' => 'Completed',
2346 'trxn_id' => 'my_trxn',
2347 ]);
2348
2349 $contribution = Contribution::get()
2350 ->addWhere('trxn_id', '=', 'my_trxn')
2351 ->addSelect('Custom_Group.Enter_text_here')
2352 ->addSelect('id')
2353 ->execute()->first();
2354 $this->assertEquals('first', $contribution['Custom_Group.Enter_text_here']);
2355
2356 Contribution::update()->setValues(['Custom_Group.Enter_text_here' => 'second'])->addWhere('id', '=', $contribution['id'])->execute();
2357
2358 $this->callAPISuccess('contribution', 'repeattransaction', [
2359 'original_contribution_id' => $originalContribution['id'],
2360 'contribution_status_id' => 'Completed',
2361 'trxn_id' => 'number_3',
2362 ]);
2363
2364 $contribution = Contribution::get()
2365 ->addWhere('trxn_id', '=', 'number_3')
2366 ->setSelect(['id', 'Custom_Group.Enter_text_here'])
2367 ->execute()->first();
2368 $this->assertEquals('second', $contribution['Custom_Group.Enter_text_here']);
2369 }
2370
893a550c 2371 /**
0e6ccb2e 2372 * Test repeat contribution successfully creates line items (plural).
562e4fb8 2373 *
2374 * @throws \CRM_Core_Exception
0e6ccb2e
K
2375 */
2376 public function testRepeatTransactionLineItems() {
7150b1c8 2377 // CRM-19309
9099cab3
CW
2378 $originalContribution = $this->setUpRepeatTransaction($recurParams = [], 'multiple');
2379 $this->callAPISuccess('contribution', 'repeattransaction', [
0e6ccb2e
K
2380 'original_contribution_id' => $originalContribution['id'],
2381 'contribution_status_id' => 'Completed',
2382 'trxn_id' => uniqid(),
9099cab3 2383 ]);
0e6ccb2e 2384
9099cab3 2385 $lineItemParams = [
0e6ccb2e
K
2386 'entity_id' => $originalContribution['id'],
2387 'sequential' => 1,
9099cab3 2388 'return' => [
0e6ccb2e
K
2389 'entity_table',
2390 'qty',
2391 'unit_price',
2392 'line_total',
2393 'label',
2394 'financial_type_id',
2395 'deductible_amount',
2396 'price_field_value_id',
2397 'price_field_id',
9099cab3
CW
2398 ],
2399 ];
2400 $lineItem1 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
0e6ccb2e 2401 'entity_id' => $originalContribution['id'],
9099cab3
CW
2402 ]));
2403 $lineItem2 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
0e6ccb2e 2404 'entity_id' => $originalContribution['id'] + 1,
9099cab3 2405 ]));
0e6ccb2e
K
2406
2407 // unset id and entity_id for all of them to be able to compare the lineItems:
2408 unset($lineItem1['values'][0]['id'], $lineItem1['values'][0]['entity_id']);
2409 unset($lineItem2['values'][0]['id'], $lineItem2['values'][0]['entity_id']);
2410 $this->assertEquals($lineItem1['values'][0], $lineItem2['values'][0]);
2411
2412 unset($lineItem1['values'][1]['id'], $lineItem1['values'][1]['entity_id']);
2413 unset($lineItem2['values'][1]['id'], $lineItem2['values'][1]['entity_id']);
2414 $this->assertEquals($lineItem1['values'][1], $lineItem2['values'][1]);
2415
7150b1c8
K
2416 // CRM-19309 so in future we also want to:
2417 // check that financial_line_items have been created for entity_id 3 and 4;
0e6ccb2e 2418
9099cab3 2419 $this->callAPISuccessGetCount('FinancialItem', ['description' => 'Sales Tax', 'amount' => 0], 0);
0e6ccb2e
K
2420 }
2421
2422 /**
2423 * Test repeat contribution successfully creates is_test transaction.
893a550c 2424 */
2425 public function testRepeatTransactionIsTest() {
2426 $this->_params['is_test'] = 1;
9099cab3 2427 $originalContribution = $this->setUpRepeatTransaction(['is_test' => 1], 'single');
893a550c 2428
9099cab3 2429 $this->callAPISuccess('contribution', 'repeattransaction', [
893a550c 2430 'original_contribution_id' => $originalContribution['id'],
2431 'contribution_status_id' => 'Completed',
2432 'trxn_id' => uniqid(),
9099cab3
CW
2433 ]);
2434 $this->callAPISuccessGetCount('Contribution', ['contribution_test' => 1], 2);
893a550c 2435 }
2436
d5580ed4 2437 /**
2438 * Test repeat contribution passed in status.
2439 */
2440 public function testRepeatTransactionPassedInStatus() {
9099cab3 2441 $originalContribution = $this->setUpRepeatTransaction($recurParams = [], 'single');
d5580ed4 2442
9099cab3 2443 $this->callAPISuccess('contribution', 'repeattransaction', [
d5580ed4 2444 'original_contribution_id' => $originalContribution['id'],
2445 'contribution_status_id' => 'Pending',
2446 'trxn_id' => uniqid(),
9099cab3
CW
2447 ]);
2448 $this->callAPISuccessGetCount('Contribution', ['contribution_status_id' => 2], 1);
d5580ed4 2449 }
2450
1eade77d 2451 /**
2452 * Test repeat contribution accepts recur_id instead of original_contribution_id.
2453 */
2454 public function testRepeatTransactionAcceptRecurID() {
9099cab3 2455 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', [
1eade77d 2456 'contact_id' => $this->_individualId,
2457 'installments' => '12',
2458 'frequency_interval' => '1',
2459 'amount' => '100',
2460 'contribution_status_id' => 1,
2461 'start_date' => '2012-01-01 00:00:00',
2462 'currency' => 'USD',
2463 'frequency_unit' => 'month',
2464 'payment_processor_id' => $this->paymentProcessorID,
9099cab3 2465 ]);
1eade77d 2466 $this->callAPISuccess('contribution', 'create', array_merge(
2467 $this->_params,
9099cab3 2468 ['contribution_recur_id' => $contributionRecur['id']])
1eade77d 2469 );
2470
9099cab3 2471 $this->callAPISuccess('contribution', 'repeattransaction', [
1eade77d 2472 'contribution_recur_id' => $contributionRecur['id'],
2473 'contribution_status_id' => 'Completed',
2474 'trxn_id' => uniqid(),
9099cab3 2475 ]);
1eade77d 2476
1eade77d 2477 }
2478
28124368 2479 /**
562e4fb8 2480 * CRM-19873 Test repeattransaction if contribution_recur_id is a test.
2481 *
2482 * @throws \CRM_Core_Exception
28124368
PH
2483 */
2484 public function testRepeatTransactionTestRecurId() {
562e4fb8 2485 $contributionRecur = $this->callAPISuccess('ContributionRecur', 'create', [
28124368
PH
2486 'contact_id' => $this->_individualId,
2487 'frequency_interval' => '1',
2488 'amount' => '1.00',
2489 'contribution_status_id' => 1,
2490 'start_date' => '2017-01-01 00:00:00',
2491 'currency' => 'USD',
2492 'frequency_unit' => 'month',
2493 'payment_processor_id' => $this->paymentProcessorID,
2494 'is_test' => 1,
9099cab3 2495 ]);
28124368
PH
2496 $this->callAPISuccess('contribution', 'create', array_merge(
2497 $this->_params,
9099cab3 2498 [
28124368
PH
2499 'contribution_recur_id' => $contributionRecur['id'],
2500 'is_test' => 1,
9099cab3 2501 ])
28124368
PH
2502 );
2503
9099cab3 2504 $repeatedContribution = $this->callAPISuccess('contribution', 'repeattransaction', [
28124368
PH
2505 'contribution_recur_id' => $contributionRecur['id'],
2506 'contribution_status_id' => 'Completed',
562e4fb8 2507 'trxn_id' => 'magic_number',
9099cab3 2508 ]);
28124368
PH
2509
2510 $this->assertEquals($contributionRecur['values'][1]['is_test'], $repeatedContribution['values'][2]['is_test']);
28124368 2511 }
37f29fcf 2512
d2334242 2513 /**
37f29fcf 2514 * CRM-19945 Tests that Contribute.repeattransaction renews a membership when contribution status=Completed
7c3f3d59 2515 *
562e4fb8 2516 * @throws \CRM_Core_Exception
d2334242 2517 */
37f29fcf 2518 public function testRepeatTransactionMembershipRenewCompletedContribution() {
d2334242
PH
2519 list($originalContribution, $membership) = $this->setUpAutoRenewMembership();
2520
562e4fb8 2521 $contribution = $this->callAPISuccess('Contribution', 'repeattransaction', [
7c3f3d59 2522 'contribution_recur_id' => $originalContribution['values'][1]['contribution_recur_id'],
562e4fb8 2523 'contribution_status_id' => 'Failed',
9099cab3 2524 ]);
d2334242 2525
9099cab3 2526 $this->callAPISuccess('membership', 'create', [
39b959db
SL
2527 'id' => $membership['id'],
2528 'end_date' => 'yesterday',
2529 'status_id' => 'Expired',
9099cab3 2530 ]);
d2334242 2531
562e4fb8 2532 $contribution = $this->callAPISuccess('Contribution', 'repeattransaction', [
39b959db
SL
2533 'contribution_recur_id' => $originalContribution['values'][1]['contribution_recur_id'],
2534 'contribution_status_id' => 'Completed',
2535 'trxn_id' => 'bobsled',
9099cab3 2536 ]);
d2334242 2537
9099cab3 2538 $membershipStatusId = $this->callAPISuccess('membership', 'getvalue', [
d2334242
PH
2539 'id' => $membership['id'],
2540 'return' => 'status_id',
9099cab3 2541 ]);
d2334242 2542
9099cab3 2543 $membership = $this->callAPISuccess('membership', 'get', [
37f29fcf 2544 'id' => $membership['id'],
9099cab3 2545 ]);
37f29fcf
MW
2546
2547 $this->assertEquals('New', CRM_Core_PseudoConstant::getName('CRM_Member_BAO_Membership', 'status_id', $membershipStatusId));
2548
9099cab3 2549 $lineItem = $this->callAPISuccessGetSingle('LineItem', ['contribution_id' => $contribution['id']]);
37f29fcf 2550 $this->assertEquals('civicrm_membership', $lineItem['entity_table']);
9099cab3 2551 $this->callAPISuccessGetCount('MembershipPayment', ['membership_id' => $membership['id']]);
37f29fcf
MW
2552 }
2553
4e6cd940 2554 /**
2555 * This is one of those tests that locks in existing behaviour.
2556 *
2557 * I feel like correct behaviour is arguable & has been discussed in the past. However, if the membership has
2558 * a date which says it should be expired then the result of repeattransaction is to push that date
2559 * to be one membership term from 'now' with status 'new'.
2560 */
2561 public function testRepeattransactionRenewMembershipOldMembership() {
2562 $entities = $this->setUpAutoRenewMembership();
2563 $newStatusID = CRM_Core_PseudoConstant::getKey('CRM_Member_BAO_Membership', 'status_id', 'New');
2564 $membership = $this->callAPISuccess('Membership', 'create', [
2565 'id' => $entities[1]['id'],
2566 'join_date' => '4 months ago',
2567 'start_date' => '3 months ago',
2568 'end_date' => '2 months ago',
2569 ]);
2570 $membership = $membership['values'][$membership['id']];
2571
2572 // This status does not appear to be calculated at all and is set to 'new'. Feels like a bug.
2573 $this->assertEquals($newStatusID, $membership['status_id']);
2574
2575 // So it seems renewing this expired membership results in it's new status being current and it being pushed to a future date
2576 $this->callAPISuccess('Contribution', 'repeattransaction', ['original_contribution_id' => $entities[0]['id'], 'contribution_status_id' => 'Completed']);
2577 $membership = $this->callAPISuccessGetSingle('Membership', ['id' => $membership['id']]);
2578 // If this date calculation winds up being flakey the spirit of the test would be maintained by just checking
2579 // date is greater than today.
2580 $this->assertEquals(date('Y-m-d', strtotime('+ 1 month -1 day')), $membership['end_date']);
2581 $this->assertEquals($newStatusID, $membership['membership_type_id']);
2582 }
2583
37f29fcf
MW
2584 /**
2585 * CRM-19945 Tests that Contribute.repeattransaction DOES NOT renew a membership when contribution status=Failed
2586 *
2587 * @dataProvider contributionStatusProvider
23c64784 2588 *
2589 * @throws \CRM_Core_Exception
37f29fcf
MW
2590 */
2591 public function testRepeatTransactionMembershipRenewContributionNotCompleted($contributionStatus) {
2592 // Completed status should renew so we don't test that here
23c64784 2593 // In Progress status was never actually intended to be available for contributions.
2594 // Partially paid is not valid.
2595 if (in_array($contributionStatus['name'], ['Completed', 'In Progress', 'Partially paid'])) {
37f29fcf
MW
2596 return;
2597 }
2598 list($originalContribution, $membership) = $this->setUpAutoRenewMembership();
2599
562e4fb8 2600 $this->callAPISuccess('Contribution', 'repeattransaction', [
2601 'original_contribution_id' => $originalContribution['id'],
2602 'contribution_status_id' => 'Completed',
9099cab3 2603 ]);
37f29fcf 2604
9099cab3 2605 $this->callAPISuccess('membership', 'create', [
37f29fcf
MW
2606 'id' => $membership['id'],
2607 'end_date' => 'yesterday',
2608 'status_id' => 'Expired',
9099cab3 2609 ]);
37f29fcf 2610
9099cab3 2611 $contribution = $this->callAPISuccess('contribution', 'repeattransaction', [
37f29fcf
MW
2612 'contribution_recur_id' => $originalContribution['values'][1]['contribution_recur_id'],
2613 'contribution_status_id' => $contributionStatus['name'],
2614 'trxn_id' => 'bobsled',
9099cab3 2615 ]);
37f29fcf 2616
562e4fb8 2617 $updatedMembership = $this->callAPISuccess('membership', 'getsingle', ['id' => $membership['id']]);
37f29fcf
MW
2618
2619 $dateTime = new DateTime('yesterday');
2620 $this->assertEquals($dateTime->format('Y-m-d'), $updatedMembership['end_date']);
2621 $this->assertEquals(CRM_Core_PseudoConstant::getKey('CRM_Member_BAO_Membership', 'status_id', 'Expired'), $updatedMembership['status_id']);
7c3f3d59 2622
9099cab3 2623 $lineItem = $this->callAPISuccessGetSingle('LineItem', ['contribution_id' => $contribution['id']]);
7c3f3d59 2624 $this->assertEquals('civicrm_membership', $lineItem['entity_table']);
9099cab3 2625 $this->callAPISuccessGetCount('MembershipPayment', ['membership_id' => $membership['id']]);
d2334242 2626 }
28124368 2627
37f29fcf
MW
2628 /**
2629 * Dataprovider provides contribution status as [optionvalue=>contribution_status_name]
2630 * FIXME: buildOptions seems to die in CRM_Core_Config::_construct when in test mode.
2631 *
2632 * @return array
2633 * @throws \CiviCRM_API3_Exception
2634 */
2635 public function contributionStatusProvider() {
2636 $contributionStatuses = civicrm_api3('OptionValue', 'get', [
2637 'return' => ["id", "name"],
2638 'option_group_id' => "contribution_status",
2639 ]);
2640 foreach ($contributionStatuses['values'] as $statusName) {
2641 $statuses[] = [$statusName];
2642 }
2643 return $statuses;
2644 }
2645
c03f1689
EM
2646 /**
2647 * CRM-16397 test appropriate action if total amount has changed for single line items.
2648 */
2649 public function testRepeatTransactionAlteredAmount() {
2650 $paymentProcessorID = $this->paymentProcessorCreate();
9099cab3 2651 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', [
c03f1689
EM
2652 'contact_id' => $this->_individualId,
2653 'installments' => '12',
2654 'frequency_interval' => '1',
2655 'amount' => '500',
2656 'contribution_status_id' => 1,
2657 'start_date' => '2012-01-01 00:00:00',
2658 'currency' => 'USD',
2659 'frequency_unit' => 'month',
2660 'payment_processor_id' => $paymentProcessorID,
9099cab3 2661 ]);
c03f1689
EM
2662 $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
2663 $this->_params,
9099cab3 2664 [
c03f1689 2665 'contribution_recur_id' => $contributionRecur['id'],
9099cab3 2666 ])
c03f1689
EM
2667 );
2668
9099cab3 2669 $this->callAPISuccess('contribution', 'repeattransaction', [
c03f1689
EM
2670 'original_contribution_id' => $originalContribution['id'],
2671 'contribution_status_id' => 'Completed',
2672 'trxn_id' => uniqid(),
2673 'total_amount' => '400',
2674 'fee_amount' => 50,
9099cab3 2675 ]);
0e6ccb2e 2676
9099cab3 2677 $lineItemParams = [
c03f1689
EM
2678 'entity_id' => $originalContribution['id'],
2679 'sequential' => 1,
9099cab3 2680 'return' => [
c03f1689
EM
2681 'entity_table',
2682 'qty',
2683 'unit_price',
2684 'line_total',
2685 'label',
2686 'financial_type_id',
2687 'deductible_amount',
2688 'price_field_value_id',
2689 'price_field_id',
9099cab3
CW
2690 ],
2691 ];
2692 $this->callAPISuccessGetSingle('contribution', [
c03f1689 2693 'total_amount' => 400,
c03f1689
EM
2694 'fee_amount' => 50,
2695 'net_amount' => 350,
9099cab3
CW
2696 ]);
2697 $lineItem1 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
c03f1689 2698 'entity_id' => $originalContribution['id'],
9099cab3 2699 ]));
c03f1689 2700 $expectedLineItem = array_merge(
9099cab3 2701 $lineItem1['values'][0], [
c03f1689
EM
2702 'line_total' => '400.00',
2703 'unit_price' => '400.00',
9099cab3 2704 ]
542d9e2c 2705 );
c03f1689 2706
9099cab3 2707 $lineItem2 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
c03f1689 2708 'entity_id' => $originalContribution['id'] + 1,
9099cab3 2709 ]));
0e6ccb2e 2710
c03f1689
EM
2711 unset($expectedLineItem['id'], $expectedLineItem['entity_id']);
2712 unset($lineItem2['values'][0]['id'], $lineItem2['values'][0]['entity_id']);
2713 $this->assertEquals($expectedLineItem, $lineItem2['values'][0]);
c02c17df 2714 }
c03f1689 2715
3c49d90c 2716 /**
fa839a68 2717 * Test financial_type_id override behaviour with a single line item.
2718 *
2719 * CRM-17718 a passed in financial_type_id is allowed to override the original contribution where there
2720 * is only one line item.
3c49d90c 2721 */
2722 public function testRepeatTransactionPassedInFinancialType() {
2723 $originalContribution = $this->setUpRecurringContribution();
2724
9099cab3 2725 $this->callAPISuccess('contribution', 'repeattransaction', [
3c49d90c 2726 'original_contribution_id' => $originalContribution['id'],
2727 'contribution_status_id' => 'Completed',
2728 'trxn_id' => uniqid(),
2729 'financial_type_id' => 2,
9099cab3
CW
2730 ]);
2731 $lineItemParams = [
3c49d90c 2732 'entity_id' => $originalContribution['id'],
2733 'sequential' => 1,
9099cab3 2734 'return' => [
3c49d90c 2735 'entity_table',
2736 'qty',
2737 'unit_price',
2738 'line_total',
2739 'label',
2740 'financial_type_id',
2741 'deductible_amount',
2742 'price_field_value_id',
2743 'price_field_id',
9099cab3
CW
2744 ],
2745 ];
3c49d90c 2746
fa839a68 2747 $this->callAPISuccessGetSingle('Contribution', [
3c49d90c 2748 'total_amount' => 100,
2749 'financial_type_id' => 2,
9099cab3
CW
2750 ]);
2751 $lineItem1 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
3c49d90c 2752 'entity_id' => $originalContribution['id'],
9099cab3 2753 ]));
3c49d90c 2754 $expectedLineItem = array_merge(
9099cab3 2755 $lineItem1['values'][0], [
3c49d90c 2756 'line_total' => '100.00',
2757 'unit_price' => '100.00',
2758 'financial_type_id' => 2,
257ab382 2759 'contribution_type_id' => 2,
9099cab3 2760 ]
3c49d90c 2761 );
9099cab3 2762 $lineItem2 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
3c49d90c 2763 'entity_id' => $originalContribution['id'] + 1,
9099cab3 2764 ]));
3c49d90c 2765 unset($expectedLineItem['id'], $expectedLineItem['entity_id']);
2766 unset($lineItem2['values'][0]['id'], $lineItem2['values'][0]['entity_id']);
2767 $this->assertEquals($expectedLineItem, $lineItem2['values'][0]);
2768 }
2769
fa839a68 2770 /**
2771 * Test financial_type_id override behaviour with a single line item.
2772 *
2773 * CRM-17718 a passed in financial_type_id is not allowed to override the original contribution where there
2774 * is more than one line item.
2775 */
2776 public function testRepeatTransactionPassedInFinancialTypeTwoLineItems() {
2777 $this->_params = $this->getParticipantOrderParams();
2778 $originalContribution = $this->setUpRecurringContribution();
2779
2780 $this->callAPISuccess('Contribution', 'repeattransaction', [
2781 'original_contribution_id' => $originalContribution['id'],
2782 'contribution_status_id' => 'Completed',
2783 'trxn_id' => 'repeat',
2784 'financial_type_id' => 2,
2785 ]);
2786
2787 // Retrieve the new contribution and note the financial type passed in has been ignored.
2788 $contribution = $this->callAPISuccessGetSingle('Contribution', [
2789 'trxn_id' => 'repeat',
2790 ]);
2791 $this->assertEquals(4, $contribution['financial_type_id']);
2792
2793 $lineItems = $this->callAPISuccess('line_item', 'get', [
2794 'entity_id' => $contribution['id'],
2795 ])['values'];
2796 foreach ($lineItems as $lineItem) {
2797 $this->assertNotEquals(2, $lineItem['financial_type_id']);
2798 }
2799 }
2800
7f4ef731 2801 /**
2802 * CRM-17718 test appropriate action if financial type has changed for single line items.
2803 */
2804 public function testRepeatTransactionUpdatedFinancialType() {
9099cab3 2805 $originalContribution = $this->setUpRecurringContribution([], ['financial_type_id' => 2]);
7f4ef731 2806
9099cab3 2807 $this->callAPISuccess('contribution', 'repeattransaction', [
7f4ef731 2808 'contribution_recur_id' => $originalContribution['id'],
2809 'contribution_status_id' => 'Completed',
2810 'trxn_id' => uniqid(),
9099cab3
CW
2811 ]);
2812 $lineItemParams = [
7f4ef731 2813 'entity_id' => $originalContribution['id'],
2814 'sequential' => 1,
9099cab3 2815 'return' => [
7f4ef731 2816 'entity_table',
2817 'qty',
2818 'unit_price',
2819 'line_total',
2820 'label',
2821 'financial_type_id',
2822 'deductible_amount',
2823 'price_field_value_id',
2824 'price_field_id',
9099cab3
CW
2825 ],
2826 ];
7f4ef731 2827
9099cab3 2828 $this->callAPISuccessGetSingle('contribution', [
7f4ef731 2829 'total_amount' => 100,
2830 'financial_type_id' => 2,
9099cab3
CW
2831 ]);
2832 $lineItem1 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
7f4ef731 2833 'entity_id' => $originalContribution['id'],
9099cab3 2834 ]));
7f4ef731 2835 $expectedLineItem = array_merge(
9099cab3 2836 $lineItem1['values'][0], [
7f4ef731 2837 'line_total' => '100.00',
2838 'unit_price' => '100.00',
2839 'financial_type_id' => 2,
257ab382 2840 'contribution_type_id' => 2,
9099cab3 2841 ]
7f4ef731 2842 );
2843
9099cab3 2844 $lineItem2 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
7f4ef731 2845 'entity_id' => $originalContribution['id'] + 1,
9099cab3 2846 ]));
7f4ef731 2847 unset($expectedLineItem['id'], $expectedLineItem['entity_id']);
2848 unset($lineItem2['values'][0]['id'], $lineItem2['values'][0]['entity_id']);
2849 $this->assertEquals($expectedLineItem, $lineItem2['values'][0]);
2850 }
2851
c02c17df 2852 /**
1eade77d 2853 * CRM-16397 test appropriate action if campaign has been passed in.
c02c17df 2854 */
2855 public function testRepeatTransactionPassedInCampaign() {
2856 $paymentProcessorID = $this->paymentProcessorCreate();
2857 $campaignID = $this->campaignCreate();
2858 $campaignID2 = $this->campaignCreate();
9099cab3 2859 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', [
c02c17df 2860 'contact_id' => $this->_individualId,
2861 'installments' => '12',
2862 'frequency_interval' => '1',
2863 'amount' => '100',
2864 'contribution_status_id' => 1,
2865 'start_date' => '2012-01-01 00:00:00',
2866 'currency' => 'USD',
2867 'frequency_unit' => 'month',
2868 'payment_processor_id' => $paymentProcessorID,
9099cab3 2869 ]);
c02c17df 2870 $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
2871 $this->_params,
9099cab3 2872 [
c02c17df 2873 'contribution_recur_id' => $contributionRecur['id'],
2874 'campaign_id' => $campaignID,
9099cab3 2875 ])
c02c17df 2876 );
2877
9099cab3 2878 $this->callAPISuccess('contribution', 'repeattransaction', [
c02c17df 2879 'original_contribution_id' => $originalContribution['id'],
2880 'contribution_status_id' => 'Completed',
2881 'trxn_id' => uniqid(),
2882 'campaign_id' => $campaignID2,
9099cab3 2883 ]);
c02c17df 2884
9099cab3 2885 $this->callAPISuccessGetSingle('contribution', [
c02c17df 2886 'total_amount' => 100,
2887 'campaign_id' => $campaignID2,
9099cab3 2888 ]);
c02c17df 2889 }
2890
2891 /**
2892 * CRM-17718 campaign stored on contribution recur gets priority.
2893 *
2894 * This reflects the fact we permit people to update them.
2895 */
2896 public function testRepeatTransactionUpdatedCampaign() {
2897 $paymentProcessorID = $this->paymentProcessorCreate();
2898 $campaignID = $this->campaignCreate();
2899 $campaignID2 = $this->campaignCreate();
9099cab3 2900 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', [
c02c17df 2901 'contact_id' => $this->_individualId,
2902 'installments' => '12',
2903 'frequency_interval' => '1',
2904 'amount' => '100',
2905 'contribution_status_id' => 1,
2906 'start_date' => '2012-01-01 00:00:00',
2907 'currency' => 'USD',
2908 'frequency_unit' => 'month',
2909 'payment_processor_id' => $paymentProcessorID,
2910 'campaign_id' => $campaignID,
9099cab3 2911 ]);
c02c17df 2912 $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
2913 $this->_params,
9099cab3 2914 [
c02c17df 2915 'contribution_recur_id' => $contributionRecur['id'],
2916 'campaign_id' => $campaignID2,
9099cab3 2917 ])
c02c17df 2918 );
2919
9099cab3 2920 $this->callAPISuccess('contribution', 'repeattransaction', [
c02c17df 2921 'original_contribution_id' => $originalContribution['id'],
2922 'contribution_status_id' => 'Completed',
2923 'trxn_id' => uniqid(),
9099cab3 2924 ]);
c02c17df 2925
9099cab3 2926 $this->callAPISuccessGetSingle('contribution', [
c02c17df 2927 'total_amount' => 100,
2928 'campaign_id' => $campaignID,
9099cab3 2929 ]);
c03f1689
EM
2930 }
2931
2b0de476
E
2932 /**
2933 * CRM-20685 Repeattransaction produces incorrect Financial Type ID (in specific circumstance) - if number of lineItems = 1.
2934 *
2935 * This case happens when the line item & contribution do not have the same type in his initiating transaction.
2936 */
2937 public function testRepeatTransactionUpdatedFinancialTypeAndNotEquals() {
9099cab3 2938 $originalContribution = $this->setUpRecurringContribution([], ['financial_type_id' => 2]);
2b0de476 2939 // This will made the trick to get the not equals behaviour.
9099cab3
CW
2940 $this->callAPISuccess('line_item', 'create', ['id' => 1, 'financial_type_id' => 4]);
2941 $this->callAPISuccess('contribution', 'repeattransaction', [
2b0de476
E
2942 'contribution_recur_id' => $originalContribution['id'],
2943 'contribution_status_id' => 'Completed',
2944 'trxn_id' => uniqid(),
9099cab3
CW
2945 ]);
2946 $lineItemParams = [
2b0de476
E
2947 'entity_id' => $originalContribution['id'],
2948 'sequential' => 1,
9099cab3 2949 'return' => [
2b0de476
E
2950 'entity_table',
2951 'qty',
2952 'unit_price',
2953 'line_total',
2954 'label',
2955 'financial_type_id',
2956 'deductible_amount',
2957 'price_field_value_id',
2958 'price_field_id',
9099cab3
CW
2959 ],
2960 ];
2961 $this->callAPISuccessGetSingle('contribution', [
2b0de476
E
2962 'total_amount' => 100,
2963 'financial_type_id' => 2,
9099cab3
CW
2964 ]);
2965 $lineItem1 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
2b0de476 2966 'entity_id' => $originalContribution['id'],
9099cab3 2967 ]));
2b0de476 2968 $expectedLineItem = array_merge(
9099cab3 2969 $lineItem1['values'][0], [
2b0de476
E
2970 'line_total' => '100.00',
2971 'unit_price' => '100.00',
2972 'financial_type_id' => 4,
2973 'contribution_type_id' => 4,
9099cab3 2974 ]
2b0de476
E
2975 );
2976
9099cab3 2977 $lineItem2 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, [
2b0de476 2978 'entity_id' => $originalContribution['id'] + 1,
9099cab3
CW
2979 ]));
2980 $this->callAPISuccess('line_item', 'create', ['id' => 1, 'financial_type_id' => 1]);
2b0de476
E
2981 unset($expectedLineItem['id'], $expectedLineItem['entity_id']);
2982 unset($lineItem2['values'][0]['id'], $lineItem2['values'][0]['entity_id']);
2983 $this->assertEquals($expectedLineItem, $lineItem2['values'][0]);
2984 }
2985
2936c3b5
EM
2986 /**
2987 * Test completing a transaction does not 'mess' with net amount (CRM-15960).
2988 */
2989 public function testCompleteTransactionNetAmountOK() {
2990 $this->createLoggedInUser();
9099cab3 2991 $params = array_merge($this->_params, ['contribution_status_id' => 2]);
2936c3b5
EM
2992 unset($params['net_amount']);
2993 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 2994 $this->callAPISuccess('contribution', 'completetransaction', [
2936c3b5 2995 'id' => $contribution['id'],
9099cab3
CW
2996 ]);
2997 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['id' => $contribution['id']]);
2936c3b5
EM
2998 $this->assertEquals('Completed', $contribution['contribution_status']);
2999 $this->assertTrue(($contribution['total_amount'] - $contribution['net_amount']) == $contribution['fee_amount']);
3000 }
3001
46fa5206 3002 /**
1e52837d 3003 * CRM-14151 - Test completing a transaction via the API.
46fa5206 3004 */
00be9182 3005 public function testCompleteTransactionWithReceiptDateSet() {
76e8d9c4 3006 $this->swapMessageTemplateForTestTemplate();
5896d037 3007 $mut = new CiviMailUtils($this, TRUE);
46fa5206 3008 $this->createLoggedInUser();
9099cab3 3009 $params = array_merge($this->_params, ['contribution_status_id' => 2, 'receipt_date' => 'now']);
6c6e6187 3010 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3
CW
3011 $this->callAPISuccess('contribution', 'completetransaction', ['id' => $contribution['id'], 'trxn_date' => date('Y-m-d')]);
3012 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id'], 'sequential' => 1]);
46fa5206 3013 $this->assertEquals('Completed', $contribution['values'][0]['contribution_status']);
39052b78
AH
3014 // Make sure receive_date is original date and make sure payment date is today
3015 $this->assertEquals('2012-05-11', date('Y-m-d', strtotime($contribution['values'][0]['receive_date'])));
3016 $payment = $this->callAPISuccess('payment', 'get', ['contribution_id' => $contribution['id'], 'sequential' => 1]);
3017 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($payment['values'][0]['trxn_date'])));
9099cab3 3018 $mut->checkMailLog([
46fa5206 3019 'Receipt - Contribution',
76e8d9c4 3020 'receipt_date:::' . date('Ymd'),
9099cab3 3021 ]);
0efa8efe 3022 $mut->stop();
76e8d9c4 3023 $this->revertTemplateToReservedTemplate();
0efa8efe 3024 }
3025
e2ca457d
KG
3026 /**
3027 * CRM-1960 - Test to ensure that completetransaction respects the is_email_receipt setting
3028 */
3029 public function testCompleteTransactionWithEmailReceiptInput() {
d891a273 3030 $contributionPage = $this->createReceiptableContributionPage();
3031
e2ca457d 3032 $this->_params['contribution_page_id'] = $contributionPage['id'];
9099cab3 3033 $params = array_merge($this->_params, ['contribution_status_id' => 2]);
e2ca457d
KG
3034 $contribution = $this->callAPISuccess('contribution', 'create', $params);
3035 // Complete the transaction overriding is_email_receipt to = FALSE
9099cab3 3036 $this->callAPISuccess('contribution', 'completetransaction', [
e2ca457d
KG
3037 'id' => $contribution['id'],
3038 'trxn_date' => date('2011-04-09'),
3039 'trxn_id' => 'kazam',
3040 'is_email_receipt' => 0,
9099cab3 3041 ]);
e2ca457d 3042 // Check if a receipt was issued
9099cab3 3043 $receipt_date = $this->callAPISuccess('Contribution', 'getvalue', ['id' => $contribution['id'], 'return' => 'receipt_date']);
e2ca457d
KG
3044 $this->assertEquals('', $receipt_date);
3045 }
3b8c739e 3046
d891a273 3047 /**
3048 * Test that $is_recur is assigned to the receipt.
3049 */
3050 public function testCompleteTransactionForRecurring() {
fa839a68 3051 $this->mut = new CiviMailUtils($this, TRUE);
d891a273 3052 $this->swapMessageTemplateForTestTemplate();
3053 $recurring = $this->setUpRecurringContribution();
9099cab3 3054 $contributionPage = $this->createReceiptableContributionPage(['is_recur' => TRUE, 'recur_frequency_unit' => 'month', 'recur_interval' => 1]);
d891a273 3055
3056 $this->_params['contribution_page_id'] = $contributionPage['id'];
3057 $this->_params['contribution_recur_id'] = $recurring['id'];
3058
3059 $contribution = $this->setUpForCompleteTransaction();
3060
9099cab3 3061 $this->callAPISuccess('contribution', 'completetransaction', [
d891a273 3062 'id' => $contribution['id'],
3063 'trxn_date' => date('2011-04-09'),
3064 'trxn_id' => 'kazam',
3065 'is_email_receipt' => 1,
9099cab3 3066 ]);
d891a273 3067
9099cab3 3068 $this->mut->checkMailLog([
d891a273 3069 'is_recur:::1',
0131a2ce 3070 'cancelSubscriptionUrl:::' . CIVICRM_UF_BASEURL,
9099cab3 3071 ]);
d891a273 3072 $this->mut->stop();
3073 $this->revertTemplateToReservedTemplate();
3074 }
39b959db 3075
55df1211
AS
3076 /**
3077 * CRM-19710 - Test to ensure that completetransaction respects the input for is_email_receipt setting.
3078 *
3079 * If passed in it will override the default from contribution page.
3080 */
3081 public function testCompleteTransactionWithEmailReceiptInputTrue() {
3082 $mut = new CiviMailUtils($this, TRUE);
3083 $this->createLoggedInUser();
3084 // Create a Contribution Page with is_email_receipt = FALSE
9099cab3 3085 $contributionPage = $this->callAPISuccess('ContributionPage', 'create', [
55df1211
AS
3086 'receipt_from_name' => 'Mickey Mouse',
3087 'receipt_from_email' => 'mickey@mouse.com',
3088 'title' => "Test Contribution Page",
3089 'financial_type_id' => 1,
3090 'currency' => 'CAD',
3091 'is_monetary' => TRUE,
3092 'is_email_receipt' => 0,
9099cab3 3093 ]);
55df1211 3094 $this->_params['contribution_page_id'] = $contributionPage['id'];
9099cab3 3095 $params = array_merge($this->_params, ['contribution_status_id' => 2, 'receipt_date' => 'now']);
55df1211
AS
3096 $contribution = $this->callAPISuccess('contribution', 'create', $params);
3097 // Complete the transaction overriding is_email_receipt to = TRUE
9099cab3 3098 $this->callAPISuccess('contribution', 'completetransaction', [
55df1211
AS
3099 'id' => $contribution['id'],
3100 'is_email_receipt' => 1,
9099cab3
CW
3101 ]);
3102 $mut->checkMailLog([
e2481819 3103 'Contribution Information',
9099cab3 3104 ]);
55df1211
AS
3105 $mut->stop();
3106 }
d891a273 3107
b80f2ad1
E
3108 /**
3109 * Complete the transaction using the template with all the possible.
3110 */
3111 public function testCompleteTransactionWithTestTemplate() {
3112 $this->swapMessageTemplateForTestTemplate();
ec7e3954 3113 $contribution = $this->setUpForCompleteTransaction();
9099cab3 3114 $this->callAPISuccess('contribution', 'completetransaction', [
b80f2ad1
E
3115 'id' => $contribution['id'],
3116 'trxn_date' => date('2011-04-09'),
3117 'trxn_id' => 'kazam',
9099cab3
CW
3118 ]);
3119 $receive_date = $this->callAPISuccess('Contribution', 'getvalue', ['id' => $contribution['id'], 'return' => 'receive_date']);
3120 $this->mut->checkMailLog([
b80f2ad1
E
3121 'email:::anthony_anderson@civicrm.org',
3122 'is_monetary:::1',
3123 'amount:::100.00',
3124 'currency:::USD',
3125 'receive_date:::' . date('Ymd', strtotime($receive_date)),
3126 'receipt_date:::' . date('Ymd'),
3127 'contributeMode:::notify',
3128 'title:::Contribution',
3129 'displayName:::Mr. Anthony Anderson II',
3130 'trxn_id:::kazam',
ec7e3954 3131 'contactID:::' . $this->_params['contact_id'],
b80f2ad1
E
3132 'contributionID:::' . $contribution['id'],
3133 'financialTypeId:::1',
3134 'financialTypeName:::Donation',
9099cab3 3135 ]);
ec7e3954 3136 $this->mut->stop();
b80f2ad1
E
3137 $this->revertTemplateToReservedTemplate();
3138 }
3139
ec7e3954
E
3140 /**
3141 * Complete the transaction using the template with all the possible.
3142 */
3143 public function testCompleteTransactionContributionPageFromAddress() {
9099cab3 3144 $contributionPage = $this->callAPISuccess('ContributionPage', 'create', [
ec7e3954
E
3145 'receipt_from_name' => 'Mickey Mouse',
3146 'receipt_from_email' => 'mickey@mouse.com',
3147 'title' => "Test Contribution Page",
3148 'financial_type_id' => 1,
3149 'currency' => 'NZD',
3150 'goal_amount' => 50,
3151 'is_pay_later' => 1,
3152 'is_monetary' => TRUE,
3153 'is_email_receipt' => TRUE,
9099cab3 3154 ]);
ec7e3954
E
3155 $this->_params['contribution_page_id'] = $contributionPage['id'];
3156 $contribution = $this->setUpForCompleteTransaction();
9099cab3
CW
3157 $this->callAPISuccess('contribution', 'completetransaction', ['id' => $contribution['id']]);
3158 $this->mut->checkMailLog([
ec7e3954
E
3159 'mickey@mouse.com',
3160 'Mickey Mouse <',
9099cab3 3161 ]);
ec7e3954
E
3162 $this->mut->stop();
3163 }
3164
91259407 3165 /**
3166 * Test completing first transaction in a recurring series.
3167 *
3168 * The status should be set to 'in progress' and the next scheduled payment date calculated.
050e11d5 3169 *
3170 * @dataProvider getScheduledDateData
3171 *
3172 * @param array $dataSet
3173 *
3174 * @throws \Exception
91259407 3175 */
050e11d5 3176 public function testCompleteTransactionSetStatusToInProgress($dataSet) {
91259407 3177 $paymentProcessorID = $this->paymentProcessorCreate();
9099cab3 3178 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
91259407 3179 'contact_id' => $this->_individualId,
050e11d5 3180 'installments' => '2',
91259407 3181 'frequency_interval' => '1',
3182 'amount' => '500',
3183 'contribution_status_id' => 'Pending',
3184 'start_date' => '2012-01-01 00:00:00',
3185 'currency' => 'USD',
3186 'frequency_unit' => 'month',
3187 'payment_processor_id' => $paymentProcessorID,
9099cab3 3188 ], $dataSet['data']));
91259407 3189 $contribution = $this->callAPISuccess('contribution', 'create', array_merge(
3190 $this->_params,
9099cab3 3191 [
91259407 3192 'contribution_recur_id' => $contributionRecur['id'],
3193 'contribution_status_id' => 'Pending',
050e11d5 3194 'receive_date' => $dataSet['receive_date'],
9099cab3 3195 ])
91259407 3196 );
9099cab3 3197 $this->callAPISuccess('Contribution', 'completetransaction', [
050e11d5 3198 'id' => $contribution,
3199 'receive_date' => $dataSet['receive_date'],
9099cab3
CW
3200 ]);
3201 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', [
91259407 3202 'id' => $contributionRecur['id'],
9099cab3
CW
3203 'return' => ['next_sched_contribution_date', 'contribution_status_id'],
3204 ]);
91259407 3205 $this->assertEquals(5, $contributionRecur['contribution_status_id']);
050e11d5 3206 $this->assertEquals($dataSet['expected'], $contributionRecur['next_sched_contribution_date']);
3207 $this->callAPISuccess('Contribution', 'create', array_merge(
3208 $this->_params,
9099cab3 3209 [
050e11d5 3210 'contribution_recur_id' => $contributionRecur['id'],
3211 'contribution_status_id' => 'Completed',
9099cab3 3212 ]
050e11d5 3213 ));
9099cab3 3214 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', [
050e11d5 3215 'id' => $contributionRecur['id'],
9099cab3
CW
3216 'return' => ['contribution_status_id'],
3217 ]);
050e11d5 3218 $this->assertEquals(1, $contributionRecur['contribution_status_id']);
3219 }
3220
3221 /**
3222 * Get dates for testing.
3223 *
3224 * @return array
3225 */
3226 public function getScheduledDateData() {
9099cab3
CW
3227 $result = [];
3228 $result[]['2016-08-31-1-month'] = [
3229 'data' => [
050e11d5 3230 'start_date' => '2016-08-31',
3231 'frequency_interval' => 1,
3232 'frequency_unit' => 'month',
9099cab3 3233 ],
050e11d5 3234 'receive_date' => '2016-08-31',
3235 'expected' => '2016-10-01 00:00:00',
9099cab3
CW
3236 ];
3237 $result[]['2012-01-01-1-month'] = [
3238 'data' => [
050e11d5 3239 'start_date' => '2012-01-01',
3240 'frequency_interval' => 1,
3241 'frequency_unit' => 'month',
9099cab3 3242 ],
050e11d5 3243 'receive_date' => '2012-01-01',
3244 'expected' => '2012-02-01 00:00:00',
9099cab3
CW
3245 ];
3246 $result[]['2012-01-01-1-month'] = [
3247 'data' => [
050e11d5 3248 'start_date' => '2012-01-01',
3249 'frequency_interval' => 1,
3250 'frequency_unit' => 'month',
9099cab3 3251 ],
050e11d5 3252 'receive_date' => '2012-02-29',
3253 'expected' => '2012-03-29 00:00:00',
9099cab3
CW
3254 ];
3255 $result['receive_date_includes_time']['2012-01-01-1-month'] = [
3256 'data' => [
46f459f2 3257 'start_date' => '2012-01-01',
3258 'frequency_interval' => 1,
3259 'frequency_unit' => 'month',
3260 'next_sched_contribution_date' => '2012-02-29',
9099cab3 3261 ],
46f459f2 3262 'receive_date' => '2012-02-29 16:00:00',
3263 'expected' => '2012-03-29 00:00:00',
9099cab3 3264 ];
050e11d5 3265 return $result;
91259407 3266 }
3267
294cc627 3268 /**
3269 * Test completing a pledge with the completeTransaction api..
3270 *
3271 * Note that we are creating a logged in user because email goes out from
3272 * that person.
3273 */
3274 public function testCompleteTransactionUpdatePledgePayment() {
9f9fa558 3275 $this->swapMessageTemplateForTestTemplate();
294cc627 3276 $mut = new CiviMailUtils($this, TRUE);
3277 $mut->clearMessages();
3278 $this->createLoggedInUser();
3279 $contributionID = $this->createPendingPledgeContribution();
9099cab3 3280 $this->callAPISuccess('contribution', 'completetransaction', [
294cc627 3281 'id' => $contributionID,
3282 'trxn_date' => '1 Feb 2013',
9099cab3
CW
3283 ]);
3284 $pledge = $this->callAPISuccessGetSingle('Pledge', [
294cc627 3285 'id' => $this->_ids['pledge'],
9099cab3 3286 ]);
294cc627 3287 $this->assertEquals('Completed', $pledge['pledge_status']);
3288
9099cab3 3289 $status = $this->callAPISuccessGetValue('PledgePayment', [
294cc627 3290 'pledge_id' => $this->_ids['pledge'],
3291 'return' => 'status_id',
9099cab3 3292 ]);
294cc627 3293 $this->assertEquals(1, $status);
9099cab3 3294 $mut->checkMailLog([
9f9fa558 3295 'amount:::500.00',
39052b78
AH
3296 // The `receive_date` should remain as it was created.
3297 // TODO: the latest payment transaction date (and maybe other details,
3298 // such as amount and payment instrument) would be a useful token to make
3299 // available.
3300 'receive_date:::20120511000000',
76e8d9c4 3301 "receipt_date:::\n",
9099cab3 3302 ]);
294cc627 3303 $mut->stop();
9f9fa558 3304 $this->revertTemplateToReservedTemplate();
294cc627 3305 }
3306
0efa8efe 3307 /**
eceb18cc 3308 * Test completing a transaction with an event via the API.
0efa8efe 3309 *
3310 * Note that we are creating a logged in user because email goes out from
3311 * that person
ed7e2e99 3312 *
3313 * @throws \CRM_Core_Exception
0efa8efe 3314 */
00be9182 3315 public function testCompleteTransactionWithParticipantRecord() {
5896d037 3316 $mut = new CiviMailUtils($this, TRUE);
0efa8efe 3317 $mut->clearMessages();
71acd4bf 3318 $this->_individualId = $this->createLoggedInUser();
0efa8efe 3319 $contributionID = $this->createPendingParticipantContribution();
ed7e2e99 3320 $this->createJoinedProfile(['entity_id' => $this->_ids['event']['test'], 'entity_table' => 'civicrm_event']);
f736929b 3321 $this->createJoinedProfile(['entity_id' => $this->_ids['event']['test'], 'entity_table' => 'civicrm_event', 'weight' => 2], ['name' => 'post_1', 'title' => 'title_post_2', 'frontend_title' => 'public 2']);
3322 $this->createJoinedProfile(['entity_id' => $this->_ids['event']['test'], 'entity_table' => 'civicrm_event', 'weight' => 3], ['name' => 'post_2', 'title' => 'title_post_3', 'frontend_title' => 'public 3']);
3323 $this->eliminateUFGroupOne();
ed7e2e99 3324
9099cab3 3325 $this->callAPISuccess('contribution', 'completetransaction', [
39b959db 3326 'id' => $contributionID,
9099cab3 3327 ]
0efa8efe 3328 );
9099cab3 3329 $participantStatus = $this->callAPISuccessGetValue('participant', [
92915c55
TO
3330 'id' => $this->_ids['participant'],
3331 'return' => 'participant_status_id',
9099cab3 3332 ]);
0efa8efe 3333 $this->assertEquals(1, $participantStatus);
71acd4bf
JP
3334
3335 //Assert only three activities are created.
ed7e2e99 3336 $activities = $this->callAPISuccess('Activity', 'get', [
3337 'contact_id' => $this->_individualId,
3338 ])['values'];
3339
f736929b 3340 $this->assertCount(3, $activities);
71acd4bf 3341 $activityNames = array_count_values(CRM_Utils_Array::collect('activity_name', $activities));
b56b628c 3342 // record two activities before and after completing payment for Event registration
71acd4bf 3343 $this->assertEquals(2, $activityNames['Event Registration']);
b56b628c 3344 // update the original 'Contribution' activity created after completing payment
71acd4bf
JP
3345 $this->assertEquals(1, $activityNames['Contribution']);
3346
9099cab3 3347 $mut->checkMailLog([
0efa8efe 3348 'Annual CiviCRM meet',
3349 'Event',
12ff7379 3350 'This is a confirmation that your registration has been received and your status has been updated to Registered.',
ed7e2e99 3351 'First Name: Logged In',
3352 'Public title',
f736929b 3353 'public 2',
3354 'public 3',
3355 ], ['Back end title', 'title_post_2', 'title_post_3']);
66d3f9be
EM
3356 $mut->stop();
3357 }
3358
3359 /**
eceb18cc 3360 * Test membership is renewed when transaction completed.
66d3f9be 3361 */
00be9182 3362 public function testCompleteTransactionMembershipPriceSet() {
66d3f9be 3363 $this->createPriceSetWithPage('membership');
9099cab3 3364 $stateOfGrace = $this->callAPISuccess('MembershipStatus', 'getvalue', [
4ff927bc 3365 'name' => 'Grace',
39b959db 3366 'return' => 'id',
9099cab3 3367 ]);
66d3f9be 3368 $this->setUpPendingContribution($this->_ids['price_field_value'][0]);
9099cab3
CW
3369 $membership = $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
3370 $logs = $this->callAPISuccess('MembershipLog', 'get', [
4ff927bc 3371 'membership_id' => $this->_ids['membership'],
9099cab3 3372 ]);
4ff927bc 3373 $this->assertEquals(1, $logs['count']);
3374 $this->assertEquals($stateOfGrace, $membership['status_id']);
9099cab3
CW
3375 $this->callAPISuccess('contribution', 'completetransaction', ['id' => $this->_ids['contribution']]);
3376 $membership = $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
66d3f9be 3377 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 1 year')), $membership['end_date']);
9099cab3 3378 $this->callAPISuccessGetSingle('LineItem', [
4ff927bc 3379 'entity_id' => $this->_ids['membership'],
3380 'entity_table' => 'civicrm_membership',
9099cab3
CW
3381 ]);
3382 $logs = $this->callAPISuccess('MembershipLog', 'get', [
4ff927bc 3383 'membership_id' => $this->_ids['membership'],
9099cab3 3384 ]);
4ff927bc 3385 $this->assertEquals(2, $logs['count']);
3386 $this->assertNotEquals($stateOfGrace, $logs['values'][2]['status_id']);
98f0683a
JP
3387 //Assert only three activities are created.
3388 $activities = CRM_Activity_BAO_Activity::getContactActivity($this->_ids['contact']);
3389 $this->assertEquals(3, count($activities));
3390 $activityNames = array_flip(CRM_Utils_Array::collect('activity_name', $activities));
3391 $this->assertArrayHasKey('Contribution', $activityNames);
3392 $this->assertArrayHasKey('Membership Signup', $activityNames);
3393 $this->assertArrayHasKey('Change Membership Status', $activityNames);
66d3f9be
EM
3394 $this->cleanUpAfterPriceSets();
3395 }
3396
0f07bb06 3397 /**
3398 * Test if renewal activity is create after changing Pending contribution to Completed via offline
3399 */
3400 public function testPendingToCompleteContribution() {
c77986c0 3401 $this->createPriceSetWithPage('membership');
0f07bb06 3402 $this->setUpPendingContribution($this->_ids['price_field_value'][0]);
9099cab3 3403 $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
66a1e31f 3404 // Case 1: Assert that Membership Signup Activity is created on Pending to Completed Contribution via backoffice
9099cab3 3405 $activity = $this->callAPISuccess('Activity', 'get', [
b6d493f3
MD
3406 'activity_type_id' => 'Membership Signup',
3407 'source_record_id' => $this->_ids['membership'],
3408 'status_id' => 'Scheduled',
9099cab3 3409 ]);
b6d493f3 3410 $this->assertEquals(1, $activity['count']);
0f07bb06 3411
3412 // change pending contribution to completed
3413 $form = new CRM_Contribute_Form_Contribution();
c77986c0 3414
9099cab3 3415 $form->_params = [
0f07bb06 3416 'id' => $this->_ids['contribution'],
3417 'total_amount' => 20,
3418 'net_amount' => 20,
3419 'fee_amount' => 0,
3420 'financial_type_id' => 1,
0f07bb06 3421 'contact_id' => $this->_individualId,
3422 'contribution_status_id' => 1,
3423 'billing_middle_name' => '',
3424 'billing_last_name' => 'Adams',
3425 'billing_street_address-5' => '790L Lincoln St S',
3426 'billing_city-5' => 'Maryknoll',
3427 'billing_state_province_id-5' => 1031,
3428 'billing_postal_code-5' => 10545,
3429 'billing_country_id-5' => 1228,
3430 'frequency_interval' => 1,
3431 'frequency_unit' => 'month',
3432 'installments' => '',
3433 'hidden_AdditionalDetail' => 1,
3434 'hidden_Premium' => 1,
3435 'from_email_address' => '"civi45" <civi45@civicrm.com>',
3436 'receipt_date' => '',
3437 'receipt_date_time' => '',
3438 'payment_processor_id' => $this->paymentProcessorID,
3439 'currency' => 'USD',
3440 'contribution_page_id' => $this->_ids['contribution_page'],
3441 'contribution_mode' => 'membership',
3442 'source' => 'Membership Signup and Renewal',
9099cab3 3443 ];
c77986c0 3444
3445 $form->testSubmit($form->_params, CRM_Core_Action::UPDATE);
3446
66a1e31f 3447 // Case 2: After successful payment for Pending backoffice there are three activities created
b6d493f3 3448 // 2.a Update status of existing Scheduled Membership Signup (created in step 1) to Completed
9099cab3 3449 $activity = $this->callAPISuccess('Activity', 'get', [
767d3e2e 3450 'activity_type_id' => 'Membership Signup',
b6d493f3
MD
3451 'source_record_id' => $this->_ids['membership'],
3452 'status_id' => 'Completed',
9099cab3 3453 ]);
767d3e2e 3454 $this->assertEquals(1, $activity['count']);
b6d493f3 3455 // 2.b Contribution activity created to record successful payment
9099cab3 3456 $activity = $this->callAPISuccess('Activity', 'get', [
b6d493f3 3457 'activity_type_id' => 'Contribution',
767d3e2e 3458 'source_record_id' => $this->_ids['contribution'],
b6d493f3 3459 'status_id' => 'Completed',
9099cab3 3460 ]);
b6d493f3 3461 $this->assertEquals(1, $activity['count']);
fde55343 3462
b6d493f3 3463 // 2.c 'Change membership type' activity created to record Membership status change from Grace to Current
9099cab3 3464 $activity = $this->callAPISuccess('Activity', 'get', [
b6d493f3
MD
3465 'activity_type_id' => 'Change Membership Status',
3466 'source_record_id' => $this->_ids['membership'],
3467 'status_id' => 'Completed',
9099cab3 3468 ]);
d2460a89 3469 $this->assertEquals(1, $activity['count']);
b6d493f3 3470 $this->assertEquals('Status changed from Grace to Current', $activity['values'][$activity['id']]['subject']);
fde55343
JP
3471
3472 //Create another pending contribution for renewal
9099cab3 3473 $contribution = $this->callAPISuccess('contribution', 'create', [
fde55343
JP
3474 'domain_id' => 1,
3475 'contact_id' => $this->_ids['contact'],
3476 'receive_date' => date('Ymd'),
3477 'total_amount' => 20.00,
3478 'financial_type_id' => 1,
3479 'payment_instrument_id' => 'Credit Card',
3480 'non_deductible_amount' => 10.00,
3481 'trxn_id' => 'rdhfi88',
3482 'invoice_id' => 'dofhiewuyr',
3483 'source' => 'SSF',
3484 'contribution_status_id' => 2,
3485 'contribution_page_id' => $this->_ids['contribution_page'],
c77986c0 3486 // We can't rely on contribution api to link line items correctly to membership
3487 'skipLineItem' => TRUE,
9099cab3
CW
3488 'api.membership_payment.create' => ['membership_id' => $this->_ids['membership']],
3489 ]);
fde55343 3490
9099cab3 3491 $this->callAPISuccess('line_item', 'create', [
fde55343
JP
3492 'entity_id' => $contribution['id'],
3493 'entity_table' => 'civicrm_contribution',
3494 'contribution_id' => $contribution['id'],
3495 'price_field_id' => $this->_ids['price_field'][0],
3496 'qty' => 1,
3497 'unit_price' => 20,
3498 'line_total' => 20,
3499 'financial_type_id' => 1,
c77986c0 3500 'price_field_value_id' => $this->_ids['price_field_value']['cont'],
9099cab3
CW
3501 ]);
3502 $this->callAPISuccess('line_item', 'create', [
c77986c0 3503 'entity_id' => $this->_ids['membership'],
3504 'entity_table' => 'civicrm_membership',
3505 'contribution_id' => $contribution['id'],
3506 'price_field_id' => $this->_ids['price_field'][0],
3507 'qty' => 1,
3508 'unit_price' => 20,
3509 'line_total' => 20,
3510 'financial_type_id' => 1,
fde55343 3511 'price_field_value_id' => $this->_ids['price_field_value'][0],
c77986c0 3512 'membership_type_id' => $this->_ids['membership_type'],
9099cab3 3513 ]);
fde55343
JP
3514
3515 //Update it to Failed.
3516 $form->_params['id'] = $contribution['id'];
3517 $form->_params['contribution_status_id'] = 4;
c77986c0 3518
3519 $form->testSubmit($form->_params, CRM_Core_Action::UPDATE);
fde55343 3520 //Existing membership should not get updated to expired.
9099cab3 3521 $membership = $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
fde55343 3522 $this->assertNotEquals($membership['status_id'], 4);
0f07bb06 3523 }
3524
66d3f9be 3525 /**
7e9abd5a 3526 * Test membership is renewed for 2 terms when transaction completed based on the line item having 2 terms as qty.
3527 *
3528 * Also check that altering the qty for the most recent contribution results in repeattransaction picking it up.
66d3f9be 3529 */
00be9182 3530 public function testCompleteTransactionMembershipPriceSetTwoTerms() {
66d3f9be
EM
3531 $this->createPriceSetWithPage('membership');
3532 $this->setUpPendingContribution($this->_ids['price_field_value'][1]);
9099cab3 3533 $this->callAPISuccess('contribution', 'completetransaction', ['id' => $this->_ids['contribution']]);
7e9abd5a 3534 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
66d3f9be 3535 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 2 years')), $membership['end_date']);
7e9abd5a 3536
3537 $paymentProcessorID = $this->paymentProcessorAuthorizeNetCreate();
3538
3539 $contributionRecurID = $this->callAPISuccess('ContributionRecur', 'create', ['contact_id' => $membership['contact_id'], 'payment_processor_id' => $paymentProcessorID, 'amount' => 20, 'frequency_interval' => 1])['id'];
3540 $this->callAPISuccess('Contribution', 'create', ['id' => $this->_ids['contribution'], 'contribution_recur_id' => $contributionRecurID]);
3541 $this->callAPISuccess('contribution', 'repeattransaction', ['contribution_recur_id' => $contributionRecurID, 'contribution_status_id' => 'Completed']);
3542 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
3543 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 4 years')), $membership['end_date']);
3544
3545 // Update the most recent contribution to have a qty of 1 in it's line item and then repeat, expecting just 1 year to be added.
3546 $contribution = Contribution::get()->setOrderBy(['id' => 'DESC'])->setSelect(['id'])->execute()->first();
3547 CRM_Core_DAO::executeQuery('UPDATE civicrm_line_item SET price_field_value_id = ' . $this->_ids['price_field_value'][0] . ' WHERE contribution_id = ' . $contribution['id']);
3548 $this->callAPISuccess('contribution', 'repeattransaction', ['contribution_recur_id' => $contributionRecurID, 'contribution_status_id' => 'Completed']);
3549 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
3550 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 5 years')), $membership['end_date']);
3551
66d3f9be
EM
3552 $this->cleanUpAfterPriceSets();
3553 }
3554
00be9182 3555 public function cleanUpAfterPriceSets() {
1cf3c2b1 3556 $this->quickCleanUpFinancialEntities();
66d3f9be 3557 $this->contactDelete($this->_ids['contact']);
66d3f9be
EM
3558 }
3559
66d3f9be 3560 /**
eceb18cc 3561 * Set up a pending transaction with a specific price field id.
1e52837d 3562 *
100fef9d 3563 * @param int $priceFieldValueID
39b959db 3564 * @param array $contriParams
5d4c1098 3565 *
3566 * @throws \CRM_Core_Exception
66d3f9be 3567 */
9099cab3 3568 public function setUpPendingContribution($priceFieldValueID, $contriParams = []) {
66d3f9be 3569 $contactID = $this->individualCreate();
5d4c1098 3570 $contribution = $this->callAPISuccess('Order', 'create', array_merge([
66d3f9be
EM
3571 'domain_id' => 1,
3572 'contact_id' => $contactID,
3573 'receive_date' => date('Ymd'),
0f07bb06 3574 'total_amount' => 20.00,
66d3f9be
EM
3575 'financial_type_id' => 1,
3576 'payment_instrument_id' => 'Credit Card',
3577 'non_deductible_amount' => 10.00,
98f0683a
JP
3578 'trxn_id' => 'jdhfi' . rand(1, 100),
3579 'invoice_id' => 'djfhiew' . rand(5, 100),
66d3f9be
EM
3580 'source' => 'SSF',
3581 'contribution_status_id' => 2,
3582 'contribution_page_id' => $this->_ids['contribution_page'],
5d4c1098 3583 'line_items' => [
3584 [
3585 'line_item' => [
3586 [
3587 'price_field_id' => $this->_ids['price_field'][0],
3588 'qty' => 1,
3589 'entity_table' => 'civicrm_membership',
3590 'unit_price' => 20,
3591 'line_total' => 20,
3592 'financial_type_id' => 1,
3593 'price_field_value_id' => $priceFieldValueID,
3594 ],
3595 ],
3596 'params' => [
3597 'contact_id' => $contactID,
3598 'membership_type_id' => $this->_ids['membership_type'],
3599 'start_date' => 'yesterday - 1 year',
3600 'end_date' => 'yesterday',
3601 'join_date' => 'yesterday - 1 year',
3602 ],
3603 ],
3604 ],
9099cab3 3605 ], $contriParams));
66d3f9be 3606
66d3f9be
EM
3607 $this->_ids['contact'] = $contactID;
3608 $this->_ids['contribution'] = $contribution['id'];
5d4c1098 3609 $this->_ids['membership'] = $this->callAPISuccessGetValue('MembershipPayment', ['return' => 'membership_id', 'contribution_id' => $contribution['id']]);
0efa8efe 3610 }
3611
2f45e1c2 3612 /**
eceb18cc 3613 * Test sending a mail via the API.
450dfb41 3614 *
3615 * @throws \CRM_Core_Exception
49cba3ad 3616 * @throws \CiviCRM_API3_Exception
6a488035 3617 */
00be9182 3618 public function testSendMail() {
5896d037 3619 $mut = new CiviMailUtils($this, TRUE);
49cba3ad 3620 $orderParams = $this->_params;
3621 $orderParams['contribution_status_id'] = 'Pending';
3622 $orderParams['api.PaymentProcessor.pay'] = [
3623 'payment_processor_id' => $this->paymentProcessorID,
3624 'credit_card_type' => 'Visa',
3625 'credit_card_number' => 41111111111111,
3626 'amount' => 5,
3627 ];
3628
3629 $order = $this->callAPISuccess('Order', 'create', $orderParams);
3630 $this->callAPISuccess('Payment', 'create', ['total_amount' => 5, 'is_send_notification' => 0, 'order_id' => $order['id']]);
3631 $address = $this->callAPISuccess('Address', 'create', ['contribution_id' => $order['id'], 'name' => 'bob', 'contact_id' => 1, 'street_address' => 'blah']);
3632 $this->callAPISuccess('Contribution', 'create', ['id' => $order['id'], 'address_id' => $address['id']]);
9099cab3 3633 $this->callAPISuccess('contribution', 'sendconfirmation', [
49cba3ad 3634 'id' => $order['id'],
39b959db 3635 'receipt_from_email' => 'api@civicrm.org',
9099cab3
CW
3636 ]);
3637 $mut->checkMailLog([
39b959db
SL
3638 '$ 100.00',
3639 'Contribution Information',
9099cab3 3640 ], [
39b959db 3641 'Event',
9099cab3 3642 ]);
128d44a1 3643
49cba3ad 3644 $this->checkCreditCardDetails($mut, $order['id']);
6a488035 3645 $mut->stop();
49cba3ad 3646 $tplVars = CRM_Core_Smarty::singleton()->get_template_vars();
3647 $this->assertEquals('bob', $tplVars['billingName']);
3648 $this->assertEquals("bob\nblah\n", $tplVars['address']);
6a488035
TO
3649 }
3650
dbacb875
AS
3651 /**
3652 * Test sending a mail via the API.
3653 * This simulates webform_civicrm using pay later contribution page
3654 */
3655 public function testSendconfirmationPayLater() {
3656 $mut = new CiviMailUtils($this, TRUE);
3657
3658 // Create contribution page
9099cab3 3659 $pageParams = [
dbacb875
AS
3660 'title' => 'Webform Contributions',
3661 'financial_type_id' => 1,
3662 'contribution_type_id' => 1,
3663 'is_confirm_enabled' => 1,
3664 'is_pay_later' => 1,
3665 'pay_later_text' => 'I will send payment by cheque',
3666 'pay_later_receipt' => 'Send your cheque payable to "CiviCRM LLC" to the office',
9099cab3 3667 ];
dbacb875
AS
3668 $contributionPage = $this->callAPISuccess('contribution_page', 'create', $pageParams);
3669
3670 // Create pay later contribution
9099cab3 3671 $contribParams = [
dbacb875
AS
3672 'contact_id' => $this->_individualId,
3673 'financial_type_id' => 1,
3674 'is_pay_later' => 1,
3675 'contribution_status_id' => 2,
3676 'contribution_page_id' => $contributionPage['id'],
3677 'total_amount' => '10.00',
9099cab3 3678 ];
dbacb875
AS
3679 $contribution = $this->callAPISuccess('contribution', 'create', $contribParams);
3680
3681 // Create line item
9099cab3 3682 $lineItemParams = [
dbacb875
AS
3683 'contribution_id' => $contribution['id'],
3684 'entity_id' => $contribution['id'],
3685 'entity_table' => 'civicrm_contribution',
3686 'label' => 'My lineitem label',
3687 'qty' => 1,
3688 'unit_price' => "10.00",
3689 'line_total' => "10.00",
9099cab3 3690 ];
dbacb875
AS
3691 $lineItem = $this->callAPISuccess('lineItem', 'create', $lineItemParams);
3692
3693 // Create email
3694 try {
9099cab3 3695 civicrm_api3('contribution', 'sendconfirmation', [
39b959db
SL
3696 'id' => $contribution['id'],
3697 'receipt_from_email' => 'api@civicrm.org',
9099cab3 3698 ]);
717fdb8a
AS
3699 }
3700 catch (Exception $e) {
dbacb875
AS
3701 // Need to figure out how to stop this some other day
3702 // We don't care about the Payment Processor because this is Pay Later
3703 // The point of this test is to check we get the pay_later version of the mail
3704 if ($e->getMessage() != "Undefined variable: CRM16923AnUnreliableMethodHasBeenUserToDeterminePaymentProcessorFromContributionPage") {
3705 throw $e;
3706 }
3707 }
3708
3709 // Retrieve mail & check it has the pay_later_receipt info
3710 $mut->getMostRecentEmail('raw');
9099cab3 3711 $mut->checkMailLog([
39b959db
SL
3712 (string) $contribParams['total_amount'],
3713 $pageParams['pay_later_receipt'],
9099cab3 3714 ], [
39b959db 3715 'Event',
9099cab3 3716 ]);
dbacb875
AS
3717 $mut->stop();
3718 }
3719
128d44a1 3720 /**
3721 * Check credit card details in sent mail via API
3722 *
450dfb41 3723 * @param CiviMailUtils $mut
128d44a1 3724 * @param int $contributionID Contribution ID
3725 *
450dfb41 3726 * @throws \CRM_Core_Exception
128d44a1 3727 */
3728 public function checkCreditCardDetails($mut, $contributionID) {
450dfb41 3729 $this->callAPISuccess('contribution', 'create', $this->_params);
9099cab3 3730 $this->callAPISuccess('contribution', 'sendconfirmation', [
39b959db
SL
3731 'id' => $contributionID,
3732 'receipt_from_email' => 'api@civicrm.org',
3733 'payment_processor_id' => $this->paymentProcessorID,
9099cab3
CW
3734 ]);
3735 $mut->checkMailLog([
39b959db
SL
3736 // billing header
3737 'Billing Name and Address',
3738 // billing name
3739 'anthony_anderson@civicrm.org',
9099cab3 3740 ], [
39b959db 3741 'Event',
9099cab3 3742 ]);
128d44a1 3743 }
3744
2f45e1c2 3745 /**
eceb18cc 3746 * Test sending a mail via the API.
6a488035 3747 */
00be9182 3748 public function testSendMailEvent() {
5896d037 3749 $mut = new CiviMailUtils($this, TRUE);
6c6e6187 3750 $contribution = $this->callAPISuccess('contribution', 'create', $this->_params);
9099cab3 3751 $event = $this->eventCreate([
6a488035
TO
3752 'is_email_confirm' => 1,
3753 'confirm_from_email' => 'test@civicrm.org',
9099cab3 3754 ]);
6a488035 3755 $this->_eventID = $event['id'];
9099cab3 3756 $participantParams = [
6a488035
TO
3757 'contact_id' => $this->_individualId,
3758 'event_id' => $this->_eventID,
3759 'status_id' => 1,
3760 'role_id' => 1,
3761 // to ensure it matches later on
3762 'register_date' => '2007-07-21 00:00:00',
3763 'source' => 'Online Event Registration: API Testing',
4ab7d517 3764
9099cab3 3765 ];
2f45e1c2 3766 $participant = $this->callAPISuccess('participant', 'create', $participantParams);
9099cab3 3767 $this->callAPISuccess('participant_payment', 'create', [
6a488035
TO
3768 'participant_id' => $participant['id'],
3769 'contribution_id' => $contribution['id'],
9099cab3
CW
3770 ]);
3771 $this->callAPISuccess('contribution', 'sendconfirmation', [
39b959db
SL
3772 'id' => $contribution['id'],
3773 'receipt_from_email' => 'api@civicrm.org',
9099cab3 3774 ]);
6a488035 3775
9099cab3 3776 $mut->checkMailLog([
39b959db
SL
3777 'Annual CiviCRM meet',
3778 'Event',
3779 'To: "Mr. Anthony Anderson II" <anthony_anderson@civicrm.org>',
9099cab3 3780 ], []);
6a488035
TO
3781 $mut->stop();
3782 }
3783
4302618d 3784 /**
1e52837d
EM
3785 * This function does a GET & compares the result against the $params.
3786 *
3787 * Use as a double check on Creates.
3788 *
3789 * @param array $params
3790 * @param int $id
67f947ac 3791 * @param bool $delete
6c6e6187 3792 */
1e52837d 3793 public function contributionGetnCheck($params, $id, $delete = TRUE) {
6a488035 3794
9099cab3 3795 $contribution = $this->callAPISuccess('Contribution', 'Get', [
6a488035 3796 'id' => $id,
9099cab3 3797 ]);
6a488035
TO
3798
3799 if ($delete) {
9099cab3 3800 $this->callAPISuccess('contribution', 'delete', ['id' => $id]);
6a488035 3801 }
2bfae985 3802 $this->assertAPISuccess($contribution, 0);
6a488035
TO
3803 $values = $contribution['values'][$contribution['id']];
3804 $params['receive_date'] = date('Y-m-d H:i:s', strtotime($params['receive_date']));
3805 // this is not returned in id format
3806 unset($params['payment_instrument_id']);
3807 $params['contribution_source'] = $params['source'];
3808 unset($params['source']);
3809 foreach ($params as $key => $value) {
22f80e87 3810 $this->assertEquals($value, $values[$key], $key . " value: $value doesn't match " . print_r($values, TRUE));
6a488035
TO
3811 }
3812 }
3813
294cc627 3814 /**
3815 * Create a pending contribution & linked pending pledge record.
3816 */
3817 public function createPendingPledgeContribution() {
3818
9099cab3 3819 $pledgeID = $this->pledgeCreate(['contact_id' => $this->_individualId, 'installments' => 1, 'amount' => 500]);
294cc627 3820 $this->_ids['pledge'] = $pledgeID;
9099cab3 3821 $contribution = $this->callAPISuccess('contribution', 'create', array_merge($this->_params, [
294cc627 3822 'contribution_status_id' => 'Pending',
39b959db 3823 'total_amount' => 500,
9099cab3
CW
3824 ]));
3825 $paymentID = $this->callAPISuccessGetValue('PledgePayment', [
3826 'options' => ['limit' => 1],
294cc627 3827 'return' => 'id',
9099cab3
CW
3828 ]);
3829 $this->callAPISuccess('PledgePayment', 'create', [
294cc627 3830 'id' => $paymentID,
3831 'contribution_id' =>
3832 $contribution['id'],
3833 'status_id' => 'Pending',
3834 'scheduled_amount' => 500,
9099cab3 3835 ]);
294cc627 3836
3837 return $contribution['id'];
3838 }
3839
0efa8efe 3840 /**
1e52837d 3841 * Create a pending contribution & linked pending participant record (along with an event).
0efa8efe 3842 */
5896d037 3843 public function createPendingParticipantContribution() {
ed7e2e99 3844 $this->_ids['event']['test'] = $this->eventCreate(['is_email_confirm' => 1, 'confirm_from_email' => 'test@civicrm.org'])['id'];
3845 $participantID = $this->participantCreate(['event_id' => $this->_ids['event']['test'], 'status_id' => 6, 'contact_id' => $this->_individualId]);
5896d037 3846 $this->_ids['participant'] = $participantID;
9099cab3 3847 $params = array_merge($this->_params, ['contact_id' => $this->_individualId, 'contribution_status_id' => 2, 'financial_type_id' => 'Event Fee']);
6c6e6187 3848 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 3849 $this->callAPISuccess('participant_payment', 'create', [
92915c55
TO
3850 'contribution_id' => $contribution['id'],
3851 'participant_id' => $participantID,
9099cab3
CW
3852 ]);
3853 $this->callAPISuccess('line_item', 'get', [
0efa8efe 3854 'entity_id' => $contribution['id'],
3855 'entity_table' => 'civicrm_contribution',
9099cab3 3856 'api.line_item.create' => [
0efa8efe 3857 'entity_id' => $participantID,
3858 'entity_table' => 'civicrm_participant',
9099cab3
CW
3859 ],
3860 ]);
0efa8efe 3861 return $contribution['id'];
3862 }
3863
4cbe18b8 3864 /**
1e52837d
EM
3865 * Get financial transaction amount.
3866 *
100fef9d 3867 * @param int $contId
4cbe18b8
EM
3868 *
3869 * @return null|string
f4d89200 3870 */
2da40d21 3871 public function _getFinancialTrxnAmount($contId) {
6c6e6187 3872 $query = "SELECT
6a488035
TO
3873 SUM( ft.total_amount ) AS total
3874 FROM civicrm_financial_trxn AS ft
3875 LEFT JOIN civicrm_entity_financial_trxn AS ceft ON ft.id = ceft.financial_trxn_id
3876 WHERE ceft.entity_table = 'civicrm_contribution'
3877 AND ceft.entity_id = {$contId}";
3878
6c6e6187
TO
3879 $result = CRM_Core_DAO::singleValueQuery($query);
3880 return $result;
3881 }
6a488035 3882
4cbe18b8 3883 /**
100fef9d 3884 * @param int $contId
4cbe18b8
EM
3885 *
3886 * @return null|string
f4d89200 3887 */
2da40d21 3888 public function _getFinancialItemAmount($contId) {
6c6e6187
TO
3889 $lineItem = key(CRM_Price_BAO_LineItem::getLineItems($contId, 'contribution'));
3890 $query = "SELECT
6a488035
TO
3891 SUM(amount)
3892 FROM civicrm_financial_item
3893 WHERE entity_table = 'civicrm_line_item'
3894 AND entity_id = {$lineItem}";
6c6e6187
TO
3895 $result = CRM_Core_DAO::singleValueQuery($query);
3896 return $result;
3897 }
6a488035 3898
4cbe18b8 3899 /**
100fef9d 3900 * @param int $contId
4cbe18b8
EM
3901 * @param $context
3902 */
00be9182 3903 public function _checkFinancialItem($contId, $context) {
6c6e6187 3904 if ($context != 'paylater') {
9099cab3 3905 $params = [
5896d037
TO
3906 'entity_id' => $contId,
3907 'entity_table' => 'civicrm_contribution',
9099cab3 3908 ];
6c6e6187 3909 $trxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($params, TRUE));
9099cab3 3910 $entityParams = [
6a488035
TO
3911 'financial_trxn_id' => $trxn['financial_trxn_id'],
3912 'entity_table' => 'civicrm_financial_item',
9099cab3 3913 ];
6c6e6187 3914 $entityTrxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($entityParams));
9099cab3 3915 $params = [
6a488035 3916 'id' => $entityTrxn['entity_id'],
9099cab3 3917 ];
6c6e6187
TO
3918 }
3919 if ($context == 'paylater') {
3920 $lineItems = CRM_Price_BAO_LineItem::getLineItems($contId, 'contribution');
3921 foreach ($lineItems as $key => $item) {
9099cab3 3922 $params = [
5896d037
TO
3923 'entity_id' => $key,
3924 'entity_table' => 'civicrm_line_item',
9099cab3
CW
3925 ];
3926 $compareParams = ['status_id' => 1];
6c6e6187
TO
3927 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialItem', $params, $compareParams);
3928 }
3929 }
3930 elseif ($context == 'refund') {
9099cab3 3931 $compareParams = [
5896d037
TO
3932 'status_id' => 1,
3933 'financial_account_id' => 1,
3934 'amount' => -100,
9099cab3 3935 ];
6c6e6187
TO
3936 }
3937 elseif ($context == 'cancelPending') {
9099cab3 3938 $compareParams = [
5896d037
TO
3939 'status_id' => 3,
3940 'financial_account_id' => 1,
3941 'amount' => -100,
9099cab3 3942 ];
6c6e6187
TO
3943 }
3944 elseif ($context == 'changeFinancial') {
3945 $lineKey = key(CRM_Price_BAO_LineItem::getLineItems($contId, 'contribution'));
9099cab3 3946 $params = [
5896d037
TO
3947 'entity_id' => $lineKey,
3948 'amount' => -100,
9099cab3
CW
3949 ];
3950 $compareParams = [
5896d037 3951 'financial_account_id' => 1,
9099cab3 3952 ];
6c6e6187 3953 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialItem', $params, $compareParams);
9099cab3 3954 $params = [
5896d037
TO
3955 'financial_account_id' => 3,
3956 'entity_id' => $lineKey,
9099cab3
CW
3957 ];
3958 $compareParams = [
5896d037 3959 'amount' => 100,
9099cab3 3960 ];
6c6e6187
TO
3961 }
3962 if ($context != 'paylater') {
3963 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialItem', $params, $compareParams);
3964 }
3965 }
6a488035 3966
b0e806fa 3967 /**
3968 * Check correct financial transaction entries were created for the change in payment instrument.
3969 *
3970 * @param int $contributionID
3971 * @param int $originalInstrumentID
3972 * @param int $newInstrumentID
39b959db 3973 * @param int $amount
b0e806fa 3974 */
3975 public function checkFinancialTrxnPaymentInstrumentChange($contributionID, $originalInstrumentID, $newInstrumentID, $amount = 100) {
3976
3977 $entityFinancialTrxns = $this->getFinancialTransactionsForContribution($contributionID);
3978
9099cab3 3979 $originalTrxnParams = [
b0e806fa 3980 'to_financial_account_id' => CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($originalInstrumentID),
3981 'payment_instrument_id' => $originalInstrumentID,
3982 'amount' => $amount,
3983 'status_id' => 1,
9099cab3 3984 ];
b0e806fa 3985
9099cab3 3986 $reversalTrxnParams = [
b0e806fa 3987 'to_financial_account_id' => CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($originalInstrumentID),
3988 'payment_instrument_id' => $originalInstrumentID,
3989 'amount' => -$amount,
3990 'status_id' => 1,
9099cab3 3991 ];
b0e806fa 3992
9099cab3 3993 $newTrxnParams = [
b0e806fa 3994 'to_financial_account_id' => CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($newInstrumentID),
3995 'payment_instrument_id' => $newInstrumentID,
3996 'amount' => $amount,
3997 'status_id' => 1,
9099cab3 3998 ];
b0e806fa 3999
9099cab3 4000 foreach ([$originalTrxnParams, $reversalTrxnParams, $newTrxnParams] as $index => $transaction) {
b0e806fa 4001 $entityFinancialTrxn = $entityFinancialTrxns[$index];
4002 $this->assertEquals($entityFinancialTrxn['amount'], $transaction['amount']);
4003
9099cab3 4004 $financialTrxn = $this->callAPISuccessGetSingle('FinancialTrxn', [
b0e806fa 4005 'id' => $entityFinancialTrxn['financial_trxn_id'],
9099cab3 4006 ]);
b0e806fa 4007 $this->assertEquals($transaction['status_id'], $financialTrxn['status_id']);
4008 $this->assertEquals($transaction['amount'], $financialTrxn['total_amount']);
4009 $this->assertEquals($transaction['amount'], $financialTrxn['net_amount']);
4010 $this->assertEquals(0, $financialTrxn['fee_amount']);
4011 $this->assertEquals($transaction['payment_instrument_id'], $financialTrxn['payment_instrument_id']);
4012 $this->assertEquals($transaction['to_financial_account_id'], $financialTrxn['to_financial_account_id']);
4013
4014 // Generic checks.
4015 $this->assertEquals(1, $financialTrxn['is_payment']);
4016 $this->assertEquals('USD', $financialTrxn['currency']);
4017 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($financialTrxn['trxn_date'])));
4018 }
4019 }
4020
4cbe18b8 4021 /**
52da5b1e 4022 * Check financial transaction.
4023 *
4024 * @todo break this down into sensible functions - most calls to it only use a few lines out of the big if.
4025 *
4ff927bc 4026 * @param array $contribution
4027 * @param string $context
100fef9d 4028 * @param int $instrumentId
52da5b1e 4029 * @param array $extraParams
4cbe18b8 4030 */
9099cab3 4031 public function _checkFinancialTrxn($contribution, $context, $instrumentId = NULL, $extraParams = []) {
b0e806fa 4032 $financialTrxns = $this->getFinancialTransactionsForContribution($contribution['id']);
4033 $trxn = array_pop($financialTrxns);
4034
9099cab3 4035 $params = [
5896d037 4036 'id' => $trxn['financial_trxn_id'],
9099cab3 4037 ];
6c6e6187 4038 if ($context == 'payLater') {
9099cab3 4039 $compareParams = [
5896d037 4040 'status_id' => 1,
876b8ab0 4041 'from_financial_account_id' => CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contribution['financial_type_id'], 'Accounts Receivable Account is'),
9099cab3 4042 ];
6c6e6187
TO
4043 }
4044 elseif ($context == 'refund') {
9099cab3 4045 $compareParams = [
5896d037
TO
4046 'to_financial_account_id' => 6,
4047 'total_amount' => -100,
4048 'status_id' => 7,
b7990bb6 4049 'trxn_date' => '2015-01-01 09:00:00',
797d4c52 4050 'trxn_id' => 'the refund',
9099cab3 4051 ];
6c6e6187
TO
4052 }
4053 elseif ($context == 'cancelPending') {
9099cab3 4054 $compareParams = [
ed4d0aea 4055 'to_financial_account_id' => 7,
5896d037
TO
4056 'total_amount' => -100,
4057 'status_id' => 3,
9099cab3 4058 ];
6c6e6187
TO
4059 }
4060 elseif ($context == 'changeFinancial' || $context == 'paymentInstrument') {
b0e806fa 4061 // @todo checkFinancialTrxnPaymentInstrumentChange instead for paymentInstrument.
4062 // It does the same thing with greater readability.
4063 // @todo remove handling for
4064
9099cab3 4065 $entityParams = [
5896d037
TO
4066 'entity_id' => $contribution['id'],
4067 'entity_table' => 'civicrm_contribution',
4068 'amount' => -100,
9099cab3 4069 ];
6c6e6187 4070 $trxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($entityParams));
9099cab3 4071 $trxnParams1 = [
6a488035 4072 'id' => $trxn['financial_trxn_id'],
9099cab3 4073 ];
122250ec 4074 if (empty($extraParams)) {
9099cab3 4075 $compareParams = [
122250ec
SL
4076 'total_amount' => -100,
4077 'status_id' => 1,
9099cab3 4078 ];
122250ec 4079 }
1a3d69b0 4080 elseif ($context !== 'changeFinancial') {
9099cab3 4081 $compareParams = [
122250ec
SL
4082 'total_amount' => 100,
4083 'status_id' => 1,
9099cab3 4084 ];
122250ec 4085 }
6c6e6187
TO
4086 if ($context == 'paymentInstrument') {
4087 $compareParams['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($instrumentId);
4088 $compareParams['payment_instrument_id'] = $instrumentId;
4089 }
4090 else {
4091 $compareParams['to_financial_account_id'] = 12;
4092 }
5ca657dd 4093 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialTrxn', $trxnParams1, array_merge($compareParams, $extraParams));
4094 $compareParams['total_amount'] = 100;
1a3d69b0
SL
4095 // Reverse the extra params now that we will be checking the new positive transaction.
4096 if ($context === 'changeFinancial' && !empty($extraParams)) {
4097 foreach ($extraParams as $param => $value) {
4098 $extraParams[$param] = 0 - $value;
4099 }
4100 }
6c6e6187
TO
4101 }
4102
797d4c52 4103 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialTrxn', $params, array_merge($compareParams, $extraParams));
6c6e6187 4104 }
6a488035 4105
4cbe18b8
EM
4106 /**
4107 * @return mixed
4108 */
5896d037 4109 public function _addPaymentInstrument() {
6c6e6187 4110 $gId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'payment_instrument', 'id', 'name');
9099cab3 4111 $optionParams = [
5896d037
TO
4112 'option_group_id' => $gId,
4113 'label' => 'Test Card',
4114 'name' => 'Test Card',
4115 'value' => '6',
4116 'weight' => '6',
4117 'is_active' => 1,
9099cab3 4118 ];
6c6e6187
TO
4119 $optionValue = $this->callAPISuccess('option_value', 'create', $optionParams);
4120 $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' "));
9099cab3 4121 $financialParams = [
5896d037
TO
4122 'entity_table' => 'civicrm_option_value',
4123 'entity_id' => $optionValue['id'],
4124 'account_relationship' => $relationTypeId,
4125 'financial_account_id' => 7,
9099cab3 4126 ];
db62d3a5 4127 CRM_Financial_BAO_FinancialTypeAccount::add($financialParams);
6c6e6187
TO
4128 $this->assertNotEmpty($optionValue['values'][$optionValue['id']]['value']);
4129 return $optionValue['values'][$optionValue['id']]['value'];
4130 }
6a488035 4131
02a9c0a4 4132 public function _deletedAddedPaymentInstrument() {
9099cab3 4133 $result = $this->callAPISuccess('OptionValue', 'get', [
02a9c0a4 4134 'option_group_id' => 'payment_instrument',
4135 'name' => 'Test Card',
4136 'value' => '6',
4137 'is_active' => 1,
9099cab3 4138 ]);
02a9c0a4 4139 if ($id = CRM_Utils_Array::value('id', $result)) {
9099cab3 4140 $this->callAPISuccess('OptionValue', 'delete', ['id' => $id]);
02a9c0a4 4141 }
4142 }
4143
3c49d90c 4144 /**
4145 * Set up the basic recurring contribution for tests.
4146 *
4147 * @param array $generalParams
4148 * Parameters that can be merged into the recurring AND the contribution.
7f4ef731 4149 *
4150 * @param array $recurParams
4151 * Parameters to merge into the recur only.
3c49d90c 4152 *
4153 * @return array|int
fa839a68 4154 * @throws \CRM_Core_Exception
3c49d90c 4155 */
9099cab3
CW
4156 protected function setUpRecurringContribution($generalParams = [], $recurParams = []) {
4157 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
3c49d90c 4158 'contact_id' => $this->_individualId,
4159 'installments' => '12',
4160 'frequency_interval' => '1',
4161 'amount' => '100',
4162 'contribution_status_id' => 1,
4163 'start_date' => '2012-01-01 00:00:00',
4164 'currency' => 'USD',
4165 'frequency_unit' => 'month',
4166 'payment_processor_id' => $this->paymentProcessorID,
9099cab3 4167 ], $generalParams, $recurParams));
fa839a68 4168 $contributionParams = array_merge(
3c49d90c 4169 $this->_params,
9099cab3 4170 [
3c49d90c 4171 'contribution_recur_id' => $contributionRecur['id'],
fa839a68 4172 'contribution_status_id' => 'Pending',
4173 ], $generalParams);
4174 $contributionParams['api.Payment.create'] = ['total_amount' => $contributionParams['total_amount']];
4175 $originalContribution = $this->callAPISuccess('Order', 'create', $contributionParams);
3c49d90c 4176 return $originalContribution;
4177 }
4178
d2334242
PH
4179 /**
4180 * Set up a basic auto-renew membership for tests.
4181 *
4182 * @param array $generalParams
4183 * Parameters that can be merged into the recurring AND the contribution.
4184 *
4185 * @param array $recurParams
4186 * Parameters to merge into the recur only.
4187 *
4188 * @return array|int
562e4fb8 4189 * @throws \CRM_Core_Exception
d2334242 4190 */
9099cab3
CW
4191 protected function setUpAutoRenewMembership($generalParams = [], $recurParams = []) {
4192 $newContact = $this->callAPISuccess('Contact', 'create', [
39b959db
SL
4193 'contact_type' => 'Individual',
4194 'sort_name' => 'McTesterson, Testy',
4195 'display_name' => 'Testy McTesterson',
4196 'preferred_language' => 'en_US',
4197 'preferred_mail_format' => 'Both',
4198 'first_name' => 'Testy',
4199 'last_name' => 'McTesterson',
4200 'contact_is_deleted' => '0',
4201 'email_id' => '4',
4202 'email' => 'tmctesterson@example.com',
4203 'on_hold' => '0',
9099cab3
CW
4204 ]);
4205 $membershipType = $this->callAPISuccess('MembershipType', 'create', [
562e4fb8 4206 'domain_id' => 'Default Domain Name',
d2334242 4207 'member_of_contact_id' => 1,
562e4fb8 4208 'financial_type_id' => 'Member Dues',
4209 'duration_unit' => 'month',
d2334242 4210 'duration_interval' => 1,
5b1b8db2 4211 'period_type' => 'rolling',
562e4fb8 4212 'name' => 'Standard Member',
d2334242 4213 'minimum_fee' => 100,
9099cab3
CW
4214 ]);
4215 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
76e80087 4216 'contact_id' => $newContact['id'],
d2334242
PH
4217 'installments' => '12',
4218 'frequency_interval' => '1',
4219 'amount' => '100',
4220 'contribution_status_id' => 1,
4221 'start_date' => '2012-01-01 00:00:00',
4222 'currency' => 'USD',
4223 'frequency_unit' => 'month',
4224 'payment_processor_id' => $this->paymentProcessorID,
9099cab3 4225 ], $generalParams, $recurParams));
7c3f3d59 4226
9099cab3 4227 $membership = $this->callAPISuccess('membership', 'create', [
7c3f3d59 4228 'contact_id' => $newContact['id'],
4229 'contribution_recur_id' => $contributionRecur['id'],
4230 'financial_type_id' => "Member Dues",
4231 'membership_type_id' => $membershipType['id'],
4232 'num_terms' => 1,
4233 'skipLineItem' => TRUE,
9099cab3 4234 ]);
7c3f3d59 4235
4236 CRM_Price_BAO_LineItem::getLineItemArray($this->_params, NULL, 'membership', $membershipType['id']);
d2334242
PH
4237 $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
4238 $this->_params,
9099cab3 4239 [
d2334242
PH
4240 'contact_id' => $newContact['id'],
4241 'contribution_recur_id' => $contributionRecur['id'],
4242 'financial_type_id' => "Member Dues",
4243 'contribution_status_id' => 1,
4244 'invoice_id' => uniqid(),
9099cab3 4245 ], $generalParams)
d2334242 4246 );
9099cab3 4247 $lineItem = $this->callAPISuccess('LineItem', 'getsingle', []);
7c3f3d59 4248 $this->assertEquals('civicrm_membership', $lineItem['entity_table']);
9099cab3
CW
4249 $membership = $this->callAPISuccess('Membership', 'getsingle', ['id' => $lineItem['entity_id']]);
4250 $this->callAPISuccess('LineItem', 'getsingle', []);
4251 $this->callAPISuccessGetCount('MembershipPayment', ['membership_id' => $membership['id']], 1);
d2334242 4252
9099cab3 4253 return [$originalContribution, $membership];
d2334242 4254 }
39b959db 4255
893a550c 4256 /**
4257 * Set up a repeat transaction.
4258 *
4259 * @param array $recurParams
39b959db
SL
4260 * @param mixed $flag
4261 * @param array $contributionParams
893a550c 4262 * @return array
4263 */
9099cab3 4264 protected function setUpRepeatTransaction($recurParams = [], $flag, $contributionParams = []) {
893a550c 4265 $paymentProcessorID = $this->paymentProcessorCreate();
9099cab3 4266 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
893a550c 4267 'contact_id' => $this->_individualId,
4268 'installments' => '12',
4269 'frequency_interval' => '1',
4270 'amount' => '500',
4271 'contribution_status_id' => 1,
4272 'start_date' => '2012-01-01 00:00:00',
4273 'currency' => 'USD',
4274 'frequency_unit' => 'month',
4275 'payment_processor_id' => $paymentProcessorID,
9099cab3 4276 ], $recurParams));
0e6ccb2e 4277
7150b1c8 4278 $originalContribution = '';
0e6ccb2e 4279 if ($flag == 'multiple') {
7150b1c8 4280 // CRM-19309 create a contribution + also add in line_items (plural):
19893cf2 4281 $params = array_merge($this->_params, $contributionParams);
0e6ccb2e 4282 $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
19893cf2 4283 $params,
9099cab3 4284 [
0e6ccb2e
K
4285 'contribution_recur_id' => $contributionRecur['id'],
4286 'skipLineItem' => 1,
9099cab3
CW
4287 'api.line_item.create' => [
4288 [
0e6ccb2e
K
4289 'price_field_id' => 1,
4290 'qty' => 2,
4291 'line_total' => '20',
4292 'unit_price' => '10',
4293 'financial_type_id' => 1,
9099cab3
CW
4294 ],
4295 [
0e6ccb2e
K
4296 'price_field_id' => 1,
4297 'qty' => 1,
4298 'line_total' => '80',
4299 'unit_price' => '80',
4300 'financial_type_id' => 2,
9099cab3
CW
4301 ],
4302 ],
4303 ]
0e6ccb2e
K
4304 )
4305 );
4306 }
4307 elseif ($flag == 'single') {
9099cab3 4308 $params = array_merge($this->_params, ['contribution_recur_id' => $contributionRecur['id']]);
19893cf2
SL
4309 $params = array_merge($params, $contributionParams);
4310 $originalContribution = $this->callAPISuccess('contribution', 'create', $params);
0e6ccb2e 4311 }
b2250d14 4312 $originalContribution['contribution_recur_id'] = $contributionRecur['id'];
f69a9ac3 4313 $originalContribution['payment_processor_id'] = $paymentProcessorID;
893a550c 4314 return $originalContribution;
4315 }
4316
ec7e3954
E
4317 /**
4318 * Common set up routine.
4319 *
4320 * @return array
4321 */
4322 protected function setUpForCompleteTransaction() {
4323 $this->mut = new CiviMailUtils($this, TRUE);
4324 $this->createLoggedInUser();
9099cab3 4325 $params = array_merge($this->_params, ['contribution_status_id' => 2, 'receipt_date' => 'now']);
ec7e3954
E
4326 $contribution = $this->callAPISuccess('contribution', 'create', $params);
4327 return $contribution;
4328 }
4329
9c01d961
SL
4330 /**
4331 * Test repeat contribution uses the Payment Processor' payment_instrument setting.
562e4fb8 4332 *
4333 * @throws \CRM_Core_Exception
9c01d961
SL
4334 */
4335 public function testRepeatTransactionWithNonCreditCardDefault() {
562e4fb8 4336 $contributionRecur = $this->callAPISuccess('ContributionRecur', 'create', [
9c01d961
SL
4337 'contact_id' => $this->_individualId,
4338 'installments' => '12',
4339 'frequency_interval' => '1',
4340 'amount' => '100',
4341 'contribution_status_id' => 1,
4342 'start_date' => '2012-01-01 00:00:00',
4343 'currency' => 'USD',
4344 'frequency_unit' => 'month',
4345 'payment_processor_id' => $this->paymentProcessorID,
9099cab3 4346 ]);
9c01d961
SL
4347 $contribution1 = $this->callAPISuccess('contribution', 'create', array_merge(
4348 $this->_params,
9099cab3 4349 ['contribution_recur_id' => $contributionRecur['id'], 'payment_instrument_id' => 2])
9c01d961 4350 );
9099cab3 4351 $contribution2 = $this->callAPISuccess('contribution', 'repeattransaction', [
9c01d961 4352 'contribution_status_id' => 'Completed',
562e4fb8 4353 'trxn_id' => 'blah',
9c01d961 4354 'original_contribution_id' => $contribution1,
9099cab3 4355 ]);
562e4fb8 4356 $this->assertEquals('Debit Card', CRM_Contribute_PseudoConstant::getLabel('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', $contribution2['values'][$contribution2['id']]['payment_instrument_id']));
9c01d961
SL
4357 }
4358
ee63135d 4359 /**
4360 * CRM-20008 Tests repeattransaction creates pending membership.
4361 */
37f29fcf 4362 public function testRepeatTransactionMembershipCreatePendingContribution() {
ee63135d 4363 list($originalContribution, $membership) = $this->setUpAutoRenewMembership();
9099cab3 4364 $this->callAPISuccess('membership', 'create', [
ee63135d 4365 'id' => $membership['id'],
4366 'end_date' => 'yesterday',
4367 'status_id' => 'Expired',
9099cab3
CW
4368 ]);
4369 $repeatedContribution = $this->callAPISuccess('contribution', 'repeattransaction', [
ee63135d 4370 'contribution_recur_id' => $originalContribution['values'][1]['contribution_recur_id'],
4371 'contribution_status_id' => 'Pending',
4372 'trxn_id' => uniqid(),
9099cab3
CW
4373 ]);
4374 $membershipStatusId = $this->callAPISuccess('membership', 'getvalue', [
ee63135d 4375 'id' => $membership['id'],
4376 'return' => 'status_id',
9099cab3 4377 ]);
ee63135d 4378
4379 // Let's see if the membership payments got created while we're at it.
9099cab3 4380 $membershipPayments = $this->callAPISuccess('MembershipPayment', 'get', [
37f29fcf 4381 'membership_id' => $membership['id'],
9099cab3 4382 ]);
ee63135d 4383 $this->assertEquals(2, $membershipPayments['count']);
4384
4385 $this->assertEquals('Expired', CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'status_id', $membershipStatusId));
9099cab3
CW
4386 $this->callAPISuccess('Contribution', 'completetransaction', ['id' => $repeatedContribution['id']]);
4387 $membership = $this->callAPISuccessGetSingle('membership', [
ee63135d 4388 'id' => $membership['id'],
4389 'return' => 'status_id, end_date',
9099cab3 4390 ]);
37f29fcf 4391 $this->assertEquals('New', CRM_Core_PseudoConstant::getName('CRM_Member_BAO_Membership', 'status_id', $membership['status_id']));
ee63135d 4392 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 1 month')), $membership['end_date']);
ee63135d 4393 }
4394
cefed6df
SL
4395 /**
4396 * Test sending a mail via the API.
562e4fb8 4397 *
4398 * @throws \CRM_Core_Exception
cefed6df
SL
4399 */
4400 public function testSendMailWithAPISetFromDetails() {
4401 $mut = new CiviMailUtils($this, TRUE);
4402 $contribution = $this->callAPISuccess('contribution', 'create', $this->_params);
9099cab3 4403 $this->callAPISuccess('contribution', 'sendconfirmation', [
cefed6df
SL
4404 'id' => $contribution['id'],
4405 'receipt_from_email' => 'api@civicrm.org',
4406 'receipt_from_name' => 'CiviCRM LLC',
9099cab3
CW
4407 ]);
4408 $mut->checkMailLog([
39b959db
SL
4409 'From: CiviCRM LLC <api@civicrm.org>',
4410 'Contribution Information',
9099cab3 4411 ], [
39b959db 4412 'Event',
9099cab3 4413 ]);
cefed6df
SL
4414 $mut->stop();
4415 }
4416
4417 /**
4418 * Test sending a mail via the API.
4419 */
4420 public function testSendMailWithNoFromSetFallToDomain() {
4421 $this->createLoggedInUser();
4422 $mut = new CiviMailUtils($this, TRUE);
4423 $contribution = $this->callAPISuccess('contribution', 'create', $this->_params);
9099cab3 4424 $this->callAPISuccess('contribution', 'sendconfirmation', [
cefed6df 4425 'id' => $contribution['id'],
9099cab3
CW
4426 ]);
4427 $domain = $this->callAPISuccess('domain', 'getsingle', ['id' => 1]);
4428 $mut->checkMailLog([
39b959db
SL
4429 'From: ' . $domain['from_name'] . ' <' . $domain['from_email'] . '>',
4430 'Contribution Information',
9099cab3 4431 ], [
39b959db 4432 'Event',
9099cab3 4433 ]);
cefed6df
SL
4434 $mut->stop();
4435 }
4436
4437 /**
4438 * Test sending a mail via the API.
4439 */
4440 public function testSendMailWithRepeatTransactionAPIFalltoDomain() {
4441 $this->createLoggedInUser();
4442 $mut = new CiviMailUtils($this, TRUE);
9099cab3
CW
4443 $contribution = $this->setUpRepeatTransaction([], 'single');
4444 $this->callAPISuccess('contribution', 'repeattransaction', [
cefed6df
SL
4445 'contribution_status_id' => 'Completed',
4446 'trxn_id' => uniqid(),
4447 'original_contribution_id' => $contribution,
9099cab3
CW
4448 ]);
4449 $domain = $this->callAPISuccess('domain', 'getsingle', ['id' => 1]);
4450 $mut->checkMailLog([
39b959db
SL
4451 'From: ' . $domain['from_name'] . ' <' . $domain['from_email'] . '>',
4452 'Contribution Information',
9099cab3 4453 ], [
39b959db 4454 'Event',
9099cab3 4455 ]
cefed6df
SL
4456 );
4457 $mut->stop();
4458 }
4459
4460 /**
4461 * Test sending a mail via the API.
4462 */
4463 public function testSendMailWithRepeatTransactionAPIFalltoContributionPage() {
4464 $mut = new CiviMailUtils($this, TRUE);
9099cab3 4465 $contributionPage = $this->contributionPageCreate(['receipt_from_name' => 'CiviCRM LLC', 'receipt_from_email' => 'contributionpage@civicrm.org', 'is_email_receipt' => 1]);
cefed6df 4466 $paymentProcessorID = $this->paymentProcessorCreate();
9099cab3 4467 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', [
cefed6df
SL
4468 'contact_id' => $this->_individualId,
4469 'installments' => '12',
4470 'frequency_interval' => '1',
4471 'amount' => '500',
4472 'contribution_status_id' => 1,
4473 'start_date' => '2012-01-01 00:00:00',
4474 'currency' => 'USD',
4475 'frequency_unit' => 'month',
4476 'payment_processor_id' => $paymentProcessorID,
9099cab3 4477 ]);
cefed6df
SL
4478 $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
4479 $this->_params,
9099cab3 4480 [
cefed6df 4481 'contribution_recur_id' => $contributionRecur['id'],
39b959db 4482 'contribution_page_id' => $contributionPage['id'],
9099cab3 4483 ])
cefed6df 4484 );
9099cab3 4485 $this->callAPISuccess('contribution', 'repeattransaction', [
cefed6df
SL
4486 'contribution_status_id' => 'Completed',
4487 'trxn_id' => uniqid(),
4488 'original_contribution_id' => $originalContribution,
9099cab3 4489 ]
cefed6df 4490 );
9099cab3 4491 $mut->checkMailLog([
39b959db
SL
4492 'From: CiviCRM LLC <contributionpage@civicrm.org>',
4493 'Contribution Information',
9099cab3 4494 ], [
39b959db 4495 'Event',
9099cab3 4496 ]);
cefed6df
SL
4497 $mut->stop();
4498 }
4499
4fb4e64f
SL
4500 /**
4501 * Test sending a mail via the API.
4502 */
4503 public function testSendMailWithRepeatTransactionAPIFalltoSystemFromNoDefaultFrom() {
4504 $mut = new CiviMailUtils($this, TRUE);
9099cab3
CW
4505 $originalContribution = $contribution = $this->setUpRepeatTransaction([], 'single');
4506 $fromEmail = $this->CallAPISuccess('optionValue', 'get', ['is_default' => 1, 'option_group_id' => 'from_email_address', 'sequential' => 1]);
4fb4e64f 4507 foreach ($fromEmail['values'] as $from) {
9099cab3 4508 $this->callAPISuccess('optionValue', 'create', ['is_default' => 0, 'id' => $from['id']]);
4fb4e64f 4509 }
9099cab3
CW
4510 $domain = $this->callAPISuccess('domain', 'getsingle', ['id' => CRM_Core_Config::domainID()]);
4511 $this->callAPISuccess('contribution', 'repeattransaction', [
4fb4e64f
SL
4512 'contribution_status_id' => 'Completed',
4513 'trxn_id' => uniqid(),
4514 'original_contribution_id' => $originalContribution,
9099cab3
CW
4515 ]);
4516 $mut->checkMailLog([
39b959db
SL
4517 'From: ' . $domain['name'] . ' <' . $domain['domain_email'] . '>',
4518 'Contribution Information',
9099cab3 4519 ], [
39b959db 4520 'Event',
9099cab3 4521 ]);
4fb4e64f
SL
4522 $mut->stop();
4523 }
4524
d891a273 4525 /**
4526 * Create a Contribution Page with is_email_receipt = TRUE.
4527 *
4528 * @param array $params
4529 * Params to overwrite with.
4530 *
4531 * @return array|int
4532 */
9099cab3
CW
4533 protected function createReceiptableContributionPage($params = []) {
4534 $contributionPage = $this->callAPISuccess('ContributionPage', 'create', array_merge([
d891a273 4535 'receipt_from_name' => 'Mickey Mouse',
4536 'receipt_from_email' => 'mickey@mouse.com',
4537 'title' => "Test Contribution Page",
4538 'financial_type_id' => 1,
4539 'currency' => 'CAD',
4540 'is_monetary' => TRUE,
4541 'is_email_receipt' => TRUE,
9099cab3 4542 ], $params));
d891a273 4543 return $contributionPage;
4544 }
4545
121c4616 4546 /**
4547 * function to test card_type and pan truncation.
4548 */
4549 public function testCardTypeAndPanTruncation() {
4550 $creditCardTypeIDs = array_flip(CRM_Financial_DAO_FinancialTrxn::buildOptions('card_type_id'));
4551 $contactId = $this->individualCreate();
9099cab3 4552 $params = [
121c4616 4553 'contact_id' => $contactId,
4554 'receive_date' => '2016-01-20',
4555 'total_amount' => 100,
4556 'financial_type_id' => 1,
4557 'payment_instrument' => 'Credit Card',
4558 'card_type_id' => $creditCardTypeIDs['Visa'],
4559 'pan_truncation' => 4567,
9099cab3 4560 ];
121c4616 4561 $contribution = $this->callAPISuccess('contribution', 'create', $params);
4562 $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
4563 $financialTrxn = $this->callAPISuccessGetSingle(
4564 'FinancialTrxn',
9099cab3 4565 [
121c4616 4566 'id' => $lastFinancialTrxnId['financialTrxnId'],
9099cab3
CW
4567 'return' => ['card_type_id', 'pan_truncation'],
4568 ]
121c4616 4569 );
4570 $this->assertEquals(CRM_Utils_Array::value('card_type_id', $financialTrxn), $creditCardTypeIDs['Visa']);
4571 $this->assertEquals(CRM_Utils_Array::value('pan_truncation', $financialTrxn), 4567);
9099cab3 4572 $params = [
121c4616 4573 'id' => $contribution['id'],
4574 'pan_truncation' => 2345,
4575 'card_type_id' => $creditCardTypeIDs['Amex'],
9099cab3 4576 ];
121c4616 4577 $contribution = $this->callAPISuccess('contribution', 'create', $params);
4578 $financialTrxn = $this->callAPISuccessGetSingle(
4579 'FinancialTrxn',
9099cab3 4580 [
121c4616 4581 'id' => $lastFinancialTrxnId['financialTrxnId'],
9099cab3
CW
4582 'return' => ['card_type_id', 'pan_truncation'],
4583 ]
121c4616 4584 );
4585 $this->assertEquals(CRM_Utils_Array::value('card_type_id', $financialTrxn), $creditCardTypeIDs['Amex']);
4586 $this->assertEquals(CRM_Utils_Array::value('pan_truncation', $financialTrxn), 2345);
4587 }
4588
19893cf2
SL
4589 /**
4590 * Test repeat contribution uses non default currency
4591 * @see https://issues.civicrm.org/jira/projects/CRM/issues/CRM-20678
4592 */
4593 public function testRepeatTransactionWithDifferenceCurrency() {
9099cab3
CW
4594 $originalContribution = $this->setUpRepeatTransaction(['currency' => 'AUD'], 'single', ['currency' => 'AUD']);
4595 $contribution = $this->callAPISuccess('contribution', 'repeattransaction', [
19893cf2
SL
4596 'original_contribution_id' => $originalContribution['id'],
4597 'contribution_status_id' => 'Completed',
4598 'trxn_id' => uniqid(),
9099cab3 4599 ]);
19893cf2
SL
4600 $this->assertEquals('AUD', $contribution['values'][$contribution['id']]['currency']);
4601 }
4602
b0e806fa 4603 /**
4604 * Get the financial items for the contribution.
4605 *
4606 * @param int $contributionID
4607 *
4608 * @return array
4609 * Array of associated financial items.
4610 */
4611 protected function getFinancialTransactionsForContribution($contributionID) {
9099cab3 4612 $trxnParams = [
b0e806fa 4613 'entity_id' => $contributionID,
4614 'entity_table' => 'civicrm_contribution',
9099cab3 4615 ];
b0e806fa 4616 // @todo the following function has naming errors & has a weird signature & appears to
4617 // only be called from test classes. Move into test suite & maybe just use api
4618 // from this function.
562e4fb8 4619 return array_merge(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($trxnParams));
b0e806fa 4620 }
4621
1af690c4 4622 /**
4623 * Test getunique api call for Contribution entity
4624 */
4625 public function testContributionGetUnique() {
562e4fb8 4626 $result = $this->callAPIAndDocument($this->entity, 'getunique', [], __FUNCTION__, __FILE__);
1af690c4 4627 $this->assertEquals(2, $result['count']);
9099cab3
CW
4628 $this->assertEquals(['trxn_id'], $result['values']['UI_contrib_trxn_id']);
4629 $this->assertEquals(['invoice_id'], $result['values']['UI_contrib_invoice_id']);
1af690c4 4630 }
4631
d8bd2007
PN
4632 /**
4633 * Test Repeat Transaction Contribution with Tax amount.
4634 * https://lab.civicrm.org/dev/core/issues/806
4635 */
4636 public function testRepeatContributionWithTaxAmount() {
4637 $this->enableTaxAndInvoicing();
4638 $financialType = $this->callAPISuccess('financial_type', 'create', [
4639 'name' => 'Test taxable financial Type',
4640 'is_reserved' => 0,
4641 'is_active' => 1,
4642 ]);
4643 $this->relationForFinancialTypeWithFinancialAccount($financialType['id']);
4644 $contribution = $this->setUpRepeatTransaction(
4645 [],
4646 'single',
4647 [
4648 'financial_type_id' => $financialType['id'],
4649 ]
4650 );
9099cab3 4651 $this->callAPISuccess('contribution', 'repeattransaction', [
d8bd2007
PN
4652 'original_contribution_id' => $contribution['id'],
4653 'contribution_status_id' => 'Completed',
4654 'trxn_id' => uniqid(),
9099cab3 4655 ]);
9583e46d
JP
4656 $payments = $this->callAPISuccess('Contribution', 'get', ['sequential' => 1])['values'];
4657 //Assert if first payment and repeated payment has the same contribution amount.
4658 $this->assertEquals($payments[0]['total_amount'], $payments[1]['total_amount']);
d8bd2007 4659 $this->callAPISuccessGetCount('Contribution', [], 2);
5d8c94bc
JP
4660
4661 //Assert line item records.
4662 $lineItems = $this->callAPISuccess('LineItem', 'get', ['sequential' => 1])['values'];
4663 foreach ($lineItems as $lineItem) {
4664 $this->assertEquals($lineItem['unit_price'], $this->_params['total_amount']);
4665 $this->assertEquals($lineItem['line_total'], $this->_params['total_amount']);
4666 }
4667 $this->callAPISuccessGetCount('Contribution', [], 2);
d8bd2007
PN
4668 }
4669
a8fdb24e
CW
4670 public function testGetCurrencyOptions() {
4671 $result = $this->callAPISuccess('Contribution', 'getoptions', [
4672 'field' => 'currency',
4673 ]);
4674 $this->assertEquals('US Dollar', $result['values']['USD']);
4675 $this->assertNotContains('$', $result['values']);
4676 $result = $this->callAPISuccess('Contribution', 'getoptions', [
4677 'field' => 'currency',
4678 'context' => "abbreviate",
4679 ]);
4680 $this->assertEquals('$', $result['values']['USD']);
4681 $this->assertNotContains('US Dollar', $result['values']);
4682 }
4683
79c9d4c2 4684 /**
4685 * @throws \API_Exception
4686 * @throws \CRM_Core_Exception
4687 * @throws \Civi\API\Exception\UnauthorizedException
4688 */
2ac10e87 4689 public function testSetCustomDataInCreateAndHook() {
79c9d4c2 4690 $this->createCustomGroupWithFieldOfType([], 'int');
4691 $this->ids['CustomField']['text'] = (int) $this->createTextCustomField(['custom_group_id' => $this->ids['CustomGroup']['Custom Group']])['id'];
2ac10e87
SL
4692 $this->hookClass->setHook('civicrm_post', [
4693 $this,
4694 'civicrmPostContributionCustom',
4695 ]);
4696 $params = $this->_params;
4697 $params['custom_' . $this->ids['CustomField']['text']] = 'Some Text';
4698 $contribution = $this->callAPISuccess('Contribution', 'create', $params);
4699 $getContribution = $this->callAPISuccess('Contribution', 'get', [
4700 'id' => $contribution['id'],
4701 'return' => ['id', 'custom_' . $this->ids['CustomField']['text'], 'custom_' . $this->ids['CustomField']['int']],
4702 ]);
79c9d4c2 4703 $this->assertEquals(5, $getContribution['values'][$contribution['id']][$this->getCustomFieldName('int')]);
2ac10e87 4704 $this->assertEquals('Some Text', $getContribution['values'][$contribution['id']]['custom_' . $this->ids['CustomField']['text']]);
c971eccf
CW
4705 $this->callAPISuccess('CustomField', 'delete', ['id' => $this->ids['CustomField']['text']]);
4706 $this->callAPISuccess('CustomField', 'delete', ['id' => $this->ids['CustomField']['int']]);
4707 $this->callAPISuccess('CustomGroup', 'delete', ['id' => $this->ids['CustomGroup']['Custom Group']]);
2ac10e87
SL
4708 }
4709
79c9d4c2 4710 /**
4711 * Implement post hook.
4712 *
4713 * @param string $op
4714 * @param string $objectName
4715 * @param int $objectId
4716 * @param \CRM_Core_DAO $objectRef
4717 *
4718 * @throws \CRM_Core_Exception
4719 */
2ac10e87
SL
4720 public function civicrmPostContributionCustom($op, $objectName, $objectId, &$objectRef) {
4721 if ($objectName === 'Contribution' && $op === 'create') {
4722 $this->callAPISuccess('Contribution', 'create', [
4723 'id' => $objectId,
4724 'custom_' . $this->ids['CustomField']['int'] => 5,
4725 ]);
4726 }
4727 }
4728
c971eccf
CW
4729 /**
4730 * Test that passing in label for an option value linked to a custom field works
4731 * @see dev/core#1816
4732 */
4733 public function testCustomValueOptionLabelTest() {
4734 $this->createCustomGroupWithFieldOfType([], 'radio');
4735 $params = $this->_params;
4736 $params['custom_' . $this->ids['CustomField']['radio']] = 'Red Testing';
4737 $contribution = $this->callAPISuccess('Contribution', 'Create', $params);
4738 }
4739
605665c7 4740 /**
4741 * Test repeatTransaction with installments and next_sched_contribution_date
4742 *
4743 * @dataProvider getRepeatTransactionNextSchedData
4744 *
4745 * @param array $dataSet
4746 *
4747 * @throws \Exception
4748 */
4749 public function testRepeatTransactionUpdateNextSchedContributionDate($dataSet) {
4750 $paymentProcessorID = $this->paymentProcessorCreate();
4751 // Create the contribution before the recur so it doesn't trigger the update of next_sched_contribution_date
4752 $contribution = $this->callAPISuccess('contribution', 'create', array_merge(
4753 $this->_params,
4754 [
4755 'contribution_status_id' => 'Completed',
4756 'receive_date' => $dataSet['repeat'][0]['receive_date'],
4757 ])
4758 );
4759 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
4760 'contact_id' => $this->_individualId,
4761 'frequency_interval' => '1',
4762 'amount' => '500',
4763 'contribution_status_id' => 'Pending',
4764 'start_date' => '2012-01-01 00:00:00',
4765 'currency' => 'USD',
4766 'frequency_unit' => 'month',
4767 'payment_processor_id' => $paymentProcessorID,
4768 ], $dataSet['recur']));
4769 // Link the existing contribution to the recur *after* creating the recur.
4770 // If we just created the contribution now the next_sched_contribution_date would be automatically set
4771 // and we want to test the case when it is empty.
4772 $this->callAPISuccess('contribution', 'create', [
4773 'id' => $contribution['id'],
4774 'contribution_recur_id' => $contributionRecur['id'],
4775 ]);
4776
4777 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', [
4778 'id' => $contributionRecur['id'],
4779 'return' => ['next_sched_contribution_date', 'contribution_status_id'],
4780 ]);
4781 // Check that next_sched_contribution_date is empty
4782 $this->assertEquals('', $contributionRecur['next_sched_contribution_date'] ?? '');
4783
4784 $this->callAPISuccess('Contribution', 'repeattransaction', [
4785 'contribution_status_id' => 'Completed',
4786 'contribution_recur_id' => $contributionRecur['id'],
4787 'receive_date' => $dataSet['repeat'][0]['receive_date'],
4788 ]);
4789 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', [
4790 'id' => $contributionRecur['id'],
4791 'return' => ['next_sched_contribution_date', 'contribution_status_id'],
4792 ]);
4793 // Check that recur has status "In Progress"
4794 $this->assertEquals(
4795 (string) CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $dataSet['repeat'][0]['expectedRecurStatus']),
4796 $contributionRecur['contribution_status_id']
4797 );
4798 // Check that next_sched_contribution_date has been set to 1 period after the contribution receive date (ie. 1 month)
4799 $this->assertEquals($dataSet['repeat'][0]['expectedNextSched'], $contributionRecur['next_sched_contribution_date']);
4800
4801 // Now call Contribution.repeattransaction again and check that the next_sched_contribution_date has moved forward by 1 period again
4802 $this->callAPISuccess('Contribution', 'repeattransaction', [
4803 'contribution_status_id' => 'Completed',
4804 'contribution_recur_id' => $contributionRecur['id'],
4805 'receive_date' => $dataSet['repeat'][1]['receive_date'],
4806 ]);
4807 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', [
4808 'id' => $contributionRecur['id'],
4809 'return' => ['next_sched_contribution_date', 'contribution_status_id'],
4810 ]);
4811 // Check that recur has status "In Progress" or "Completed" depending on whether number of installments has been reached
4812 $this->assertEquals(
4813 (string) CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $dataSet['repeat'][1]['expectedRecurStatus']),
4814 $contributionRecur['contribution_status_id']
4815 );
4816 // Check that next_sched_contribution_date has been set to 1 period after the contribution receive date (ie. 1 month)
4817 $this->assertEquals($dataSet['repeat'][1]['expectedNextSched'], $contributionRecur['next_sched_contribution_date'] ?? '');
4818 }
4819
4820 /**
4821 * Get dates for testing.
4822 *
4823 * @return array
4824 */
4825 public function getRepeatTransactionNextSchedData() {
4826 // Both these tests handle/test the case that next_sched_contribution_date is empty when Contribution.repeattransaction
4827 // is called for the first time. Historically setting it was inconsistent but on new updates it should always be set.
4828 /*
4829 * This tests that calling Contribution.repeattransaction with installments does the following:
4830 * - For the first call to repeattransaction the recur status is In Progress and next_sched_contribution_date is updated
4831 * to match next expected receive_date.
4832 * - Once the 3rd contribution is created contributionRecur status = completed and next_sched_contribution_date = ''.
4833 */
4834 $result['receive_date_includes_time_with_installments']['2012-01-01-1-month'] = [
4835 'recur' => [
4836 'start_date' => '2012-01-01',
4837 'frequency_interval' => 1,
4838 'installments' => '3',
4839 'frequency_unit' => 'month',
4840 ],
4841 'repeat' => [
4842 [
4843 'receive_date' => '2012-02-29 16:00:00',
4844 'expectedNextSched' => '2012-03-29 00:00:00',
4845 'expectedRecurStatus' => 'In Progress',
4846 ],
4847 [
4848 'receive_date' => '2012-03-29 16:00:00',
4849 'expectedNextSched' => '',
4850 'expectedRecurStatus' => 'Completed',
4851 ],
4852 ],
4853 ];
4854 /*
4855 * This tests that calling Contribution.repeattransaction with no installments does the following:
4856 * - For the each call to repeattransaction the recur status is In Progress and next_sched_contribution_date is updated
4857 * to match next expected receive_date.
4858 */
4859 $result['receive_date_includes_time_no_installments']['2012-01-01-1-month'] = [
4860 'recur' => [
4861 'start_date' => '2012-01-01',
4862 'frequency_interval' => 1,
4863 'frequency_unit' => 'month',
4864 ],
4865 'repeat' => [
4866 [
4867 'receive_date' => '2012-02-29 16:00:00',
4868 'expectedNextSched' => '2012-03-29 00:00:00',
4869 'expectedRecurStatus' => 'In Progress',
4870 ],
4871 [
4872 'receive_date' => '2012-03-29 16:00:00',
4873 'expectedNextSched' => '2012-04-29 00:00:00',
4874 'expectedRecurStatus' => 'In Progress',
4875 ],
4876 ],
4877 ];
4878 return $result;
4879 }
4880
39052b78
AH
4881 /**
4882 * Make sure that recording a payment doesn't alter the receive_date of a
4883 * pending contribution.
4884 */
4885 public function testPaymentDontChangeReceiveDate() {
4886 $params = [
4887 'contact_id' => $this->_individualId,
4888 'total_amount' => 100,
4889 'receive_date' => '2020-02-02',
4890 'contribution_status_id' => 'Pending',
4891 ];
4892 $contributionID = $this->contributionCreate($params);
4893 $paymentParams = [
4894 'contribution_id' => $contributionID,
4895 'total_amount' => 100,
4896 'trxn_date' => '2020-03-04',
4897 ];
4898 $this->callAPISuccess('payment', 'create', $paymentParams);
4899
4900 //check if contribution status is set to "Completed".
4901 $contribution = $this->callAPISuccess('Contribution', 'getSingle', [
4902 'id' => $contributionID,
4903 ]);
4904 $this->assertEquals('2020-02-02 00:00:00', $contribution['receive_date']);
4905 }
4906
d0b559aa
SP
4907 /**
4908 * Make sure that recording a payment with Different Payment Instrument update main contribution record payment
4909 * instrument too. If multiple Payment Recorded, last payment record payment (when No more due) instrument set to main
4910 * payment
4911 */
4912 public function testPaymentVerifyPaymentInstrumentChange() {
4913 // Create Pending contribution with pay later mode, with payment instrument Check
4914 $params = [
4915 'contact_id' => $this->_individualId,
4916 'total_amount' => 100,
4917 'receive_date' => '2020-02-02',
4918 'contribution_status_id' => 'Pending',
4919 'is_pay_later' => 1,
4920 'payment_instrument_id' => 'Check',
4921 ];
4922 $contributionID = $this->contributionCreate($params);
4923
d0b559aa
SP
4924 // Record the the Payment with instrument other than Check, e.g EFT
4925 $paymentParams = [
4926 'contribution_id' => $contributionID,
4927 'total_amount' => 50,
4928 'trxn_date' => '2020-03-04',
d0d6dd40 4929 'payment_instrument_id' => 'EFT',
d0b559aa
SP
4930 ];
4931 $this->callAPISuccess('payment', 'create', $paymentParams);
4932
4933 $contribution = $this->callAPISuccess('Contribution', 'getSingle', [
4934 'id' => $contributionID,
4935 ]);
4936 // payment status should be 'Partially paid'
4937 $this->assertEquals('Partially paid', $contribution['contribution_status']);
4938
4939 // Record the the Payment with instrument other than Check, e.g Cash (pay all remaining amount)
4940 $paymentParams = [
4941 'contribution_id' => $contributionID,
4942 'total_amount' => 50,
4943 'trxn_date' => '2020-03-04',
d0d6dd40 4944 'payment_instrument_id' => 'Cash',
d0b559aa
SP
4945 ];
4946 $this->callAPISuccess('payment', 'create', $paymentParams);
4947
4948 //check if contribution Payment Instrument (Payment Method) is is set to "Cash".
4949 $contribution = $this->callAPISuccess('Contribution', 'getSingle', [
4950 'id' => $contributionID,
4951 ]);
4952 $this->assertEquals('Cash', $contribution['payment_instrument']);
4953 $this->assertEquals('Completed', $contribution['contribution_status']);
4954 }
4955
bb35c5f3
JG
4956 /**
4957 * Test the "clean money" functionality.
4958 */
4959 public function testCleanMoney() {
4960 $params = [
4961 'contact_id' => $this->_individualId,
4962 'financial_type_id' => 1,
4963 'total_amount' => '$100',
4964 'fee_amount' => '$20',
4965 'net_amount' => '$80',
4966 'non_deductible_amount' => '$80',
4967 'sequential' => 1,
4968 ];
4969 $id = $this->callAPISuccess('Contribution', 'create', $params)['id'];
4970 // Reading the return values of the API isn't reliable here; get the data from the db.
4971 $contribution = $this->callAPISuccess('Contribution', 'getsingle', ['id' => $id]);
4972 $this->assertEquals('100.00', $contribution['total_amount']);
4973 $this->assertEquals('20.00', $contribution['fee_amount']);
4974 $this->assertEquals('80.00', $contribution['net_amount']);
4975 $this->assertEquals('80.00', $contribution['non_deductible_amount']);
4976 }
4977
6a488035 4978}