First commit

This commit is contained in:
Theodotos Andreou 2018-01-14 13:10:16 +00:00
commit c6e2478c40
13918 changed files with 2303184 additions and 0 deletions

View file

@ -0,0 +1,240 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality for batch profile update for contributions.
*/
class CRM_Contribute_Form_Task_Batch extends CRM_Contribute_Form_Task {
/**
* The title of the group
*
* @var string
*/
protected $_title;
/**
* Maximum profile fields that will be displayed
*/
protected $_maxFields = 9;
/**
* Variable to store redirect path
*/
protected $_userContext;
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
// initialize the task and row fields
parent::preProcess();
//get the contact read only fields to display.
$readOnlyFields = array_merge(array('sort_name' => ts('Name')),
CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'contact_autocomplete_options',
TRUE, NULL, FALSE, 'name', TRUE
)
);
//get the read only field data.
$returnProperties = array_fill_keys(array_keys($readOnlyFields), 1);
$contactDetails = CRM_Contact_BAO_Contact_Utils::contactDetails($this->_contributionIds,
'CiviContribute', $returnProperties
);
$this->assign('contactDetails', $contactDetails);
$this->assign('readOnlyFields', $readOnlyFields);
}
/**
* Build the form object.
*/
public function buildQuickForm() {
$ufGroupId = $this->get('ufGroupId');
if (!$ufGroupId) {
CRM_Core_Error::fatal('ufGroupId is missing');
}
$this->_title = ts('Update multiple contributions') . ' - ' . CRM_Core_BAO_UFGroup::getTitle($ufGroupId);
CRM_Utils_System::setTitle($this->_title);
$this->addDefaultButtons(ts('Save'));
$this->_fields = array();
$this->_fields = CRM_Core_BAO_UFGroup::getFields($ufGroupId, FALSE, CRM_Core_Action::VIEW);
// remove file type field and then limit fields
$suppressFields = FALSE;
$removehtmlTypes = array('File', 'Autocomplete-Select');
foreach ($this->_fields as $name => $field) {
if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name) &&
in_array($this->_fields[$name]['html_type'], $removehtmlTypes)
) {
$suppressFields = TRUE;
unset($this->_fields[$name]);
}
//fix to reduce size as we are using this field in grid
if (is_array($field['attributes']) && !empty($this->_fields[$name]['attributes']['size']) && $this->_fields[$name]['attributes']['size'] > 19) {
//shrink class to "form-text-medium"
$this->_fields[$name]['attributes']['size'] = 19;
}
}
$this->_fields = array_slice($this->_fields, 0, $this->_maxFields);
$this->addButtons(array(
array(
'type' => 'submit',
'name' => ts('Update Contribution(s)'),
'isDefault' => TRUE,
),
array(
'type' => 'cancel',
'name' => ts('Cancel'),
),
)
);
$this->assign('profileTitle', $this->_title);
$this->assign('componentIds', $this->_contributionIds);
//load all campaigns.
if (array_key_exists('contribution_campaign_id', $this->_fields)) {
$this->_componentCampaigns = array();
CRM_Core_PseudoConstant::populate($this->_componentCampaigns,
'CRM_Contribute_DAO_Contribution',
TRUE, 'campaign_id', 'id',
' id IN (' . implode(' , ', array_values($this->_contributionIds)) . ' ) '
);
}
// It is possible to have fields that are required in CiviCRM not be required in the
// profile. Overriding that here. Perhaps a better approach would be to
// make them required in the schema & read that up through getFields functionality.
$requiredFields = array('receive_date');
//fix for CRM-2752
$customFields = CRM_Core_BAO_CustomField::getFields('Contribution');
foreach ($this->_contributionIds as $contributionId) {
$typeId = CRM_Core_DAO::getFieldValue("CRM_Contribute_DAO_Contribution", $contributionId, 'financial_type_id');
foreach ($this->_fields as $name => $field) {
$entityColumnValue = array();
if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
$customValue = CRM_Utils_Array::value($customFieldID, $customFields);
if (!empty($customValue['extends_entity_column_value'])) {
$entityColumnValue = explode(CRM_Core_DAO::VALUE_SEPARATOR,
$customValue['extends_entity_column_value']
);
}
if (!empty($entityColumnValue[$typeId]) ||
CRM_Utils_System::isNull(CRM_Utils_Array::value($typeId, $entityColumnValue))
) {
CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contributionId);
}
}
else {
// handle non custom fields
if (in_array($field['name'], $requiredFields)) {
$field['is_required'] = TRUE;
}
CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contributionId);
}
}
}
$this->assign('fields', $this->_fields);
// don't set the status message when form is submitted.
$buttonName = $this->controller->getButtonName('submit');
if ($suppressFields && $buttonName != '_qf_Batch_next') {
CRM_Core_Session::setStatus(ts("File or Autocomplete-Select type field(s) in the selected profile are not supported for Update multiple contributions."), ts('Unsupported Field Type'), 'error');
}
$this->addDefaultButtons(ts('Update Contributions'));
}
/**
* Set default values for the form.
*/
public function setDefaultValues() {
if (empty($this->_fields)) {
return;
}
$defaults = array();
foreach ($this->_contributionIds as $contributionId) {
CRM_Core_BAO_UFGroup::setProfileDefaults(NULL, $this->_fields, $defaults, FALSE, $contributionId, 'Contribute');
}
return $defaults;
}
/**
* Process the form after the input has been submitted and validated.
*/
public function postProcess() {
$params = $this->exportValues();
if (isset($params['field'])) {
foreach ($params['field'] as $contributionID => $value) {
$value['id'] = $contributionID;
if (!empty($value['financial_type'])) {
$value['financial_type_id'] = $value['financial_type'];
}
$value['options'] = array(
'reload' => 1,
);
$contribution = civicrm_api3('Contribution', 'create', $value);
$contribution = $contribution['values'][$contributionID];
// @todo add check as to whether the status is updated.
if (!empty($value['contribution_status_id'])) {
// @todo - use completeorder api or make api call do this.
CRM_Contribute_BAO_Contribution::transitionComponentWithReturnMessage($contribution['id'],
$value['contribution_status_id'],
CRM_Utils_Array::value("field[{$contributionID}][contribution_status_id]", $this->_defaultValues),
$contribution['receive_date']
);
}
}
CRM_Core_Session::setStatus(ts("Your updates have been saved."), ts('Saved'), 'success');
}
else {
CRM_Core_Session::setStatus(ts("No updates have been saved."), ts('Not Saved'), 'alert');
}
}
}

View file

@ -0,0 +1,127 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality to delete a group of contributions.
*
* This class provides functionality for the actual deletion.
*/
class CRM_Contribute_Form_Task_Delete extends CRM_Contribute_Form_Task {
/**
* Are we operating in "single mode", i.e. deleting one
* specific contribution?
*
* @var boolean
*/
protected $_single = FALSE;
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
//check for delete
if (!CRM_Core_Permission::checkActionPermission('CiviContribute', CRM_Core_Action::DELETE)) {
CRM_Core_Error::fatal(ts('You do not have permission to access this page.'));
}
parent::preProcess();
}
/**
* Build the form object.
*/
public function buildQuickForm() {
$count = 0;
if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) {
foreach ($this->_contributionIds as $key => $id) {
$finTypeID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $id, 'financial_type_id');
if (!CRM_Core_Permission::check('delete contributions of type ' . CRM_Contribute_PseudoConstant::financialType($finTypeID))) {
unset($this->_contributionIds[$key]);
$count++;
}
// Now check for lineItems
if ($lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($id)) {
foreach ($lineItems as $items) {
if (!CRM_Core_Permission::check('delete contributions of type ' . CRM_Contribute_PseudoConstant::financialType($items['financial_type_id']))) {
unset($this->_contributionIds[$key]);
$count++;
break;
}
}
}
}
}
if ($count && empty($this->_contributionIds)) {
CRM_Core_Session::setStatus(ts('1 contribution could not be deleted.', array('plural' => '%count contributions could not be deleted.', 'count' => $count)), ts('Error'), 'error');
$this->addButtons(array(
array(
'type' => 'back',
'name' => ts('Cancel'),
),
)
);
}
elseif ($count && !empty($this->_contributionIds)) {
CRM_Core_Session::setStatus(ts('1 contribution will not be deleted.', array('plural' => '%count contributions will not be deleted.', 'count' => $count)), ts('Warning'), 'warning');
$this->addDefaultButtons(ts('Delete Contributions'), 'done');
}
else {
$this->addDefaultButtons(ts('Delete Contributions'), 'done');
}
}
/**
* Process the form after the input has been submitted and validated.
*/
public function postProcess() {
$deleted = $failed = 0;
foreach ($this->_contributionIds as $contributionId) {
if (CRM_Contribute_BAO_Contribution::deleteContribution($contributionId)) {
$deleted++;
}
else {
$failed++;
}
}
if ($deleted) {
$msg = ts('%count contribution deleted.', array('plural' => '%count contributions deleted.', 'count' => $deleted));
CRM_Core_Session::setStatus($msg, ts('Removed'), 'success');
}
if ($failed) {
CRM_Core_Session::setStatus(ts('1 could not be deleted.', array('plural' => '%count could not be deleted.', 'count' => $failed)), ts('Error'), 'error');
}
}
}

View file

@ -0,0 +1,97 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality to email a group of contacts.
*/
class CRM_Contribute_Form_Task_Email extends CRM_Contribute_Form_Task {
/**
* Are we operating in "single mode", i.e. sending email to one
* specific contact?
*
* @var boolean
*/
public $_single = FALSE;
public $_noEmails = FALSE;
/**
* All the existing templates in the system.
*
* @var array
*/
public $_templates = NULL;
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
CRM_Contact_Form_Task_EmailCommon::preProcessFromAddress($this);
parent::preProcess();
// we have all the contribution ids, so now we get the contact ids
parent::setContactIDs();
$this->assign('single', $this->_single);
}
/**
* Build the form object.
*/
public function buildQuickForm() {
//enable form element
$this->assign('emailTask', TRUE);
CRM_Contact_Form_Task_EmailCommon::buildQuickForm($this);
}
/**
* Process the form after the input has been submitted and validated.
*/
public function postProcess() {
CRM_Contact_Form_Task_EmailCommon::postProcess($this);
}
/**
* List available tokens for this form.
*
* @return array
*/
public function listTokens() {
$tokens = CRM_Core_SelectValues::contactTokens();
$tokens = array_merge(CRM_Core_SelectValues::contributionTokens(), $tokens);
return $tokens;
}
}

View file

@ -0,0 +1,683 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
use Dompdf\Dompdf;
use Dompdf\Options;
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality to email a group of
* contacts.
*/
class CRM_Contribute_Form_Task_Invoice extends CRM_Contribute_Form_Task {
/**
* Are we operating in "single mode", i.e. updating the task of only
* one specific contribution?
*
* @var boolean
*/
public $_single = FALSE;
/**
* Gives all the statues for conribution.
*/
public $_contributionStatusId;
/**
* Gives the HTML template of PDF Invoice.
*/
public $_messageInvoice;
/**
* This variable is used to assign parameters for HTML template of PDF Invoice.
*/
public $_invoiceTemplate;
/**
* Selected output.
*/
public $_selectedOutput;
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
$id = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE);
if ($id) {
$this->_contributionIds = array($id);
$this->_componentClause = " civicrm_contribution.id IN ( $id ) ";
$this->_single = TRUE;
$this->assign('totalSelectedContributions', 1);
// set the redirection after actions
$contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE);
$url = CRM_Utils_System::url('civicrm/contact/view/contribution',
"action=view&reset=1&id={$id}&cid={$contactId}&context=contribution&selectedChild=contribute"
);
CRM_Core_Session::singleton()->pushUserContext($url);
}
else {
parent::preProcess();
}
// check that all the contribution ids have status Completed, Pending, Refunded.
$this->_contributionStatusId = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
$status = array('Completed', 'Pending', 'Refunded');
$statusId = array();
foreach ($this->_contributionStatusId as $key => $value) {
if (in_array($value, $status)) {
$statusId[] = $key;
}
}
$Id = implode(",", $statusId);
$query = "SELECT count(*) FROM civicrm_contribution WHERE contribution_status_id NOT IN ($Id) AND {$this->_componentClause}";
$count = CRM_Core_DAO::singleValueQuery($query);
if ($count != 0) {
CRM_Core_Error::statusBounce(ts('Please select only contributions with Completed, Pending, Refunded status.'));
}
// we have all the contribution ids, so now we get the contact ids
parent::setContactIDs();
$this->assign('single', $this->_single);
$qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this);
$urlParams = 'force=1';
if (CRM_Utils_Rule::qfKey($qfKey)) {
$urlParams .= "&qfKey=$qfKey";
}
$url = CRM_Utils_System::url('civicrm/contribute/search', $urlParams);
$breadCrumb = array(
array(
'url' => $url,
'title' => ts('Search Results'),
),
);
CRM_Utils_System::appendBreadCrumb($breadCrumb);
$this->_selectedOutput = CRM_Utils_Request::retrieve('select', 'String', $this);
$this->assign('selectedOutput', $this->_selectedOutput);
if ($this->_selectedOutput == 'email') {
CRM_Utils_System::setTitle(ts('Email Invoice'));
}
else {
CRM_Utils_System::setTitle(ts('Print Contribution Invoice'));
}
}
/**
* Build the form object.
*/
public function buildQuickForm() {
$session = CRM_Core_Session::singleton();
$this->preventAjaxSubmit();
if (CRM_Core_Permission::check('administer CiviCRM')) {
$this->assign('isAdmin', 1);
}
$contactID = $session->get('userID');
$contactEmails = CRM_Core_BAO_Email::allEmails($contactID);
$emails = array();
$fromDisplayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
$contactID, 'display_name'
);
foreach ($contactEmails as $emailId => $item) {
$email = $item['email'];
if ($email) {
$emails[$emailId] = '"' . $fromDisplayName . '" <' . $email . '> ';
}
if (isset($emails[$emailId])) {
$emails[$emailId] .= $item['locationType'];
if ($item['is_primary']) {
$emails[$emailId] .= ' ' . ts('(preferred)');
}
$emails[$emailId] = htmlspecialchars($emails[$emailId]);
}
}
$fromEmailAddress = CRM_Core_OptionGroup::values('from_email_address');
foreach ($fromEmailAddress as $key => $email) {
$fromEmailAddress[$key] = htmlspecialchars($fromEmailAddress[$key]);
}
$fromEmail = CRM_Utils_Array::crmArrayMerge($emails, $fromEmailAddress);
$this->add('select', 'from_email_address', ts('From Email Address'), array('' => '- select -') + $fromEmail);
if ($this->_selectedOutput != 'email') {
$this->addElement('radio', 'output', NULL, ts('Email Invoice'), 'email_invoice');
$this->addElement('radio', 'output', NULL, ts('PDF Invoice'), 'pdf_invoice');
$this->addRule('output', ts('Selection required'), 'required');
$this->addFormRule(array('CRM_Contribute_Form_Task_Invoice', 'formRule'));
}
else {
$this->addRule('from_email_address', ts('From Email Address is required'), 'required');
}
$this->add('wysiwyg', '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(
'rows' => 2,
'cols' => 40,
));
$this->addButtons(array(
array(
'type' => 'upload',
'name' => $this->_selectedOutput == 'email' ? ts('Send Email') : ts('Process Invoice(s)'),
'isDefault' => TRUE,
),
array(
'type' => 'cancel',
'name' => ts('Cancel'),
),
)
);
}
/**
* Global validation rules for the form.
*
* @param array $values
*
* @return array
* list of errors to be posted back to the form
*/
public static function formRule($values) {
$errors = array();
if ($values['output'] == 'email_invoice' && empty($values['from_email_address'])) {
$errors['from_email_address'] = ts("From Email Address is required");
}
return $errors;
}
/**
* Process the form after the input has been submitted and validated.
*/
public function postProcess() {
$params = $this->controller->exportValues($this->_name);
self::printPDF($this->_contributionIds, $params, $this->_contactIds);
}
/**
* Process the PDf and email with activity and attachment on click of Print Invoices.
*
* @param array $contribIDs
* Contribution Id.
* @param array $params
* Associated array of submitted values.
* @param array $contactIds
* Contact Id.
*/
public static function printPDF($contribIDs, &$params, $contactIds) {
// get all the details needed to generate a invoice
$messageInvoice = array();
$invoiceTemplate = CRM_Core_Smarty::singleton();
$invoiceElements = CRM_Contribute_Form_Task_PDF::getElements($contribIDs, $params, $contactIds);
// gives the status id when contribution status is 'Refunded'
$contributionStatusID = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
$refundedStatusId = CRM_Utils_Array::key('Refunded', $contributionStatusID);
$cancelledStatusId = CRM_Utils_Array::key('Cancelled', $contributionStatusID);
$pendingStatusId = CRM_Utils_Array::key('Pending', $contributionStatusID);
// getting data from admin page
$prefixValue = Civi::settings()->get('contribution_invoice_settings');
foreach ($invoiceElements['details'] as $contribID => $detail) {
$input = $ids = $objects = array();
if (in_array($detail['contact'], $invoiceElements['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 (!$invoiceElements['baseIPN']->validateData($input, $ids, $objects, FALSE)) {
CRM_Core_Error::fatal();
}
$contribution = &$objects['contribution'];
$input['amount'] = $contribution->total_amount;
$input['invoice_id'] = $contribution->invoice_id;
$input['receive_date'] = $contribution->receive_date;
$input['contribution_status_id'] = $contribution->contribution_status_id;
$input['organization_name'] = $contribution->_relatedObjects['contact']->organization_name;
$objects['contribution']->receive_date = CRM_Utils_Date::isoToMysql($objects['contribution']->receive_date);
$addressParams = array('contact_id' => $contribution->contact_id);
$addressDetails = CRM_Core_BAO_Address::getValues($addressParams);
// to get billing address if present
$billingAddress = array();
foreach ($addressDetails as $address) {
if (($address['is_billing'] == 1) && ($address['is_primary'] == 1) && ($address['contact_id'] == $contribution->contact_id)) {
$billingAddress[$address['contact_id']] = $address;
break;
}
elseif (($address['is_billing'] == 0 && $address['is_primary'] == 1) || ($address['is_billing'] == 1) && ($address['contact_id'] == $contribution->contact_id)) {
$billingAddress[$address['contact_id']] = $address;
}
}
if (!empty($billingAddress[$contribution->contact_id]['state_province_id'])) {
$stateProvinceAbbreviation = CRM_Core_PseudoConstant::stateProvinceAbbreviation($billingAddress[$contribution->contact_id]['state_province_id']);
}
else {
$stateProvinceAbbreviation = '';
}
if ($contribution->contribution_status_id == $refundedStatusId || $contribution->contribution_status_id == $cancelledStatusId) {
if (is_null($contribution->creditnote_id)) {
$creditNoteId = CRM_Contribute_BAO_Contribution::createCreditNoteId();
CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contribution->id, 'creditnote_id', $creditNoteId);
}
else {
$creditNoteId = $contribution->creditnote_id;
}
}
if (!$contribution->invoice_number) {
$contribution->invoice_number = CRM_Contribute_BAO_Contribution::getInvoiceNumber($contribution->id);
}
//to obtain due date for PDF invoice
$contributionReceiveDate = date('F j,Y', strtotime(date($input['receive_date'])));
$invoiceDate = date("F j, Y");
$dueDate = date('F j, Y', strtotime($contributionReceiveDate . "+" . $prefixValue['due_date'] . "" . $prefixValue['due_date_period']));
if ($input['component'] == 'contribute') {
$lineItem = CRM_Price_BAO_LineItem::getLineItemsByContributionID($contribID);
}
else {
$eid = $contribution->_relatedObjects['participant']->id;
$lineItem = CRM_Price_BAO_LineItem::getLineItems($eid, 'participant', NULL, TRUE, FALSE, TRUE);
}
$resultPayments = civicrm_api3('Payment', 'get', array(
'sequential' => 1,
'contribution_id' => $contribID,
));
$amountPaid = 0;
foreach ($resultPayments['values'] as $singlePayment) {
// Only count payments that have been (status =) completed.
if ($singlePayment['status_id'] == 1) {
$amountPaid += $singlePayment['total_amount'];
}
}
$amountDue = ($input['amount'] - $amountPaid);
// retrieving the subtotal and sum of same tax_rate
$dataArray = array();
$subTotal = 0;
foreach ($lineItem as $taxRate) {
if (isset($dataArray[(string) $taxRate['tax_rate']])) {
$dataArray[(string) $taxRate['tax_rate']] = $dataArray[(string) $taxRate['tax_rate']] + CRM_Utils_Array::value('tax_amount', $taxRate);
}
else {
$dataArray[(string) $taxRate['tax_rate']] = CRM_Utils_Array::value('tax_amount', $taxRate);
}
$subTotal += CRM_Utils_Array::value('subTotal', $taxRate);
}
// to email the invoice
$mailDetails = array();
$values = array();
if ($contribution->_component == 'event') {
$daoName = 'CRM_Event_DAO_Event';
$pageId = $contribution->_relatedObjects['event']->id;
$mailElements = array(
'title',
'confirm_from_name',
'confirm_from_email',
'cc_confirm',
'bcc_confirm',
);
CRM_Core_DAO::commonRetrieveAll($daoName, 'id', $pageId, $mailDetails, $mailElements);
$values['title'] = CRM_Utils_Array::value('title', $mailDetails[$contribution->_relatedObjects['event']->id]);
$values['confirm_from_name'] = CRM_Utils_Array::value('confirm_from_name', $mailDetails[$contribution->_relatedObjects['event']->id]);
$values['confirm_from_email'] = CRM_Utils_Array::value('confirm_from_email', $mailDetails[$contribution->_relatedObjects['event']->id]);
$values['cc_confirm'] = CRM_Utils_Array::value('cc_confirm', $mailDetails[$contribution->_relatedObjects['event']->id]);
$values['bcc_confirm'] = CRM_Utils_Array::value('bcc_confirm', $mailDetails[$contribution->_relatedObjects['event']->id]);
$title = CRM_Utils_Array::value('title', $mailDetails[$contribution->_relatedObjects['event']->id]);
}
elseif ($contribution->_component == 'contribute') {
$daoName = 'CRM_Contribute_DAO_ContributionPage';
$pageId = $contribution->contribution_page_id;
$mailElements = array(
'title',
'receipt_from_name',
'receipt_from_email',
'cc_receipt',
'bcc_receipt',
);
CRM_Core_DAO::commonRetrieveAll($daoName, 'id', $pageId, $mailDetails, $mailElements);
$values['title'] = CRM_Utils_Array::value('title', CRM_Utils_Array::value($contribution->contribution_page_id, $mailDetails));
$values['receipt_from_name'] = CRM_Utils_Array::value('receipt_from_name', CRM_Utils_Array::value($contribution->contribution_page_id, $mailDetails));
$values['receipt_from_email'] = CRM_Utils_Array::value('receipt_from_email', CRM_Utils_Array::value($contribution->contribution_page_id, $mailDetails));
$values['cc_receipt'] = CRM_Utils_Array::value('cc_receipt', CRM_Utils_Array::value($contribution->contribution_page_id, $mailDetails));
$values['bcc_receipt'] = CRM_Utils_Array::value('bcc_receipt', CRM_Utils_Array::value($contribution->contribution_page_id, $mailDetails));
$title = CRM_Utils_Array::value('title', CRM_Utils_Array::value($contribution->contribution_page_id, $mailDetails));
}
$source = $contribution->source;
$config = CRM_Core_Config::singleton();
if (!isset($params['forPage'])) {
$config->doNotAttachPDFReceipt = 1;
}
// get organization address
$domain = CRM_Core_BAO_Domain::getDomain();
$locParams = array('contact_id' => $domain->contact_id);
$locationDefaults = CRM_Core_BAO_Location::getValues($locParams);
if (isset($locationDefaults['address'][1]['state_province_id'])) {
$stateProvinceAbbreviationDomain = CRM_Core_PseudoConstant::stateProvinceAbbreviation($locationDefaults['address'][1]['state_province_id']);
}
else {
$stateProvinceAbbreviationDomain = '';
}
if (isset($locationDefaults['address'][1]['country_id'])) {
$countryDomain = CRM_Core_PseudoConstant::country($locationDefaults['address'][1]['country_id']);
}
else {
$countryDomain = '';
}
// parameters to be assign for template
$tplParams = array(
'title' => $title,
'component' => $input['component'],
'id' => $contribution->id,
'source' => $source,
'invoice_number' => $contribution->invoice_number,
'invoice_id' => $contribution->invoice_id,
'resourceBase' => $config->userFrameworkResourceURL,
'defaultCurrency' => $config->defaultCurrency,
'amount' => $contribution->total_amount,
'amountDue' => $amountDue,
'amountPaid' => $amountPaid,
'invoice_date' => $invoiceDate,
'dueDate' => $dueDate,
'notes' => CRM_Utils_Array::value('notes', $prefixValue),
'display_name' => $contribution->_relatedObjects['contact']->display_name,
'lineItem' => $lineItem,
'dataArray' => $dataArray,
'refundedStatusId' => $refundedStatusId,
'pendingStatusId' => $pendingStatusId,
'cancelledStatusId' => $cancelledStatusId,
'contribution_status_id' => $contribution->contribution_status_id,
'subTotal' => $subTotal,
'street_address' => CRM_Utils_Array::value('street_address', CRM_Utils_Array::value($contribution->contact_id, $billingAddress)),
'supplemental_address_1' => CRM_Utils_Array::value('supplemental_address_1', CRM_Utils_Array::value($contribution->contact_id, $billingAddress)),
'supplemental_address_2' => CRM_Utils_Array::value('supplemental_address_2', CRM_Utils_Array::value($contribution->contact_id, $billingAddress)),
'supplemental_address_3' => CRM_Utils_Array::value('supplemental_address_3', CRM_Utils_Array::value($contribution->contact_id, $billingAddress)),
'city' => CRM_Utils_Array::value('city', CRM_Utils_Array::value($contribution->contact_id, $billingAddress)),
'stateProvinceAbbreviation' => $stateProvinceAbbreviation,
'postal_code' => CRM_Utils_Array::value('postal_code', CRM_Utils_Array::value($contribution->contact_id, $billingAddress)),
'is_pay_later' => $contribution->is_pay_later,
'organization_name' => $contribution->_relatedObjects['contact']->organization_name,
'domain_organization' => $domain->name,
'domain_street_address' => CRM_Utils_Array::value('street_address', CRM_Utils_Array::value('1', $locationDefaults['address'])),
'domain_supplemental_address_1' => CRM_Utils_Array::value('supplemental_address_1', CRM_Utils_Array::value('1', $locationDefaults['address'])),
'domain_supplemental_address_2' => CRM_Utils_Array::value('supplemental_address_2', CRM_Utils_Array::value('1', $locationDefaults['address'])),
'domain_supplemental_address_3' => CRM_Utils_Array::value('supplemental_address_3', CRM_Utils_Array::value('1', $locationDefaults['address'])),
'domain_city' => CRM_Utils_Array::value('city', CRM_Utils_Array::value('1', $locationDefaults['address'])),
'domain_postal_code' => CRM_Utils_Array::value('postal_code', CRM_Utils_Array::value('1', $locationDefaults['address'])),
'domain_state' => $stateProvinceAbbreviationDomain,
'domain_country' => $countryDomain,
'domain_email' => CRM_Utils_Array::value('email', CRM_Utils_Array::value('1', $locationDefaults['email'])),
'domain_phone' => CRM_Utils_Array::value('phone', CRM_Utils_Array::value('1', $locationDefaults['phone'])),
);
if (isset($creditNoteId)) {
$tplParams['creditnote_id'] = $creditNoteId;
}
$pdfFileName = $contribution->invoice_number . ".pdf";
$sendTemplateParams = array(
'groupName' => 'msg_tpl_workflow_contribution',
'valueName' => 'contribution_invoice_receipt',
'contactId' => $contribution->contact_id,
'tplParams' => $tplParams,
'PDFFilename' => $pdfFileName,
);
$session = CRM_Core_Session::singleton();
$contactID = $session->get('userID');
//CRM-16319 - we dont store in userID in case the user is doing multiple
//transactions etc
if (empty($contactID)) {
$contactID = $session->get('transaction.userID');
}
// Fix Invoice email doesnot send out when completed payment using Paypal
if (empty($contactID)) {
$contactID = current($contactIds);
}
$contactEmails = CRM_Core_BAO_Email::allEmails($contactID);
$emails = array();
$fromDisplayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
$contactID, 'display_name'
);
foreach ($contactEmails as $emailId => $item) {
$email = $item['email'];
if ($email) {
$emails[$emailId] = '"' . $fromDisplayName . '" <' . $email . '> ';
}
}
$fromEmail = CRM_Utils_Array::crmArrayMerge($emails, CRM_Core_OptionGroup::values('from_email_address'));
// from email address
if (isset($params['from_email_address'])) {
$fromEmailAddress = CRM_Utils_Array::value($params['from_email_address'], $fromEmail);
}
// condition to check for download PDF Invoice or email Invoice
if ($invoiceElements['createPdf']) {
list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
if (isset($params['forPage'])) {
return $html;
}
else {
$mail = array(
'subject' => $subject,
'body' => $message,
'html' => $html,
);
if ($mail['html']) {
$messageInvoice[] = $mail['html'];
}
else {
$messageInvoice[] = nl2br($mail['body']);
}
}
}
elseif ($contribution->_component == 'contribute') {
$email = CRM_Contact_BAO_Contact::getPrimaryEmail($contribution->contact_id);
$sendTemplateParams['tplParams'] = array_merge($tplParams, array('email_comment' => $invoiceElements['params']['email_comment']));
$sendTemplateParams['from'] = $fromEmailAddress;
$sendTemplateParams['toEmail'] = $email;
$sendTemplateParams['cc'] = CRM_Utils_Array::value('cc_receipt', $values);
$sendTemplateParams['bcc'] = CRM_Utils_Array::value('bcc_receipt', $values);
list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
// functions call for adding activity with attachment
$pdfFileName = "{$invoiceNumber}.pdf";
$fileName = self::putFile($html, $pdfFileName);
self::addActivities($subject, $contribution->contact_id, $fileName, $params);
}
elseif ($contribution->_component == 'event') {
$email = CRM_Contact_BAO_Contact::getPrimaryEmail($contribution->contact_id);
$sendTemplateParams['tplParams'] = array_merge($tplParams, array('email_comment' => $invoiceElements['params']['email_comment']));
$sendTemplateParams['from'] = $fromEmailAddress;
$sendTemplateParams['toEmail'] = $email;
$sendTemplateParams['cc'] = CRM_Utils_Array::value('cc_confirm', $values);
$sendTemplateParams['bcc'] = CRM_Utils_Array::value('bcc_confirm', $values);
list($sent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
// functions call for adding activity with attachment
$pdfFileName = "{$invoiceNumber}.pdf";
$fileName = self::putFile($html, $pdfFileName);
self::addActivities($subject, $contribution->contact_id, $fileName, $params);
}
$invoiceTemplate->clearTemplateVars();
}
if ($invoiceElements['createPdf']) {
if (isset($params['forPage'])) {
return $html;
}
else {
$pdfFileName = "{$invoiceNumber}.pdf";
CRM_Utils_PDF_Utils::html2pdf($messageInvoice, $pdfFileName, FALSE, array(
'margin_top' => 10,
'margin_left' => 65,
'metric' => 'px',
));
// functions call for adding activity with attachment
$fileName = self::putFile($html, $pdfFileName);
self::addActivities($subject, $contactIds, $fileName, $params);
CRM_Utils_System::civiExit();
}
}
else {
if ($invoiceElements['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 => $invoiceElements['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);
}
}
/**
* Add activity for Email Invoice and the PDF Invoice.
*
* @param string $subject
* Activity subject.
* @param array $contactIds
* Contact Id.
* @param string $fileName
* Gives the location with name of the file.
* @param array $params
* For invoices.
*
*/
static public function addActivities($subject, $contactIds, $fileName, $params) {
$session = CRM_Core_Session::singleton();
$userID = $session->get('userID');
$config = CRM_Core_Config::singleton();
$config->doNotAttachPDFReceipt = 1;
if (!empty($params['output']) && $params['output'] == 'pdf_invoice') {
$activityTypeID = CRM_Core_PseudoConstant::getKey(
'CRM_Activity_DAO_Activity',
'activity_type_id',
'Downloaded Invoice'
);
}
else {
$activityTypeID = CRM_Core_PseudoConstant::getKey(
'CRM_Activity_DAO_Activity',
'activity_type_id',
'Emailed Invoice'
);
}
$activityParams = array(
'subject' => $subject,
'source_contact_id' => $userID,
'target_contact_id' => $contactIds,
'activity_type_id' => $activityTypeID,
'activity_date_time' => date('YmdHis'),
'attachFile_1' => array(
'uri' => $fileName,
'type' => 'application/pdf',
'location' => $fileName,
'upload_date' => date('YmdHis'),
),
);
CRM_Activity_BAO_Activity::create($activityParams);
}
/**
* Create the Invoice file in upload folder for attachment.
*
* @param string $html
* Content for pdf in html format.
*
* @param string $name
*
* @return string
* Name of file which is in pdf format
*/
static public function putFile($html, $name = 'Invoice.pdf') {
$options = new Options();
$options->set('isRemoteEnabled', TRUE);
$doc = new DOMPDF($options);
$doc->load_html($html);
$doc->render();
$html = $doc->output();
$config = CRM_Core_Config::singleton();
$fileName = $config->uploadDir . $name;
file_put_contents($fileName, $html);
return $fileName;
}
/**
* Callback to perform action on Print Invoice button.
*/
public static function getPrintPDF() {
$contributionId = CRM_Utils_Request::retrieve('id', 'Positive', CRM_Core_DAO::$_nullObject, FALSE);
$contributionIDs = array($contributionId);
$contactId = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullObject, FALSE);
$params = array('output' => 'pdf_invoice');
CRM_Contribute_Form_Task_Invoice::printPDF($contributionIDs, $params, $contactId);
}
}

View file

@ -0,0 +1,308 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality to email a group of
* contacts.
*/
class CRM_Contribute_Form_Task_PDF extends CRM_Contribute_Form_Task {
/**
* Are we operating in "single mode", i.e. updating the task of only
* one specific contribution?
*
* @var boolean
*/
public $_single = FALSE;
protected $_rows;
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
$id = CRM_Utils_Request::retrieve('id', 'Positive',
$this, FALSE
);
if ($id) {
$this->_contributionIds = array($id);
$this->_componentClause = " civicrm_contribution.id IN ( $id ) ";
$this->_single = TRUE;
$this->assign('totalSelectedContributions', 1);
}
else {
parent::preProcess();
}
// check that all the contribution ids have pending status
$query = "
SELECT count(*)
FROM civicrm_contribution
WHERE contribution_status_id != 1
AND {$this->_componentClause}";
$count = CRM_Core_DAO::singleValueQuery($query);
if ($count != 0) {
CRM_Core_Error::statusBounce("Please select only online contributions with Completed status.");
}
$this->assign('single', $this->_single);
$qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this);
$urlParams = 'force=1';
if (CRM_Utils_Rule::qfKey($qfKey)) {
$urlParams .= "&qfKey=$qfKey";
}
$url = CRM_Utils_System::url('civicrm/contribute/search', $urlParams);
$breadCrumb = array(
array(
'url' => $url,
'title' => ts('Search Results'),
),
);
CRM_Contact_Form_Task_EmailCommon ::preProcessFromAddress($this, FALSE);
// we have all the contribution ids, so now we get the contact ids
parent::setContactIDs();
CRM_Utils_System::appendBreadCrumb($breadCrumb);
CRM_Utils_System::setTitle(ts('Print Contribution Receipts'));
}
/**
* Build the form object.
*/
public function buildQuickForm() {
$this->addElement('radio', 'output', NULL, ts('Email Receipts'), 'email_receipt',
array(
'onClick' => "document.getElementById('selectPdfFormat').style.display = 'none';
document.getElementById('selectEmailFrom').style.display = 'block';")
);
$this->addElement('radio', 'output', NULL, ts('PDF Receipts'), 'pdf_receipt',
array('onClick' => "document.getElementById('selectPdfFormat').style.display = 'block';")
);
$this->addRule('output', ts('Selection required'), 'required');
$this->add('select', 'pdf_format_id', ts('Page Format'),
array(0 => ts('- default -')) + CRM_Core_BAO_PdfFormat::getList(TRUE)
);
$this->add('checkbox', 'receipt_update', ts('Update receipt dates for these contributions'), FALSE);
$this->add('checkbox', 'override_privacy', ts('Override privacy setting? (Do not email / Do not mail)'), FALSE);
$this->add('select', 'fromEmailAddress', ts('From Email'), $this->_fromEmails, FALSE, array('class' => 'crm-select2 huge'));
$this->addButtons(array(
array(
'type' => 'next',
'name' => ts('Process Receipt(s)'),
'isDefault' => TRUE,
),
array(
'type' => 'back',
'name' => ts('Cancel'),
),
)
);
}
/**
* Set default values.
*/
public function setDefaultValues() {
$defaultFormat = CRM_Core_BAO_PdfFormat::getDefaultValues();
return array('pdf_format_id' => $defaultFormat['id'], 'receipt_update' => 1, 'override_privacy' => 0);
}
/**
* Process the form after the input has been submitted and validated.
*/
public function postProcess() {
// get all the details needed to generate a receipt
$message = array();
$template = CRM_Core_Smarty::singleton();
$params = $this->controller->exportValues($this->_name);
$elements = self::getElements($this->_contributionIds, $params, $this->_contactIds);
foreach ($elements['details'] as $contribID => $detail) {
$input = $ids = $objects = array();
if (in_array($detail['contact'], $elements['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 (!$elements['baseIPN']->validateData($input, $ids, $objects, FALSE)) {
CRM_Core_Error::fatal();
}
$contribution = &$objects['contribution'];
// 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;
$input['receipt_update'] = $params['receipt_update'];
$input['contribution_status_id'] = $contribution->contribution_status_id;
$input['paymentProcessor'] = empty($contribution->trxn_id) ? NULL :
CRM_Core_DAO::singleValueQuery("SELECT payment_processor_id
FROM civicrm_financial_trxn
WHERE trxn_id = %1
LIMIT 1", array(
1 => array($contribution->trxn_id, 'String')));
// CRM_Contribute_BAO_Contribution::composeMessageArray expects mysql formatted date
$objects['contribution']->receive_date = CRM_Utils_Date::isoToMysql($objects['contribution']->receive_date);
$values = array();
if (isset($params['fromEmailAddress']) && !$elements['createPdf']) {
// CRM-19129 Allow useres the choice of From Email to send the receipt from.
$fromEmail = $params['fromEmailAddress'];
$from = CRM_Utils_Array::value($fromEmail, $this->_emails);
$fromDetails = explode(' <', $from);
$input['receipt_from_email'] = substr(trim($fromDetails[1]), 0, -1);
$input['receipt_from_name'] = str_replace('"', '', $fromDetails[0]);
}
$mail = CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $objects['contribution']->id, $values,
$elements['createPdf']);
if ($mail['html']) {
$message[] = $mail['html'];
}
else {
$message[] = nl2br($mail['body']);
}
// reset template values before processing next transactions
$template->clearTemplateVars();
}
if ($elements['createPdf']) {
CRM_Utils_PDF_Utils::html2pdf($message,
'civicrmContributionReceipt.pdf',
FALSE,
$elements['params']['pdf_format_id']
);
CRM_Utils_System::civiExit();
}
else {
if ($elements['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 => $elements['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);
}
}
/**
* 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
*
*/
static public 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;
}
}

View file

@ -0,0 +1,174 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality to create PDF letter for a group of contacts or a single contact.
*/
class CRM_Contribute_Form_Task_PDFLetter extends CRM_Contribute_Form_Task {
/**
* All the existing templates in the system.
*
* @var array
*/
public $_templates = NULL;
public $_single = NULL;
public $_cid = NULL;
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
$this->skipOnHold = $this->skipDeceased = FALSE;
CRM_Contact_Form_Task_PDFLetterCommon::preProcess($this);
// store case id if present
$this->_caseId = CRM_Utils_Request::retrieve('caseid', 'Positive', $this, FALSE);
// retrieve contact ID if this is 'single' mode
$cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE);
$this->_activityId = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE);
if ($cid) {
CRM_Contact_Form_Task_PDFLetterCommon::preProcessSingle($this, $cid);
$this->_single = TRUE;
$this->_cid = $cid;
}
else {
parent::preProcess();
}
$this->assign('single', $this->_single);
}
/**
* This virtual function is used to set the default values of
* various form elements
*
* access public
*
* @return array
* reference to the array of default values
*/
/**
* @return array
*/
public function setDefaultValues() {
$defaults = array();
if (isset($this->_activityId)) {
$params = array('id' => $this->_activityId);
CRM_Activity_BAO_Activity::retrieve($params, $defaults);
$defaults['html_message'] = CRM_Utils_Array::value('details', $defaults);
}
else {
$defaults['thankyou_update'] = 1;
}
$defaults = $defaults + CRM_Contact_Form_Task_PDFLetterCommon::setDefaultValues();
return $defaults;
}
/**
* Build the form object.
*/
public function buildQuickForm() {
//enable form element
$this->assign('suppressForm', FALSE);
// use contact form as a base
CRM_Contact_Form_Task_PDFLetterCommon::buildQuickForm($this);
// specific need for contributions
$this->add('static', 'more_options_header', NULL, ts('Thank-you Letter Options'));
$this->add('checkbox', 'receipt_update', ts('Update receipt dates for these contributions'), FALSE);
$this->add('checkbox', 'thankyou_update', ts('Update thank-you dates for these contributions'), FALSE);
// Group options for tokens are not yet implemented. dgg
$options = array(
'' => ts('- no grouping -'),
'contact_id' => ts('Contact'),
'contribution_recur_id' => ts('Contact and Recurring'),
'financial_type_id' => ts('Contact and Financial Type'),
'campaign_id' => ts('Contact and Campaign'),
'payment_instrument_id' => ts('Contact and Payment Method'),
);
$this->addElement('select', 'group_by', ts('Group contributions by'), $options, array(), "<br/>", FALSE);
// this was going to be free-text but I opted for radio options in case there was a script injection risk
$separatorOptions = array('comma' => 'Comma', 'td' => 'Horizontal Table Cell', 'tr' => 'Vertical Table Cell', 'br' => 'Line Break');
$this->addElement('select', 'group_by_separator', ts('Separator (grouped contributions)'), $separatorOptions);
$emailOptions = array(
'' => ts('Generate PDFs for printing (only)'),
'email' => ts('Send emails where possible. Generate printable PDFs for contacts who cannot receive email.'),
'both' => ts('Send emails where possible. Generate printable PDFs for all contacts.'),
);
if (CRM_Core_Config::singleton()->doNotAttachPDFReceipt) {
$emailOptions['pdfemail'] = ts('Send emails with an attached PDF where possible. Generate printable PDFs for contacts who cannot receive email.');
$emailOptions['pdfemail_both'] = ts('Send emails with an attached PDF where possible. Generate printable PDFs for all contacts.');
}
$this->addElement('select', 'email_options', ts('Print and email options'), $emailOptions, array(), "<br/>", FALSE);
$this->addButtons(array(
array(
'type' => 'upload',
'name' => ts('Make Thank-you Letters'),
'isDefault' => TRUE,
),
array(
'type' => 'cancel',
'name' => ts('Done'),
),
)
);
}
/**
* Process the form after the input has been submitted and validated.
*/
public function postProcess() {
CRM_Contribute_Form_Task_PDFLetterCommon::postProcess($this);
}
/**
* List available tokens for this form.
*
* @return array
*/
public function listTokens() {
$tokens = CRM_Core_SelectValues::contactTokens();
$tokens = array_merge(CRM_Core_SelectValues::contributionTokens(), $tokens);
return $tokens;
}
}

View file

@ -0,0 +1,428 @@
<?php
/**
* This class provides the common functionality for creating PDF letter for
* one or a group of contact ids.
*/
class CRM_Contribute_Form_Task_PDFLetterCommon extends CRM_Contact_Form_Task_PDFLetterCommon {
/**
* Process the form after the input has been submitted and validated.
*
* @param CRM_Contribute_Form_Task $form
* @param array $formValues
*/
public static function postProcess(&$form, $formValues = NULL) {
if (empty($formValues)) {
$formValues = $form->controller->exportValues($form->getName());
}
list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($formValues);
$isPDF = FALSE;
$emailParams = array();
if (!empty($formValues['email_options'])) {
$returnProperties['email'] = $returnProperties['on_hold'] = $returnProperties['is_deceased'] = $returnProperties['do_not_email'] = 1;
$emailParams = array(
'subject' => $formValues['subject'],
);
// We need display_name for emailLetter() so add to returnProperties here
$returnProperties['display_name'] = 1;
if (stristr($formValues['email_options'], 'pdfemail')) {
$isPDF = TRUE;
}
}
// update dates ?
$receipt_update = isset($formValues['receipt_update']) ? $formValues['receipt_update'] : FALSE;
$thankyou_update = isset($formValues['thankyou_update']) ? $formValues['thankyou_update'] : FALSE;
$nowDate = date('YmdHis');
$receipts = $thanks = $emailed = 0;
$updateStatus = '';
$task = 'CRM_Contribution_Form_Task_PDFLetterCommon';
$realSeparator = ', ';
$tableSeparators = array(
'td' => '</td><td>',
'tr' => '</td></tr><tr><td>',
);
//the original thinking was mutliple options - but we are going with only 2 (comma & td) for now in case
// there are security (& UI) issues we need to think through
if (isset($formValues['group_by_separator'])) {
if (in_array($formValues['group_by_separator'], array('td', 'tr'))) {
$realSeparator = $tableSeparators[$formValues['group_by_separator']];
}
elseif ($formValues['group_by_separator'] == 'br') {
$realSeparator = "<br />";
}
}
$separator = '****~~~~';// a placeholder in case the separator is common in the string - e.g ', '
$groupBy = $formValues['group_by'];
// skip some contacts ?
$skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE;
$skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE;
$contributionIDs = $form->getVar('_contributionIds');
if ($form->_includesSoftCredits) {
//@todo - comment on what is stored there
$contributionIDs = $form->getVar('_contributionContactIds');
}
list($contributions, $contacts) = self::buildContributionArray($groupBy, $contributionIDs, $returnProperties, $skipOnHold, $skipDeceased, $messageToken, $task, $separator, $form->_includesSoftCredits);
$html = array();
$contactHtml = $emailedHtml = array();
foreach ($contributions as $contributionId => $contribution) {
$contact = &$contacts[$contribution['contact_id']];
$grouped = FALSE;
$groupByID = 0;
if ($groupBy) {
$groupByID = empty($contribution[$groupBy]) ? 0 : $contribution[$groupBy];
$contribution = $contact['combined'][$groupBy][$groupByID];
$grouped = TRUE;
}
if (empty($groupBy) || empty($contact['is_sent'][$groupBy][$groupByID])) {
$html[$contributionId] = self::generateHtml($contact, $contribution, $groupBy, $contributions, $realSeparator, $tableSeparators, $messageToken, $html_message, $separator, $grouped, $groupByID);
$contactHtml[$contact['contact_id']][] = $html[$contributionId];
if (!empty($formValues['email_options'])) {
if (self::emailLetter($contact, $html[$contributionId], $isPDF, $formValues, $emailParams)) {
$emailed++;
if (!stristr($formValues['email_options'], 'both')) {
$emailedHtml[$contributionId] = TRUE;
}
}
}
$contact['is_sent'][$groupBy][$groupByID] = TRUE;
}
// update dates (do it for each contribution including grouped recurring contribution)
//@todo - the 2 calls below bypass all hooks. Using the api would possibly be slower than one call but not than 2
if ($receipt_update) {
$result = CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'receipt_date', $nowDate);
if ($result) {
$receipts++;
}
}
if ($thankyou_update) {
$result = CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'thankyou_date', $nowDate);
if ($result) {
$thanks++;
}
}
}
// This seems silly, but the old behavior was to first check `_cid`
// and then use the provided `$contactIds`. Probably not even necessary,
// but difficult to audit.
$contactIds = $form->_cid ? array($form->_cid) : array_keys($contacts);
self::createActivities($form, $html_message, $contactIds, CRM_Utils_Array::value('subject', $formValues, ts('Thank you letter')), CRM_Utils_Array::value('campaign_id', $formValues), $contactHtml);
$html = array_diff_key($html, $emailedHtml);
if (!empty($formValues['is_unit_test'])) {
return $html;
}
//CRM-19761
if (!empty($html)) {
$type = $formValues['document_type'];
if ($type == 'pdf') {
CRM_Utils_PDF_Utils::html2pdf($html, "CiviLetter.pdf", FALSE, $formValues);
}
else {
CRM_Utils_PDF_Document::html2doc($html, "CiviLetter.$type", $formValues);
}
}
$form->postProcessHook();
if ($emailed) {
$updateStatus = ts('Receipts have been emailed to %1 contributions.', array(1 => $emailed));
}
if ($receipts) {
$updateStatus = ts('Receipt date has been updated for %1 contributions.', array(1 => $receipts));
}
if ($thanks) {
$updateStatus .= ' ' . ts('Thank-you date has been updated for %1 contributions.', array(1 => $thanks));
}
if ($updateStatus) {
CRM_Core_Session::setStatus($updateStatus);
}
if (!empty($html)) {
// ie. we have only sent emails - lets no show a white screen
CRM_Utils_System::civiExit(1);
}
}
/**
* Check whether any of the tokens exist in the html outside a table cell.
* If they do the table cell separator is not supported (return false)
* At this stage we are only anticipating contributions passed in this way but
* it would be easy to add others
* @param $tokens
* @param $html
*
* @return bool
*/
public static function isValidHTMLWithTableSeparator($tokens, $html) {
$relevantEntities = array('contribution');
foreach ($relevantEntities as $entity) {
if (isset($tokens[$entity]) && is_array($tokens[$entity])) {
foreach ($tokens[$entity] as $token) {
if (!self::isHtmlTokenInTableCell($token, $entity, $html)) {
return FALSE;
}
}
}
}
return TRUE;
}
/**
* Check that the token only appears in a table cell. The '</td><td>' separator cannot otherwise work
* Calculate the number of times it appears IN the cell & the number of times it appears - should be the same!
*
* @param $token
* @param $entity
* @param $textToSearch
*
* @return bool
*/
public static function isHtmlTokenInTableCell($token, $entity, $textToSearch) {
$tokenToMatch = $entity . '.' . $token;
$dontCare = array();
$within = preg_match_all("|<td.+?{" . $tokenToMatch . "}.+?</td|si", $textToSearch, $dontCare);
$total = preg_match_all("|{" . $tokenToMatch . "}|", $textToSearch, $dontCare);
return ($within == $total);
}
/**
*
* @param string $html_message
* @param array $contact
* @param array $contribution
* @param array $messageToken
* @param bool $grouped
* Does this letter represent more than one contribution.
* @param string $separator
* What is the preferred letter separator.
* @return string
*/
private static function resolveTokens($html_message, $contact, $contribution, $messageToken, $grouped, $separator) {
$categories = self::getTokenCategories();
$tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact, TRUE, $messageToken);
if ($grouped) {
$tokenHtml = CRM_Utils_Token::replaceMultipleContributionTokens($separator, $tokenHtml, $contribution, TRUE, $messageToken);
}
else {
// no change to normal behaviour to avoid risk of breakage
$tokenHtml = CRM_Utils_Token::replaceContributionTokens($tokenHtml, $contribution, TRUE, $messageToken);
}
$tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact, $categories, TRUE);
if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) {
$smarty = CRM_Core_Smarty::singleton();
// also add the tokens to the template
$smarty->assign_by_ref('contact', $contact);
$tokenHtml = $smarty->fetch("string:$tokenHtml");
}
return $tokenHtml;
}
/**
* Generate the contribution array from the form, we fill in the contact details and determine any aggregation
* around contact_id of contribution_recur_id
*
* @param string $groupBy
* @param array $contributionIDs
* @param array $returnProperties
* @param bool $skipOnHold
* @param bool $skipDeceased
* @param array $messageToken
* @param string $task
* @param string $separator
* @param bool $isIncludeSoftCredits
*
* @return array
*/
public static function buildContributionArray($groupBy, $contributionIDs, $returnProperties, $skipOnHold, $skipDeceased, $messageToken, $task, $separator, $isIncludeSoftCredits) {
$contributions = $contacts = array();
foreach ($contributionIDs as $item => $contributionId) {
// Basic return attributes available to the template.
$returnValues = array('contact_id', 'total_amount', 'financial_type', 'receive_date', 'contribution_campaign_title');
if (!empty($messageToken['contribution'])) {
$returnValues = array_merge($messageToken['contribution'], $returnValues);
}
// retrieve contribution tokens listed in $returnProperties using Contribution.Get API
$contribution = civicrm_api3('Contribution', 'getsingle', array(
'id' => $contributionId,
'return' => $returnValues,
));
$contribution['campaign'] = CRM_Utils_Array::value('contribution_campaign_title', $contribution);
$contributions[$contributionId] = $contribution;
if ($isIncludeSoftCredits) {
//@todo find out why this happens & add comments
list($contactID) = explode('-', $item);
$contactID = (int) $contactID;
}
else {
$contactID = $contribution['contact_id'];
}
if (!isset($contacts[$contactID])) {
$contacts[$contactID] = array();
$contacts[$contactID]['contact_aggregate'] = 0;
$contacts[$contactID]['combined'] = $contacts[$contactID]['contribution_ids'] = array();
}
$contacts[$contactID]['contact_aggregate'] += $contribution['total_amount'];
$groupByID = empty($contribution[$groupBy]) ? 0 : $contribution[$groupBy];
$contacts[$contactID]['contribution_ids'][$groupBy][$groupByID][$contributionId] = TRUE;
if (!isset($contacts[$contactID]['combined'][$groupBy]) || !isset($contacts[$contactID]['combined'][$groupBy][$groupByID])) {
$contacts[$contactID]['combined'][$groupBy][$groupByID] = $contribution;
$contacts[$contactID]['aggregates'][$groupBy][$groupByID] = $contribution['total_amount'];
}
else {
$contacts[$contactID]['combined'][$groupBy][$groupByID] = self::combineContributions($contacts[$contactID]['combined'][$groupBy][$groupByID], $contribution, $separator);
$contacts[$contactID]['aggregates'][$groupBy][$groupByID] += $contribution['total_amount'];
}
}
// Assign the available contributions before calling tokens so hooks parsing smarty can access it.
// Note that in core code you can only use smarty here if enable if for the whole site, incl
// CiviMail, with a big performance impact.
// Hooks allow more nuanced smarty usage here.
CRM_Core_Smarty::singleton()->assign('contributions', $contributions);
foreach ($contacts as $contactID => $contact) {
$tokenResolvedContacts = CRM_Utils_Token::getTokenDetails(array('contact_id' => $contactID),
$returnProperties,
$skipOnHold,
$skipDeceased,
NULL,
$messageToken,
$task
);
$contacts[$contactID] = array_merge($tokenResolvedContacts[0][$contactID], $contact);
}
return array($contributions, $contacts);
}
/**
* We combine the contributions by adding the contribution to each field with the separator in
* between the existing value and the new one. We put the separator there even if empty so it is clear what the
* value for previous contributions was
*
* @param array $existing
* @param array $contribution
* @param string $separator
*
* @return array
*/
public static function combineContributions($existing, $contribution, $separator) {
foreach ($contribution as $field => $value) {
$existing[$field] = isset($existing[$field]) ? $existing[$field] . $separator : '';
$existing[$field] .= $value;
}
return $existing;
}
/**
* We are going to retrieve the combined contribution and if smarty mail is enabled we
* will also assign an array of contributions for this contact to the smarty template
*
* @param array $contact
* @param array $contributions
* @param $groupBy
* @param int $groupByID
*/
public static function assignCombinedContributionValues($contact, $contributions, $groupBy, $groupByID) {
CRM_Core_Smarty::singleton()->assign('contact_aggregate', $contact['contact_aggregate']);
CRM_Core_Smarty::singleton()
->assign('contributions', array_intersect_key($contributions, $contact['contribution_ids'][$groupBy][$groupByID]));
CRM_Core_Smarty::singleton()->assign('contribution_aggregate', $contact['aggregates'][$groupBy][$groupByID]);
}
/**
* Send pdf by email.
*
* @param array $contact
* @param string $html
*
* @param $is_pdf
* @param array $format
* @param array $params
*
* @return bool
*/
public static function emailLetter($contact, $html, $is_pdf, $format = array(), $params = array()) {
try {
if (empty($contact['email'])) {
return FALSE;
}
$mustBeEmpty = array('do_not_email', 'is_deceased', 'on_hold');
foreach ($mustBeEmpty as $emptyField) {
if (!empty($contact[$emptyField])) {
return FALSE;
}
}
$defaults = array(
'toName' => $contact['display_name'],
'toEmail' => $contact['email'],
'text' => '',
'html' => $html,
);
if (empty($params['from'])) {
$emails = CRM_Core_BAO_Email::getFromEmail();
$emails = array_keys($emails);
$defaults['from'] = array_pop($emails);
}
if (!empty($params['subject'])) {
$defaults['subject'] = $params['subject'];
}
else {
$defaults['subject'] = ts('Thank you for your contribution/s');
}
if ($is_pdf) {
$defaults['html'] = ts('Please see attached');
$defaults['attachments'] = array(CRM_Utils_Mail::appendPDF('ThankYou.pdf', $html, $format));
}
$params = array_merge($defaults);
return CRM_Utils_Mail::send($params);
}
catch (CRM_Core_Exception $e) {
return FALSE;
}
}
/**
* @param $contact
* @param $formValues
* @param $contribution
* @param $groupBy
* @param $contributions
* @param $realSeparator
* @param $tableSeparators
* @param $messageToken
* @param $html_message
* @param $separator
* @param $categories
* @param bool $grouped
* @param int $groupByID
*
* @return string
*/
protected static function generateHtml(&$contact, $contribution, $groupBy, $contributions, $realSeparator, $tableSeparators, $messageToken, $html_message, $separator, $grouped, $groupByID) {
static $validated = FALSE;
$html = NULL;
self::assignCombinedContributionValues($contact, $contributions, $groupBy, $groupByID);
if (empty($groupBy) || empty($contact['is_sent'][$groupBy][$groupByID])) {
if (!$validated && in_array($realSeparator, $tableSeparators) && !self::isValidHTMLWithTableSeparator($messageToken, $html_message)) {
$realSeparator = ', ';
CRM_Core_Session::setStatus(ts('You have selected the table cell separator, but one or more token fields are not placed inside a table cell. This would result in invalid HTML, so comma separators have been used instead.'));
}
$validated = TRUE;
$html = str_replace($separator, $realSeparator, self::resolveTokens($html_message, $contact, $contribution, $messageToken, $grouped, $separator));
}
return $html;
}
}

View file

@ -0,0 +1,136 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality for batch profile update for contributions.
*/
class CRM_Contribute_Form_Task_PickProfile extends CRM_Contribute_Form_Task {
/**
* The title of the group
*
* @var string
*/
protected $_title;
/**
* Maximum contributions that should be allowed to update
*/
protected $_maxContributions = 100;
/**
* Variable to store redirect path
*/
protected $_userContext;
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
// initialize the task and row fields
parent::preProcess();
$session = CRM_Core_Session::singleton();
$this->_userContext = $session->readUserContext();
CRM_Utils_System::setTitle(ts('Update multiple contributions'));
$validate = FALSE;
//validations
if (count($this->_contributionIds) > $this->_maxContributions) {
CRM_Core_Session::setStatus(ts("The maximum number of contributions you can select for Update multiple contributions is %1. You have selected %2. Please select fewer contributions from your search results and try again.", array(
1 => $this->_maxContributions,
2 => count($this->_contributionIds),
)), ts('Update multiple records error'), 'error');
$validate = TRUE;
}
// than redirect
if ($validate) {
CRM_Utils_System::redirect($this->_userContext);
}
}
/**
* Build the form object.
*/
public function buildQuickForm() {
$types = array('Contribution');
$profiles = CRM_Core_BAO_UFGroup::getProfiles($types, TRUE);
if (empty($profiles)) {
CRM_Core_Session::setStatus(ts("You will need to create a Profile containing the %1 fields you want to edit before you can use Update multiple contributions. Navigate to Administer CiviCRM > Customize Data and Screens > CiviCRM Profile to configure a Profile. Consult the online Administrator documentation for more information.", array(1 => $types[0])), ts('Profile Required'), 'error');
CRM_Utils_System::redirect($this->_userContext);
}
$ufGroupElement = $this->add('select', 'uf_group_id', ts('Select Profile'),
array(
'' => ts('- select profile -'),
) + $profiles, TRUE
);
$this->addDefaultButtons(ts('Continue'));
}
/**
* Add local and global form rules.
*/
public function addRules() {
$this->addFormRule(array('CRM_Contribute_Form_Task_PickProfile', 'formRule'));
}
/**
* Global validation rules for the form.
*
* @param array $fields
* Posted values of the form.
*
* @return array
* list of errors to be posted back to the form
*/
public static function formRule($fields) {
return TRUE;
}
/**
* Process the form after the input has been submitted and validated.
*/
public function postProcess() {
$params = $this->exportValues();
$this->set('ufGroupId', $params['uf_group_id']);
// also reset the batch page so it gets new values from the db
$this->controller->resetPage('Batch');
}
}

View file

@ -0,0 +1,97 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality to print contribution records.
*/
class CRM_Contribute_Form_Task_Print extends CRM_Contribute_Form_Task {
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
parent::preprocess();
// set print view, so that print templates are called
$this->controller->setPrint(1);
// get the formatted params
$queryParams = $this->get('queryParams');
$sortID = NULL;
if ($this->get(CRM_Utils_Sort::SORT_ID)) {
$sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID),
$this->get(CRM_Utils_Sort::SORT_DIRECTION)
);
}
$selector = new CRM_Contribute_Selector_Search($queryParams, $this->_action, $this->_componentClause);
$controller = new CRM_Core_Selector_Controller($selector, NULL, $sortID, CRM_Core_Action::VIEW, $this, CRM_Core_Selector_Controller::SCREEN);
$controller->setEmbedded(TRUE);
$controller->run();
}
/**
* Build the form object.
*
* It consists of
* - displaying the QILL (query in local language)
* - displaying elements for saving the search
*/
public function buildQuickForm() {
//
// just need to add a javascript to popup the window for printing
//
$this->addButtons(array(
array(
'type' => 'next',
'name' => ts('Print Contributions'),
'js' => array('onclick' => 'window.print()'),
'isDefault' => TRUE,
),
array(
'type' => 'back',
'name' => ts('Done'),
),
)
);
}
/**
* Process the form after the input has been submitted and validated.
*/
public function postProcess() {
// redirect to the main search page after printing is over
}
}

View file

@ -0,0 +1,59 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* Used for displaying results
*/
class CRM_Contribute_Form_Task_Result extends CRM_Contribute_Form_Task {
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
}
/**
* Build the form object.
*/
public function buildQuickForm() {
$this->addButtons(array(
array(
'type' => 'done',
'name' => ts('Done'),
'isDefault' => TRUE,
),
)
);
}
}

View file

@ -0,0 +1,87 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality to save a search
* Saved Searches are used for saving frequently used queries
*/
class CRM_Contribute_Form_Task_SearchTaskHookSample extends CRM_Contribute_Form_Task {
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
parent::preProcess();
$rows = array();
// display name and contribution details of all selected contacts
$contribIDs = implode(',', $this->_contributionIds);
$query = "
SELECT co.total_amount as amount,
co.receive_date as receive_date,
co.source as source,
ct.display_name as display_name
FROM civicrm_contribution co
INNER JOIN civicrm_contact ct ON ( co.contact_id = ct.id )
WHERE co.id IN ( $contribIDs )";
$dao = CRM_Core_DAO::executeQuery($query,
CRM_Core_DAO::$_nullArray
);
while ($dao->fetch()) {
$rows[] = array(
'display_name' => $dao->display_name,
'amount' => $dao->amount,
'source' => $dao->source,
'receive_date' => $dao->receive_date,
);
}
$this->assign('rows', $rows);
}
/**
* Build the form object.
*/
public function buildQuickForm() {
$this->addButtons(array(
array(
'type' => 'done',
'name' => ts('Done'),
'isDefault' => TRUE,
),
)
);
}
}

View file

@ -0,0 +1,350 @@
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
/**
* This class provides the functionality to email a group of contacts.
*/
class CRM_Contribute_Form_Task_Status extends CRM_Contribute_Form_Task {
/**
* Are we operating in "single mode", i.e. updating the task of only
* one specific contribution?
*
* @var boolean
*/
public $_single = FALSE;
protected $_rows;
/**
* Build all the data structures needed to build the form.
*/
public function preProcess() {
$id = CRM_Utils_Request::retrieve('id', 'Positive',
$this, FALSE
);
if ($id) {
$this->_contributionIds = array($id);
$this->_componentClause = " civicrm_contribution.id IN ( $id ) ";
$this->_single = TRUE;
$this->assign('totalSelectedContributions', 1);
}
else {
parent::preProcess();
}
// check that all the contribution ids have pending status
$query = "
SELECT count(*)
FROM civicrm_contribution
WHERE contribution_status_id != 2
AND {$this->_componentClause}";
$count = CRM_Core_DAO::singleValueQuery($query,
CRM_Core_DAO::$_nullArray
);
if ($count != 0) {
CRM_Core_Error::statusBounce(ts('Please select only online contributions with Pending status.'));
}
// we have all the contribution ids, so now we get the contact ids
parent::setContactIDs();
$this->assign('single', $this->_single);
}
/**
* Build the form object.
*/
public function buildQuickForm() {
$status = CRM_Contribute_PseudoConstant::contributionStatus();
unset($status[2]);
unset($status[5]);
unset($status[6]);
$this->add('select', 'contribution_status_id',
ts('Contribution Status'),
$status,
TRUE
);
$contribIDs = implode(',', $this->_contributionIds);
$query = "
SELECT c.id as contact_id,
co.id as contribution_id,
c.display_name as display_name,
co.total_amount as amount,
co.receive_date as receive_date,
co.source as source,
co.payment_instrument_id as paid_by,
co.check_number as check_no
FROM civicrm_contact c,
civicrm_contribution co
WHERE co.contact_id = c.id
AND co.id IN ( $contribIDs )";
$dao = CRM_Core_DAO::executeQuery($query,
CRM_Core_DAO::$_nullArray
);
// build a row for each contribution id
$this->_rows = array();
$attributes = CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Contribution');
$defaults = array();
$now = date("m/d/Y");
$paidByOptions = array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::paymentInstrument();
while ($dao->fetch()) {
$row['contact_id'] = $dao->contact_id;
$row['contribution_id'] = $dao->contribution_id;
$row['display_name'] = $dao->display_name;
$row['amount'] = $dao->amount;
$row['source'] = $dao->source;
$row['trxn_id'] = &$this->addElement('text', "trxn_id_{$row['contribution_id']}", ts('Transaction ID'));
$this->addRule("trxn_id_{$row['contribution_id']}",
ts('This Transaction ID already exists in the database. Include the account number for checks.'),
'objectExists',
array('CRM_Contribute_DAO_Contribution', $dao->contribution_id, 'trxn_id')
);
$row['fee_amount'] = &$this->add('text', "fee_amount_{$row['contribution_id']}", ts('Fee Amount'),
$attributes['fee_amount']
);
$this->addRule("fee_amount_{$row['contribution_id']}", ts('Please enter a valid amount.'), 'money');
$defaults["fee_amount_{$row['contribution_id']}"] = 0.0;
$row['trxn_date'] = $this->addDate("trxn_date_{$row['contribution_id']}", FALSE,
ts('Receipt Date'), array('formatType' => 'activityDate')
);
$defaults["trxn_date_{$row['contribution_id']}"] = $now;
$this->add("text", "check_number_{$row['contribution_id']}", ts('Check Number'));
$defaults["check_number_{$row['contribution_id']}"] = $dao->check_no;
$this->add("select", "payment_instrument_id_{$row['contribution_id']}", ts('Payment Method'), $paidByOptions);
$defaults["payment_instrument_id_{$row['contribution_id']}"] = $dao->paid_by;
$this->_rows[] = $row;
}
$this->assign_by_ref('rows', $this->_rows);
$this->setDefaults($defaults);
$this->addButtons(array(
array(
'type' => 'next',
'name' => ts('Update Pending Status'),
'isDefault' => TRUE,
),
array(
'type' => 'back',
'name' => ts('Cancel'),
),
)
);
$this->addFormRule(array('CRM_Contribute_Form_Task_Status', 'formRule'));
}
/**
* Global validation rules for the form.
*
* @param array $fields
* Posted values of the form.
*
* @return array
* list of errors to be posted back to the form
*/
public static function formRule($fields) {
$seen = $errors = array();
foreach ($fields as $name => $value) {
if (strpos($name, 'trxn_id_') !== FALSE) {
if ($fields[$name]) {
if (array_key_exists($value, $seen)) {
$errors[$name] = ts('Transaction ID\'s must be unique. Include the account number for checks.');
}
$seen[$value] = 1;
}
}
if ((strpos($name, 'check_number_') !== FALSE) && $value) {
$contribID = substr($name, 13);
if ($fields["payment_instrument_id_{$contribID}"] != CRM_Core_OptionGroup::getValue('payment_instrument', 'Check', 'name')) {
$errors["payment_instrument_id_{$contribID}"] = ts("Payment Method should be Check when a check number is entered for a contribution.");
}
}
}
return empty($errors) ? TRUE : $errors;
}
/**
* Process the form after the input has been submitted and validated.
*/
public function postProcess() {
$params = $this->controller->exportValues($this->_name);
// submit the form with values.
self::processForm($this, $params);
CRM_Core_Session::setStatus(ts('Contribution status has been updated for selected record(s).'), ts('Status Updated'), 'success');
}
/**
* Process the form with submitted params.
*
* Also supports unit test.
*
* @param CRM_Core_Form $form
* @param array $params
*
* @throws \Exception
*/
public static function processForm($form, $params) {
$statusID = CRM_Utils_Array::value('contribution_status_id', $params);
$baseIPN = new CRM_Core_Payment_BaseIPN();
$transaction = new CRM_Core_Transaction();
// get the missing pieces for each contribution
$contribIDs = implode(',', $form->_contributionIds);
$details = self::getDetails($contribIDs);
$template = CRM_Core_Smarty::singleton();
// for each contribution id, we just call the baseIPN stuff
foreach ($form->_rows as $row) {
$input = $ids = $objects = array();
$input['component'] = $details[$row['contribution_id']]['component'];
$ids['contact'] = $row['contact_id'];
$ids['contribution'] = $row['contribution_id'];
$ids['contributionRecur'] = NULL;
$ids['contributionPage'] = NULL;
$ids['membership'] = CRM_Utils_Array::value('membership', $details[$row['contribution_id']]);
$ids['participant'] = CRM_Utils_Array::value('participant', $details[$row['contribution_id']]);
$ids['event'] = CRM_Utils_Array::value('event', $details[$row['contribution_id']]);
if (!$baseIPN->validateData($input, $ids, $objects, FALSE)) {
CRM_Core_Error::fatal();
}
$contribution = &$objects['contribution'];
$contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL,
'name'
);
if ($statusID == array_search('Cancelled', $contributionStatuses)) {
$baseIPN->cancelled($objects, $transaction);
$transaction->commit();
continue;
}
elseif ($statusID == array_search('Failed', $contributionStatuses)) {
$baseIPN->failed($objects, $transaction);
$transaction->commit();
continue;
}
// status is not pending
if ($contribution->contribution_status_id != array_search('Pending',
$contributionStatuses
)
) {
$transaction->commit();
continue;
}
// 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'] = $params["fee_amount_{$row['contribution_id']}"];
$input['check_number'] = $params["check_number_{$row['contribution_id']}"];
$input['payment_instrument_id'] = $params["payment_instrument_id_{$row['contribution_id']}"];
$input['net_amount'] = $contribution->total_amount - $input['fee_amount'];
if (!empty($params["trxn_id_{$row['contribution_id']}"])) {
$input['trxn_id'] = trim($params["trxn_id_{$row['contribution_id']}"]);
}
else {
$input['trxn_id'] = $contribution->invoice_id;
}
$input['trxn_date'] = CRM_Utils_Date::processDate($params["trxn_date_{$row['contribution_id']}"], date('H:i:s'));
// @todo calling baseIPN like this is a pattern in it's last gasps. Call contribute.completetransaction api.
$baseIPN->completeTransaction($input, $ids, $objects, $transaction, FALSE);
// reset template values before processing next transactions
$template->clearTemplateVars();
}
}
/**
* @param $contributionIDs
*
* @return array
*/
public static function &getDetails($contributionIDs) {
$query = "
SELECT c.id as contribution_id,
c.contact_id as contact_id ,
mp.membership_id as membership_id ,
pp.participant_id as participant_id ,
p.event_id as event_id
FROM civicrm_contribution c
LEFT JOIN civicrm_membership_payment mp ON mp.contribution_id = c.id
LEFT JOIN civicrm_participant_payment pp ON pp.contribution_id = c.id
LEFT JOIN civicrm_participant p ON pp.participant_id = p.id
WHERE c.id IN ( $contributionIDs )";
$rows = array();
$dao = CRM_Core_DAO::executeQuery($query,
CRM_Core_DAO::$_nullArray
);
$rows = array();
while ($dao->fetch()) {
$rows[$dao->contribution_id]['component'] = $dao->participant_id ? 'event' : 'contribute';
$rows[$dao->contribution_id]['contact'] = $dao->contact_id;
if ($dao->membership_id) {
if (!array_key_exists('membership', $rows[$dao->contribution_id])) {
$rows[$dao->contribution_id]['membership'] = array();
}
$rows[$dao->contribution_id]['membership'][] = $dao->membership_id;
}
if ($dao->participant_id) {
$rows[$dao->contribution_id]['participant'] = $dao->participant_id;
}
if ($dao->event_id) {
$rows[$dao->contribution_id]['event'] = $dao->event_id;
}
}
return $rows;
}
}