Merge pull request #15790 from civicrm/5.20
[civicrm-core.git] / tests / phpunit / api / v3 / PledgePaymentTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2020 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 * Test class for Pledge API - civicrm_pledge_*
30 *
31 * @package CiviCRM_APIv3
32 * @group headless
33 */
34 class api_v3_PledgePaymentTest extends CiviUnitTestCase {
35
36 protected $_individualId;
37 protected $_pledgeID;
38 protected $_contributionID;
39 protected $_financialTypeId = 1;
40 protected $_entity = 'PledgePayment';
41
42 /**
43 * Setup for tests.
44 *
45 * @throws \CRM_Core_Exception
46 */
47 public function setUp() {
48 parent::setUp();
49 $this->_individualId = $this->individualCreate();
50 $this->_pledgeID = $this->pledgeCreate(['contact_id' => $this->_individualId]);
51 $this->_contributionID = $this->contributionCreate(['contact_id' => $this->_individualId]);
52 }
53
54 /**
55 * Clean up after function.
56 * @throws \CRM_Core_Exception
57 */
58 public function tearDown() {
59 $tablesToTruncate = [
60 'civicrm_contribution',
61 'civicrm_contact',
62 'civicrm_pledge',
63 'civicrm_pledge_payment',
64 'civicrm_line_item',
65 ];
66
67 $this->quickCleanup($tablesToTruncate);
68 parent::tearDown();
69 }
70
71 public function testGetPledgePayment() {
72 $params = [];
73 $result = $this->callAPIAndDocument('pledge_payment', 'get', $params, __FUNCTION__, __FILE__);
74 $this->assertEquals(5, $result['count'], " in line " . __LINE__);
75 }
76
77 /**
78 * Test that passing in a single variable works.
79 */
80 public function testGetSinglePledgePayment() {
81 $createparams = [
82 'contact_id' => $this->_individualId,
83 'pledge_id' => $this->_pledgeID,
84 'contribution_id' => $this->_contributionID,
85 'status_id' => 1,
86 ];
87 $createResult = $this->callAPISuccess('pledge_payment', 'create', $createparams);
88 $params = [
89 'contribution_id' => $this->_contributionID,
90 ];
91 $result = $this->callAPISuccess('pledge_payment', 'get', $params);
92 $this->assertEquals(1, $result['count'], " in line " . __LINE__);
93 }
94
95 /**
96 * Test process_pledge job log.
97 */
98 public function testProcessPledgeJob() {
99 $pledgeStatuses = CRM_Core_OptionGroup::values('pledge_status',
100 FALSE, FALSE, FALSE, NULL, 'name'
101 );
102 //Make first payment.
103 $paymentParams = [
104 'contact_id' => $this->_individualId,
105 'pledge_id' => $this->_pledgeID,
106 'contribution_id' => $this->_contributionID,
107 'scheduled_date' => date('Ymd', strtotime("-1 days")),
108 'status_id' => array_search('Pending', $pledgeStatuses),
109 ];
110 $firstPayment = $this->callAPISuccess('pledge_payment', 'create', $paymentParams);
111 //Status should be 'Pending' after first incomplete payment.
112 $checkStatus = $this->callAPISuccess('pledge', 'getsingle', [
113 'id' => $this->_pledgeID,
114 'return' => 'pledge_status',
115 ]);
116 $this->assertEquals('Pending Label**', $checkStatus['pledge_status']);
117
118 //Execute process_pledge job log.
119 $result = $this->callAPISuccess('Job', 'process_pledge', []);
120 $this->assertEquals("Checking if status update is needed for Pledge Id: {$this->_pledgeID} (current status is Pending)\n\r- status updated to: Overdue\n\r1 records updated.", $result['values']);
121
122 //Status should be 'Overdue' after processing.
123 $statusAfterProcessing = $this->callAPISuccess('pledge', 'getsingle', [
124 'id' => $this->_pledgeID,
125 'return' => 'pledge_status',
126 ]);
127 $this->assertEquals('Overdue', $statusAfterProcessing['pledge_status']);
128 }
129
130 /**
131 * Test status of pledge on payments and cancellation.
132 */
133 public function testPledgeStatus() {
134 //Status should initially be Pending.
135 $checkStatus = $this->callAPISuccess('pledge', 'getsingle', [
136 'id' => $this->_pledgeID,
137 'return' => 'pledge_status',
138 ]);
139 $this->assertEquals('Pending Label**', $checkStatus['pledge_status']);
140
141 //Make first payment.
142 $paymentParams = [
143 'contact_id' => $this->_individualId,
144 'pledge_id' => $this->_pledgeID,
145 'contribution_id' => $this->_contributionID,
146 'status_id' => 1,
147 ];
148 $firstPayment = $this->callAPISuccess('pledge_payment', 'create', $paymentParams);
149
150 //Status should be 'In Progress' after first payment.
151 $checkStatus = $this->callAPISuccess('pledge', 'getsingle', [
152 'id' => $this->_pledgeID,
153 'return' => 'pledge_status',
154 ]);
155 $this->assertEquals('In Progress', $checkStatus['pledge_status']);
156
157 //Cancel the Pledge.
158 $paymentStatusTypes = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
159 $updateParams = [
160 'id' => $this->_pledgeID,
161 'status_id' => array_search('Cancelled', $paymentStatusTypes),
162 ];
163 $this->callAPISuccess('pledge', 'create', $updateParams);
164
165 //Status should be calculated as Cancelled.
166 $pledgeStatus = CRM_Pledge_BAO_PledgePayment::calculatePledgeStatus($this->_pledgeID);
167 $this->assertEquals('Cancelled', $paymentStatusTypes[$pledgeStatus]);
168
169 //Already completed payments should not be cancelled.
170 $checkPaymentStatus = $this->callAPISuccess('pledge_payment', 'getsingle', [
171 'id' => $firstPayment['id'],
172 'return' => 'status_id',
173 ]);
174 $this->assertEquals(array_search('Completed', $paymentStatusTypes), $checkPaymentStatus['status_id']);
175 }
176
177 /**
178 * Test that passing in a single variable works:: status_id
179 */
180 public function testGetSinglePledgePaymentByStatusID() {
181 $createparams = [
182 'contact_id' => $this->_individualId,
183 'pledge_id' => $this->_pledgeID,
184 'contribution_id' => $this->_contributionID,
185 'status_id' => 1,
186 ];
187 $createResult = $this->callAPISuccess('pledge_payment', 'create', $createparams);
188 $params = [
189 'status_id' => 1,
190 ];
191
192 $result = $this->callAPISuccess('pledge_payment', 'get', $params);
193 $this->assertEquals(1, $result['count'], " in line " . __LINE__);
194 }
195
196 /**
197 * Test that creating a payment will add the contribution ID.
198 */
199 public function testCreatePledgePayment() {
200 //check that 5 pledge payments exist at the start
201 $beforeAdd = $this->callAPISuccess('pledge_payment', 'get', []);
202 $this->assertEquals(5, $beforeAdd['count'], " in line " . __LINE__);
203
204 //test the pledge_payment_create function
205 $params = [
206 'contact_id' => $this->_individualId,
207 'pledge_id' => $this->_pledgeID,
208 'contribution_id' => $this->_contributionID,
209 'status_id' => 1,
210 'actual_amount' => 20,
211 ];
212 $result = $this->callAPIAndDocument('pledge_payment', 'create', $params, __FUNCTION__, __FILE__);
213
214 //check existing updated not new one created - 'create' means add contribution_id in this context
215 $afterAdd = $this->callAPISuccess('pledge_payment', 'get', []);
216 $this->assertEquals(5, $afterAdd['count'], " in line " . __LINE__);
217
218 //get the created payment & check it out
219 $getParams['id'] = $result['id'];
220 $getIndPayment = $this->callAPISuccess('pledge_payment', 'get', $getParams);
221 $this->assertEquals(1, $getIndPayment['count'], " in line " . __LINE__);
222 $this->assertEquals(20, $getIndPayment['values'][$result['id']]['actual_amount'], " in line " . __LINE__);
223
224 //create a second pledge payment - need a contribution first &can't use the CiviUnitTest case function as invoice is hard-coded
225 $contributionParams = [
226 'total_amount' => 20,
227 'contact_id' => $this->_individualId,
228 'financial_type_id' => $this->_financialTypeId,
229 ];
230 $contribution = $this->callAPISuccess('contribution', 'create', $contributionParams);
231 $params['contribution_id'] = $contribution['id'];
232
233 $resultCont2 = $this->callAPISuccess('pledge_payment', 'create', $params);
234 //make sure original is untouched & has not been updated
235 $this->assertGreaterThan($result['id'], $resultCont2['id'], " in line " . __LINE__);
236 $getIndPaymentAgain = $this->callAPISuccess('pledge_payment', 'get', $getParams);
237 $this->assertEquals(1, $getIndPaymentAgain['count'], " in line " . __LINE__);
238 $this->assertEquals($this->_contributionID, $getIndPaymentAgain['values'][$result['id']]['contribution_id'], " in line " . __LINE__);
239 }
240
241 /**
242 * Test checks behaviour when more payments are created than should be possible.
243 */
244 public function testCreatePledgePaymentAllCreated() {
245 $params = [
246 'pledge_id' => $this->_pledgeID,
247 'status_id' => 1,
248 ];
249 // create one more pledge than there are spaces for
250 $i = 0;
251 while ($i <= 5) {
252 $contributionParams = [
253 'total_amount' => 20,
254 'contact_id' => $this->_individualId,
255 'financial_type_id' => $this->_financialTypeId,
256 ];
257 $contribution = $this->callAPISuccess('contribution', 'create', $contributionParams);
258
259 $params['contribution_id'] = $contribution['id'];
260
261 $resultCont2 = civicrm_api('pledge_payment', 'create', $params + ['version' => $this->_apiversion]);
262 $i++;
263 }
264 // check that only 5 exist & we got an error setting the 6th
265 $result = $this->callAPISuccess('PledgePayment', 'Get', [
266 'pledge_id' => $this->_pledgeID,
267 ]);
268 // the last one above should result in an error
269 $this->assertEquals("There are no unmatched payment on this pledge. Pass in the pledge_payment id to specify one or 'option.create_new' to create one", $resultCont2['error_message']);
270 $this->assertEquals(5, $result['count']);
271
272 $params['option.create_new'] = 1;
273 $params['scheduled_amount'] = 20;
274 $params['scheduled_date'] = '20131212';
275 $resultcreatenew = $this->callAPISuccess('pledge_payment', 'create', $params);
276 $result = $this->callAPISuccess('PledgePayment', 'Get', [
277 'pledge_id' => $this->_pledgeID,
278 ]);
279
280 $this->assertEquals(6, $result['count']);
281 }
282
283 /**
284 * Test that creating a payment adds the contribution ID where only one pledge payment is in schedule.
285 */
286 public function testCreatePledgePaymentWhereOnlyOnePayment() {
287 $pledgeParams = [
288 'contact_id' => $this->_individualId,
289 'pledge_create_date' => date('Ymd'),
290 'start_date' => date('Ymd'),
291 'scheduled_date' => 'first day 2015',
292 'pledge_amount' => 100.00,
293 'pledge_status_id' => '2',
294 'pledge_financial_type_id' => '1',
295 'pledge_original_installment_amount' => 20,
296 'frequency_interval' => 5,
297 'frequency_unit' => 'year',
298 'frequency_day' => 15,
299 'installments' => 1,
300 'sequential' => 1,
301 ];
302
303 $contributionID = $this->contributionCreate([
304 'contact_id' => $this->_individualId,
305 'financial_type_id' => $this->_financialTypeId,
306 'invoice_id' => 45,
307 'trxn_id' => 45,
308 ]);
309 $pledge = $this->callAPISuccess('Pledge', 'Create', $pledgeParams);
310
311 //test the pledge_payment_create function
312 $params = [
313 'contact_id' => $this->_individualId,
314 'pledge_id' => $pledge['id'],
315 'contribution_id' => $contributionID,
316 'status_id' => 1,
317 'actual_amount' => 20,
318 ];
319 $result = $this->callAPISuccess('pledge_payment', 'create', $params);
320
321 //check existing updated not new one created - 'create' means add contribution_id in this context
322 $afterAdd = $this->callAPISuccess('pledge_payment', 'get', [
323 'contribution_id' => $contributionID,
324 ]);
325 $this->assertEquals(1, $afterAdd['count'], " in line " . __LINE__);
326 }
327
328 public function testUpdatePledgePayment() {
329 $params = [
330 'pledge_id' => $this->_pledgeID,
331 'contribution_id' => $this->_contributionID,
332 'status_id' => 2,
333 'actual_amount' => 20,
334 ];
335 $result = $this->callAPISuccess('pledge_payment', 'create', $params);
336 $updateparams = [
337 'id' => $result['id'],
338 'status_id' => 1,
339 ];
340
341 $result = $this->callAPIAndDocument('pledge_payment', 'update', $updateparams, __FUNCTION__, __FILE__);
342 $this->getAndCheck(array_merge($params, $updateparams), $result['id'], $this->_entity);
343 }
344
345 public function testDeletePledgePayment() {
346 $params = [
347 'contact_id' => $this->_individualId,
348 'pledge_id' => $this->_pledgeID,
349 'contribution_id' => $this->_contributionID,
350 'status_id' => 1,
351 'sequential' => 1,
352 'actual_amount' => 20,
353 ];
354 $pledgePayment = $this->callAPISuccess('pledge_payment', 'create', $params);
355
356 $deleteParams = [
357 'id' => $pledgePayment['id'],
358 ];
359 $result = $this->callAPIAndDocument('pledge_payment', 'delete', $deleteParams, __FUNCTION__, __FILE__);
360 }
361
362 public function testGetFields() {
363 $result = $this->callAPISuccess('PledgePayment', 'GetFields', []);
364 $this->assertType('array', $result);
365 }
366
367 }