Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 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 TO |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
16 | */ |
17 | ||
18 | /** | |
19 | * This class provides the functionality to email a group of | |
20 | * contacts. | |
21 | */ | |
22 | class CRM_Contribute_Form_Task_PDF extends CRM_Contribute_Form_Task { | |
23 | ||
24 | /** | |
25 | * Are we operating in "single mode", i.e. updating the task of only | |
26 | * one specific contribution? | |
27 | * | |
b67daa72 | 28 | * @var bool |
6a488035 TO |
29 | */ |
30 | public $_single = FALSE; | |
31 | ||
32 | protected $_rows; | |
33 | ||
34 | /** | |
fe482240 | 35 | * Build all the data structures needed to build the form. |
95ea96be | 36 | */ |
389bcebf | 37 | public function preProcess() { |
8c2b7d01 | 38 | parent::preProcess(); |
6a488035 TO |
39 | // check that all the contribution ids have pending status |
40 | $query = " | |
41 | SELECT count(*) | |
42 | FROM civicrm_contribution | |
43 | WHERE contribution_status_id != 1 | |
44 | AND {$this->_componentClause}"; | |
6f57e938 | 45 | if (CRM_Core_DAO::singleValueQuery($query)) { |
46 | CRM_Core_Error::statusBounce("Please select only contributions with Completed status."); | |
6a488035 TO |
47 | } |
48 | ||
6a488035 TO |
49 | $this->assign('single', $this->_single); |
50 | ||
51 | $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this); | |
52 | $urlParams = 'force=1'; | |
53 | if (CRM_Utils_Rule::qfKey($qfKey)) { | |
54 | $urlParams .= "&qfKey=$qfKey"; | |
55 | } | |
56 | ||
57 | $url = CRM_Utils_System::url('civicrm/contribute/search', $urlParams); | |
be2fb01f CW |
58 | $breadCrumb = [ |
59 | [ | |
353ffa53 | 60 | 'url' => $url, |
6a488035 | 61 | 'title' => ts('Search Results'), |
be2fb01f CW |
62 | ], |
63 | ]; | |
f68954cb | 64 | CRM_Contact_Form_Task_EmailCommon ::preProcessFromAddress($this, FALSE); |
7d86c73a | 65 | // we have all the contribution ids, so now we get the contact ids |
3c4ce98e | 66 | parent::setContactIDs(); |
6a488035 | 67 | CRM_Utils_System::appendBreadCrumb($breadCrumb); |
7e2e2551 | 68 | $this->setTitle(ts('Print Contribution Receipts')); |
813e32ef | 69 | // Ajax submit would interfere with pdf file download |
70 | $this->preventAjaxSubmit(); | |
6a488035 TO |
71 | } |
72 | ||
73 | /** | |
fe482240 | 74 | * Build the form object. |
6a488035 TO |
75 | */ |
76 | public function buildQuickForm() { | |
77 | ||
78 | $this->addElement('radio', 'output', NULL, ts('Email Receipts'), 'email_receipt', | |
be2fb01f | 79 | [ |
6d98bfad | 80 | 'onClick' => "document.getElementById('selectPdfFormat').style.display = 'none'; |
1330f57a SL |
81 | document.getElementById('selectEmailFrom').style.display = 'block';", |
82 | ] | |
6a488035 TO |
83 | ); |
84 | $this->addElement('radio', 'output', NULL, ts('PDF Receipts'), 'pdf_receipt', | |
be2fb01f | 85 | [ |
99ad38df | 86 | 'onClick' => "document.getElementById('selectPdfFormat').style.display = 'block'; |
1330f57a SL |
87 | document.getElementById('selectEmailFrom').style.display = 'none';", |
88 | ] | |
6a488035 TO |
89 | ); |
90 | $this->addRule('output', ts('Selection required'), 'required'); | |
91 | ||
92 | $this->add('select', 'pdf_format_id', ts('Page Format'), | |
be2fb01f | 93 | [0 => ts('- default -')] + CRM_Core_BAO_PdfFormat::getList(TRUE) |
6a488035 | 94 | ); |
10708045 | 95 | $this->add('checkbox', 'receipt_update', ts('Update receipt dates for these contributions'), FALSE); |
be4478f0 | 96 | $this->add('checkbox', 'override_privacy', ts('Override privacy setting? (Do not email / Do not mail)'), FALSE); |
6a488035 | 97 | |
beac1417 | 98 | $this->add('select', 'from_email_address', ts('From Email'), $this->_fromEmails, FALSE); |
6d98bfad | 99 | |
be2fb01f | 100 | $this->addButtons([ |
1330f57a SL |
101 | [ |
102 | 'type' => 'next', | |
103 | 'name' => ts('Process Receipt(s)'), | |
104 | 'isDefault' => TRUE, | |
105 | ], | |
106 | [ | |
107 | 'type' => 'back', | |
108 | 'name' => ts('Cancel'), | |
109 | ], | |
110 | ]); | |
6a488035 TO |
111 | } |
112 | ||
113 | /** | |
fe482240 | 114 | * Set default values. |
6a488035 | 115 | */ |
00be9182 | 116 | public function setDefaultValues() { |
6a488035 | 117 | $defaultFormat = CRM_Core_BAO_PdfFormat::getDefaultValues(); |
be2fb01f | 118 | return ['pdf_format_id' => $defaultFormat['id'], 'receipt_update' => 1, 'override_privacy' => 0]; |
6a488035 TO |
119 | } |
120 | ||
121 | /** | |
fe482240 | 122 | * Process the form after the input has been submitted and validated. |
6a488035 TO |
123 | */ |
124 | public function postProcess() { | |
125 | // get all the details needed to generate a receipt | |
be2fb01f | 126 | $message = []; |
2826a42e | 127 | $template = CRM_Core_Smarty::singleton(); |
6a488035 | 128 | |
6efffa5d PB |
129 | $params = $this->controller->exportValues($this->_name); |
130 | $elements = self::getElements($this->_contributionIds, $params, $this->_contactIds); | |
6a488035 | 131 | |
2826a42e | 132 | foreach ($elements['details'] as $contribID => $detail) { |
4d53a839 | 133 | $input = $ids = []; |
6a488035 | 134 | |
3a1261ac | 135 | if (in_array($detail['contact'], $elements['excludeContactIds'])) { |
6a488035 TO |
136 | continue; |
137 | } | |
4d53a839 | 138 | // @todo - CRM_Contribute_BAO_Contribution::sendMail re-does pretty much everything between here & when we call it. |
6a488035 TO |
139 | $input['component'] = $detail['component']; |
140 | ||
141 | $ids['contact'] = $detail['contact']; | |
2826a42e | 142 | $ids['contribution'] = $contribID; |
6a488035 TO |
143 | $ids['contributionRecur'] = NULL; |
144 | $ids['contributionPage'] = NULL; | |
9c1bc317 CW |
145 | $ids['membership'] = $detail['membership'] ?? NULL; |
146 | $ids['participant'] = $detail['participant'] ?? NULL; | |
147 | $ids['event'] = $detail['event'] ?? NULL; | |
6a488035 | 148 | |
4d53a839 | 149 | $contribution = new CRM_Contribute_BAO_Contribution(); |
150 | $contribution->id = $contribID; | |
151 | $contribution->fetch(); | |
6a488035 TO |
152 | |
153 | // set some fake input values so we can reuse IPN code | |
353ffa53 TO |
154 | $input['amount'] = $contribution->total_amount; |
155 | $input['is_test'] = $contribution->is_test; | |
6a488035 TO |
156 | $input['fee_amount'] = $contribution->fee_amount; |
157 | $input['net_amount'] = $contribution->net_amount; | |
353ffa53 | 158 | $input['trxn_id'] = $contribution->trxn_id; |
77c21b32 | 159 | $input['trxn_date'] = $contribution->trxn_date ?? NULL; |
cc7b912f | 160 | $input['receipt_update'] = $params['receipt_update']; |
d5580ed4 | 161 | $input['contribution_status_id'] = $contribution->contribution_status_id; |
35724050 BS |
162 | $input['paymentProcessor'] = empty($contribution->trxn_id) ? NULL : |
163 | CRM_Core_DAO::singleValueQuery("SELECT payment_processor_id | |
164 | FROM civicrm_financial_trxn | |
165 | WHERE trxn_id = %1 | |
be2fb01f | 166 | LIMIT 1", [ |
1330f57a SL |
167 | 1 => [$contribution->trxn_id, 'String'], |
168 | ]); | |
6a488035 | 169 | |
beac1417 | 170 | if (isset($params['from_email_address']) && !$elements['createPdf']) { |
5b8e26b5 SL |
171 | // If a logged in user from email is used rather than a domain wide from email address |
172 | // the from_email_address params key will be numerical and we need to convert it to be | |
173 | // in normal from email format | |
174 | $from = CRM_Utils_Mail::formatFromAddress($params['from_email_address']); | |
df72e709 | 175 | // CRM-19129 Allow useres the choice of From Email to send the receipt from. |
5b8e26b5 | 176 | $fromDetails = explode(' <', $from); |
6d98bfad SL |
177 | $input['receipt_from_email'] = substr(trim($fromDetails[1]), 0, -1); |
178 | $input['receipt_from_name'] = str_replace('"', '', $fromDetails[0]); | |
179 | } | |
180 | ||
4d53a839 | 181 | $mail = CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $contribID, $elements['createPdf']); |
6a488035 | 182 | |
edf20304 | 183 | if (!empty($mail['html'])) { |
6a488035 TO |
184 | $message[] = $mail['html']; |
185 | } | |
edf20304 | 186 | elseif (!empty($mail['body'])) { |
6a488035 TO |
187 | $message[] = nl2br($mail['body']); |
188 | } | |
189 | ||
190 | // reset template values before processing next transactions | |
191 | $template->clearTemplateVars(); | |
192 | } | |
3a1261ac RK |
193 | |
194 | if ($elements['createPdf']) { | |
6a488035 | 195 | CRM_Utils_PDF_Utils::html2pdf($message, |
442f0436 | 196 | 'receipt.pdf', |
6a488035 | 197 | FALSE, |
3a1261ac | 198 | $elements['params']['pdf_format_id'] |
6a488035 TO |
199 | ); |
200 | CRM_Utils_System::civiExit(); | |
201 | } | |
202 | else { | |
3a1261ac | 203 | if ($elements['suppressedEmails']) { |
be2fb01f | 204 | $status = ts('Email was NOT sent to %1 contacts (no email address on file, or communication preferences specify DO NOT EMAIL, or contact is deceased).', [1 => $elements['suppressedEmails']]); |
6a488035 TO |
205 | $msgTitle = ts('Email Error'); |
206 | $msgType = 'error'; | |
207 | } | |
208 | else { | |
209 | $status = ts('Your mail has been sent.'); | |
210 | $msgTitle = ts('Sent'); | |
211 | $msgType = 'success'; | |
212 | } | |
213 | CRM_Core_Session::setStatus($status, $msgTitle, $msgType); | |
214 | } | |
215 | } | |
3a1261ac RK |
216 | |
217 | /** | |
fe482240 | 218 | * Declaration of common variables for Invoice and PDF. |
3a1261ac | 219 | * |
3a1261ac | 220 | * |
014c4014 TO |
221 | * @param array $contribIds |
222 | * Contribution Id. | |
223 | * @param array $params | |
224 | * Parameter for pdf or email invoices. | |
225 | * @param array $contactIds | |
226 | * Contact Id. | |
6efffa5d | 227 | * |
a6c01b45 CW |
228 | * @return array |
229 | * array of common elements | |
2826a42e | 230 | * |
9ce03d87 | 231 | * @throws \CiviCRM_API3_Exception |
3a1261ac | 232 | */ |
1330f57a | 233 | public static function getElements($contribIds, $params, $contactIds) { |
be2fb01f | 234 | $pdfElements = []; |
3a1261ac | 235 | |
6efffa5d | 236 | $pdfElements['contribIDs'] = implode(',', $contribIds); |
3a1261ac | 237 | |
3e93468d | 238 | $pdfElements['details'] = self::getDetails($pdfElements['contribIDs']); |
3a1261ac RK |
239 | |
240 | $pdfElements['baseIPN'] = new CRM_Core_Payment_BaseIPN(); | |
241 | ||
6efffa5d | 242 | $pdfElements['params'] = $params; |
3a1261ac RK |
243 | |
244 | $pdfElements['createPdf'] = FALSE; | |
830b3e83 | 245 | if (!empty($pdfElements['params']['output']) && |
9ce03d87 | 246 | ($pdfElements['params']['output'] === 'pdf_invoice' || $pdfElements['params']['output'] === 'pdf_receipt') |
353ffa53 | 247 | ) { |
3a1261ac RK |
248 | $pdfElements['createPdf'] = TRUE; |
249 | } | |
250 | ||
be2fb01f | 251 | $excludeContactIds = []; |
3a1261ac | 252 | if (!$pdfElements['createPdf']) { |
9ce03d87 EM |
253 | $contactDetails = civicrm_api3('Contact', 'get', [ |
254 | 'return' => ['email', 'do_not_email', 'is_deceased', 'on_hold'], | |
255 | 'id' => ['IN' => $contactIds], | |
66f43ef2 | 256 | 'options' => ['limit' => 0], |
9ce03d87 | 257 | ])['values']; |
3a1261ac | 258 | $pdfElements['suppressedEmails'] = 0; |
830b3e83 | 259 | $suppressedEmails = 0; |
3a1261ac | 260 | foreach ($contactDetails as $id => $values) { |
10708045 EM |
261 | if (empty($values['email']) || |
262 | (empty($params['override_privacy']) && !empty($values['do_not_email'])) | |
b99f3e96 | 263 | || !empty($values['is_deceased']) |
353ffa53 TO |
264 | || !empty($values['on_hold']) |
265 | ) { | |
874c9be7 TO |
266 | $suppressedEmails++; |
267 | $pdfElements['suppressedEmails'] = $suppressedEmails; | |
268 | $excludeContactIds[] = $values['contact_id']; | |
3a1261ac RK |
269 | } |
270 | } | |
271 | } | |
272 | $pdfElements['excludeContactIds'] = $excludeContactIds; | |
2826a42e | 273 | |
3a1261ac RK |
274 | return $pdfElements; |
275 | } | |
96025800 | 276 | |
3e93468d AH |
277 | /** |
278 | * @param string $contributionIDs | |
279 | * | |
280 | * @return array | |
281 | */ | |
282 | private static function getDetails($contributionIDs) { | |
283 | if (empty($contributionIDs)) { | |
284 | return []; | |
285 | } | |
286 | $query = " | |
287 | SELECT c.id as contribution_id, | |
288 | c.contact_id as contact_id , | |
289 | mp.membership_id as membership_id , | |
290 | pp.participant_id as participant_id , | |
291 | p.event_id as event_id | |
292 | FROM civicrm_contribution c | |
293 | LEFT JOIN civicrm_membership_payment mp ON mp.contribution_id = c.id | |
294 | LEFT JOIN civicrm_participant_payment pp ON pp.contribution_id = c.id | |
295 | LEFT JOIN civicrm_participant p ON pp.participant_id = p.id | |
296 | WHERE c.id IN ( $contributionIDs )"; | |
297 | ||
298 | $rows = []; | |
299 | $dao = CRM_Core_DAO::executeQuery($query); | |
300 | ||
301 | while ($dao->fetch()) { | |
302 | $rows[$dao->contribution_id]['component'] = $dao->participant_id ? 'event' : 'contribute'; | |
303 | $rows[$dao->contribution_id]['contact'] = $dao->contact_id; | |
304 | if ($dao->membership_id) { | |
305 | if (!array_key_exists('membership', $rows[$dao->contribution_id])) { | |
306 | $rows[$dao->contribution_id]['membership'] = []; | |
307 | } | |
308 | $rows[$dao->contribution_id]['membership'][] = $dao->membership_id; | |
309 | } | |
310 | if ($dao->participant_id) { | |
311 | $rows[$dao->contribution_id]['participant'] = $dao->participant_id; | |
312 | } | |
313 | if ($dao->event_id) { | |
314 | $rows[$dao->contribution_id]['event'] = $dao->event_id; | |
315 | } | |
316 | } | |
317 | return $rows; | |
318 | } | |
319 | ||
6a488035 | 320 | } |