Fix sendconfirmation api to respect cc and bcc set in params
[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();
7ba71757 3319 // Unset source to test whether one is generated if not set already on the contribution.
3320 unset($this->_params['source']);
0efa8efe 3321 $contributionID = $this->createPendingParticipantContribution();
ed7e2e99 3322 $this->createJoinedProfile(['entity_id' => $this->_ids['event']['test'], 'entity_table' => 'civicrm_event']);
f736929b 3323 $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']);
3324 $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']);
3325 $this->eliminateUFGroupOne();
ed7e2e99 3326
7ba71757 3327 $this->callAPISuccess('contribution', 'completetransaction', ['id' => $contributionID]);
3328 $contribution = $this->callAPISuccessGetSingle('Contribution', ['id' => $contributionID, 'return' => ['contribution_source']]);
3329 $this->assertEquals('Online Event Registration: Annual CiviCRM meet', $contribution['contribution_source']);
9099cab3 3330 $participantStatus = $this->callAPISuccessGetValue('participant', [
92915c55
TO
3331 'id' => $this->_ids['participant'],
3332 'return' => 'participant_status_id',
9099cab3 3333 ]);
0efa8efe 3334 $this->assertEquals(1, $participantStatus);
71acd4bf
JP
3335
3336 //Assert only three activities are created.
ed7e2e99 3337 $activities = $this->callAPISuccess('Activity', 'get', [
3338 'contact_id' => $this->_individualId,
3339 ])['values'];
3340
f736929b 3341 $this->assertCount(3, $activities);
71acd4bf 3342 $activityNames = array_count_values(CRM_Utils_Array::collect('activity_name', $activities));
b56b628c 3343 // record two activities before and after completing payment for Event registration
71acd4bf 3344 $this->assertEquals(2, $activityNames['Event Registration']);
b56b628c 3345 // update the original 'Contribution' activity created after completing payment
71acd4bf
JP
3346 $this->assertEquals(1, $activityNames['Contribution']);
3347
9099cab3 3348 $mut->checkMailLog([
0efa8efe 3349 'Annual CiviCRM meet',
3350 'Event',
12ff7379 3351 'This is a confirmation that your registration has been received and your status has been updated to Registered.',
ed7e2e99 3352 'First Name: Logged In',
3353 'Public title',
f736929b 3354 'public 2',
3355 'public 3',
3356 ], ['Back end title', 'title_post_2', 'title_post_3']);
66d3f9be
EM
3357 $mut->stop();
3358 }
3359
3360 /**
eceb18cc 3361 * Test membership is renewed when transaction completed.
66d3f9be 3362 */
00be9182 3363 public function testCompleteTransactionMembershipPriceSet() {
66d3f9be 3364 $this->createPriceSetWithPage('membership');
9099cab3 3365 $stateOfGrace = $this->callAPISuccess('MembershipStatus', 'getvalue', [
4ff927bc 3366 'name' => 'Grace',
39b959db 3367 'return' => 'id',
9099cab3 3368 ]);
66d3f9be 3369 $this->setUpPendingContribution($this->_ids['price_field_value'][0]);
9099cab3
CW
3370 $membership = $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
3371 $logs = $this->callAPISuccess('MembershipLog', 'get', [
4ff927bc 3372 'membership_id' => $this->_ids['membership'],
9099cab3 3373 ]);
4ff927bc 3374 $this->assertEquals(1, $logs['count']);
3375 $this->assertEquals($stateOfGrace, $membership['status_id']);
9099cab3
CW
3376 $this->callAPISuccess('contribution', 'completetransaction', ['id' => $this->_ids['contribution']]);
3377 $membership = $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
66d3f9be 3378 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 1 year')), $membership['end_date']);
9099cab3 3379 $this->callAPISuccessGetSingle('LineItem', [
4ff927bc 3380 'entity_id' => $this->_ids['membership'],
3381 'entity_table' => 'civicrm_membership',
9099cab3
CW
3382 ]);
3383 $logs = $this->callAPISuccess('MembershipLog', 'get', [
4ff927bc 3384 'membership_id' => $this->_ids['membership'],
9099cab3 3385 ]);
4ff927bc 3386 $this->assertEquals(2, $logs['count']);
3387 $this->assertNotEquals($stateOfGrace, $logs['values'][2]['status_id']);
98f0683a
JP
3388 //Assert only three activities are created.
3389 $activities = CRM_Activity_BAO_Activity::getContactActivity($this->_ids['contact']);
3390 $this->assertEquals(3, count($activities));
3391 $activityNames = array_flip(CRM_Utils_Array::collect('activity_name', $activities));
3392 $this->assertArrayHasKey('Contribution', $activityNames);
3393 $this->assertArrayHasKey('Membership Signup', $activityNames);
3394 $this->assertArrayHasKey('Change Membership Status', $activityNames);
66d3f9be
EM
3395 $this->cleanUpAfterPriceSets();
3396 }
3397
0f07bb06 3398 /**
3399 * Test if renewal activity is create after changing Pending contribution to Completed via offline
3400 */
3401 public function testPendingToCompleteContribution() {
c77986c0 3402 $this->createPriceSetWithPage('membership');
0f07bb06 3403 $this->setUpPendingContribution($this->_ids['price_field_value'][0]);
9099cab3 3404 $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
66a1e31f 3405 // Case 1: Assert that Membership Signup Activity is created on Pending to Completed Contribution via backoffice
9099cab3 3406 $activity = $this->callAPISuccess('Activity', 'get', [
b6d493f3
MD
3407 'activity_type_id' => 'Membership Signup',
3408 'source_record_id' => $this->_ids['membership'],
3409 'status_id' => 'Scheduled',
9099cab3 3410 ]);
b6d493f3 3411 $this->assertEquals(1, $activity['count']);
0f07bb06 3412
3413 // change pending contribution to completed
3414 $form = new CRM_Contribute_Form_Contribution();
c77986c0 3415
9099cab3 3416 $form->_params = [
0f07bb06 3417 'id' => $this->_ids['contribution'],
3418 'total_amount' => 20,
3419 'net_amount' => 20,
3420 'fee_amount' => 0,
3421 'financial_type_id' => 1,
0f07bb06 3422 'contact_id' => $this->_individualId,
3423 'contribution_status_id' => 1,
3424 'billing_middle_name' => '',
3425 'billing_last_name' => 'Adams',
3426 'billing_street_address-5' => '790L Lincoln St S',
3427 'billing_city-5' => 'Maryknoll',
3428 'billing_state_province_id-5' => 1031,
3429 'billing_postal_code-5' => 10545,
3430 'billing_country_id-5' => 1228,
3431 'frequency_interval' => 1,
3432 'frequency_unit' => 'month',
3433 'installments' => '',
3434 'hidden_AdditionalDetail' => 1,
3435 'hidden_Premium' => 1,
3436 'from_email_address' => '"civi45" <civi45@civicrm.com>',
3437 'receipt_date' => '',
3438 'receipt_date_time' => '',
3439 'payment_processor_id' => $this->paymentProcessorID,
3440 'currency' => 'USD',
3441 'contribution_page_id' => $this->_ids['contribution_page'],
3442 'contribution_mode' => 'membership',
3443 'source' => 'Membership Signup and Renewal',
9099cab3 3444 ];
c77986c0 3445
3446 $form->testSubmit($form->_params, CRM_Core_Action::UPDATE);
3447
66a1e31f 3448 // Case 2: After successful payment for Pending backoffice there are three activities created
b6d493f3 3449 // 2.a Update status of existing Scheduled Membership Signup (created in step 1) to Completed
9099cab3 3450 $activity = $this->callAPISuccess('Activity', 'get', [
767d3e2e 3451 'activity_type_id' => 'Membership Signup',
b6d493f3
MD
3452 'source_record_id' => $this->_ids['membership'],
3453 'status_id' => 'Completed',
9099cab3 3454 ]);
767d3e2e 3455 $this->assertEquals(1, $activity['count']);
b6d493f3 3456 // 2.b Contribution activity created to record successful payment
9099cab3 3457 $activity = $this->callAPISuccess('Activity', 'get', [
b6d493f3 3458 'activity_type_id' => 'Contribution',
767d3e2e 3459 'source_record_id' => $this->_ids['contribution'],
b6d493f3 3460 'status_id' => 'Completed',
9099cab3 3461 ]);
b6d493f3 3462 $this->assertEquals(1, $activity['count']);
fde55343 3463
b6d493f3 3464 // 2.c 'Change membership type' activity created to record Membership status change from Grace to Current
9099cab3 3465 $activity = $this->callAPISuccess('Activity', 'get', [
b6d493f3
MD
3466 'activity_type_id' => 'Change Membership Status',
3467 'source_record_id' => $this->_ids['membership'],
3468 'status_id' => 'Completed',
9099cab3 3469 ]);
d2460a89 3470 $this->assertEquals(1, $activity['count']);
b6d493f3 3471 $this->assertEquals('Status changed from Grace to Current', $activity['values'][$activity['id']]['subject']);
fde55343
JP
3472
3473 //Create another pending contribution for renewal
9099cab3 3474 $contribution = $this->callAPISuccess('contribution', 'create', [
fde55343
JP
3475 'domain_id' => 1,
3476 'contact_id' => $this->_ids['contact'],
3477 'receive_date' => date('Ymd'),
3478 'total_amount' => 20.00,
3479 'financial_type_id' => 1,
3480 'payment_instrument_id' => 'Credit Card',
3481 'non_deductible_amount' => 10.00,
3482 'trxn_id' => 'rdhfi88',
3483 'invoice_id' => 'dofhiewuyr',
3484 'source' => 'SSF',
3485 'contribution_status_id' => 2,
3486 'contribution_page_id' => $this->_ids['contribution_page'],
c77986c0 3487 // We can't rely on contribution api to link line items correctly to membership
3488 'skipLineItem' => TRUE,
9099cab3
CW
3489 'api.membership_payment.create' => ['membership_id' => $this->_ids['membership']],
3490 ]);
fde55343 3491
9099cab3 3492 $this->callAPISuccess('line_item', 'create', [
fde55343
JP
3493 'entity_id' => $contribution['id'],
3494 'entity_table' => 'civicrm_contribution',
3495 'contribution_id' => $contribution['id'],
3496 'price_field_id' => $this->_ids['price_field'][0],
3497 'qty' => 1,
3498 'unit_price' => 20,
3499 'line_total' => 20,
3500 'financial_type_id' => 1,
c77986c0 3501 'price_field_value_id' => $this->_ids['price_field_value']['cont'],
9099cab3
CW
3502 ]);
3503 $this->callAPISuccess('line_item', 'create', [
c77986c0 3504 'entity_id' => $this->_ids['membership'],
3505 'entity_table' => 'civicrm_membership',
3506 'contribution_id' => $contribution['id'],
3507 'price_field_id' => $this->_ids['price_field'][0],
3508 'qty' => 1,
3509 'unit_price' => 20,
3510 'line_total' => 20,
3511 'financial_type_id' => 1,
fde55343 3512 'price_field_value_id' => $this->_ids['price_field_value'][0],
c77986c0 3513 'membership_type_id' => $this->_ids['membership_type'],
9099cab3 3514 ]);
fde55343
JP
3515
3516 //Update it to Failed.
3517 $form->_params['id'] = $contribution['id'];
3518 $form->_params['contribution_status_id'] = 4;
c77986c0 3519
3520 $form->testSubmit($form->_params, CRM_Core_Action::UPDATE);
fde55343 3521 //Existing membership should not get updated to expired.
9099cab3 3522 $membership = $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
fde55343 3523 $this->assertNotEquals($membership['status_id'], 4);
0f07bb06 3524 }
3525
66d3f9be 3526 /**
7e9abd5a 3527 * Test membership is renewed for 2 terms when transaction completed based on the line item having 2 terms as qty.
3528 *
3529 * Also check that altering the qty for the most recent contribution results in repeattransaction picking it up.
66d3f9be 3530 */
00be9182 3531 public function testCompleteTransactionMembershipPriceSetTwoTerms() {
66d3f9be
EM
3532 $this->createPriceSetWithPage('membership');
3533 $this->setUpPendingContribution($this->_ids['price_field_value'][1]);
9099cab3 3534 $this->callAPISuccess('contribution', 'completetransaction', ['id' => $this->_ids['contribution']]);
7e9abd5a 3535 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
66d3f9be 3536 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 2 years')), $membership['end_date']);
7e9abd5a 3537
3538 $paymentProcessorID = $this->paymentProcessorAuthorizeNetCreate();
3539
3540 $contributionRecurID = $this->callAPISuccess('ContributionRecur', 'create', ['contact_id' => $membership['contact_id'], 'payment_processor_id' => $paymentProcessorID, 'amount' => 20, 'frequency_interval' => 1])['id'];
3541 $this->callAPISuccess('Contribution', 'create', ['id' => $this->_ids['contribution'], 'contribution_recur_id' => $contributionRecurID]);
3542 $this->callAPISuccess('contribution', 'repeattransaction', ['contribution_recur_id' => $contributionRecurID, 'contribution_status_id' => 'Completed']);
3543 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
3544 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 4 years')), $membership['end_date']);
3545
3546 // 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.
3547 $contribution = Contribution::get()->setOrderBy(['id' => 'DESC'])->setSelect(['id'])->execute()->first();
3548 CRM_Core_DAO::executeQuery('UPDATE civicrm_line_item SET price_field_value_id = ' . $this->_ids['price_field_value'][0] . ' WHERE contribution_id = ' . $contribution['id']);
3549 $this->callAPISuccess('contribution', 'repeattransaction', ['contribution_recur_id' => $contributionRecurID, 'contribution_status_id' => 'Completed']);
3550 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
3551 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 5 years')), $membership['end_date']);
3552
66d3f9be
EM
3553 $this->cleanUpAfterPriceSets();
3554 }
3555
00be9182 3556 public function cleanUpAfterPriceSets() {
1cf3c2b1 3557 $this->quickCleanUpFinancialEntities();
66d3f9be 3558 $this->contactDelete($this->_ids['contact']);
66d3f9be
EM
3559 }
3560
66d3f9be 3561 /**
eceb18cc 3562 * Set up a pending transaction with a specific price field id.
1e52837d 3563 *
100fef9d 3564 * @param int $priceFieldValueID
39b959db 3565 * @param array $contriParams
5d4c1098 3566 *
3567 * @throws \CRM_Core_Exception
66d3f9be 3568 */
9099cab3 3569 public function setUpPendingContribution($priceFieldValueID, $contriParams = []) {
66d3f9be 3570 $contactID = $this->individualCreate();
5d4c1098 3571 $contribution = $this->callAPISuccess('Order', 'create', array_merge([
66d3f9be
EM
3572 'domain_id' => 1,
3573 'contact_id' => $contactID,
3574 'receive_date' => date('Ymd'),
0f07bb06 3575 'total_amount' => 20.00,
66d3f9be
EM
3576 'financial_type_id' => 1,
3577 'payment_instrument_id' => 'Credit Card',
3578 'non_deductible_amount' => 10.00,
98f0683a
JP
3579 'trxn_id' => 'jdhfi' . rand(1, 100),
3580 'invoice_id' => 'djfhiew' . rand(5, 100),
66d3f9be
EM
3581 'source' => 'SSF',
3582 'contribution_status_id' => 2,
3583 'contribution_page_id' => $this->_ids['contribution_page'],
5d4c1098 3584 'line_items' => [
3585 [
3586 'line_item' => [
3587 [
3588 'price_field_id' => $this->_ids['price_field'][0],
3589 'qty' => 1,
3590 'entity_table' => 'civicrm_membership',
3591 'unit_price' => 20,
3592 'line_total' => 20,
3593 'financial_type_id' => 1,
3594 'price_field_value_id' => $priceFieldValueID,
3595 ],
3596 ],
3597 'params' => [
3598 'contact_id' => $contactID,
3599 'membership_type_id' => $this->_ids['membership_type'],
3600 'start_date' => 'yesterday - 1 year',
3601 'end_date' => 'yesterday',
3602 'join_date' => 'yesterday - 1 year',
3603 ],
3604 ],
3605 ],
9099cab3 3606 ], $contriParams));
66d3f9be 3607
66d3f9be
EM
3608 $this->_ids['contact'] = $contactID;
3609 $this->_ids['contribution'] = $contribution['id'];
5d4c1098 3610 $this->_ids['membership'] = $this->callAPISuccessGetValue('MembershipPayment', ['return' => 'membership_id', 'contribution_id' => $contribution['id']]);
0efa8efe 3611 }
3612
2f45e1c2 3613 /**
eceb18cc 3614 * Test sending a mail via the API.
450dfb41 3615 *
3616 * @throws \CRM_Core_Exception
49cba3ad 3617 * @throws \CiviCRM_API3_Exception
6a488035 3618 */
00be9182 3619 public function testSendMail() {
5896d037 3620 $mut = new CiviMailUtils($this, TRUE);
49cba3ad 3621 $orderParams = $this->_params;
3622 $orderParams['contribution_status_id'] = 'Pending';
3623 $orderParams['api.PaymentProcessor.pay'] = [
3624 'payment_processor_id' => $this->paymentProcessorID,
3625 'credit_card_type' => 'Visa',
3626 'credit_card_number' => 41111111111111,
3627 'amount' => 5,
3628 ];
3629
3630 $order = $this->callAPISuccess('Order', 'create', $orderParams);
3631 $this->callAPISuccess('Payment', 'create', ['total_amount' => 5, 'is_send_notification' => 0, 'order_id' => $order['id']]);
3632 $address = $this->callAPISuccess('Address', 'create', ['contribution_id' => $order['id'], 'name' => 'bob', 'contact_id' => 1, 'street_address' => 'blah']);
3633 $this->callAPISuccess('Contribution', 'create', ['id' => $order['id'], 'address_id' => $address['id']]);
9099cab3 3634 $this->callAPISuccess('contribution', 'sendconfirmation', [
49cba3ad 3635 'id' => $order['id'],
39b959db 3636 'receipt_from_email' => 'api@civicrm.org',
9099cab3
CW
3637 ]);
3638 $mut->checkMailLog([
39b959db
SL
3639 '$ 100.00',
3640 'Contribution Information',
9099cab3 3641 ], [
39b959db 3642 'Event',
9099cab3 3643 ]);
128d44a1 3644
49cba3ad 3645 $this->checkCreditCardDetails($mut, $order['id']);
6a488035 3646 $mut->stop();
49cba3ad 3647 $tplVars = CRM_Core_Smarty::singleton()->get_template_vars();
3648 $this->assertEquals('bob', $tplVars['billingName']);
3649 $this->assertEquals("bob\nblah\n", $tplVars['address']);
6a488035
TO
3650 }
3651
dbacb875
AS
3652 /**
3653 * Test sending a mail via the API.
3654 * This simulates webform_civicrm using pay later contribution page
3655 */
3656 public function testSendconfirmationPayLater() {
3657 $mut = new CiviMailUtils($this, TRUE);
3658
3659 // Create contribution page
9099cab3 3660 $pageParams = [
dbacb875
AS
3661 'title' => 'Webform Contributions',
3662 'financial_type_id' => 1,
3663 'contribution_type_id' => 1,
3664 'is_confirm_enabled' => 1,
3665 'is_pay_later' => 1,
3666 'pay_later_text' => 'I will send payment by cheque',
3667 'pay_later_receipt' => 'Send your cheque payable to "CiviCRM LLC" to the office',
9099cab3 3668 ];
dbacb875
AS
3669 $contributionPage = $this->callAPISuccess('contribution_page', 'create', $pageParams);
3670
3671 // Create pay later contribution
9099cab3 3672 $contribParams = [
dbacb875
AS
3673 'contact_id' => $this->_individualId,
3674 'financial_type_id' => 1,
3675 'is_pay_later' => 1,
3676 'contribution_status_id' => 2,
3677 'contribution_page_id' => $contributionPage['id'],
3678 'total_amount' => '10.00',
9099cab3 3679 ];
dbacb875
AS
3680 $contribution = $this->callAPISuccess('contribution', 'create', $contribParams);
3681
3682 // Create line item
9099cab3 3683 $lineItemParams = [
dbacb875
AS
3684 'contribution_id' => $contribution['id'],
3685 'entity_id' => $contribution['id'],
3686 'entity_table' => 'civicrm_contribution',
3687 'label' => 'My lineitem label',
3688 'qty' => 1,
3689 'unit_price' => "10.00",
3690 'line_total' => "10.00",
9099cab3 3691 ];
dbacb875
AS
3692 $lineItem = $this->callAPISuccess('lineItem', 'create', $lineItemParams);
3693
3694 // Create email
3695 try {
9099cab3 3696 civicrm_api3('contribution', 'sendconfirmation', [
39b959db
SL
3697 'id' => $contribution['id'],
3698 'receipt_from_email' => 'api@civicrm.org',
9099cab3 3699 ]);
717fdb8a
AS
3700 }
3701 catch (Exception $e) {
dbacb875
AS
3702 // Need to figure out how to stop this some other day
3703 // We don't care about the Payment Processor because this is Pay Later
3704 // The point of this test is to check we get the pay_later version of the mail
3705 if ($e->getMessage() != "Undefined variable: CRM16923AnUnreliableMethodHasBeenUserToDeterminePaymentProcessorFromContributionPage") {
3706 throw $e;
3707 }
3708 }
3709
3710 // Retrieve mail & check it has the pay_later_receipt info
3711 $mut->getMostRecentEmail('raw');
9099cab3 3712 $mut->checkMailLog([
39b959db
SL
3713 (string) $contribParams['total_amount'],
3714 $pageParams['pay_later_receipt'],
9099cab3 3715 ], [
39b959db 3716 'Event',
9099cab3 3717 ]);
94db3e6e 3718 $this->checkReceiptDetails($mut, $contributionPage['id'], $contribution['id']);
dbacb875
AS
3719 $mut->stop();
3720 }
3721
128d44a1 3722 /**
3723 * Check credit card details in sent mail via API
3724 *
450dfb41 3725 * @param CiviMailUtils $mut
128d44a1 3726 * @param int $contributionID Contribution ID
3727 *
450dfb41 3728 * @throws \CRM_Core_Exception
128d44a1 3729 */
3730 public function checkCreditCardDetails($mut, $contributionID) {
450dfb41 3731 $this->callAPISuccess('contribution', 'create', $this->_params);
9099cab3 3732 $this->callAPISuccess('contribution', 'sendconfirmation', [
39b959db
SL
3733 'id' => $contributionID,
3734 'receipt_from_email' => 'api@civicrm.org',
3735 'payment_processor_id' => $this->paymentProcessorID,
9099cab3
CW
3736 ]);
3737 $mut->checkMailLog([
39b959db
SL
3738 // billing header
3739 'Billing Name and Address',
3740 // billing name
3741 'anthony_anderson@civicrm.org',
9099cab3 3742 ], [
39b959db 3743 'Event',
9099cab3 3744 ]);
128d44a1 3745 }
3746
94db3e6e
JP
3747 /**
3748 * Check receipt details in sent mail via API
3749 *
3750 * @param CiviMailUtils $mut
3751 * @param int $pageID Page ID
3752 * @param int $contributionID Contribution ID
3753 *
3754 * @throws \CRM_Core_Exception
3755 */
3756 public function checkReceiptDetails($mut, $pageID, $contributionID) {
3757 $pageReceipt = [
3758 'receipt_from_name' => "Page FromName",
3759 'receipt_from_email' => "page_from@email.com",
3760 'cc_receipt' => "page_cc@email.com",
3761 'receipt_text' => "Page Receipt Text",
3762 ];
3763 $customReceipt = [
3764 'receipt_from_name' => "Custom FromName",
3765 'receipt_from_email' => "custom_from@email.com",
3766 'cc_receipt' => "custom_cc@email.com",
3767 'receipt_text' => "Test Custom Receipt Text",
3768 ];
3769 $this->callAPISuccess('ContributionPage', 'create', array_merge([
3770 'id' => $pageID,
3771 'is_email_receipt' => 1,
3772 ], $pageReceipt));
3773
3774 $this->callAPISuccess('contribution', 'sendconfirmation', array_merge([
3775 'id' => $contributionID,
3776 'payment_processor_id' => $this->paymentProcessorID,
3777 ], $customReceipt));
3778
3779 //Verify if custom receipt details are present in email.
3780 $mut->checkMailLog(array_values($customReceipt), array_values($pageReceipt));
3781 }
3782
2f45e1c2 3783 /**
eceb18cc 3784 * Test sending a mail via the API.
6a488035 3785 */
00be9182 3786 public function testSendMailEvent() {
5896d037 3787 $mut = new CiviMailUtils($this, TRUE);
6c6e6187 3788 $contribution = $this->callAPISuccess('contribution', 'create', $this->_params);
9099cab3 3789 $event = $this->eventCreate([
6a488035
TO
3790 'is_email_confirm' => 1,
3791 'confirm_from_email' => 'test@civicrm.org',
9099cab3 3792 ]);
6a488035 3793 $this->_eventID = $event['id'];
9099cab3 3794 $participantParams = [
6a488035
TO
3795 'contact_id' => $this->_individualId,
3796 'event_id' => $this->_eventID,
3797 'status_id' => 1,
3798 'role_id' => 1,
3799 // to ensure it matches later on
3800 'register_date' => '2007-07-21 00:00:00',
3801 'source' => 'Online Event Registration: API Testing',
4ab7d517 3802
9099cab3 3803 ];
2f45e1c2 3804 $participant = $this->callAPISuccess('participant', 'create', $participantParams);
9099cab3 3805 $this->callAPISuccess('participant_payment', 'create', [
6a488035
TO
3806 'participant_id' => $participant['id'],
3807 'contribution_id' => $contribution['id'],
9099cab3
CW
3808 ]);
3809 $this->callAPISuccess('contribution', 'sendconfirmation', [
39b959db
SL
3810 'id' => $contribution['id'],
3811 'receipt_from_email' => 'api@civicrm.org',
9099cab3 3812 ]);
6a488035 3813
9099cab3 3814 $mut->checkMailLog([
39b959db
SL
3815 'Annual CiviCRM meet',
3816 'Event',
3817 'To: "Mr. Anthony Anderson II" <anthony_anderson@civicrm.org>',
9099cab3 3818 ], []);
6a488035
TO
3819 $mut->stop();
3820 }
3821
4302618d 3822 /**
1e52837d
EM
3823 * This function does a GET & compares the result against the $params.
3824 *
3825 * Use as a double check on Creates.
3826 *
3827 * @param array $params
3828 * @param int $id
67f947ac 3829 * @param bool $delete
6c6e6187 3830 */
1e52837d 3831 public function contributionGetnCheck($params, $id, $delete = TRUE) {
6a488035 3832
9099cab3 3833 $contribution = $this->callAPISuccess('Contribution', 'Get', [
6a488035 3834 'id' => $id,
9099cab3 3835 ]);
6a488035
TO
3836
3837 if ($delete) {
9099cab3 3838 $this->callAPISuccess('contribution', 'delete', ['id' => $id]);
6a488035 3839 }
2bfae985 3840 $this->assertAPISuccess($contribution, 0);
6a488035
TO
3841 $values = $contribution['values'][$contribution['id']];
3842 $params['receive_date'] = date('Y-m-d H:i:s', strtotime($params['receive_date']));
3843 // this is not returned in id format
3844 unset($params['payment_instrument_id']);
3845 $params['contribution_source'] = $params['source'];
3846 unset($params['source']);
3847 foreach ($params as $key => $value) {
22f80e87 3848 $this->assertEquals($value, $values[$key], $key . " value: $value doesn't match " . print_r($values, TRUE));
6a488035
TO
3849 }
3850 }
3851
294cc627 3852 /**
3853 * Create a pending contribution & linked pending pledge record.
3854 */
3855 public function createPendingPledgeContribution() {
3856
9099cab3 3857 $pledgeID = $this->pledgeCreate(['contact_id' => $this->_individualId, 'installments' => 1, 'amount' => 500]);
294cc627 3858 $this->_ids['pledge'] = $pledgeID;
9099cab3 3859 $contribution = $this->callAPISuccess('contribution', 'create', array_merge($this->_params, [
294cc627 3860 'contribution_status_id' => 'Pending',
39b959db 3861 'total_amount' => 500,
9099cab3
CW
3862 ]));
3863 $paymentID = $this->callAPISuccessGetValue('PledgePayment', [
3864 'options' => ['limit' => 1],
294cc627 3865 'return' => 'id',
9099cab3
CW
3866 ]);
3867 $this->callAPISuccess('PledgePayment', 'create', [
294cc627 3868 'id' => $paymentID,
3869 'contribution_id' =>
3870 $contribution['id'],
3871 'status_id' => 'Pending',
3872 'scheduled_amount' => 500,
9099cab3 3873 ]);
294cc627 3874
3875 return $contribution['id'];
3876 }
3877
0efa8efe 3878 /**
1e52837d 3879 * Create a pending contribution & linked pending participant record (along with an event).
0efa8efe 3880 */
5896d037 3881 public function createPendingParticipantContribution() {
ed7e2e99 3882 $this->_ids['event']['test'] = $this->eventCreate(['is_email_confirm' => 1, 'confirm_from_email' => 'test@civicrm.org'])['id'];
3883 $participantID = $this->participantCreate(['event_id' => $this->_ids['event']['test'], 'status_id' => 6, 'contact_id' => $this->_individualId]);
5896d037 3884 $this->_ids['participant'] = $participantID;
9099cab3 3885 $params = array_merge($this->_params, ['contact_id' => $this->_individualId, 'contribution_status_id' => 2, 'financial_type_id' => 'Event Fee']);
6c6e6187 3886 $contribution = $this->callAPISuccess('contribution', 'create', $params);
9099cab3 3887 $this->callAPISuccess('participant_payment', 'create', [
92915c55
TO
3888 'contribution_id' => $contribution['id'],
3889 'participant_id' => $participantID,
9099cab3
CW
3890 ]);
3891 $this->callAPISuccess('line_item', 'get', [
0efa8efe 3892 'entity_id' => $contribution['id'],
3893 'entity_table' => 'civicrm_contribution',
9099cab3 3894 'api.line_item.create' => [
0efa8efe 3895 'entity_id' => $participantID,
3896 'entity_table' => 'civicrm_participant',
9099cab3
CW
3897 ],
3898 ]);
0efa8efe 3899 return $contribution['id'];
3900 }
3901
4cbe18b8 3902 /**
1e52837d
EM
3903 * Get financial transaction amount.
3904 *
100fef9d 3905 * @param int $contId
4cbe18b8
EM
3906 *
3907 * @return null|string
f4d89200 3908 */
2da40d21 3909 public function _getFinancialTrxnAmount($contId) {
6c6e6187 3910 $query = "SELECT
6a488035
TO
3911 SUM( ft.total_amount ) AS total
3912 FROM civicrm_financial_trxn AS ft
3913 LEFT JOIN civicrm_entity_financial_trxn AS ceft ON ft.id = ceft.financial_trxn_id
3914 WHERE ceft.entity_table = 'civicrm_contribution'
3915 AND ceft.entity_id = {$contId}";
3916
6c6e6187
TO
3917 $result = CRM_Core_DAO::singleValueQuery($query);
3918 return $result;
3919 }
6a488035 3920
4cbe18b8 3921 /**
100fef9d 3922 * @param int $contId
4cbe18b8
EM
3923 *
3924 * @return null|string
f4d89200 3925 */
2da40d21 3926 public function _getFinancialItemAmount($contId) {
6c6e6187
TO
3927 $lineItem = key(CRM_Price_BAO_LineItem::getLineItems($contId, 'contribution'));
3928 $query = "SELECT
6a488035
TO
3929 SUM(amount)
3930 FROM civicrm_financial_item
3931 WHERE entity_table = 'civicrm_line_item'
3932 AND entity_id = {$lineItem}";
6c6e6187
TO
3933 $result = CRM_Core_DAO::singleValueQuery($query);
3934 return $result;
3935 }
6a488035 3936
4cbe18b8 3937 /**
100fef9d 3938 * @param int $contId
4cbe18b8
EM
3939 * @param $context
3940 */
00be9182 3941 public function _checkFinancialItem($contId, $context) {
6c6e6187 3942 if ($context != 'paylater') {
9099cab3 3943 $params = [
5896d037
TO
3944 'entity_id' => $contId,
3945 'entity_table' => 'civicrm_contribution',
9099cab3 3946 ];
6c6e6187 3947 $trxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($params, TRUE));
9099cab3 3948 $entityParams = [
6a488035
TO
3949 'financial_trxn_id' => $trxn['financial_trxn_id'],
3950 'entity_table' => 'civicrm_financial_item',
9099cab3 3951 ];
6c6e6187 3952 $entityTrxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($entityParams));
9099cab3 3953 $params = [
6a488035 3954 'id' => $entityTrxn['entity_id'],
9099cab3 3955 ];
6c6e6187
TO
3956 }
3957 if ($context == 'paylater') {
3958 $lineItems = CRM_Price_BAO_LineItem::getLineItems($contId, 'contribution');
3959 foreach ($lineItems as $key => $item) {
9099cab3 3960 $params = [
5896d037
TO
3961 'entity_id' => $key,
3962 'entity_table' => 'civicrm_line_item',
9099cab3
CW
3963 ];
3964 $compareParams = ['status_id' => 1];
6c6e6187
TO
3965 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialItem', $params, $compareParams);
3966 }
3967 }
3968 elseif ($context == 'refund') {
9099cab3 3969 $compareParams = [
5896d037
TO
3970 'status_id' => 1,
3971 'financial_account_id' => 1,
3972 'amount' => -100,
9099cab3 3973 ];
6c6e6187
TO
3974 }
3975 elseif ($context == 'cancelPending') {
9099cab3 3976 $compareParams = [
5896d037
TO
3977 'status_id' => 3,
3978 'financial_account_id' => 1,
3979 'amount' => -100,
9099cab3 3980 ];
6c6e6187
TO
3981 }
3982 elseif ($context == 'changeFinancial') {
3983 $lineKey = key(CRM_Price_BAO_LineItem::getLineItems($contId, 'contribution'));
9099cab3 3984 $params = [
5896d037
TO
3985 'entity_id' => $lineKey,
3986 'amount' => -100,
9099cab3
CW
3987 ];
3988 $compareParams = [
5896d037 3989 'financial_account_id' => 1,
9099cab3 3990 ];
6c6e6187 3991 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialItem', $params, $compareParams);
9099cab3 3992 $params = [
5896d037
TO
3993 'financial_account_id' => 3,
3994 'entity_id' => $lineKey,
9099cab3
CW
3995 ];
3996 $compareParams = [
5896d037 3997 'amount' => 100,
9099cab3 3998 ];
6c6e6187
TO
3999 }
4000 if ($context != 'paylater') {
4001 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialItem', $params, $compareParams);
4002 }
4003 }
6a488035 4004
b0e806fa 4005 /**
4006 * Check correct financial transaction entries were created for the change in payment instrument.
4007 *
4008 * @param int $contributionID
4009 * @param int $originalInstrumentID
4010 * @param int $newInstrumentID
39b959db 4011 * @param int $amount
b0e806fa 4012 */
4013 public function checkFinancialTrxnPaymentInstrumentChange($contributionID, $originalInstrumentID, $newInstrumentID, $amount = 100) {
4014
4015 $entityFinancialTrxns = $this->getFinancialTransactionsForContribution($contributionID);
4016
9099cab3 4017 $originalTrxnParams = [
b0e806fa 4018 'to_financial_account_id' => CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($originalInstrumentID),
4019 'payment_instrument_id' => $originalInstrumentID,
4020 'amount' => $amount,
4021 'status_id' => 1,
9099cab3 4022 ];
b0e806fa 4023
9099cab3 4024 $reversalTrxnParams = [
b0e806fa 4025 'to_financial_account_id' => CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($originalInstrumentID),
4026 'payment_instrument_id' => $originalInstrumentID,
4027 'amount' => -$amount,
4028 'status_id' => 1,
9099cab3 4029 ];
b0e806fa 4030
9099cab3 4031 $newTrxnParams = [
b0e806fa 4032 'to_financial_account_id' => CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($newInstrumentID),
4033 'payment_instrument_id' => $newInstrumentID,
4034 'amount' => $amount,
4035 'status_id' => 1,
9099cab3 4036 ];
b0e806fa 4037
9099cab3 4038 foreach ([$originalTrxnParams, $reversalTrxnParams, $newTrxnParams] as $index => $transaction) {
b0e806fa 4039 $entityFinancialTrxn = $entityFinancialTrxns[$index];
4040 $this->assertEquals($entityFinancialTrxn['amount'], $transaction['amount']);
4041
9099cab3 4042 $financialTrxn = $this->callAPISuccessGetSingle('FinancialTrxn', [
b0e806fa 4043 'id' => $entityFinancialTrxn['financial_trxn_id'],
9099cab3 4044 ]);
b0e806fa 4045 $this->assertEquals($transaction['status_id'], $financialTrxn['status_id']);
4046 $this->assertEquals($transaction['amount'], $financialTrxn['total_amount']);
4047 $this->assertEquals($transaction['amount'], $financialTrxn['net_amount']);
4048 $this->assertEquals(0, $financialTrxn['fee_amount']);
4049 $this->assertEquals($transaction['payment_instrument_id'], $financialTrxn['payment_instrument_id']);
4050 $this->assertEquals($transaction['to_financial_account_id'], $financialTrxn['to_financial_account_id']);
4051
4052 // Generic checks.
4053 $this->assertEquals(1, $financialTrxn['is_payment']);
4054 $this->assertEquals('USD', $financialTrxn['currency']);
4055 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($financialTrxn['trxn_date'])));
4056 }
4057 }
4058
4cbe18b8 4059 /**
52da5b1e 4060 * Check financial transaction.
4061 *
4062 * @todo break this down into sensible functions - most calls to it only use a few lines out of the big if.
4063 *
4ff927bc 4064 * @param array $contribution
4065 * @param string $context
100fef9d 4066 * @param int $instrumentId
52da5b1e 4067 * @param array $extraParams
4cbe18b8 4068 */
9099cab3 4069 public function _checkFinancialTrxn($contribution, $context, $instrumentId = NULL, $extraParams = []) {
b0e806fa 4070 $financialTrxns = $this->getFinancialTransactionsForContribution($contribution['id']);
4071 $trxn = array_pop($financialTrxns);
4072
9099cab3 4073 $params = [
5896d037 4074 'id' => $trxn['financial_trxn_id'],
9099cab3 4075 ];
6c6e6187 4076 if ($context == 'payLater') {
9099cab3 4077 $compareParams = [
5896d037 4078 'status_id' => 1,
876b8ab0 4079 'from_financial_account_id' => CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contribution['financial_type_id'], 'Accounts Receivable Account is'),
9099cab3 4080 ];
6c6e6187
TO
4081 }
4082 elseif ($context == 'refund') {
9099cab3 4083 $compareParams = [
5896d037
TO
4084 'to_financial_account_id' => 6,
4085 'total_amount' => -100,
4086 'status_id' => 7,
b7990bb6 4087 'trxn_date' => '2015-01-01 09:00:00',
797d4c52 4088 'trxn_id' => 'the refund',
9099cab3 4089 ];
6c6e6187
TO
4090 }
4091 elseif ($context == 'cancelPending') {
9099cab3 4092 $compareParams = [
ed4d0aea 4093 'to_financial_account_id' => 7,
5896d037
TO
4094 'total_amount' => -100,
4095 'status_id' => 3,
9099cab3 4096 ];
6c6e6187
TO
4097 }
4098 elseif ($context == 'changeFinancial' || $context == 'paymentInstrument') {
b0e806fa 4099 // @todo checkFinancialTrxnPaymentInstrumentChange instead for paymentInstrument.
4100 // It does the same thing with greater readability.
4101 // @todo remove handling for
4102
9099cab3 4103 $entityParams = [
5896d037
TO
4104 'entity_id' => $contribution['id'],
4105 'entity_table' => 'civicrm_contribution',
4106 'amount' => -100,
9099cab3 4107 ];
6c6e6187 4108 $trxn = current(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($entityParams));
9099cab3 4109 $trxnParams1 = [
6a488035 4110 'id' => $trxn['financial_trxn_id'],
9099cab3 4111 ];
122250ec 4112 if (empty($extraParams)) {
9099cab3 4113 $compareParams = [
122250ec
SL
4114 'total_amount' => -100,
4115 'status_id' => 1,
9099cab3 4116 ];
122250ec 4117 }
1a3d69b0 4118 elseif ($context !== 'changeFinancial') {
9099cab3 4119 $compareParams = [
122250ec
SL
4120 'total_amount' => 100,
4121 'status_id' => 1,
9099cab3 4122 ];
122250ec 4123 }
6c6e6187
TO
4124 if ($context == 'paymentInstrument') {
4125 $compareParams['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($instrumentId);
4126 $compareParams['payment_instrument_id'] = $instrumentId;
4127 }
4128 else {
4129 $compareParams['to_financial_account_id'] = 12;
4130 }
5ca657dd 4131 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialTrxn', $trxnParams1, array_merge($compareParams, $extraParams));
4132 $compareParams['total_amount'] = 100;
1a3d69b0
SL
4133 // Reverse the extra params now that we will be checking the new positive transaction.
4134 if ($context === 'changeFinancial' && !empty($extraParams)) {
4135 foreach ($extraParams as $param => $value) {
4136 $extraParams[$param] = 0 - $value;
4137 }
4138 }
6c6e6187
TO
4139 }
4140
797d4c52 4141 $this->assertDBCompareValues('CRM_Financial_DAO_FinancialTrxn', $params, array_merge($compareParams, $extraParams));
6c6e6187 4142 }
6a488035 4143
4cbe18b8
EM
4144 /**
4145 * @return mixed
4146 */
5896d037 4147 public function _addPaymentInstrument() {
6c6e6187 4148 $gId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'payment_instrument', 'id', 'name');
9099cab3 4149 $optionParams = [
5896d037
TO
4150 'option_group_id' => $gId,
4151 'label' => 'Test Card',
4152 'name' => 'Test Card',
4153 'value' => '6',
4154 'weight' => '6',
4155 'is_active' => 1,
9099cab3 4156 ];
6c6e6187
TO
4157 $optionValue = $this->callAPISuccess('option_value', 'create', $optionParams);
4158 $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' "));
9099cab3 4159 $financialParams = [
5896d037
TO
4160 'entity_table' => 'civicrm_option_value',
4161 'entity_id' => $optionValue['id'],
4162 'account_relationship' => $relationTypeId,
4163 'financial_account_id' => 7,
9099cab3 4164 ];
db62d3a5 4165 CRM_Financial_BAO_FinancialTypeAccount::add($financialParams);
6c6e6187
TO
4166 $this->assertNotEmpty($optionValue['values'][$optionValue['id']]['value']);
4167 return $optionValue['values'][$optionValue['id']]['value'];
4168 }
6a488035 4169
02a9c0a4 4170 public function _deletedAddedPaymentInstrument() {
9099cab3 4171 $result = $this->callAPISuccess('OptionValue', 'get', [
02a9c0a4 4172 'option_group_id' => 'payment_instrument',
4173 'name' => 'Test Card',
4174 'value' => '6',
4175 'is_active' => 1,
9099cab3 4176 ]);
02a9c0a4 4177 if ($id = CRM_Utils_Array::value('id', $result)) {
9099cab3 4178 $this->callAPISuccess('OptionValue', 'delete', ['id' => $id]);
02a9c0a4 4179 }
4180 }
4181
3c49d90c 4182 /**
4183 * Set up the basic recurring contribution for tests.
4184 *
4185 * @param array $generalParams
4186 * Parameters that can be merged into the recurring AND the contribution.
7f4ef731 4187 *
4188 * @param array $recurParams
4189 * Parameters to merge into the recur only.
3c49d90c 4190 *
4191 * @return array|int
fa839a68 4192 * @throws \CRM_Core_Exception
3c49d90c 4193 */
9099cab3
CW
4194 protected function setUpRecurringContribution($generalParams = [], $recurParams = []) {
4195 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
3c49d90c 4196 'contact_id' => $this->_individualId,
4197 'installments' => '12',
4198 'frequency_interval' => '1',
4199 'amount' => '100',
4200 'contribution_status_id' => 1,
4201 'start_date' => '2012-01-01 00:00:00',
4202 'currency' => 'USD',
4203 'frequency_unit' => 'month',
4204 'payment_processor_id' => $this->paymentProcessorID,
9099cab3 4205 ], $generalParams, $recurParams));
fa839a68 4206 $contributionParams = array_merge(
3c49d90c 4207 $this->_params,
9099cab3 4208 [
3c49d90c 4209 'contribution_recur_id' => $contributionRecur['id'],
fa839a68 4210 'contribution_status_id' => 'Pending',
4211 ], $generalParams);
4212 $contributionParams['api.Payment.create'] = ['total_amount' => $contributionParams['total_amount']];
4213 $originalContribution = $this->callAPISuccess('Order', 'create', $contributionParams);
3c49d90c 4214 return $originalContribution;
4215 }
4216
d2334242
PH
4217 /**
4218 * Set up a basic auto-renew membership for tests.
4219 *
4220 * @param array $generalParams
4221 * Parameters that can be merged into the recurring AND the contribution.
4222 *
4223 * @param array $recurParams
4224 * Parameters to merge into the recur only.
4225 *
4226 * @return array|int
562e4fb8 4227 * @throws \CRM_Core_Exception
d2334242 4228 */
9099cab3
CW
4229 protected function setUpAutoRenewMembership($generalParams = [], $recurParams = []) {
4230 $newContact = $this->callAPISuccess('Contact', 'create', [
39b959db
SL
4231 'contact_type' => 'Individual',
4232 'sort_name' => 'McTesterson, Testy',
4233 'display_name' => 'Testy McTesterson',
4234 'preferred_language' => 'en_US',
4235 'preferred_mail_format' => 'Both',
4236 'first_name' => 'Testy',
4237 'last_name' => 'McTesterson',
4238 'contact_is_deleted' => '0',
4239 'email_id' => '4',
4240 'email' => 'tmctesterson@example.com',
4241 'on_hold' => '0',
9099cab3
CW
4242 ]);
4243 $membershipType = $this->callAPISuccess('MembershipType', 'create', [
562e4fb8 4244 'domain_id' => 'Default Domain Name',
d2334242 4245 'member_of_contact_id' => 1,
562e4fb8 4246 'financial_type_id' => 'Member Dues',
4247 'duration_unit' => 'month',
d2334242 4248 'duration_interval' => 1,
5b1b8db2 4249 'period_type' => 'rolling',
562e4fb8 4250 'name' => 'Standard Member',
d2334242 4251 'minimum_fee' => 100,
9099cab3
CW
4252 ]);
4253 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
76e80087 4254 'contact_id' => $newContact['id'],
d2334242
PH
4255 'installments' => '12',
4256 'frequency_interval' => '1',
4257 'amount' => '100',
4258 'contribution_status_id' => 1,
4259 'start_date' => '2012-01-01 00:00:00',
4260 'currency' => 'USD',
4261 'frequency_unit' => 'month',
4262 'payment_processor_id' => $this->paymentProcessorID,
9099cab3 4263 ], $generalParams, $recurParams));
7c3f3d59 4264
9099cab3 4265 $membership = $this->callAPISuccess('membership', 'create', [
7c3f3d59 4266 'contact_id' => $newContact['id'],
4267 'contribution_recur_id' => $contributionRecur['id'],
4268 'financial_type_id' => "Member Dues",
4269 'membership_type_id' => $membershipType['id'],
4270 'num_terms' => 1,
4271 'skipLineItem' => TRUE,
9099cab3 4272 ]);
7c3f3d59 4273
4274 CRM_Price_BAO_LineItem::getLineItemArray($this->_params, NULL, 'membership', $membershipType['id']);
d2334242
PH
4275 $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
4276 $this->_params,
9099cab3 4277 [
d2334242
PH
4278 'contact_id' => $newContact['id'],
4279 'contribution_recur_id' => $contributionRecur['id'],
4280 'financial_type_id' => "Member Dues",
4281 'contribution_status_id' => 1,
4282 'invoice_id' => uniqid(),
9099cab3 4283 ], $generalParams)
d2334242 4284 );
9099cab3 4285 $lineItem = $this->callAPISuccess('LineItem', 'getsingle', []);
7c3f3d59 4286 $this->assertEquals('civicrm_membership', $lineItem['entity_table']);
9099cab3
CW
4287 $membership = $this->callAPISuccess('Membership', 'getsingle', ['id' => $lineItem['entity_id']]);
4288 $this->callAPISuccess('LineItem', 'getsingle', []);
4289 $this->callAPISuccessGetCount('MembershipPayment', ['membership_id' => $membership['id']], 1);
d2334242 4290
9099cab3 4291 return [$originalContribution, $membership];
d2334242 4292 }
39b959db 4293
893a550c 4294 /**
4295 * Set up a repeat transaction.
4296 *
4297 * @param array $recurParams
39b959db
SL
4298 * @param mixed $flag
4299 * @param array $contributionParams
893a550c 4300 * @return array
4301 */
9099cab3 4302 protected function setUpRepeatTransaction($recurParams = [], $flag, $contributionParams = []) {
893a550c 4303 $paymentProcessorID = $this->paymentProcessorCreate();
9099cab3 4304 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
893a550c 4305 'contact_id' => $this->_individualId,
4306 'installments' => '12',
4307 'frequency_interval' => '1',
4308 'amount' => '500',
4309 'contribution_status_id' => 1,
4310 'start_date' => '2012-01-01 00:00:00',
4311 'currency' => 'USD',
4312 'frequency_unit' => 'month',
4313 'payment_processor_id' => $paymentProcessorID,
9099cab3 4314 ], $recurParams));
0e6ccb2e 4315
7150b1c8 4316 $originalContribution = '';
0e6ccb2e 4317 if ($flag == 'multiple') {
7150b1c8 4318 // CRM-19309 create a contribution + also add in line_items (plural):
19893cf2 4319 $params = array_merge($this->_params, $contributionParams);
0e6ccb2e 4320 $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
19893cf2 4321 $params,
9099cab3 4322 [
0e6ccb2e
K
4323 'contribution_recur_id' => $contributionRecur['id'],
4324 'skipLineItem' => 1,
9099cab3
CW
4325 'api.line_item.create' => [
4326 [
0e6ccb2e
K
4327 'price_field_id' => 1,
4328 'qty' => 2,
4329 'line_total' => '20',
4330 'unit_price' => '10',
4331 'financial_type_id' => 1,
9099cab3
CW
4332 ],
4333 [
0e6ccb2e
K
4334 'price_field_id' => 1,
4335 'qty' => 1,
4336 'line_total' => '80',
4337 'unit_price' => '80',
4338 'financial_type_id' => 2,
9099cab3
CW
4339 ],
4340 ],
4341 ]
0e6ccb2e
K
4342 )
4343 );
4344 }
4345 elseif ($flag == 'single') {
9099cab3 4346 $params = array_merge($this->_params, ['contribution_recur_id' => $contributionRecur['id']]);
19893cf2
SL
4347 $params = array_merge($params, $contributionParams);
4348 $originalContribution = $this->callAPISuccess('contribution', 'create', $params);
0e6ccb2e 4349 }
b2250d14 4350 $originalContribution['contribution_recur_id'] = $contributionRecur['id'];
f69a9ac3 4351 $originalContribution['payment_processor_id'] = $paymentProcessorID;
893a550c 4352 return $originalContribution;
4353 }
4354
ec7e3954
E
4355 /**
4356 * Common set up routine.
4357 *
4358 * @return array
4359 */
4360 protected function setUpForCompleteTransaction() {
4361 $this->mut = new CiviMailUtils($this, TRUE);
4362 $this->createLoggedInUser();
9099cab3 4363 $params = array_merge($this->_params, ['contribution_status_id' => 2, 'receipt_date' => 'now']);
ec7e3954
E
4364 $contribution = $this->callAPISuccess('contribution', 'create', $params);
4365 return $contribution;
4366 }
4367
9c01d961
SL
4368 /**
4369 * Test repeat contribution uses the Payment Processor' payment_instrument setting.
562e4fb8 4370 *
4371 * @throws \CRM_Core_Exception
9c01d961
SL
4372 */
4373 public function testRepeatTransactionWithNonCreditCardDefault() {
562e4fb8 4374 $contributionRecur = $this->callAPISuccess('ContributionRecur', 'create', [
9c01d961
SL
4375 'contact_id' => $this->_individualId,
4376 'installments' => '12',
4377 'frequency_interval' => '1',
4378 'amount' => '100',
4379 'contribution_status_id' => 1,
4380 'start_date' => '2012-01-01 00:00:00',
4381 'currency' => 'USD',
4382 'frequency_unit' => 'month',
4383 'payment_processor_id' => $this->paymentProcessorID,
9099cab3 4384 ]);
9c01d961
SL
4385 $contribution1 = $this->callAPISuccess('contribution', 'create', array_merge(
4386 $this->_params,
9099cab3 4387 ['contribution_recur_id' => $contributionRecur['id'], 'payment_instrument_id' => 2])
9c01d961 4388 );
9099cab3 4389 $contribution2 = $this->callAPISuccess('contribution', 'repeattransaction', [
9c01d961 4390 'contribution_status_id' => 'Completed',
562e4fb8 4391 'trxn_id' => 'blah',
9c01d961 4392 'original_contribution_id' => $contribution1,
9099cab3 4393 ]);
562e4fb8 4394 $this->assertEquals('Debit Card', CRM_Contribute_PseudoConstant::getLabel('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', $contribution2['values'][$contribution2['id']]['payment_instrument_id']));
9c01d961
SL
4395 }
4396
ee63135d 4397 /**
4398 * CRM-20008 Tests repeattransaction creates pending membership.
4399 */
37f29fcf 4400 public function testRepeatTransactionMembershipCreatePendingContribution() {
ee63135d 4401 list($originalContribution, $membership) = $this->setUpAutoRenewMembership();
9099cab3 4402 $this->callAPISuccess('membership', 'create', [
ee63135d 4403 'id' => $membership['id'],
4404 'end_date' => 'yesterday',
4405 'status_id' => 'Expired',
9099cab3
CW
4406 ]);
4407 $repeatedContribution = $this->callAPISuccess('contribution', 'repeattransaction', [
ee63135d 4408 'contribution_recur_id' => $originalContribution['values'][1]['contribution_recur_id'],
4409 'contribution_status_id' => 'Pending',
4410 'trxn_id' => uniqid(),
9099cab3
CW
4411 ]);
4412 $membershipStatusId = $this->callAPISuccess('membership', 'getvalue', [
ee63135d 4413 'id' => $membership['id'],
4414 'return' => 'status_id',
9099cab3 4415 ]);
ee63135d 4416
4417 // Let's see if the membership payments got created while we're at it.
9099cab3 4418 $membershipPayments = $this->callAPISuccess('MembershipPayment', 'get', [
37f29fcf 4419 'membership_id' => $membership['id'],
9099cab3 4420 ]);
ee63135d 4421 $this->assertEquals(2, $membershipPayments['count']);
4422
4423 $this->assertEquals('Expired', CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'status_id', $membershipStatusId));
9099cab3
CW
4424 $this->callAPISuccess('Contribution', 'completetransaction', ['id' => $repeatedContribution['id']]);
4425 $membership = $this->callAPISuccessGetSingle('membership', [
ee63135d 4426 'id' => $membership['id'],
4427 'return' => 'status_id, end_date',
9099cab3 4428 ]);
37f29fcf 4429 $this->assertEquals('New', CRM_Core_PseudoConstant::getName('CRM_Member_BAO_Membership', 'status_id', $membership['status_id']));
ee63135d 4430 $this->assertEquals(date('Y-m-d', strtotime('yesterday + 1 month')), $membership['end_date']);
ee63135d 4431 }
4432
cefed6df
SL
4433 /**
4434 * Test sending a mail via the API.
562e4fb8 4435 *
4436 * @throws \CRM_Core_Exception
cefed6df
SL
4437 */
4438 public function testSendMailWithAPISetFromDetails() {
4439 $mut = new CiviMailUtils($this, TRUE);
4440 $contribution = $this->callAPISuccess('contribution', 'create', $this->_params);
9099cab3 4441 $this->callAPISuccess('contribution', 'sendconfirmation', [
cefed6df
SL
4442 'id' => $contribution['id'],
4443 'receipt_from_email' => 'api@civicrm.org',
4444 'receipt_from_name' => 'CiviCRM LLC',
9099cab3
CW
4445 ]);
4446 $mut->checkMailLog([
39b959db
SL
4447 'From: CiviCRM LLC <api@civicrm.org>',
4448 'Contribution Information',
9099cab3 4449 ], [
39b959db 4450 'Event',
9099cab3 4451 ]);
cefed6df
SL
4452 $mut->stop();
4453 }
4454
4455 /**
4456 * Test sending a mail via the API.
4457 */
4458 public function testSendMailWithNoFromSetFallToDomain() {
4459 $this->createLoggedInUser();
4460 $mut = new CiviMailUtils($this, TRUE);
4461 $contribution = $this->callAPISuccess('contribution', 'create', $this->_params);
9099cab3 4462 $this->callAPISuccess('contribution', 'sendconfirmation', [
cefed6df 4463 'id' => $contribution['id'],
9099cab3
CW
4464 ]);
4465 $domain = $this->callAPISuccess('domain', 'getsingle', ['id' => 1]);
4466 $mut->checkMailLog([
39b959db
SL
4467 'From: ' . $domain['from_name'] . ' <' . $domain['from_email'] . '>',
4468 'Contribution Information',
9099cab3 4469 ], [
39b959db 4470 'Event',
9099cab3 4471 ]);
cefed6df
SL
4472 $mut->stop();
4473 }
4474
4475 /**
4476 * Test sending a mail via the API.
4477 */
4478 public function testSendMailWithRepeatTransactionAPIFalltoDomain() {
4479 $this->createLoggedInUser();
4480 $mut = new CiviMailUtils($this, TRUE);
9099cab3
CW
4481 $contribution = $this->setUpRepeatTransaction([], 'single');
4482 $this->callAPISuccess('contribution', 'repeattransaction', [
cefed6df
SL
4483 'contribution_status_id' => 'Completed',
4484 'trxn_id' => uniqid(),
4485 'original_contribution_id' => $contribution,
9099cab3
CW
4486 ]);
4487 $domain = $this->callAPISuccess('domain', 'getsingle', ['id' => 1]);
4488 $mut->checkMailLog([
39b959db
SL
4489 'From: ' . $domain['from_name'] . ' <' . $domain['from_email'] . '>',
4490 'Contribution Information',
9099cab3 4491 ], [
39b959db 4492 'Event',
9099cab3 4493 ]
cefed6df
SL
4494 );
4495 $mut->stop();
4496 }
4497
4498 /**
4499 * Test sending a mail via the API.
4500 */
4501 public function testSendMailWithRepeatTransactionAPIFalltoContributionPage() {
4502 $mut = new CiviMailUtils($this, TRUE);
9099cab3 4503 $contributionPage = $this->contributionPageCreate(['receipt_from_name' => 'CiviCRM LLC', 'receipt_from_email' => 'contributionpage@civicrm.org', 'is_email_receipt' => 1]);
cefed6df 4504 $paymentProcessorID = $this->paymentProcessorCreate();
9099cab3 4505 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', [
cefed6df
SL
4506 'contact_id' => $this->_individualId,
4507 'installments' => '12',
4508 'frequency_interval' => '1',
4509 'amount' => '500',
4510 'contribution_status_id' => 1,
4511 'start_date' => '2012-01-01 00:00:00',
4512 'currency' => 'USD',
4513 'frequency_unit' => 'month',
4514 'payment_processor_id' => $paymentProcessorID,
9099cab3 4515 ]);
cefed6df
SL
4516 $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
4517 $this->_params,
9099cab3 4518 [
cefed6df 4519 'contribution_recur_id' => $contributionRecur['id'],
39b959db 4520 'contribution_page_id' => $contributionPage['id'],
9099cab3 4521 ])
cefed6df 4522 );
9099cab3 4523 $this->callAPISuccess('contribution', 'repeattransaction', [
cefed6df
SL
4524 'contribution_status_id' => 'Completed',
4525 'trxn_id' => uniqid(),
4526 'original_contribution_id' => $originalContribution,
9099cab3 4527 ]
cefed6df 4528 );
9099cab3 4529 $mut->checkMailLog([
39b959db
SL
4530 'From: CiviCRM LLC <contributionpage@civicrm.org>',
4531 'Contribution Information',
9099cab3 4532 ], [
39b959db 4533 'Event',
9099cab3 4534 ]);
cefed6df
SL
4535 $mut->stop();
4536 }
4537
4fb4e64f
SL
4538 /**
4539 * Test sending a mail via the API.
4540 */
4541 public function testSendMailWithRepeatTransactionAPIFalltoSystemFromNoDefaultFrom() {
4542 $mut = new CiviMailUtils($this, TRUE);
9099cab3
CW
4543 $originalContribution = $contribution = $this->setUpRepeatTransaction([], 'single');
4544 $fromEmail = $this->CallAPISuccess('optionValue', 'get', ['is_default' => 1, 'option_group_id' => 'from_email_address', 'sequential' => 1]);
4fb4e64f 4545 foreach ($fromEmail['values'] as $from) {
9099cab3 4546 $this->callAPISuccess('optionValue', 'create', ['is_default' => 0, 'id' => $from['id']]);
4fb4e64f 4547 }
9099cab3
CW
4548 $domain = $this->callAPISuccess('domain', 'getsingle', ['id' => CRM_Core_Config::domainID()]);
4549 $this->callAPISuccess('contribution', 'repeattransaction', [
4fb4e64f
SL
4550 'contribution_status_id' => 'Completed',
4551 'trxn_id' => uniqid(),
4552 'original_contribution_id' => $originalContribution,
9099cab3
CW
4553 ]);
4554 $mut->checkMailLog([
39b959db
SL
4555 'From: ' . $domain['name'] . ' <' . $domain['domain_email'] . '>',
4556 'Contribution Information',
9099cab3 4557 ], [
39b959db 4558 'Event',
9099cab3 4559 ]);
4fb4e64f
SL
4560 $mut->stop();
4561 }
4562
d891a273 4563 /**
4564 * Create a Contribution Page with is_email_receipt = TRUE.
4565 *
4566 * @param array $params
4567 * Params to overwrite with.
4568 *
4569 * @return array|int
4570 */
9099cab3
CW
4571 protected function createReceiptableContributionPage($params = []) {
4572 $contributionPage = $this->callAPISuccess('ContributionPage', 'create', array_merge([
d891a273 4573 'receipt_from_name' => 'Mickey Mouse',
4574 'receipt_from_email' => 'mickey@mouse.com',
4575 'title' => "Test Contribution Page",
4576 'financial_type_id' => 1,
4577 'currency' => 'CAD',
4578 'is_monetary' => TRUE,
4579 'is_email_receipt' => TRUE,
9099cab3 4580 ], $params));
d891a273 4581 return $contributionPage;
4582 }
4583
121c4616 4584 /**
4585 * function to test card_type and pan truncation.
4586 */
4587 public function testCardTypeAndPanTruncation() {
4588 $creditCardTypeIDs = array_flip(CRM_Financial_DAO_FinancialTrxn::buildOptions('card_type_id'));
4589 $contactId = $this->individualCreate();
9099cab3 4590 $params = [
121c4616 4591 'contact_id' => $contactId,
4592 'receive_date' => '2016-01-20',
4593 'total_amount' => 100,
4594 'financial_type_id' => 1,
4595 'payment_instrument' => 'Credit Card',
4596 'card_type_id' => $creditCardTypeIDs['Visa'],
4597 'pan_truncation' => 4567,
9099cab3 4598 ];
121c4616 4599 $contribution = $this->callAPISuccess('contribution', 'create', $params);
4600 $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
4601 $financialTrxn = $this->callAPISuccessGetSingle(
4602 'FinancialTrxn',
9099cab3 4603 [
121c4616 4604 'id' => $lastFinancialTrxnId['financialTrxnId'],
9099cab3
CW
4605 'return' => ['card_type_id', 'pan_truncation'],
4606 ]
121c4616 4607 );
4608 $this->assertEquals(CRM_Utils_Array::value('card_type_id', $financialTrxn), $creditCardTypeIDs['Visa']);
4609 $this->assertEquals(CRM_Utils_Array::value('pan_truncation', $financialTrxn), 4567);
9099cab3 4610 $params = [
121c4616 4611 'id' => $contribution['id'],
4612 'pan_truncation' => 2345,
4613 'card_type_id' => $creditCardTypeIDs['Amex'],
9099cab3 4614 ];
121c4616 4615 $contribution = $this->callAPISuccess('contribution', 'create', $params);
4616 $financialTrxn = $this->callAPISuccessGetSingle(
4617 'FinancialTrxn',
9099cab3 4618 [
121c4616 4619 'id' => $lastFinancialTrxnId['financialTrxnId'],
9099cab3
CW
4620 'return' => ['card_type_id', 'pan_truncation'],
4621 ]
121c4616 4622 );
4623 $this->assertEquals(CRM_Utils_Array::value('card_type_id', $financialTrxn), $creditCardTypeIDs['Amex']);
4624 $this->assertEquals(CRM_Utils_Array::value('pan_truncation', $financialTrxn), 2345);
4625 }
4626
19893cf2
SL
4627 /**
4628 * Test repeat contribution uses non default currency
4629 * @see https://issues.civicrm.org/jira/projects/CRM/issues/CRM-20678
4630 */
4631 public function testRepeatTransactionWithDifferenceCurrency() {
9099cab3
CW
4632 $originalContribution = $this->setUpRepeatTransaction(['currency' => 'AUD'], 'single', ['currency' => 'AUD']);
4633 $contribution = $this->callAPISuccess('contribution', 'repeattransaction', [
19893cf2
SL
4634 'original_contribution_id' => $originalContribution['id'],
4635 'contribution_status_id' => 'Completed',
4636 'trxn_id' => uniqid(),
9099cab3 4637 ]);
19893cf2
SL
4638 $this->assertEquals('AUD', $contribution['values'][$contribution['id']]['currency']);
4639 }
4640
b0e806fa 4641 /**
4642 * Get the financial items for the contribution.
4643 *
4644 * @param int $contributionID
4645 *
4646 * @return array
4647 * Array of associated financial items.
4648 */
4649 protected function getFinancialTransactionsForContribution($contributionID) {
9099cab3 4650 $trxnParams = [
b0e806fa 4651 'entity_id' => $contributionID,
4652 'entity_table' => 'civicrm_contribution',
9099cab3 4653 ];
b0e806fa 4654 // @todo the following function has naming errors & has a weird signature & appears to
4655 // only be called from test classes. Move into test suite & maybe just use api
4656 // from this function.
562e4fb8 4657 return array_merge(CRM_Financial_BAO_FinancialItem::retrieveEntityFinancialTrxn($trxnParams));
b0e806fa 4658 }
4659
1af690c4 4660 /**
4661 * Test getunique api call for Contribution entity
4662 */
4663 public function testContributionGetUnique() {
562e4fb8 4664 $result = $this->callAPIAndDocument($this->entity, 'getunique', [], __FUNCTION__, __FILE__);
1af690c4 4665 $this->assertEquals(2, $result['count']);
9099cab3
CW
4666 $this->assertEquals(['trxn_id'], $result['values']['UI_contrib_trxn_id']);
4667 $this->assertEquals(['invoice_id'], $result['values']['UI_contrib_invoice_id']);
1af690c4 4668 }
4669
d8bd2007
PN
4670 /**
4671 * Test Repeat Transaction Contribution with Tax amount.
4672 * https://lab.civicrm.org/dev/core/issues/806
4673 */
4674 public function testRepeatContributionWithTaxAmount() {
4675 $this->enableTaxAndInvoicing();
4676 $financialType = $this->callAPISuccess('financial_type', 'create', [
4677 'name' => 'Test taxable financial Type',
4678 'is_reserved' => 0,
4679 'is_active' => 1,
4680 ]);
4681 $this->relationForFinancialTypeWithFinancialAccount($financialType['id']);
4682 $contribution = $this->setUpRepeatTransaction(
4683 [],
4684 'single',
4685 [
4686 'financial_type_id' => $financialType['id'],
4687 ]
4688 );
9099cab3 4689 $this->callAPISuccess('contribution', 'repeattransaction', [
d8bd2007
PN
4690 'original_contribution_id' => $contribution['id'],
4691 'contribution_status_id' => 'Completed',
4692 'trxn_id' => uniqid(),
9099cab3 4693 ]);
9583e46d
JP
4694 $payments = $this->callAPISuccess('Contribution', 'get', ['sequential' => 1])['values'];
4695 //Assert if first payment and repeated payment has the same contribution amount.
4696 $this->assertEquals($payments[0]['total_amount'], $payments[1]['total_amount']);
d8bd2007 4697 $this->callAPISuccessGetCount('Contribution', [], 2);
5d8c94bc
JP
4698
4699 //Assert line item records.
4700 $lineItems = $this->callAPISuccess('LineItem', 'get', ['sequential' => 1])['values'];
4701 foreach ($lineItems as $lineItem) {
4702 $this->assertEquals($lineItem['unit_price'], $this->_params['total_amount']);
4703 $this->assertEquals($lineItem['line_total'], $this->_params['total_amount']);
4704 }
4705 $this->callAPISuccessGetCount('Contribution', [], 2);
d8bd2007
PN
4706 }
4707
a8fdb24e
CW
4708 public function testGetCurrencyOptions() {
4709 $result = $this->callAPISuccess('Contribution', 'getoptions', [
4710 'field' => 'currency',
4711 ]);
4712 $this->assertEquals('US Dollar', $result['values']['USD']);
4713 $this->assertNotContains('$', $result['values']);
4714 $result = $this->callAPISuccess('Contribution', 'getoptions', [
4715 'field' => 'currency',
4716 'context' => "abbreviate",
4717 ]);
4718 $this->assertEquals('$', $result['values']['USD']);
4719 $this->assertNotContains('US Dollar', $result['values']);
4720 }
4721
79c9d4c2 4722 /**
4723 * @throws \API_Exception
4724 * @throws \CRM_Core_Exception
4725 * @throws \Civi\API\Exception\UnauthorizedException
4726 */
2ac10e87 4727 public function testSetCustomDataInCreateAndHook() {
79c9d4c2 4728 $this->createCustomGroupWithFieldOfType([], 'int');
4729 $this->ids['CustomField']['text'] = (int) $this->createTextCustomField(['custom_group_id' => $this->ids['CustomGroup']['Custom Group']])['id'];
2ac10e87
SL
4730 $this->hookClass->setHook('civicrm_post', [
4731 $this,
4732 'civicrmPostContributionCustom',
4733 ]);
4734 $params = $this->_params;
4735 $params['custom_' . $this->ids['CustomField']['text']] = 'Some Text';
4736 $contribution = $this->callAPISuccess('Contribution', 'create', $params);
4737 $getContribution = $this->callAPISuccess('Contribution', 'get', [
4738 'id' => $contribution['id'],
4739 'return' => ['id', 'custom_' . $this->ids['CustomField']['text'], 'custom_' . $this->ids['CustomField']['int']],
4740 ]);
79c9d4c2 4741 $this->assertEquals(5, $getContribution['values'][$contribution['id']][$this->getCustomFieldName('int')]);
2ac10e87 4742 $this->assertEquals('Some Text', $getContribution['values'][$contribution['id']]['custom_' . $this->ids['CustomField']['text']]);
c971eccf
CW
4743 $this->callAPISuccess('CustomField', 'delete', ['id' => $this->ids['CustomField']['text']]);
4744 $this->callAPISuccess('CustomField', 'delete', ['id' => $this->ids['CustomField']['int']]);
4745 $this->callAPISuccess('CustomGroup', 'delete', ['id' => $this->ids['CustomGroup']['Custom Group']]);
2ac10e87
SL
4746 }
4747
79c9d4c2 4748 /**
4749 * Implement post hook.
4750 *
4751 * @param string $op
4752 * @param string $objectName
4753 * @param int $objectId
4754 * @param \CRM_Core_DAO $objectRef
4755 *
4756 * @throws \CRM_Core_Exception
4757 */
2ac10e87
SL
4758 public function civicrmPostContributionCustom($op, $objectName, $objectId, &$objectRef) {
4759 if ($objectName === 'Contribution' && $op === 'create') {
4760 $this->callAPISuccess('Contribution', 'create', [
4761 'id' => $objectId,
4762 'custom_' . $this->ids['CustomField']['int'] => 5,
4763 ]);
4764 }
4765 }
4766
c971eccf
CW
4767 /**
4768 * Test that passing in label for an option value linked to a custom field works
4769 * @see dev/core#1816
4770 */
4771 public function testCustomValueOptionLabelTest() {
4772 $this->createCustomGroupWithFieldOfType([], 'radio');
4773 $params = $this->_params;
4774 $params['custom_' . $this->ids['CustomField']['radio']] = 'Red Testing';
4775 $contribution = $this->callAPISuccess('Contribution', 'Create', $params);
4776 }
4777
605665c7 4778 /**
4779 * Test repeatTransaction with installments and next_sched_contribution_date
4780 *
4781 * @dataProvider getRepeatTransactionNextSchedData
4782 *
4783 * @param array $dataSet
4784 *
4785 * @throws \Exception
4786 */
4787 public function testRepeatTransactionUpdateNextSchedContributionDate($dataSet) {
4788 $paymentProcessorID = $this->paymentProcessorCreate();
4789 // Create the contribution before the recur so it doesn't trigger the update of next_sched_contribution_date
4790 $contribution = $this->callAPISuccess('contribution', 'create', array_merge(
4791 $this->_params,
4792 [
4793 'contribution_status_id' => 'Completed',
4794 'receive_date' => $dataSet['repeat'][0]['receive_date'],
4795 ])
4796 );
4797 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
4798 'contact_id' => $this->_individualId,
4799 'frequency_interval' => '1',
4800 'amount' => '500',
4801 'contribution_status_id' => 'Pending',
4802 'start_date' => '2012-01-01 00:00:00',
4803 'currency' => 'USD',
4804 'frequency_unit' => 'month',
4805 'payment_processor_id' => $paymentProcessorID,
4806 ], $dataSet['recur']));
4807 // Link the existing contribution to the recur *after* creating the recur.
4808 // If we just created the contribution now the next_sched_contribution_date would be automatically set
4809 // and we want to test the case when it is empty.
4810 $this->callAPISuccess('contribution', 'create', [
4811 'id' => $contribution['id'],
4812 'contribution_recur_id' => $contributionRecur['id'],
4813 ]);
4814
4815 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', [
4816 'id' => $contributionRecur['id'],
4817 'return' => ['next_sched_contribution_date', 'contribution_status_id'],
4818 ]);
4819 // Check that next_sched_contribution_date is empty
4820 $this->assertEquals('', $contributionRecur['next_sched_contribution_date'] ?? '');
4821
4822 $this->callAPISuccess('Contribution', 'repeattransaction', [
4823 'contribution_status_id' => 'Completed',
4824 'contribution_recur_id' => $contributionRecur['id'],
4825 'receive_date' => $dataSet['repeat'][0]['receive_date'],
4826 ]);
4827 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', [
4828 'id' => $contributionRecur['id'],
4829 'return' => ['next_sched_contribution_date', 'contribution_status_id'],
4830 ]);
4831 // Check that recur has status "In Progress"
4832 $this->assertEquals(
4833 (string) CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $dataSet['repeat'][0]['expectedRecurStatus']),
4834 $contributionRecur['contribution_status_id']
4835 );
4836 // Check that next_sched_contribution_date has been set to 1 period after the contribution receive date (ie. 1 month)
4837 $this->assertEquals($dataSet['repeat'][0]['expectedNextSched'], $contributionRecur['next_sched_contribution_date']);
4838
4839 // Now call Contribution.repeattransaction again and check that the next_sched_contribution_date has moved forward by 1 period again
4840 $this->callAPISuccess('Contribution', 'repeattransaction', [
4841 'contribution_status_id' => 'Completed',
4842 'contribution_recur_id' => $contributionRecur['id'],
4843 'receive_date' => $dataSet['repeat'][1]['receive_date'],
4844 ]);
4845 $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', [
4846 'id' => $contributionRecur['id'],
4847 'return' => ['next_sched_contribution_date', 'contribution_status_id'],
4848 ]);
4849 // Check that recur has status "In Progress" or "Completed" depending on whether number of installments has been reached
4850 $this->assertEquals(
4851 (string) CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $dataSet['repeat'][1]['expectedRecurStatus']),
4852 $contributionRecur['contribution_status_id']
4853 );
4854 // Check that next_sched_contribution_date has been set to 1 period after the contribution receive date (ie. 1 month)
4855 $this->assertEquals($dataSet['repeat'][1]['expectedNextSched'], $contributionRecur['next_sched_contribution_date'] ?? '');
4856 }
4857
4858 /**
4859 * Get dates for testing.
4860 *
4861 * @return array
4862 */
4863 public function getRepeatTransactionNextSchedData() {
4864 // Both these tests handle/test the case that next_sched_contribution_date is empty when Contribution.repeattransaction
4865 // is called for the first time. Historically setting it was inconsistent but on new updates it should always be set.
4866 /*
4867 * This tests that calling Contribution.repeattransaction with installments does the following:
4868 * - For the first call to repeattransaction the recur status is In Progress and next_sched_contribution_date is updated
4869 * to match next expected receive_date.
4870 * - Once the 3rd contribution is created contributionRecur status = completed and next_sched_contribution_date = ''.
4871 */
4872 $result['receive_date_includes_time_with_installments']['2012-01-01-1-month'] = [
4873 'recur' => [
4874 'start_date' => '2012-01-01',
4875 'frequency_interval' => 1,
4876 'installments' => '3',
4877 'frequency_unit' => 'month',
4878 ],
4879 'repeat' => [
4880 [
4881 'receive_date' => '2012-02-29 16:00:00',
4882 'expectedNextSched' => '2012-03-29 00:00:00',
4883 'expectedRecurStatus' => 'In Progress',
4884 ],
4885 [
4886 'receive_date' => '2012-03-29 16:00:00',
4887 'expectedNextSched' => '',
4888 'expectedRecurStatus' => 'Completed',
4889 ],
4890 ],
4891 ];
4892 /*
4893 * This tests that calling Contribution.repeattransaction with no installments does the following:
4894 * - For the each call to repeattransaction the recur status is In Progress and next_sched_contribution_date is updated
4895 * to match next expected receive_date.
4896 */
4897 $result['receive_date_includes_time_no_installments']['2012-01-01-1-month'] = [
4898 'recur' => [
4899 'start_date' => '2012-01-01',
4900 'frequency_interval' => 1,
4901 'frequency_unit' => 'month',
4902 ],
4903 'repeat' => [
4904 [
4905 'receive_date' => '2012-02-29 16:00:00',
4906 'expectedNextSched' => '2012-03-29 00:00:00',
4907 'expectedRecurStatus' => 'In Progress',
4908 ],
4909 [
4910 'receive_date' => '2012-03-29 16:00:00',
4911 'expectedNextSched' => '2012-04-29 00:00:00',
4912 'expectedRecurStatus' => 'In Progress',
4913 ],
4914 ],
4915 ];
4916 return $result;
4917 }
4918
39052b78
AH
4919 /**
4920 * Make sure that recording a payment doesn't alter the receive_date of a
4921 * pending contribution.
4922 */
4923 public function testPaymentDontChangeReceiveDate() {
4924 $params = [
4925 'contact_id' => $this->_individualId,
4926 'total_amount' => 100,
4927 'receive_date' => '2020-02-02',
4928 'contribution_status_id' => 'Pending',
4929 ];
4930 $contributionID = $this->contributionCreate($params);
4931 $paymentParams = [
4932 'contribution_id' => $contributionID,
4933 'total_amount' => 100,
4934 'trxn_date' => '2020-03-04',
4935 ];
4936 $this->callAPISuccess('payment', 'create', $paymentParams);
4937
4938 //check if contribution status is set to "Completed".
4939 $contribution = $this->callAPISuccess('Contribution', 'getSingle', [
4940 'id' => $contributionID,
4941 ]);
4942 $this->assertEquals('2020-02-02 00:00:00', $contribution['receive_date']);
4943 }
4944
d0b559aa
SP
4945 /**
4946 * Make sure that recording a payment with Different Payment Instrument update main contribution record payment
4947 * instrument too. If multiple Payment Recorded, last payment record payment (when No more due) instrument set to main
4948 * payment
4949 */
4950 public function testPaymentVerifyPaymentInstrumentChange() {
4951 // Create Pending contribution with pay later mode, with payment instrument Check
4952 $params = [
4953 'contact_id' => $this->_individualId,
4954 'total_amount' => 100,
4955 'receive_date' => '2020-02-02',
4956 'contribution_status_id' => 'Pending',
4957 'is_pay_later' => 1,
4958 'payment_instrument_id' => 'Check',
4959 ];
4960 $contributionID = $this->contributionCreate($params);
4961
d0b559aa
SP
4962 // Record the the Payment with instrument other than Check, e.g EFT
4963 $paymentParams = [
4964 'contribution_id' => $contributionID,
4965 'total_amount' => 50,
4966 'trxn_date' => '2020-03-04',
d0d6dd40 4967 'payment_instrument_id' => 'EFT',
d0b559aa
SP
4968 ];
4969 $this->callAPISuccess('payment', 'create', $paymentParams);
4970
4971 $contribution = $this->callAPISuccess('Contribution', 'getSingle', [
4972 'id' => $contributionID,
4973 ]);
4974 // payment status should be 'Partially paid'
4975 $this->assertEquals('Partially paid', $contribution['contribution_status']);
4976
4977 // Record the the Payment with instrument other than Check, e.g Cash (pay all remaining amount)
4978 $paymentParams = [
4979 'contribution_id' => $contributionID,
4980 'total_amount' => 50,
4981 'trxn_date' => '2020-03-04',
d0d6dd40 4982 'payment_instrument_id' => 'Cash',
d0b559aa
SP
4983 ];
4984 $this->callAPISuccess('payment', 'create', $paymentParams);
4985
4986 //check if contribution Payment Instrument (Payment Method) is is set to "Cash".
4987 $contribution = $this->callAPISuccess('Contribution', 'getSingle', [
4988 'id' => $contributionID,
4989 ]);
4990 $this->assertEquals('Cash', $contribution['payment_instrument']);
4991 $this->assertEquals('Completed', $contribution['contribution_status']);
4992 }
4993
bb35c5f3
JG
4994 /**
4995 * Test the "clean money" functionality.
4996 */
4997 public function testCleanMoney() {
4998 $params = [
4999 'contact_id' => $this->_individualId,
5000 'financial_type_id' => 1,
5001 'total_amount' => '$100',
5002 'fee_amount' => '$20',
5003 'net_amount' => '$80',
5004 'non_deductible_amount' => '$80',
5005 'sequential' => 1,
5006 ];
5007 $id = $this->callAPISuccess('Contribution', 'create', $params)['id'];
5008 // Reading the return values of the API isn't reliable here; get the data from the db.
5009 $contribution = $this->callAPISuccess('Contribution', 'getsingle', ['id' => $id]);
5010 $this->assertEquals('100.00', $contribution['total_amount']);
5011 $this->assertEquals('20.00', $contribution['fee_amount']);
5012 $this->assertEquals('80.00', $contribution['net_amount']);
5013 $this->assertEquals('80.00', $contribution['non_deductible_amount']);
5014 }
5015
6a488035 5016}