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;
72 public $_selectedOutput;
75 * build all the data structures needed to build the form
80 function preProcess() {
81 $id = CRM_Utils_Request
::retrieve('id', 'Positive', $this, FALSE);
83 $this->_contributionIds
= array($id);
84 $this->_componentClause
= " civicrm_contribution.id IN ( $id ) ";
85 $this->_single
= TRUE;
86 $this->assign('totalSelectedContributions', 1);
92 // check that all the contribution ids have status Completed, Pending, Refunded.
93 $this->_contributionStatusId
= CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
94 $status = array('Completed', 'Pending', 'Refunded');
96 foreach ($this->_contributionStatusId
as $key => $value) {
97 if (in_array($value, $status)) {
101 $Id = implode(",", $statusId);
102 $query = "SELECT count(*) FROM civicrm_contribution WHERE contribution_status_id NOT IN ($Id) AND {$this->_componentClause}";
103 $count = CRM_Core_DAO
::singleValueQuery($query);
105 CRM_Core_Error
::statusBounce(ts('Please select only contributions with Completed, Pending, Refunded status.'));
108 // we have all the contribution ids, so now we get the contact ids
109 parent
::setContactIDs();
110 $this->assign('single', $this->_single
);
112 $qfKey = CRM_Utils_Request
::retrieve('qfKey', 'String', $this);
113 $urlParams = 'force=1';
114 if (CRM_Utils_Rule
::qfKey($qfKey)) {
115 $urlParams .= "&qfKey=$qfKey";
118 $url = CRM_Utils_System
::url('civicrm/contribute/search', $urlParams);
122 'title' => ts('Search Results'),
126 CRM_Utils_System
::appendBreadCrumb($breadCrumb);
128 $this->_selectedOutput
= CRM_Utils_Request
::retrieve('select', 'String', $this);
129 $this->assign('selectedOutput', $this->_selectedOutput
);
131 if ($this->_selectedOutput
== 'email') {
132 CRM_Utils_System
::setTitle(ts('Email Invoice'));
135 CRM_Utils_System
::setTitle(ts('Print Contribution Invoice'));
146 public function buildQuickForm() {
147 $session = CRM_Core_Session
::singleton();
148 if (CRM_Core_Permission
::check('administer CiviCRM')) {
149 $this->assign('isAdmin', 1);
151 $contactID = $session->get('userID');
152 $contactEmails = CRM_Core_BAO_Email
::allEmails($contactID);
154 $fromDisplayName = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
155 $contactID, 'display_name'
157 foreach ($contactEmails as $emailId => $item) {
158 $email = $item['email'];
160 $emails[$emailId] = '"' . $fromDisplayName . '" <' . $email . '> ';
162 if (isset($emails[$emailId])) {
163 $emails[$emailId] .= $item['locationType'];
164 if ($item['is_primary']) {
165 $emails[$emailId] .= ' ' . ts('(preferred)');
167 $emails[$emailId] = htmlspecialchars($emails[$emailId]);
170 $fromEmailAddress = CRM_Core_OptionGroup
::values('from_email_address');
171 foreach ($fromEmailAddress as $key => $email) {
172 $fromEmailAddress[$key] = htmlspecialchars($fromEmailAddress[$key]);
174 $fromEmail = CRM_Utils_Array
::crmArrayMerge($emails, $fromEmailAddress);
175 $this->add('select', 'from_email_address', ts('From Email Address'), array('' => '- select -') +
$fromEmail);
176 if ($this->_selectedOutput
!= 'email') {
177 $this->addElement('radio', 'output', NULL, ts('Email Invoice'), 'email_invoice');
178 $this->addElement('radio', 'output', NULL, ts('PDF Invoice'), 'pdf_invoice');
179 $this->addRule('output', ts('Selection required'), 'required');
180 $this->addFormRule(array('CRM_Contribute_Form_Task_Invoice', 'formRule'));
183 $this->addRule('from_email_address', ts('From Email Address is required'), 'required');
186 $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(
191 if (in_array("email", $this->urlPath
)) {
192 $this->addButtons(array(
195 'name' => ts('Email Invoice'),
200 'name' => ts('Cancel'),
206 $this->addButtons(array(
209 'name' => ts('Process Invoice(s)'),
214 'name' => ts('Cancel'),
222 * global validation rules for the form
226 * @internal param array $fields posted values of the form
228 * @return array list of errors to be posted back to the form
232 static function formRule($values) {
235 if ($values['output'] == 'email_invoice' && empty($values['from_email_address'])) {
236 $errors['from_email_address'] = ts("From Email Address is required");
243 * process the form after the input has been submitted and validated
249 public function postProcess() {
250 $params = $this->controller
->exportValues($this->_name
);
251 $this->printPDF($this->_contributionIds
, $params, $this->_contactIds
);
256 * process the PDf and email with activity and attachment
257 * on click of Print Invoices
259 * @param array $contribIDs Contribution Id
260 * @param array $params for pdf or email invoices
261 * @param array $contactIds Contact Id
265 static function printPDF($contribIDs, $params, $contactIds) {
266 // get all the details needed to generate a invoice
267 $messageInvoice = array();
268 $invoiceTemplate = CRM_Core_Smarty
::singleton();
269 $invoiceElements = CRM_Contribute_Form_Task_PDF
::getElements($contribIDs, $params, $contactIds);
271 // gives the status id when contribution status is 'Refunded'
272 $contributionStatusID = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
273 $refundedStatusId = CRM_Utils_Array
::key('Refunded', $contributionStatusID);
275 // getting data from admin page
276 $prefixValue = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::CONTRIBUTE_PREFERENCES_NAME
, 'contribution_invoice_settings');
278 foreach ($invoiceElements['details'] as $contribID => $detail) {
279 $input = $ids = $objects = array();
280 if (in_array($detail['contact'], $invoiceElements['excludeContactIds'])) {
284 $input['component'] = $detail['component'];
286 $ids['contact'] = $detail['contact'];
287 $ids['contribution'] = $contribID;
288 $ids['contributionRecur'] = NULL;
289 $ids['contributionPage'] = NULL;
290 $ids['membership'] = CRM_Utils_Array
::value('membership', $detail);
291 $ids['participant'] = CRM_Utils_Array
::value('participant', $detail);
292 $ids['event'] = CRM_Utils_Array
::value('event', $detail);
294 if (!$invoiceElements['baseIPN']->validateData($input, $ids, $objects, FALSE)) {
295 CRM_Core_Error
::fatal();
298 $contribution = & $objects['contribution'];
300 $input['amount'] = $contribution->total_amount
;
301 $input['invoice_id'] = $contribution->invoice_id
;
302 $input['receive_date'] = $contribution->receive_date
;
303 $input['contribution_status_id'] = $contribution->contribution_status_id
;
304 $input['organization_name'] = $contribution->_relatedObjects
['contact']->organization_name
;
306 $objects['contribution']->receive_date
= CRM_Utils_Date
::isoToMysql($objects['contribution']->receive_date
);
308 $addressParams = array('contact_id' => $contribution->contact_id
);
309 $addressDetails = CRM_Core_BAO_Address
::getValues($addressParams);
311 // to get billing address if present
312 $billingAddress = array();
313 foreach ($addressDetails as $key => $address) {
314 if ((isset($address['is_billing']) && $address['is_billing'] == 1) && (isset($address['is_primary']) && $address['is_primary'] == 1) && $address['contact_id'] == $contribution->contact_id
) {
315 $billingAddress[$address['contact_id']] = $address;
318 elseif (($address['is_billing'] == 0 && $address['is_primary'] == 1) ||
(isset($address['is_billing']) && $address['is_billing'] == 1) && $address['contact_id'] == $contribution->contact_id
) {
319 $billingAddress[$address['contact_id']] = $address;
323 if (!empty($billingAddress[$contribution->contact_id
]['state_province_id'])) {
324 $stateProvinceAbbreviation = CRM_Core_PseudoConstant
::stateProvinceAbbreviation($billingAddress[$contribution->contact_id
]['state_province_id']);
327 $stateProvinceAbbreviation = '';
330 if ($contribution->contribution_status_id
== $refundedStatusId) {
331 $creditNoteId = CRM_Utils_Array
::value('credit_notes_prefix', $prefixValue) . "" . $contribution->id
;
333 $invoiceId = CRM_Utils_Array
::value('invoice_prefix', $prefixValue) . "" . $contribution->id
;
335 //to obtain due date for PDF invoice
336 $contributionReceiveDate = date('F j,Y', strtotime(date($input['receive_date'])));
337 $invoiceDate = date("F j, Y");
338 $dueDate = date('F j ,Y', strtotime($contributionReceiveDate . "+" . $prefixValue['due_date'] . "" . $prefixValue['due_date_period']));
340 if ($input['component'] == 'contribute') {
342 $etable = 'contribution';
345 $eid = $contribution->_relatedObjects
['participant']->id
;
346 $etable = 'participant';
349 //TO DO: Need to do changes for partially paid to display amount due on PDF invoice
350 $amountDue = ($input['amount'] - $input['amount']);
352 // retreiving the subtotal and sum of same tax_rate
353 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($eid, $etable);
354 $dataArray = array();
356 foreach ($lineItem as $entity_id => $taxRate) {
357 if (isset($dataArray[(string) $taxRate['tax_rate']])) {
358 $dataArray[(string) $taxRate['tax_rate']] = $dataArray[(string) $taxRate['tax_rate']] + CRM_Utils_Array
::value('tax_amount', $taxRate);
361 $dataArray[(string) $taxRate['tax_rate']] = CRM_Utils_Array
::value('tax_amount', $taxRate);
363 $subTotal +
= CRM_Utils_Array
::value('subTotal', $taxRate);
366 // to email the invoice
367 $mailDetails = array();
369 if ($contribution->_component
== 'event') {
370 $daoName = 'CRM_Event_DAO_Event';
371 $pageId = $contribution->_relatedObjects
['event']->id
;
372 $mailElements = array(
375 'confirm_from_email',
379 CRM_Core_DAO
::commonRetrieveAll($daoName, 'id', $pageId, $mailDetails, $mailElements);
380 $values['title'] = CRM_Utils_Array
::value('title', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
381 $values['confirm_from_name'] = CRM_Utils_Array
::value('confirm_from_name', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
382 $values['confirm_from_email'] = CRM_Utils_Array
::value('confirm_from_email', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
383 $values['cc_confirm'] = CRM_Utils_Array
::value('cc_confirm', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
384 $values['bcc_confirm'] = CRM_Utils_Array
::value('bcc_confirm', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
386 $title = CRM_Utils_Array
::value('title', $mailDetails[$contribution->_relatedObjects
['event']->id
]);
388 elseif ($contribution->_component
== 'contribute') {
389 $daoName = 'CRM_Contribute_DAO_ContributionPage';
390 $pageId = $contribution->contribution_page_id
;
391 $mailElements = array(
394 'receipt_from_email',
398 CRM_Core_DAO
::commonRetrieveAll($daoName, 'id', $pageId, $mailDetails, $mailElements);
400 $values['title'] = CRM_Utils_Array
::value('title', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
401 $values['receipt_from_name'] = CRM_Utils_Array
::value('receipt_from_name', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
402 $values['receipt_from_email'] = CRM_Utils_Array
::value('receipt_from_email', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
403 $values['cc_receipt'] = CRM_Utils_Array
::value('cc_receipt', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
404 $values['bcc_receipt'] = CRM_Utils_Array
::value('bcc_receipt', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
406 $title = CRM_Utils_Array
::value('title', CRM_Utils_Array
::value($contribution->contribution_page_id
, $mailDetails));
408 $source = $contribution->source
;
410 $config = CRM_Core_Config
::singleton();
411 if (!isset($params['forPage'])) {
412 $config->doNotAttachPDFReceipt
= 1;
415 // get organization address
416 $domain = CRM_Core_BAO_Domain
::getDomain();
417 $locParams = array('contact_id' => $domain->id
);
418 $locationDefaults = CRM_Core_BAO_Location
::getValues($locParams);
419 if (isset($locationDefaults['address'][1]['state_province_id'])) {
420 $stateProvinceAbbreviationDomain = CRM_Core_PseudoConstant
::stateProvinceAbbreviation($locationDefaults['address'][1]['state_province_id']);
423 $stateProvinceAbbreviationDomain = '';
425 if (isset($locationDefaults['address'][1]['country_id'])) {
426 $countryDomain = CRM_Core_PseudoConstant
::country($locationDefaults['address'][1]['country_id']);
432 // parameters to be assign for template
435 'component' => $input['component'],
436 'id' => $contribution->id
,
438 'invoice_id' => $invoiceId,
439 'resourceBase' => $config->resourceBase
,
440 'defaultCurrency' => $config->defaultCurrency
,
441 'amount' => $contribution->total_amount
,
442 'amountDue' => $amountDue,
443 'invoice_date' => $invoiceDate,
444 'dueDate' => $dueDate,
445 'notes' => CRM_Utils_Array
::value('notes', $prefixValue),
446 'display_name' => $contribution->_relatedObjects
['contact']->display_name
,
447 'lineItem' => $lineItem,
448 'dataArray' => $dataArray,
449 'refundedStatusId' => $refundedStatusId,
450 'contribution_status_id' => $contribution->contribution_status_id
,
451 'subTotal' => $subTotal,
452 'street_address' => CRM_Utils_Array
::value('street_address', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
453 'supplemental_address_1' => CRM_Utils_Array
::value('supplemental_address_1', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
454 'supplemental_address_2' => CRM_Utils_Array
::value('supplemental_address_2', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
455 'city' => CRM_Utils_Array
::value('city', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
456 'stateProvinceAbbreviation' => $stateProvinceAbbreviation,
457 'postal_code' => CRM_Utils_Array
::value('postal_code', CRM_Utils_Array
::value($contribution->contact_id
, $billingAddress)),
458 'is_pay_later' => $contribution->is_pay_later
,
459 'organization_name' => $contribution->_relatedObjects
['contact']->organization_name
,
460 'domain_organization' => $domain->name
,
461 'domain_street_address' => CRM_Utils_Array
::value('street_address', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
462 'domain_supplemental_address_1' => CRM_Utils_Array
::value('supplemental_address_1', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
463 'domain_supplemental_address_2' => CRM_Utils_Array
::value('supplemental_address_2', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
464 'domain_city' => CRM_Utils_Array
::value('city', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
465 'domain_postal_code' => CRM_Utils_Array
::value('postal_code', CRM_Utils_Array
::value('1', $locationDefaults['address'])),
466 'domain_state' => $stateProvinceAbbreviationDomain,
467 'domain_country' => $countryDomain,
468 'domain_email' => CRM_Utils_Array
::value('email', CRM_Utils_Array
::value('1', $locationDefaults['email'])),
469 'domain_phone' => CRM_Utils_Array
::value('phone', CRM_Utils_Array
::value('1', $locationDefaults['phone'])),
472 if (isset($creditNoteId)) {
473 $tplParams['creditnote_id'] = $creditNoteId;
476 $sendTemplateParams = array(
477 'groupName' => 'msg_tpl_workflow_contribution',
478 'valueName' => 'contribution_invoice_receipt',
479 'contactId' => $contribution->contact_id
,
480 'tplParams' => $tplParams,
481 'PDFFilename' => 'Invoice.pdf',
483 $session = CRM_Core_Session
::singleton();
484 $contactID = $session->get('userID');
485 $contactEmails = CRM_Core_BAO_Email
::allEmails($contactID);
487 $fromDisplayName = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
488 $contactID, 'display_name'
491 foreach ($contactEmails as $emailId => $item) {
492 $email = $item['email'];
494 $emails[$emailId] = '"' . $fromDisplayName . '" <' . $email . '> ';
497 $fromEmail = CRM_Utils_Array
::crmArrayMerge($emails, CRM_Core_OptionGroup
::values('from_email_address'));
499 // from email address
500 if (isset($params['from_email_address'])) {
501 $fromEmailAddress = CRM_Utils_Array
::value($params['from_email_address'], $fromEmail);
503 // condition to check for download PDF Invoice or email Invoice
504 if ($invoiceElements['createPdf']) {
505 list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate
::sendTemplate($sendTemplateParams);
506 if (isset($params['forPage'])) {
511 'subject' => $subject,
516 $messageInvoice[] = $mail['html'];
519 $messageInvoice[] = nl2br($mail['body']);
523 elseif ($contribution->_component
== 'contribute') {
524 $email = CRM_Contact_BAO_Contact
::getPrimaryEmail($contribution->contact_id
);
526 $sendTemplateParams['tplParams'] = array_merge($tplParams, array('email_comment' => $invoiceElements['params']['email_comment']));
527 $sendTemplateParams['from'] = $fromEmailAddress;
528 $sendTemplateParams['toEmail'] = $email;
529 $sendTemplateParams['cc'] = CRM_Utils_Array
::value('cc_receipt', $values);
530 $sendTemplateParams['bcc'] = CRM_Utils_Array
::value('bcc_receipt', $values);
532 list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate
::sendTemplate($sendTemplateParams);
533 // functions call for adding activity with attachment
534 $fileName = self
::putFile($html);
535 self
::addActivities($subject, $contribution->contact_id
, $fileName, $params);
537 elseif ($contribution->_component
== 'event') {
538 $email = CRM_Contact_BAO_Contact
::getPrimaryEmail($contribution->contact_id
);
540 $sendTemplateParams['tplParams'] = array_merge($tplParams, array('email_comment' => $invoiceElements['params']['email_comment']));
541 $sendTemplateParams['from'] = $fromEmailAddress;
542 $sendTemplateParams['toEmail'] = $email;
543 $sendTemplateParams['cc'] = CRM_Utils_Array
::value('cc_confirm', $values);
544 $sendTemplateParams['bcc'] = CRM_Utils_Array
::value('bcc_confirm', $values);
546 list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate
::sendTemplate($sendTemplateParams);
547 // functions call for adding activity with attachment
548 $fileName = self
::putFile($html);
549 self
::addActivities($subject, $contribution->contact_id
, $fileName, $params);
552 CRM_Core_DAO
::setFieldValue('CRM_Contribute_DAO_Contribution', $contribution->id
, 'invoice_id', $invoiceId);
553 if ($contribution->contribution_status_id
== $refundedStatusId) {
554 CRM_Core_DAO
::setFieldValue('CRM_Contribute_DAO_Contribution', $contribution->id
, 'creditnote_id', $creditNoteId);
556 $invoiceTemplate->clearTemplateVars();
559 if ($invoiceElements['createPdf']) {
560 if (isset($params['forPage'])) {
564 CRM_Utils_PDF_Utils
::html2pdf($messageInvoice, 'Invoice.pdf', FALSE, array(
569 // functions call for adding activity with attachment
570 $fileName = self
::putFile($html);
571 self
::addActivities($subject, $contactIds, $fileName, $params);
573 CRM_Utils_System
::civiExit();
577 if ($invoiceElements['suppressedEmails']) {
578 $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']));
579 $msgTitle = ts('Email Error');
583 $status = ts('Your mail has been sent.');
584 $msgTitle = ts('Sent');
585 $msgType = 'success';
587 CRM_Core_Session
::setStatus($status, $msgTitle, $msgType);
593 * This function is use for adding activity for
594 * Email Invoice and the PDF Invoice
596 * @param string $subject Activity subject
597 * @param array $contactIds Contact Id
598 * @param string $fileName gives the location with name of the file
599 * @param array $params for invoices
604 static public function addActivities($subject, $contactIds, $fileName, $params) {
605 $session = CRM_Core_Session
::singleton();
606 $userID = $session->get('userID');
607 $config = CRM_Core_Config
::singleton();
608 $config->doNotAttachPDFReceipt
= 1;
610 if (!empty($params['output']) && $params['output'] == 'pdf_invoice') {
611 $activityTypeID = CRM_Core_OptionGroup
::getValue('activity_type',
612 'Downloaded Invoice',
617 $activityTypeID = CRM_Core_OptionGroup
::getValue('activity_type',
623 $activityParams = array(
624 'subject' => $subject,
625 'source_contact_id' => $userID,
626 'target_contact_id' => $contactIds,
627 'activity_type_id' => $activityTypeID,
628 'activity_date_time' => date('YmdHis'),
629 'attachFile_1' => array(
631 'type' => 'application/pdf',
632 'location' => $fileName,
633 'upload_date' => date('YmdHis'),
636 CRM_Activity_BAO_Activity
::create($activityParams);
641 * This function is use for creating the Invoice file in upload folder
644 * @param $html content for pdf in html format
646 * return $fileName of file which is in pdf format
649 static public function putFile($html) {
650 require_once("packages/dompdf/dompdf_config.inc.php");
651 spl_autoload_register('DOMPDF_autoload');
653 $doc->load_html($html);
655 $html = $doc->output();
656 $config = CRM_Core_Config
::singleton();
657 $fileName = $config->uploadDir
. 'Invoice.pdf';
658 file_put_contents($fileName, $html);