Merge pull request #19946 from MikeyMJCO/patch-9
[civicrm-core.git] / CRM / Contribute / BAO / ContributionPage.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
18 use Civi\Api4\Contribution;
19
20 /**
21 * This class contains Contribution Page related functions.
22 */
23 class CRM_Contribute_BAO_ContributionPage extends CRM_Contribute_DAO_ContributionPage {
24
25 /**
26 * Creates a contribution page.
27 *
28 * @param array $params
29 *
30 * @return CRM_Contribute_DAO_ContributionPage
31 */
32 public static function create($params) {
33 $financialTypeId = NULL;
34 if (!empty($params['id']) && !CRM_Price_BAO_PriceSet::getFor('civicrm_contribution_page', $params['id'], NULL, 1)) {
35 $financialTypeId = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage', $params['id'], 'financial_type_id');
36 }
37
38 if (isset($params['payment_processor']) && is_array($params['payment_processor'])) {
39 $params['payment_processor'] = implode(CRM_Core_DAO::VALUE_SEPARATOR, $params['payment_processor']);
40 }
41 $hook = empty($params['id']) ? 'create' : 'edit';
42 CRM_Utils_Hook::pre($hook, 'ContributionPage', CRM_Utils_Array::value('id', $params), $params);
43 $dao = new CRM_Contribute_DAO_ContributionPage();
44 $dao->copyValues($params);
45 $dao->save();
46 if ($financialTypeId && !empty($params['financial_type_id']) && $financialTypeId != $params['financial_type_id']) {
47 CRM_Price_BAO_PriceFieldValue::updateFinancialType($params['id'], 'civicrm_contribution_page', $params['financial_type_id']);
48 }
49 CRM_Utils_Hook::post($hook, 'ContributionPage', $dao->id, $dao);
50 CRM_Core_PseudoConstant::flush();
51 return $dao;
52 }
53
54 /**
55 * Update the is_active flag in the db.
56 *
57 * @deprecated - this bypasses hooks.
58 *
59 * @param int $id
60 * Id of the database record.
61 * @param bool $is_active
62 * Value we want to set the is_active field.
63 *
64 * @return bool
65 * true if we found and updated the object, else false
66 */
67 public static function setIsActive($id, $is_active) {
68 return CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_ContributionPage', $id, 'is_active', $is_active);
69 }
70
71 /**
72 * Load values for a contribution page.
73 *
74 * @param int $id
75 * @param array $values
76 */
77 public static function setValues($id, &$values) {
78 $modules = ['CiviContribute', 'soft_credit', 'on_behalf'];
79 $values['custom_pre_id'] = $values['custom_post_id'] = NULL;
80
81 $params = ['id' => $id];
82 CRM_Core_DAO::commonRetrieve('CRM_Contribute_DAO_ContributionPage', $params, $values);
83
84 // get the profile ids
85 $ufJoinParams = [
86 'entity_table' => 'civicrm_contribution_page',
87 'entity_id' => $id,
88 ];
89
90 // retrieve profile id as also unserialize module_data corresponding to each $module
91 foreach ($modules as $module) {
92 $ufJoinParams['module'] = $module;
93 $ufJoin = new CRM_Core_DAO_UFJoin();
94 $ufJoin->copyValues($ufJoinParams);
95 if ($module == 'CiviContribute') {
96 $ufJoin->orderBy('weight asc');
97 $ufJoin->find();
98 while ($ufJoin->fetch()) {
99 if ($ufJoin->weight == 1) {
100 $values['custom_pre_id'] = $ufJoin->uf_group_id;
101 }
102 else {
103 $values['custom_post_id'] = $ufJoin->uf_group_id;
104 }
105 }
106 }
107 else {
108 $ufJoin->find(TRUE);
109 if (!$ufJoin->is_active) {
110 continue;
111 }
112 $params = CRM_Contribute_BAO_ContributionPage::formatModuleData($ufJoin->module_data, TRUE, $module);
113 $values = array_merge($params, $values);
114 if ($module == 'soft_credit') {
115 $values['honoree_profile_id'] = $ufJoin->uf_group_id;
116 $values['honor_block_is_active'] = $ufJoin->is_active;
117 }
118 else {
119 $values['onbehalf_profile_id'] = $ufJoin->uf_group_id;
120 }
121 }
122 }
123 }
124
125 /**
126 * Send the emails.
127 *
128 * @param int $contactID
129 * Contact id.
130 * @param array $values
131 * Associated array of fields.
132 * @param bool $isTest
133 * If in test mode.
134 * @param bool $returnMessageText
135 * Return the message text instead of sending the mail.
136 *
137 * @param array $fieldTypes
138 *
139 * @throws \CRM_Core_Exception
140 */
141 public static function sendMail($contactID, $values, $isTest = FALSE, $returnMessageText = FALSE, $fieldTypes = NULL) {
142 $gIds = [];
143 $params = ['custom_pre_id' => [], 'custom_post_id' => []];
144 $email = NULL;
145
146 // We are trying to fight the good fight against leaky variables (CRM-17519) so let's get really explicit
147 // about ensuring the variables we want for the template are defined.
148 // @todo add to this until all tpl params are explicit in this function and not waltzing around the codebase.
149 // Next stage is to remove this & ensure there are no e-notices - ie. all are set before they hit this fn.
150 $valuesRequiredForTemplate = [
151 'customPre',
152 'customPost',
153 'customPre_grouptitle',
154 'customPost_grouptitle',
155 'useForMember',
156 'membership_assign',
157 'amount',
158 'receipt_date',
159 'is_pay_later',
160 ];
161
162 foreach ($valuesRequiredForTemplate as $valueRequiredForTemplate) {
163 if (!isset($values[$valueRequiredForTemplate])) {
164 $values[$valueRequiredForTemplate] = NULL;
165 }
166 }
167
168 if (isset($values['custom_pre_id'])) {
169 $preProfileType = CRM_Core_BAO_UFField::getProfileType($values['custom_pre_id']);
170 if ($preProfileType == 'Membership' && !empty($values['membership_id'])) {
171 $params['custom_pre_id'] = [
172 [
173 'member_id',
174 '=',
175 $values['membership_id'],
176 0,
177 0,
178 ],
179 ];
180 }
181 elseif ($preProfileType == 'Contribution' && !empty($values['contribution_id'])) {
182 $params['custom_pre_id'] = [
183 [
184 'contribution_id',
185 '=',
186 $values['contribution_id'],
187 0,
188 0,
189 ],
190 ];
191 }
192
193 $gIds['custom_pre_id'] = $values['custom_pre_id'];
194 }
195
196 if (isset($values['custom_post_id'])) {
197 $postProfileType = CRM_Core_BAO_UFField::getProfileType($values['custom_post_id']);
198 if ($postProfileType == 'Membership' && !empty($values['membership_id'])) {
199 $params['custom_post_id'] = [
200 [
201 'member_id',
202 '=',
203 $values['membership_id'],
204 0,
205 0,
206 ],
207 ];
208 }
209 elseif ($postProfileType == 'Contribution' && !empty($values['contribution_id'])) {
210 $params['custom_post_id'] = [
211 [
212 'contribution_id',
213 '=',
214 $values['contribution_id'],
215 0,
216 0,
217 ],
218 ];
219 }
220
221 $gIds['custom_post_id'] = $values['custom_post_id'];
222 }
223
224 if (!empty($values['is_for_organization'])) {
225 if (!empty($values['membership_id'])) {
226 $params['onbehalf_profile'] = [
227 [
228 'member_id',
229 '=',
230 $values['membership_id'],
231 0,
232 0,
233 ],
234 ];
235 }
236 elseif (!empty($values['contribution_id'])) {
237 $params['onbehalf_profile'] = [
238 [
239 'contribution_id',
240 '=',
241 $values['contribution_id'],
242 0,
243 0,
244 ],
245 ];
246 }
247 }
248
249 //check whether it is a test drive
250 if ($isTest && !empty($params['custom_pre_id'])) {
251 $params['custom_pre_id'][] = [
252 'contribution_test',
253 '=',
254 1,
255 0,
256 0,
257 ];
258 }
259
260 if ($isTest && !empty($params['custom_post_id'])) {
261 $params['custom_post_id'][] = [
262 'contribution_test',
263 '=',
264 1,
265 0,
266 0,
267 ];
268 }
269
270 if (!$returnMessageText && !empty($gIds)) {
271 //send notification email if field values are set (CRM-1941)
272 foreach ($gIds as $key => $gId) {
273 if ($gId) {
274 $email = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gId, 'notify');
275 if ($email) {
276 $val = CRM_Core_BAO_UFGroup::checkFieldsEmptyValues($gId, $contactID, CRM_Utils_Array::value($key, $params), TRUE);
277 CRM_Core_BAO_UFGroup::commonSendMail($contactID, $val);
278 }
279 }
280 }
281 }
282
283 if (!empty($values['is_email_receipt']) || !empty($values['onbehalf_dupe_alert']) ||
284 $returnMessageText
285 ) {
286 $template = CRM_Core_Smarty::singleton();
287
288 if (!array_key_exists('related_contact', $values)) {
289 list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID, FALSE, CRM_Core_BAO_LocationType::getBilling());
290 }
291 // get primary location email if no email exist( for billing location).
292 if (!$email) {
293 list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID);
294 }
295 if (empty($displayName)) {
296 list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID);
297 }
298
299 //for display profile need to get individual contact id,
300 //hence get it from related_contact if on behalf of org true CRM-3767
301 //CRM-5001 Contribution/Membership:: On Behalf of Organization,
302 //If profile GROUP contain the Individual type then consider the
303 //profile is of Individual ( including the custom data of membership/contribution )
304 //IF Individual type not present in profile then it is consider as Organization data.
305 $userID = $contactID;
306 if ($preID = CRM_Utils_Array::value('custom_pre_id', $values)) {
307 if (!empty($values['related_contact'])) {
308 $preProfileTypes = CRM_Core_BAO_UFGroup::profileGroups($preID);
309 if (in_array('Individual', $preProfileTypes) || in_array('Contact', $preProfileTypes)) {
310 //Take Individual contact ID
311 $userID = $values['related_contact'] ?? NULL;
312 }
313 }
314 [$values['customPre_grouptitle'], $values['customPre']] = self::getProfileNameAndFields($preID, $userID, $params['custom_pre_id']);
315 }
316 $userID = $contactID;
317 if ($postID = CRM_Utils_Array::value('custom_post_id', $values)) {
318 if (!empty($values['related_contact'])) {
319 $postProfileTypes = CRM_Core_BAO_UFGroup::profileGroups($postID);
320 if (in_array('Individual', $postProfileTypes) || in_array('Contact', $postProfileTypes)) {
321 //Take Individual contact ID
322 $userID = $values['related_contact'] ?? NULL;
323 }
324 }
325 list($values['customPost_grouptitle'], $values['customPost']) = self::getProfileNameAndFields($postID, $userID, $params['custom_post_id']);
326 }
327 if (isset($values['honor'])) {
328 $honorValues = $values['honor'];
329 $template->_values = ['honoree_profile_id' => $values['honoree_profile_id']];
330 CRM_Contribute_BAO_ContributionSoft::formatHonoreeProfileFields(
331 $template,
332 $honorValues['honor_profile_values'],
333 $honorValues['honor_id']
334 );
335 }
336
337 $title = $values['title'] ?? CRM_Contribute_BAO_Contribution_Utils::getContributionPageTitle($values['contribution_page_id']);
338
339 // Set email variables explicitly to avoid leaky smarty variables.
340 // All of these will be assigned to the template, replacing any that might be assigned elsewhere.
341 $tplParams = [
342 'email' => $email,
343 'receiptFromEmail' => $values['receipt_from_email'] ?? NULL,
344 'contactID' => $contactID,
345 'displayName' => $displayName,
346 'contributionID' => $values['contribution_id'] ?? NULL,
347 'contributionOtherID' => $values['contribution_other_id'] ?? NULL,
348 // CRM-5095
349 'lineItem' => $values['lineItem'] ?? NULL,
350 // CRM-5095
351 'priceSetID' => $values['priceSetID'] ?? NULL,
352 'title' => $title,
353 'isShare' => $values['is_share'] ?? NULL,
354 'thankyou_title' => $values['thankyou_title'] ?? NULL,
355 'customPre' => $values['customPre'],
356 'customPre_grouptitle' => $values['customPre_grouptitle'],
357 'customPost' => $values['customPost'],
358 'customPost_grouptitle' => $values['customPost_grouptitle'],
359 'useForMember' => $values['useForMember'],
360 'membership_assign' => $values['membership_assign'],
361 'amount' => $values['amount'],
362 'is_pay_later' => $values['is_pay_later'],
363 'receipt_date' => !$values['receipt_date'] ? NULL : date('YmdHis', strtotime($values['receipt_date'])),
364 'pay_later_receipt' => $values['pay_later_receipt'] ?? NULL,
365 'honor_block_is_active' => $values['honor_block_is_active'] ?? NULL,
366 'contributionStatus' => $values['contribution_status'] ?? NULL,
367 ];
368
369 if (!empty($values['financial_type_id'])) {
370 $tplParams['financialTypeId'] = $values['financial_type_id'];
371 $tplParams['financialTypeName'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType',
372 $values['financial_type_id']);
373 // Legacy support
374 $tplParams['contributionTypeName'] = $tplParams['financialTypeName'];
375 }
376
377 if ($contributionPageId = CRM_Utils_Array::value('id', $values)) {
378 $tplParams['contributionPageId'] = $contributionPageId;
379 }
380
381 // address required during receipt processing (pdf and email receipt)
382 if ($displayAddress = CRM_Utils_Array::value('address', $values)) {
383 $tplParams['address'] = $displayAddress;
384 }
385
386 // CRM-6976
387 $originalCCReceipt = $values['cc_receipt'] ?? NULL;
388
389 // cc to related contacts of contributor OR the one who
390 // signs up. Is used for cases like - on behalf of
391 // contribution / signup ..etc
392 if (array_key_exists('related_contact', $values)) {
393 list($ccDisplayName, $ccEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($values['related_contact']);
394 $ccMailId = "{$ccDisplayName} <{$ccEmail}>";
395
396 //@todo - this is the only place in this function where $values is altered - but I can't find any evidence it is used
397 $values['cc_receipt'] = !empty($values['cc_receipt']) ? ($values['cc_receipt'] . ',' . $ccMailId) : $ccMailId;
398
399 // reset primary-email in the template
400 $tplParams['email'] = $ccEmail;
401
402 $tplParams['onBehalfName'] = $displayName;
403 $tplParams['onBehalfEmail'] = $email;
404
405 if (!empty($values['onbehalf_profile_id'])) {
406 self::buildCustomDisplay($values['onbehalf_profile_id'], 'onBehalfProfile', $contactID, $template, $params['onbehalf_profile'], $fieldTypes);
407 }
408 }
409
410 // use either the contribution or membership receipt, based on whether it’s a membership-related contrib or not
411 $sendTemplateParams = [
412 'groupName' => !empty($values['isMembership']) ? 'msg_tpl_workflow_membership' : 'msg_tpl_workflow_contribution',
413 'valueName' => !empty($values['isMembership']) ? 'membership_online_receipt' : 'contribution_online_receipt',
414 'contactId' => $contactID,
415 'tplParams' => $tplParams,
416 'isTest' => $isTest,
417 'PDFFilename' => 'receipt.pdf',
418 ];
419
420 if ($returnMessageText) {
421 list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
422 return [
423 'subject' => $subject,
424 'body' => $message,
425 'to' => $displayName,
426 'html' => $html,
427 ];
428 }
429
430 if (empty($values['receipt_from_name']) && empty($values['receipt_from_name'])) {
431 list($values['receipt_from_name'], $values['receipt_from_email']) = CRM_Core_BAO_Domain::getNameAndEmail();
432 }
433
434 if ($values['is_email_receipt']) {
435 $sendTemplateParams['from'] = CRM_Utils_Array::value('receipt_from_name', $values) . ' <' . $values['receipt_from_email'] . '>';
436 $sendTemplateParams['toName'] = $displayName;
437 $sendTemplateParams['toEmail'] = $email;
438 $sendTemplateParams['cc'] = $values['cc_receipt'] ?? NULL;
439 $sendTemplateParams['bcc'] = $values['bcc_receipt'] ?? NULL;
440 //send email with pdf invoice
441 if (Civi::settings()->get('invoicing') && Civi::settings()->get('invoice_is_email_pdf')) {
442 $sendTemplateParams['isEmailPdf'] = TRUE;
443 $sendTemplateParams['contributionId'] = $values['contribution_id'];
444 }
445 list($sent, $subject, $message) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
446 }
447
448 // send duplicate alert, if dupe match found during on-behalf-of processing.
449 if (!empty($values['onbehalf_dupe_alert'])) {
450 $sendTemplateParams['groupName'] = 'msg_tpl_workflow_contribution';
451 $sendTemplateParams['valueName'] = 'contribution_dupalert';
452 $sendTemplateParams['from'] = ts('Automatically Generated') . " <{$values['receipt_from_email']}>";
453 $sendTemplateParams['toName'] = $values['receipt_from_name'] ?? NULL;
454 $sendTemplateParams['toEmail'] = $values['receipt_from_email'] ?? NULL;
455 $sendTemplateParams['tplParams']['onBehalfID'] = $contactID;
456 $sendTemplateParams['tplParams']['receiptMessage'] = $message;
457
458 // fix cc and reset back to original, CRM-6976
459 $sendTemplateParams['cc'] = $originalCCReceipt;
460
461 CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
462 }
463 }
464 }
465
466 /**
467 * Get the profile title and fields.
468 *
469 * @param int $gid
470 * @param int $cid
471 * @param array $params
472 * @param array $fieldTypes
473 *
474 * @return array
475 *
476 * @throws \CRM_Core_Exception
477 */
478 protected static function getProfileNameAndFields($gid, $cid, $params, $fieldTypes = []) {
479 $groupTitle = NULL;
480 $values = [];
481 if ($gid) {
482 if (CRM_Core_BAO_UFGroup::filterUFGroups($gid, $cid)) {
483 $fields = CRM_Core_BAO_UFGroup::getFields($gid, FALSE, CRM_Core_Action::VIEW, NULL, NULL, FALSE, NULL, FALSE, NULL, CRM_Core_Permission::CREATE, NULL);
484 foreach ($fields as $k => $v) {
485 if (!$groupTitle) {
486 $groupTitle = $v['groupDisplayTitle'];
487 }
488 // suppress all file fields from display and formatting fields
489 if (
490 $v['data_type'] === 'File' || $v['name'] === 'image_URL' || $v['field_type'] === 'Formatting') {
491 unset($fields[$k]);
492 }
493
494 if (!empty($fieldTypes) && (!in_array($v['field_type'], $fieldTypes))) {
495 unset($fields[$k]);
496 }
497 }
498
499 CRM_Core_BAO_UFGroup::getValues($cid, $fields, $values, FALSE, $params);
500 }
501 }
502 return [$groupTitle, $values];
503 }
504
505 /**
506 * Send the emails for Recurring Contribution Notification.
507 *
508 * @param int $contributionID
509 * @param string $type
510 * TxnType.
511 * Contribution page id.
512 * @param object $recur
513 * Object of recurring contribution table.
514 * @param bool|object $autoRenewMembership is it a auto renew membership.
515 *
516 * @throws \API_Exception
517 */
518 public static function recurringNotify($contributionID, $type, $recur, $autoRenewMembership = FALSE): void {
519 $contribution = Contribution::get(FALSE)
520 ->addWhere('id', '=', $contributionID)
521 ->setSelect([
522 'contribution_page_id',
523 'contact_id',
524 'contribution_recur_id',
525 'contribution_recur.is_email_receipt',
526 'contribution_page.title',
527 'contribution_page.is_email_receipt',
528 'contribution_page.receipt_from_name',
529 'contribution_page.receipt_from_email',
530 'contribution_page.cc_receipt',
531 'contribution_page.bcc_receipt',
532 ])
533 ->execute()->first();
534
535 if ($contribution['contribution_recur.is_email_receipt'] || $contribution['contribution_page.is_email_receipt']) {
536 if ($contribution['contribution_page.receipt_from_email']) {
537 $receiptFromName = $contribution['contribution_page.receipt_from_name'];
538 $receiptFromEmail = $contribution['contribution_page.receipt_from_email'];
539 }
540 else {
541 [$receiptFromName, $receiptFromEmail] = CRM_Core_BAO_Domain::getNameAndEmail();
542 }
543
544 $receiptFrom = "$receiptFromName <$receiptFromEmail>";
545 [$displayName, $email] = CRM_Contact_BAO_Contact_Location::getEmailDetails($contribution['contact_id'], FALSE);
546 $templatesParams = [
547 'groupName' => 'msg_tpl_workflow_contribution',
548 'valueName' => 'contribution_recurring_notify',
549 'contactId' => $contribution['contact_id'],
550 'tplParams' => [
551 'recur_frequency_interval' => $recur->frequency_interval,
552 'recur_frequency_unit' => $recur->frequency_unit,
553 'recur_installments' => $recur->installments,
554 'recur_start_date' => $recur->start_date,
555 'recur_end_date' => $recur->end_date,
556 'recur_amount' => $recur->amount,
557 'recur_txnType' => $type,
558 'displayName' => $displayName,
559 'receipt_from_name' => $receiptFromName,
560 'receipt_from_email' => $receiptFromEmail,
561 'auto_renew_membership' => $autoRenewMembership,
562 ],
563 'from' => $receiptFrom,
564 'toName' => $displayName,
565 'toEmail' => $email,
566 ];
567 //CRM-13811
568 $templatesParams['cc'] = $contribution['contribution_page.cc_receipt'];
569 $templatesParams['bcc'] = $contribution['contribution_page.cc_receipt'];
570 if ($recur->id) {
571 // in some cases its just recurringNotify() thats called for the first time and these urls don't get set.
572 // like in PaypalPro, & therefore we set it here additionally.
573 $template = CRM_Core_Smarty::singleton();
574 $paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($recur->id, 'recur', 'obj');
575 $url = $paymentProcessor->subscriptionURL($recur->id, 'recur', 'cancel');
576 $template->assign('cancelSubscriptionUrl', $url);
577
578 $url = $paymentProcessor->subscriptionURL($recur->id, 'recur', 'billing');
579 $template->assign('updateSubscriptionBillingUrl', $url);
580
581 $url = $paymentProcessor->subscriptionURL($recur->id, 'recur', 'update');
582 $template->assign('updateSubscriptionUrl', $url);
583 }
584
585 list($sent) = CRM_Core_BAO_MessageTemplate::sendTemplate($templatesParams);
586
587 if ($sent) {
588 CRM_Core_Error::debug_log_message('Success: mail sent for recurring notification.');
589 }
590 else {
591 CRM_Core_Error::debug_log_message('Failure: mail not sent for recurring notification.');
592 }
593 }
594 }
595
596 /**
597 * Add the custom fields for contribution page (ie profile).
598 *
599 * @deprecated assigning values to smarty like this is risky because
600 * - it is hard to debug since $name is used in the assign
601 * - it is potentially 'leaky' - it's better to do this on the form
602 * or close to where it is used / required. See CRM-17519 for leakage e.g.
603 *
604 * @param int $gid
605 * Uf group id.
606 * @param string $name
607 * @param int $cid
608 * Contact id.
609 * @param $template
610 * @param array $params
611 * Params to build component whereclause.
612 *
613 * @param array|null $fieldTypes
614 */
615 public static function buildCustomDisplay($gid, $name, $cid, &$template, &$params, $fieldTypes = NULL) {
616 list($groupTitle, $values) = self::getProfileNameAndFields($gid, $cid, $params, $fieldTypes);
617 if (!empty($values)) {
618 $template->assign($name, $values);
619 }
620 $template->assign($name . "_grouptitle", $groupTitle);
621 }
622
623 /**
624 * Make a copy of a contribution page, including all the blocks in the page.
625 *
626 * @param int $id
627 * The contribution page id to copy.
628 *
629 * @return CRM_Contribute_DAO_ContributionPage
630 */
631 public static function copy($id) {
632 $session = CRM_Core_Session::singleton();
633
634 $fieldsFix = [
635 'prefix' => [
636 'title' => ts('Copy of') . ' ',
637 ],
638 'replace' => [
639 'created_id' => $session->get('userID'),
640 'created_date' => date('YmdHis'),
641 ],
642 ];
643 $copy = CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_ContributionPage', [
644 'id' => $id,
645 ], NULL, $fieldsFix);
646
647 //copying all the blocks pertaining to the contribution page
648 $copyPledgeBlock = CRM_Core_DAO::copyGeneric('CRM_Pledge_DAO_PledgeBlock', [
649 'entity_id' => $id,
650 'entity_table' => 'civicrm_contribution_page',
651 ], [
652 'entity_id' => $copy->id,
653 ]);
654
655 $copyMembershipBlock = CRM_Core_DAO::copyGeneric('CRM_Member_DAO_MembershipBlock', [
656 'entity_id' => $id,
657 'entity_table' => 'civicrm_contribution_page',
658 ], [
659 'entity_id' => $copy->id,
660 ]);
661
662 $copyUFJoin = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin', [
663 'entity_id' => $id,
664 'entity_table' => 'civicrm_contribution_page',
665 ], [
666 'entity_id' => $copy->id,
667 ]);
668
669 $copyWidget = CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_Widget', [
670 'contribution_page_id' => $id,
671 ], [
672 'contribution_page_id' => $copy->id,
673 ]);
674
675 //copy price sets
676 CRM_Price_BAO_PriceSet::copyPriceSet('civicrm_contribution_page', $id, $copy->id);
677
678 $copyTellFriend = CRM_Core_DAO::copyGeneric('CRM_Friend_DAO_Friend', [
679 'entity_id' => $id,
680 'entity_table' => 'civicrm_contribution_page',
681 ], [
682 'entity_id' => $copy->id,
683 ]);
684
685 $copyPersonalCampaignPages = CRM_Core_DAO::copyGeneric('CRM_PCP_DAO_PCPBlock', [
686 'entity_id' => $id,
687 'entity_table' => 'civicrm_contribution_page',
688 ], [
689 'entity_id' => $copy->id,
690 'target_entity_id' => $copy->id,
691 ]);
692
693 $copyPremium = CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_Premium', [
694 'entity_id' => $id,
695 'entity_table' => 'civicrm_contribution_page',
696 ], [
697 'entity_id' => $copy->id,
698 ]);
699 $premiumQuery = "
700 SELECT id
701 FROM civicrm_premiums
702 WHERE entity_table = 'civicrm_contribution_page'
703 AND entity_id ={$id}";
704
705 $premiumDao = CRM_Core_DAO::executeQuery($premiumQuery);
706 while ($premiumDao->fetch()) {
707 if ($premiumDao->id) {
708 CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_PremiumsProduct', [
709 'premiums_id' => $premiumDao->id,
710 ], [
711 'premiums_id' => $copyPremium->id,
712 ]);
713 }
714 }
715
716 $copy->save();
717
718 CRM_Utils_Hook::copy('ContributionPage', $copy);
719
720 return $copy;
721 }
722
723 /**
724 * Get info for all sections enable/disable.
725 *
726 * @param array $contribPageIds
727 * @return array
728 * info regarding all sections.
729 */
730 public static function getSectionInfo($contribPageIds = []) {
731 $info = [];
732 $whereClause = NULL;
733 if (is_array($contribPageIds) && !empty($contribPageIds)) {
734 $whereClause = 'WHERE civicrm_contribution_page.id IN ( ' . implode(', ', $contribPageIds) . ' )';
735 }
736
737 $sections = [
738 'settings',
739 'amount',
740 'membership',
741 'custom',
742 'thankyou',
743 'friend',
744 'pcp',
745 'widget',
746 'premium',
747 ];
748 $query = "
749 SELECT civicrm_contribution_page.id as id,
750 civicrm_contribution_page.financial_type_id as settings,
751 amount_block_is_active as amount,
752 civicrm_membership_block.id as membership,
753 civicrm_uf_join.id as custom,
754 civicrm_contribution_page.thankyou_title as thankyou,
755 civicrm_tell_friend.id as friend,
756 civicrm_pcp_block.id as pcp,
757 civicrm_contribution_widget.id as widget,
758 civicrm_premiums.id as premium
759 FROM civicrm_contribution_page
760 LEFT JOIN civicrm_membership_block ON ( civicrm_membership_block.entity_id = civicrm_contribution_page.id
761 AND civicrm_membership_block.entity_table = 'civicrm_contribution_page'
762 AND civicrm_membership_block.is_active = 1 )
763 LEFT JOIN civicrm_uf_join ON ( civicrm_uf_join.entity_id = civicrm_contribution_page.id
764 AND civicrm_uf_join.entity_table = 'civicrm_contribution_page'
765 AND module = 'CiviContribute'
766 AND civicrm_uf_join.is_active = 1 )
767 LEFT JOIN civicrm_tell_friend ON ( civicrm_tell_friend.entity_id = civicrm_contribution_page.id
768 AND civicrm_tell_friend.entity_table = 'civicrm_contribution_page'
769 AND civicrm_tell_friend.is_active = 1)
770 LEFT JOIN civicrm_pcp_block ON ( civicrm_pcp_block.entity_id = civicrm_contribution_page.id
771 AND civicrm_pcp_block.entity_table = 'civicrm_contribution_page'
772 AND civicrm_pcp_block.is_active = 1 )
773 LEFT JOIN civicrm_contribution_widget ON ( civicrm_contribution_widget.contribution_page_id = civicrm_contribution_page.id
774 AND civicrm_contribution_widget.is_active = 1 )
775 LEFT JOIN civicrm_premiums ON ( civicrm_premiums.entity_id = civicrm_contribution_page.id
776 AND civicrm_premiums.entity_table = 'civicrm_contribution_page'
777 AND civicrm_premiums.premiums_active = 1 )
778 $whereClause";
779
780 $contributionPage = CRM_Core_DAO::executeQuery($query);
781 while ($contributionPage->fetch()) {
782 if (!isset($info[$contributionPage->id]) || !is_array($info[$contributionPage->id])) {
783 $info[$contributionPage->id] = array_fill_keys(array_values($sections), FALSE);
784 }
785 foreach ($sections as $section) {
786 if ($contributionPage->$section) {
787 $info[$contributionPage->id][$section] = TRUE;
788 }
789 }
790 }
791
792 return $info;
793 }
794
795 /**
796 * Get options for a given field.
797 * @see CRM_Core_DAO::buildOptions
798 *
799 * @param string $fieldName
800 * @param string $context : @see CRM_Core_DAO::buildOptionsContext
801 * @param array $props : whatever is known about this dao object
802 *
803 * @return array|bool
804 */
805 public static function buildOptions($fieldName, $context = NULL, $props = []) {
806 $params = [];
807 // Special logic for fields whose options depend on context or properties
808 switch ($fieldName) {
809 case 'financial_type_id':
810 // @fixme - this is going to ignore context, better to get conditions, add params, and call PseudoConstant::get
811 // @fixme - https://lab.civicrm.org/dev/core/issues/547 if CiviContribute not enabled this causes an invalid query
812 // because $relationTypeId is not set in CRM_Financial_BAO_FinancialType::getIncomeFinancialType()
813 if (array_key_exists('CiviContribute', CRM_Core_Component::getEnabledComponents())) {
814 return CRM_Financial_BAO_FinancialType::getIncomeFinancialType();
815 }
816 return [];
817 }
818 return CRM_Core_PseudoConstant::get(__CLASS__, $fieldName, $params, $context);
819 }
820
821 /**
822 * Get or Set honor/on_behalf params for processing module_data or setting default values.
823 *
824 * @param array $params :
825 * @param bool $setDefault : If yes then returns array to used for setting default value afterward
826 * @param string $module : processing module_data for which module? e.g. soft_credit, on_behalf
827 *
828 * @return array|string
829 */
830 public static function formatModuleData($params, $setDefault = FALSE, $module) {
831 $tsLocale = CRM_Core_I18n::getLocale();
832 $config = CRM_Core_Config::singleton();
833 $json = $jsonDecode = NULL;
834 $multilingual = CRM_Core_I18n::isMultilingual();
835
836 $moduleDataFormat = [
837 'soft_credit' => [
838 1 => 'soft_credit_types',
839 'multilingual' => [
840 'honor_block_title',
841 'honor_block_text',
842 ],
843 ],
844 'on_behalf' => [
845 1 => 'is_for_organization',
846 'multilingual' => [
847 'for_organization',
848 ],
849 ],
850 ];
851
852 //When we are fetching the honor params respecting both multi and mono lingual state
853 //and setting it to default param of Contribution Page's Main and Setting form
854 if ($setDefault) {
855 $jsonDecode = json_decode($params);
856 $jsonDecode = (array) $jsonDecode->$module;
857 if (!$multilingual && !empty($jsonDecode['default'])) {
858 //monolingual state
859 $jsonDecode += (array) $jsonDecode['default'];
860 unset($jsonDecode['default']);
861 }
862 elseif (!empty($jsonDecode[$tsLocale])) {
863 //multilingual state
864 foreach ($jsonDecode[$tsLocale] as $column => $value) {
865 $jsonDecode[$column] = $value;
866 }
867 unset($jsonDecode[$tsLocale]);
868 }
869 return $jsonDecode;
870 }
871
872 //check and handle multilingual honoree params
873 if (!$multilingual) {
874 //if in singlelingual state simply return the array format
875 $json = [$module => NULL];
876 foreach ($moduleDataFormat[$module] as $key => $attribute) {
877 if ($key === 'multilingual') {
878 $json[$module]['default'] = [];
879 foreach ($attribute as $attr) {
880 $json[$module]['default'][$attr] = $params[$attr];
881 }
882 }
883 else {
884 $json[$module][$attribute] = $params[$attribute];
885 }
886 }
887 $json = json_encode($json);
888 }
889 else {
890 //if in multilingual state then retrieve the module_data against this contribution and
891 //merge with earlier module_data json data to current so not to lose earlier multilingual module_data information
892 $json = [$module => NULL];
893 foreach ($moduleDataFormat[$module] as $key => $attribute) {
894 if ($key === 'multilingual') {
895 $json[$module][$tsLocale] = [];
896 foreach ($attribute as $attr) {
897 $json[$module][$tsLocale][$attr] = $params[$attr];
898 }
899 }
900 else {
901 $json[$module][$attribute] = $params[$attribute];
902 }
903 }
904
905 $ufJoinDAO = new CRM_Core_DAO_UFJoin();
906 $ufJoinDAO->module = $module;
907 $ufJoinDAO->entity_id = $params['id'];
908 $ufJoinDAO->find(TRUE);
909 $jsonData = json_decode($ufJoinDAO->module_data);
910 if ($jsonData) {
911 $json[$module] = array_merge((array) $jsonData->$module, $json[$module]);
912 }
913 $json = json_encode($json);
914 }
915 return $json;
916 }
917
918 /**
919 * Generate html for pdf in confirmation receipt email attachment.
920 * @param int $contributionId
921 * Contribution Page Id.
922 * @param int $userID
923 * Contact id for contributor.
924 * @return array
925 */
926 public static function addInvoicePdfToEmail($contributionId, $userID) {
927 $contributionID = [$contributionId];
928 $contactId = [$userID];
929 $pdfParams = [
930 'output' => 'pdf_invoice',
931 'forPage' => 'confirmpage',
932 ];
933 $pdfHtml = CRM_Contribute_Form_Task_Invoice::printPDF($contributionID, $pdfParams, $contactId);
934 return $pdfHtml;
935 }
936
937 /**
938 * Helper to determine if the page supports separate membership payments.
939 *
940 * @param int $id form id
941 *
942 * @return bool
943 * isSeparateMembershipPayment
944 */
945 public static function getIsMembershipPayment($id) {
946 $membershipBlocks = civicrm_api3('membership_block', 'get', [
947 'entity_table' => 'civicrm_contribution_page',
948 'entity_id' => $id,
949 'sequential' => TRUE,
950 ]);
951 if (!$membershipBlocks['count']) {
952 return FALSE;
953 }
954 return $membershipBlocks['values'][0]['is_separate_payment'];
955 }
956
957 }