--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.3 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2013 |
+ +--------------------------------------------------------------------+
+ | 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 |
+ +--------------------------------------------------------------------+
+*/
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2013
+ * $Id$
+ *
+ */
+
+/**
+ * This class provides the functionality to create PDF letter for a group of
+ * contacts or a single contact.
+ */
+class CRM_Contact_Form_Task_LatexPDF extends CRM_Contact_Form_Task {
+
+ /**
+ * all the existing templates in the system
+ *
+ * @var array
+ */
+ public $_templates = NULL;
+
+ public $_single = NULL;
+
+ public $_cid = NULL;
+
+ public $_activityId = NULL;
+
+ /**
+ * build all the data structures needed to build the form
+ *
+ * @return void
+ * @access public
+ */
+ function preProcess() {
+
+ $this->skipOnHold = $this->skipDeceased = FALSE;
+ CRM_Contact_Form_Task_PDFLatexCommon::preProcess($this);
+
+ // store case id if present
+ $this->_caseId = CRM_Utils_Request::retrieve('caseid', 'Positive', $this, FALSE);
+
+ // retrieve contact ID if this is 'single' mode
+ $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE);
+
+ if ($cid) {
+ // this is true in non-search context / single mode
+ // in search context 'id' is the default profile id for search display
+ // CRM-11227
+ $this->_activityId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE);
+ }
+
+ if ($cid) {
+ CRM_Contact_Form_Task_PDFLatexCommon::preProcessSingle($this, $cid);
+ $this->_single = TRUE;
+ $this->_cid = $cid;
+ }
+ else {
+ parent::preProcess();
+ }
+ $this->assign('single', $this->_single);
+ }
+
+ function setDefaultValues() {
+ $defaults = array();
+ if (isset($this->_activityId)) {
+ $params = array('id' => $this->_activityId);
+ CRM_Activity_BAO_Activity::retrieve($params, $defaults);
+ $defaults['html_message'] = CRM_Utils_Array::value('details', $defaults);
+ }
+ $defaults = $defaults + CRM_Contact_Form_Task_PDFLatexCommon::setDefaultValues();
+ return $defaults;
+ }
+
+ /**
+ * Build the form
+ *
+ * @access public
+ *
+ * @return void
+ */
+ public function buildQuickForm() {
+ //enable form element
+ $this->assign('suppressForm', FALSE);
+ CRM_Contact_Form_Task_PDFLatexCommon::buildQuickForm($this);
+ }
+
+ /**
+ * process the form after the input has been submitted and validated
+ *
+ * @access public
+ *
+ * @return None
+ */
+ public function postProcess() {
+ CRM_Contact_Form_Task_PDFLatexCommon::postProcess($this);
+ }
+}
+
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.3 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2013 |
+ +--------------------------------------------------------------------+
+ | 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 |
+ +--------------------------------------------------------------------+
+*/
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2013
+ * $Id$
+ *
+ */
+
+/**
+ * This class provides the common functionality for creating PDF letter for
+ * one or a group of contact ids.
+ */
+class CRM_Contact_Form_Task_PDFLatexCommon {
+
+ /**
+ * build all the data structures needed to build the form
+ *
+ * @return void
+ * @access public
+ */
+ static function preProcess(&$form) {
+ $messageText = array();
+ $messageSubject = array();
+ $dao = new CRM_Core_BAO_MessageTemplates();
+ $dao->is_active = 1;
+ $dao->find();
+ while ($dao->fetch()) {
+ $messageText[$dao->id] = $dao->msg_text;
+ $messageSubject[$dao->id] = $dao->msg_subject;
+ }
+
+ $form->assign('message', $messageText);
+ $form->assign('messageSubject', $messageSubject);
+ }
+
+ static function preProcessSingle(&$form, $cid) {
+ $form->_contactIds = array($cid);
+ // put contact display name in title for single contact mode
+ CRM_Contact_Page_View::setTitle($cid);
+ }
+
+ /**
+ * Build the form
+ *
+ * @access public
+ *
+ * @return void
+ */
+ static function buildQuickForm(&$form) {
+ $form->add('static', 'pdf_format_header', NULL, ts('Page Format'));
+ $form->add(
+ 'select',
+ 'format_id',
+ ts('Select Format'),
+ array(0 => ts('- default -')) + CRM_Core_BAO_PdfFormat::getList(TRUE),
+ FALSE,
+ array('onChange' => "selectFormat( this.value, false );")
+ );;
+ $form->add(
+ 'select',
+ 'paper_size',
+ ts('Paper Size'),
+ array(0 => ts('- default -')) + CRM_Core_BAO_PaperSize::getList(TRUE),
+ FALSE,
+ array('onChange' => "selectPaper( this.value ); showUpdateFormatChkBox();")
+ );
+ $form->add('static', 'paper_dimensions', NULL, ts('Width x Height'));
+ $form->add(
+ 'select',
+ 'orientation',
+ ts('Orientation'),
+ CRM_Core_BAO_PdfFormat::getPageOrientations(),
+ FALSE,
+ array('onChange' => "updatePaperDimensions(); showUpdateFormatChkBox();")
+ );
+ $form->add(
+ 'select',
+ 'metric',
+ ts('Unit of Measure'),
+ CRM_Core_BAO_PdfFormat::getUnits(),
+ FALSE,
+ array('onChange' => "selectMetric( this.value );")
+ );
+ $form->add(
+ 'text',
+ 'margin_left',
+ ts('Left Margin'),
+ array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
+ TRUE
+ );
+ $form->add(
+ 'text',
+ 'margin_right',
+ ts('Right Margin'),
+ array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
+ TRUE
+ );
+ $form->add(
+ 'text',
+ 'margin_top',
+ ts('Top Margin'),
+ array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
+ TRUE
+ );
+ $form->add(
+ 'text',
+ 'margin_bottom',
+ ts('Bottom Margin'),
+ array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
+ TRUE
+ );
+ $form->add('checkbox', 'bind_format', ts('Always use this Page Format with the selected Template'));
+ $form->add('checkbox', 'update_format', ts('Update Page Format (this will affect all templates that use this format)'));
+
+ $form->assign('useThisPageFormat', ts('Always use this Page Format with the new template?'));
+ $form->assign('useSelectedPageFormat', ts('Should the new template always use the selected Page Format?'));
+ $form->assign('totalSelectedContacts', count($form->_contactIds));
+
+ CRM_Mailing_BAO_Mailing::commonLetterCompose($form);
+
+ if ($form->_single) {
+ $cancelURL = CRM_Utils_System::url(
+ 'civicrm/contact/view',
+ "reset=1&cid={$form->_cid}&selectedChild=activity",
+ FALSE,
+ NULL,
+ FALSE
+ );
+ if ($form->get('action') == CRM_Core_Action::VIEW) {
+ $form->addButtons(array(
+ array(
+ 'type' => 'cancel',
+ 'name' => ts('Done'),
+ 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"),
+ ),
+ )
+ );
+ }
+ else {
+ $form->addButtons(array(
+ array(
+ 'type' => 'submit',
+ 'name' => ts('Make PDF Letter'),
+ 'isDefault' => TRUE,
+ ),
+ array(
+ 'type' => 'cancel',
+ 'name' => ts('Done'),
+ 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"),
+ ),
+ )
+ );
+ }
+ }
+ else {
+ $form->addDefaultButtons(ts('Make PDF Letters'));
+ }
+
+ $form->addFormRule(array('CRM_Contact_Form_Task_PDFLatexCommon', 'formRule'), $form);
+ }
+
+ /**
+ * Set default values
+ */
+ static function setDefaultValues() {
+ $defaultFormat = CRM_Core_BAO_PdfFormat::getDefaultValues();
+ $defaultFormat['format_id'] = $defaultFormat['id'];
+ return $defaultFormat;
+ }
+
+ /**
+ * form rule
+ *
+ * @param array $fields the input form values
+ * @param array $dontCare
+ * @param array $self additional values form 'this'
+ *
+ * @return true if no errors, else array of errors
+ * @access public
+ *
+ */
+ static function formRule($fields, $dontCare, $self) {
+ $errors = array();
+ $template = CRM_Core_Smarty::singleton();
+
+ //Added for CRM-1393
+ if (CRM_Utils_Array::value('saveTemplate', $fields) && empty($fields['saveTemplateName'])) {
+ $errors['saveTemplateName'] = ts("Enter name to save message template");
+ }
+ if (!is_numeric($fields['margin_left'])) {
+ $errors['margin_left'] = 'Margin must be numeric';
+ }
+ if (!is_numeric($fields['margin_right'])) {
+ $errors['margin_right'] = 'Margin must be numeric';
+ }
+ if (!is_numeric($fields['margin_top'])) {
+ $errors['margin_top'] = 'Margin must be numeric';
+ }
+ if (!is_numeric($fields['margin_bottom'])) {
+ $errors['margin_bottom'] = 'Margin must be numeric';
+ }
+ return empty($errors) ? TRUE : $errors;
+ }
+
+ /**
+ * part of the post process which prepare and extract information from the template
+ *
+ * @access protected
+ *
+ * @return array( $categories, $html_message, $messageToken, $returnProperties )
+ */
+ static protected function processMessageTemplate(&$form) {
+ $formValues = $form->controller->exportValues($form->getName());
+
+ // process message template
+ if (CRM_Utils_Array::value('saveTemplate', $formValues) || CRM_Utils_Array::value('updateTemplate', $formValues)) {
+ $messageTemplate = array(
+ 'msg_text' => NULL,
+ 'msg_html' => $formValues['html_message'],
+ 'msg_subject' => NULL,
+ 'is_active' => TRUE,
+ );
+
+ $messageTemplate['pdf_format_id'] = 'null';
+ if (CRM_Utils_Array::value('bind_format', $formValues) && $formValues['format_id'] > 0) {
+ $messageTemplate['pdf_format_id'] = $formValues['format_id'];
+ }
+ if (CRM_Utils_Array::value('saveTemplate', $formValues) && $formValues['saveTemplate']) {
+ $messageTemplate['msg_title'] = $formValues['saveTemplateName'];
+ CRM_Core_BAO_MessageTemplates::add($messageTemplate);
+ }
+
+ if (CRM_Utils_Array::value('updateTemplate', $formValues) && $formValues['template'] && $formValues['updateTemplate']) {
+ $messageTemplate['id'] = $formValues['template'];
+
+ unset($messageTemplate['msg_title']);
+ CRM_Core_BAO_MessageTemplates::add($messageTemplate);
+ }
+ }
+ elseif (CRM_Utils_Array::value('template', $formValues) > 0) {
+ if (CRM_Utils_Array::value('bind_format', $formValues) && $formValues['format_id'] > 0) {
+ $query = "UPDATE civicrm_msg_template SET pdf_format_id = {$formValues['format_id']} WHERE id = {$formValues['template']}";
+ }
+ else {
+ $query = "UPDATE civicrm_msg_template SET pdf_format_id = NULL WHERE id = {$formValues['template']}";
+ }
+ CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray);
+ }
+ if (CRM_Utils_Array::value('update_format', $formValues)) {
+ $bao = new CRM_Core_BAO_PdfFormat();
+ $bao->savePdfFormat($formValues, $formValues['format_id']);
+ }
+
+ $html = array();
+
+ $tokens = array();
+ CRM_Utils_Hook::tokens($tokens);
+ $categories = array_keys($tokens);
+
+ $html_message = $formValues['html_message'];
+
+ //time being hack to strip ' '
+ //from particular letter line, CRM-6798
+ self::formatMessage($html_message);
+
+ $messageToken = CRM_Utils_Token::getTokens($html_message);
+
+ $returnProperties = array();
+ if (isset($messageToken['contact'])) {
+ foreach ($messageToken['contact'] as $key => $value) {
+ $returnProperties[$value] = 1;
+ }
+ }
+
+ return array($formValues, $categories, $html_message, $messageToken, $returnProperties);
+ }
+
+ /**
+ * process the form after the input has been submitted and validated
+ *
+ * @access public
+ *
+ * @return None
+ */
+ static function postProcess(&$form) {
+ list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($form);
+
+ $skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE;
+ $skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE;
+
+ foreach ($form->_contactIds as $item => $contactId) {
+ $params = array('contact_id' => $contactId);
+
+ list($contact) = CRM_Utils_Token::getTokenDetails($params,
+ $returnProperties,
+ $skipOnHold,
+ $skipDeceased,
+ NULL,
+ $messageToken,
+ 'CRM_Contact_Form_Task_PDFLatexCommon'
+ );
+ if (civicrm_error($contact)) {
+ $notSent[] = $contactId;
+ continue;
+ }
+
+ $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken);
+ $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $categories, TRUE);
+
+ if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) {
+ $smarty = CRM_Core_Smarty::singleton();
+ // also add the contact tokens to the template
+ $smarty->assign_by_ref('contact', $contact);
+ $tokenHtml = $smarty->fetch("string:$tokenHtml");
+ }
+
+ $html[] = $tokenHtml;
+ }
+
+ self::createActivities($form, $html_message, $form->_contactIds);
+
+ CRM_Utils_PDF_Utils::latex2pdf($html, "CiviLatex.pdf", FALSE, $formValues);
+
+ $form->postProcessHook();
+
+ CRM_Utils_System::civiExit(1);
+ }
+
+ function createActivities($form, $html_message, $contactIds) {
+
+ $session = CRM_Core_Session::singleton();
+ $userID = $session->get('userID');
+ $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type',
+ 'Print PDF LaTeX Letter',
+ 'name'
+ );
+ $activityParams = array(
+ 'source_contact_id' => $userID,
+ 'activity_type_id' => $activityTypeID,
+ 'activity_date_time' => date('YmdHis'),
+ 'details' => $html_message,
+ );
+ if (!empty($form->_activityId)) {
+ $activityParams += array('id' => $form->_activityId);
+ }
+ if ($form->_cid) {
+ $activity = CRM_Activity_BAO_Activity::create($activityParams);
+ }
+ else {
+ // create Print PDF activity for each selected contact. CRM-6886
+ $activityIds = array();
+ foreach ($contactIds as $contactId) {
+ $activityID = CRM_Activity_BAO_Activity::create($activityParams);
+ $activityIds[$contactId] = $activityID->id;
+ }
+ }
+
+ foreach ($form->_contactIds as $contactId) {
+ $activityTargetParams = array(
+ 'activity_id' => empty($activity->id) ? $activityIds[$contactId] : $activity->id,
+ 'target_contact_id' => $contactId,
+ );
+ CRM_Activity_BAO_Activity::createActivityTarget($activityTargetParams);
+ }
+ }
+
+ function formatMessage(&$message) {
+ $newLineOperators = array(
+ 'p' => array(
+ 'oper' => '<p>',
+ 'pattern' => '/<(\s+)?p(\s+)?>/m',
+ ),
+ 'br' => array(
+ 'oper' => '<br />',
+ 'pattern' => '/<(\s+)?br(\s+)?\/>/m',
+ ),
+ );
+
+ $htmlMsg = preg_split($newLineOperators['p']['pattern'], $message);
+ foreach ($htmlMsg as $k => & $m) {
+ $messages = preg_split($newLineOperators['br']['pattern'], $m);
+ foreach ($messages as $key => & $msg) {
+ $msg = trim($msg);
+ $matches = array();
+ if (preg_match('/^( )+/', $msg, $matches)) {
+ $spaceLen = strlen($matches[0]) / 6;
+ $trimMsg = ltrim($msg, ' ');
+ $charLen = strlen($trimMsg);
+ $totalLen = $charLen + $spaceLen;
+ if ($totalLen > 100) {
+ $spacesCount = 10;
+ if ($spaceLen > 50) {
+ $spacesCount = 20;
+ }
+ if ($charLen > 100) {
+ $spacesCount = 1;
+ }
+ $msg = str_repeat(' ', $spacesCount) . $trimMsg;
+ }
+ }
+ }
+ $m = implode($newLineOperators['br']['oper'], $messages);
+ }
+ $message = implode($newLineOperators['p']['oper'], $htmlMsg);
+ }
+}
+
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.4 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2013 |
+ +--------------------------------------------------------------------+
+ | 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 |
+ +--------------------------------------------------------------------+
+*/
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2013
+ * $Id$
+ *
+ */
+
+/**
+ * This class provides the functionality to create PDF letter for a group of
+ * contacts or a single contact.
+ */
+class CRM_Contribute_Form_Task_PDFLatex extends CRM_Contribute_Form_Task {
+
+ /**
+ * all the existing templates in the system
+ *
+ * @var array
+ */
+ public $_templates = NULL;
+
+ public $_single = NULL;
+
+ public $_cid = NULL;
+
+ /**
+ * build all the data structures needed to build the form
+ *
+ * @return void
+ * @access public
+ */
+ 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);
+
+ // retrieve contact ID if this is 'single' mode
+ $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE);
+
+ $this->_activityId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE);
+
+ if ($cid) {
+ CRM_Contact_Form_Task_PDFLetterCommon::preProcessSingle($this, $cid);
+ $this->_single = TRUE;
+ $this->_cid = $cid;
+ }
+ else {
+ parent::preProcess();
+ }
+ $this->assign('single', $this->_single);
+ }
+
+ function setDefaultValues() {
+ $defaults = array();
+ if (isset($this->_activityId)) {
+ $params = array('id' => $this->_activityId);
+ CRM_Activity_BAO_Activity::retrieve($params, $defaults);
+ $defaults['html_message'] = $defaults['details'];
+ }
+ $defaults = $defaults + CRM_Contact_Form_Task_PDFLetterCommon::setDefaultValues();
+ return $defaults;
+ }
+
+ /**
+ * Build the form
+ *
+ * @access public
+ *
+ * @return void
+ */
+ public function buildQuickForm() {
+ //enable form element
+ $this->assign('suppressForm', FALSE);
+
+ // use contact form as a base
+ CRM_Contact_Form_Task_PDFLetterCommon::buildQuickForm($this);
+
+ // specific need for contributions
+ $this->add('static', 'more_options_header', NULL, ts('Record Update 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(), "<br/>", FALSE);
+
+ $this->addButtons(array(
+ array(
+ 'type' => 'submit',
+ 'name' => ts('Make Thank-you Letters'),
+ 'isDefault' => TRUE,
+ ),
+ array(
+ 'type' => 'cancel',
+ 'name' => ts('Done'),
+ ),
+ )
+ );
+
+ }
+
+ /**
+ * process the form after the input has been submitted and validated
+ *
+ * @access public
+ *
+ * @return None
+ */
+ public function postProcess() {
+ // TODO: rewrite using contribution token and one letter by contribution
+ $this->setContactIDs();
+
+ CRM_Contribute_Form_Task_PDFLatexCommon::postProcess($this);
+ }
+
+
+}
+
--- /dev/null
+<?php
+
+/**
+ * This class provides the common functionality for creating PDF letter for
+ * one or a group of contact ids.
+ */
+class CRM_Contribute_Form_Task_PDFLatexCommon extends CRM_Contact_Form_Task_PDFLetterCommon {
+
+ /**
+ * process the form after the input has been submitted and validated
+ *
+ * @access public
+ *
+ * @return None
+ */
+ static function postProcess(&$form) {
+
+ list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($form);
+ //CRM_Core_Error::debug_log_message(":2 $html_message"); //OK
+
+ // 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;
+ $updateStatus = '';
+
+ // skip some contacts ?
+ $skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE;
+ $skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE;
+
+ foreach ($form->getVar('_contributionIds') as $item => $contributionId) {
+
+ // get contact information
+ $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;
+ }
+
+ // 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], FALSE, $messageToken);
+ $tokenHtml = CRM_Utils_Token::replaceContributionTokens($tokenHtml, $contribution[$contributionId], TRUE, $messageToken);
+ $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $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");
+ }
+
+ $html[] = $tokenHtml;
+
+ // update dates (do it for each contribution including grouped recurring contribution)
+ 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++;
+ }
+ }
+ }
+
+ self::createActivities($form, $html_message, $form->_contactIds);
+
+ CRM_Utils_PDF_Utils::latex2pdf($html, "CiviLatex.pdf", FALSE, $formValues);
+
+ $form->postProcessHook();
+
+ if ($receipts) {
+ $updateStatus = ts('Receipt date has been updated for %1 contributions.', array(1 => $receipts));
+ }
+ if ($thanks) {
+ $updateStatus .= ' ' . ts('Thank-you date has been updated for %1 contributions.', array(1 => $thanks));
+ }
+
+ if ($updateStatus) {
+ CRM_Core_Session::setStatus($updateStatus);
+ }
+
+ CRM_Utils_System::civiExit(1);
+ }
+ //end of function
+}
+
--- /dev/null
+<?php
+/*
+ * Copyright (C) 2012
+ * Licensed to CiviCRM under the GPL v3 or higher
+ *
+ * Written and contributed by Ward Vandewege <ward@fsf.org> (http://www.fsf.org)
+ *
+ */
+
+require_once 'CRM/Core/Payment.php';
+class CRM_Core_Payment_TrustCommerce extends CRM_Core_Payment {
+ CONST CHARSET = 'iso-8859-1';
+ CONST AUTH_APPROVED = 'approve';
+ CONST AUTH_DECLINED = 'decline';
+ CONST AUTH_BADDATA = 'baddata';
+ CONST AUTH_ERROR = 'error';
+
+ static protected $_mode = NULL;
+
+ static protected $_params = array();
+
+ /**
+ * We only need one instance of this object. So we use the singleton
+ * pattern and cache the instance in this variable
+ *
+ * @var object
+ * @static
+ */
+ static private $_singleton = NULL;
+
+ /**
+ * Constructor
+ *
+ * @param string $mode the mode of operation: live or test
+ *
+ * @return void
+ */ function __construct($mode, &$paymentProcessor) {
+ $this->_mode = $mode;
+
+ $this->_paymentProcessor = $paymentProcessor;
+
+ $this->_processorName = ts('TrustCommerce');
+
+ $config = CRM_Core_Config::singleton();
+ $this->_setParam('user_name', $paymentProcessor['user_name']);
+ $this->_setParam('password', $paymentProcessor['password']);
+
+ $this->_setParam('timestamp', time());
+ srand(time());
+ $this->_setParam('sequence', rand(1, 1000));
+ }
+
+ /**
+ * singleton function used to manage this object
+ *
+ * @param string $mode the mode of operation: live or test
+ *
+ * @return object
+ * @static
+ *
+ */
+ static
+ function &singleton($mode, &$paymentProcessor) {
+ $processorName = $paymentProcessor['name'];
+ if (self::$_singleton[$processorName] === NULL) {
+ self::$_singleton[$processorName] = new CRM_Core_Payment_TrustCommerce($mode, $paymentProcessor);
+ }
+ return self::$_singleton[$processorName];
+ }
+
+ /**
+ * Submit a payment using Advanced Integration Method
+ *
+ * @param array $params assoc array of input parameters for this transaction
+ *
+ * @return array the result in a nice formatted array (or an error object)
+ * @public
+ */
+ function doDirectPayment(&$params) {
+ if (!extension_loaded("tclink")) {
+ return self::error(9001, 'TrustCommerce requires that the tclink module is loaded');
+ }
+
+ /*
+ * recurpayment function does not compile an array & then proces it -
+ * - the tpl does the transformation so adding call to hook here
+ * & giving it a change to act on the params array
+ */
+
+ $newParams = $params;
+ if (CRM_Utils_Array::value('is_recur', $params) &&
+ $params['contributionRecurID']
+ ) {
+ CRM_Utils_Hook::alterPaymentProcessorParams($this,
+ $params,
+ $newParams
+ );
+ }
+ foreach ($newParams as $field => $value) {
+ $this->_setParam($field, $value);
+ }
+
+ if (CRM_Utils_Array::value('is_recur', $params) &&
+ $params['contributionRecurID']
+ ) {
+ return $this->doRecurPayment($params);
+ }
+
+ $postFields = array();
+ $tclink = $this->_getTrustCommerceFields();
+
+ // Set up our call for hook_civicrm_paymentProcessor,
+ // since we now have our parameters as assigned for the AIM back end.
+ CRM_Utils_Hook::alterPaymentProcessorParams($this,
+ $params,
+ $tclink
+ );
+
+ // TrustCommerce will not refuse duplicates, so we should check if the user already submitted this transaction
+ if ($this->_checkDupe($tclink['ticket'])) {
+ return self::error(9004, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. You can try your transaction again. If you continue to have problems please contact the site administrator.');
+ }
+
+ $result = tclink_send($tclink);
+
+ if (!$result) {
+ return self::error(9002, 'Could not initiate connection to payment gateway');
+ }
+
+ foreach ($result as $field => $value) {
+ error_log("result: $field => $value");
+ }
+
+ switch($result['status']) {
+ case self::AUTH_APPROVED:
+ // It's all good
+ break;
+ case self::AUTH_DECLINED:
+ // TODO FIXME be more or less specific?
+ // declinetype can be: decline, avs, cvv, call, expiredcard, carderror, authexpired, fraud, blacklist, velocity
+ // See TC documentation for more info
+ return self::error(9009, "Your transaction was declined: {$result['declinetype']}");
+ break;
+ case self::AUTH_BADDATA:
+ // TODO FIXME do something with $result['error'] and $result['offender']
+ return self::error(9011, "Invalid credit card information. Please re-enter.");
+ break;
+ case self::AUTH_ERROR:
+ return self::error(9002, 'Could not initiate connection to payment gateway');
+ break;
+ }
+
+ // Success
+
+ $params['trxn_id'] = $result['transid'];
+ $params['gross_amount'] = $tclink['amount'] / 100;
+
+ return $params;
+ }
+
+ /**
+ * Submit an Automated Recurring Billing subscription
+ *
+ * @param array $params assoc array of input parameters for this transaction
+ *
+ * @return array the result in a nice formatted array (or an error object)
+ * @public
+ */
+ function doRecurPayment(&$params) {
+ $template = CRM_Core_Smarty::singleton();
+
+ $intervalLength = $this->_getParam('frequency_interval');
+ $intervalUnit = $this->_getParam('frequency_unit');
+ if ($intervalUnit == 'week') {
+ $intervalLength *= 7;
+ $intervalUnit = 'days';
+ }
+ elseif ($intervalUnit == 'year') {
+ $intervalLength *= 12;
+ $intervalUnit = 'months';
+ }
+ elseif ($intervalUnit == 'day') {
+ $intervalUnit = 'days';
+ }
+ elseif ($intervalUnit == 'month') {
+ $intervalUnit = 'months';
+ }
+
+ // interval cannot be less than 7 days or more than 1 year
+ if ($intervalUnit == 'days') {
+ if ($intervalLength < 7) {
+ return self::error(9001, 'Payment interval must be at least one week');
+ }
+ elseif ($intervalLength > 365) {
+ return self::error(9001, 'Payment interval may not be longer than one year');
+ }
+ }
+ elseif ($intervalUnit == 'months') {
+ if ($intervalLength < 1) {
+ return self::error(9001, 'Payment interval must be at least one week');
+ }
+ elseif ($intervalLength > 12) {
+ return self::error(9001, 'Payment interval may not be longer than one year');
+ }
+ }
+
+ $template->assign('intervalLength', $intervalLength);
+ $template->assign('intervalUnit', $intervalUnit);
+
+ $template->assign('apiLogin', $this->_getParam('apiLogin'));
+ $template->assign('paymentKey', $this->_getParam('paymentKey'));
+ $template->assign('refId', substr($this->_getParam('invoiceID'), 0, 20));
+
+ //for recurring, carry first contribution id
+ $template->assign('invoiceNumber', $this->_getParam('contributionID'));
+ $firstPaymentDate = $this->_getParam('receive_date');
+ if (!empty($firstPaymentDate)) {
+ //allow for post dated payment if set in form
+ $template->assign('startDate', date('Y-m-d', strtotime($firstPaymentDate)));
+ }
+ else {
+ $template->assign('startDate', date('Y-m-d'));
+ }
+ // for open ended subscription totalOccurrences has to be 9999
+ $installments = $this->_getParam('installments');
+ $template->assign('totalOccurrences', $installments ? $installments : 9999);
+
+ $template->assign('amount', $this->_getParam('amount'));
+
+ $template->assign('cardNumber', $this->_getParam('credit_card_number'));
+ $exp_month = str_pad($this->_getParam('month'), 2, '0', STR_PAD_LEFT);
+ $exp_year = $this->_getParam('year');
+ $template->assign('expirationDate', $exp_year . '-' . $exp_month);
+ // name rather than description is used in the tpl - see http://www.authorize.net/support/ARB_guide.pdf
+ $template->assign('name', $this->_getParam('description'));
+
+ $template->assign('email', $this->_getParam('email'));
+ $template->assign('contactID', $this->_getParam('contactID'));
+ $template->assign('billingFirstName', $this->_getParam('billing_first_name'));
+ $template->assign('billingLastName', $this->_getParam('billing_last_name'));
+ $template->assign('billingAddress', $this->_getParam('street_address'));
+ $template->assign('billingCity', $this->_getParam('city'));
+ $template->assign('billingState', $this->_getParam('state_province'));
+ $template->assign('billingZip', $this->_getParam('postal_code'));
+ $template->assign('billingCountry', $this->_getParam('country'));
+
+ $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
+ // submit to authorize.net
+
+ $submit = curl_init($this->_paymentProcessor['url_recur']);
+ if (!$submit) {
+ return self::error(9002, 'Could not initiate connection to payment gateway');
+ }
+ curl_setopt($submit, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($submit, CURLOPT_HTTPHEADER, array("Content-Type: text/xml"));
+ curl_setopt($submit, CURLOPT_HEADER, 1);
+ curl_setopt($submit, CURLOPT_POSTFIELDS, $arbXML);
+ curl_setopt($submit, CURLOPT_POST, 1);
+ curl_setopt($submit, CURLOPT_SSL_VERIFYPEER, 0);
+
+ $response = curl_exec($submit);
+
+ if (!$response) {
+ return self::error(curl_errno($submit), curl_error($submit));
+ }
+
+ curl_close($submit);
+ $responseFields = $this->_ParseArbReturn($response);
+
+ if ($responseFields['resultCode'] == 'Error') {
+ return self::error($responseFields['code'], $responseFields['text']);
+ }
+
+ // update recur processor_id with subscriptionId
+ CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_ContributionRecur', $params['contributionRecurID'],
+ 'processor_id', $responseFields['subscriptionId']
+ );
+ //only impact of assigning this here is is can be used to cancel the subscription in an automated test
+ // if it isn't cancelled a duplicate transaction error occurs
+ if (CRM_Utils_Array::value('subscriptionId', $responseFields)) {
+ $this->_setParam('subscriptionId', $responseFields['subscriptionId']);
+ }
+ return $params;
+ }
+
+ function _getTrustCommerceFields() {
+ // Total amount is from the form contribution field
+ $amount = $this->_getParam('total_amount');
+ // CRM-9894 would this ever be the case??
+ if (empty($amount)) {
+ $amount = $this->_getParam('amount');
+ }
+ $fields = array();
+ $fields['custid'] = $this->_getParam('user_name');
+ $fields['password'] = $this->_getParam('password');
+ $fields['action'] = 'sale';
+
+ // Enable address verification
+ $fields['avs'] = 'y';
+
+ $fields['address1'] = $this->_getParam('street_address');
+ $fields['zip'] = $this->_getParam('postal_code');
+
+ $fields['name'] = $this->_getParam('billing_first_name') . ' ' . $this->_getParam('billing_last_name');
+
+ // We need to pass the amount to TrustCommerce in dollar cents
+ $fields['amount'] = $amount * 100;
+
+ // Unique identifier
+ $fields['ticket'] = substr($this->_getParam('invoiceID'), 0, 20);
+
+ // cc info
+ $fields['cc'] = $this->_getParam('credit_card_number');
+ $fields['cvv'] = $this->_getParam('cvv2');
+ $exp_month = str_pad($this->_getParam('month'), 2, '0', STR_PAD_LEFT);
+ $exp_year = substr($this->_getParam('year'),-2);
+ $fields['exp'] = "$exp_month$exp_year";
+
+ if ($this->_mode != 'live') {
+ $fields['demo'] = 'y';
+ }
+ // TODO FIXME remove
+ foreach ($fields as $field => $value) {
+ if ($field == 'custid') $value = '********';
+ if ($field == 'password') $value = '********';
+ error_log("fields: $field => $value");
+ }
+
+ return $fields;
+ }
+
+ /**
+ * Checks to see if invoice_id already exists in db
+ *
+ * @param int $invoiceId The ID to check
+ *
+ * @return bool True if ID exists, else false
+ */
+ function _checkDupe($invoiceId) {
+ require_once 'CRM/Contribute/DAO/Contribution.php';
+ $contribution = new CRM_Contribute_DAO_Contribution();
+ $contribution->invoice_id = $invoiceId;
+ return $contribution->find();
+ }
+
+ /**
+ * Get the value of a field if set
+ *
+ * @param string $field the field
+ *
+ * @return mixed value of the field, or empty string if the field is
+ * not set
+ */
+ function _getParam($field) {
+ return CRM_Utils_Array::value($field, $this->_params, '');
+ }
+
+ function &error($errorCode = NULL, $errorMessage = NULL) {
+ $e = CRM_Core_Error::singleton();
+ if ($errorCode) {
+ $e->push($errorCode, 0, NULL, $errorMessage);
+ }
+ else {
+ $e->push(9001, 0, NULL, 'Unknown System Error.');
+ }
+ return $e;
+ }
+
+ /**
+ * Set a field to the specified value. Value must be a scalar (int,
+ * float, string, or boolean)
+ *
+ * @param string $field
+ * @param mixed $value
+ *
+ * @return bool false if value is not a scalar, true if successful
+ */
+ function _setParam($field, $value) {
+ if (!is_scalar($value)) {
+ return FALSE;
+ }
+ else {
+ $this->_params[$field] = $value;
+ }
+ }
+
+ /**
+ * This function checks to see if we have the right config values
+ *
+ * @return string the error message if any
+ * @public
+ */
+ function checkConfig() {
+ $error = array();
+ if (empty($this->_paymentProcessor['user_name'])) {
+ $error[] = ts('Customer ID is not set for this payment processor');
+ }
+
+ if (empty($this->_paymentProcessor['password'])) {
+ $error[] = ts('Password is not set for this payment processor');
+ }
+
+ if (!empty($error)) {
+ return implode('<p>', $error);
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ function cancelSubscriptionURL($entityID = NULL, $entity = NULL) {
+ if ($entityID && $entity == 'membership') {
+ require_once 'CRM/Contact/BAO/Contact/Utils.php';
+ $contactID = CRM_Core_DAO::getFieldValue("CRM_Member_DAO_Membership", $entityID, "contact_id");
+ $checksumValue = CRM_Contact_BAO_Contact_Utils::generateChecksum($contactID, NULL, 'inf');
+
+ return CRM_Utils_System::url('civicrm/contribute/unsubscribe',
+ "reset=1&mid={$entityID}&cs={$checksumValue}", TRUE, NULL, FALSE, FALSE
+ );
+ }
+
+ return ($this->_mode == 'test') ? 'https://test.authorize.net' : 'https://authorize.net';
+ }
+
+ function cancelSubscription() {
+ $template = CRM_Core_Smarty::singleton();
+
+ $template->assign('subscriptionType', 'cancel');
+
+ $template->assign('apiLogin', $this->_getParam('apiLogin'));
+ $template->assign('paymentKey', $this->_getParam('paymentKey'));
+ $template->assign('subscriptionId', $this->_getParam('subscriptionId'));
+
+ $arbXML = $template->fetch('CRM/Contribute/Form/Contribution/AuthorizeNetARB.tpl');
+
+ // submit to authorize.net
+ $submit = curl_init($this->_paymentProcessor['url_recur']);
+ if (!$submit) {
+ return self::error(9002, 'Could not initiate connection to payment gateway');
+ }
+
+ curl_setopt($submit, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($submit, CURLOPT_HTTPHEADER, array("Content-Type: text/xml"));
+ curl_setopt($submit, CURLOPT_HEADER, 1);
+ curl_setopt($submit, CURLOPT_POSTFIELDS, $arbXML);
+ curl_setopt($submit, CURLOPT_POST, 1);
+ curl_setopt($submit, CURLOPT_SSL_VERIFYPEER, 0);
+
+ $response = curl_exec($submit);
+
+ if (!$response) {
+ return self::error(curl_errno($submit), curl_error($submit));
+ }
+
+ curl_close($submit);
+
+ $responseFields = $this->_ParseArbReturn($response);
+
+ if ($responseFields['resultCode'] == 'Error') {
+ return self::error($responseFields['code'], $responseFields['text']);
+ }
+
+ // carry on cancelation procedure
+ return TRUE;
+ }
+}
+
--- /dev/null
+ INSERT INTO civicrm_payment_processor_type
+ (name, title, description, is_active, is_default, user_name_label, password_label, signature_label, subject_label, class_name, url_site_default, url_recur_default, url_button_default, url_site_test_default, url_recur_test_default, url_button_test_default, billing_mode, is_recur )
+ VALUES
+ ('TrustCommerce','TrustCommerce',NULL,1,0,'Customer ID','Password',NULL,NULL,'Payment_TrustCommerce',NULL,NULL,NULL,NULL,NULL,NULL,1,NULL);
+
+
+
--- /dev/null
+diff --git a/CRM/Contribute/Form/Task/PDFLatex.php b/CRM/Contribute/Form/Task/PDFLatex.php
+new file mode 100644
+index 0000000..f353e00
+--- /dev/null
++++ b/CRM/Contribute/Form/Task/PDFLatex.php
+@@ -0,0 +1,147 @@
++<?php
++/*
++ +--------------------------------------------------------------------+
++ | CiviCRM version 4.4 |
++ +--------------------------------------------------------------------+
++ | Copyright CiviCRM LLC (c) 2004-2013 |
++ +--------------------------------------------------------------------+
++ | 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 |
++ +--------------------------------------------------------------------+
++*/
++
++/**
++ *
++ * @package CRM
++ * @copyright CiviCRM LLC (c) 2004-2013
++ * $Id$
++ *
++ */
++
++/**
++ * This class provides the functionality to create PDF letter for a group of
++ * contacts or a single contact.
++ */
++class CRM_Contribute_Form_Task_PDFLatex extends CRM_Contribute_Form_Task {
++
++ /**
++ * all the existing templates in the system
++ *
++ * @var array
++ */
++ public $_templates = NULL;
++
++ public $_single = NULL;
++
++ public $_cid = NULL;
++
++ /**
++ * build all the data structures needed to build the form
++ *
++ * @return void
++ * @access public
++ */
++ 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);
++
++ // retrieve contact ID if this is 'single' mode
++ $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE);
++
++ $this->_activityId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE);
++
++ if ($cid) {
++ CRM_Contact_Form_Task_PDFLetterCommon::preProcessSingle($this, $cid);
++ $this->_single = TRUE;
++ $this->_cid = $cid;
++ }
++ else {
++ parent::preProcess();
++ }
++ $this->assign('single', $this->_single);
++ }
++
++ function setDefaultValues() {
++ $defaults = array();
++ if (isset($this->_activityId)) {
++ $params = array('id' => $this->_activityId);
++ CRM_Activity_BAO_Activity::retrieve($params, $defaults);
++ $defaults['html_message'] = $defaults['details'];
++ }
++ $defaults = $defaults + CRM_Contact_Form_Task_PDFLetterCommon::setDefaultValues();
++ return $defaults;
++ }
++
++ /**
++ * Build the form
++ *
++ * @access public
++ *
++ * @return void
++ */
++ public function buildQuickForm() {
++ //enable form element
++ $this->assign('suppressForm', FALSE);
++
++ // use contact form as a base
++ CRM_Contact_Form_Task_PDFLetterCommon::buildQuickForm($this);
++
++ // specific need for contributions
++ $this->add('static', 'more_options_header', NULL, ts('Record Update 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(), "<br/>", FALSE);
++
++ $this->addButtons(array(
++ array(
++ 'type' => 'submit',
++ 'name' => ts('Make Thank-you Letters'),
++ 'isDefault' => TRUE,
++ ),
++ array(
++ 'type' => 'cancel',
++ 'name' => ts('Done'),
++ ),
++ )
++ );
++
++ }
++
++ /**
++ * process the form after the input has been submitted and validated
++ *
++ * @access public
++ *
++ * @return None
++ */
++ public function postProcess() {
++ // TODO: rewrite using contribution token and one letter by contribution
++ $this->setContactIDs();
++
++ CRM_Contribute_Form_Task_PDFLatexCommon::postProcess($this);
++ }
++
++
++}
++
+diff --git a/CRM/Contribute/Form/Task/PDFLatexCommon.php b/CRM/Contribute/Form/Task/PDFLatexCommon.php
+new file mode 100644
+index 0000000..862b03f
+--- /dev/null
++++ b/CRM/Contribute/Form/Task/PDFLatexCommon.php
+@@ -0,0 +1,116 @@
++<?php
++
++/**
++ * This class provides the common functionality for creating PDF letter for
++ * one or a group of contact ids.
++ */
++class CRM_Contribute_Form_Task_PDFLatexCommon extends CRM_Contact_Form_Task_PDFLetterCommon {
++
++ /**
++ * process the form after the input has been submitted and validated
++ *
++ * @access public
++ *
++ * @return None
++ */
++ static function postProcess(&$form) {
++
++ list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($form);
++ //CRM_Core_Error::debug_log_message(":2 $html_message"); //OK
++
++ // 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;
++ $updateStatus = '';
++
++ // skip some contacts ?
++ $skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE;
++ $skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE;
++
++ foreach ($form->getVar('_contributionIds') as $item => $contributionId) {
++
++ // get contact information
++ $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;
++ }
++
++ // 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], FALSE, $messageToken);
++ $tokenHtml = CRM_Utils_Token::replaceContributionTokens($tokenHtml, $contribution[$contributionId], TRUE, $messageToken);
++ $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $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");
++ }
++
++ $html[] = $tokenHtml;
++
++ // update dates (do it for each contribution including grouped recurring contribution)
++ 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++;
++ }
++ }
++ }
++
++ self::createActivities($form, $html_message, $form->_contactIds);
++
++ CRM_Utils_PDF_Utils::latex2pdf($html, "CiviLatex.pdf", FALSE, $formValues);
++
++ $form->postProcessHook();
++
++ if ($receipts) {
++ $updateStatus = ts('Receipt date has been updated for %1 contributions.', array(1 => $receipts));
++ }
++ if ($thanks) {
++ $updateStatus .= ' ' . ts('Thank-you date has been updated for %1 contributions.', array(1 => $thanks));
++ }
++
++ if ($updateStatus) {
++ CRM_Core_Session::setStatus($updateStatus);
++ }
++
++ CRM_Utils_System::civiExit(1);
++ }
++ //end of function
++}
++
+diff --git a/CRM/Contribute/Task.php b/CRM/Contribute/Task.php
+index 987b280..129cb45 100644
+--- a/CRM/Contribute/Task.php
++++ b/CRM/Contribute/Task.php
+@@ -39,7 +39,7 @@
+ *
+ */
+ class CRM_Contribute_Task {
+- CONST DELETE_CONTRIBUTIONS = 1, PRINT_CONTRIBUTIONS = 2, EXPORT_CONTRIBUTIONS = 3, BATCH_CONTRIBUTIONS = 4, EMAIL_CONTACTS = 5, UPDATE_STATUS = 6, PDF_RECEIPT = 7;
++ CONST DELETE_CONTRIBUTIONS = 1, PRINT_CONTRIBUTIONS = 2, EXPORT_CONTRIBUTIONS = 3, BATCH_CONTRIBUTIONS = 4, EMAIL_CONTACTS = 5, UPDATE_STATUS = 6, PDF_RECEIPT = 7, LATEX_TEST = 9;
+
+ /**
+ * the task array
+@@ -106,6 +106,10 @@ static function &tasks() {
+ 'class' => 'CRM_Contribute_Form_Task_PDFLetter',
+ 'result' => FALSE,
+ ),
++ 9 => array('title' => ts('Latex Letters for Contributions'),
++ 'class' => 'CRM_Contribute_Form_Task_PDFLatex',
++ 'result' => FALSE,
++ ),
+ );
+
+ //CRM-4418, check for delete
+diff --git a/CRM/Utils/PDF/Utils.php b/CRM/Utils/PDF/Utils.php
+index 72d4880..e9d59b9 100644
+--- a/CRM/Utils/PDF/Utils.php
++++ b/CRM/Utils/PDF/Utils.php
+@@ -34,6 +34,69 @@
+ */
+ class CRM_Utils_PDF_Utils {
+
++ static function latex2pdf(&$text, $fileName = 'civicrm.pdf', $output = FALSE, $pdfFormat = NULL) {
++ /* FIXME: get $paper_size, $orientation, $margins */
++
++ if (is_array($text)) {
++ $pages = &$text;
++ }
++ else {
++ $pages = array($text);
++ }
++
++
++ $head='\documentclass[12pt]{letter}
++\oddsidemargin 0in
++\evensidemargin 0in
++\textwidth 6.5in
++
++\topmargin -.25in
++\textheight 8.15in
++
++\address{\vspace{0.354in}}
++
++\begin{document}
++
++';
++ $footer='
++\end{document}';
++
++ $latex = $head;
++ foreach ($pages as $page) {
++ $latex.=$page;
++ }
++ $latex.=$footer;
++
++ $descriptorspec = array(
++ 0 => array("pipe", "r"),
++ 1 => array("pipe", "w")
++ );
++
++
++
++ $process = proc_open("/usr/local/bin/pdflatex_wrapper.sh", $descriptorspec, $pipes);
++
++
++ if (is_resource($process)) {
++ fwrite($pipes[0], $latex);
++ fclose($pipes[0]);
++
++ $pdf = stream_get_contents($pipes[1]);
++ fclose($pipes[1]);
++ } else {
++ CRM_Core_Error::debug_log_message("ERROR creating PDF. Check /tmp/pdflatex_*");
++ }
++
++ if ($output) {
++ return $pdf;
++ }
++ else {
++ header('Content-Type: application/pdf');
++ header('Content-Disposition: attachment; filename="' . $fileName . '"');
++ echo $pdf;
++ }
++ }
++
+ static function html2pdf(&$text, $fileName = 'civicrm.pdf', $output = FALSE, $pdfFormat = NULL) {
+ if (is_array($text)) {
+ $pages = &$text;
+diff --git a/CRM/Utils/Token.php b/CRM/Utils/Token.php
+index 28ca941..e8df124 100644
+--- a/CRM/Utils/Token.php
++++ b/CRM/Utils/Token.php
+@@ -619,7 +619,10 @@ function ($matches) use(&$contact, $html, $returnBlankToken, $escapeSmarty) {
+ $str
+ );
+
+- $str = preg_replace('/\\\\|\{(\s*)?\}/', ' ', $str);
++ // 2013-08-31 nico@fsf.org this replacement is stripping all the '{' and '}' from the LaTeX files
++ // maybe it got solved at some point. maybe it has undesired collateral effects. I'm bugging the
++ // CiviCRM community to take a look at this pull request.
++ //$str = preg_replace('/\\\\|\{(\s*)?\}/', ' ', $str);
+ return $str;
+ }
+
+diff --git a/templates/CRM/Contact/Form/Task/PDFLatexCommon.tpl b/templates/CRM/Contact/Form/Task/PDFLatexCommon.tpl
+new file mode 100644
+index 0000000..1f75f97
+--- /dev/null
++++ b/templates/CRM/Contact/Form/Task/PDFLatexCommon.tpl
+@@ -0,0 +1,312 @@
++{*
++ +--------------------------------------------------------------------+
++ | CiviCRM version 4.4 |
++ +--------------------------------------------------------------------+
++ | Copyright CiviCRM LLC (c) 2004-2013 |
++ +--------------------------------------------------------------------+
++ | 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 |
++ +--------------------------------------------------------------------+
++*}
++{*common template for compose PDF letters*}
++{if $form.template.html}
++<table class="form-layout-compressed">
++ <tr>
++ <td class="label-left">{$form.template.label}</td>
++ <td>{$form.template.html}</td>
++ </tr>
++</table>
++{/if}
++
++<div class="crm-accordion-wrapper collapsed">
++ <div class="crm-accordion-header">
++ {$form.pdf_format_header.html}
++ </div>
++ <div class="crm-accordion-body">
++ <div class="crm-block crm-form-block crm-pdf-format-form-block">
++ <table class="form-layout-compressed">
++ <tr>
++ <td class="label-left">{$form.format_id.label}</td><td>{$form.format_id.html}{help id="id-pdf-format" file="CRM/Contact/Form/Task/PDFLetterCommon.hlp"}</td>
++ <td colspan="2"> </td>
++ </tr>
++ <tr>
++ <td class="label-left">{$form.paper_size.label}</td><td>{$form.paper_size.html}</td>
++ <td class="label-left">{$form.orientation.label}</td><td>{$form.orientation.html}</td>
++ </tr>
++ <tr>
++ <td class="label-left">{$form.metric.label}</td><td>{$form.metric.html}</td>
++ <td colspan="2"> </td>
++ </tr>
++ <tr>
++ <td>{$form.paper_dimensions.html}</td><td id="paper_dimensions"> </td>
++ <td colspan="2"> </td>
++ </tr>
++ <tr>
++ <td class="label-left">{$form.margin_top.label}</td><td>{$form.margin_top.html}</td>
++ <td class="label-left">{$form.margin_bottom.label}</td><td>{$form.margin_bottom.html}</td>
++ </tr>
++ <tr>
++ <td class="label-left">{$form.margin_left.label}</td><td>{$form.margin_left.html}</td>
++ <td class="label-left">{$form.margin_right.label}</td><td>{$form.margin_right.html}</td>
++ </tr>
++ </table>
++ <div id="bindFormat">{$form.bind_format.html} {$form.bind_format.label}</div>
++ <div id="updateFormat" style="display: none">{$form.update_format.html} {$form.update_format.label}</div>
++ </div>
++ </div>
++</div>
++
++<div class="crm-accordion-wrapper crm-html_email-accordion ">
++<div class="crm-accordion-header">
++ {$form.html_message.label}
++</div><!-- /.crm-accordion-header -->
++ <div class="crm-accordion-body">
++ {if $action neq 4}
++ <span class="helpIcon" id="helphtml">
++ <a href="#" onClick="return showToken('Html', 1);">{$form.token1.label}</a>
++ {help id="id-token-html" file="CRM/Contact/Form/Task/Email.hlp" tplFile=$tplFile isAdmin=$isAdmin editor=$editor}
++ <div id="tokenHtml" style="display:none;">
++ <input style="border:1px solid #999999;" type="text" id="filter1" size="20" name="filter1" onkeyup="filter(this, 1)"/><br />
++ <span class="description">{ts}Begin typing to filter list of tokens{/ts}</span><br/>
++ {$form.token1.html}
++ </div>
++ </span>
++ {/if}
++ <div class="clear"></div>
++ <div class='html'>
++ {if $editor EQ 'textarea'}
++ <div class="help description">{ts}The content of this page should be LaTeX.{/ts}</div>
++ {/if}
++ {$form.html_message.html}<br />
++ </div>
++
++<div id="editMessageDetails">
++ <div id="updateDetails" >
++ {$form.updateTemplate.html} {$form.updateTemplate.label}
++ </div>
++ <div>
++ {$form.saveTemplate.html} {$form.saveTemplate.label}
++ </div>
++</div>
++
++<div id="saveDetails" class="section">
++ <div class="label">{$form.saveTemplateName.label}</div>
++ <div class="content">{$form.saveTemplateName.html|crmAddClass:huge}</div>
++</div>
++
++ </div><!-- /.crm-accordion-body -->
++</div><!-- /.crm-accordion-wrapper -->
++
++{include file="CRM/Mailing/Form/InsertTokens.tpl"}
++
++{literal}
++<script type="text/javascript">
++cj(function() {
++ cj().crmAccordions();
++});
++
++var currentWidth;
++var currentHeight;
++var currentMetric = document.getElementById('metric').value;
++showBindFormatChkBox();
++selectPaper( document.getElementById('paper_size').value );
++
++function tokenReplHtml ( )
++{
++ var token1 = cj("#token1").val( )[0];
++ var editor = {/literal}"{$editor}"{literal};
++ if ( editor == "tinymce" ) {
++ var content= tinyMCE.get('html_message').getContent() +token1;
++ tinyMCE.get('html_message').setContent(content);
++ } else if ( editor == "joomlaeditor" ) {
++ tinyMCE.execCommand('mceInsertContent',false, token1);
++ var msg = document.getElementById(html_message).value;
++ var cursorlen = document.getElementById(html_message).selectionStart;
++ var textlen = msg.length;
++ document.getElementById(html_message).value = msg.substring(0, cursorlen) + token1 + msg.substring(cursorlen, textlen);
++ var cursorPos = (cursorlen + token1.length);
++ document.getElementById(html_message).selectionStart = cursorPos;
++ document.getElementById(html_message).selectionEnd = cursorPos;
++ document.getElementById(html_message).focus();
++ } else if ( editor == "ckeditor" ) {
++ oEditor = CKEDITOR.instances[html_message];
++ oEditor.insertHtml(token1.toString() );
++ } else if ( editor == "drupalwysiwyg" ) {
++ Drupal.wysiwyg.instances[html_message].insert(token1.toString());
++ } else {
++ var msg = document.getElementById(html_message).value;
++ var cursorlen = document.getElementById(html_message).selectionStart;
++ var textlen = msg.length;
++ document.getElementById(html_message).value = msg.substring(0, cursorlen) + token1 + msg.substring(cursorlen, textlen);
++ var cursorPos = (cursorlen + token1.length);
++ document.getElementById(html_message).selectionStart = cursorPos;
++ document.getElementById(html_message).selectionEnd = cursorPos;
++ document.getElementById(html_message).focus();
++ }
++ verify();
++}
++
++function showBindFormatChkBox()
++{
++ var templateExists = true;
++ if ( document.getElementById('template') == null || document.getElementById('template').value == '' ) {
++ templateExists = false;
++ }
++ var formatExists = true;
++ if ( document.getElementById('format_id').value == 0 ) {
++ formatExists = false;
++ }
++ if ( templateExists && formatExists ) {
++ document.getElementById("bindFormat").style.display = "block";
++ } else if ( formatExists && document.getElementById("saveTemplate") != null && document.getElementById("saveTemplate").checked ) {
++ document.getElementById("bindFormat").style.display = "block";
++ var yes = confirm( '{/literal}{$useThisPageFormat}{literal}' );
++ if ( yes ) {
++ document.getElementById("bind_format").checked = true;
++ }
++ } else {
++ document.getElementById("bindFormat").style.display = "none";
++ document.getElementById("bind_format").checked = false;
++ }
++}
++
++function showUpdateFormatChkBox()
++{
++ if ( document.getElementById('format_id').value != 0 ) {
++ document.getElementById("updateFormat").style.display = "block";
++ }
++}
++
++function hideUpdateFormatChkBox()
++{
++ document.getElementById("update_format").checked = false;
++ document.getElementById("updateFormat").style.display = "none";
++}
++
++function selectFormat( val, bind )
++{
++ if ( val == null || val == 0 ) {
++ val = 0;
++ bind = false;
++ }
++ var dataUrl = {/literal}"{crmURL p='civicrm/ajax/pdfFormat' h=0 }"{literal};
++ cj.post( dataUrl, {formatId: val}, function( data ) {
++ cj("#format_id").val( data.id );
++ cj("#paper_size").val( data.paper_size );
++ cj("#orientation").val( data.orientation );
++ cj("#metric").val( data.metric );
++ cj("#margin_top").val( data.margin_top );
++ cj("#margin_bottom").val( data.margin_bottom );
++ cj("#margin_left").val( data.margin_left );
++ cj("#margin_right").val( data.margin_right );
++ selectPaper( data.paper_size );
++ hideUpdateFormatChkBox();
++ document.getElementById('bind_format').checked = bind;
++ showBindFormatChkBox();
++ }, 'json');
++}
++
++function selectPaper( val )
++{
++ dataUrl = {/literal}"{crmURL p='civicrm/ajax/paperSize' h=0 }"{literal};
++ cj.post( dataUrl, {paperSizeName: val}, function( data ) {
++ cj("#paper_size").val( data.name );
++ metric = document.getElementById('metric').value;
++ currentWidth = convertMetric( data.width, data.metric, metric );
++ currentHeight = convertMetric( data.height, data.metric, metric );
++ updatePaperDimensions( );
++ }, 'json');
++}
++
++function selectMetric( metric )
++{
++ convertField( 'margin_top', currentMetric, metric );
++ convertField( 'margin_bottom', currentMetric, metric );
++ convertField( 'margin_left', currentMetric, metric );
++ convertField( 'margin_right', currentMetric, metric );
++ currentWidth = convertMetric( currentWidth, currentMetric, metric );
++ currentHeight = convertMetric( currentHeight, currentMetric, metric );
++ updatePaperDimensions( );
++}
++
++function updatePaperDimensions( )
++{
++ metric = document.getElementById('metric').value;
++ width = new String( currentWidth.toFixed( 2 ) );
++ height = new String( currentHeight.toFixed( 2 ) );
++ if ( document.getElementById('orientation').value == 'landscape' ) {
++ width = new String( currentHeight.toFixed( 2 ) );
++ height = new String( currentWidth.toFixed( 2 ) );
++ }
++ document.getElementById('paper_dimensions').innerHTML = parseFloat( width ) + ' ' + metric + ' x ' + parseFloat( height ) + ' ' + metric;
++ currentMetric = metric;
++}
++
++function convertField( id, from, to )
++{
++ val = document.getElementById( id ).value;
++ if ( val == '' || isNaN( val ) ) return;
++ val = convertMetric( val, from, to );
++ val = new String( val.toFixed( 3 ) );
++ document.getElementById( id ).value = parseFloat( val );
++}
++
++function convertMetric( value, from, to ) {
++ switch( from + to ) {
++ case 'incm': return value * 2.54;
++ case 'inmm': return value * 25.4;
++ case 'inpt': return value * 72;
++ case 'cmin': return value / 2.54;
++ case 'cmmm': return value * 10;
++ case 'cmpt': return value * 72 / 2.54;
++ case 'mmin': return value / 25.4;
++ case 'mmcm': return value / 10;
++ case 'mmpt': return value * 72 / 25.4;
++ case 'ptin': return value / 72;
++ case 'ptcm': return value * 2.54 / 72;
++ case 'ptmm': return value * 25.4 / 72;
++ }
++ return value;
++}
++
++function showSaveDetails(chkbox) {
++ var formatSelected = ( document.getElementById('format_id').value > 0 );
++ var templateSelected = ( document.getElementById('template') != null && document.getElementById('template').value > 0 );
++ if (chkbox.checked) {
++ document.getElementById("saveDetails").style.display = "block";
++ document.getElementById("saveTemplateName").disabled = false;
++ if ( formatSelected && ! templateSelected ) {
++ document.getElementById("bindFormat").style.display = "block";
++ var yes = confirm( '{/literal}{$useSelectedPageFormat}{literal}' );
++ if ( yes ) {
++ document.getElementById("bind_format").checked = true;
++ }
++ }
++ } else {
++ document.getElementById("saveDetails").style.display = "none";
++ document.getElementById("saveTemplateName").disabled = true;
++ if ( ! templateSelected ) {
++ document.getElementById("bindFormat").style.display = "none";
++ document.getElementById("bind_format").checked = false;
++ }
++ }
++}
++
++</script>
++{/literal}
++
+diff --git a/templates/CRM/Contribute/Form/Task/PDFLatex.tpl b/templates/CRM/Contribute/Form/Task/PDFLatex.tpl
+new file mode 100644
+index 0000000..a7fb259
+--- /dev/null
++++ b/templates/CRM/Contribute/Form/Task/PDFLatex.tpl
+@@ -0,0 +1,48 @@
++{*
++ +--------------------------------------------------------------------+
++ | CiviCRM version 4.4 |
++ +--------------------------------------------------------------------+
++ | Copyright CiviCRM LLC (c) 2004-2013 |
++ +--------------------------------------------------------------------+
++ | 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 |
++ +--------------------------------------------------------------------+
++*}
++<div class="crm-form-block crm-block crm-contact-task-pdflatex-form-block">
++<h3>{ts}Thank-you Letter In Latex for Contributions (PDF){/ts}</h3>
++{if $single eq false}
++ <div class="messages status no-popup">{include file="CRM/Contribute/Form/Task.tpl"}</div>
++{/if}
++
++<div class="crm-accordion-wrapper crm-html_email-accordion ">
++ <div class="crm-accordion-header">
++ {$form.more_options_header.html}
++ </div><!-- /.crm-accordion-header -->
++ <div class="crm-accordion-body">
++ <table class="form-layout-compressed">
++ <tr><td class="label-left">{$form.thankyou_update.html} {$form.thankyou_update.label}</td><td></td></tr>
++ <tr><td class="label-left">{$form.receipt_update.html} {$form.receipt_update.label}</td><td></td></tr>
++ <!--tr><td class="label-left">{$form.is_group_by.label} (<a href="#" title="unselect" onclick="unselectRadio('is_group_by'); return false;" >{ts}clear{/ts}</a>)</td><td>{$form.is_group_by.html}</td></tr-->
++ </table>
++ </div><!-- /.crm-accordion-body -->
++</div><!-- /.crm-accordion-wrapper -->
++
++{include file="CRM/Contact/Form/Task/PDFLatexCommon.tpl"}
++
++<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
++</div>
+--
+1.8.4
+
--- /dev/null
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.3 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2013 |
+ +--------------------------------------------------------------------+
+ | 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 |
+ +--------------------------------------------------------------------+
+*}
+<div class="crm-form-block crm-block crm-contact-task-pdf-form-block">
+<h3>{ts}Create Printable Latex Letters (PDF){/ts}</h3>
+{if $single eq false}
+ <div class="messages status no-popup">{include file="CRM/Contact/Form/Task.tpl"}</div>
+{/if}
+{include file="CRM/Contact/Form/Task/LatexPDFLatexCommon.tpl"}
+<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
+</div>
--- /dev/null
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.4 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2013 |
+ +--------------------------------------------------------------------+
+ | 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 |
+ +--------------------------------------------------------------------+
+*}
+{*common template for compose PDF letters*}
+{if $form.template.html}
+<table class="form-layout-compressed">
+ <tr>
+ <td class="label-left">{$form.template.label}</td>
+ <td>{$form.template.html}</td>
+ </tr>
+</table>
+{/if}
+
+<div class="crm-accordion-wrapper collapsed">
+ <div class="crm-accordion-header">
+ {$form.pdf_format_header.html}
+ </div>
+ <div class="crm-accordion-body">
+ <div class="crm-block crm-form-block crm-pdf-format-form-block">
+ <table class="form-layout-compressed">
+ <tr>
+ <td class="label-left">{$form.format_id.label}</td><td>{$form.format_id.html}{help id="id-pdf-format" file="CRM/Contact/Form/Task/PDFLetterCommon.hlp"}</td>
+ <td colspan="2"> </td>
+ </tr>
+ <tr>
+ <td class="label-left">{$form.paper_size.label}</td><td>{$form.paper_size.html}</td>
+ <td class="label-left">{$form.orientation.label}</td><td>{$form.orientation.html}</td>
+ </tr>
+ <tr>
+ <td class="label-left">{$form.metric.label}</td><td>{$form.metric.html}</td>
+ <td colspan="2"> </td>
+ </tr>
+ <tr>
+ <td>{$form.paper_dimensions.html}</td><td id="paper_dimensions"> </td>
+ <td colspan="2"> </td>
+ </tr>
+ <tr>
+ <td class="label-left">{$form.margin_top.label}</td><td>{$form.margin_top.html}</td>
+ <td class="label-left">{$form.margin_bottom.label}</td><td>{$form.margin_bottom.html}</td>
+ </tr>
+ <tr>
+ <td class="label-left">{$form.margin_left.label}</td><td>{$form.margin_left.html}</td>
+ <td class="label-left">{$form.margin_right.label}</td><td>{$form.margin_right.html}</td>
+ </tr>
+ </table>
+ <div id="bindFormat">{$form.bind_format.html} {$form.bind_format.label}</div>
+ <div id="updateFormat" style="display: none">{$form.update_format.html} {$form.update_format.label}</div>
+ </div>
+ </div>
+</div>
+
+<div class="crm-accordion-wrapper crm-html_email-accordion ">
+<div class="crm-accordion-header">
+ {$form.html_message.label}
+</div><!-- /.crm-accordion-header -->
+ <div class="crm-accordion-body">
+ {if $action neq 4}
+ <span class="helpIcon" id="helphtml">
+ <a href="#" onClick="return showToken('Html', 1);">{$form.token1.label}</a>
+ {help id="id-token-html" file="CRM/Contact/Form/Task/Email.hlp" tplFile=$tplFile isAdmin=$isAdmin editor=$editor}
+ <div id="tokenHtml" style="display:none;">
+ <input style="border:1px solid #999999;" type="text" id="filter1" size="20" name="filter1" onkeyup="filter(this, 1)"/><br />
+ <span class="description">{ts}Begin typing to filter list of tokens{/ts}</span><br/>
+ {$form.token1.html}
+ </div>
+ </span>
+ {/if}
+ <div class="clear"></div>
+ <div class='html'>
+ {if $editor EQ 'textarea'}
+ <div class="help description">{ts}The content of this page should be LaTeX.{/ts}</div>
+ {/if}
+ {$form.html_message.html}<br />
+ </div>
+
+<div id="editMessageDetails">
+ <div id="updateDetails" >
+ {$form.updateTemplate.html} {$form.updateTemplate.label}
+ </div>
+ <div>
+ {$form.saveTemplate.html} {$form.saveTemplate.label}
+ </div>
+</div>
+
+<div id="saveDetails" class="section">
+ <div class="label">{$form.saveTemplateName.label}</div>
+ <div class="content">{$form.saveTemplateName.html|crmAddClass:huge}</div>
+</div>
+
+ </div><!-- /.crm-accordion-body -->
+</div><!-- /.crm-accordion-wrapper -->
+
+{include file="CRM/Mailing/Form/InsertTokens.tpl"}
+
+{literal}
+<script type="text/javascript">
+cj(function() {
+ cj().crmAccordions();
+});
+
+var currentWidth;
+var currentHeight;
+var currentMetric = document.getElementById('metric').value;
+showBindFormatChkBox();
+selectPaper( document.getElementById('paper_size').value );
+
+function tokenReplHtml ( )
+{
+ var token1 = cj("#token1").val( )[0];
+ var editor = {/literal}"{$editor}"{literal};
+ if ( editor == "tinymce" ) {
+ var content= tinyMCE.get('html_message').getContent() +token1;
+ tinyMCE.get('html_message').setContent(content);
+ } else if ( editor == "joomlaeditor" ) {
+ tinyMCE.execCommand('mceInsertContent',false, token1);
+ var msg = document.getElementById(html_message).value;
+ var cursorlen = document.getElementById(html_message).selectionStart;
+ var textlen = msg.length;
+ document.getElementById(html_message).value = msg.substring(0, cursorlen) + token1 + msg.substring(cursorlen, textlen);
+ var cursorPos = (cursorlen + token1.length);
+ document.getElementById(html_message).selectionStart = cursorPos;
+ document.getElementById(html_message).selectionEnd = cursorPos;
+ document.getElementById(html_message).focus();
+ } else if ( editor == "ckeditor" ) {
+ oEditor = CKEDITOR.instances[html_message];
+ oEditor.insertHtml(token1.toString() );
+ } else if ( editor == "drupalwysiwyg" ) {
+ Drupal.wysiwyg.instances[html_message].insert(token1.toString());
+ } else {
+ var msg = document.getElementById(html_message).value;
+ var cursorlen = document.getElementById(html_message).selectionStart;
+ var textlen = msg.length;
+ document.getElementById(html_message).value = msg.substring(0, cursorlen) + token1 + msg.substring(cursorlen, textlen);
+ var cursorPos = (cursorlen + token1.length);
+ document.getElementById(html_message).selectionStart = cursorPos;
+ document.getElementById(html_message).selectionEnd = cursorPos;
+ document.getElementById(html_message).focus();
+ }
+ verify();
+}
+
+function showBindFormatChkBox()
+{
+ var templateExists = true;
+ if ( document.getElementById('template') == null || document.getElementById('template').value == '' ) {
+ templateExists = false;
+ }
+ var formatExists = true;
+ if ( document.getElementById('format_id').value == 0 ) {
+ formatExists = false;
+ }
+ if ( templateExists && formatExists ) {
+ document.getElementById("bindFormat").style.display = "block";
+ } else if ( formatExists && document.getElementById("saveTemplate") != null && document.getElementById("saveTemplate").checked ) {
+ document.getElementById("bindFormat").style.display = "block";
+ var yes = confirm( '{/literal}{$useThisPageFormat}{literal}' );
+ if ( yes ) {
+ document.getElementById("bind_format").checked = true;
+ }
+ } else {
+ document.getElementById("bindFormat").style.display = "none";
+ document.getElementById("bind_format").checked = false;
+ }
+}
+
+function showUpdateFormatChkBox()
+{
+ if ( document.getElementById('format_id').value != 0 ) {
+ document.getElementById("updateFormat").style.display = "block";
+ }
+}
+
+function hideUpdateFormatChkBox()
+{
+ document.getElementById("update_format").checked = false;
+ document.getElementById("updateFormat").style.display = "none";
+}
+
+function selectFormat( val, bind )
+{
+ if ( val == null || val == 0 ) {
+ val = 0;
+ bind = false;
+ }
+ var dataUrl = {/literal}"{crmURL p='civicrm/ajax/pdfFormat' h=0 }"{literal};
+ cj.post( dataUrl, {formatId: val}, function( data ) {
+ cj("#format_id").val( data.id );
+ cj("#paper_size").val( data.paper_size );
+ cj("#orientation").val( data.orientation );
+ cj("#metric").val( data.metric );
+ cj("#margin_top").val( data.margin_top );
+ cj("#margin_bottom").val( data.margin_bottom );
+ cj("#margin_left").val( data.margin_left );
+ cj("#margin_right").val( data.margin_right );
+ selectPaper( data.paper_size );
+ hideUpdateFormatChkBox();
+ document.getElementById('bind_format').checked = bind;
+ showBindFormatChkBox();
+ }, 'json');
+}
+
+function selectPaper( val )
+{
+ dataUrl = {/literal}"{crmURL p='civicrm/ajax/paperSize' h=0 }"{literal};
+ cj.post( dataUrl, {paperSizeName: val}, function( data ) {
+ cj("#paper_size").val( data.name );
+ metric = document.getElementById('metric').value;
+ currentWidth = convertMetric( data.width, data.metric, metric );
+ currentHeight = convertMetric( data.height, data.metric, metric );
+ updatePaperDimensions( );
+ }, 'json');
+}
+
+function selectMetric( metric )
+{
+ convertField( 'margin_top', currentMetric, metric );
+ convertField( 'margin_bottom', currentMetric, metric );
+ convertField( 'margin_left', currentMetric, metric );
+ convertField( 'margin_right', currentMetric, metric );
+ currentWidth = convertMetric( currentWidth, currentMetric, metric );
+ currentHeight = convertMetric( currentHeight, currentMetric, metric );
+ updatePaperDimensions( );
+}
+
+function updatePaperDimensions( )
+{
+ metric = document.getElementById('metric').value;
+ width = new String( currentWidth.toFixed( 2 ) );
+ height = new String( currentHeight.toFixed( 2 ) );
+ if ( document.getElementById('orientation').value == 'landscape' ) {
+ width = new String( currentHeight.toFixed( 2 ) );
+ height = new String( currentWidth.toFixed( 2 ) );
+ }
+ document.getElementById('paper_dimensions').innerHTML = parseFloat( width ) + ' ' + metric + ' x ' + parseFloat( height ) + ' ' + metric;
+ currentMetric = metric;
+}
+
+function convertField( id, from, to )
+{
+ val = document.getElementById( id ).value;
+ if ( val == '' || isNaN( val ) ) return;
+ val = convertMetric( val, from, to );
+ val = new String( val.toFixed( 3 ) );
+ document.getElementById( id ).value = parseFloat( val );
+}
+
+function convertMetric( value, from, to ) {
+ switch( from + to ) {
+ case 'incm': return value * 2.54;
+ case 'inmm': return value * 25.4;
+ case 'inpt': return value * 72;
+ case 'cmin': return value / 2.54;
+ case 'cmmm': return value * 10;
+ case 'cmpt': return value * 72 / 2.54;
+ case 'mmin': return value / 25.4;
+ case 'mmcm': return value / 10;
+ case 'mmpt': return value * 72 / 25.4;
+ case 'ptin': return value / 72;
+ case 'ptcm': return value * 2.54 / 72;
+ case 'ptmm': return value * 25.4 / 72;
+ }
+ return value;
+}
+
+function showSaveDetails(chkbox) {
+ var formatSelected = ( document.getElementById('format_id').value > 0 );
+ var templateSelected = ( document.getElementById('template') != null && document.getElementById('template').value > 0 );
+ if (chkbox.checked) {
+ document.getElementById("saveDetails").style.display = "block";
+ document.getElementById("saveTemplateName").disabled = false;
+ if ( formatSelected && ! templateSelected ) {
+ document.getElementById("bindFormat").style.display = "block";
+ var yes = confirm( '{/literal}{$useSelectedPageFormat}{literal}' );
+ if ( yes ) {
+ document.getElementById("bind_format").checked = true;
+ }
+ }
+ } else {
+ document.getElementById("saveDetails").style.display = "none";
+ document.getElementById("saveTemplateName").disabled = true;
+ if ( ! templateSelected ) {
+ document.getElementById("bindFormat").style.display = "none";
+ document.getElementById("bind_format").checked = false;
+ }
+ }
+}
+
+</script>
+{/literal}
+
--- /dev/null
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.4 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2013 |
+ +--------------------------------------------------------------------+
+ | 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 |
+ +--------------------------------------------------------------------+
+*}
+<div class="crm-form-block crm-block crm-contact-task-pdflatex-form-block">
+<h3>{ts}Thank-you Letter In Latex for Contributions (PDF){/ts}</h3>
+{if $single eq false}
+ <div class="messages status no-popup">{include file="CRM/Contribute/Form/Task.tpl"}</div>
+{/if}
+
+<div class="crm-accordion-wrapper crm-html_email-accordion ">
+ <div class="crm-accordion-header">
+ {$form.more_options_header.html}
+ </div><!-- /.crm-accordion-header -->
+ <div class="crm-accordion-body">
+ <table class="form-layout-compressed">
+ <tr><td class="label-left">{$form.thankyou_update.html} {$form.thankyou_update.label}</td><td></td></tr>
+ <tr><td class="label-left">{$form.receipt_update.html} {$form.receipt_update.label}</td><td></td></tr>
+ <!--tr><td class="label-left">{$form.is_group_by.label} (<a href="#" title="unselect" onclick="unselectRadio('is_group_by'); return false;" >{ts}clear{/ts}</a>)</td><td>{$form.is_group_by.html}</td></tr-->
+ </table>
+ </div><!-- /.crm-accordion-body -->
+</div><!-- /.crm-accordion-wrapper -->
+
+{include file="CRM/Contact/Form/Task/PDFLatexCommon.tpl"}
+
+<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
+</div>
--- /dev/null
+diff --git a/CRM/Contact/Form/Search/Custom/Group.php b/CRM/Contact/Form/Search/Custom/Group.php
+index 999a733..b40d55f 100644
+--- a/CRM/Contact/Form/Search/Custom/Group.php
++++ b/CRM/Contact/Form/Search/Custom/Group.php
+@@ -32,7 +32,9 @@
+ * $Id$
+ *
+ */
+-class CRM_Contact_Form_Search_Custom_Group extends CRM_Contact_Form_Search_Custom_Base implements CRM_Contact_Form_Search_Interface {
++class CRM_Contact_Form_Search_Custom_Group
++ extends CRM_Contact_Form_Search_Custom_Base
++ implements CRM_Contact_Form_Search_Interface {
+
+ protected $_formValues;
+
+@@ -283,7 +285,7 @@ function from() {
+ $xGroups = 0;
+ }
+
+- $sql = "CREATE TEMPORARY TABLE Xg_{$this->_tableName} ( contact_id int primary key) ENGINE=HEAP";
++ $sql = "CREATE TEMPORARY TABLE Xg_{$this->_tableName} ( contact_id int primary key) ENGINE=MyISAM";
+ CRM_Core_DAO::executeQuery($sql);
+
+ //used only when exclude group is selected
+@@ -318,7 +320,7 @@ function from() {
+
+ $sql = "CREATE TEMPORARY TABLE Ig_{$this->_tableName} ( id int PRIMARY KEY AUTO_INCREMENT,
+ contact_id int,
+- group_names varchar(64)) ENGINE=HEAP";
++ group_names varchar(64)) ENGINE=MyISAM";
+
+ CRM_Core_DAO::executeQuery($sql);
+
+@@ -418,7 +420,7 @@ function from() {
+ $xTags = 0;
+ }
+
+- $sql = "CREATE TEMPORARY TABLE Xt_{$this->_tableName} ( contact_id int primary key) ENGINE=HEAP";
++ $sql = "CREATE TEMPORARY TABLE Xt_{$this->_tableName} ( contact_id int primary key) ENGINE=MyISAM";
+ CRM_Core_DAO::executeQuery($sql);
+
+ //used only when exclude tag is selected
+@@ -436,7 +438,7 @@ function from() {
+
+ $sql = "CREATE TEMPORARY TABLE It_{$this->_tableName} ( id int PRIMARY KEY AUTO_INCREMENT,
+ contact_id int,
+- tag_names varchar(64)) ENGINE=HEAP";
++ tag_names varchar(64)) ENGINE=MyISAM";
+
+ CRM_Core_DAO::executeQuery($sql);
+