<?php
/*
+--------------------------------------------------------------------+
- | CiviCRM version 4.6 |
+ | CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2015 |
+--------------------------------------------------------------------+
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2015
- * $Id$
- *
*/
class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
//set defaults in create mode
if (!$contributionID) {
CRM_Core_DAO::setCreateDefaults($params, self::getDefaults());
- self::calculateMissingAmountParams($params);
}
+ self::calculateMissingAmountParams($params, $contributionID);
if (!empty($params['payment_instrument_id'])) {
$paymentInstruments = CRM_Contribute_PseudoConstant::paymentInstrument('name');
$setPrevContribution = FALSE;
}
}
+ if ($contributionID && $setPrevContribution) {
+ $params['prevContribution'] = self::getValues(array('id' => $contributionID), CRM_Core_DAO::$_nullArray, CRM_Core_DAO::$_nullArray);
+ }
if ($contributionID) {
CRM_Utils_Hook::pre('edit', 'Contribution', $contributionID, $params);
$contribution->id = $contributionID;
- if (!CRM_Utils_Rule::currencyCode($contribution->currency)) {
- $config = CRM_Core_Config::singleton();
- $contribution->currency = $config->defaultCurrency;
- }
-
- if ($contributionID && $setPrevContribution) {
- $params['prevContribution'] = self::getValues(array('id' => $contributionID), CRM_Core_DAO::$_nullArray, CRM_Core_DAO::$_nullArray);
+ if (empty($contribution->id)) {
+ // (only) on 'create', make sure that a valid currency is set (CRM-16845)
+ if (!CRM_Utils_Rule::currencyCode($contribution->currency)) {
+ $config = CRM_Core_Config::singleton();
+ $contribution->currency = $config->defaultCurrency;
+ }
}
$result = $contribution->save();
* @param array $ids
* The array that holds all the db ids.
*
- * @return CRM_Contribute_BAO_Contribution|null the found object or null
+ * @return CRM_Contribute_BAO_Contribution|null
+ * The found object or null
*/
- public static function &getValues($params, &$values, &$ids) {
+ public static function getValues($params, &$values, &$ids) {
if (empty($params)) {
return NULL;
}
*
* @param array $params
* Params for a new contribution before they are saved.
+ * @param int|null $contributionID
+ * Contribution ID if we are dealing with an update.
+ *
+ * @throws \CiviCRM_API3_Exception
*/
- public static function calculateMissingAmountParams(&$params) {
- if (!isset($params['fee_amount'])) {
+ public static function calculateMissingAmountParams(&$params, $contributionID) {
+ if (!$contributionID && !isset($params['fee_amount'])) {
if (isset($params['total_amount']) && isset($params['net_amount'])) {
$params['fee_amount'] = $params['total_amount'] - $params['net_amount'];
}
}
}
if (!isset($params['net_amount'])) {
- $params['net_amount'] = $params['total_amount'] - $params['fee_amount'];
+ if (!$contributionID) {
+ $params['net_amount'] = $params['total_amount'] - $params['fee_amount'];
+ }
+ else {
+ if (isset($params['fee_amount']) || isset($params['total_amount'])) {
+ // We have an existing contribution and fee_amount or total_amount has been passed in but not net_amount.
+ // net_amount may need adjusting.
+ $contribution = civicrm_api3('Contribution', 'getsingle', array(
+ 'id' => $contributionID,
+ 'return' => array('total_amount', 'net_amount'),
+ ));
+ $totalAmount = isset($params['total_amount']) ? $params['total_amount'] : CRM_Utils_Array::value('total_amount', $contribution);
+ $feeAmount = isset($params['fee_amount']) ? $params['fee_amount'] : CRM_Utils_Array::value('fee_amount', $contribution);
+ $params['net_amount'] = $totalAmount - $feeAmount;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param $params
+ * @param $billingLocationTypeID
+ *
+ * @return array
+ */
+ protected static function getBillingAddressParams($params, $billingLocationTypeID) {
+ $hasBillingField = FALSE;
+ $billingFields = array(
+ 'street_address',
+ 'city',
+ 'state_province_id',
+ 'postal_code',
+ 'country_id',
+ );
+
+ //build address array
+ $addressParams = array();
+ $addressParams['location_type_id'] = $billingLocationTypeID;
+ $addressParams['is_billing'] = 1;
+
+ $billingFirstName = CRM_Utils_Array::value('billing_first_name', $params);
+ $billingMiddleName = CRM_Utils_Array::value('billing_middle_name', $params);
+ $billingLastName = CRM_Utils_Array::value('billing_last_name', $params);
+ $addressParams['address_name'] = "{$billingFirstName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingMiddleName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingLastName}";
+
+ foreach ($billingFields as $value) {
+ $addressParams[$value] = CRM_Utils_Array::value("billing_{$value}-{$billingLocationTypeID}", $params);
+ if (!empty($addressParams[$value])) {
+ $hasBillingField = TRUE;
+ }
}
+ return array($hasBillingField, $addressParams);
+ }
+
+ /**
+ * Get address params ready to be passed to the payment processor.
+ *
+ * We need address params in a couple of formats. For the payment processor we wan state_province_id-5.
+ * To create an address we need state_province_id.
+ *
+ * @param array $params
+ * @param int $billingLocationTypeID
+ *
+ * @return array
+ */
+ public static function getPaymentProcessorReadyAddressParams($params, $billingLocationTypeID) {
+ list($hasBillingField, $addressParams) = self::getBillingAddressParams($params, $billingLocationTypeID);
+ foreach ($addressParams as $name => $field) {
+ if (substr($name, 0, 8) == 'billing_') {
+ $addressParams[substr($name, 9)] = $addressParams[$field];
+ }
+ }
+ return array($hasBillingField, $addressParams);
}
/**
}
}
- // Handle soft credit and / or link to personal campaign page
- $softIDs = CRM_Contribute_BAO_ContributionSoft::getSoftCreditIds($contribution->id);
-
- $pcpId = CRM_Contribute_BAO_ContributionSoft::getSoftCreditIds($contribution->id, TRUE);
-
- if ($pcp = CRM_Utils_Array::value('pcp', $params)) {
- $softParams = array();
- $softParams['id'] = $pcpId ? $pcpId : NULL;
- $softParams['contribution_id'] = $contribution->id;
- $softParams['pcp_id'] = $pcp['pcp_made_through_id'];
- $softParams['contact_id'] = CRM_Core_DAO::getFieldValue('CRM_PCP_DAO_PCP',
- $pcp['pcp_made_through_id'], 'contact_id'
- );
- $softParams['currency'] = $contribution->currency;
- $softParams['amount'] = $contribution->total_amount;
- $softParams['pcp_display_in_roll'] = CRM_Utils_Array::value('pcp_display_in_roll', $pcp);
- $softParams['pcp_roll_nickname'] = CRM_Utils_Array::value('pcp_roll_nickname', $pcp);
- $softParams['pcp_personal_note'] = CRM_Utils_Array::value('pcp_personal_note', $pcp);
- $softParams['soft_credit_type_id'] = CRM_Core_OptionGroup::getValue('soft_credit_type', 'pcp', 'name');
- $contributionSoft = CRM_Contribute_BAO_ContributionSoft::add($softParams);
- //Send notification to owner for PCP
- if ($contributionSoft->pcp_id && empty($pcpId)) {
- CRM_Contribute_Form_Contribution_Confirm::pcpNotifyOwner($contribution, $contributionSoft);
- }
- }
- //Delete PCP against this contribution and create new on submitted PCP information
- elseif (array_key_exists('pcp', $params) && $pcpId) {
- $deleteParams = array('id' => $pcpId);
- CRM_Contribute_BAO_ContributionSoft::del($deleteParams);
- }
- if (isset($params['soft_credit'])) {
- $softParams = $params['soft_credit'];
- foreach ($softParams as $softParam) {
- if (!empty($softIDs)) {
- $key = key($softIDs);
- $softParam['id'] = $softIDs[$key];
- unset($softIDs[$key]);
- }
- $softParam['contribution_id'] = $contribution->id;
- $softParam['currency'] = $contribution->currency;
- //case during Contribution Import when we assign soft contribution amount as contribution's total_amount by default
- if (empty($softParam['amount'])) {
- $softParam['amount'] = $contribution->total_amount;
- }
- CRM_Contribute_BAO_ContributionSoft::add($softParam);
- }
-
- if (!empty($softIDs)) {
- foreach ($softIDs as $softID) {
- if (!in_array($softID, $params['soft_credit_ids'])) {
- $deleteParams = array('id' => $softID);
- CRM_Contribute_BAO_ContributionSoft::del($deleteParams);
- }
- }
- }
- }
+ CRM_Contribute_BAO_ContributionSoft::processSoftContribution($params, $contribution);
$transaction->commit();
'name'
);
if (!$activity->find(TRUE)) {
+ if (empty($contribution->contact_id)) {
+ $contribution->find(TRUE);
+ }
CRM_Activity_BAO_Activity::addActivity($contribution, 'Offline');
}
else {
* (reference) the default values, some of which need to be resolved.
* @param bool $reverse
* True if we want to resolve the values in the reverse direction (value -> name).
- *
- * @return void
*/
public static function resolveDefaults(&$defaults, $reverse = FALSE) {
self::lookupValue($defaults, 'financial_type', CRM_Contribute_PseudoConstant::financialType(), $reverse);
),
);
+ // CRM-16713 - contribution search by Premiums on 'Find Contribution' form.
+ $premiums = array(
+ 'contribution_product_id' => array(
+ 'title' => ts('Premium'),
+ 'name' => 'contribution_product_id',
+ 'where' => 'civicrm_product.id',
+ 'data_type' => CRM_Utils_Type::T_INT,
+ ),
+ );
+
$fields = array_merge($impFields, $typeField, $contributionStatus, $contributionPage, $optionField, $expFieldProduct,
- $expFieldsContrib, $contributionNote, $contributionRecurId, $extraFields, $softCreditFields, $financialAccount,
+ $expFieldsContrib, $contributionNote, $contributionRecurId, $extraFields, $softCreditFields, $financialAccount, $premiums,
CRM_Core_BAO_CustomField::getFieldsForImport('Contribution')
);
return $results;
}
+ /**
+ * React to a financial transaction (payment) failure.
+ *
+ * Prior to CRM-16417 these were simply removed from the database but it has been agreed that seeing attempted
+ * payments is important for forensic and outreach reasons.
+ *
+ * @param int $contributionID
+ * @param string $message
+ */
+ public static function failPayment($contributionID, $contactID, $message) {
+ civicrm_api3('activity', 'create', array(
+ 'activity_type_id' => 'Failed Payment',
+ 'details' => $message,
+ 'subject' => ts('Payment failed at payment processor'),
+ 'source_record_id' => $contributionID,
+ 'source_contact_id' => CRM_Core_Session::getLoggedInContactID() ? CRM_Core_Session::getLoggedInContactID() :
+ $contactID,
+ ));
+ }
+
/**
* Check if there is a contribution with the same trxn_id or invoice_id.
*
*
* @return array
* list of contribution fields
- *
*/
public static function getHonorContacts($honorId) {
$params = array();
$nextYear = $year + 1;
if ($config->fiscalYearStart) {
- if ($config->fiscalYearStart['M'] < 10) {
- $config->fiscalYearStart['M'] = '0' . $config->fiscalYearStart['M'];
+ $newFiscalYearStart = $config->fiscalYearStart;
+ if ($newFiscalYearStart['M'] < 10) {
+ $newFiscalYearStart['M'] = '0' . $newFiscalYearStart['M'];
}
- if ($config->fiscalYearStart['d'] < 10) {
- $config->fiscalYearStart['d'] = '0' . $config->fiscalYearStart['d'];
+ if ($newFiscalYearStart['d'] < 10) {
+ $newFiscalYearStart['d'] = '0' . $newFiscalYearStart['d'];
}
+ $config->fiscalYearStart = $newFiscalYearStart;
$monthDay = $config->fiscalYearStart['M'] . $config->fiscalYearStart['d'];
}
else {
/**
* Check if there is a contribution with the params passed in.
+ *
* Used for trxn_id,invoice_id and contribution_id
*
* @param array $params
*
* @return array
* associated array
- *
*/
public static function getContributionDetails($exportMode, $componentIds) {
$paymentDetails = array();
/**
* Create address associated with contribution record.
*
+ * As long as there is one or more billing field in the parameters we will create the address.
+ *
+ * (historically the decision to create or not was based on the payment 'type' but these lines are greyer than once
+ * thought).
+ *
* @param array $params
* @param int $billingLocationTypeID
*
* @return int
* address id
*/
- public static function createAddress(&$params, $billingLocationTypeID) {
- $billingFields = array(
- 'street_address',
- 'city',
- 'state_province_id',
- 'postal_code',
- 'country_id',
- );
-
- //build address array
- $addressParams = array();
- $addressParams['location_type_id'] = $billingLocationTypeID;
- $addressParams['is_billing'] = 1;
-
- $billingFirstName = CRM_Utils_Array::value('billing_first_name', $params);
- $billingMiddleName = CRM_Utils_Array::value('billing_middle_name', $params);
- $billingLastName = CRM_Utils_Array::value('billing_last_name', $params);
- $addressParams['address_name'] = "{$billingFirstName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingMiddleName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingLastName}";
-
- foreach ($billingFields as $value) {
- $addressParams[$value] = CRM_Utils_Array::value("billing_{$value}-{$billingLocationTypeID}", $params);
+ public static function createAddress($params, $billingLocationTypeID) {
+ list($hasBillingField, $addressParams) = self::getBillingAddressParams($params, $billingLocationTypeID);
+ if ($hasBillingField) {
+ $address = CRM_Core_BAO_Address::add($addressParams, FALSE);
+ return $address->id;
}
+ return NULL;
- $address = CRM_Core_BAO_Address::add($addressParams, FALSE);
-
- return $address->id;
}
/**
*
* @param int $contributionId
* @param int $contactId
- *
*/
public static function deleteAddress($contributionId = NULL, $contactId = NULL) {
$clauses = array();
/**
* Update contribution as well as related objects.
*
+ * This function by-passes hooks - to address this - don't use this function.
+ *
+ * @deprecated
+ *
+ * Use api contribute.completetransaction
+ * For failures use failPayment (preferably exposing by api in the process).
+ *
* @param array $params
* @param bool $processContributionObject
*
return CRM_Core_DAO::singleValueQuery($query);
}
+ /**
+ * Repeat a transaction as part of a recurring series.
+ *
+ * Only call this via the api as it is being refactored. The intention is that the repeatTransaction function
+ * (possibly living on the ContributionRecur BAO) would be called first to create a pending contribution with a
+ * subsequent call to the contribution.completetransaction api.
+ *
+ * The completeTransaction functionality has historically been overloaded to both complete and repeat payments.
+ *
+ * @param CRM_Contribute_BAO_Contribution $contribution
+ * @param array $input
+ * @param array $contributionParams
+ *
+ * @return array
+ */
+ protected static function repeatTransaction(&$contribution, &$input, $contributionParams) {
+ if (!empty($contribution->id)) {
+ return FALSE;
+ }
+ if (empty($contribution->id)) {
+ // Unclear why this would only be set for repeats.
+ if (!empty($input['amount'])) {
+ $contribution->total_amount = $contributionParams['total_amount'] = $input['amount'];
+ }
+ $templateContribution = civicrm_api3('Contribution', 'getsingle', array(
+ 'contribution_recur_id' => $contributionParams['contribution_recur_id'],
+ 'options' => array('limit' => 1),
+ ));
+ $contributionParams['skipLineItem'] = TRUE;
+ $contributionParams['status_id'] = 'Pending';
+ $contributionParams['financial_type_id'] = $templateContribution['financial_type_id'];
+ $contributionParams['contact_id'] = $templateContribution['contact_id'];
+ $contributionParams['source'] = empty($templateContribution['source']) ? ts('Recurring contribution') : $templateContribution['source'];
+ $createContribution = civicrm_api3('Contribution', 'create', $contributionParams);
+ $contribution->id = $createContribution['id'];
+ $input['line_item'] = CRM_Contribute_BAO_ContributionRecur::addRecurLineItems($contribution->contribution_recur_id, $contribution);
+ CRM_Contribute_BAO_ContributionRecur::copyCustomValues($contributionParams['contribution_recur_id'], $contribution->id);
+ return TRUE;
+ }
+ }
+
/**
* Get individual id for onbehalf contribution.
*
* Input as delivered from Payment Processor.
* @param array $ids
* Ids as Loaded by Payment Processor.
- * @param bool $required
- * Is Payment processor / contribution page required.
* @param bool $loadAll
* Load all related objects - even where id not passed in? (allows API to call this).
*
* @return bool
* @throws Exception
*/
- public function loadRelatedObjects(&$input, &$ids, $required = FALSE, $loadAll = FALSE) {
+ public function loadRelatedObjects(&$input, &$ids, $loadAll = FALSE) {
if ($loadAll) {
$ids = array_merge($this->getComponentDetails($this->id), $ids);
if (empty($ids['contact']) && isset($this->contact_id)) {
$this->_component = strtolower(CRM_Utils_Array::value('component', $input, 'contribute'));
}
}
- $paymentProcessorID = CRM_Utils_Array::value('paymentProcessor', $ids);
- $contributionType = new CRM_Financial_BAO_FinancialType();
- $contributionType->id = $this->financial_type_id;
- if (!$contributionType->find(TRUE)) {
- throw new Exception("Could not find financial type record: " . $this->financial_type_id);
+
+ // If the object is not fully populated then make sure it is - this is a more about legacy paths & cautious
+ // refactoring than anything else, and has unit test coverage.
+ if (empty($this->financial_type_id)) {
+ $this->find(TRUE);
}
- if (!empty($ids['contact'])) {
- $this->_relatedObjects['contact'] = new CRM_Contact_BAO_Contact();
- $this->_relatedObjects['contact']->id = $ids['contact'];
- $this->_relatedObjects['contact']->find(TRUE);
+
+ $paymentProcessorID = CRM_Utils_Array::value('payment_processor_id', $input, CRM_Utils_Array::value(
+ 'paymentProcessor',
+ $ids
+ ));
+
+ if (!$paymentProcessorID && $this->contribution_page_id) {
+ $paymentProcessorID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage',
+ $this->contribution_page_id,
+ 'payment_processor'
+ );
+ if ($paymentProcessorID) {
+ $intentionalEnotice = $CRM16923AnUnreliableMethodHasBeenUserToDeterminePaymentProcessorFromContributionPage;
+ }
+ }
+
+ $ids['contributionType'] = $this->financial_type_id;
+ $ids['financialType'] = $this->financial_type_id;
+
+ $entities = array(
+ 'contact' => 'CRM_Contact_BAO_Contact',
+ 'contributionRecur' => 'CRM_Contribute_BAO_ContributionRecur',
+ 'contributionType' => 'CRM_Financial_BAO_FinancialType',
+ 'financialType' => 'CRM_Financial_BAO_FinancialType',
+ );
+ foreach ($entities as $entity => $bao) {
+ if (!empty($ids[$entity])) {
+ $this->_relatedObjects[$entity] = new $bao();
+ $this->_relatedObjects[$entity]->id = $ids[$entity];
+ if (!$this->_relatedObjects[$entity]->find(TRUE)) {
+ throw new CRM_Core_Exception($entity . ' could not be loaded');
+ }
+ }
+ }
+
+ if (!empty($ids['contributionRecur']) && !$paymentProcessorID) {
+ $paymentProcessorID = $this->_relatedObjects['contributionRecur']->payment_processor_id;
+ }
+
+ if (!empty($ids['pledge_payment'])) {
+ foreach ($ids['pledge_payment'] as $key => $paymentID) {
+ if (empty($paymentID)) {
+ continue;
+ }
+ $payment = new CRM_Pledge_BAO_PledgePayment();
+ $payment->id = $paymentID;
+ if (!$payment->find(TRUE)) {
+ throw new Exception("Could not find pledge payment record: " . $paymentID);
+ }
+ $this->_relatedObjects['pledge_payment'][] = $payment;
+ }
}
- $this->_relatedObjects['contributionType'] = $contributionType;
if ($this->_component == 'contribute') {
// retrieve the other optional objects first so
}
}
}
-
- if (!empty($ids['pledge_payment'])) {
-
- foreach ($ids['pledge_payment'] as $key => $paymentID) {
- if (empty($paymentID)) {
- continue;
- }
- $payment = new CRM_Pledge_BAO_PledgePayment();
- $payment->id = $paymentID;
- if (!$payment->find(TRUE)) {
- throw new Exception("Could not find pledge payment record: " . $paymentID);
- }
- $this->_relatedObjects['pledge_payment'][] = $payment;
- }
- }
-
- if (!empty($ids['contributionRecur'])) {
- $recur = new CRM_Contribute_BAO_ContributionRecur();
- $recur->id = $ids['contributionRecur'];
- if (!$recur->find(TRUE)) {
- throw new Exception("Could not find recur record: " . $ids['contributionRecur']);
- }
- $this->_relatedObjects['contributionRecur'] = &$recur;
- //get payment processor id from recur object.
- $paymentProcessorID = $recur->payment_processor_id;
- }
- //for normal contribution get the payment processor id.
- if (!$paymentProcessorID) {
- if ($this->contribution_page_id) {
- // get the payment processor id from contribution page
- $paymentProcessorID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionPage',
- $this->contribution_page_id,
- 'payment_processor'
- );
- }
- //fail to load payment processor id.
- elseif (empty($ids['pledge_payment'])) {
- $loadObjectSuccess = TRUE;
- if ($required) {
- throw new Exception("Could not find contribution page for contribution record: " . $this->id);
- }
- return $loadObjectSuccess;
- }
- }
}
else {
// we are in event mode
$this->_relatedObjects['participant'] = &$participant;
+ // get the payment processor id from event - this is inaccurate see CRM-16923
+ // in future we should look at throwing an exception here rather than an dubious guess.
if (!$paymentProcessorID) {
$paymentProcessorID = $this->_relatedObjects['event']->payment_processor;
+ if ($paymentProcessorID) {
+ $intentionalEnotice = $CRM16923AnUnreliableMethodHasBeenUserToDeterminePaymentProcessorFromEvent;
+ }
}
}
$this->is_test ? 'test' : 'live'
);
$ids['paymentProcessor'] = $paymentProcessorID;
- $this->_relatedObjects['paymentProcessor'] = &$paymentProcessor;
- }
- elseif ($required) {
- throw new Exception("Could not find payment processor for contribution record: " . $this->id);
+ $this->_relatedObjects['paymentProcessor'] = $paymentProcessor;
}
-
return TRUE;
}
* @throws Exception
*/
public function composeMessageArray(&$input, &$ids, &$values, $recur = FALSE, $returnMessageText = TRUE) {
- if (empty($this->_relatedObjects)) {
- $this->loadRelatedObjects($input, $ids);
- }
+ $this->loadRelatedObjects($input, $ids);
+
if (empty($this->_component)) {
$this->_component = CRM_Utils_Array::value('component', $input);
}
//what does recur 'mean here - to do with payment processor return functionality but
// what is the importance
if ($recur && !empty($this->_relatedObjects['paymentProcessor'])) {
- $paymentObject = &CRM_Core_Payment::singleton(
- $this->is_test ? 'test' : 'live',
- $this->_relatedObjects['paymentProcessor']
- );
+ $paymentObject = Civi\Payment\System::singleton()->getByProcessor($this->_relatedObjects['paymentProcessor']);
$entityID = $entity = NULL;
if (isset($ids['contribution'])) {
$entityID = $ids['membership'][0];
}
- $url = $paymentObject->subscriptionURL($entityID, $entity);
- $template->assign('cancelSubscriptionUrl', $url);
-
- $url = $paymentObject->subscriptionURL($entityID, $entity, 'billing');
- $template->assign('updateSubscriptionBillingUrl', $url);
-
- $url = $paymentObject->subscriptionURL($entityID, $entity, 'update');
- $template->assign('updateSubscriptionUrl', $url);
+ $template->assign('cancelSubscriptionUrl', $paymentObject->subscriptionURL($entityID, $entity));
+ $template->assign('updateSubscriptionBillingUrl', $paymentObject->subscriptionURL($entityID, $entity, 'billing'));
+ $template->assign('updateSubscriptionUrl', $paymentObject->subscriptionURL($entityID, $entity, 'update'));
if ($this->_relatedObjects['paymentProcessor']['billing_mode'] & CRM_Core_Payment::BILLING_MODE_FORM) {
//direct mode showing billing block, so use directIPN for temporary
}
// todo remove strtolower - check consistency
if (strtolower($this->_component) == 'event') {
+ $eventParams = array('id' => $this->_relatedObjects['participant']->event_id);
+ $values['event'] = array();
+
+ CRM_Event_BAO_Event::retrieve($eventParams, $values['event']);
+
+ //get location details
+ $locationParams = array('entity_id' => $this->_relatedObjects['participant']->event_id, 'entity_table' => 'civicrm_event');
+ $values['location'] = CRM_Core_BAO_Location::getValues($locationParams);
+
+ $ufJoinParams = array(
+ 'entity_table' => 'civicrm_event',
+ 'entity_id' => $ids['event'],
+ 'module' => 'CiviEvent',
+ );
+
+ list($custom_pre_id,
+ $custom_post_ids
+ ) = CRM_Core_BAO_UFJoin::getUFGroupIds($ufJoinParams);
+
+ $values['custom_pre_id'] = $custom_pre_id;
+ $values['custom_post_id'] = $custom_post_ids;
+ //for tasks 'Change Participant Status' and 'Batch Update Participants Via Profile' case
+ //and cases involving status updation through ipn
+ // whatever that means!
+ // total_amount appears to be the preferred input param & it is unclear why we support amount here
+ // perhaps we should throw an e-notice if amount is set & force total_amount?
+ if (!empty($input['amount'])) {
+ $values['totalAmount'] = $input['amount'];
+ }
+
+ if ($values['event']['is_email_confirm']) {
+ $values['is_email_receipt'] = 1;
+ }
return CRM_Event_BAO_Event::sendMail($ids['contact'], $values,
$this->_relatedObjects['participant']->id, $this->is_test, $returnMessageText
);
$values['address'] = $addressDetails[0]['display'];
}
if ($this->_component == 'contribute') {
+ //get soft contributions
+ $softContributions = CRM_Contribute_BAO_ContributionSoft::getSoftContribution($this->id, TRUE);
+ if (!empty($softContributions)) {
+ $values['softContributions'] = $softContributions['soft_credit'];
+ }
if (isset($this->contribution_page_id)) {
CRM_Contribute_BAO_ContributionPage::setValues(
$this->contribution_page_id,
$values['event'] = array();
CRM_Event_BAO_Event::retrieve($eventParams, $values['event']);
+ // add custom fields for event
+ $eventGroupTree = CRM_Core_BAO_CustomGroup::getTree('Event', $this->_relatedObjects['event'], $this->_relatedObjects['event']->id);
+
+ $eventCustomGroup = array();
+ foreach ($eventGroupTree as $key => $group) {
+ if ($key === 'info') {
+ continue;
+ }
+
+ foreach ($group['fields'] as $k => $customField) {
+ $groupLabel = $group['title'];
+ if (!empty($customField['customValue'])) {
+ foreach ($customField['customValue'] as $customFieldValues) {
+ $eventCustomGroup[$groupLabel][$customField['label']] = CRM_Utils_Array::value('data', $customFieldValues);
+ }
+ }
+ }
+ }
+ $values['event']['customGroup'] = $eventCustomGroup;
+
+ //get participant details
+ $participantParams = array(
+ 'id' => $this->_relatedObjects['participant']->id,
+ );
+
+ $values['participant'] = array();
+
+ CRM_Event_BAO_Participant::getValues($participantParams, $values['participant'], $participantIds);
+ // add custom fields for event
+ $participantGroupTree = CRM_Core_BAO_CustomGroup::getTree('Participant', $this->_relatedObjects['participant'], $this->_relatedObjects['participant']->id);
+ $participantCustomGroup = array();
+ foreach ($participantGroupTree as $key => $group) {
+ if ($key === 'info') {
+ continue;
+ }
+
+ foreach ($group['fields'] as $k => $customField) {
+ $groupLabel = $group['title'];
+ if (!empty($customField['customValue'])) {
+ foreach ($customField['customValue'] as $customFieldValues) {
+ $participantCustomGroup[$groupLabel][$customField['label']] = CRM_Utils_Array::value('data', $customFieldValues);
+ }
+ }
+ }
+ }
+ $values['participant']['customGroup'] = $participantCustomGroup;
//get location details
$locationParams = array(
}
}
+ $groupTree = CRM_Core_BAO_CustomGroup::getTree('Contribution', $this, $this->id);
+
+ $customGroup = array();
+ foreach ($groupTree as $key => $group) {
+ if ($key === 'info') {
+ continue;
+ }
+
+ foreach ($group['fields'] as $k => $customField) {
+ $groupLabel = $group['title'];
+ if (!empty($customField['customValue'])) {
+ foreach ($customField['customValue'] as $customFieldValues) {
+ $customGroup[$groupLabel][$customField['label']] = CRM_Utils_Array::value('data', $customFieldValues);
+ }
+ }
+ }
+ }
+ $values['customGroup'] = $customGroup;
+
return $values;
}
$template->assign('is_recur', (bool) $recur);
$template->assign('currency', $this->currency);
$template->assign('address', CRM_Utils_Address::format($input));
+ if (!empty($values['customGroup'])) {
+ $template->assign('customGroup', $values['customGroup']);
+ }
+ if (!empty($values['softContributions'])) {
+ $template->assign('softContributions', $values['softContributions']);
+ }
if ($this->_component == 'event') {
$template->assign('title', $values['event']['title']);
$participantRoles = CRM_Event_PseudoConstant::participantRole();
}
$values['event']['participant_role'] = implode(', ', $viewRoles);
$template->assign('event', $values['event']);
+ $template->assign('participant', $values['participant']);
$template->assign('location', $values['location']);
$template->assign('customPre', $values['custom_pre_id']);
$template->assign('customPost', $values['custom_post_id']);
$params['entity_id'] = $financialTxn->id;
}
}
- // record line items and finacial items
+ // record line items and financial items
if (empty($params['skipLineItem'])) {
CRM_Price_BAO_LineItem::processPriceSet($entityId, CRM_Utils_Array::value('line_item', $params), $params['contribution'], $entityTable, $update);
}
) {
return;
}
+ if (($params['prevContribution']->contribution_status_id == array_search('Partially paid', $contributionStatus))
+ && $params['contribution']->contribution_status_id == array_search('Completed', $contributionStatus)
+ && $context == 'changedStatus'
+ ) {
+ return;
+ }
if ($context == 'changedAmount' || $context == 'changeFinancialType') {
- $itemAmount = $params['trxnParams']['total_amount'] = $params['total_amount'] - $params['prevContribution']->total_amount;
+ $itemAmount = $params['trxnParams']['total_amount'] = $params['trxnParams']['net_amount'] = $params['total_amount'] - $params['prevContribution']->total_amount;
}
if ($context == 'changedStatus') {
//get all the statuses
|| $params['contribution']->contribution_status_id == array_search('Cancelled', $contributionStatus))
) {
$params['trxnParams']['total_amount'] = -$params['total_amount'];
+ if (is_null($params['contribution']->creditnote_id) || $params['contribution']->creditnote_id == "null") {
+ self::createCreditNoteId($params['contribution']->id);
+ }
}
elseif (($params['prevContribution']->contribution_status_id == array_search('Pending', $contributionStatus)
&& $params['prevContribution']->is_pay_later) || $params['prevContribution']->contribution_status_id == array_search('In Progress', $contributionStatus)
if ($params['contribution']->contribution_status_id == array_search('Cancelled', $contributionStatus)) {
$params['trxnParams']['to_financial_account_id'] = $arAccountId;
$params['trxnParams']['total_amount'] = -$params['total_amount'];
+ if (is_null($params['contribution']->creditnote_id) || $params['contribution']->creditnote_id == "null") {
+ self::createCreditNoteId($params['contribution']->id);
+ }
}
else {
$params['trxnParams']['from_financial_account_id'] = $arAccountId;
'Pending' => array('Cancelled', 'Completed', 'Failed'),
'In Progress' => array('Cancelled', 'Completed', 'Failed'),
'Refunded' => array('Cancelled', 'Completed'),
+ 'Partially paid' => array('Completed'),
);
if (!in_array($contributionStatuses[$fields['contribution_status_id']], $checkStatus[$contributionStatuses[$values['contribution_status_id']]])) {
}
}
+ /**
+ * Update related pledge payment payments.
+ *
+ * This function has been refactored out of the back office contribution form and may
+ * still overlap with other functions.
+ *
+ * @param string $action
+ * @param int $pledgePaymentID
+ * @param int $contributionID
+ * @param bool $adjustTotalAmount
+ * @param float $total_amount
+ * @param float $original_total_amount
+ * @param int $contribution_status_id
+ * @param int $original_contribution_status_id
+ */
+ public static function updateRelatedPledge(
+ $action,
+ $pledgePaymentID,
+ $contributionID,
+ $adjustTotalAmount,
+ $total_amount,
+ $original_total_amount,
+ $contribution_status_id,
+ $original_contribution_status_id
+ ) {
+ if (!$pledgePaymentID || $action & CRM_Core_Action::ADD && !$contributionID) {
+ return;
+ }
+
+ if ($pledgePaymentID) {
+ //store contribution id in payment record.
+ CRM_Core_DAO::setFieldValue('CRM_Pledge_DAO_PledgePayment', $pledgePaymentID, 'contribution_id', $contributionID);
+ }
+ else {
+ $pledgePaymentID = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment',
+ $contributionID,
+ 'id',
+ 'contribution_id'
+ );
+ }
+ $pledgeID = CRM_Core_DAO::getFieldValue('CRM_Pledge_DAO_PledgePayment',
+ $contributionID,
+ 'pledge_id',
+ 'contribution_id'
+ );
+
+ $updatePledgePaymentStatus = FALSE;
+
+ // If either the status or the amount has changed we update the pledge status.
+ if ($action & CRM_Core_Action::ADD) {
+ $updatePledgePaymentStatus = TRUE;
+ }
+ elseif ($action & CRM_Core_Action::UPDATE && (($original_contribution_status_id != $contribution_status_id) ||
+ ($original_total_amount != $total_amount))
+ ) {
+ $updatePledgePaymentStatus = TRUE;
+ }
+
+ if ($updatePledgePaymentStatus) {
+ CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeID,
+ array($pledgePaymentID),
+ $contribution_status_id,
+ NULL,
+ $total_amount,
+ $adjustTotalAmount
+ );
+ }
+ }
+
+ /**
+ * Compute the stats values
+ *
+ * @param $stat either 'mode' or 'median'
+ * @param $sql
+ * @param $alias of civicrm_contribution
+ */
+ public static function computeStats($stat, $sql, $alias = NULL) {
+ $mode = $median = array();
+ switch ($stat) {
+ case 'mode':
+ $modeDAO = CRM_Core_DAO::executeQuery($sql);
+ while ($modeDAO->fetch()) {
+ if ($modeDAO->civicrm_contribution_total_amount_count > 1) {
+ $mode[] = CRM_Utils_Money::format($modeDAO->amount, $modeDAO->currency);
+ }
+ else {
+ $mode[] = 'N/A';
+ }
+ }
+ return $mode;
+
+ case 'median':
+ $currencies = CRM_Core_OptionGroup::values('currencies_enabled');
+ foreach ($currencies as $currency => $val) {
+ $midValue = 0;
+ $where = "AND {$alias}.currency = '{$currency}'";
+ $rowCount = CRM_Core_DAO::singleValueQuery("SELECT count(*) as count {$sql} {$where}");
+
+ $even = FALSE;
+ $offset = 1;
+ $medianRow = floor($rowCount / 2);
+ if ($rowCount % 2 == 0 && !empty($medianRow)) {
+ $even = TRUE;
+ $offset++;
+ $medianRow--;
+ }
+
+ $medianValue = "SELECT {$alias}.total_amount as median
+ {$sql} {$where}
+ ORDER BY median LIMIT {$medianRow},{$offset}";
+ $medianValDAO = CRM_Core_DAO::executeQuery($medianValue);
+ while ($medianValDAO->fetch()) {
+ if ($even) {
+ $midValue = $midValue + $medianValDAO->median;
+ }
+ else {
+ $median[] = CRM_Utils_Money::format($medianValDAO->median, $currency);
+ }
+ }
+ if ($even) {
+ $midValue = $midValue / 2;
+ $median[] = CRM_Utils_Money::format($midValue, $currency);
+ }
+ }
+ return $median;
+
+ default:
+ return;
+ }
+ }
+
+ /**
+ * Complete an order.
+ *
+ * Do not call this directly - use the contribution.completetransaction api as this function is being refactored.
+ *
+ * Currently overloaded to complete a transaction & repeat a transaction - fix!
+ *
+ * Moving it out of the BaseIPN class is just the first step.
+ *
+ * @param array $input
+ * @param array $ids
+ * @param array $objects
+ * @param CRM_Core_Transaction $transaction
+ * @param int $recur
+ * @param CRM_Contribute_BAO_Contribution $contribution
+ * @param bool $isRecurring
+ * Duplication of param needs review. Only used by AuthorizeNetIPN
+ * @param int $isFirstOrLastRecurringPayment
+ * Deprecated param only used by AuthorizeNetIPN.
+ */
+ public static function completeOrder(&$input, &$ids, $objects, $transaction, $recur, $contribution, $isRecurring, $isFirstOrLastRecurringPayment) {
+ $primaryContributionID = isset($contribution->id) ? $contribution->id : $objects['first_contribution']->id;
+ // The previous details are used when calculating line items so keep it before any code that 'does something'
+ if (!empty($contribution->id)) {
+ $input['prevContribution'] = CRM_Contribute_BAO_Contribution::getValues(array('id' => $contribution->id),
+ CRM_Core_DAO::$_nullArray, CRM_Core_DAO::$_nullArray);
+ }
+ $inputContributionWhiteList = array(
+ 'fee_amount',
+ 'net_amount',
+ 'trxn_id',
+ 'check_number',
+ 'payment_instrument_id',
+ 'is_test',
+ 'campaign_id',
+ 'receive_date',
+ );
+
+ $contributionParams = array_merge(array(
+ 'contribution_status_id' => 'Completed',
+ ), array_intersect_key($input, array_fill_keys($inputContributionWhiteList, 1)
+ ));
+
+ $participant = CRM_Utils_Array::value('participant', $objects);
+ $memberships = CRM_Utils_Array::value('membership', $objects);
+ $recurContrib = CRM_Utils_Array::value('contributionRecur', $objects);
+ if (!empty($recurContrib->id)) {
+ $contributionParams['contribution_recur_id'] = $recurContrib->id;
+ }
+ self::repeatTransaction($contribution, $input, $contributionParams);
+
+ if (is_numeric($memberships)) {
+ $memberships = array($objects['membership']);
+ }
+
+ $changeDate = CRM_Utils_Array::value('trxn_date', $input, date('YmdHis'));
+
+ $values = array();
+ if (isset($input['is_email_receipt'])) {
+ $values['is_email_receipt'] = $input['is_email_receipt'];
+ }
+
+ if ($input['component'] == 'contribute') {
+ if ($contribution->contribution_page_id) {
+ CRM_Contribute_BAO_ContributionPage::setValues($contribution->contribution_page_id, $values);
+ $contributionParams['source'] = ts('Online Contribution') . ': ' . $values['title'];
+ }
+ elseif ($recurContrib && $recurContrib->id) {
+ $contributionParams['contribution_page_id'] = NULL;
+ $values['amount'] = $recurContrib->amount;
+ $values['financial_type_id'] = $objects['contributionType']->id;
+ $values['title'] = $source = ts('Offline Recurring Contribution');
+ $domainValues = CRM_Core_BAO_Domain::getNameAndEmail();
+ $values['receipt_from_name'] = $domainValues[0];
+ $values['receipt_from_email'] = $domainValues[1];
+ }
+
+ if (empty($contributionParams['receive_date']) && $changeDate) {
+ $contributionParams['receive_date'] = $changeDate;
+ }
+
+ if ($recurContrib && $recurContrib->id && !isset($input['is_email_receipt'])) {
+ //CRM-13273 - is_email_receipt setting on recurring contribution should take precedence over contribution page setting
+ // but CRM-16124 if $input['is_email_receipt'] is set then that should not be overridden.
+ $values['is_email_receipt'] = $recurContrib->is_email_receipt;
+ }
+
+ if (!empty($values['is_email_receipt'])) {
+ $contributionParams['receipt_date'] = $changeDate;
+ }
+
+ if (!empty($memberships)) {
+ foreach ($memberships as $membershipTypeIdKey => $membership) {
+ if ($membership) {
+ $membershipParams = array(
+ 'id' => $membership->id,
+ 'contact_id' => $membership->contact_id,
+ 'is_test' => $membership->is_test,
+ 'membership_type_id' => $membership->membership_type_id,
+ );
+
+ $currentMembership = CRM_Member_BAO_Membership::getContactMembership($membershipParams['contact_id'],
+ $membershipParams['membership_type_id'],
+ $membershipParams['is_test'],
+ $membershipParams['id']
+ );
+
+ // CRM-8141 update the membership type with the value recorded in log when membership created/renewed
+ // this picks up membership type changes during renewals
+ $sql = "
+SELECT membership_type_id
+FROM civicrm_membership_log
+WHERE membership_id={$membershipParams['id']}
+ORDER BY id DESC
+LIMIT 1;";
+ $dao = CRM_Core_DAO::executeQuery($sql);
+ if ($dao->fetch()) {
+ if (!empty($dao->membership_type_id)) {
+ $membershipParams['membership_type_id'] = $dao->membership_type_id;
+ }
+ }
+ $dao->free();
+
+ $membershipParams['num_terms'] = $contribution->getNumTermsByContributionAndMembershipType(
+ $membershipParams['membership_type_id'],
+ $primaryContributionID
+ );
+ $dates = array_fill_keys(array('join_date', 'start_date', 'end_date'), NULL);
+ if ($currentMembership) {
+ /*
+ * Fixed FOR CRM-4433
+ * In BAO/Membership.php(renewMembership function), we skip the extend membership date and status
+ * when Contribution mode is notify and membership is for renewal )
+ */
+ CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, $changeDate);
+
+ // @todo - we should pass membership_type_id instead of null here but not
+ // adding as not sure of testing
+ $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membershipParams['id'],
+ $changeDate, NULL, $membershipParams['num_terms']
+ );
+
+ $dates['join_date'] = $currentMembership['join_date'];
+ }
+
+ //get the status for membership.
+ $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dates['start_date'],
+ $dates['end_date'],
+ $dates['join_date'],
+ 'today',
+ TRUE,
+ $membershipParams['membership_type_id'],
+ $membershipParams
+ );
+
+ $membershipParams['status_id'] = CRM_Utils_Array::value('id', $calcStatus, 'New');
+ //we might be renewing membership,
+ //so make status override false.
+ $membershipParams['is_override'] = FALSE;
+ civicrm_api3('Membership', 'create', $membershipParams);
+
+ //update related Memberships.
+ CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $membershipParams);
+ }
+ }
+ }
+ }
+ else {
+ if (empty($input['IAmAHorribleNastyBeyondExcusableHackInTheCRMEventFORMTaskClassThatNeedsToBERemoved'])) {
+ $eventDetail = civicrm_api3('Event', 'getsingle', array('id' => $objects['event']->id));
+ $contributionParams['source'] = ts('Online Event Registration') . ': ' . $eventDetail['title'];
+ if ($eventDetail['is_email_confirm']) {
+ // @todo this should be set by the function that sends the mail after sending.
+ $contributionParams['receipt_date'] = $changeDate;
+ }
+ $participantParams['id'] = $participant->id;
+ $participantParams['status_id'] = 'Registered';
+ civicrm_api3('Participant', 'create', $participantParams);
+ }
+ }
+
+ $contributionParams['id'] = $contribution->id;
+
+ civicrm_api3('Contribution', 'create', $contributionParams);
+
+ // Add new soft credit against current $contribution.
+ if (CRM_Utils_Array::value('contributionRecur', $objects) && $objects['contributionRecur']->id) {
+ CRM_Contribute_BAO_ContributionRecur::addrecurSoftCredit($objects['contributionRecur']->id, $contribution->id);
+ }
+
+ $paymentProcessorId = '';
+ if (isset($objects['paymentProcessor'])) {
+ if (is_array($objects['paymentProcessor'])) {
+ $paymentProcessorId = $objects['paymentProcessor']['id'];
+ }
+ else {
+ $paymentProcessorId = $objects['paymentProcessor']->id;
+ }
+ }
+
+ $contributionStatuses = CRM_Core_PseudoConstant::get('CRM_Contribute_DAO_Contribution', 'contribution_status_id', array(
+ 'labelColumn' => 'name',
+ 'flip' => 1,
+ ));
+ if ((empty($input['prevContribution']) && $paymentProcessorId) || (!$input['prevContribution']->is_pay_later && $input['prevContribution']->contribution_status_id == $contributionStatuses['Pending'])) {
+ $input['payment_processor'] = $paymentProcessorId;
+ }
+ $input['contribution_status_id'] = $contributionStatuses['Completed'];
+ $input['total_amount'] = $input['amount'];
+ $input['contribution'] = $contribution;
+ $input['financial_type_id'] = $contribution->financial_type_id;
+
+ if (!empty($contribution->_relatedObjects['participant'])) {
+ $input['contribution_mode'] = 'participant';
+ $input['participant_id'] = $contribution->_relatedObjects['participant']->id;
+ $input['skipLineItem'] = 1;
+ }
+ elseif (!empty($contribution->_relatedObjects['membership'])) {
+ $input['skipLineItem'] = TRUE;
+ $input['contribution_mode'] = 'membership';
+ }
+ //@todo writing a unit test I was unable to create a scenario where this line did not fatal on second
+ // and subsequent payments. In this case the line items are created at
+ // CRM_Contribute_BAO_ContributionRecur::addRecurLineItems
+ // and since the contribution is saved prior to this line there is always a contribution-id,
+ // however there is never a prevContribution (which appears to mean original contribution not previous
+ // contribution - or preUpdateContributionObject most accurately)
+ // so, this is always called & only appears to succeed when prevContribution exists - which appears
+ // to mean "are we updating an exisitng pending contribution"
+ //I was able to make the unit test complete as fataling here doesn't prevent
+ // the contribution being created - but activities would not be created or emails sent
+
+ CRM_Contribute_BAO_Contribution::recordFinancialAccounts($input, NULL);
+
+ CRM_Core_Error::debug_log_message("Contribution record updated successfully");
+ $transaction->commit();
+
+ CRM_Contribute_BAO_ContributionRecur::updateRecurLinkedPledge($contribution);
+
+ // create an activity record
+ if ($input['component'] == 'contribute') {
+ //CRM-4027
+ $targetContactID = NULL;
+ if (!empty($ids['related_contact'])) {
+ $targetContactID = $contribution->contact_id;
+ $contribution->contact_id = $ids['related_contact'];
+ }
+ CRM_Activity_BAO_Activity::addActivity($contribution, NULL, $targetContactID);
+ // event
+ }
+ else {
+ CRM_Activity_BAO_Activity::addActivity($participant);
+ }
+
+ // CRM-9132 legacy behaviour was that receipts were sent out in all instances. Still sending
+ // when array_key 'is_email_receipt doesn't exist in case some instances where is needs setting haven't been set
+ if (!array_key_exists('is_email_receipt', $values) ||
+ $values['is_email_receipt'] == 1
+ ) {
+ self::sendMail($input, $ids, $objects['contribution'], $values, $recur, FALSE);
+ CRM_Core_Error::debug_log_message("Receipt sent");
+ }
+
+ CRM_Core_Error::debug_log_message("Success: Database updated");
+ if ($isRecurring) {
+ CRM_Contribute_BAO_ContributionRecur::sendRecurringStartOrEndNotification($ids, $recur,
+ $isFirstOrLastRecurringPayment);
+ }
+ }
+
+ /**
+ * Send receipt from contribution.
+ *
+ * Do not call this directly - it is being refactored. use contribution.sendmessage api call.
+ *
+ * Note that the compose message part has been moved to contribution
+ * In general LoadObjects is called first to get the objects but the composeMessageArray function now calls it.
+ *
+ * @param array $input
+ * Incoming data from Payment processor.
+ * @param array $ids
+ * Related object IDs.
+ * @param CRM_Contribute_BAO_Contribution $contribution
+ * @param array $values
+ * Values related to objects that have already been loaded.
+ * @param bool $recur
+ * Is it part of a recurring contribution.
+ * @param bool $returnMessageText
+ * Should text be returned instead of sent. This.
+ * is because the function is also used to generate pdfs
+ *
+ * @return array
+ */
+ public static function sendMail(&$input, &$ids, $contribution, &$values, $recur = FALSE, $returnMessageText = FALSE) {
+ $input['is_recur'] = $recur;
+ // set receipt from e-mail and name in value
+ if (!$returnMessageText) {
+ $session = CRM_Core_Session::singleton();
+ $userID = $session->get('userID');
+ if (!empty($userID)) {
+ list($userName, $userEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($userID);
+ $values['receipt_from_email'] = CRM_Utils_Array::value('receipt_from_email', $input, $userEmail);
+ $values['receipt_from_name'] = CRM_Utils_Array::value('receipt_from_name', $input, $userName);
+ }
+ }
+ return $contribution->composeMessageArray($input, $ids, $values, $recur, $returnMessageText);
+ }
+
+ /**
+ * Generate credit note id with next avaible number
+ *
+ * @param Integer $contributionId
+ * Contribution Id.
+ *
+ * @return string
+ * Credit Note Id.
+ */
+ public static function createCreditNoteId($contributionId) {
+ $prefixValue = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings');
+
+ $query = "select count(creditnote_id) as creditnote_number from civicrm_contribution";
+ $dao = CRM_Core_DAO::executeQuery($query);
+ $dao->fetch();
+ $creditNoteNum = $dao->creditnote_number;
+ $creditNoteId = NULL;
+
+ do {
+ $creditNoteNum++;
+ $creditNoteId = CRM_Utils_Array::value('credit_notes_prefix', $prefixValue) . "" . $creditNoteNum;
+ $result = civicrm_api3('Contribution', 'getcount', array(
+ 'sequential' => 1,
+ 'creditnote_id' => $creditNoteId,
+ ));
+ } while ($result > 0);
+
+ CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'creditnote_id', $creditNoteId);
+ return $creditNoteId;
+ }
+
}