fixed spelling of address on lines 122 and 247
[civicrm-core.git] / CRM / Contact / Form / Task / PDFLetterCommon.php
CommitLineData
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/**
424029e3 19 * This class provides the common functionality for creating PDF letter for one or a group of contact ids.
6a488035 20 */
958060c1 21class CRM_Contact_Form_Task_PDFLetterCommon extends CRM_Core_Form_Task_PDFLetterCommon {
6a488035 22
2fe8b920 23 protected static $tokenCategories;
24
cc144465
TO
25 /**
26 * @return array
27 * Array(string $machineName => string $label).
28 */
29 public static function getLoggingOptions() {
be2fb01f 30 return [
cc144465
TO
31 'none' => ts('Do not record'),
32 'multiple' => ts('Multiple activities (one per contact)'),
33 'combined' => ts('One combined activity'),
34 'combined-attached' => ts('One combined activity plus one file attachment'),
35 // 'multiple-attached' <== not worth the work
be2fb01f 36 ];
cc144465
TO
37 }
38
6a488035 39 /**
fe482240 40 * Build all the data structures needed to build the form.
6a488035 41 *
c490a46a 42 * @param CRM_Core_Form $form
6a488035 43 */
00be9182 44 public static function preProcess(&$form) {
beac1417 45 CRM_Contact_Form_Task_EmailCommon::preProcessFromAddress($form);
be2fb01f
CW
46 $messageText = [];
47 $messageSubject = [];
353ffa53 48 $dao = new CRM_Core_BAO_MessageTemplate();
6a488035
TO
49 $dao->is_active = 1;
50 $dao->find();
51 while ($dao->fetch()) {
52 $messageText[$dao->id] = $dao->msg_text;
53 $messageSubject[$dao->id] = $dao->msg_subject;
54 }
55
56 $form->assign('message', $messageText);
57 $form->assign('messageSubject', $messageSubject);
958060c1 58 parent::preProcess($form);
6a488035
TO
59 }
60
86538308 61 /**
c490a46a 62 * @param CRM_Core_Form $form
100fef9d 63 * @param int $cid
86538308 64 */
00be9182 65 public static function preProcessSingle(&$form, $cid) {
fe61faf3 66 $form->_contactIds = explode(',', $cid);
6a488035 67 // put contact display name in title for single contact mode
fe61faf3 68 if (count($form->_contactIds) === 1) {
be2fb01f 69 CRM_Utils_System::setTitle(ts('Print/Merge Document for %1', [1 => CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name')]));
fe61faf3 70 }
6a488035
TO
71 }
72
6a488035 73 /**
fe482240 74 * Part of the post process which prepare and extract information from the template.
6a488035 75 *
6a488035 76 *
2bd6b6cf 77 * @param array $formValues
dbddfb08 78 *
72b3a70c
CW
79 * @return array
80 * [$categories, $html_message, $messageToken, $returnProperties]
6a488035 81 */
2bd6b6cf 82 public static function processMessageTemplate($formValues) {
958060c1 83 $html_message = self::processTemplate($formValues);
6a488035 84
2fe8b920 85 $categories = self::getTokenCategories();
6a488035 86
6a488035
TO
87 //time being hack to strip '&nbsp;'
88 //from particular letter line, CRM-6798
89 self::formatMessage($html_message);
90
91 $messageToken = CRM_Utils_Token::getTokens($html_message);
92
be2fb01f 93 $returnProperties = [];
6a488035
TO
94 if (isset($messageToken['contact'])) {
95 foreach ($messageToken['contact'] as $key => $value) {
96 $returnProperties[$value] = 1;
97 }
98 }
99
be2fb01f 100 return [$formValues, $categories, $html_message, $messageToken, $returnProperties];
6a488035
TO
101 }
102
103 /**
fe482240 104 * Process the form after the input has been submitted and validated.
6a488035 105 *
c490a46a 106 * @param CRM_Core_Form $form
2fe8b920 107 * @throws \CRM_Core_Exception
b69df99f 108 * @throws \CiviCRM_API3_Exception
6a488035 109 */
00be9182 110 public static function postProcess(&$form) {
2bd6b6cf 111 $formValues = $form->controller->exportValues($form->getName());
112 list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($formValues);
2e1f50d6
CW
113 $skipOnHold = $form->skipOnHold ?? FALSE;
114 $skipDeceased = $form->skipDeceased ?? TRUE;
be2fb01f 115 $html = $activityIds = [];
ad7fdc34 116
117 // CRM-16725 Skip creation of activities if user is previewing their PDF letter(s)
752cee47 118 if (self::isLiveMode($form)) {
fe61faf3 119 $activityIds = self::createActivities($form, $html_message, $form->_contactIds, $formValues['subject'], CRM_Utils_Array::value('campaign_id', $formValues));
ad7fdc34 120 }
121
122 if (!empty($formValues['document_file_path'])) {
9eae09f1 123 list($html_message, $zip) = CRM_Utils_PDF_Document::unzipDoc($formValues['document_file_path'], $formValues['document_type']);
ad7fdc34 124 }
6a488035
TO
125
126 foreach ($form->_contactIds as $item => $contactId) {
8ffa3b7c 127 $caseId = NULL;
be2fb01f 128 $params = ['contact_id' => $contactId];
6a488035 129
b69df99f
CW
130 $caseId = $form->getVar('_caseId');
131 if (empty($caseId) && !empty($form->_caseIds[$item])) {
132 $caseId = $form->_caseIds[$item];
133 }
134 if ($caseId) {
135 $params['case_id'] = $caseId;
136 }
137
6a488035
TO
138 list($contact) = CRM_Utils_Token::getTokenDetails($params,
139 $returnProperties,
140 $skipOnHold,
141 $skipDeceased,
142 NULL,
143 $messageToken,
144 'CRM_Contact_Form_Task_PDFLetterCommon'
145 );
2c8a6e63 146
6a488035
TO
147 if (civicrm_error($contact)) {
148 $notSent[] = $contactId;
149 continue;
150 }
151
152 $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken);
b69df99f 153
8ffa3b7c 154 if ($caseId) {
155 $tokenHtml = CRM_Utils_Token::replaceCaseTokens($caseId, $tokenHtml, $messageToken);
07945b3c 156 }
6a488035
TO
157 $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $categories, TRUE);
158
159 if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) {
160 $smarty = CRM_Core_Smarty::singleton();
161 // also add the contact tokens to the template
162 $smarty->assign_by_ref('contact', $contact);
163 $tokenHtml = $smarty->fetch("string:$tokenHtml");
164 }
165
166 $html[] = $tokenHtml;
167 }
168
38faa439 169 $tee = NULL;
dd8e53c4 170 if (self::isLiveMode($form) && Civi::settings()->get('recordGeneratedLetters') === 'combined-attached') {
bdac10d8
TO
171 if (count($activityIds) !== 1) {
172 throw new CRM_Core_Exception("When recordGeneratedLetters=combined-attached, there should only be one activity.");
173 }
38faa439 174 $tee = CRM_Utils_ConsoleTee::create()->start();
3c48a60c
TO
175 }
176
0aeb5a1e 177 $type = $formValues['document_type'];
3c48a60c 178 $mimeType = self::getMimeType($type);
3ed92c14 179 // ^^ Useful side-effect: consistently throws error for unrecognized types.
0aeb5a1e
CW
180
181 if ($type == 'pdf') {
3c48a60c
TO
182 $fileName = "CiviLetter.$type";
183 CRM_Utils_PDF_Utils::html2pdf($html, $fileName, FALSE, $formValues);
0aeb5a1e 184 }
ad7fdc34 185 elseif (!empty($formValues['document_file_path'])) {
63c8a9ba
TO
186 $fileName = pathinfo($formValues['document_file_path'], PATHINFO_FILENAME) . '.' . $type;
187 CRM_Utils_PDF_Document::printDocuments($html, $fileName, $type, $zip);
ad7fdc34 188 }
0aeb5a1e 189 else {
3c48a60c
TO
190 $fileName = "CiviLetter.$type";
191 CRM_Utils_PDF_Document::html2doc($html, $fileName, $formValues);
192 }
193
38faa439
TO
194 if ($tee) {
195 $tee->stop();
196 $content = file_get_contents($tee->getFileName(), NULL, NULL, NULL, 5);
3c48a60c
TO
197 if (empty($content)) {
198 throw new \CRM_Core_Exception("Failed to capture document content (type=$type)!");
199 }
200 foreach ($activityIds as $activityId) {
be2fb01f 201 civicrm_api3('Attachment', 'create', [
3c48a60c
TO
202 'entity_table' => 'civicrm_activity',
203 'entity_id' => $activityId,
204 'name' => $fileName,
205 'mime_type' => $mimeType,
be2fb01f 206 'options' => [
38faa439 207 'move-file' => $tee->getFileName(),
be2fb01f
CW
208 ],
209 ]);
3c48a60c 210 }
0aeb5a1e 211 }
6a488035
TO
212
213 $form->postProcessHook();
214
292c8687 215 CRM_Utils_System::civiExit();
6a488035
TO
216 }
217
86538308 218 /**
c490a46a 219 * @param CRM_Core_Form $form
818b4373
TO
220 * @param string $html_message
221 * @param array $contactIds
3280f327 222 * @param string $subject
223 * @param int $campaign_id
224 * @param array $perContactHtml
225 *
818b4373
TO
226 * @return array
227 * List of activity IDs.
228 * There may be 1 or more, depending on the system-settings
229 * and use-case.
86538308
EM
230 *
231 * @throws CRM_Core_Exception
232 */
be2fb01f 233 public static function createActivities($form, $html_message, $contactIds, $subject, $campaign_id, $perContactHtml = []) {
6a488035 234
be2fb01f 235 $activityParams = [
3280f327 236 'subject' => $subject,
237 'campaign_id' => $campaign_id,
2dbdb9b9 238 'source_contact_id' => CRM_Core_Session::getLoggedInContactID(),
3280f327 239 'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Print PDF Letter'),
6a488035
TO
240 'activity_date_time' => date('YmdHis'),
241 'details' => $html_message,
be2fb01f 242 ];
6a488035 243 if (!empty($form->_activityId)) {
be2fb01f 244 $activityParams += ['id' => $form->_activityId];
6a488035 245 }
818b4373 246
be2fb01f 247 $activityIds = [];
818b4373
TO
248 switch (Civi::settings()->get('recordGeneratedLetters')) {
249 case 'none':
be2fb01f 250 return [];
818b4373
TO
251
252 case 'multiple':
253 // One activity per contact.
fe61faf3 254 foreach ($contactIds as $i => $contactId) {
be2fb01f 255 $fullParams = [
6d3827cb 256 'target_contact_id' => $contactId,
be2fb01f 257 ] + $activityParams;
fe61faf3
CW
258 if (!empty($form->_caseId)) {
259 $fullParams['case_id'] = $form->_caseId;
260 }
261 elseif (!empty($form->_caseIds[$i])) {
262 $fullParams['case_id'] = $form->_caseIds[$i];
263 }
264
3280f327 265 if (isset($perContactHtml[$contactId])) {
266 $fullParams['details'] = implode('<hr>', $perContactHtml[$contactId]);
267 }
268 $activity = civicrm_api3('Activity', 'create', $fullParams);
269 $activityIds[$contactId] = $activity['id'];
818b4373
TO
270 }
271
272 break;
273
274 case 'combined':
275 case 'combined-attached':
276 // One activity with all contacts.
be2fb01f 277 $fullParams = [
6d3827cb 278 'target_contact_id' => $contactIds,
be2fb01f 279 ] + $activityParams;
fe61faf3
CW
280 if (!empty($form->_caseId)) {
281 $fullParams['case_id'] = $form->_caseId;
282 }
283 elseif (!empty($form->_caseIds)) {
284 $fullParams['case_id'] = $form->_caseIds;
285 }
286 $activity = civicrm_api3('Activity', 'create', $fullParams);
287 $activityIds[] = $activity['id'];
818b4373
TO
288 break;
289
290 default:
291 throw new CRM_Core_Exception("Unrecognized option in recordGeneratedLetters: " . Civi::settings()->get('recordGeneratedLetters'));
6a488035 292 }
818b4373 293
818b4373 294 return $activityIds;
6a488035
TO
295 }
296
86538308 297 /**
3c48a60c
TO
298 * Convert from a vague-type/file-extension to mime-type.
299 *
300 * @param string $type
301 * @return string
302 * @throws \CRM_Core_Exception
303 */
304 private static function getMimeType($type) {
be2fb01f 305 $mimeTypes = [
4b54b8bb 306 'pdf' => 'application/pdf',
3c48a60c
TO
307 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
308 'odt' => 'application/vnd.oasis.opendocument.text',
309 'html' => 'text/html',
be2fb01f 310 ];
3c48a60c
TO
311 if (isset($mimeTypes[$type])) {
312 return $mimeTypes[$type];
313 }
314 else {
315 throw new \CRM_Core_Exception("Cannot determine mime type");
316 }
317 }
318
2fe8b920 319 /**
320 * Get the categories required for rendering tokens.
321 *
322 * @return array
323 */
324 protected static function getTokenCategories() {
3280f327 325 if (!isset(Civi::$statics[__CLASS__]['token_categories'])) {
be2fb01f 326 $tokens = [];
2fe8b920 327 CRM_Utils_Hook::tokens($tokens);
3280f327 328 Civi::$statics[__CLASS__]['token_categories'] = array_keys($tokens);
2fe8b920 329 }
3280f327 330 return Civi::$statics[__CLASS__]['token_categories'];
2fe8b920 331 }
332
752cee47 333 /**
334 * Is the form in live mode (as opposed to being run as a preview).
335 *
336 * Returns true if the user has clicked the Download Document button on a
337 * Print/Merge Document (PDF Letter) search task form, or false if the Preview
338 * button was clicked.
339 *
340 * @param CRM_Core_Form $form
341 *
342 * @return bool
343 * TRUE if the Download Document button was clicked (also defaults to TRUE
344 * if the form controller does not exist), else FALSE
345 */
346 protected static function isLiveMode($form) {
347 // CRM-21255 - Hrm, CiviCase 4+5 seem to report buttons differently...
348 $buttonName = $form->controller->getButtonName();
349 $c = $form->controller->container();
350 $isLiveMode = ($buttonName == '_qf_PDF_upload') || isset($c['values']['PDF']['buttons']['_qf_PDF_upload']);
351 return $isLiveMode;
352 }
353
6a488035 354}