*/
protected $_inputParameters = array();
+ protected $_isRecurring = FALSE;
+
+ protected $_isFirstOrLastRecurringPayment = FALSE;
/**
* Constructor
*/
if (!$this->loadObjects($input, $ids, $objects, $required, $paymentProcessorID)) {
return FALSE;
}
-
+ //the process is that the loadObjects is kind of hacked by loading the objects for the original contribution and then somewhat inconsistently using them for the
+ //current contribution. Here we ensure that the original contribution is available to the complete transaction function
+ //we don't want to fix this in the payment processor classes because we would have to fix all of them - so better to fix somewhere central
+ if (isset($objects['contributionRecur'])) {
+ $objects['first_contribution'] = $objects['contribution'];
+ }
return TRUE;
}
//add lineitems for recurring payments
if (!empty($objects['contributionRecur']) && $objects['contributionRecur']->id && $addLineItems) {
- $this->addrecurLineItems($objects['contributionRecur']->id, $contribution->id, CRM_Core_DAO::$_nullArray);
+ $this->addRecurLineItems($objects['contributionRecur']->id, $contribution);
}
//add new soft credit against current contribution id and
//add lineitems for recurring payments
if (!empty($objects['contributionRecur']) && $objects['contributionRecur']->id && $addLineItems) {
- $this->addrecurLineItems($objects['contributionRecur']->id, $contribution->id, CRM_Core_DAO::$_nullArray);
+ $this->addRecurLineItems($objects['contributionRecur']->id, $contribution);
}
//add new soft credit against current $contribution and
*/
function unhandled(&$objects, &$transaction) {
$transaction->rollback();
- // we dont handle this as yet
- CRM_Core_Error::debug_log_message("returning since contribution status: $status is not handled");
- echo "Failure: contribution status $status is not handled<p>";
+ CRM_Core_Error::debug_log_message("returning since contribution status: is not handled");
+ echo "Failure: contribution status is not handled<p>";
return FALSE;
}
*/
function completeTransaction(&$input, &$ids, &$objects, &$transaction, $recur = FALSE) {
$contribution = &$objects['contribution'];
+
+ $primaryContributionID = isset($contribution->id) ? $contribution->id : $objects['first_contribution']->id;
+
$memberships = &$objects['membership'];
if (is_numeric($memberships)) {
$memberships = array($objects['membership']);
// else fall back to using current membership type
$dao->free();
- $num_terms = $contribution->getNumTermsByContributionAndMembershipType($membership->membership_type_id);
+ $num_terms = $contribution->getNumTermsByContributionAndMembershipType($membership->membership_type_id, $primaryContributionID);
if ($currentMembership) {
/*
* Fixed FOR CRM-4433
}
//add lineitems for recurring payments
- if (!empty($objects['contributionRecur']) && $objects['contributionRecur']->id && $addLineItems) {
- $this->addrecurLineItems($objects['contributionRecur']->id, $contribution->id, $input);
+ if (!empty($objects['contributionRecur']) && $objects['contributionRecur']->id) {
+ if ($addLineItems) {
+ $input ['line_item'] = $this->addRecurLineItems($objects['contributionRecur']->id, $contribution);
+ }
+ else {
+ // this is just to prevent e-notices when we call recordFinancialAccounts - per comments on that line - intention is somewhat unclear
+ $input['line_item'] = array();
+ }
}
//copy initial contribution custom fields for recurring contributions
$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 $this->addrecurLineItems
+ // and subsequent payments. In this case the line items are created at $this->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)
// 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("Success: Database updated");
+ if ($this->_isRecurring) {
+ $this->sendRecurringStartOrEndNotification($ids, $recur);
+ }
}
/**
return TRUE;
}
- /*
+ /**
* Send receipt from contribution. 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
*
- * @params array $input Incoming data from Payment processor
- * @params array $ids Related object IDs
- * @params array $values values related to objects that have already been loaded
- * @params bool $recur is it part of a recurring contribution
- * @params bool $returnMessageText Should text be returned instead of sent. This
- * is because the function is also used to generate pdfs
- */
- /**
- * @param $input
- * @param $ids
+ * @param array $input Incoming data from Payment processor
+ * @param array $ids Related object IDs
* @param $objects
- * @param $values
- * @param bool $recur
- * @param bool $returnMessageText
+ * @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 mixed
+ * @return array
*/
function sendMail(&$input, &$ids, &$objects, &$values, $recur = FALSE, $returnMessageText = FALSE) {
$contribution = &$objects['contribution'];
return $contribution->composeMessageArray($input, $ids, $values, $recur, $returnMessageText);
}
+ /**
+ * Send start or end notification for recurring payments
+ * @param $ids
+ * @param $recur
+ */
+ function sendRecurringStartOrEndNotification($ids, $recur) {
+ if ($this->_isFirstOrLastRecurringPayment) {
+ $autoRenewMembership = FALSE;
+ if ($recur->id &&
+ isset($ids['membership']) && $ids['membership']
+ ) {
+ $autoRenewMembership = TRUE;
+ }
+
+ //send recurring Notification email for user
+ CRM_Contribute_BAO_ContributionPage::recurringNotify($this->_isFirstOrLastRecurringPayment,
+ $ids['contact'],
+ $ids['contributionPage'],
+ $recur,
+ $autoRenewMembership
+ );
+ }
+ }
+
/**
* Update contribution status - this is only called from one place in the code &
* it is unclear whether it is a function on the way in or on the way out
}
/**
- * @param $recurId
- * @param $contributionId
- * @param $input
+ * @param int $recurId
+ * @param $contribution
+ *
+ * @return array
*/
- function addrecurLineItems($recurId, $contributionId, &$input) {
- $lineSets = $lineItems = array();
-
- //Get the first contribution id with recur id
- if ($recurId) {
- $contriID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $recurId, 'id', 'contribution_recur_id');
- $lineItems = CRM_Price_BAO_LineItem::getLineItems($contriID, 'contribution');
- if (!empty($lineItems)) {
- foreach ($lineItems as $key => $value) {
- $pricesetID = new CRM_Price_DAO_PriceField();
- $pricesetID->id = $value['price_field_id'];
- $pricesetID->find(TRUE);
- $lineSets[$pricesetID->price_set_id][] = $value;
+ function addRecurLineItems($recurId, $contribution) {
+ $lineSets = array();
+
+ $originalContributionID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $recurId, 'id', 'contribution_recur_id');
+ $lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($originalContributionID);
+ if (!empty($lineItems)) {
+ foreach ($lineItems as $key => $value) {
+ $priceField = new CRM_Price_DAO_PriceField();
+ $priceField->id = $value['price_field_id'];
+ $priceField->find(TRUE);
+ $lineSets[$priceField->price_set_id][] = $value;
+ if ($value['entity_table'] == 'civicrm_membership') {
+ try {
+ civicrm_api3('membership_payment', 'create', array('membership_id' => $value['entity_id'], 'contribution_id' => $contribution->id));
+ }
+ catch (CiviCRM_API3_Exception $e) {
+ // we are catching & ignoring errors as an extra precaution since lost IPNs may be more serious that lost membership_payment data
+ // this fn is unit-tested so risk of changes elsewhere breaking it are otherwise mitigated
+ }
}
}
- if (!empty($input)) {
- $input['line_item'] = $lineSets;
- }
- else {
- CRM_Price_BAO_LineItem::processPriceSet($contributionId, $lineSets);
- }
}
+ else {
+ CRM_Price_BAO_LineItem::processPriceSet($contribution->id, $lineSets, $contribution);
+ }
+ return $lineSets;
}
// function to copy custom data of the