From: Eileen McNaughton Date: Fri, 10 Jul 2015 04:59:42 +0000 (+1200) Subject: Merge branch '4.6' of https://github.com/civicrm/civicrm-core X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=8bef2e38f2acd7e60b2ca397f91ea0da373f6db6;p=civicrm-core.git Merge branch '4.6' of https://github.com/civicrm/civicrm-core Conflicts: CRM/Contribute/Form/Contribution.php CRM/Member/BAO/Membership.php CRM/Member/Form.php CRM/Member/Form/MembershipRenewal.php tests/phpunit/api/v3/ContributionPageTest.php --- 8bef2e38f2acd7e60b2ca397f91ea0da373f6db6 diff --cc CRM/Contribute/BAO/Contribution/Utils.php index 5f8a9e2ef1,174e122181..503480b808 --- a/CRM/Contribute/BAO/Contribution/Utils.php +++ b/CRM/Contribute/BAO/Contribution/Utils.php @@@ -283,16 -315,40 +283,21 @@@ class CRM_Contribute_BAO_Contribution_U $form->_params['source'] = $paymentParams['contribution_source']; } - // check if pending was set to true by payment processor - $pending = FALSE; - if (!empty($form->_params['contribution_status_pending'])) { - $pending = TRUE; - } - if (!(!empty($paymentParams['is_recur']) && $form->_contributeMode == 'direct')) { - $contribution = CRM_Contribute_Form_Contribution_Confirm::processContribution($form, - $form->_params, $result, - $contactID, $contributionType, - $pending, TRUE, - $isTest, - $lineItems - ); - } $form->postProcessPremium($premiumParams, $contribution); - if (is_array($result) && !empty($result['trxn_id'])) { - $contribution->trxn_id = $result['trxn_id']; + if (is_array($result)) { + if (!empty($result['trxn_id'])) { + $contribution->trxn_id = $result['trxn_id']; + } + if (!empty($result['payment_status_id'])) { + $contribution->payment_status_id = $result['payment_status_id']; + } } - $membershipResult[1] = $contribution; + $result['contribution'] = $contribution; } - - if ($component == 'membership') { - return $membershipResult; - } - //Do not send an email if Recurring contribution is done via Direct Mode //We will send email once the IPN is received. - if (!empty($paymentParams['is_recur']) && $form->_contributeMode == 'direct') { - return TRUE; + if ($form->_contributeMode == 'direct') { + return $result; } // get the price set values for receipt. diff --cc CRM/Contribute/Form/Contribution.php index 812ec435ce,9476ac6433..bf323fc4b9 --- a/CRM/Contribute/Form/Contribution.php +++ b/CRM/Contribute/Form/Contribution.php @@@ -1313,523 -1876,4 +1313,521 @@@ class CRM_Contribute_Form_Contribution } } + /** + * Wrapper for unit testing the post process submit function. + * + * (If we expose through api we can get default additions 'for free'). + * + * @param array $params + * @param int $action + * @param string|null $creditCardMode + * + * @throws \CiviCRM_API3_Exception + */ + public function testSubmit($params, $action, $creditCardMode = NULL) { + $defaults = array( + 'soft_credit_contact_id' => array(), + 'receipt_date' => '', + 'receipt_date_time' => '', + 'cancel_date' => '', + 'cancel_date_time' => '', + 'hidden_Premium' => 1, + ); + $this->_bltID = 5; + if (!empty($params['id'])) { + $existingContribution = civicrm_api3('contribution', 'getsingle', array( + 'id' => $params['id'], + )); + $this->_id = $params['id']; + } + else { + $existingContribution = array(); + } + + $this->_defaults['contribution_status_id'] = CRM_Utils_Array::value('contribution_status_id', + $existingContribution + ); + + $this->_defaults['total_amount'] = CRM_Utils_Array::value('total_amount', + $existingContribution + ); + + if ($creditCardMode) { + $this->_mode = $creditCardMode; + } + + // Required because processCreditCard calls set method on this. + $_SERVER['REQUEST_METHOD'] = 'GET'; + $this->controller = new CRM_Core_Controller(); + + CRM_Contribute_Form_AdditionalInfo::buildPremium($this); + + $this->_fields = array(); + $this->submit(array_merge($defaults, $params), $action, CRM_Utils_Array::value('pledge_payment_id', $params)); + + } + + /** + * @param array $submittedValues + * + * @param int $action + * Action constant + * - CRM_Core_Action::UPDATE + * + * @param $pledgePaymentID + * + * @return array + * @throws \Exception + */ + protected function submit($submittedValues, $action, $pledgePaymentID) { + $softParams = $softIDs = array(); + $pId = $contribution = $isRelatedId = FALSE; + + if (!empty($submittedValues['price_set_id']) && $action & CRM_Core_Action::UPDATE) { + $line = CRM_Price_BAO_LineItem::getLineItems($this->_id, 'contribution'); + $lineID = key($line); + $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', CRM_Utils_Array::value('price_field_id', $line[$lineID]), 'price_set_id'); + $quickConfig = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $priceSetId, 'is_quick_config'); + if ($quickConfig) { + CRM_Price_BAO_LineItem::deleteLineItems($this->_id, 'civicrm_contribution'); + } + } + + // Process price set and get total amount and line items. + $lineItem = array(); + $priceSetId = CRM_Utils_Array::value('price_set_id', $submittedValues); + if (empty($priceSetId) && !$this->_id) { + $this->_priceSetId = $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', 'default_contribution_amount', 'id', 'name'); + $this->_priceSet = current(CRM_Price_BAO_PriceSet::getSetDetail($priceSetId)); + $fieldID = key($this->_priceSet['fields']); + $fieldValueId = key($this->_priceSet['fields'][$fieldID]['options']); + $this->_priceSet['fields'][$fieldID]['options'][$fieldValueId]['amount'] = $submittedValues['total_amount']; + $submittedValues['price_' . $fieldID] = 1; + } + + if ($priceSetId) { + CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'], + $submittedValues, $lineItem[$priceSetId]); + + // Unset tax amount for offline 'is_quick_config' contribution. + if ($this->_priceSet['is_quick_config'] && + !array_key_exists($submittedValues['financial_type_id'], CRM_Core_PseudoConstant::getTaxRates()) + ) { + unset($submittedValues['tax_amount']); + } + $submittedValues['total_amount'] = CRM_Utils_Array::value('amount', $submittedValues); + } + if ($this->_id) { + if ($this->_compId) { + if ($this->_context == 'participant') { + $pId = $this->_compId; + } + elseif ($this->_context == 'membership') { + $isRelatedId = TRUE; + } + else { + $pId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $this->_id, 'participant_id', 'contribution_id'); + } + } + else { + $contributionDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($this->_id); + if (array_key_exists('membership', $contributionDetails)) { + $isRelatedId = TRUE; + } + elseif (array_key_exists('participant', $contributionDetails)) { + $pId = $contributionDetails['participant']; + } + } + } + if (!$priceSetId && !empty($submittedValues['total_amount']) && $this->_id) { + // CRM-10117 update the line items for participants. + if ($pId) { + $entityTable = 'participant'; + $entityID = $pId; + $isRelatedId = FALSE; + $participantParams = array( + 'fee_amount' => $submittedValues['total_amount'], + 'id' => $entityID, + ); + CRM_Event_BAO_Participant::add($participantParams); + if (empty($this->_lineItems)) { + $this->_lineItems[] = CRM_Price_BAO_LineItem::getLineItems($entityID, 'participant', 1); + } + } + else { + $entityTable = 'contribution'; + $entityID = $this->_id; + } + + $lineItems = CRM_Price_BAO_LineItem::getLineItems($entityID, $entityTable, NULL, TRUE, $isRelatedId); + foreach (array_keys($lineItems) as $id) { + $lineItems[$id]['id'] = $id; + } + $itemId = key($lineItems); + if ($itemId && !empty($lineItems[$itemId]['price_field_id'])) { + $this->_priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'price_set_id'); + } + + if ($this->_priceSetId && CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config')) { + $lineItems[$itemId]['unit_price'] = $lineItems[$itemId]['line_total'] = CRM_Utils_Rule::cleanMoney(CRM_Utils_Array::value('total_amount', $submittedValues)); + + // Update line total and total amount with tax on edit. + $financialItemsId = CRM_Core_PseudoConstant::getTaxRates(); + if (array_key_exists($submittedValues['financial_type_id'], $financialItemsId)) { + $lineItems[$itemId]['tax_rate'] = $financialItemsId[$submittedValues['financial_type_id']]; + } + else { + $lineItems[$itemId]['tax_rate'] = $lineItems[$itemId]['tax_amount'] = ""; + $submittedValues['tax_amount'] = 'null'; + } + if ($lineItems[$itemId]['tax_rate']) { + $lineItems[$itemId]['tax_amount'] = ($lineItems[$itemId]['tax_rate'] / 100) * $lineItems[$itemId]['line_total']; + $submittedValues['total_amount'] = $lineItems[$itemId]['line_total'] + $lineItems[$itemId]['tax_amount']; + $submittedValues['tax_amount'] = $lineItems[$itemId]['tax_amount']; + } + } + // CRM-10117 update the line items for participants. + if (!empty($lineItems[$itemId]['price_field_id'])) { + $lineItem[$this->_priceSetId] = $lineItems; + } + } + + $isQuickConfig = 0; + if ($this->_priceSetId && CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config')) { + $isQuickConfig = 1; + } + //CRM-11529 for quick config back office transactions + //when financial_type_id is passed in form, update the + //line items with the financial type selected in form + if ($isQuickConfig && !empty($submittedValues['financial_type_id']) && CRM_Utils_Array::value($this->_priceSetId, $lineItem) + ) { + foreach ($lineItem[$this->_priceSetId] as &$values) { + $values['financial_type_id'] = $submittedValues['financial_type_id']; + } + } + + if (!isset($submittedValues['total_amount'])) { + $submittedValues['total_amount'] = CRM_Utils_Array::value('total_amount', $this->_values); + } + $this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ? $lineItem : FALSE); + + if (!empty($submittedValues['pcp_made_through_id'])) { + $pcp = array(); + $fields = array( + 'pcp_made_through_id', + 'pcp_display_in_roll', + 'pcp_roll_nickname', + 'pcp_personal_note', + ); + foreach ($fields as $f) { + $pcp[$f] = CRM_Utils_Array::value($f, $submittedValues); + } + } + + $isEmpty = array_keys(array_flip($submittedValues['soft_credit_contact_id'])); + if ($this->_id && count($isEmpty) == 1 && key($isEmpty) == NULL) { + //Delete existing soft credit records if soft credit list is empty on update + CRM_Contribute_BAO_ContributionSoft::del(array('contribution_id' => $this->_id)); + } + else { + //build soft credit params + foreach ($submittedValues['soft_credit_contact_id'] as $key => $val) { + if ($val && $submittedValues['soft_credit_amount'][$key]) { + $softParams[$key]['contact_id'] = $val; + $softParams[$key]['amount'] = CRM_Utils_Rule::cleanMoney($submittedValues['soft_credit_amount'][$key]); + $softParams[$key]['soft_credit_type_id'] = $submittedValues['soft_credit_type'][$key]; + if (!empty($submittedValues['soft_credit_id'][$key])) { + $softIDs[] = $softParams[$key]['id'] = $submittedValues['soft_credit_id'][$key]; + } + } + } + } + + // set the contact, when contact is selected + if (!empty($submittedValues['contact_id'])) { + $this->_contactID = $submittedValues['contact_id']; + } + $formValues = $submittedValues; + + // Credit Card Contribution. + if ($this->_mode) { + $paramsSetByPaymentProcessingSubsystem = array( + 'trxn_id', + 'payment_instrument_id', + 'contribution_status_id', + 'cancel_date', + 'cancel_reason', + ); + foreach ($paramsSetByPaymentProcessingSubsystem as $key) { + if (isset($formValues[$key])) { + unset($formValues[$key]); + } + } + $contribution = $this->processCreditCard($formValues, $lineItem, $this->_contactID); + foreach ($paramsSetByPaymentProcessingSubsystem as $key) { + $formValues[$key] = $contribution->$key; + } + } + else { + // Offline Contribution. + $submittedValues = $this->unsetCreditCardFields($submittedValues); + + // get the required field value only. + + $params = $ids = array(); + + $params['contact_id'] = $this->_contactID; + $params['currency'] = $this->getCurrency($submittedValues); + + $fields = array( + 'financial_type_id', + 'contribution_status_id', + 'payment_instrument_id', + 'cancel_reason', + 'source', + 'check_number', + ); + foreach ($fields as $f) { + $params[$f] = CRM_Utils_Array::value($f, $formValues); + } + + if (!empty($pcp)) { + $params['pcp'] = $pcp; + } - if (!empty($softParams)) { - $params['soft_credit'] = $softParams; - $params['soft_credit_ids'] = $softIDs; - } ++ $params['soft_credit'] = !empty($softParams) ? $softParams : array(); ++ $params['soft_credit_ids'] = !empty($softIDs) ? $softIDs : array(); + + // CRM-5740 if priceset is used, no need to cleanup money. + if ($priceSetId) { + $params['skipCleanMoney'] = 1; + } + + $dates = array( + 'receive_date', + 'receipt_date', + 'cancel_date', + ); + + foreach ($dates as $d) { + $params[$d] = CRM_Utils_Date::processDate($formValues[$d], $formValues[$d . '_time'], TRUE); + } + + if (!empty($formValues['is_email_receipt'])) { + $params['receipt_date'] = date("Y-m-d"); + } + + if ($params['contribution_status_id'] == CRM_Core_OptionGroup::getValue('contribution_status', 'Cancelled', 'name') + || $params['contribution_status_id'] == CRM_Core_OptionGroup::getValue('contribution_status', 'Refunded', 'name') + ) { + if (CRM_Utils_System::isNull(CRM_Utils_Array::value('cancel_date', $params))) { + $params['cancel_date'] = date('Y-m-d'); + } + } + else { + $params['cancel_date'] = $params['cancel_reason'] = 'null'; + } + + // Set is_pay_later flag for back-office offline Pending status contributions CRM-8996 + // else if contribution_status is changed to Completed is_pay_later flag is changed to 0, CRM-15041 + if ($params['contribution_status_id'] == CRM_Core_OptionGroup::getValue('contribution_status', 'Pending', 'name')) { + $params['is_pay_later'] = 1; + } + elseif ($params['contribution_status_id'] == CRM_Core_OptionGroup::getValue('contribution_status', 'Completed', 'name')) { + $params['is_pay_later'] = 0; + } + + $ids['contribution'] = $params['id'] = $this->_id; + + // Add Additional common information to formatted params. + CRM_Contribute_Form_AdditionalInfo::postProcessCommon($formValues, $params, $this); + if ($pId) { + $params['contribution_mode'] = 'participant'; + $params['participant_id'] = $pId; + $params['skipLineItem'] = 1; + } + elseif ($isRelatedId) { + $params['contribution_mode'] = 'membership'; + } + $params['line_item'] = $lineItem; + $params['payment_processor_id'] = $params['payment_processor'] = CRM_Utils_Array::value('id', $this->_paymentProcessor); + if (isset($submittedValues['tax_amount'])) { + $params['tax_amount'] = $submittedValues['tax_amount']; + } + //create contribution. + if ($isQuickConfig) { + $params['is_quick_config'] = 1; + } + $params['non_deductible_amount'] = $this->calculateNonDeductibleAmount($params, $formValues); + + $contribution = CRM_Contribute_BAO_Contribution::create($params, $ids); + + // process associated membership / participant, CRM-4395 + if ($contribution->id && $action & CRM_Core_Action::UPDATE) { + $this->statusMessage[] = $this->updateRelatedComponent($contribution->id, + $contribution->contribution_status_id, + CRM_Utils_Array::value('contribution_status_id', + $this->_values + ), + $contribution->receive_date + ); + } + + array_unshift($this->statusMessage, ts('The contribution record has been saved.')); + + $this->invoicingPostProcessHook($submittedValues, $action, $lineItem); + + //send receipt mail. + if ($contribution->id && !empty($formValues['is_email_receipt'])) { + $formValues['contact_id'] = $this->_contactID; + $formValues['contribution_id'] = $contribution->id; + + $formValues += CRM_Contribute_BAO_ContributionSoft::getSoftContribution($contribution->id); + + // to get 'from email id' for send receipt + $this->fromEmailId = $formValues['from_email_address']; + if (CRM_Contribute_Form_AdditionalInfo::emailReceipt($this, $formValues)) { + $this->statusMessage[] = ts('A receipt has been emailed to the contributor.'); + } + } + + $this->statusMessageTitle = ts('Saved'); + + } + + if ($contribution->id && !empty($formValues['product_name'][0])) { + CRM_Contribute_Form_AdditionalInfo::processPremium($submittedValues, $contribution->id, + $this->_premiumID, $this->_options + ); + } + + if ($contribution->id && isset($submittedValues['note'])) { + CRM_Contribute_Form_AdditionalInfo::processNote($submittedValues, $this->_contactID, $contribution->id, $this->_noteID); + } + + CRM_Core_Session::setStatus(implode(' ', $this->statusMessage), $this->statusMessageTitle, 'success'); + + CRM_Contribute_BAO_Contribution::updateRelatedPledge( + $action, + $pledgePaymentID, + $contribution->id, + (CRM_Utils_Array::value('option_type', $formValues) == 2) ? TRUE : FALSE, + $formValues['total_amount'], + CRM_Utils_Array::value('total_amount', $this->_defaults), + $formValues['contribution_status_id'], + CRM_Utils_Array::value('contribution_status_id', $this->_defaults) + ); + return $contribution; + } + + /** + * Assign tax calculations to contribution receipts. + * + * @param array $submittedValues + * @param int $action + * @param array $lineItem + */ + protected function invoicingPostProcessHook($submittedValues, $action, $lineItem) { + + $invoiceSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings'); + if (!CRM_Utils_Array::value('invoicing', $invoiceSettings)) { + return; + } + $taxRate = array(); + $getTaxDetails = FALSE; + if ($action & CRM_Core_Action::ADD) { + $line = $lineItem; + } + elseif ($action & CRM_Core_Action::UPDATE) { + $line = $this->_lineItems; + } + foreach ($line as $key => $value) { + foreach ($value as $v) { + if (isset($taxRate[(string) CRM_Utils_Array::value('tax_rate', $v)])) { + $taxRate[(string) $v['tax_rate']] = $taxRate[(string) $v['tax_rate']] + CRM_Utils_Array::value('tax_amount', $v); + } + else { + if (isset($v['tax_rate'])) { + $taxRate[(string) $v['tax_rate']] = CRM_Utils_Array::value('tax_amount', $v); + $getTaxDetails = TRUE; + } + } + } + } + + if ($action & CRM_Core_Action::UPDATE) { + if (isset($submittedValues['tax_amount'])) { + $totalTaxAmount = $submittedValues['tax_amount']; + } + else { + $totalTaxAmount = $this->_values['tax_amount']; + } + $this->assign('totalTaxAmount', $totalTaxAmount); + $this->assign('dataArray', $taxRate); + } + else { + if (!empty($submittedValues['price_set_id'])) { + $this->assign('totalTaxAmount', $submittedValues['tax_amount']); + $this->assign('getTaxDetails', $getTaxDetails); + $this->assign('dataArray', $taxRate); + $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings)); + } + else { + $this->assign('totalTaxAmount', CRM_Utils_Array::value('tax_amount', $submittedValues)); + } + } + } + + /** + * Calculate non deductible amount. + * + * CRM-11956 + * if non_deductible_amount exists i.e. Additional Details field set was opened [and staff typed something] - + * if non_deductible_amount does NOT exist - then calculate it depending on: + * $financialType->is_deductible and whether there is a product (premium). + * + * @param $params + * @param $formValues + * + * @return array + */ + protected function calculateNonDeductibleAmount($params, $formValues) { + if (!empty($params['non_deductible_amount'])) { + return $params['non_deductible_amount']; + } + if (empty($params['non_deductible_amount'])) { + $contributionType = new CRM_Financial_DAO_FinancialType(); + $contributionType->id = $params['financial_type_id']; + + if ($contributionType->is_deductible) { + + if (isset($formValues['product_name'][0])) { + $selectProduct = $formValues['product_name'][0]; + } + // if there is a product - compare the value to the contribution amount + if (isset($selectProduct)) { + $productDAO = new CRM_Contribute_DAO_Product(); + $productDAO->id = $selectProduct; + $productDAO->find(TRUE); + // product value exceeds contribution amount + if ($params['total_amount'] < $productDAO->price) { + return $params['total_amount']; + } + // product value does NOT exceed contribution amount + else { + return $productDAO->price; + } + } + // contribution is deductible - but there is no product + else { + return '0.00'; + } + } + // contribution is NOT deductible + else { + return $params['total_amount']; + } + } + return 0; + } + } diff --cc CRM/Member/BAO/Membership.php index 6115e4b845,31e293d5e5..9c67bf3f05 --- a/CRM/Member/BAO/Membership.php +++ b/CRM/Member/BAO/Membership.php @@@ -1307,13 -1449,20 +1307,20 @@@ AND civicrm_membership.is_test = %2" $form->_values['contribution_id'] = $membershipContributionID; } - if ($form->_contributeMode == 'direct') { - if (CRM_Utils_Array::value('contribution_status_id', $paymentResult) == 1) { + // Refer to CRM-16737. Payment processors 'should' return payment_status_id + // to denote the outcome of the transaction. + // + // In 4.7 trxn_id will no longer denote the outcome & all processor transactions must return an array + // containing payment_status_id. + // In 4.6 support (such as there was) for other ways of denoting payment outcome is retained but the use + // of payment_status_id is strongly encouraged. + if (!empty($form->_params['is_recur']) && $form->_contributeMode == 'direct') { - if (!empty($membershipContribution->trxn_id) && !isset($membershipContribution->payment_status_id) - || (!empty($membershipContribution->payment_status_id) && $membershipContribution->payment_status_id == 1)) { ++ if (!isset($membershipContribution->payment_status_id) && $membershipContribution->payment_status_id == 1) { try { civicrm_api3('contribution', 'completetransaction', array( - 'id' => $membershipContribution->id, - 'trxn_id' => $membershipContribution->trxn_id, + 'id' => $paymentResult['contribution']->id, + 'trxn_id' => $paymentResult['contribution']->trxn_id, + 'is_transactional' => FALSE, )); } catch (CiviCRM_API3_Exception $e) { diff --cc CRM/Member/Form.php index 808cba5611,6bdd3c62e8..0c86ccfb6f --- a/CRM/Member/Form.php +++ b/CRM/Member/Form.php @@@ -263,29 -223,50 +263,75 @@@ class CRM_Member_Form extends CRM_Contr } } + protected function setContextVariables($params) { + $variables = array( + 'action' => '_action', + 'context' => '_context', + 'id' => '_id', + 'cid' => '_contactID', + 'mode' => '_mode', + ); + foreach ($variables as $paramKey => $classVar) { + if (isset($params[$paramKey]) && !isset($this->$classVar)) { + $this->$classVar = $params[$paramKey]; + } + } + + if ($this->_mode) { + $this->assignPaymentRelatedVariables(); + } + + if ($this->_id) { + $this->_memType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_id, 'membership_type_id'); + $this->_membershipIDs[] = $this->_id; + } + $this->_fromEmails = CRM_Core_BAO_Email::getFromEmail(); + } + + /** + * Create a recurring contribution record. + * + * Recurring contribution parameters are set explicitly rather than merging paymentParams because it's hard + * to know the downstream impacts if we keep passing around the same array. + * + * @param $paymentParams + * + * @return array + * @throws \CiviCRM_API3_Exception + */ + protected function processRecurringContribution($paymentParams) { + $membershipID = $paymentParams['membership_type_id'][1]; + $contributionRecurParams = array( + 'contact_id' => $paymentParams['contactID'], + 'amount' => $paymentParams['total_amount'], + 'payment_processor_id' => $paymentParams['payment_processor_id'], + 'campaign_id' => CRM_Utils_Array::value('campaign_id', $paymentParams), + 'financial_type_id' => $paymentParams['financial_type_id'], + 'is_email_receipt' => CRM_Utils_Array::value('is_email_receipt', $paymentParams), + // This is not great as it could also be direct debit - but is consistent with elsewhere & all need fixing. + 'payment_instrument_id' => 1, + 'invoice_id' => CRM_Utils_Array::value('invoiceID ', $paymentParams), + ); + + $mapping = array( + 'frequency_interval' => 'duration_interval', + 'frequency_unit' => 'duration_unit', + ); + $membershipType = civicrm_api3('MembershipType', 'getsingle', array( + 'id' => $membershipID, + 'return' => $mapping, + )); + + foreach ($mapping as $recurringFieldName => $membershipTypeFieldName) { + $contributionRecurParams[$recurringFieldName] = $membershipType[$membershipTypeFieldName]; + } + + $contributionRecur = civicrm_api3('ContributionRecur', 'create', $contributionRecurParams); + $returnParams = array( + 'contributionRecurID' => $contributionRecur['id'], + 'is_recur' => TRUE, + ); + return $returnParams; + } + } diff --cc CRM/Member/Form/MembershipRenewal.php index 20f52c1590,7a1c5c7a8e..bd812c5b9e --- a/CRM/Member/Form/MembershipRenewal.php +++ b/CRM/Member/Form/MembershipRenewal.php @@@ -559,8 -580,9 +559,8 @@@ class CRM_Member_Form_MembershipRenewa $this->_params['description'] = ts('Office Credit Card Membership Renewal Contribution'); $this->_params['ip_address'] = CRM_Utils_System::ipAddress(); $this->_params['amount'] = $formValues['total_amount']; - $this->_params['currencyID'] = $config->defaultCurrency; - $this->_params['payment_action'] = 'Sale'; + $this->_params['currencyID'] = CRM_Core_Config::singleton()->defaultCurrency; - $this->_params['invoiceID'] = md5(uniqid(rand(), TRUE)); + $paymentParams['invoiceID'] = $this->_params['invoiceID'] = md5(uniqid(rand(), TRUE)); // at this point we've created a contact and stored its address etc // all the payment processors expect the name and address to be in the passed params @@@ -576,7 -598,11 +576,11 @@@ $payment = CRM_Core_Payment::singleton($this->_mode, $this->_paymentProcessor, $this); + if (!empty($paymentParams['auto_renew'])) { + $contributionRecurParams = $this->processRecurringContribution($paymentParams); + $paymentParams = array_merge($paymentParams, $contributionRecurParams); + } - $result = &$payment->doDirectPayment($paymentParams); + $result = $payment->doDirectPayment($paymentParams); if (is_a($result, 'CRM_Core_Error')) { CRM_Core_Error::displaySessionError($result); diff --cc tests/phpunit/api/v3/ContributionPageTest.php index d2d1dfa926,c42bc70703..96e8225415 --- a/tests/phpunit/api/v3/ContributionPageTest.php +++ b/tests/phpunit/api/v3/ContributionPageTest.php @@@ -299,13 -328,13 +299,13 @@@ class api_v3_ContributionPageTest exten * - the first creates a new membership, completed contribution, in progress recurring. Check these * - create another - end date should be extended */ - public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurNow() { - public function testLegacySubmitMembershipPriceSetPaymentPaymentProcessorRecur() { ++ public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPayment() { $this->params['is_recur'] = 1; $var = array(); $this->params['recur_frequency_unit'] = 'month'; $this->setUpMembershipContributionPage(); - $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor); - $dummyPP->setDoDirectPaymentResult(array('contribution_status_id' => 1, 'trxn_id' => 'create_first_success')); + $dummyPP = CRM_Core_Payment::singleton('live', $this->_paymentProcessor); - $dummyPP->setDoDirectPaymentResult(array('contribution_status_id' => 1, 'trxn_id' => 'create_first_success')); ++ $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_first_success')); $submitParams = array( 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']), @@@ -341,7 -370,7 +341,7 @@@ //$this->callAPISuccess('line_item', 'getsingle', array('contribution_id' => $contribution['id'], 'entity_id' => $membership['id'])); //renew it with processor setting completed - should extend membership $submitParams['contact_id'] = $contribution['contact_id']; -- $dummyPP->setDoDirectPaymentResult(array('contribution_status_id' => 1, 'trxn_id' => 'create_second_success')); ++ $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_second_success')); $this->callAPISuccess('contribution_page', 'submit', $submitParams); $this->callAPISuccess('contribution', 'getsingle', array( 'id' => array('NOT IN' => array($contribution['id'])), @@@ -366,8 -395,8 +366,8 @@@ $this->params['is_recur'] = 1; $this->params['recur_frequency_unit'] = 'month'; $this->setUpMembershipContributionPage(); - $dummyPP = CRM_Core_Payment::singleton('live', $this->_paymentProcessor); + $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor); - $dummyPP->setDoDirectPaymentResult(array('contribution_status_id' => 2)); + $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 2)); $submitParams = array( 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),