/** * Check a string (mailing body) for required tokens. * * @param string $str The message * @return true|array true if all required tokens are found, * else an array of the missing tokens * @access public * @static */ public static function requiredTokens(&$str) { if (self::$_requiredTokens == null) { self::$_requiredTokens = array('domain.address' => ts("Domain address - displays your organization's postal address."), 'action.optOutUrl' => array('action.optOut' => ts("'Opt out via email' - displays an email address for recipients to opt out of receiving emails from your organization."), 'action.optOutUrl' => ts("'Opt out via web page' - creates a link for recipients to click if they want to opt out of receiving emails from your organization. Alternatively, you can include the 'Opt out via email' token."))); } $missing = array(); foreach (self::$_requiredTokens as $token => $value) { if (!is_array($value)) { if (!preg_match('/(^|[^\\{])' . preg_quote('{' . $token . '}') . '/', $str)) { $missing[$token] = $value; } } else { $present = false; $desc = null; foreach ($value as $t => $d) { $desc = $d; if (preg_match('/(^|[^\\{])' . preg_quote('{' . $t . '}') . '/', $str)) { $present = true; } } if (!$present) { $missing[$token] = $desc; } } } if (empty($missing)) { return true; } return $missing; }
/** * Get AngularJS modules and their dependencies * * @return array * list of modules; same format as CRM_Utils_Hook::angularModules(&$angularModules) * @see CRM_Utils_Hook::angularModules */ public function getAngularModules() { // load angular files only if valid permissions are granted to the user if (!CRM_Core_Permission::check('access CiviMail') && !CRM_Core_Permission::check('create mailings') && !CRM_Core_Permission::check('schedule mailings') && !CRM_Core_Permission::check('approve mailings')) { return array(); } $result = array(); $result['crmMailing'] = array('ext' => 'civicrm', 'js' => array('ang/crmMailing.js', 'ang/crmMailing/*.js'), 'css' => array('ang/crmMailing.css'), 'partials' => array('ang/crmMailing')); $result['crmMailingAB'] = array('ext' => 'civicrm', 'js' => array('ang/crmMailingAB.js', 'ang/crmMailingAB/*.js', 'ang/crmMailingAB/*/*.js'), 'css' => array('ang/crmMailingAB.css'), 'partials' => array('ang/crmMailingAB')); $result['crmD3'] = array('ext' => 'civicrm', 'js' => array('ang/crmD3.js', 'bower_components/d3/d3.min.js')); $config = CRM_Core_Config::singleton(); $session = CRM_Core_Session::singleton(); $contactID = $session->get('userID'); // Get past mailings // CRM-16155 - Limit to a reasonable number $civiMails = civicrm_api3('Mailing', 'get', array('is_completed' => 1, 'mailing_type' => array('IN' => array('standalone', 'winner')), 'return' => array('id', 'name', 'scheduled_date'), 'sequential' => 1, 'options' => array('limit' => 500, 'sort' => 'is_archived asc, scheduled_date desc'))); // Generic params $params = array('options' => array('limit' => 0), 'sequential' => 1); $groupNames = civicrm_api3('Group', 'get', $params + array('is_active' => 1, 'check_permissions' => TRUE, 'return' => array('title', 'visibility', 'group_type', 'is_hidden'))); $headerfooterList = civicrm_api3('MailingComponent', 'get', $params + array('is_active' => 1, 'return' => array('name', 'component_type', 'is_default', 'body_html', 'body_text'))); $emailAdd = civicrm_api3('Email', 'get', array('sequential' => 1, 'return' => "email", 'contact_id' => $contactID)); $mesTemplate = civicrm_api3('MessageTemplate', 'get', $params + array('sequential' => 1, 'is_active' => 1, 'return' => array("id", "msg_title"), 'workflow_id' => array('IS NULL' => ""))); $mailTokens = civicrm_api3('Mailing', 'gettokens', array('entity' => array('contact', 'mailing'), 'sequential' => 1)); $fromAddress = civicrm_api3('OptionValue', 'get', $params + array('option_group_id' => "from_email_address", 'domain_id' => CRM_Core_Config::domainID())); CRM_Core_Resources::singleton()->addSetting(array('crmMailing' => array('civiMails' => $civiMails['values'], 'campaignEnabled' => in_array('CiviCampaign', $config->enableComponents), 'groupNames' => $groupNames['values'], 'headerfooterList' => $headerfooterList['values'], 'mesTemplate' => $mesTemplate['values'], 'emailAdd' => $emailAdd['values'], 'mailTokens' => $mailTokens['values'], 'contactid' => $contactID, 'requiredTokens' => CRM_Utils_Token::getRequiredTokens(), 'enableReplyTo' => (int) CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, 'replyTo'), 'disableMandatoryTokensCheck' => (int) CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, 'disable_mandatory_tokens_check'), 'fromAddress' => $fromAddress['values'], 'defaultTestEmail' => civicrm_api3('Contact', 'getvalue', array('id' => 'user_contact_id', 'return' => 'email')), 'visibility' => CRM_Utils_Array::makeNonAssociative(CRM_Core_SelectValues::groupVisibility()), 'workflowEnabled' => CRM_Mailing_Info::workflowEnabled())))->addPermissions(array('view all contacts', 'access CiviMail', 'create mailings', 'schedule mailings', 'approve mailings', 'delete in CiviMail', 'edit message templates')); return $result; }
/** * Build the form object. */ public function buildQuickForm() { $this->applyFilter('__ALL__', 'trim'); $this->addFormRule(array('CRM_Admin_Form_Preferences_Address', 'formRule')); //get the tokens for Mailing Label field $tokens = CRM_Core_SelectValues::contactTokens(); $this->assign('tokens', CRM_Utils_Token::formatTokensForDisplay($tokens)); parent::buildQuickForm(); }
/** * Assert the content of document * * @param array $formValues * @param array $type */ public function _testDocumentContent($formValues, $type) { $html = array(); $form = new CRM_Contact_Form_Task_PDFLetterCommon(); list($formValues, $categories, $html_message, $messageToken, $returnProperties) = $form->processMessageTemplate($formValues); list($html_message, $zip) = CRM_Utils_PDF_Document::unzipDoc($formValues['document_file_path'], $formValues['document_type']); foreach ($this->_contactIds as $item => $contactId) { $params = array('contact_id' => $contactId); list($contact) = CRM_Utils_Token::getTokenDetails($params, $returnProperties, FALSE, FALSE, NULL, $messageToken, 'CRM_Contact_Form_Task_PDFLetterCommon'); $html[] = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken); } $returnContent = CRM_Utils_PDF_Document::printDocuments($formValues['document_file_path'], $html, $type, $zip, TRUE); $returnContent = strip_tags($returnContent); $this->assertTrue(strpos($returnContent, 'Hello Antonia D`souza') !== 0); $this->assertTrue(strpos($returnContent, 'Hello Anthony Collins') !== 0); }
/** * Apply the various CRM_Utils_Token helpers. * * @param TokenRenderEvent $e */ public function onRender(TokenRenderEvent $e) { $isHtml = $e->message['format'] == 'text/html'; $useSmarty = !empty($e->context['smarty']); $e->string = \CRM_Utils_Token::replaceDomainTokens($e->string, \CRM_Core_BAO_Domain::getDomain(), $isHtml, $e->message['tokens'], $useSmarty); if (!empty($e->context['contact'])) { $e->string = \CRM_Utils_Token::replaceContactTokens($e->string, $e->context['contact'], $isHtml, $e->message['tokens'], FALSE, $useSmarty); // FIXME: This may depend on $contact being merged with hook values. $e->string = \CRM_Utils_Token::replaceHookTokens($e->string, $e->context['contact'], $e->context['hookTokenCategories'], $isHtml, $useSmarty); \CRM_Utils_Token::replaceGreetingTokens($e->string, NULL, $e->context['contact']['contact_id'], NULL, $useSmarty); } if ($useSmarty) { $smarty = \CRM_Core_Smarty::singleton(); $e->string = $smarty->fetch("string:" . $e->string); } }
/** * generate htmlfor pdf letters * * @param array $membershipIDs * @param array $returnProperties * @param bool $skipOnHold * @param bool $skipDeceased * @param unknown_type $messageToken * @param $html_message * @param $categories * * @return unknown */ static function generateHTML($membershipIDs, $returnProperties, $skipOnHold, $skipDeceased, $messageToken, $html_message, $categories) { $memberships = CRM_Utils_Token::getMembershipTokenDetails($membershipIDs); foreach ($membershipIDs as $membershipID) { $membership = $memberships[$membershipID]; // get contact information $contactId = $membership['contact_id']; $params = array('contact_id' => $contactId); //getTokenDetails is much like calling the api contact.get function - but - with some minor // special handlings. It preceeds the existence of the api list($contacts) = CRM_Utils_Token::getTokenDetails($params, $returnProperties, $skipOnHold, $skipDeceased, NULL, $messageToken, 'CRM_Contribution_Form_Task_PDFLetterCommon'); $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contacts[$contactId], TRUE, $messageToken); $tokenHtml = CRM_Utils_Token::replaceEntityTokens('membership', $membership, $tokenHtml, $messageToken); $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contacts[$contactId], $categories, TRUE); $tokenHtml = CRM_Utils_Token::parseThroughSmarty($tokenHtml, $contacts[$contactId]); $html[] = $tokenHtml; } return $html; }
/** * Run this page (figure out the action needed and perform it). * * @return void */ public function run() { $session = CRM_Core_Session::singleton(); $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', CRM_Core_DAO::$_nullObject, FALSE, 'text'); $type = CRM_Utils_Request::retrieve('type', 'String', CRM_Core_DAO::$_nullObject, FALSE, 'text'); $options = array(); $session->getVars($options, "CRM_Mailing_Controller_Send_{$qfKey}"); //get the options if control come from search context, CRM-3711 if (empty($options)) { $session->getVars($options, "CRM_Contact_Controller_Search_{$qfKey}"); } // FIXME: the below and CRM_Mailing_Form_Test::testMail() // should be refactored $fromEmail = NULL; $mailing = new CRM_Mailing_BAO_Mailing(); if (!empty($options)) { $mailing->id = $options['mailing_id']; $fromEmail = CRM_Utils_Array::value('from_email', $options); } $mailing->find(TRUE); CRM_Mailing_BAO_Mailing::tokenReplace($mailing); // get and format attachments $attachments = CRM_Core_BAO_File::getEntityFile('civicrm_mailing', $mailing->id); //get details of contact with token value including Custom Field Token Values.CRM-3734 $returnProperties = $mailing->getReturnProperties(); $params = array('contact_id' => $session->get('userID')); $details = CRM_Utils_Token::getTokenDetails($params, $returnProperties, TRUE, TRUE, NULL, $mailing->getFlattenedTokens(), get_class($this)); $mime =& $mailing->compose(NULL, NULL, NULL, $session->get('userID'), $fromEmail, $fromEmail, TRUE, $details[0][$session->get('userID')], $attachments); if ($type == 'html') { CRM_Utils_System::setHttpHeader('Content-Type', 'text/html; charset=utf-8'); print $mime->getHTMLBody(); } else { CRM_Utils_System::setHttpHeader('Content-Type', 'text/plain; charset=utf-8'); print $mime->getTXTBody(); } CRM_Utils_System::civiExit(); }
/** * @param int $contactId * @param array $exportParams * * @return array */ public static function _replaceMergeTokens($contactId, $exportParams) { $greetings = array(); $contact = NULL; $greetingFields = array('postal_greeting', 'addressee'); foreach ($greetingFields as $greeting) { if (!empty($exportParams[$greeting])) { $greetingLabel = $exportParams[$greeting]; if (empty($contact)) { $values = array('id' => $contactId, 'version' => 3); $contact = civicrm_api('contact', 'get', $values); if (!empty($contact['is_error'])) { return $greetings; } $contact = $contact['values'][$contact['id']]; } $tokens = array('contact' => $greetingLabel); $greetings[$greeting] = CRM_Utils_Token::replaceContactTokens($greetingLabel, $contact, NULL, $tokens); } } return $greetings; }
/** * Function takes participant ids and statuses * update status from $fromStatusId to $toStatusId * and send mail + create activities. * * @param array $participantIds * Participant ids. * @param int $toStatusId * Update status id. * @param int $fromStatusId * From status id. * @param bool $returnResult * @param bool $skipCascadeRule * * @return array|NULL */ public static function transitionParticipants($participantIds, $toStatusId, $fromStatusId = NULL, $returnResult = FALSE, $skipCascadeRule = FALSE) { if (!is_array($participantIds) || empty($participantIds) || !$toStatusId) { return NULL; } //thumb rule is if we triggering primary participant need to triggered additional $allParticipantIds = $primaryANDAdditonalIds = array(); foreach ($participantIds as $id) { $allParticipantIds[] = $id; if (self::isPrimaryParticipant($id)) { //filter additional as per status transition rules, CRM-5403 if ($skipCascadeRule) { $additionalIds = self::getAdditionalParticipantIds($id); } else { $additionalIds = self::getValidAdditionalIds($id, $fromStatusId, $toStatusId); } if (!empty($additionalIds)) { $allParticipantIds = array_merge($allParticipantIds, $additionalIds); $primaryANDAdditonalIds[$id] = $additionalIds; } } } //get the unique participant ids, $allParticipantIds = array_unique($allParticipantIds); //pull required participants, contacts, events data, if not in hand static $eventDetails = array(); static $domainValues = array(); static $contactDetails = array(); $contactIds = $eventIds = $participantDetails = array(); $statusTypes = CRM_Event_PseudoConstant::participantStatus(); $participantRoles = CRM_Event_PseudoConstant::participantRole(); $pendingStatuses = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Pending'"); //first thing is pull all necessory data from db. $participantIdClause = '(' . implode(',', $allParticipantIds) . ')'; //get all participants data. $query = "SELECT * FROM civicrm_participant WHERE id IN {$participantIdClause}"; $dao = CRM_Core_DAO::executeQuery($query); while ($dao->fetch()) { $participantDetails[$dao->id] = array('id' => $dao->id, 'role' => $participantRoles[$dao->role_id], 'is_test' => $dao->is_test, 'event_id' => $dao->event_id, 'status_id' => $dao->status_id, 'fee_amount' => $dao->fee_amount, 'contact_id' => $dao->contact_id, 'register_date' => $dao->register_date, 'registered_by_id' => $dao->registered_by_id); if (!array_key_exists($dao->contact_id, $contactDetails)) { $contactIds[$dao->contact_id] = $dao->contact_id; } if (!array_key_exists($dao->event_id, $eventDetails)) { $eventIds[$dao->event_id] = $dao->event_id; } } //get the domain values. if (empty($domainValues)) { // making all tokens available to templates. $domain = CRM_Core_BAO_Domain::getDomain(); $tokens = array('domain' => array('name', 'phone', 'address', 'email'), 'contact' => CRM_Core_SelectValues::contactTokens()); foreach ($tokens['domain'] as $token) { $domainValues[$token] = CRM_Utils_Token::getDomainTokenReplacement($token, $domain); } } //get all required contacts detail. if (!empty($contactIds)) { // get the contact details. list($currentContactDetails) = CRM_Utils_Token::getTokenDetails($contactIds, NULL, FALSE, FALSE, NULL, array(), 'CRM_Event_BAO_Participant'); foreach ($currentContactDetails as $contactId => $contactValues) { $contactDetails[$contactId] = $contactValues; } } //get all required events detail. if (!empty($eventIds)) { foreach ($eventIds as $eventId) { //retrieve event information $eventParams = array('id' => $eventId); CRM_Event_BAO_Event::retrieve($eventParams, $eventDetails[$eventId]); //get default participant role. $eventDetails[$eventId]['participant_role'] = CRM_Utils_Array::value($eventDetails[$eventId]['default_role_id'], $participantRoles); //get the location info $locParams = array('entity_id' => $eventId, 'entity_table' => 'civicrm_event'); $eventDetails[$eventId]['location'] = CRM_Core_BAO_Location::getValues($locParams, TRUE); } } //now we are ready w/ all required data. //take a decision as per statuses. $emailType = NULL; $toStatus = $statusTypes[$toStatusId]; $fromStatus = CRM_Utils_Array::value($fromStatusId, $statusTypes); switch ($toStatus) { case 'Pending from waitlist': case 'Pending from approval': switch ($fromStatus) { case 'On waitlist': case 'Awaiting approval': $emailType = 'Confirm'; break; } break; case 'Expired': //no matter from where u come send expired mail. $emailType = $toStatus; break; case 'Cancelled': //no matter from where u come send cancel mail. $emailType = $toStatus; break; } //as we process additional w/ primary, there might be case if user //select primary as well as additionals, so avoid double processing. $processedParticipantIds = array(); $mailedParticipants = array(); //send mails and update status. foreach ($participantDetails as $participantId => $participantValues) { $updateParticipantIds = array(); if (in_array($participantId, $processedParticipantIds)) { continue; } //check is it primary and has additional. if (array_key_exists($participantId, $primaryANDAdditonalIds)) { foreach ($primaryANDAdditonalIds[$participantId] as $additonalId) { if ($emailType) { $mail = self::sendTransitionParticipantMail($additonalId, $participantDetails[$additonalId], $eventDetails[$participantDetails[$additonalId]['event_id']], $contactDetails[$participantDetails[$additonalId]['contact_id']], $domainValues, $emailType); //get the mail participant ids if ($mail) { $mailedParticipants[$additonalId] = $contactDetails[$participantDetails[$additonalId]['contact_id']]['display_name']; } } $updateParticipantIds[] = $additonalId; $processedParticipantIds[] = $additonalId; } } //now send email appropriate mail to primary. if ($emailType) { $mail = self::sendTransitionParticipantMail($participantId, $participantValues, $eventDetails[$participantValues['event_id']], $contactDetails[$participantValues['contact_id']], $domainValues, $emailType); //get the mail participant ids if ($mail) { $mailedParticipants[$participantId] = $contactDetails[$participantValues['contact_id']]['display_name']; } } //now update status of group/one at once. $updateParticipantIds[] = $participantId; //update the register date only when we, //move participant to pending class, CRM-6496 $updateRegisterDate = FALSE; if (array_key_exists($toStatusId, $pendingStatuses)) { $updateRegisterDate = TRUE; } self::updateStatus($updateParticipantIds, $toStatusId, $updateRegisterDate); $processedParticipantIds[] = $participantId; } //return result for cron. if ($returnResult) { $results = array('mailedParticipants' => $mailedParticipants, 'updatedParticipantIds' => $processedParticipantIds); return $results; } }
/** * Replace Contribution tokens in html. * * @param string $str * @param array $contribution * @param bool|string $html * @param string $knownTokens * @param bool|string $escapeSmarty * * @return 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 $str = preg_replace_callback(self::tokenRegex($key), function ($matches) use(&$contribution, $html, $escapeSmarty) { return CRM_Utils_Token::getContributionTokenReplacement($matches[1], $contribution, $html, $escapeSmarty); }, $str); $str = preg_replace('/\\\\|\\{(\\s*)?\\}/', ' ', $str); return $str; }
/** * Send SMS. * * @param array $contactDetails * @param array $activityParams * @param array $smsParams * @param $contactIds * @param int $userID * * @return array * @throws CRM_Core_Exception */ public static function sendSMS(&$contactDetails, &$activityParams, &$smsParams = array(), &$contactIds, $userID = NULL) { if ($userID == NULL) { $session = CRM_Core_Session::singleton(); $userID = $session->get('userID'); } $text =& $activityParams['sms_text_message']; // CRM-4575 // token replacement of addressee/email/postal greetings // get the tokens added in subject and message $messageToken = CRM_Utils_Token::getTokens($text); // Create the meta level record first ( sms activity ) $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'SMS', 'name'); $details = $text; $activitySubject = $activityParams['activity_subject']; $activityParams = array('source_contact_id' => $userID, 'activity_type_id' => $activityTypeID, 'activity_date_time' => date('YmdHis'), 'subject' => $activitySubject, 'details' => $details, 'status_id' => 2); $activity = self::create($activityParams); $activityID = $activity->id; $returnProperties = array(); if (isset($messageToken['contact'])) { foreach ($messageToken['contact'] as $key => $value) { $returnProperties[$value] = 1; } } // call token hook $tokens = array(); CRM_Utils_Hook::tokens($tokens); $categories = array_keys($tokens); // get token details for contacts, call only if tokens are used $details = array(); if (!empty($returnProperties) || !empty($tokens)) { list($details) = CRM_Utils_Token::getTokenDetails($contactIds, $returnProperties, NULL, NULL, FALSE, $messageToken, 'CRM_Activity_BAO_Activity'); } $success = 0; $escapeSmarty = FALSE; $errMsgs = array(); foreach ($contactDetails as $values) { $contactId = $values['contact_id']; if (!empty($details) && is_array($details["{$contactId}"])) { // unset email from details since it always returns primary email address unset($details["{$contactId}"]['email']); unset($details["{$contactId}"]['email_id']); $values = array_merge($values, $details["{$contactId}"]); } $tokenText = CRM_Utils_Token::replaceContactTokens($text, $values, FALSE, $messageToken, FALSE, $escapeSmarty); $tokenText = CRM_Utils_Token::replaceHookTokens($tokenText, $values, $categories, FALSE, $escapeSmarty); // Only send if the phone is of type mobile $phoneTypes = CRM_Core_OptionGroup::values('phone_type', TRUE, FALSE, FALSE, NULL, 'name'); if ($values['phone_type_id'] == CRM_Utils_Array::value('Mobile', $phoneTypes)) { $smsParams['To'] = $values['phone']; } else { $smsParams['To'] = ''; } $sendResult = self::sendSMSMessage($contactId, $tokenText, $smsParams, $activityID, $userID); if (PEAR::isError($sendResult)) { // Collect all of the PEAR_Error objects $errMsgs[] = $sendResult; } else { $success++; } } // If at least one message was sent and no errors // were generated then return a boolean value of TRUE. // Otherwise, return FALSE (no messages sent) or // and array of 1 or more PEAR_Error objects. $sent = FALSE; if ($success > 0 && count($errMsgs) == 0) { $sent = TRUE; } elseif (count($errMsgs) > 0) { $sent = $errMsgs; } return array($sent, $activity->id, $success); }
public static function updatePledgeStatus($params) { $returnMessages = array(); $sendReminders = CRM_Utils_Array::value('send_reminders', $params, FALSE); $allStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); //unset statues that we never use for pledges foreach (array('Completed', 'Cancelled', 'Failed') as $statusKey) { if ($key = CRM_Utils_Array::key($statusKey, $allStatus)) { unset($allStatus[$key]); } } $statusIds = implode(',', array_keys($allStatus)); $updateCnt = 0; $query = "\nSELECT pledge.contact_id as contact_id,\n pledge.id as pledge_id,\n pledge.amount as amount,\n payment.scheduled_date as scheduled_date,\n pledge.create_date as create_date,\n payment.id as payment_id,\n pledge.currency as currency,\n pledge.contribution_page_id as contribution_page_id,\n payment.reminder_count as reminder_count,\n pledge.max_reminders as max_reminders,\n payment.reminder_date as reminder_date,\n pledge.initial_reminder_day as initial_reminder_day,\n pledge.additional_reminder_day as additional_reminder_day,\n pledge.status_id as pledge_status,\n payment.status_id as payment_status,\n pledge.is_test as is_test,\n pledge.campaign_id as campaign_id,\n SUM(payment.scheduled_amount) as amount_due,\n ( SELECT sum(civicrm_pledge_payment.actual_amount)\n FROM civicrm_pledge_payment\n WHERE civicrm_pledge_payment.status_id = 1\n AND civicrm_pledge_payment.pledge_id = pledge.id\n ) as amount_paid\n FROM civicrm_pledge pledge, civicrm_pledge_payment payment\n WHERE pledge.id = payment.pledge_id\n AND payment.status_id IN ( {$statusIds} ) AND pledge.status_id IN ( {$statusIds} )\n GROUP By payment.id\n "; $dao = CRM_Core_DAO::executeQuery($query); $now = date('Ymd'); $pledgeDetails = $contactIds = $pledgePayments = $pledgeStatus = array(); while ($dao->fetch()) { $checksumValue = CRM_Contact_BAO_Contact_Utils::generateChecksum($dao->contact_id); $pledgeDetails[$dao->payment_id] = array('scheduled_date' => $dao->scheduled_date, 'amount_due' => $dao->amount_due, 'amount' => $dao->amount, 'amount_paid' => $dao->amount_paid, 'create_date' => $dao->create_date, 'contact_id' => $dao->contact_id, 'pledge_id' => $dao->pledge_id, 'checksumValue' => $checksumValue, 'contribution_page_id' => $dao->contribution_page_id, 'reminder_count' => $dao->reminder_count, 'max_reminders' => $dao->max_reminders, 'reminder_date' => $dao->reminder_date, 'initial_reminder_day' => $dao->initial_reminder_day, 'additional_reminder_day' => $dao->additional_reminder_day, 'pledge_status' => $dao->pledge_status, 'payment_status' => $dao->payment_status, 'is_test' => $dao->is_test, 'currency' => $dao->currency, 'campaign_id' => $dao->campaign_id); $contactIds[$dao->contact_id] = $dao->contact_id; $pledgeStatus[$dao->pledge_id] = $dao->pledge_status; if (CRM_Utils_Date::overdue(CRM_Utils_Date::customFormat($dao->scheduled_date, '%Y%m%d'), $now) && $dao->payment_status != array_search('Overdue', $allStatus)) { $pledgePayments[$dao->pledge_id][$dao->payment_id] = $dao->payment_id; } } // process the updating script... foreach ($pledgePayments as $pledgeId => $paymentIds) { // 1. update the pledge /pledge payment status. returns new status when an update happens $returnMessages[] = "Checking if status update is needed for Pledge Id: {$pledgeId} (current status is {$allStatus[$pledgeStatus[$pledgeId]]})"; $newStatus = CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeId, $paymentIds, array_search('Overdue', $allStatus), NULL, 0, FALSE, TRUE); if ($newStatus != $pledgeStatus[$pledgeId]) { $returnMessages[] = "- status updated to: {$allStatus[$newStatus]}"; $updateCnt += 1; } } if ($sendReminders) { // retrieve domain tokens $domain = CRM_Core_BAO_Domain::getDomain(); $tokens = array('domain' => array('name', 'phone', 'address', 'email'), 'contact' => CRM_Core_SelectValues::contactTokens()); $domainValues = array(); foreach ($tokens['domain'] as $token) { $domainValues[$token] = CRM_Utils_Token::getDomainTokenReplacement($token, $domain); } //get the domain email address, since we don't carry w/ object. $domainValue = CRM_Core_BAO_Domain::getNameAndEmail(); $domainValues['email'] = $domainValue[1]; // retrieve contact tokens // this function does NOT return Deceased contacts since we don't want to send them email list($contactDetails) = CRM_Utils_Token::getTokenDetails($contactIds, NULL, FALSE, FALSE, NULL, $tokens, 'CRM_UpdatePledgeRecord'); // assign domain values to template $template = CRM_Core_Smarty::singleton(); $template->assign('domain', $domainValues); //set receipt from $receiptFrom = '"' . $domainValues['name'] . '" <' . $domainValues['email'] . '>'; foreach ($pledgeDetails as $paymentId => $details) { if (array_key_exists($details['contact_id'], $contactDetails)) { $contactId = $details['contact_id']; $pledgerName = $contactDetails[$contactId]['display_name']; } else { continue; } if (empty($details['reminder_date'])) { $nextReminderDate = new DateTime($details['scheduled_date']); $nextReminderDate->modify("-" . $details['initial_reminder_day'] . "day"); $nextReminderDate = $nextReminderDate->format("Ymd"); } else { $nextReminderDate = new DateTime($details['reminder_date']); $nextReminderDate->modify("+" . $details['additional_reminder_day'] . "day"); $nextReminderDate = $nextReminderDate->format("Ymd"); } if ($details['reminder_count'] < $details['max_reminders'] && $nextReminderDate <= $now) { $toEmail = $doNotEmail = $onHold = NULL; if (!empty($contactDetails[$contactId]['email'])) { $toEmail = $contactDetails[$contactId]['email']; } if (!empty($contactDetails[$contactId]['do_not_email'])) { $doNotEmail = $contactDetails[$contactId]['do_not_email']; } if (!empty($contactDetails[$contactId]['on_hold'])) { $onHold = $contactDetails[$contactId]['on_hold']; } // 2. send acknowledgement mail if ($toEmail && !($doNotEmail || $onHold)) { //assign value to template $template->assign('amount_paid', $details['amount_paid'] ? $details['amount_paid'] : 0); $template->assign('contact', $contactDetails[$contactId]); $template->assign('next_payment', $details['scheduled_date']); $template->assign('amount_due', $details['amount_due']); $template->assign('checksumValue', $details['checksumValue']); $template->assign('contribution_page_id', $details['contribution_page_id']); $template->assign('pledge_id', $details['pledge_id']); $template->assign('scheduled_payment_date', $details['scheduled_date']); $template->assign('amount', $details['amount']); $template->assign('create_date', $details['create_date']); $template->assign('currency', $details['currency']); list($mailSent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate(array('groupName' => 'msg_tpl_workflow_pledge', 'valueName' => 'pledge_reminder', 'contactId' => $contactId, 'from' => $receiptFrom, 'toName' => $pledgerName, 'toEmail' => $toEmail)); // 3. update pledge payment details if ($mailSent) { CRM_Pledge_BAO_PledgePayment::updateReminderDetails($paymentId); $activityType = 'Pledge Reminder'; $activityParams = array('subject' => $subject, 'source_contact_id' => $contactId, 'source_record_id' => $paymentId, 'assignee_contact_id' => $contactId, 'activity_type_id' => CRM_Core_OptionGroup::getValue('activity_type', $activityType, 'name'), 'activity_date_time' => CRM_Utils_Date::isoToMysql($now), 'due_date_time' => CRM_Utils_Date::isoToMysql($details['scheduled_date']), 'is_test' => $details['is_test'], 'status_id' => 2, 'campaign_id' => $details['campaign_id']); if (is_a(civicrm_api('activity', 'create', $activityParams), 'CRM_Core_Error')) { $returnMessages[] = "Failed creating Activity for acknowledgment"; return array('is_error' => 1, 'message' => $returnMessages); } $returnMessages[] = "Payment reminder sent to: {$pledgerName} - {$toEmail}"; } } } } // end foreach on $pledgeDetails } // end if ( $sendReminders ) $returnMessages[] = "{$updateCnt} records updated."; return array('is_error' => 0, 'messages' => implode("\n\r", $returnMessages)); }
/** * Cancel this participant and finish, send cancellation email. At this point no * auto-cancellation of payment is handled, so payment needs to be manually cancelled * * return @void */ public function cancelParticipant($params) { //set participant record status to Cancelled, refund payment if possible // send email to participant and admin, and log Activity $value = array(); $value['id'] = $this->_participant_id; $cancelledId = array_search('Cancelled', CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Negative'")); $value['status_id'] = $cancelledId; CRM_Event_BAO_Participant::create($value); $domainValues = array(); $domain = CRM_Core_BAO_Domain::getDomain(); $tokens = array('domain' => array('name', 'phone', 'address', 'email'), 'contact' => CRM_Core_SelectValues::contactTokens()); foreach ($tokens['domain'] as $token) { $domainValues[$token] = CRM_Utils_Token::getDomainTokenReplacement($token, $domain); } $participantRoles = array(); $participantRoles = CRM_Event_PseudoConstant::participantRole(); $participantDetails = array(); $query = "SELECT * FROM civicrm_participant WHERE id = {$this->_participant_id}"; $dao = CRM_Core_DAO::executeQuery($query); while ($dao->fetch()) { $participantDetails[$dao->id] = array('id' => $dao->id, 'role' => $participantRoles[$dao->role_id], 'is_test' => $dao->is_test, 'event_id' => $dao->event_id, 'status_id' => $dao->status_id, 'fee_amount' => $dao->fee_amount, 'contact_id' => $dao->contact_id, 'register_date' => $dao->register_date, 'registered_by_id' => $dao->registered_by_id); } $eventDetails = array(); $eventParams = array('id' => $this->_event_id); CRM_Event_BAO_Event::retrieve($eventParams, $eventDetails[$this->_event_id]); //get default participant role. $eventDetails[$this->_event_id]['participant_role'] = CRM_Utils_Array::value($eventDetails[$this->_event_id]['default_role_id'], $participantRoles); //get the location info $locParams = array('entity_id' => $this->_event_id, 'entity_table' => 'civicrm_event'); $eventDetails[$this->_event_id]['location'] = CRM_Core_BAO_Location::getValues($locParams, TRUE); //get contact details $contactIds[$this->_contact_id] = $this->_contact_id; list($currentContactDetails) = CRM_Utils_Token::getTokenDetails($contactIds, NULL, FALSE, FALSE, NULL, array(), 'CRM_Event_BAO_Participant'); foreach ($currentContactDetails as $contactId => $contactValues) { $contactDetails[$this->_contact_id] = $contactValues; } //send a 'cancelled' email to user, and cc the event's cc_confirm email $mail = CRM_Event_BAO_Participant::sendTransitionParticipantMail($this->_participant_id, $participantDetails[$this->_participant_id], $eventDetails[$this->_event_id], $contactDetails[$this->_contact_id], $domainValues, "Cancelled", ""); $statusMsg = ts('Event registration information for %1 has been updated.', array(1 => $this->_contact_name)); $statusMsg .= ' ' . ts('A cancellation email has been sent to %1.', array(1 => $this->_contact_email)); CRM_Core_Session::setStatus($statusMsg, ts('Saved'), 'success'); $url = CRM_Utils_System::url('civicrm/event/info', "reset=1&id={$this->_event_id}&noFullMsg=true"); CRM_Utils_System::redirect($url); }
/** * Function for validation * * @param array $params (ref.) an assoc array of name/value pairs * * @param $files * @param $self * * @return mixed true or array of errors * @access public * @static */ static function formRule($params, $files, $self) { if (!empty($_POST['_qf_Import_refresh'])) { return TRUE; } $errors = array(); $template = CRM_Core_Smarty::singleton(); $domain = CRM_Core_BAO_Domain::getDomain(); $mailing = new CRM_Mailing_BAO_Mailing(); $mailing->id = $self->_mailingID; $mailing->find(TRUE); $session = CRM_Core_Session::singleton(); $values = array('contact_id' => $session->get('userID'), 'version' => 3); require_once 'api/api.php'; $contact = civicrm_api('contact', 'get', $values); //CRM-4524 $contact = reset($contact['values']); $verp = array_flip(array('optOut', 'reply', 'unsubscribe', 'resubscribe', 'owner')); foreach ($verp as $key => $value) { $verp[$key]++; } $urls = array_flip(array('forward', 'optOutUrl', 'unsubscribeUrl', 'resubscribeUrl')); foreach ($urls as $key => $value) { $urls[$key]++; } $skipTextFile = $self->get('skipTextFile'); if (!$params['upload_type']) { if (!isset($files['textFile']) || !file_exists($files['textFile']['tmp_name'])) { if (!$skipTextFile) { $errors['textFile'] = ts('Please provide a Text'); } } } else { if (empty($params['text_message'])) { $errors['text_message'] = ts('Please provide a Text'); } else { if (!empty($params['text_message'])) { $messageCheck = CRM_Utils_Array::value('text_message', $params); if ($messageCheck && strlen($messageCheck) > CRM_SMS_Provider::MAX_SMS_CHAR) { $errors['text_message'] = ts("You can configure the SMS message body up to %1 characters", array(1 => CRM_SMS_Provider::MAX_SMS_CHAR)); } } } if (!empty($params['saveTemplate']) && empty($params['saveTemplateName'])) { $errors['saveTemplateName'] = ts('Please provide a Template Name.'); } } if ($params['upload_type'] || file_exists(CRM_Utils_Array::value('tmp_name', $files['textFile'])) || !$params['upload_type'] && $params['text_message']) { if (!$params['upload_type']) { $str = file_get_contents($files['textFile']['tmp_name']); $name = $files['textFile']['name']; } else { $str = $params['text_message']; $name = 'text message'; } $dataErrors = array(); /* Do a full token replacement on a dummy verp, the current * contact and domain, and the first organization. */ // here we make a dummy mailing object so that we // can retrieve the tokens that we need to replace // so that we do get an invalid token error // this is qute hacky and I hope that there might // be a suggestion from someone on how to // make it a bit more elegant $dummy_mail = new CRM_Mailing_BAO_Mailing(); $mess = "body_text"; $dummy_mail->{$mess} = $str; $tokens = $dummy_mail->getTokens(); $str = CRM_Utils_Token::replaceSubscribeInviteTokens($str); $str = CRM_Utils_Token::replaceDomainTokens($str, $domain, NULL, $tokens['text']); $str = CRM_Utils_Token::replaceMailingTokens($str, $mailing, NULL, $tokens['text']); $str = CRM_Utils_Token::replaceOrgTokens($str, $org); $str = CRM_Utils_Token::replaceActionTokens($str, $verp, $urls, NULL, $tokens['text']); $str = CRM_Utils_Token::replaceContactTokens($str, $contact, NULL, $tokens['text']); $unmatched = CRM_Utils_Token::unmatchedTokens($str); $contentCheck = CRM_Utils_String::htmlToText($str); if (!empty($unmatched) && 0) { foreach ($unmatched as $token) { $dataErrors[] = '<li>' . ts('Invalid token code') . ' {' . $token . '}</li>'; } } if (strlen($contentCheck) > CRM_SMS_Provider::MAX_SMS_CHAR) { $dataErrors[] = '<li>' . ts('The body of the SMS cannot exceed %1 characters.', array(1 => CRM_SMS_Provider::MAX_SMS_CHAR)) . '</li>'; } if (!empty($dataErrors)) { $errors['textFile'] = ts('The following errors were detected in %1:', array(1 => $name)) . ' <ul>' . implode('', $dataErrors) . '</ul>'; } } $templateName = CRM_Core_BAO_MessageTemplate::getMessageTemplates(); if (!empty($params['saveTemplate']) && in_array(CRM_Utils_Array::value('saveTemplateName', $params), $templateName)) { $errors['saveTemplate'] = ts('Duplicate Template Name.'); } return empty($errors) ? TRUE : $errors; }
/** * Ask a contact for subscription confirmation (opt-in) * * @param string $email * The email address. * * @return void */ public function send_confirm_request($email) { $config = CRM_Core_Config::singleton(); $domain = CRM_Core_BAO_Domain::getDomain(); //get the default domain email address. list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail(); $localpart = CRM_Core_BAO_MailSettings::defaultLocalpart(); $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain(); $confirm = implode($config->verpSeparator, array($localpart . 'c', $this->contact_id, $this->id, $this->hash)) . "@{$emailDomain}"; $group = new CRM_Contact_BAO_Group(); $group->id = $this->group_id; $group->find(TRUE); $component = new CRM_Mailing_BAO_Component(); $component->is_default = 1; $component->is_active = 1; $component->component_type = 'Subscribe'; $component->find(TRUE); $headers = array('Subject' => $component->subject, 'From' => "\"{$domainEmailName}\" <{$domainEmailAddress}>", 'To' => $email, 'Reply-To' => $confirm, 'Return-Path' => "do-not-reply@{$emailDomain}"); $url = CRM_Utils_System::url('civicrm/mailing/confirm', "reset=1&cid={$this->contact_id}&sid={$this->id}&h={$this->hash}", TRUE); $html = $component->body_html; if ($component->body_text) { $text = $component->body_text; } else { $text = CRM_Utils_String::htmlToText($component->body_html); } $bao = new CRM_Mailing_BAO_Mailing(); $bao->body_text = $text; $bao->body_html = $html; $tokens = $bao->getTokens(); $html = CRM_Utils_Token::replaceDomainTokens($html, $domain, TRUE, $tokens['html']); $html = CRM_Utils_Token::replaceSubscribeTokens($html, $group->title, $url, TRUE); $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, FALSE, $tokens['text']); $text = CRM_Utils_Token::replaceSubscribeTokens($text, $group->title, $url, FALSE); // render the & entities in text mode, so that the links work $text = str_replace('&', '&', $text); $message = new Mail_mime("\n"); $message->setHTMLBody($html); $message->setTxtBody($text); $b = CRM_Utils_Mail::setMimeParams($message); $h = $message->headers($headers); CRM_Mailing_BAO_Mailing::addMessageIdHeader($h, 's', $this->contact_id, $this->id, $this->hash); $mailer = \Civi::service('pear_mail'); if (is_object($mailer)) { $errorScope = CRM_Core_TemporaryErrorScope::ignoreException(); $mailer->send($email, $h, $b); unset($errorScope); } }
/** * Process a greeting template string to produce the individualised greeting text. * * This works just like message templates for mailings: * the template is processed with the token substitution mechanism, * to supply the individual contact data; * and it is also processed with Smarty, * to allow for conditionals etc. based on the contact data. * * Note: We don't pass any variables to Smarty -- * all variable data is inserted into the input string * by the token substitution mechanism, * before Smarty is invoked. * * @param string $templateString * The greeting template string with contact tokens + Smarty syntax. * * @param array $contactDetails * @param int $contactID * @param string $className */ public static function processGreetingTemplate(&$templateString, $contactDetails, $contactID, $className) { CRM_Utils_Token::replaceGreetingTokens($templateString, $contactDetails, $contactID, $className, TRUE); $smarty = CRM_Core_Smarty::singleton(); $templateString = $smarty->fetch("string:{$templateString}"); }
/** * @param $fields * @param $mailing * @param $mailer * @param $job_date * @param $attachments * * @return bool|null * @throws Exception */ public function deliverGroup(&$fields, &$mailing, &$mailer, &$job_date, &$attachments) { static $smtpConnectionErrors = 0; if (!is_object($mailer) || empty($fields)) { CRM_Core_Error::fatal(); } // get the return properties $returnProperties = $mailing->getReturnProperties(); $params = $targetParams = $deliveredParams = array(); $count = 0; /** * CRM-15702: Sending bulk sms to contacts without e-mail address fails. * Solution is to skip checking for on hold */ $skipOnHold = TRUE; //do include a statement to check wether e-mail address is on hold if ($mailing->sms_provider_id) { $skipOnHold = FALSE; //do not include a statement to check wether e-mail address is on hold } foreach ($fields as $key => $field) { $params[] = $field['contact_id']; } $details = CRM_Utils_Token::getTokenDetails($params, $returnProperties, $skipOnHold, TRUE, NULL, $mailing->getFlattenedTokens(), get_class($this), $this->id); $config = CRM_Core_Config::singleton(); foreach ($fields as $key => $field) { $contactID = $field['contact_id']; if (!array_key_exists($contactID, $details[0])) { $details[0][$contactID] = array(); } /* Compose the mailing */ $recipient = $replyToEmail = NULL; $replyValue = strcmp($mailing->replyto_email, $mailing->from_email); if ($replyValue) { $replyToEmail = $mailing->replyto_email; } $message =& $mailing->compose($this->id, $field['id'], $field['hash'], $field['contact_id'], $field['email'], $recipient, FALSE, $details[0][$contactID], $attachments, FALSE, NULL, $replyToEmail); if (empty($message)) { // lets keep the message in the queue // most likely a permissions related issue with smarty templates // or a bad contact id? CRM-9833 continue; } /* Send the mailing */ $body =& $message->get(); $headers =& $message->headers(); if ($mailing->sms_provider_id) { $provider = CRM_SMS_Provider::singleton(array('mailing_id' => $mailing->id)); $body = $provider->getMessage($message, $field['contact_id'], $details[0][$contactID]); $headers = $provider->getRecipientDetails($field, $details[0][$contactID]); } // make $recipient actually be the *encoded* header, so as not to baffle Mail_RFC822, CRM-5743 $recipient = $headers['To']; $result = NULL; // disable error reporting on real mailings (but leave error reporting for tests), CRM-5744 if ($job_date) { $errorScope = CRM_Core_TemporaryErrorScope::ignoreException(); } $result = $mailer->send($recipient, $headers, $body, $this->id); if ($job_date) { unset($errorScope); } if (is_a($result, 'PEAR_Error') && !$mailing->sms_provider_id) { // CRM-9191 $message = $result->getMessage(); if (strpos($message, 'Failed to write to socket') !== FALSE || strpos($message, 'Failed to set sender') !== FALSE) { // lets log this message and code $code = $result->getCode(); CRM_Core_Error::debug_log_message("SMTP Socket Error or failed to set sender error. Message: {$message}, Code: {$code}"); // these are socket write errors which most likely means smtp connection errors // lets skip them $smtpConnectionErrors++; if ($smtpConnectionErrors <= 5) { continue; } // seems like we have too many of them in a row, we should // write stuff to disk and abort the cron job $this->writeToDB($deliveredParams, $targetParams, $mailing, $job_date); CRM_Core_Error::debug_log_message("Too many SMTP Socket Errors. Exiting"); CRM_Utils_System::civiExit(); } /* Register the bounce event */ $params = array('event_queue_id' => $field['id'], 'job_id' => $this->id, 'hash' => $field['hash']); $params = array_merge($params, CRM_Mailing_BAO_BouncePattern::match($result->getMessage())); CRM_Mailing_Event_BAO_Bounce::create($params); } elseif (is_a($result, 'PEAR_Error') && $mailing->sms_provider_id) { // Handle SMS errors: CRM-15426 $job_id = intval($this->id); $mailing_id = intval($mailing->id); CRM_Core_Error::debug_log_message("Failed to send SMS message. Vars: mailing_id: {$mailing_id}, job_id: {$job_id}. Error message follows."); CRM_Core_Error::debug_log_message($result->getMessage()); } else { /* Register the delivery event */ $deliveredParams[] = $field['id']; $targetParams[] = $field['contact_id']; $count++; if ($count % CRM_Core_DAO::BULK_MAIL_INSERT_COUNT == 0) { $this->writeToDB($deliveredParams, $targetParams, $mailing, $job_date); $count = 0; // hack to stop mailing job at run time, CRM-4246. // to avoid making too many DB calls for this rare case // lets do it when we snapshot $status = CRM_Core_DAO::getFieldValue('CRM_Mailing_DAO_MailingJob', $this->id, 'status', 'id', TRUE); if ($status != 'Running') { return FALSE; } } } unset($result); // seems like a successful delivery or bounce, lets decrement error count // only if we have smtp connection errors if ($smtpConnectionErrors > 0) { $smtpConnectionErrors--; } // If we have enabled the Throttle option, this is the time to enforce it. if (isset($config->mailThrottleTime) && $config->mailThrottleTime > 0) { usleep((int) $config->mailThrottleTime); } } $result = $this->writeToDB($deliveredParams, $targetParams, $mailing, $job_date); return $result; }
/** * Preview mailing. * * @param array $params * Array per getfields metadata. * * @return array * @throws \API_Exception */ function civicrm_api3_mailing_preview($params) { civicrm_api3_verify_mandatory($params, 'CRM_Mailing_DAO_Mailing', array('id'), FALSE); $fromEmail = NULL; if (!empty($params['from_email'])) { $fromEmail = $params['from_email']; } $session = CRM_Core_Session::singleton(); $mailing = new CRM_Mailing_BAO_Mailing(); $mailing->id = $params['id']; $mailing->find(TRUE); CRM_Mailing_BAO_Mailing::tokenReplace($mailing); // get and format attachments $attachments = CRM_Core_BAO_File::getEntityFile('civicrm_mailing', $mailing->id); $returnProperties = $mailing->getReturnProperties(); $contactID = CRM_Utils_Array::value('contact_id', $params); if (!$contactID) { $contactID = $session->get('userID'); } $mailingParams = array('contact_id' => $contactID); $details = CRM_Utils_Token::getTokenDetails($mailingParams, $returnProperties, TRUE, TRUE, NULL, $mailing->getFlattenedTokens()); $mime =& $mailing->compose(NULL, NULL, NULL, $session->get('userID'), $fromEmail, $fromEmail, TRUE, $details[0][$contactID], $attachments); return civicrm_api3_create_success(array('id' => $params['id'], 'contact_id' => $contactID, 'subject' => $mime->_headers['Subject'], 'body_html' => $mime->getHTMLBody(), 'body_text' => $mime->getTXTBody())); }
/** * process the form after the input has been submitted and validated * * @access public * * @return void */ public function postProcess() { $fv = $this->controller->exportValues($this->_name); $config = CRM_Core_Config::singleton(); $locName = NULL; //get the address format sequence from the config file $mailingFormat = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'mailing_format'); $sequence = CRM_Utils_Address::sequence($mailingFormat); foreach ($sequence as $v) { $address[$v] = 1; } if (array_key_exists('postal_code', $address)) { $address['postal_code_suffix'] = 1; } //build the returnproperties $returnProperties = array('display_name' => 1, 'contact_type' => 1); $mailingFormat = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'mailing_format'); $mailingFormatProperties = array(); if ($mailingFormat) { $mailingFormatProperties = self::getReturnProperties($mailingFormat); $returnProperties = array_merge($returnProperties, $mailingFormatProperties); } //we should not consider addressee for data exists, CRM-6025 if (array_key_exists('addressee', $mailingFormatProperties)) { unset($mailingFormatProperties['addressee']); } $customFormatProperties = array(); if (stristr($mailingFormat, 'custom_')) { foreach ($mailingFormatProperties as $token => $true) { if (substr($token, 0, 7) == 'custom_') { if (empty($customFormatProperties[$token])) { $customFormatProperties[$token] = $mailingFormatProperties[$token]; } } } } if (!empty($customFormatProperties)) { $returnProperties = array_merge($returnProperties, $customFormatProperties); } if (isset($fv['merge_same_address'])) { // we need first name/last name for summarising to avoid spillage $returnProperties['first_name'] = 1; $returnProperties['last_name'] = 1; } $individualFormat = FALSE; /* * CRM-8338: replace ids of household members with the id of their household * so we can merge labels by household. */ if (isset($fv['merge_same_household'])) { $this->mergeContactIdsByHousehold(); $individualFormat = TRUE; } //get the contacts information $params = array(); if (!empty($fv['location_type_id'])) { $locType = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'); $locName = $locType[$fv['location_type_id']]; $location = array('location' => array("{$locName}" => $address)); $returnProperties = array_merge($returnProperties, $location); $params[] = array('location_type', '=', array($fv['location_type_id'] => 1), 0, 0); } else { $returnProperties = array_merge($returnProperties, $address); } $rows = array(); foreach ($this->_contactIds as $key => $contactID) { $params[] = array(CRM_Core_Form::CB_PREFIX . $contactID, '=', 1, 0, 0); } // fix for CRM-2651 if (!empty($fv['do_not_mail'])) { $params[] = array('do_not_mail', '=', 0, 0, 0); } // fix for CRM-2613 $params[] = array('is_deceased', '=', 0, 0, 0); $custom = array(); foreach ($returnProperties as $name => $dontCare) { $cfID = CRM_Core_BAO_CustomField::getKeyID($name); if ($cfID) { $custom[] = $cfID; } } //get the total number of contacts to fetch from database. $numberofContacts = count($this->_contactIds); $query = new CRM_Contact_BAO_Query($params, $returnProperties); $details = $query->apiQuery($params, $returnProperties, NULL, NULL, 0, $numberofContacts); $messageToken = CRM_Utils_Token::getTokens($mailingFormat); // also get all token values CRM_Utils_Hook::tokenValues($details[0], $this->_contactIds, NULL, $messageToken, 'CRM_Contact_Form_Task_Label'); $tokens = array(); CRM_Utils_Hook::tokens($tokens); $tokenFields = array(); foreach ($tokens as $category => $catTokens) { foreach ($catTokens as $token => $tokenName) { $tokenFields[] = $token; } } foreach ($this->_contactIds as $value) { foreach ($custom as $cfID) { if (isset($details[0][$value]["custom_{$cfID}"])) { $details[0][$value]["custom_{$cfID}"] = CRM_Core_BAO_CustomField::getDisplayValue($details[0][$value]["custom_{$cfID}"], $cfID, $details[1]); } } $contact = CRM_Utils_Array::value($value, $details['0']); if (is_a($contact, 'CRM_Core_Error')) { return NULL; } // we need to remove all the "_id" unset($contact['contact_id']); if ($locName && !empty($contact[$locName])) { // If location type is not primary, $contact contains // one more array as "$contact[$locName] = array( values... )" if (!$this->tokenIsFound($contact, $mailingFormatProperties, $tokenFields)) { continue; } unset($contact[$locName]); if (!empty($contact['county_id'])) { unset($contact['county_id']); } foreach ($contact as $field => $fieldValue) { $rows[$value][$field] = $fieldValue; } $valuesothers = array(); $paramsothers = array('contact_id' => $value); $valuesothers = CRM_Core_BAO_Location::getValues($paramsothers, $valuesothers); if (!empty($fv['location_type_id'])) { foreach ($valuesothers as $vals) { if (CRM_Utils_Array::value('location_type_id', $vals) == CRM_Utils_Array::value('location_type_id', $fv)) { foreach ($vals as $k => $v) { if (in_array($k, array('email', 'phone', 'im', 'openid'))) { if ($k == 'im') { $rows[$value][$k] = $v['1']['name']; } else { $rows[$value][$k] = $v['1'][$k]; } $rows[$value][$k . '_id'] = $v['1']['id']; } } } } } } else { if (!$this->tokenIsFound($contact, $mailingFormatProperties, $tokenFields)) { continue; } if (!empty($contact['addressee_display'])) { $contact['addressee_display'] = trim($contact['addressee_display']); } if (!empty($contact['addressee'])) { $contact['addressee'] = $contact['addressee_display']; } // now create the rows for generating mailing labels foreach ($contact as $field => $fieldValue) { $rows[$value][$field] = $fieldValue; } } } if (isset($fv['merge_same_address'])) { $this->mergeSameAddress($rows); $individualFormat = TRUE; } // format the addresses according to CIVICRM_ADDRESS_FORMAT (CRM-1327) foreach ($rows as $id => $row) { if ($commMethods = CRM_Utils_Array::value('preferred_communication_method', $row)) { $val = array_filter(explode(CRM_Core_DAO::VALUE_SEPARATOR, $commMethods)); $comm = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'preferred_communication_method'); $temp = array(); foreach ($val as $vals) { $temp[] = $comm[$vals]; } $row['preferred_communication_method'] = implode(', ', $temp); } $row['id'] = $id; $formatted = CRM_Utils_Address::format($row, 'mailing_format', FALSE, TRUE, $individualFormat, $tokenFields); // CRM-2211: UFPDF doesn't have bidi support; use the PECL fribidi package to fix it. // On Ubuntu (possibly Debian?) be aware of http://pecl.php.net/bugs/bug.php?id=12366 // Due to FriBidi peculiarities, this can't be called on // a multi-line string, hence the explode+implode approach. if (function_exists('fribidi_log2vis')) { $lines = explode("\n", $formatted); foreach ($lines as $i => $line) { $lines[$i] = fribidi_log2vis($line, FRIBIDI_AUTO, FRIBIDI_CHARSET_UTF8); } $formatted = implode("\n", $lines); } $rows[$id] = array($formatted); } //call function to create labels self::createLabel($rows, $fv['label_name']); CRM_Utils_System::civiExit(1); }
/** * Build the compose mail form. * * @param CRM_Core_Form $form * * @return void */ public static function commonCompose(&$form) { //get the tokens. $tokens = array(); if (method_exists($form, 'listTokens')) { $tokens = array_merge($form->listTokens(), $tokens); } //sorted in ascending order tokens by ignoring word case $form->assign('tokens', CRM_Utils_Token::formatTokensForDisplay($tokens)); $templates = array(); $textFields = array('text_message' => ts('HTML Format'), 'sms_text_message' => ts('SMS Message')); $modePrefixes = array('Mail' => NULL, 'SMS' => 'SMS'); $className = CRM_Utils_System::getClassName($form); if ($className != 'CRM_SMS_Form_Upload' && $className != 'CRM_Contact_Form_Task_SMS' && $className != 'CRM_Contact_Form_Task_SMS') { $form->add('wysiwyg', 'html_message', ts('HTML Format'), array('cols' => '80', 'rows' => '8', 'onkeyup' => "return verify(this)")); if ($className != 'CRM_Admin_Form_ScheduleReminders') { unset($modePrefixes['SMS']); } } else { unset($textFields['text_message']); unset($modePrefixes['Mail']); } //insert message Text by selecting "Select Template option" foreach ($textFields as $id => $label) { $prefix = NULL; if ($id == 'sms_text_message') { $prefix = "SMS"; $form->assign('max_sms_length', CRM_SMS_Provider::MAX_SMS_CHAR); } $form->add('textarea', $id, $label, array('cols' => '80', 'rows' => '8', 'onkeyup' => "return verify(this, '{$prefix}')")); } foreach ($modePrefixes as $prefix) { if ($prefix == 'SMS') { $templates[$prefix] = CRM_Core_BAO_MessageTemplate::getMessageTemplates(FALSE, TRUE); } else { $templates[$prefix] = CRM_Core_BAO_MessageTemplate::getMessageTemplates(FALSE); } if (!empty($templates[$prefix])) { $form->assign('templates', TRUE); $form->add('select', "{$prefix}template", ts('Use Template'), array('' => ts('- select -')) + $templates[$prefix], FALSE, array('onChange' => "selectValue( this.value, '{$prefix}');")); } $form->add('checkbox', "{$prefix}updateTemplate", ts('Update Template'), NULL); $form->add('checkbox', "{$prefix}saveTemplate", ts('Save As New Template'), NULL, FALSE, array('onclick' => "showSaveDetails(this, '{$prefix}');")); $form->add('text', "{$prefix}saveTemplateName", ts('Template Title')); } // I'm not sure this is ever called. $action = CRM_Utils_Request::retrieve('action', 'String', $form, FALSE); if (CRM_Utils_System::getClassName($form) == 'CRM_Contact_Form_Task_PDF' && $action == CRM_Core_Action::VIEW) { $form->freeze('html_message'); } }
/** * Confirm a pending subscription * * @param int $contact_id The id of the contact * @param int $subscribe_id The id of the subscription event * @param string $hash The hash * @return boolean True on success * @access public * @static */ function confirm($contact_id, $subscribe_id, $hash) { $se =& CRM_Mailing_Event_BAO_Subscribe::verify($contact_id, $subscribe_id, $hash); if (!$se) { return false; } CRM_Core_DAO::transaction('BEGIN'); $ce =& new CRM_Mailing_Event_BAO_Confirm(); $ce->event_subscribe_id = $se->id; $ce->time_stamp = date('YmdHis'); $ce->save(); CRM_Contact_BAO_GroupContact::updateGroupMembershipStatus($contact_id, $se->group_id, 'Email', $ce->id); CRM_Core_DAO::transaction('COMMIT'); $config =& CRM_Core_Config::singleton(); $domain =& CRM_Mailing_Event_BAO_Subscribe::getDomain($subscribe_id); list($display_name, $email) = CRM_Contact_BAO_Contact::getEmailDetails($se->contact_id); $group =& new CRM_Contact_DAO_Group(); $group->id = $se->group_id; $group->find(true); require_once 'CRM/Mailing/BAO/Component.php'; $component =& new CRM_Mailing_BAO_Component(); $component->domain_id = $domain->id; $component->is_default = 1; $component->is_active = 1; $component->component_type = 'Welcome'; $component->find(true); $headers = array('Subject' => $component->subject, 'From' => ts('"%1 Administrator" <do-not-reply@%2>', array(1 => $domain->name, 2 => $domain->email_domain)), 'To' => $email, 'Reply-To' => "do-not-reply@{$domain->email_domain}", 'Return-Path' => "do-not-reply@{$domain->email_domain}"); $html = $component->body_html; require_once 'CRM/Utils/Token.php'; $html = CRM_Utils_Token::replaceDomainTokens($html, $domain, true); $html = CRM_Utils_Token::replaceWelcomeTokens($html, $group->name, true); $text = $component->body_text; $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, false); $text = CRM_Utils_Token::replaceWelcomeTokens($text, $group->name, false); $message =& new Mail_Mime("\n"); $message->setHTMLBody($html); $message->setTxtBody($text); $b = $message->get(); $h = $message->headers($headers); $mailer =& $config->getMailer(); PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array('CRM_Mailing_BAO_Mailing', 'catchSMTP')); $mailer->send($email, $h, $b); CRM_Core_Error::setCallback(); return true; }
/** * process the form after the input has been submitted and validated * * @access public * * @return void */ public function postProcess() { // get all the details needed to generate a receipt $contribIDs = implode(',', $this->_contributionIds); $details = CRM_Contribute_Form_Task_Status::getDetails($contribIDs); $baseIPN = new CRM_Core_Payment_BaseIPN(); $message = array(); $template = CRM_Core_Smarty::singleton(); $params = $this->controller->exportValues($this->_name); $createPdf = FALSE; if ($params['output'] == "pdf_receipt") { $createPdf = TRUE; } $excludeContactIds = array(); if (!$createPdf) { $returnProperties = array('email' => 1, 'do_not_email' => 1, 'is_deceased' => 1, 'on_hold' => 1); list($contactDetails) = CRM_Utils_Token::getTokenDetails($this->_contactIds, $returnProperties, FALSE, FALSE); $suppressedEmails = 0; foreach ($contactDetails as $id => $values) { if (empty($values['email']) || !empty($values['do_not_email']) || CRM_Utils_Array::value('is_deceased', $values) || !empty($values['on_hold'])) { $suppressedEmails++; $excludeContactIds[] = $values['contact_id']; } } } foreach ($details as $contribID => $detail) { $input = $ids = $objects = array(); if (in_array($detail['contact'], $excludeContactIds)) { continue; } $input['component'] = $detail['component']; $ids['contact'] = $detail['contact']; $ids['contribution'] = $contribID; $ids['contributionRecur'] = NULL; $ids['contributionPage'] = NULL; $ids['membership'] = CRM_Utils_Array::value('membership', $detail); $ids['participant'] = CRM_Utils_Array::value('participant', $detail); $ids['event'] = CRM_Utils_Array::value('event', $detail); if (!$baseIPN->validateData($input, $ids, $objects, FALSE)) { CRM_Core_Error::fatal(); } $contribution =& $objects['contribution']; // CRM_Core_Error::debug('o',$objects); // set some fake input values so we can reuse IPN code $input['amount'] = $contribution->total_amount; $input['is_test'] = $contribution->is_test; $input['fee_amount'] = $contribution->fee_amount; $input['net_amount'] = $contribution->net_amount; $input['trxn_id'] = $contribution->trxn_id; $input['trxn_date'] = isset($contribution->trxn_date) ? $contribution->trxn_date : NULL; // CRM_Contribute_BAO_Contribution::composeMessageArray expects mysql formatted date $objects['contribution']->receive_date = CRM_Utils_Date::isoToMysql($objects['contribution']->receive_date); // CRM_Core_Error::debug('input',$input); $values = array(); $mail = $baseIPN->sendMail($input, $ids, $objects, $values, FALSE, $createPdf); if ($mail['html']) { $message[] = $mail['html']; } else { $message[] = nl2br($mail['body']); } // reset template values before processing next transactions $template->clearTemplateVars(); } if ($createPdf) { CRM_Utils_PDF_Utils::html2pdf($message, 'civicrmContributionReceipt.pdf', FALSE, $params['pdf_format_id']); CRM_Utils_System::civiExit(); } else { if ($suppressedEmails) { $status = ts('Email was NOT sent to %1 contacts (no email address on file, or communication preferences specify DO NOT EMAIL, or contact is deceased).', array(1 => $suppressedEmails)); $msgTitle = ts('Email Error'); $msgType = 'error'; } else { $status = ts('Your mail has been sent.'); $msgTitle = ts('Sent'); $msgType = 'success'; } CRM_Core_Session::setStatus($status, $msgTitle, $msgType); } }
/** * Build the form object. * * @return void */ public function buildQuickForm() { // For VIEW we only want Done button if ($this->_action & CRM_Core_Action::VIEW) { // currently, the above action is used solely for previewing default workflow templates $cancelURL = CRM_Utils_System::url('civicrm/admin/messageTemplates', 'selectedChild=workflow&reset=1'); $cancelURL = str_replace('&', '&', $cancelURL); $this->addButtons(array(array('type' => 'cancel', 'name' => ts('Done'), 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"), 'isDefault' => TRUE))); } else { parent::buildQuickForm(); } if ($this->_action & CRM_Core_Action::DELETE) { return; } $breadCrumb = array(array('title' => ts('Message Templates'), 'url' => CRM_Utils_System::url('civicrm/admin/messageTemplates', 'action=browse&reset=1'))); CRM_Utils_System::appendBreadCrumb($breadCrumb); $this->applyFilter('__ALL__', 'trim'); $this->add('text', 'msg_title', ts('Message Title'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_MessageTemplate', 'msg_title'), TRUE); $this->add('text', 'msg_subject', ts('Message Subject'), CRM_Core_DAO::getAttribute('CRM_Core_DAO_MessageTemplate', 'msg_subject')); //get the tokens. $tokens = CRM_Core_SelectValues::contactTokens(); $this->assign('tokens', CRM_Utils_Token::formatTokensForDisplay($tokens)); // if not a system message use a wysiwyg editor, CRM-5971 if ($this->_id && CRM_Core_DAO::getFieldValue('CRM_Core_DAO_MessageTemplate', $this->_id, 'workflow_id')) { $this->add('textarea', 'msg_html', ts('HTML Message'), "cols=50 rows=6"); } else { $this->addWysiwyg('msg_html', ts('HTML Message'), array('cols' => '80', 'rows' => '8', 'onkeyup' => "return verify(this)")); } $this->add('textarea', 'msg_text', ts('Text Message'), "cols=50 rows=6"); $this->add('select', 'pdf_format_id', ts('PDF Page Format'), array('null' => ts('- default -')) + CRM_Core_BAO_PdfFormat::getList(TRUE), FALSE); $this->add('checkbox', 'is_active', ts('Enabled?')); if ($this->_action & CRM_Core_Action::VIEW) { $this->freeze(); CRM_Utils_System::setTitle(ts('View System Default Message Template')); } }
/** * Validation. * * @param array $params * (ref.) an assoc array of name/value pairs. * * @param $files * @param $self * * @return bool|array * mixed true or array of errors */ public static function formRule($params, $files, $self) { if (!empty($_POST['_qf_Import_refresh'])) { return TRUE; } $errors = array(); $template = CRM_Core_Smarty::singleton(); if (isset($params['html_message'])) { $htmlMessage = str_replace(array("\n", "\r"), ' ', $params['html_message']); $htmlMessage = str_replace("'", "\\'", $htmlMessage); $template->assign('htmlContent', $htmlMessage); } $domain = CRM_Core_BAO_Domain::getDomain(); $mailing = new CRM_Mailing_BAO_Mailing(); $mailing->id = $self->_mailingID; $mailing->find(TRUE); $session = CRM_Core_Session::singleton(); $values = array('contact_id' => $session->get('userID'), 'version' => 3); require_once 'api/api.php'; $contact = civicrm_api('contact', 'get', $values); //CRM-4524 $contact = reset($contact['values']); $verp = array_flip(array('optOut', 'reply', 'unsubscribe', 'resubscribe', 'owner')); foreach ($verp as $key => $value) { $verp[$key]++; } $urls = array_flip(array('forward', 'optOutUrl', 'unsubscribeUrl', 'resubscribeUrl')); foreach ($urls as $key => $value) { $urls[$key]++; } // set $header and $footer foreach (array('header', 'footer') as $part) { ${$part} = array(); if ($params["{$part}_id"]) { //echo "found<p>"; $component = new CRM_Mailing_BAO_Component(); $component->id = $params["{$part}_id"]; $component->find(TRUE); ${$part}['textFile'] = $component->body_text; ${$part}['htmlFile'] = $component->body_html; $component->free(); } else { ${$part}['htmlFile'] = ${$part}['textFile'] = ''; } } $skipTextFile = $self->get('skipTextFile'); $skipHtmlFile = $self->get('skipHtmlFile'); if (!$params['upload_type']) { if ((!isset($files['textFile']) || !file_exists($files['textFile']['tmp_name'])) && (!isset($files['htmlFile']) || !file_exists($files['htmlFile']['tmp_name']))) { if (!($skipTextFile || $skipHtmlFile)) { $errors['textFile'] = ts('Please provide either a Text or HTML formatted message - or both.'); } } } else { if (empty($params['text_message']) && empty($params['html_message'])) { $errors['html_message'] = ts('Please provide either a Text or HTML formatted message - or both.'); } if (!empty($params['saveTemplate']) && empty($params['saveTemplateName'])) { $errors['saveTemplateName'] = ts('Please provide a Template Name.'); } } foreach (array('text', 'html') as $file) { if (!$params['upload_type'] && !file_exists(CRM_Utils_Array::value('tmp_name', $files[$file . 'File']))) { continue; } if ($params['upload_type'] && !$params[$file . '_message']) { continue; } if (!$params['upload_type']) { $str = file_get_contents($files[$file . 'File']['tmp_name']); $name = $files[$file . 'File']['name']; } else { $str = $params[$file . '_message']; $str = $file == 'html' ? str_replace('%7B', '{', str_replace('%7D', '}', $str)) : $str; $name = $file . ' message'; } /* append header/footer */ $str = $header[$file . 'File'] . $str . $footer[$file . 'File']; $dataErrors = array(); /* First look for missing tokens */ if (!CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, 'disable_mandatory_tokens_check')) { $err = CRM_Utils_Token::requiredTokens($str); if ($err !== TRUE) { foreach ($err as $token => $desc) { $dataErrors[] = '<li>' . ts('This message is missing a required token - {%1}: %2', array(1 => $token, 2 => $desc)) . '</li>'; } } } /* Do a full token replacement on a dummy verp, the current * contact and domain, and the first organization. */ // here we make a dummy mailing object so that we // can retrieve the tokens that we need to replace // so that we do get an invalid token error // this is qute hacky and I hope that there might // be a suggestion from someone on how to // make it a bit more elegant $dummy_mail = new CRM_Mailing_BAO_Mailing(); $mess = "body_{$file}"; $dummy_mail->{$mess} = $str; $tokens = $dummy_mail->getTokens(); $str = CRM_Utils_Token::replaceSubscribeInviteTokens($str); $str = CRM_Utils_Token::replaceDomainTokens($str, $domain, NULL, $tokens[$file]); $str = CRM_Utils_Token::replaceMailingTokens($str, $mailing, NULL, $tokens[$file]); $str = CRM_Utils_Token::replaceOrgTokens($str, $org); $str = CRM_Utils_Token::replaceActionTokens($str, $verp, $urls, NULL, $tokens[$file]); $str = CRM_Utils_Token::replaceContactTokens($str, $contact, NULL, $tokens[$file]); $unmatched = CRM_Utils_Token::unmatchedTokens($str); if (!empty($unmatched) && 0) { foreach ($unmatched as $token) { $dataErrors[] = '<li>' . ts('Invalid token code') . ' {' . $token . '}</li>'; } } if (!empty($dataErrors)) { $errors[$file . 'File'] = ts('The following errors were detected in %1:', array(1 => $name)) . ' <ul>' . implode('', $dataErrors) . '</ul><br /><a href="' . CRM_Utils_System::docURL2('Sample CiviMail Messages', TRUE, NULL, NULL, NULL, "wiki") . '" target="_blank">' . ts('More information on required tokens...') . '</a>'; } } $templateName = CRM_Core_BAO_MessageTemplate::getMessageTemplates(); if (!empty($params['saveTemplate']) && in_array(CRM_Utils_Array::value('saveTemplateName', $params), $templateName)) { $errors['saveTemplate'] = ts('Duplicate Template Name.'); } return empty($errors) ? TRUE : $errors; }
/** * Confirm a pending subscription * * @param int $contact_id The id of the contact * @param int $subscribe_id The id of the subscription event * @param string $hash The hash * * @return boolean True on success * @access public * @static */ public static function confirm($contact_id, $subscribe_id, $hash) { $se =& CRM_Mailing_Event_BAO_Subscribe::verify($contact_id, $subscribe_id, $hash); if (!$se) { return FALSE; } // before we proceed lets just check if this contact is already 'Added' // if so, we should ignore this request and hence avoid sending multiple // emails - CRM-11157 $details = CRM_Contact_BAO_GroupContact::getMembershipDetail($contact_id, $se->group_id); if ($details && $details->status == 'Added') { // This contact is already subscribed // lets return the group title return CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $se->group_id, 'title'); } $transaction = new CRM_Core_Transaction(); $ce = new CRM_Mailing_Event_BAO_Confirm(); $ce->event_subscribe_id = $se->id; $ce->time_stamp = date('YmdHis'); $ce->save(); CRM_Contact_BAO_GroupContact::addContactsToGroup(array($contact_id), $se->group_id, 'Email', 'Added', $ce->id); $transaction->commit(); $config = CRM_Core_Config::singleton(); $domain = CRM_Core_BAO_Domain::getDomain(); list($domainEmailName, $_) = CRM_Core_BAO_Domain::getNameAndEmail(); list($display_name, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($se->contact_id); $group = new CRM_Contact_DAO_Group(); $group->id = $se->group_id; $group->find(TRUE); $component = new CRM_Mailing_BAO_Component(); $component->is_default = 1; $component->is_active = 1; $component->component_type = 'Welcome'; $component->find(TRUE); $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain(); $html = $component->body_html; if ($component->body_text) { $text = $component->body_text; } else { $text = CRM_Utils_String::htmlToText($component->body_html); } $bao = new CRM_Mailing_BAO_Mailing(); $bao->body_text = $text; $bao->body_html = $html; $tokens = $bao->getTokens(); $html = CRM_Utils_Token::replaceDomainTokens($html, $domain, TRUE, $tokens['html']); $html = CRM_Utils_Token::replaceWelcomeTokens($html, $group->title, TRUE); $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, FALSE, $tokens['text']); $text = CRM_Utils_Token::replaceWelcomeTokens($text, $group->title, FALSE); $mailParams = array('groupName' => 'Mailing Event ' . $component->component_type, 'subject' => $component->subject, 'from' => "\"{$domainEmailName}\" <do-not-reply@{$emailDomain}>", 'toEmail' => $email, 'toName' => $display_name, 'replyTo' => "do-not-reply@{$emailDomain}", 'returnPath' => "do-not-reply@{$emailDomain}", 'html' => $html, 'text' => $text); // send - ignore errors because the desired status change has already been successful $unused_result = CRM_Utils_Mail::send($mailParams); return $group->title; }
/** * Send a reponse email informing the contact of the groups from which he * has been unsubscribed. * * @param string $queue_id The queue event ID * @param array $groups List of group IDs * @param bool $is_domain Is this domain-level? * @param int $job The job ID * @return void * @access public * @static */ public static function send_unsub_response($queue_id, $groups, $is_domain = false, $job) { $config =& CRM_Core_Config::singleton(); $domain =& CRM_Core_BAO_Domain::getDomain(); $jobTable = CRM_Mailing_BAO_Job::getTableName(); $mailingTable = CRM_Mailing_DAO_Mailing::getTableName(); $contacts = CRM_Contact_DAO_Contact::getTableName(); $email = CRM_Core_DAO_Email::getTableName(); $queue = CRM_Mailing_Event_BAO_Queue::getTableName(); //get the default domain email address. list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail(); $dao =& new CRM_Mailing_BAO_Mailing(); $dao->query(" SELECT * FROM {$mailingTable} \n INNER JOIN {$jobTable} ON\n {$jobTable}.mailing_id = {$mailingTable}.id \n WHERE {$jobTable}.id = {$job}"); $dao->fetch(); $component =& new CRM_Mailing_BAO_Component(); if ($is_domain) { $component->id = $dao->optout_id; } else { $component->id = $dao->unsubscribe_id; } $component->find(true); $html = $component->body_html; if ($component->body_text) { $text = $component->body_text; } else { $text = CRM_Utils_String::htmlToText($component->body_html); } $eq =& new CRM_Core_DAO(); $eq->query("SELECT {$contacts}.preferred_mail_format as format,\n {$contacts}.id as contact_id,\n {$email}.email as email,\n {$queue}.hash as hash\n FROM {$contacts}\n INNER JOIN {$queue} ON {$queue}.contact_id = {$contacts}.id\n INNER JOIN {$email} ON {$queue}.email_id = {$email}.id\n WHERE {$queue}.id = " . CRM_Utils_Type::escape($queue_id, 'Integer')); $eq->fetch(); if ($groups) { foreach ($groups as $key => $value) { if (!$value) { unset($groups[$key]); } } } $message =& new Mail_Mime("\n"); list($addresses, $urls) = CRM_Mailing_BAO_Mailing::getVerpAndUrls($job, $queue_id, $eq->hash, $eq->email); $bao =& new CRM_Mailing_BAO_Mailing(); $bao->body_text = $text; $bao->body_html = $html; $tokens = $bao->getTokens(); require_once 'CRM/Utils/Token.php'; if ($eq->format == 'HTML' || $eq->format == 'Both') { $html = CRM_Utils_Token::replaceDomainTokens($html, $domain, true, $tokens['html']); $html = CRM_Utils_Token::replaceUnsubscribeTokens($html, $domain, $groups, true, $eq->contact_id, $eq->hash); $html = CRM_Utils_Token::replaceActionTokens($html, $addresses, $urls, true, $tokens['html']); $html = CRM_Utils_Token::replaceMailingTokens($html, $dao, null, $tokens['html']); $message->setHTMLBody($html); } if (!$html || $eq->format == 'Text' || $eq->format == 'Both') { $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, false, $tokens['text']); $text = CRM_Utils_Token::replaceUnsubscribeTokens($text, $domain, $groups, false, $eq->contact_id, $eq->hash); $text = CRM_Utils_Token::replaceActionTokens($text, $addresses, $urls, false, $tokens['text']); $text = CRM_Utils_Token::replaceMailingTokens($text, $dao, null, $tokens['text']); $message->setTxtBody($text); } require_once 'CRM/Core/BAO/MailSettings.php'; $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain(); $headers = array('Subject' => $component->subject, 'From' => "\"{$domainEmailName}\" <do-not-reply@{$emailDomain}>", 'To' => $eq->email, 'Reply-To' => "do-not-reply@{$emailDomain}", 'Return-Path' => "do-not-reply@{$emailDomain}"); $b =& CRM_Utils_Mail::setMimeParams($message); $h =& $message->headers($headers); $mailer =& $config->getMailer(); PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array('CRM_Core_Error', 'nullHandler')); if (is_object($mailer)) { $mailer->send($eq->email, $h, $b); CRM_Core_Error::setCallback(); } }
/** * Build the form object. * * * @param CRM_Core_Form $form * * @return void */ public static function buildQuickForm(&$form) { $toArray = array(); $providers = CRM_SMS_BAO_Provider::getProviders(NULL, NULL, TRUE, 'is_default desc'); $providerSelect = array(); foreach ($providers as $provider) { $providerSelect[$provider['id']] = $provider['title']; } $suppressedSms = 0; //here we are getting logged in user id as array but we need target contact id. CRM-5988 $cid = $form->get('cid'); if ($cid) { $form->_contactIds = array($cid); } $to = $form->add('text', 'to', ts('To'), array('class' => 'huge'), TRUE); $form->add('text', 'activity_subject', ts('Name The SMS'), array('class' => 'huge'), TRUE); $toSetDefault = TRUE; if (property_exists($form, '_context') && $form->_context == 'standalone') { $toSetDefault = FALSE; } // when form is submitted recompute contactIds $allToSMS = array(); if ($to->getValue()) { $allToPhone = explode(',', $to->getValue()); $form->_contactIds = array(); foreach ($allToPhone as $value) { list($contactId, $phone) = explode('::', $value); if ($contactId) { $form->_contactIds[] = $contactId; $form->_toContactPhone[] = $phone; } } $toSetDefault = TRUE; } //get the group of contacts as per selected by user in case of Find Activities if (!empty($form->_activityHolderIds)) { $extendTargetContacts = 0; $invalidActivity = 0; $validActivities = 0; foreach ($form->_activityHolderIds as $key => $id) { //valid activity check if (CRM_Core_DAO::getFieldValue('CRM_Activity_DAO_Activity', $id, 'subject', 'id') != self::RECIEVED_SMS_ACTIVITY_SUBJECT) { $invalidActivity++; continue; } $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name'); $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts); //target contacts limit check $ids = array_keys(CRM_Activity_BAO_ActivityContact::getNames($id, $targetID)); if (count($ids) > 1) { $extendTargetContacts++; continue; } $validActivities++; $form->_contactIds = empty($form->_contactIds) ? $ids : array_unique(array_merge($form->_contactIds, $ids)); } if (!$validActivities) { $errorMess = ""; if ($extendTargetContacts) { $errorMess = ts('One selected activity consists of more than one target contact.', array('count' => $extendTargetContacts, 'plural' => '%count selected activities consist of more than one target contact.')); } if ($invalidActivity) { $errorMess = $errorMess ? ' ' : ''; $errorMess .= ts('The selected activity is invalid.', array('count' => $invalidActivity, 'plural' => '%count selected activities are invalid.')); } CRM_Core_Error::statusBounce(ts("%1: SMS Reply will not be sent.", array(1 => $errorMess))); } } if (is_array($form->_contactIds) && !empty($form->_contactIds) && $toSetDefault) { $returnProperties = array('sort_name' => 1, 'phone' => 1, 'do_not_sms' => 1, 'is_deceased' => 1, 'display_name' => 1); list($form->_contactDetails) = CRM_Utils_Token::getTokenDetails($form->_contactIds, $returnProperties, FALSE, FALSE); // make a copy of all contact details $form->_allContactDetails = $form->_contactDetails; foreach ($form->_contactIds as $key => $contactId) { $value = $form->_contactDetails[$contactId]; //to check if the phone type is "Mobile" $phoneTypes = CRM_Core_OptionGroup::values('phone_type', TRUE, FALSE, FALSE, NULL, 'name'); if (CRM_Utils_System::getClassName($form) == 'CRM_Activity_Form_Task_SMS') { //to check for "if the contact id belongs to a specified activity type" $actDetails = CRM_Activity_BAO_Activity::getContactActivity($contactId); if (self::RECIEVED_SMS_ACTIVITY_SUBJECT != CRM_Utils_Array::retrieveValueRecursive($actDetails, 'subject')) { $suppressedSms++; unset($form->_contactDetails[$contactId]); continue; } } if (isset($value['phone_type_id']) && $value['phone_type_id'] != CRM_Utils_Array::value('Mobile', $phoneTypes) || $value['do_not_sms'] || empty($value['phone']) || !empty($value['is_deceased'])) { //if phone is not primary check if non-primary phone is "Mobile" if (!empty($value['phone']) && $value['phone_type_id'] != CRM_Utils_Array::value('Mobile', $phoneTypes) && empty($value['is_deceased'])) { $filter = array('do_not_sms' => 0); $contactPhones = CRM_Core_BAO_Phone::allPhones($contactId, FALSE, 'Mobile', $filter); if (count($contactPhones) > 0) { $mobilePhone = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'phone'); $form->_contactDetails[$contactId]['phone_id'] = CRM_Utils_Array::retrieveValueRecursive($contactPhones, 'id'); $form->_contactDetails[$contactId]['phone'] = $mobilePhone; $form->_contactDetails[$contactId]['phone_type_id'] = CRM_Utils_Array::value('Mobile', $phoneTypes); } else { $suppressedSms++; unset($form->_contactDetails[$contactId]); continue; } } else { $suppressedSms++; unset($form->_contactDetails[$contactId]); continue; } } if (isset($mobilePhone)) { $phone = $mobilePhone; } elseif (empty($form->_toContactPhone)) { $phone = $value['phone']; } else { $phone = CRM_Utils_Array::value($key, $form->_toContactPhone); } if ($phone) { $toArray[] = array('text' => '"' . $value['sort_name'] . '" (' . $phone . ')', 'id' => "{$contactId}::{$phone}"); } } if (empty($toArray)) { CRM_Core_Error::statusBounce(ts('Selected contact(s) do not have a valid Phone, or communication preferences specify DO NOT SMS, or they are deceased')); } } //activity related variables if (isset($invalidActivity)) { $form->assign('invalidActivity', $invalidActivity); } if (isset($extendTargetContacts)) { $form->assign('extendTargetContacts', $extendTargetContacts); } $form->assign('toContact', json_encode($toArray)); $form->assign('suppressedSms', $suppressedSms); $form->assign('totalSelectedContacts', count($form->_contactIds)); $form->add('select', 'sms_provider_id', ts('From'), $providerSelect, TRUE); CRM_Mailing_BAO_Mailing::commonCompose($form); if ($form->_single) { // also fix the user context stack if ($form->_context) { $url = CRM_Utils_System::url('civicrm/dashboard', 'reset=1'); } else { $url = CRM_Utils_System::url('civicrm/contact/view', "&show=1&action=browse&cid={$form->_contactIds[0]}&selectedChild=activity"); } $session = CRM_Core_Session::singleton(); $session->replaceUserContext($url); $form->addDefaultButtons(ts('Send SMS'), 'upload', 'cancel'); } else { $form->addDefaultButtons(ts('Send SMS'), 'upload'); } $form->addFormRule(array('CRM_Contact_Form_Task_SMSCommon', 'formRule'), $form); }
public function buildQuickForm() { $session = CRM_Core_Session::singleton(); $this->add('text', 'test_email', ts('Send to This Address')); $defaults['test_email'] = $session->get('ufUniqID'); $qfKey = $this->get('qfKey'); $this->add('select', 'test_group', ts('Send to This Group'), array('' => ts('- none -')) + CRM_Core_PseudoConstant::group('Mailing')); $this->setDefaults($defaults); $this->add('submit', 'sendtest', ts('Send a Test Mailing')); $name = ts('Next'); if (CRM_Mailing_Info::workflowEnabled()) { if (!CRM_Core_Permission::check('schedule mailings') && CRM_Core_Permission::check('create mailings')) { $name = ts('Inform Scheduler'); } } $buttons = array(array('type' => 'back', 'name' => ts('Previous')), array('type' => 'next', 'name' => $name, 'spacing' => ' ', 'isDefault' => TRUE), array('type' => 'submit', 'name' => ts('Save & Continue Later')), array('type' => 'cancel', 'name' => ts('Cancel'))); $this->addButtons($buttons); $mailingID = $this->get('mailing_id'); $textFile = $this->get('textFile'); $htmlFile = $this->get('htmlFile'); $this->addFormRule(array('CRM_Mailing_Form_Test', 'testMail'), $this); $preview = array(); if ($textFile) { $preview['text_link'] = CRM_Utils_System::url('civicrm/mailing/preview', "type=text&qfKey={$qfKey}"); } if ($htmlFile) { $preview['html_link'] = CRM_Utils_System::url('civicrm/mailing/preview', "type=html&qfKey={$qfKey}"); } $preview['attachment'] = CRM_Core_BAO_File::attachmentInfo('civicrm_mailing', $mailingID); $this->assign('preview', $preview); //Token Replacement of Subject in preview mailing $options = array(); $prefix = "CRM_Mailing_Controller_Send_{$qfKey}"; if ($this->_searchBasedMailing) { $prefix = "CRM_Contact_Controller_Search_{$qfKey}"; } $session->getVars($options, $prefix); $mailing = new CRM_Mailing_BAO_Mailing(); $mailing->id = $options['mailing_id']; $mailing->find(TRUE); $fromEmail = $mailing->from_email; $replyToEmail = $mailing->replyto_email; $attachments = CRM_Core_BAO_File::getEntityFile('civicrm_mailing', $mailing->id); $returnProperties = $mailing->getReturnProperties(); $userID = $session->get('userID'); $params = array('contact_id' => $userID); $details = CRM_Utils_Token::getTokenDetails($params, $returnProperties, TRUE, TRUE, NULL, $mailing->getFlattenedTokens(), get_class($this)); $allDetails =& $mailing->compose(NULL, NULL, NULL, $userID, $fromEmail, $fromEmail, TRUE, $details[0][$userID], $attachments); $this->assign('subject', $allDetails->_headers['Subject']); }
/** * Declaration of common variables for Invoice and PDF. * * * @param array $contribIds * Contribution Id. * @param array $params * Parameter for pdf or email invoices. * @param array $contactIds * Contact Id. * * @return array * array of common elements * */ public static function getElements($contribIds, $params, $contactIds) { $pdfElements = array(); $pdfElements['contribIDs'] = implode(',', $contribIds); $pdfElements['details'] = CRM_Contribute_Form_Task_Status::getDetails($pdfElements['contribIDs']); $pdfElements['baseIPN'] = new CRM_Core_Payment_BaseIPN(); $pdfElements['params'] = $params; $pdfElements['createPdf'] = FALSE; if (!empty($pdfElements['params']['output']) && ($pdfElements['params']['output'] == "pdf_invoice" || $pdfElements['params']['output'] == "pdf_receipt")) { $pdfElements['createPdf'] = TRUE; } $excludeContactIds = array(); if (!$pdfElements['createPdf']) { $returnProperties = array('email' => 1, 'do_not_email' => 1, 'is_deceased' => 1, 'on_hold' => 1); list($contactDetails) = CRM_Utils_Token::getTokenDetails($contactIds, $returnProperties, FALSE, FALSE); $pdfElements['suppressedEmails'] = 0; $suppressedEmails = 0; foreach ($contactDetails as $id => $values) { if (empty($values['email']) || empty($params['override_privacy']) && !empty($values['do_not_email']) || CRM_Utils_Array::value('is_deceased', $values) || !empty($values['on_hold'])) { $suppressedEmails++; $pdfElements['suppressedEmails'] = $suppressedEmails; $excludeContactIds[] = $values['contact_id']; } } } $pdfElements['excludeContactIds'] = $excludeContactIds; return $pdfElements; }
/** * @param $contactId * @param $to * @param $scheduleID * @param $from * @param $tokenParams * * @return bool|null * @throws CRM_Core_Exception */ static function sendReminder($contactId, $to, $scheduleID, $from, $tokenParams) { $email = $to['email']; $phoneNumber = $to['phone']; $schedule = new CRM_Core_DAO_ActionSchedule(); $schedule->id = $scheduleID; $domain = CRM_Core_BAO_Domain::getDomain(); $result = NULL; $hookTokens = array(); if ($schedule->find(TRUE)) { $body_text = $schedule->body_text; $body_html = $schedule->body_html; $sms_body_text = $schedule->sms_body_text; $body_subject = $schedule->subject; if (!$body_text) { $body_text = CRM_Utils_String::htmlToText($body_html); } $params = array(array('contact_id', '=', $contactId, 0, 0)); list($contact, $_) = CRM_Contact_BAO_Query::apiQuery($params); //CRM-4524 $contact = reset($contact); if (!$contact || is_a($contact, 'CRM_Core_Error')) { return NULL; } // merge activity tokens with contact array $contact = array_merge($contact, $tokenParams); //CRM-5734 CRM_Utils_Hook::tokenValues($contact, $contactId); CRM_Utils_Hook::tokens($hookTokens); $categories = array_keys($hookTokens); $type = array('body_html' => 'html', 'body_text' => 'text', 'sms_body_text' => 'text'); foreach ($type as $bodyType => $value) { $dummy_mail = new CRM_Mailing_BAO_Mailing(); if ($bodyType == 'sms_body_text') { $dummy_mail->body_text = ${$bodyType}; } else { $dummy_mail->{${$bodyType}} = ${$bodyType}; } $tokens = $dummy_mail->getTokens(); if (${$bodyType}) { CRM_Utils_Token::replaceGreetingTokens(${$bodyType}, NULL, $contact['contact_id']); ${$bodyType} = CRM_Utils_Token::replaceDomainTokens(${$bodyType}, $domain, TRUE, $tokens[$value], TRUE); ${$bodyType} = CRM_Utils_Token::replaceContactTokens(${$bodyType}, $contact, FALSE, $tokens[$value], FALSE, TRUE); ${$bodyType} = CRM_Utils_Token::replaceComponentTokens(${$bodyType}, $contact, $tokens[$value], TRUE, FALSE); ${$bodyType} = CRM_Utils_Token::replaceHookTokens(${$bodyType}, $contact, $categories, TRUE); } } $html = $body_html; $text = $body_text; $sms_text = $sms_body_text; $smarty = CRM_Core_Smarty::singleton(); foreach (array('text', 'html', 'sms_text') as $elem) { ${$elem} = $smarty->fetch("string:{${$elem}}"); } $matches = array(); preg_match_all('/(?<!\\{|\\\\)\\{(\\w+\\.\\w+)\\}(?!\\})/', $body_subject, $matches, PREG_PATTERN_ORDER); $subjectToken = NULL; if ($matches[1]) { foreach ($matches[1] as $token) { list($type, $name) = preg_split('/\\./', $token, 2); if ($name) { if (!isset($subjectToken[$type])) { $subjectToken[$type] = array(); } $subjectToken[$type][] = $name; } } } $messageSubject = CRM_Utils_Token::replaceContactTokens($body_subject, $contact, FALSE, $subjectToken); $messageSubject = CRM_Utils_Token::replaceDomainTokens($messageSubject, $domain, TRUE, $subjectToken); $messageSubject = CRM_Utils_Token::replaceComponentTokens($messageSubject, $contact, $subjectToken, TRUE); $messageSubject = CRM_Utils_Token::replaceHookTokens($messageSubject, $contact, $categories, TRUE); $messageSubject = $smarty->fetch("string:{$messageSubject}"); if ($schedule->mode == 'SMS' or $schedule->mode == 'User_Preference') { $session = CRM_Core_Session::singleton(); $userID = $session->get('userID') ? $session->get('userID') : $contactId; $smsParams = array('To' => $phoneNumber, 'provider_id' => $schedule->sms_provider_id, 'activity_subject' => $messageSubject); $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'SMS', 'name'); $activityParams = array('source_contact_id' => $userID, 'activity_type_id' => $activityTypeID, 'activity_date_time' => date('YmdHis'), 'subject' => $messageSubject, 'details' => $sms_text, 'status_id' => CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name')); $activity = CRM_Activity_BAO_Activity::create($activityParams); CRM_Activity_BAO_Activity::sendSMSMessage($contactId, $sms_text, $html, $smsParams, $activity->id, $userID); } if ($schedule->mode == 'Email' or $schedule->mode == 'User_Preference') { // set up the parameters for CRM_Utils_Mail::send $mailParams = array('groupName' => 'Scheduled Reminder Sender', 'from' => $from, 'toName' => $contact['display_name'], 'toEmail' => $email, 'subject' => $messageSubject, 'entity' => 'action_schedule', 'entity_id' => $scheduleID); if (!$html || $contact['preferred_mail_format'] == 'Text' || $contact['preferred_mail_format'] == 'Both') { // render the & entities in text mode, so that the links work $mailParams['text'] = str_replace('&', '&', $text); } if ($html && ($contact['preferred_mail_format'] == 'HTML' || $contact['preferred_mail_format'] == 'Both')) { $mailParams['html'] = $html; } $result = CRM_Utils_Mail::send($mailParams); } } $schedule->free(); return $result; }