From 383c047b57e185022e686d9b15499ce694592b9f Mon Sep 17 00:00:00 2001 From: Dave Greenberg Date: Sun, 27 Apr 2014 17:24:25 -0700 Subject: [PATCH] CRM-14367 - Replacing PR 2751 with additional UI and help changes. ---------------------------------------- * CRM-14367: https://issues.civicrm.org/jira/browse/CRM-14367 --- CRM/Contact/Form/Task/PDFLetterCommon.php | 1 + CRM/Contribute/Form/Task/PDFLetter.php | 28 +- CRM/Contribute/Form/Task/PDFLetterCommon.php | 305 ++++++++++++++---- CRM/Core/BAO/MessageTemplate.php | 21 +- CRM/Utils/Mail.php | 31 +- CRM/Utils/Token.php | 54 +++- .../CRM/Contribute/Form/Task/PDFLetter.hlp | 48 +++ .../CRM/Contribute/Form/Task/PDFLetter.tpl | 13 +- 8 files changed, 405 insertions(+), 96 deletions(-) create mode 100644 templates/CRM/Contribute/Form/Task/PDFLetter.hlp diff --git a/CRM/Contact/Form/Task/PDFLetterCommon.php b/CRM/Contact/Form/Task/PDFLetterCommon.php index d1327a673e..f67aa261c1 100644 --- a/CRM/Contact/Form/Task/PDFLetterCommon.php +++ b/CRM/Contact/Form/Task/PDFLetterCommon.php @@ -413,6 +413,7 @@ class CRM_Contact_Form_Task_PDFLetterCommon { $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name'); $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts); + //@todo why are we using $form->_contactIds here & contactIds above - need comment foreach ($form->_contactIds as $contactId) { $activityTargetParams = array( 'activity_id' => empty($activity->id) ? $activityIds[$contactId] : $activity->id, diff --git a/CRM/Contribute/Form/Task/PDFLetter.php b/CRM/Contribute/Form/Task/PDFLetter.php index b3c8a412ea..7a53fb8d39 100644 --- a/CRM/Contribute/Form/Task/PDFLetter.php +++ b/CRM/Contribute/Form/Task/PDFLetter.php @@ -59,7 +59,6 @@ class CRM_Contribute_Form_Task_PDFLetter extends CRM_Contribute_Form_Task { function preProcess() { $this->skipOnHold = $this->skipDeceased = FALSE; CRM_Contact_Form_Task_PDFLetterCommon::preProcess($this); - // store case id if present $this->_caseId = CRM_Utils_Request::retrieve('caseid', 'Positive', $this, FALSE); @@ -108,13 +107,31 @@ class CRM_Contribute_Form_Task_PDFLetter extends CRM_Contribute_Form_Task { CRM_Contact_Form_Task_PDFLetterCommon::buildQuickForm($this); // specific need for contributions - $this->add('static', 'more_options_header', NULL, ts('Record Update Options')); + $this->add('static', 'more_options_header', NULL, ts('Thank-you Letter Options')); $this->add('checkbox', 'receipt_update', ts('Update receipt dates for these contributions'), FALSE); $this->add('checkbox', 'thankyou_update', ts('Update thank-you dates for these contributions'), FALSE); // Group options for tokens are not yet implemented. dgg - $options = array(ts('Contact'), ts('Recurring')); - $this->addRadio('is_group_by', ts('Grouping contributions in one letter based on'), $options, array('allowClear' => TRUE), "
", FALSE); + $options = array( + '' => ts('- no grouping -'), + 'contact_id' => ts('Contact'), + 'contribution_recur_id' => ts('Contact and Recurring'), + 'financial_type_id' => ts('Contact and Financial Type'), + 'campaign_id' => ts('Contact and Campaign'), + 'payment_instrument_id' => 'Contact and Payment Instrument', + ); + $this->addElement('select', 'group_by', ts('Group contributions by'), $options, array(), "
", FALSE); + // this was going to be free-text but I opted for radio options in case there was a script injection risk + $separatorOptions = array('comma' => 'Comma', 'td' => 'Table Cell' ); + $this->addElement('select', 'group_by_separator', ts('Separator (grouped contributions)'), $separatorOptions); + $emailOptions = array( + '' => ts('Generate PDFs for printing (only)'), + 'email' => ts('Send emails where possible. Generate printable PDFs for contacts who cannot receive email.'), + 'both' => ts('Send emails where possible. Generate printable PDFs for all contacts.'), + 'pdfemail' => ts('Send emails with an attached PDF where possible. Generate printable PDFs for contacts who cannot receive email.'), + 'pdfemail_both' => ts('Send emails with an attached PDF where possible. Generate printable PDFs for all contacts.'), + ); + $this->addElement('select', 'email_options', ts('Print and email options'), $emailOptions, array(), "
", FALSE); $this->addButtons(array( array( @@ -139,9 +156,6 @@ class CRM_Contribute_Form_Task_PDFLetter extends CRM_Contribute_Form_Task { * @return void */ public function postProcess() { - // TODO: rewrite using contribution token and one letter by contribution - $this->setContactIDs(); - CRM_Contribute_Form_Task_PDFLetterCommon::postProcess($this); } } diff --git a/CRM/Contribute/Form/Task/PDFLetterCommon.php b/CRM/Contribute/Form/Task/PDFLetterCommon.php index cdb34c43a0..ad411f8eb1 100644 --- a/CRM/Contribute/Form/Task/PDFLetterCommon.php +++ b/CRM/Contribute/Form/Task/PDFLetterCommon.php @@ -14,98 +14,94 @@ class CRM_Contribute_Form_Task_PDFLetterCommon extends CRM_Contact_Form_Task_PDF * @return void */ static function postProcess(&$form) { - list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($form); - + if(!empty($formValues['email_options'])) { + $returnProperties['email'] = $returnProperties['on_hold'] = $returnProperties['is_deceased'] = $returnProperties['do_not_email'] = 1; + $emailParams = array( + 'subject' => $formValues['subject'] + ); + $isPDF = FALSE; + if(stristr($formValues['email_options'], 'pdfemail')) { + $isPDF = TRUE; + } + } // update dates ? $receipt_update = isset($formValues['receipt_update']) ? $formValues['receipt_update'] : FALSE; $thankyou_update = isset($formValues['thankyou_update']) ? $formValues['thankyou_update'] : FALSE; $nowDate = date('YmdHis'); - $receipts = 0; - $thanks = 0; + $receipts = $thanks = $emailed = 0; $updateStatus = ''; + $task = 'CRM_Contribution_Form_Task_PDFLetterCommon'; + $realSeparator = ', '; + //the original thinking was mutliple options - but we are going with only 2 (comma & td) for now in case + // there are security (& UI) issues we need to think through + if(isset($formValues['group_by_separator'])) { + if($formValues['group_by_separator'] == 'td') { + $realSeparator = ""; + } + } + $separator = '****~~~~';// a placeholder in case the separator is common in the string - e.g ', ' + + $groupBy = $formValues['group_by']; // skip some contacts ? $skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE; $skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE; - $contributionIDs = $form->getVar('_contributionIds'); - if ($form->_includesSoftCredits) { - $contributionIDs = $form->getVar('_contributionContactIds'); - } - - foreach ($contributionIDs as $item => $contributionId) { - // get contact information - if ($form->_includesSoftCredits) { - list($contactId) = explode('-', $item); - $contactId = (int) $contactId; - } else { - $contactId = civicrm_api("Contribution", "getvalue", array('version' => '3', 'id' => $contributionId, 'return' => 'contact_id')); - } - $params = array('contact_id' => $contactId); - - list($contact) = CRM_Utils_Token::getTokenDetails($params, - $returnProperties, - $skipOnHold, - $skipDeceased, - NULL, - $messageToken, - 'CRM_Contribution_Form_Task_PDFLetterCommon' - ); - if (civicrm_error($contact)) { - $notSent[] = $contributionId; - continue; + list($notSent, $contributions, $contacts) = self::buildContributionArray($groupBy, $form, $returnProperties, $skipOnHold, $skipDeceased, $messageToken, $task, $separator); + $html = array(); + foreach ($contributions as $contributionId => $contribution) { + $contact = &$contacts[$contribution['contact_id']]; + $grouped = $groupByID = 0; + if($groupBy) { + $groupByID = empty($contribution[$groupBy]) ? 0 : $contribution[$groupBy]; + $contribution = $contact['combined'][$groupBy][$groupByID]; + $grouped = TRUE; } - // get contribution information - $params = array('contribution_id' => $contributionId); - $contribution = CRM_Utils_Token::getContributionTokenDetails($params, - $returnProperties, - NULL, - $messageToken, - 'CRM_Contribution_Form_Task_PDFLetterCommon' - ); - if (civicrm_error($contribution)) { - $notSent[] = $contributionId; - continue; - } - - $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken); - $tokenHtml = CRM_Utils_Token::replaceContributionTokens($tokenHtml, $contribution[$contributionId], TRUE, $messageToken); - $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $categories, TRUE); + self::assignCombinedContributionValues($contact, $contributions, $groupBy, $groupByID); - if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) { - $smarty = CRM_Core_Smarty::singleton(); - // also add the tokens to the template - $smarty->assign_by_ref('contact', $contact); - $tokenHtml = $smarty->fetch("string:$tokenHtml"); + if(empty($groupBy) || empty($contact['is_sent'][$groupBy][$groupByID])) { + $html[$contributionId] = str_replace($separator, $realSeparator, self::resolveTokens($html_message, $contact, $contribution, $messageToken, $html, $categories, $grouped, $separator)); + $contact['is_sent'][$groupBy][$groupByID] = TRUE; + if(!empty($formValues['email_options'])) { + if(self::emailLetter($contact, $html[$contributionId], $isPDF, $formValues, $emailParams)) { + $emailed ++; + if(!stristr($formValues['email_options'], 'both')) { + unset($html[$contributionId]); + } + } + } } - $html[] = $tokenHtml; - // update dates (do it for each contribution including grouped recurring contribution) + //@todo - the 2 calls below bypass all hooks. Using the api would possibly be slower than one call but not than 2 if ($receipt_update) { $result = CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'receipt_date', $nowDate); - // We can't use CRM_Core_Error::fatal here because the api error elevates the exception level. FIXME. dgg if ($result) { $receipts++; - } + } } if ($thankyou_update) { $result = CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'thankyou_date', $nowDate); - // We can't use CRM_Core_Error::fatal here because the api error elevates the exception level. FIXME. dgg if ($result) { $thanks++; + } } } - } - + //createActivities requires both $form->_contactIds and $contacts - + //@todo - figure out why + $form->_contactIds = array_keys($contacts); self::createActivities($form, $html_message, $form->_contactIds); - - CRM_Utils_PDF_Utils::html2pdf($html, "CiviLetter.pdf", FALSE, $formValues); + if(!empty($html)) { + CRM_Utils_PDF_Utils::html2pdf($html, "CiviLetter.pdf", FALSE, $formValues); + } $form->postProcessHook(); + if ($emailed) { + $updateStatus = ts('Receipts have been emailed to %1 contributions.', array(1 => $emailed)); + } if ($receipts) { $updateStatus = ts('Receipt date has been updated for %1 contributions.', array(1 => $receipts)); } @@ -116,9 +112,194 @@ class CRM_Contribute_Form_Task_PDFLetterCommon extends CRM_Contact_Form_Task_PDF if ($updateStatus) { CRM_Core_Session::setStatus($updateStatus); } + if(!empty($html)) { + // ie. we have only sent emails - lets no show a white screen + CRM_Utils_System::civiExit(1); + } + } - CRM_Utils_System::civiExit(1); +/** + * @param contact + * @param smarty + * @param html + * + + /** + * + * @param unknown $html_message + * @param array $contact + * @param array $contribution + * @param array $messageToken + * @param string $html + * @param array $categories + * @param bool $grouped Does this letter represent more than one contribution + * @param string $separator What is the preferred letter separator + * @return string + */ + private static function resolveTokens($html_message, $contact, $contribution, $messageToken, $html, $categories, $grouped, $separator) { + $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact, TRUE, $messageToken); + if($grouped) { + $tokenHtml = CRM_Utils_Token::replaceMultipleContributionTokens($separator, $tokenHtml, $contribution, TRUE, $messageToken); + } + else { + // no change to normal behaviour to avoid risk of breakage + $tokenHtml = CRM_Utils_Token::replaceContributionTokens($tokenHtml, $contribution, TRUE, $messageToken); + } + $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact, $categories, TRUE); + if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) { + $smarty = CRM_Core_Smarty::singleton(); + // also add the tokens to the template + $smarty->assign_by_ref('contact', $contact); + $tokenHtml = $smarty->fetch("string:$tokenHtml"); + } + return $tokenHtml; + } + + /** + * Generate the contribution array from the form, we fill in the contact details and determine any aggregation + * around contact_id of contribution_recur_id + * + * @param unknown $groupBy + * @param unknown $form + * @param unknown $returnProperties + * @param unknown $skipOnHold + * @param unknown $skipDeceased + * @param unknown $messageToken + * @param unknown $task + * @return multitype:Ambigous multitype:unknown multitype: + */ + static function buildContributionArray($groupBy, $form, $returnProperties, $skipOnHold, $skipDeceased, $messageToken, $task, $separator) { + $contributions = $contacts = $notSent = array(); + $contributionIDs = $form->getVar('_contributionIds'); + if ($form->_includesSoftCredits) { + //@todo - comment on what is stored there + $contributionIDs = $form->getVar('_contributionContactIds'); + } + foreach ($contributionIDs as $item => $contributionId) { + try { + // get contribution information + $params = array('contribution_id' => $contributionId); + $contribution = CRM_Utils_Token::getContributionTokenDetails(array('contribution_id' => $contributionId), + $returnProperties, + NULL, + $messageToken, + $task + ); + $contribution = $contributions[$contributionId] = $contribution[$contributionId]; + if ($form->_includesSoftCredits) { + //@todo find out why this happens & add comments + list($contactID) = explode('-', $item); + $contactID = (int) $contactId; + } else { + $contactID = $contribution['contact_id']; + } + if(!isset($contacts[$contactID])) { + list($contact) = CRM_Utils_Token::getTokenDetails(array('contact_id' => $contactID), + $returnProperties, + $skipOnHold, + $skipDeceased, + NULL, + $messageToken, + $task + ); + $contacts[$contactID] = $contact[$contactID]; + $contacts[$contactID]['contact_aggregate'] = 0; + $contacts[$contactID]['combined'] = $contacts[$contactID]['contribution_ids'] = array(); + } + + $contacts[$contactID]['contact_aggregate'] += $contribution['total_amount']; + $groupByID = empty($contribution[$groupBy]) ? 0 : $contribution[$groupBy]; + + $contacts[$contactID]['contribution_ids'][$groupBy][$groupByID][$contributionId] = TRUE; + if(!isset($contacts[$contactID]['combined'][$groupBy]) || isset($contacts[$contactID]['combined'][$groupByID])) { + $contacts[$contactID]['combined'][$groupBy][$groupByID] = $contribution; + $contacts[$contactID]['aggregates'][$groupBy][$groupByID] = $contribution['total_amount']; + } + else { + $contacts[$contactID]['combined'][$groupBy][$groupByID] = self::combineContributions($contacts[$contactID]['combined'][$groupBy][$groupByID], $contribution, $separator); + $contacts[$contactID]['aggregates'][$groupBy][$groupByID] += $contribution['total_amount']; + } + } + catch(Exception $e) { + $notSent[] = $contributionId; + } + } + return array($notSent, $contributions, $contacts); + } + + /** + * We combine the contributions by adding the contribution to each field with the separator in + * between the existing value and the new one. We put the separator there even if empty so it is clear what the + * value for previous contributions was + * @param unknown $existing + * @param unknown $contribution + * @param unknown $separator + */ + static function combineContributions($existing, $contribution, $separator) { + foreach ($contribution as $field => $value) { + if(!isset($existing[$field])) { + $existing[$field] = ''; + } + $existing[$field] .= $separator . $value; + } + return $existing; + } + + /** + * We are going to retrieve the combined contribution and if smarty mail is enabled we + * will also assign an array of contributions for this contact to the smarty template + * @param array $contact + * @param array $contributions + */ + static function assignCombinedContributionValues($contact, $contributions, $groupBy, $groupByID) { + if (!defined('CIVICRM_MAIL_SMARTY') || !CIVICRM_MAIL_SMARTY) { + return; + } + CRM_Core_Smarty::singleton()->assign('contact_aggregate', $contact['contact_aggregate']); + CRM_Core_Smarty::singleton()->assign('contributions', array_intersect_key($contributions, $contact['contribution_ids'][$groupBy][$groupByID])); + CRM_Core_Smarty::singleton()->assign('contribution_aggregate', $contact['aggregates'][$groupBy][$groupByID]); + + } + + /** + * Send pdf by email + * @param array $contact + * @param string $html + */ + static function emailLetter($contact, $html, $is_pdf, $format = array(), $params = array()) { + try { + if(empty($contact['email'])) { + return FALSE; + } + $mustBeEmpty = array('do_not_email', 'is_deceased', 'on_hold'); + foreach ($mustBeEmpty as $emptyField) { + if(!empty($contact[$emptyField])) { + return FALSE; + } + } + + $defaults = array( + 'toName' => $contact['display_name'], + 'toEmail' => $contact['email'], + 'subject' => ts('Thank you for your contribution/s'), + 'text' => '', + 'html' => $html, + ); + if(empty($params['from'])) { + $emails = CRM_Core_BAO_Email::getFromEmail(); + $emails = array_keys($emails); + $defaults['from'] = array_pop($emails); + } + if($is_pdf) { + $defaults['html'] = ts('Please see attached'); + $defaults['attachments'] = array(CRM_Utils_Mail::appendPDF('ThankYou.pdf', $html, $format)); + } + $params = array_merge($defaults); + return CRM_Utils_Mail::send($params); + } + catch (CRM_Core_Exception $e) { + return FALSE; + } } - //end of function } diff --git a/CRM/Core/BAO/MessageTemplate.php b/CRM/Core/BAO/MessageTemplate.php index a0a8fa8f3c..761e8f51c7 100644 --- a/CRM/Core/BAO/MessageTemplate.php +++ b/CRM/Core/BAO/MessageTemplate.php @@ -493,29 +493,10 @@ class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate { $params['PDFFilename'] && $params['html'] ) { - $pdf_filename = $config->templateCompileDir . CRM_Utils_File::makeFileName($params['PDFFilename']); - - //FIXME : CRM-7894 - //xmlns attribute is required in XHTML but it is invalid in HTML, - //Also the namespace "xmlns=http://www.w3.org/1999/xhtml" is default, - //and will be added to the tag even if you do not include it. - $html = preg_replace('/()/', '\1\3\4', $params['html']); - - file_put_contents($pdf_filename, CRM_Utils_PDF_Utils::html2pdf($html, - $params['PDFFilename'], - TRUE, - $format - ) - ); - if (empty($params['attachments'])) { $params['attachments'] = array(); } - $params['attachments'][] = array( - 'fullPath' => $pdf_filename, - 'mime_type' => 'application/pdf', - 'cleanName' => $params['PDFFilename'], - ); + $params['attachments'][] = CRM_Utils_Mail::appendPDF($params['PDFFilename'], $params['html'], $format); } $sent = CRM_Utils_Mail::send($params); diff --git a/CRM/Utils/Mail.php b/CRM/Utils/Mail.php index 2cbc939fd9..260daea200 100644 --- a/CRM/Utils/Mail.php +++ b/CRM/Utils/Mail.php @@ -166,7 +166,7 @@ class CRM_Utils_Mail { // Mail_smtp and Mail_sendmail mailers require Bcc anc Cc emails // be included in both $to and $headers['Cc', 'Bcc'] if (get_class($mailer) != "Mail_mail") { - //get emails from headers, since these are + //get emails from headers, since these are //combination of name and email addresses. if (!empty($headers['Cc'])) { $to[] = CRM_Utils_Array::value( 'Cc', $headers ); @@ -363,5 +363,34 @@ class CRM_Utils_Mail { return $name; } + + /** + * + * @param string $fileName + * @param string $html + * @param string $format + * + * @return array $attachments + */ + static function appendPDF($fileName, $html, $format = NULL) { + $pdf_filename = CRM_Core_Config::singleton()->templateCompileDir . CRM_Utils_File::makeFileName($fileName); + + //FIXME : CRM-7894 + //xmlns attribute is required in XHTML but it is invalid in HTML, + //Also the namespace "xmlns=http://www.w3.org/1999/xhtml" is default, + //and will be added to the tag even if you do not include it. + $html = preg_replace('/()/', '\1\3\4', $html); + + file_put_contents($pdf_filename, CRM_Utils_PDF_Utils::html2pdf($html, + $fileName, + TRUE, + $format) + ); + return array( + 'fullPath' => $pdf_filename, + 'mime_type' => 'application/pdf', + 'cleanName' => $fileName, + ); + } } diff --git a/CRM/Utils/Token.php b/CRM/Utils/Token.php index 60961b910e..605405c524 100644 --- a/CRM/Utils/Token.php +++ b/CRM/Utils/Token.php @@ -1197,6 +1197,7 @@ class CRM_Utils_Token { $tokens = array(), $className = NULL ) { + //@todo - this function basically replications calling civicrm_api3('contribution', 'get', array('id' => array('IN' => array()) if (empty($contributionIDs)) { // putting a fatal here so we can track if/when this happens CRM_Core_Error::fatal(); @@ -1416,17 +1417,26 @@ class CRM_Utils_Token { return $str; } - public static function &replaceContributionTokens($str, &$contribution, $html = FALSE, $knownTokens = NULL, $escapeSmarty = FALSE) { + /** + * Replace Contribution tokens in html + * @param unknown $str + * @param unknown $contribution + * @param string $html + * @param string $knownTokens + * @param string $escapeSmarty + * @return unknown|Ambigous |mixed + */ + public static function replaceContributionTokens($str, &$contribution, $html = FALSE, $knownTokens = NULL, $escapeSmarty = FALSE) { + $key = 'contribution'; + if (!$knownTokens || !CRM_Utils_Array::value($key, $knownTokens)) { + return $str; //early return + } self::_buildContributionTokens(); // here we intersect with the list of pre-configured valid tokens // so that we remove anything we do not recognize // I hope to move this step out of here soon and // then we will just iterate on a list of tokens that are passed to us - $key = 'contribution'; - if (!$knownTokens || empty($knownTokens[$key])) { - return $str; - } $str = preg_replace_callback( self::tokenRegex($key), @@ -1440,6 +1450,40 @@ class CRM_Utils_Token { return $str; } + /** + * We have a situation where we are rendering more than one token in each field because we are combining + * tokens from more than one contribution when pdf thank you letters are grouped (CRM-14367) + * + * The replaceContributionToken doesn't handle receive_date correctly in this scenario because of the formatting + * it applies (other tokens are OK including date fields) + * + * So we sort this out & then call the main function. Note that we are not escaping smarty on this fields like the main function + * does - but the fields is already being formatted through a date function + * + * @param string $separator + * @param string $str + * @param array $contribution + * @param string $html + * @param string $knownTokens + * @param string $escapeSmarty + */ + public static function replaceMultipleContributionTokens($separator, $str, &$contribution, $html = FALSE, $knownTokens = NULL, $escapeSmarty = FALSE) { + if(empty($knownTokens['contribution'])) { + return $str; + } + + if(in_array('receive_date', $knownTokens['contribution'])) { + $formattedDates = array(); + $dates = explode($separator, $contribution['receive_date']); + foreach ($dates as $date) { + $formattedDates[] = CRM_Utils_Date::customFormat($date, NULL, array('j', 'm', 'Y')); + } + $str = str_replace("{contribution.receive_date}", implode($separator, $formattedDates), $str); + unset($knownTokens['contribution']['receive_date']); + } + return self::replaceContributionTokens($str, $contribution, $html, $knownTokens, $escapeSmarty); + } + /** * Get replacement strings for any membership tokens (only a small number of tokens are implemnted in the first instance * - this is used by the pdfLetter task from membership search diff --git a/templates/CRM/Contribute/Form/Task/PDFLetter.hlp b/templates/CRM/Contribute/Form/Task/PDFLetter.hlp new file mode 100644 index 0000000000..11124c01eb --- /dev/null +++ b/templates/CRM/Contribute/Form/Task/PDFLetter.hlp @@ -0,0 +1,48 @@ +{* + +--------------------------------------------------------------------+ + | CiviCRM version 4.5 | + +--------------------------------------------------------------------+ + | Copyright CiviCRM LLC (c) 2004-2014 | + +--------------------------------------------------------------------+ + | This file is a part of CiviCRM. | + | | + | CiviCRM is free software; you can copy, modify, and distribute it | + | under the terms of the GNU Affero General Public License | + | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. | + | | + | CiviCRM is distributed in the hope that it will be useful, but | + | WITHOUT ANY WARRANTY; without even the implied warranty of | + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | + | See the GNU Affero General Public License for more details. | + | | + | You should have received a copy of the GNU Affero General Public | + | License and the CiviCRM Licensing Exception along | + | with this program; if not, contact CiviCRM LLC | + | at info[AT]civicrm[DOT]org. If you have questions about the | + | GNU Affero General Public License or the licensing of CiviCRM, | + | see the CiviCRM license FAQ at http://civicrm.org/licensing | + +--------------------------------------------------------------------+ +*} + +{htxt id="id-contribution-grouping-title"} + {ts}Contribution Grouping{/ts} +{/htxt} +{htxt id="id-contribution-grouping"} +

{ts}You can choose to show contribution data for multiple contributions from the same contact in one location + in the body of your letter. This option can be useful for end-of-year thank-you letters, or other situations where + you want to acknowledge multiple gifts.{/ts}

+

{ts}If you use this option, you may want to use a table layout to format the output from the contribution token(s). + In this case select the 'Table Cell' separator, and each contribution instance will be placed in it's own table + cell. Alternatively, you can use the simple 'Comma' separator which will simply separate the contribution amounts + and / or dates with commas (e.g. 'Thank you for your generous contributions of $150.00, $200.00, $450.00 this year.').{/ts} +

+{/htxt} + +{htxt id="id-contribution-email-print-title"} + {ts}Print and Email Options{/ts} +{/htxt} +{htxt id="id-contribution-email-print"} +

{ts}You can choose to send thank-you letters as emails to contacts who are able to receive email. If you + choose to do this, you can also decide whether to only print PDF's for the remaining contacts OR generate PDF's for + all.{/ts}

+{/htxt} diff --git a/templates/CRM/Contribute/Form/Task/PDFLetter.tpl b/templates/CRM/Contribute/Form/Task/PDFLetter.tpl index 277540c898..5b1fa6a233 100644 --- a/templates/CRM/Contribute/Form/Task/PDFLetter.tpl +++ b/templates/CRM/Contribute/Form/Task/PDFLetter.tpl @@ -37,7 +37,18 @@ - + + + + + + + + + + + +
{$form.thankyou_update.html} {$form.thankyou_update.label}
{$form.receipt_update.html} {$form.receipt_update.label}
{$form.group_by.label} {help id="id-contribution-grouping"}{$form.group_by.html}
{$form.group_by_separator.label}{$form.group_by_separator.html}
{$form.email_options.label} {help id="id-contribution-email-print"}{$form.email_options.html}
-- 2.25.1