Merge pull request #17742 from MiyaNoctem/dev-core-1854-fix-resetting-overridden...
[civicrm-core.git] / CRM / Contribute / Page / Tab.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17 class CRM_Contribute_Page_Tab extends CRM_Core_Page {
18
19 /**
20 * The permission we have on this contact
21 *
22 * @var string
23 */
24 public $_permission = NULL;
25
26 /**
27 * The contact ID for the contributions we are acting on
28 * @var int
29 */
30 public $_contactId = NULL;
31
32 /**
33 * The recurring contribution ID (if any)
34 * @var int
35 */
36 public $_crid = NULL;
37
38 /**
39 * This method returns the links that are given for recur search row.
40 * currently the links added for each row are:
41 * - View
42 * - Edit
43 * - Cancel
44 *
45 * @param bool $recurID
46 * @param string $context
47 *
48 * @return array
49 */
50 public static function recurLinks($recurID = FALSE, $context = 'contribution') {
51 $links = [
52 CRM_Core_Action::VIEW => [
53 'name' => ts('View'),
54 'title' => ts('View Recurring Payment'),
55 'url' => 'civicrm/contact/view/contributionrecur',
56 'qs' => "reset=1&id=%%crid%%&cid=%%cid%%&context={$context}",
57 ],
58 CRM_Core_Action::UPDATE => [
59 'name' => ts('Edit'),
60 'title' => ts('Edit Recurring Payment'),
61 'url' => 'civicrm/contribute/updaterecur',
62 'qs' => "reset=1&action=update&crid=%%crid%%&cid=%%cid%%&context={$context}",
63 ],
64 CRM_Core_Action::DISABLE => [
65 'name' => ts('Cancel'),
66 'title' => ts('Cancel'),
67 'ref' => 'crm-enable-disable',
68 ],
69 ];
70
71 if ($recurID) {
72 $paymentProcessorObj = CRM_Contribute_BAO_ContributionRecur::getPaymentProcessorObject($recurID);
73 if ($paymentProcessorObj) {
74 if ($paymentProcessorObj->supports('cancelRecurring')) {
75 unset($links[CRM_Core_Action::DISABLE]['extra'], $links[CRM_Core_Action::DISABLE]['ref']);
76 $links[CRM_Core_Action::DISABLE]['url'] = "civicrm/contribute/unsubscribe";
77 $links[CRM_Core_Action::DISABLE]['qs'] = "reset=1&crid=%%crid%%&cid=%%cid%%&context={$context}";
78 }
79
80 if ($paymentProcessorObj->supports('UpdateSubscriptionBillingInfo')) {
81 $links[CRM_Core_Action::RENEW] = [
82 'name' => ts('Change Billing Details'),
83 'title' => ts('Change Billing Details'),
84 'url' => 'civicrm/contribute/updatebilling',
85 'qs' => "reset=1&crid=%%crid%%&cid=%%cid%%&context={$context}",
86 ];
87 }
88
89 if (
90 (!CRM_Core_Permission::check('edit contributions') && $context === 'contribution') ||
91 (!$paymentProcessorObj->supports('ChangeSubscriptionAmount')
92 && !$paymentProcessorObj->supports('EditRecurringContribution')
93 )) {
94 unset($links[CRM_Core_Action::UPDATE]);
95 }
96 }
97 else {
98 unset($links[CRM_Core_Action::DISABLE]);
99 unset($links[CRM_Core_Action::UPDATE]);
100 }
101 }
102
103 return $links;
104 }
105
106 /**
107 * called when action is browse.
108 *
109 */
110 public function browse() {
111 // add annual contribution
112 $annual = [];
113 list($annual['count'],
114 $annual['amount'],
115 $annual['avg']
116 ) = CRM_Contribute_BAO_Contribution::annual($this->_contactId);
117 $this->assign('annual', $annual);
118
119 $controller = new CRM_Core_Controller_Simple(
120 'CRM_Contribute_Form_Search',
121 ts('Contributions'),
122 $this->_action,
123 FALSE, FALSE, TRUE
124 );
125 $controller->setEmbedded(TRUE);
126 $controller->reset();
127 $controller->set('cid', $this->_contactId);
128 $controller->set('crid', $this->_crid);
129 $controller->set('context', 'contribution');
130 $controller->set('limit', 50);
131 $controller->process();
132 $controller->run();
133
134 // add recurring block
135 $this->addRecurringContributionsBlock();
136
137 // enable/disable soft credit records for test contribution
138 $isTest = 0;
139 if (CRM_Utils_Request::retrieve('isTest', 'Positive', $this)) {
140 $isTest = 1;
141 }
142 $this->assign('isTest', $isTest);
143
144 $softCreditList = CRM_Contribute_BAO_ContributionSoft::getSoftContributionList($this->_contactId, NULL, $isTest);
145
146 if (!empty($softCreditList)) {
147 $softCreditTotals = [];
148
149 list($softCreditTotals['count'],
150 $softCreditTotals['cancel']['count'],
151 $softCreditTotals['amount'],
152 $softCreditTotals['avg'],
153 // to get cancel amount
154 $softCreditTotals['cancel']['amount']
155 ) = CRM_Contribute_BAO_ContributionSoft::getSoftContributionTotals($this->_contactId, $isTest);
156
157 $this->assign('softCredit', TRUE);
158 $this->assign('softCreditRows', $softCreditList);
159 $this->assign('softCreditTotals', $softCreditTotals);
160 }
161
162 if ($this->_contactId) {
163 $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId);
164 $this->assign('displayName', $displayName);
165 $tabCount = CRM_Contact_BAO_Contact::getCountComponent('contribution', $this->_contactId);
166 $this->assign('tabCount', $tabCount);
167 $this->ajaxResponse['tabCount'] = $tabCount;
168 }
169 }
170
171 /**
172 * Get all the recurring contribution information and assign to the template
173 */
174 private function addRecurringContributionsBlock() {
175 list($activeContributions, $activeContributionsCount) = $this->getActiveRecurringContributions();
176 list($inactiveRecurringContributions, $inactiveContributionsCount) = $this->getInactiveRecurringContributions();
177
178 if (!empty($activeContributions) || !empty($inactiveRecurringContributions)) {
179 // assign vars to templates
180 $this->assign('action', $this->_action);
181 $this->assign('activeRecurRows', $activeContributions);
182 $this->assign('contributionRecurCount', $activeContributionsCount + $inactiveContributionsCount);
183 $this->assign('inactiveRecurRows', $inactiveRecurringContributions);
184 $this->assign('recur', TRUE);
185 }
186 }
187
188 /**
189 * Loads active recurring contributions for the current contact and formats
190 * them to be used on the form.
191 *
192 * @return array
193 */
194 private function getActiveRecurringContributions() {
195 try {
196 $contributionRecurResult = civicrm_api3('ContributionRecur', 'get', [
197 'contact_id' => $this->_contactId,
198 'contribution_status_id' => ['NOT IN' => CRM_Contribute_BAO_ContributionRecur::getInactiveStatuses()],
199 'options' => ['limit' => 0, 'sort' => 'is_test, start_date DESC'],
200 ]);
201 $recurContributions = $contributionRecurResult['values'] ?? NULL;
202 }
203 catch (Exception $e) {
204 $recurContributions = [];
205 }
206
207 return $this->buildRecurringContributionsArray($recurContributions);
208 }
209
210 /**
211 * Loads inactive recurring contributions for the current contact and formats
212 * them to be used on the form.
213 *
214 * @return array
215 */
216 private function getInactiveRecurringContributions() {
217 try {
218 $contributionRecurResult = civicrm_api3('ContributionRecur', 'get', [
219 'contact_id' => $this->_contactId,
220 'contribution_status_id' => ['IN' => CRM_Contribute_BAO_ContributionRecur::getInactiveStatuses()],
221 'options' => ['limit' => 0, 'sort' => 'is_test, start_date DESC'],
222 ]);
223 $recurContributions = $contributionRecurResult['values'] ?? NULL;
224 }
225 catch (Exception $e) {
226 $recurContributions = NULL;
227 }
228
229 return $this->buildRecurringContributionsArray($recurContributions);
230 }
231
232 /**
233 * @param $recurContributions
234 *
235 * @return array
236 */
237 private function buildRecurringContributionsArray($recurContributions) {
238 $liveRecurringContributionCount = 0;
239 foreach ($recurContributions as $recurId => $recurDetail) {
240 // Is recurring contribution active?
241 $recurContributions[$recurId]['is_active'] = !in_array(CRM_Contribute_PseudoConstant::contributionStatus($recurDetail['contribution_status_id'], 'name'), CRM_Contribute_BAO_ContributionRecur::getInactiveStatuses());
242 if ($recurContributions[$recurId]['is_active']) {
243 $actionMask = array_sum(array_keys(self::recurLinks($recurId)));
244 }
245 else {
246 $actionMask = CRM_Core_Action::mask([CRM_Core_Permission::VIEW]);
247 }
248
249 if (empty($recurDetail['is_test'])) {
250 $liveRecurringContributionCount++;
251 }
252
253 // Get the name of the payment processor
254 if (!empty($recurDetail['payment_processor_id'])) {
255 $recurContributions[$recurId]['payment_processor'] = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessorName($recurDetail['payment_processor_id']);
256 }
257 // Get the label for the contribution status
258 if (!empty($recurDetail['contribution_status_id'])) {
259 $recurContributions[$recurId]['contribution_status'] = CRM_Core_PseudoConstant::getLabel('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $recurDetail['contribution_status_id']);
260 }
261
262 $recurContributions[$recurId]['action'] = CRM_Core_Action::formLink(self::recurLinks($recurId), $actionMask,
263 [
264 'cid' => $this->_contactId,
265 'crid' => $recurId,
266 'cxt' => 'contribution',
267 ],
268 ts('more'),
269 FALSE,
270 'contribution.selector.recurring',
271 'Contribution',
272 $recurId
273 );
274 }
275
276 return [$recurContributions, $liveRecurringContributionCount];
277 }
278
279 /**
280 * called when action is view.
281 *
282 * @return mixed
283 */
284 public function view() {
285 $controller = new CRM_Core_Controller_Simple(
286 'CRM_Contribute_Form_ContributionView',
287 ts('View Contribution'),
288 $this->_action
289 );
290 $controller->setEmbedded(TRUE);
291 $controller->set('id', $this->_id);
292 $controller->set('cid', $this->_contactId);
293
294 return $controller->run();
295 }
296
297 /**
298 * called when action is update or new.
299 *
300 * @return mixed
301 * @throws \CRM_Core_Exception
302 * @throws \Exception
303 */
304 public function edit() {
305 // set https for offline cc transaction
306 $mode = CRM_Utils_Request::retrieve('mode', 'Alphanumeric', $this);
307 if ($mode == 'test' || $mode == 'live') {
308 CRM_Utils_System::redirectToSSL();
309 }
310
311 $controller = new CRM_Core_Controller_Simple(
312 'CRM_Contribute_Form_Contribution',
313 'Create Contribution',
314 $this->_action
315 );
316 $controller->setEmbedded(TRUE);
317 $controller->set('id', $this->_id);
318 $controller->set('cid', $this->_contactId);
319
320 return $controller->run();
321 }
322
323 /**
324 * @throws \CRM_Core_Exception
325 * @throws \CiviCRM_API3_Exception
326 */
327 public function preProcess() {
328 $context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this);
329 $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'browse');
330 $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
331
332 if ($context == 'standalone') {
333 $this->_action = CRM_Core_Action::ADD;
334 }
335 else {
336 $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, empty($this->_id));
337 if (empty($this->_contactId)) {
338 $this->_contactId = civicrm_api3('contribution', 'getvalue', [
339 'id' => $this->_id,
340 'return' => 'contact_id',
341 ]);
342 }
343 $this->assign('contactId', $this->_contactId);
344
345 // check logged in url permission
346 CRM_Contact_Page_View::checkUserPermission($this);
347 }
348 $this->assign('action', $this->_action);
349
350 if ($this->_permission == CRM_Core_Permission::EDIT && !CRM_Core_Permission::check('edit contributions')) {
351 // demote to view since user does not have edit contrib rights
352 $this->_permission = CRM_Core_Permission::VIEW;
353 $this->assign('permission', 'view');
354 }
355 }
356
357 /**
358 * the main function that is called when the page
359 * loads, it decides the which action has to be taken for the page.
360 *
361 * @throws \CRM_Core_Exception
362 * @throws \CiviCRM_API3_Exception
363 */
364 public function run() {
365 $this->preProcess();
366
367 // check if we can process credit card contribs
368 $this->assign('newCredit', CRM_Core_Config::isEnabledBackOfficeCreditCardPayments());
369
370 $this->setContext();
371
372 if ($this->_action & CRM_Core_Action::VIEW) {
373 $this->view();
374 }
375 elseif ($this->_action & (CRM_Core_Action::UPDATE | CRM_Core_Action::ADD | CRM_Core_Action::DELETE)) {
376 $this->edit();
377 }
378 else {
379 $this->browse();
380 }
381
382 parent::run();
383 }
384
385 /**
386 * @throws \CRM_Core_Exception
387 */
388 public function setContext() {
389 $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this);
390 $context = CRM_Utils_Request::retrieve('context', 'Alphanumeric',
391 $this, FALSE, 'search'
392 );
393 $compContext = CRM_Utils_Request::retrieve('compContext', 'String', $this);
394
395 $searchContext = CRM_Utils_Request::retrieve('searchContext', 'String', $this);
396
397 //swap the context.
398 if ($context == 'search' && $compContext) {
399 $context = $compContext;
400 }
401 else {
402 $compContext = NULL;
403 }
404
405 // make sure we dont get tricked with a bad key
406 // so check format
407 if (!CRM_Core_Key::valid($qfKey)) {
408 $qfKey = NULL;
409 }
410
411 switch ($context) {
412 case 'user':
413 $url = CRM_Utils_System::url('civicrm/user', 'reset=1');
414 break;
415
416 case 'dashboard':
417 $url = CRM_Utils_System::url('civicrm/contribute',
418 'reset=1'
419 );
420 break;
421
422 case 'pledgeDashboard':
423 $url = CRM_Utils_System::url('civicrm/pledge',
424 'reset=1'
425 );
426 break;
427
428 case 'contribution':
429 $url = CRM_Utils_System::url('civicrm/contact/view',
430 "reset=1&force=1&cid={$this->_contactId}&selectedChild=contribute"
431 );
432 break;
433
434 case 'search':
435 case 'advanced':
436 $extraParams = "force=1";
437 if ($qfKey) {
438 $extraParams .= "&qfKey=$qfKey";
439 }
440
441 $this->assign('searchKey', $qfKey);
442 if ($context == 'advanced') {
443 $url = CRM_Utils_System::url('civicrm/contact/search/advanced', $extraParams);
444 }
445 elseif ($searchContext) {
446 $url = CRM_Utils_System::url("civicrm/$searchContext/search", $extraParams);
447 }
448 else {
449 $url = CRM_Utils_System::url('civicrm/contribute/search', $extraParams);
450 }
451 break;
452
453 case 'home':
454 $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1');
455 break;
456
457 case 'activity':
458 $url = CRM_Utils_System::url('civicrm/contact/view',
459 "reset=1&force=1&cid={$this->_contactId}&selectedChild=activity"
460 );
461 break;
462
463 case 'member':
464 case 'membership':
465 $componentId = CRM_Utils_Request::retrieve('compId', 'Positive', $this);
466 $componentAction = CRM_Utils_Request::retrieve('compAction', 'Integer', $this);
467
468 $context = 'membership';
469 $searchKey = NULL;
470 if ($compContext) {
471 $context = 'search';
472 if ($qfKey) {
473 $searchKey = "&key=$qfKey";
474 }
475 $compContext = "&compContext={$compContext}";
476 }
477 if ($componentAction & CRM_Core_Action::VIEW) {
478 $action = 'view';
479 }
480 else {
481 $action = 'update';
482 }
483 $url = CRM_Utils_System::url('civicrm/contact/view/membership',
484 "reset=1&action={$action}&id={$componentId}&cid={$this->_contactId}&context={$context}&selectedChild=member{$searchKey}{$compContext}"
485 );
486 break;
487
488 case 'participant':
489 $componentId = CRM_Utils_Request::retrieve('compId', 'Positive', $this);
490 $componentAction = CRM_Utils_Request::retrieve('compAction', 'Integer', $this);
491
492 $context = 'participant';
493 $searchKey = NULL;
494 if ($compContext) {
495 $context = 'search';
496 if ($qfKey) {
497 $searchKey = "&key=$qfKey";
498 }
499 $compContext = "&compContext={$compContext}";
500 }
501 if ($componentAction == CRM_Core_Action::VIEW) {
502 $action = 'view';
503 }
504 else {
505 $action = 'update';
506 }
507 $url = CRM_Utils_System::url('civicrm/contact/view/participant',
508 "reset=1&action={$action}&id={$componentId}&cid={$this->_contactId}&context={$context}&selectedChild=event{$searchKey}{$compContext}"
509 );
510 break;
511
512 case 'pledge':
513 $url = CRM_Utils_System::url('civicrm/contact/view',
514 "reset=1&force=1&cid={$this->_contactId}&selectedChild=pledge"
515 );
516 break;
517
518 case 'standalone':
519 $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1');
520 break;
521
522 case 'fulltext':
523 $keyName = '&qfKey';
524 $urlParams = 'force=1';
525 $urlString = 'civicrm/contact/search/custom';
526 if ($this->_action == CRM_Core_Action::UPDATE) {
527 if ($this->_contactId) {
528 $urlParams .= '&cid=' . $this->_contactId;
529 }
530 $keyName = '&key';
531 $urlParams .= '&context=fulltext&action=view';
532 $urlString = 'civicrm/contact/view/contribution';
533 }
534 if ($qfKey) {
535 $urlParams .= "$keyName=$qfKey";
536 }
537 $this->assign('searchKey', $qfKey);
538 $url = CRM_Utils_System::url($urlString, $urlParams);
539 break;
540
541 default:
542 $cid = NULL;
543 if ($this->_contactId) {
544 $cid = '&cid=' . $this->_contactId;
545 }
546 $url = CRM_Utils_System::url('civicrm/contribute/search',
547 'reset=1&force=1' . $cid
548 );
549 break;
550 }
551
552 $session = CRM_Core_Session::singleton();
553 $session->pushUserContext($url);
554 }
555
556 }