3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2014
36 * This class provides the functionality to email a group of
39 class CRM_Contribute_Form_Task_Invoice
extends CRM_Contribute_Form_Task
{
41 * Are we operating in "single mode", i.e. updating the task of only
42 * one specific contribution?
46 public $_single = FALSE;
49 * gives all the statues for conribution
53 public $_contributionStatusId;
56 * gives the HTML template of PDF Invoice
60 public $_messageInvoice;
63 * This variable is used to assign parameters for HTML template of PDF Invoice
67 public $_invoiceTemplate;
70 * build all the data structures needed to build the form
75 function preProcess() {
76 $id = CRM_Utils_Request
::retrieve('id', 'Positive', $this, FALSE);
78 $this->_contributionIds
= array($id);
79 $this->_componentClause
= " civicrm_contribution.id IN ( $id ) ";
80 $this->_single
= TRUE;
81 $this->assign('totalSelectedContributions', 1);
87 // check that all the contribution ids have status Completed, Pending, Refunded.
88 $this->_contributionStatusId
= CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
89 $status = array('Completed', 'Pending', 'Refunded');
91 foreach ($this->_contributionStatusId
as $key => $value) {
92 if (in_array($value, $status)) {
96 $Id = implode(",", $statusId);
97 $query = "SELECT count(*) FROM civicrm_contribution WHERE contribution_status_id NOT IN ($Id) AND {$this->_componentClause}";
98 $count = CRM_Core_DAO
::singleValueQuery($query);
100 CRM_Core_Error
::statusBounce(ts('Please select only contributions with Completed, Pending, Refunded status.'));
103 // we have all the contribution ids, so now we get the contact ids
104 parent
::setContactIDs();
105 $this->assign('single', $this->_single
);
107 $qfKey = CRM_Utils_Request
::retrieve('qfKey', 'String', $this);
108 $urlParams = 'force=1';
109 if (CRM_Utils_Rule
::qfKey($qfKey)) {
110 $urlParams .= "&qfKey=$qfKey";
113 $url = CRM_Utils_System
::url('civicrm/contribute/search', $urlParams);
117 'title' => ts('Search Results'),
121 CRM_Utils_System
::appendBreadCrumb($breadCrumb);
122 if (in_array("email", $this->urlPath
)) {
123 CRM_Utils_System
::setTitle(ts('Email Invoice'));
126 CRM_Utils_System
::setTitle(ts('Print Contribution Invoice'));
137 public function buildQuickForm() {
138 $session = CRM_Core_Session
::singleton();
139 if (CRM_Core_Permission
::check('administer CiviCRM')) {
140 $this->assign('isAdmin', 1);
142 $contactID = $session->get('userID');
143 $contactEmails = CRM_Core_BAO_Email
::allEmails($contactID);
145 $fromDisplayName = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
146 $contactID, 'display_name'
148 foreach ($contactEmails as $emailId => $item) {
149 $email = $item['email'];
151 $emails[$emailId] = '"' . $fromDisplayName . '" <' . $email . '> ';
153 if (isset($emails[$emailId])) {
154 $emails[$emailId] .= $item['locationType'];
155 if ($item['is_primary']) {
156 $emails[$emailId] .= ' ' . ts('(preferred)');
158 $emails[$emailId] = htmlspecialchars($emails[$emailId]);
161 $fromEmailAddress = CRM_Core_OptionGroup
::values('from_email_address');
162 foreach ($fromEmailAddress as $key => $email) {
163 $fromEmailAddress[$key] = htmlspecialchars($fromEmailAddress[$key]);
165 $fromEmail = CRM_Utils_Array
::crmArrayMerge($emails, $fromEmailAddress);
167 $this->addElement('radio', 'output', NULL, ts('Email Invoice'), 'email_invoice');
168 $this->addElement('radio', 'output', NULL, ts('PDF Invoice'), 'pdf_invoice');
169 $this->add('select', 'from_email_address', ts('From Email Address'), array('' => '- select -') +
$fromEmail);
170 $this->addFormRule(array('CRM_Contribute_Form_Task_Invoice', 'formRule'));
171 $this->addWysiwyg('email_comment', ts('If you would like to add personal message to email please add it here. (If sending to more then one receipient the same message will be sent to each contact.)'), array(
176 if (in_array("email", $this->urlPath
)) {
177 $this->addButtons(array(
180 'name' => ts('Email Invoice'),
185 'name' => ts('Cancel'),
191 $this->addButtons(array(
194 'name' => ts('Process Invoice(s)'),
199 'name' => ts('Cancel'),
207 * global validation rules for the form
211 * @internal param array $fields posted values of the form
213 * @return array list of errors to be posted back to the form
217 static function formRule($values) {
219 if (!$values['from_email_address']) {
220 if (in_array("Email Invoice", $values)) {
221 $errors['from_email_address'] = ts("From Email Address is required");
224 if (in_array("email_invoice", $values)) {
225 $errors['from_email_address'] = ts("From Email Address is required");
228 $errors['output'] = ts("Selection required");
236 * process the form after the input has been submitted and validated
242 public function postProcess() {
243 $params = $this->controller
->exportValues($this->_name
);
244 $this->printPDF($this->_contributionIds
, $params, $this->_contactIds
);
249 * process the PDf and email with activity and attachment
250 * on click of Print Invoices
252 * @param array $contribIDs Contribution Id
253 * @param array $params for pdf or email invoices
254 * @param array $contactIds Contact Id
258 static function printPDF($contribIDs, $params, $contactIds) {
259 // get all the details needed to generate a invoice
260 $messageInvoice = array();
261 $invoiceTemplate = CRM_Core_Smarty
::singleton();
262 $invoiceElements = CRM_Contribute_Form_Task_PDF
::getElements($contribIDs, $params, $contactIds);
264 // gives the status id when contribution status is 'Refunded'
265 $contributionStatusID = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
266 $refundedStatusId = CRM_Utils_Array
::key('Refunded', $contributionStatusID);
268 // getting data from admin page
269 $prefixValue = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::CONTRIBUTE_PREFERENCES_NAME
, 'contribution_invoice_settings');
271 foreach ($invoiceElements['details'] as $contribID => $detail) {
272 $input = $ids = $objects = array();
273 if (in_array($detail['contact'], $invoiceElements['excludeContactIds'])) {
277 $input['component'] = $detail['component'];
279 $ids['contact'] = $detail['contact'];
280 $ids['contribution'] = $contribID;
281 $ids['contributionRecur'] = NULL;
282 $ids['contributionPage'] = NULL;
283 $ids['membership'] = CRM_Utils_Array
::value('membership', $detail);
284 $ids['participant'] = CRM_Utils_Array
::value('participant', $detail);
285 $ids['event'] = CRM_Utils_Array
::value('event', $detail);
287 if (!$invoiceElements['baseIPN']->validateData($input, $ids, $objects, FALSE)) {
288 CRM_Core_Error
::fatal();
291 $contribution = & $objects['contribution'];
293 $input['amount'] = $contribution->total_amount
;
294 $input['invoice_id'] = $contribution->invoice_id
;
295 $input['receive_date'] = $contribution->receive_date
;
296 $input['contribution_status_id'] = $contribution->contribution_status_id
;
297 $input['organization_name'] = $contribution->_relatedObjects
['contact']->organization_name
;
299 $objects['contribution']->receive_date
= CRM_Utils_Date
::isoToMysql($objects['contribution']->receive_date
);
301 $addressParams = array('contact_id' => $contribution->contact_id
);
302 $addressDetails = CRM_Core_BAO_Address
::getValues($addressParams);
304 // to get billing address if present
305 $billingAddress = array();
306 foreach ($addressDetails as $key => $address) {
307 if ((isset($address['is_billing']) && $address['is_billing'] == 1) && (isset($address['is_primary']) && $address['is_primary'] == 1) && $address['contact_id'] == $contribution->contact_id
) {
308 $billingAddress[$address['contact_id']] = $address;
311 elseif (($address['is_billing'] == 0 && $address['is_primary'] == 1) ||
(isset($address['is_billing']) && $address['is_billing'] == 1) && $address['contact_id'] == $contribution->contact_id
) {
312 $billingAddress[$address['contact_id']] = $address;
316 if (!empty($billingAddress[$contribution->contact_id
]['state_province_id'])) {
317 $stateProvinceAbbreviation = CRM_Core_PseudoConstant
::stateProvinceAbbreviation($billingAddress[$contribution->contact_id
]['state_province_id']);
320 $stateProvinceAbbreviation = '';
323 if ($contribution->contribution_status_id
== $refundedStatusId) {
324 $creditNoteId = CRM_Utils_Array
::value('credit_notes_prefix', $prefixValue) . "" . $contribution->id
;
326 $invoiceId = CRM_Utils_Array
::value('invoice_prefix', $prefixValue) . "" . $contribution->id
;
328 //to obtain due date for PDF invoice
329 $contributionReceiveDate = date('F j,Y', strtotime(date($input['receive_date'])));
330 $invoiceDate = date("F j, Y");
331 $dueDate = date('F j ,Y', strtotime($contributionReceiveDate . "+" . $prefixValue['due_date'] . "" . $prefixValue['due_date_period']));
333 if ($input['component'] == 'contribute') {
335 $etable = 'contribution';
338 $eid = $contribution->_relatedObjects
['participant']->id
;
339 $etable = 'participant';
342 //TO DO: Need to do changes for partially paid to display amount due on PDF invoice
343 $amountDue = ($input['amount'] - $input['amount']);
345 // retreiving the subtotal and sum of same tax_rate
346 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($eid, $etable);
347 $dataArray = array();
349 foreach ($lineItem as $entity_id => $taxRate) {
350 if (isset($dataArray[(string) $taxRate['tax_rate']])) {
351 $dataArray[(string) $taxRate['tax_rate']] = $dataArray[(string) $taxRate['tax_rate']] + CRM_Utils_Array
::value('tax_amount', $taxRate);
354 $dataArray[(string) $taxRate['tax_rate']] = CRM_Utils_Array
::value('tax_amount', $taxRate);
356 $subTotal +
= CRM_Utils_Array
::value('subTotal', $taxRate);
359 // to email the invoice
360 $mailDetails = array();
362 if ($contribution->_component
== 'event') {
363 $daoName = 'CRM_Event_DAO_Event';
364 $pageId = $contribution->_relatedObjects
['event']->id
;
365 $mailElements = array(
368 'confirm_from_email',
372 CRM_Core_DAO
::commonRetrieveAll($daoName, 'id', $pageId, $mailDetails, $mailElements);
373 $values['title'] = CRM_Utils_Array
::value('title', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
374 $values['confirm_from_name'] = CRM_Utils_Array
::value('confirm_from_name', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
375 $values['confirm_from_email'] = CRM_Utils_Array
::value('confirm_from_email', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
376 $values['cc_confirm'] = CRM_Utils_Array
::value('cc_confirm', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
377 $values['bcc_confirm'] = CRM_Utils_Array
::value('bcc_confirm', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
379 $title = CRM_Utils_Array
::value('title', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
381 elseif ($contribution->_component
== 'contribute') {
382 $daoName = 'CRM_Contribute_DAO_ContributionPage';
383 $pageId = $contribution->contribution_page_id
;
384 $mailElements = array(
387 'receipt_from_email',
391 CRM_Core_DAO
::commonRetrieveAll($daoName, 'id', $pageId, $mailDetails, $mailElements);
393 $values['title'] = CRM_Utils_Array
::value('title', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
394 $values['receipt_from_name'] = CRM_Utils_Array
::value('receipt_from_name', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
395 $values['receipt_from_email'] = CRM_Utils_Array
::value('receipt_from_email', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
396 $values['cc_receipt'] = CRM_Utils_Array
::value('cc_receipt', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
397 $values['bcc_receipt'] = CRM_Utils_Array
::value('bcc_receipt', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
399 $title = CRM_Utils_Array
::value('title', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
401 $source = $contribution->source
;
403 $config = CRM_Core_Config
::singleton();
404 if (!isset($params['forPage'])) {
405 $config->doNotAttachPDFReceipt
= 1;
408 // get organization address
409 $domain = CRM_Core_BAO_Domain
::getDomain();
410 $locParams = array('contact_id' => $domain->id
);
411 $locationDefaults = CRM_Core_BAO_Location
::getValues($locParams);
412 if (isset($locationDefaults['address'][1]['state_province_id'])) {
413 $stateProvinceAbbreviationDomain = CRM_Core_PseudoConstant
::stateProvinceAbbreviation($locationDefaults['address'][1]['state_province_id']);
416 $stateProvinceAbbreviationDomain = '';
418 if (isset($locationDefaults['address'][1]['country_id'])) {
419 $countryDomain = CRM_Core_PseudoConstant
::country($locationDefaults['address'][1]['country_id']);
425 // parameters to be assign for template
428 'component' => $input['component'],
429 'id' => $contribution->id
,
431 'invoice_id' => $invoiceId,
432 'imageUploadURL' => $config->imageUploadURL
,
433 'defaultCurrency' => $config->defaultCurrency
,
434 'amount' => $contribution->total_amount
,
435 'amountDue' => $amountDue,
436 'invoice_date' => $invoiceDate,
437 'dueDate' => $dueDate,
438 'notes' => CRM_Utils_Array
::value('notes', $prefixValue),
439 'display_name' => $contribution->_relatedObjects
['contact']->display_name
,
440 'lineItem' => $lineItem,
441 'dataArray' => $dataArray,
442 'refundedStatusId' => $refundedStatusId,
443 'contribution_status_id' => $contribution->contribution_status_id
,
444 'subTotal' => $subTotal,
445 'street_address' => CRM_Utils_Array
::value('street_address', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
446 'supplemental_address_1' => CRM_Utils_Array
::value('supplemental_address_1', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
447 'supplemental_address_2' => CRM_Utils_Array
::value('supplemental_address_2', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
448 'city' => CRM_Utils_Array
::value('city', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
449 'stateProvinceAbbreviation' => $stateProvinceAbbreviation,
450 'postal_code' => CRM_Utils_Array
::value('postal_code', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
451 'is_pay_later' => $contribution->is_pay_later
,
452 'organization_name' => $contribution->_relatedObjects
['contact']->organization_name
,
453 'domain_organization' => $domain->name
,
454 'domain_street_address' => CRM_Utils_Array
::value('street_address', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
455 'domain_supplemental_address_1' => CRM_Utils_Array
::value('supplemental_address_1', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
456 'domain_supplemental_address_2' => CRM_Utils_Array
::value('supplemental_address_2', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
457 'domain_city' => CRM_Utils_Array
::value('city', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
458 'domain_postal_code' => CRM_Utils_Array
::value('postal_code', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
459 'domain_state' => $stateProvinceAbbreviationDomain,
460 'domain_country' => $countryDomain,
461 'domain_email' => CRM_Utils_Array
::value('email', CRM_Utils_Array
::value('1', $locationDefaults['email'])),
462 'domain_phone' => CRM_Utils_Array
::value('phone', CRM_Utils_Array
::value('1', $locationDefaults['phone'])),
464 if (isset($creditNoteId)) {
465 $tplParams['creditnote_id'] = $creditNoteId;
467 $sendTemplateParams = array(
468 'groupName' => 'msg_tpl_workflow_contribution',
469 'valueName' => 'contribution_invoice_receipt',
470 'contactId' => $contribution->contact_id
,
471 'tplParams' => $tplParams,
472 'PDFFilename' => 'Invoice.pdf',
474 $session = CRM_Core_Session
::singleton();
475 $contactID = $session->get('userID');
476 $contactEmails = CRM_Core_BAO_Email
::allEmails($contactID);
478 $fromDisplayName = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
479 $contactID, 'display_name'
482 foreach ($contactEmails as $emailId => $item) {
483 $email = $item['email'];
485 $emails[$emailId] = '"' . $fromDisplayName . '" <' . $email . '> ';
488 $fromEmail = CRM_Utils_Array
::crmArrayMerge($emails, CRM_Core_OptionGroup
::values('from_email_address'));
490 // from email address
491 if (isset($params['from_email_address'])) {
492 $fromEmailAddress = CRM_Utils_Array
::value($params['from_email_address'], $fromEmail);
494 // condition to check for download PDF Invoice or email Invoice
495 if ($invoiceElements['createPdf']) {
496 list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate
::sendTemplate($sendTemplateParams);
497 if (isset($params['forPage'])) {
502 'subject' => $subject,
507 $messageInvoice[] = $mail['html'];
510 $messageInvoice[] = nl2br($mail['body']);
514 elseif ($contribution->_component
== 'contribute') {
515 $email = CRM_Contact_BAO_Contact
::getPrimaryEmail($contribution->contact_id
);
517 $sendTemplateParams['tplParams'] = array_merge($tplParams, array('email_comment' => $invoiceElements['params']['email_comment']));
518 $sendTemplateParams['from'] = $fromEmailAddress;
519 $sendTemplateParams['toEmail'] = $email;
520 $sendTemplateParams['cc'] = CRM_Utils_Array
::value('cc_receipt', $values);
521 $sendTemplateParams['bcc'] = CRM_Utils_Array
::value('bcc_receipt', $values);
523 list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate
::sendTemplate($sendTemplateParams);
524 // functions call for adding activity with attachment
525 $fileName = self
::putFile($html);
526 self
::addActivities($subject, $contribution->contact_id
, $fileName, $params);
528 elseif ($contribution->_component
== 'event') {
529 $email = CRM_Contact_BAO_Contact
::getPrimaryEmail($contribution->contact_id
);
531 $sendTemplateParams['tplParams'] = array_merge($tplParams, array('email_comment' => $invoiceElements['params']['email_comment']));
532 $sendTemplateParams['from'] = $fromEmailAddress;
533 $sendTemplateParams['toEmail'] = $email;
534 $sendTemplateParams['cc'] = CRM_Utils_Array
::value('cc_confirm', $values);
535 $sendTemplateParams['bcc'] = CRM_Utils_Array
::value('bcc_confirm', $values);
537 list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate
::sendTemplate($sendTemplateParams);
538 // functions call for adding activity with attachment
539 $fileName = self
::putFile($html);
540 self
::addActivities($subject, $contribution->contact_id
, $fileName, $params);
543 CRM_Core_DAO
::setFieldValue('CRM_Contribute_DAO_Contribution', $contribution->id
, 'invoice_id', $invoiceId);
544 if ($contribution->contribution_status_id
== $refundedStatusId) {
545 CRM_Core_DAO
::setFieldValue('CRM_Contribute_DAO_Contribution', $contribution->id
, 'creditnote_id', $creditNoteId);
547 $invoiceTemplate->clearTemplateVars();
550 if ($invoiceElements['createPdf']) {
551 if (isset($params['forPage'])) {
555 CRM_Utils_PDF_Utils
::html2pdf($messageInvoice, 'Invoice.pdf', FALSE, array(
560 // functions call for adding activity with attachment
561 $fileName = self
::putFile($html);
562 self
::addActivities($subject, $contactIds, $fileName, $params['output']);
564 CRM_Utils_System
::civiExit();
568 if ($invoiceElements['suppressedEmails']) {
569 $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 => $invoiceElements['suppressedEmails']));
570 $msgTitle = ts('Email Error');
574 $status = ts('Your mail has been sent.');
575 $msgTitle = ts('Sent');
576 $msgType = 'success';
578 CRM_Core_Session
::setStatus($status, $msgTitle, $msgType);
584 * This function is use for adding activity for
585 * Email Invoice and the PDF Invoice
587 * @param string $subject Activity subject
588 * @param array $contactIds Contact Id
589 * @param string $fileName gives the location with name of the file
590 * @param array $output for invoices
595 static public function addActivities($subject, $contactIds, $fileName, $output) {
596 $session = CRM_Core_Session
::singleton();
597 $userID = $session->get('userID');
598 $config = CRM_Core_Config
::singleton();
599 $config->doNotAttachPDFReceipt
= 1;
600 if ($output['output'] == 'email_invoice' ||
(is_array($output) && array_key_exists("from_email_address", $output))) {
601 $activityTypeID = CRM_Core_OptionGroup
::getValue('activity_type',
607 $activityTypeID = CRM_Core_OptionGroup
::getValue('activity_type',
608 'Downloaded Invoice',
612 $activityParams = array(
613 'subject' => $subject,
614 'source_contact_id' => $userID,
615 'target_contact_id' => $contactIds,
616 'activity_type_id' => $activityTypeID,
617 'activity_date_time' => date('YmdHis'),
618 'attachFile_1' => array(
620 'type' => 'application/pdf',
621 'location' => $fileName,
622 'upload_date' => date('YmdHis'),
625 CRM_Activity_BAO_Activity
::create($activityParams);
630 * This function is use for creating the Invoice file in upload folder
633 * @param $html content for pdf in html format
635 * return $fileName of file which is in pdf format
638 static public function putFile($html) {
639 require_once("packages/dompdf/dompdf_config.inc.php");
640 spl_autoload_register('DOMPDF_autoload');
642 $doc->load_html($html);
644 $html = $doc->output();
645 $config = CRM_Core_Config
::singleton();
646 $fileName = $config->uploadDir
. 'Invoice.pdf';
647 file_put_contents($fileName, $html);