elseif ($contribution->contribution_status_id == CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name')) {
throw new API_Exception(ts('Contribution already completed'));
}
- $params = _ipn_complete_transaction($params, $contribution, $input, $ids);
+ $input['trxn_id'] = !empty($params['trxn_id']) ? $params['trxn_id'] : $contribution->trxn_id;
+ $params = _ipn_process_transaction($params, $contribution, $input, $ids);
}
catch(Exception $e) {
throw new API_Exception('failed to load related objects' . $e->getMessage() . "\n" . $e->getTraceAsString());
throw new API_Exception(
'A valid original contribution ID is required', 'invalid_data');
}
+ $original_contribution = clone $contribution;
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;
+
+ unset($contribution->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);
+ // Have not set trxn_id to required but an e-notice if not provided seems appropriate.
+ $input['trxn_id'] = $params['trxn_id'];
+
+ $params = _ipn_process_transaction($params, $contribution, $input, $ids, $original_contribution);
}
catch(Exception $e) {
throw new API_Exception('failed to load related objects' . $e->getMessage() . "\n" . $e->getTraceAsString());
*
* @param array $ids
*
+ * @param CRM_Contribute_BAO_Contribution $firstContribution
+ *
* @return mixed
*/
-function _ipn_complete_transaction(&$params, $contribution, $input, $ids) {
+function _ipn_process_transaction(&$params, $contribution, $input, $ids, $firstContribution = NULL) {
$objects = $contribution->_relatedObjects;
$objects['contribution'] = &$contribution;
+
+ if ($firstContribution) {
+ $objects['first_contribution'] = $firstContribution;
+ }
$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'];
);
$params['contribution_status_id'] = array(
'title' => 'Contribution Status ID',
+ 'name' => 'contribution_status_id',
'type' => CRM_Utils_Type::T_INT,
'pseudoconstant' => array(
'optionGroupName' => 'contribution_status',
);
$params['receive_date'] = array(
'title' => 'Contribution Receive Date',
+ 'name' => 'receive_date',
'type' => CRM_Utils_Type::T_DATE,
'api.default' => 'now',
);
+ $params['trxn_id'] = array(
+ 'title' => 'Transaction ID',
+ 'name' => 'trxn_id',
+ 'type' => CRM_Utils_Type::T_STRING,
+ );
+ $params['payment_processor_id'] = array(
+ 'description' => ts('Payment processor ID, will be loaded from contribution_recur if not provided'),
+ 'title' => 'Payment processor ID',
+ 'name' => 'payment_processor_id',
+ 'type' => CRM_Utils_Type::T_INT,
+ );
}
$mut->stop();
}
+ /**
+ * Test repeat contribution successfully creates line items.
+ */
+ function testRepeatTransaction() {
+ $paymentProcessorID = $this->paymentProcessorCreate();
+ $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array(
+ 'contact_id' => $this->_individualId,
+ 'installments' => '12',
+ 'frequency_interval' => '1',
+ 'amount' => '500',
+ 'contribution_status_id' => 1,
+ 'start_date' => '2012-01-01 00:00:00',
+ 'currency' => 'USD',
+ 'frequency_unit' => 'month',
+ 'payment_processor_id' => $paymentProcessorID,
+ ));
+ $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
+ $this->_params,
+ array('contribution_recur_id' => $contributionRecur['id']))
+ );
+
+ $this->callAPISuccess('contribution', 'repeattransaction', array(
+ 'original_contribution_id' => $originalContribution['id'],
+ 'contribution_status_id' => 'Completed',
+ 'trxn_id' => uniqid(),
+ ));
+ $lineItemParams = array(
+ 'entity_id' => $originalContribution['id'],
+ 'sequential' => 1,
+ 'return' => array(
+ 'entity_table',
+ 'qty',
+ 'unit_price',
+ 'line_total',
+ 'label',
+ 'financial_type_id',
+ 'deductible_amount',
+ 'price_field_value_id',
+ 'price_field_id',
+ ),
+ );
+ $lineItem1 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, array(
+ 'entity_id' => $originalContribution['id'],
+ )));
+ $lineItem2 = $this->callAPISuccess('line_item', 'get', array_merge($lineItemParams, array(
+ 'entity_id' => $originalContribution['id'] + 1,
+ )));
+ unset($lineItem1['values'][0]['id'], $lineItem1['values'][0]['entity_id']);
+ unset($lineItem2['values'][0]['id'], $lineItem2['values'][0]['entity_id']);
+ $this->assertEquals($lineItem1['values'][0], $lineItem2['values'][0]);
+
+ $this->quickCleanUpFinancialEntities();
+ }
+
/**
* Test completing a transaction does not 'mess' with net amount (CRM-15960).
*/