From 5fa7c328c43a91badbbb1410233010c22e862de7 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Sun, 22 Feb 2015 06:39:38 +1300 Subject: [PATCH] CRM-15996 add repeattransaction api & fix baseipn to create line items Note that there appears to be an issue with the contribution_recur object not being loaded. But, this seems a better place to fix it as it is a more direct way of determining if it is a recurring contribution --- CRM/Core/Payment/BaseIPN.php | 15 +++-- api/v3/Contribution.php | 116 +++++++++++++++++++++++++++++++---- 2 files changed, 112 insertions(+), 19 deletions(-) diff --git a/CRM/Core/Payment/BaseIPN.php b/CRM/Core/Payment/BaseIPN.php index 2607520887..e5354f0cd8 100644 --- a/CRM/Core/Payment/BaseIPN.php +++ b/CRM/Core/Payment/BaseIPN.php @@ -579,9 +579,12 @@ LIMIT 1;"; ) { $input['net_amount'] = $input['amount'] - $input['fee_amount']; } - $addLineItems = FALSE; + // This complete transaction function is being overloaded to create new contributions too. + // here we record if it is a new contribution. + // @todo separate the 2 more appropriately. + $isNewContribution = FALSE; if (empty($contribution->id)) { - $addLineItems = TRUE; + $isNewContribution = TRUE; } $contributionStatuses = CRM_Core_PseudoConstant::get('CRM_Contribute_DAO_Contribution', 'contribution_status_id', array( 'labelColumn' => 'name', @@ -627,10 +630,10 @@ LIMIT 1;"; $this->addrecurSoftCredit($objects['contributionRecur']->id, $contribution->id); } - //add lineitems for recurring payments - if (!empty($objects['contributionRecur']) && $objects['contributionRecur']->id) { - if ($addLineItems) { - $input['line_item'] = $this->addRecurLineItems($objects['contributionRecur']->id, $contribution); + //add line items for recurring payments + if (!empty($contribution->contribution_recur_id)) { + if ($isNewContribution) { + $input['line_item'] = $this->addRecurLineItems($contribution->contribution_recur_id, $contribution); } else { // this is just to prevent e-notices when we call recordFinancialAccounts - per comments on that line - intention is somewhat unclear diff --git a/api/v3/Contribution.php b/api/v3/Contribution.php index 1a2dff8fd4..609e38bceb 100644 --- a/api/v3/Contribution.php +++ b/api/v3/Contribution.php @@ -414,19 +414,7 @@ function civicrm_api3_contribution_completetransaction(&$params) { elseif ($contribution->contribution_status_id == CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name')) { throw new API_Exception(ts('Contribution already completed')); } - $objects = $contribution->_relatedObjects; - $objects['contribution'] = &$contribution; - $input['component'] = $contribution->_component; - $input['is_test'] = $contribution->is_test; - $input['trxn_id'] = !empty($params['trxn_id']) ? $params['trxn_id'] : $contribution->trxn_id; - $input['amount'] = $contribution->total_amount; - if (isset($params['is_email_receipt'])) { - $input['is_email_receipt'] = $params['is_email_receipt']; - } - // @todo required for base ipn but problematic as api layer handles this - $transaction = new CRM_Core_Transaction(); - $ipn = new CRM_Core_Payment_BaseIPN(); - $ipn->completeTransaction($input, $ids, $objects, $transaction, !empty($contribution->contribution_recur_id)); + $params = _ipn_complete_transaction($params, $contribution, $input, $ids); } catch(Exception $e) { throw new API_Exception('failed to load related objects' . $e->getMessage() . "\n" . $e->getTraceAsString()); @@ -453,3 +441,105 @@ function _civicrm_api3_contribution_completetransaction_spec(&$params) { 'type' => CRM_Utils_Type::T_BOOLEAN, ); } + +/** + * Complete an existing (pending) transaction. + * + * This will update related entities (participant, membership, pledge etc) + * and take any complete actions from the contribution page (e.g. send receipt). + * + * @todo - most of this should live in the BAO layer but as we want it to be an addition + * to 4.3 which is already stable we should add it to the api layer & re-factor into the BAO layer later + * + * @param array $params + * Input parameters. + * + * @throws API_Exception + * Api result array. + */ +function civicrm_api3_contribution_repeattransaction(&$params) { + $input = $ids = array(); + $contribution = new CRM_Contribute_BAO_Contribution(); + $contribution->id = $params['original_contribution_id']; + if (!$contribution->find(TRUE)) { + throw new API_Exception( + 'A valid original contribution ID is required', 'invalid_data'); + } + try { + if (!$contribution->loadRelatedObjects($input, $ids, FALSE, TRUE)) { + throw new API_Exception('failed to load related objects'); + } + unset($contribution->id, $contribution->trxn_id, $contribution->receive_date, $contribution->invoice_id); + $contribution->contribution_status_id = $params->contribution_status_id; + $contribution->receive_date = $params['receive_date']; + $params = _ipn_complete_transaction($params, $contribution, $input, $ids); + } + catch(Exception $e) { + throw new API_Exception('failed to load related objects' . $e->getMessage() . "\n" . $e->getTraceAsString()); + } +} + +/** + * Calls IPN complete transaction for completing or repeating a transaction. + * + * The IPN function is overloaded with two purposes - this is simply a wrapper for that + * when separating them in the api layer. + * + * @param array $params + * @param CRM_Contribute_BAO_Contribution $contribution + * @param array $input + * + * @param array $ids + * + * @return mixed + */ +function _ipn_complete_transaction(&$params, $contribution, $input, $ids) { + $objects = $contribution->_relatedObjects; + $objects['contribution'] = &$contribution; + $input['component'] = $contribution->_component; + $input['is_test'] = $contribution->is_test; + $input['trxn_id'] = !empty($params['trxn_id']) ? $params['trxn_id'] : $contribution->trxn_id; + $input['amount'] = $contribution->total_amount; + if (isset($params['is_email_receipt'])) { + $input['is_email_receipt'] = $params['is_email_receipt']; + } + // @todo required for base ipn but problematic as api layer handles this + $transaction = new CRM_Core_Transaction(); + $ipn = new CRM_Core_Payment_BaseIPN(); + $ipn->completeTransaction($input, $ids, $objects, $transaction, !empty($contribution->contribution_recur_id)); + return $params; +} + +/** + * Provide function metadata. + * + * @param array $params + */ +function _civicrm_api3_contribution_repeattransaction_spec(&$params) { + $params['original_contribution_id'] = array( + 'title' => 'Original Contribution ID', + 'type' => CRM_Utils_Type::T_INT, + 'api.required' => TRUE, + ); + $params['trxn_id'] = array( + 'title' => 'Transaction ID', + 'type' => CRM_Utils_Type::T_STRING, + ); + $params['is_email_receipt'] = array( + 'title' => 'Send email Receipt?', + 'type' => CRM_Utils_Type::T_BOOLEAN, + ); + $params['contribution_status_id'] = array( + 'title' => 'Contribution Status ID', + 'type' => CRM_Utils_Type::T_INT, + 'pseudoconstant' => array( + 'optionGroupName' => 'contribution_status', + ), + 'api.required' => TRUE, + ); + $params['receive_date'] = array( + 'title' => 'Contribution Receive Date', + 'type' => CRM_Utils_Type::T_DATE, + 'api.default' => 'now', + ); +} -- 2.25.1