(This was in response to discovering e-notices on no $ but was always 'part-of-the-plan'
the form only calls doPayment now. We only have one concession left to it knowing about contributeMode - whether to call PostProcess hook
* @param array $paymentParams
* Array with payment related key.
* value pairs
- * @param array $premiumParams
- * Array with premium related key.
- * value pairs
* @param int $contactID
* Contact id.
* @param int $contributionTypeId
public static function processConfirm(
&$form,
&$paymentParams,
- &$premiumParams,
$contactID,
$contributionTypeId,
$component = 'contribution',
//CRM-11456
$paymentParams['financialType_accounting_code'] = $paymentParams['contributionType_accounting_code'] = $form->_params['contributionType_accounting_code'] = CRM_Financial_BAO_FinancialAccount::getAccountingCode($contributionTypeId);
$paymentParams['contributionPageID'] = $form->_params['contributionPageID'] = $form->_values['id'];
-
- $payment = NULL;
- $paymentObjError = ts('The system did not record payment details for this payment and so could not process the transaction. Please report this error to the site administrator.');
-
- if ($isPaymentTransaction && !empty($form->_paymentProcessor)) {
- // @todo - remove this line once we are sure we can just use $form->_paymentProcessor['object'] consistently.
- $payment = Civi\Payment\System::singleton()->getByProcessor($form->_paymentProcessor);
- }
+ $paymentParams['contactID'] = $form->_params['contactID'] = $contactID;
//fix for CRM-16317
$form->_params['receive_date'] = date('YmdHis');
$form->assign('receive_date',
CRM_Utils_Date::mysqlToIso($form->_params['receive_date'])
);
- $result = NULL;
- if ($form->_contributeMode == 'notify' ||
- $isPayLater
- ) {
- // this is not going to come back, i.e. we fill in the other details
- // when we get a callback from the payment processor
- // also add the contact ID and contribution ID to the params list
- $paymentParams['contactID'] = $form->_params['contactID'] = $contactID;
+ if ($isPaymentTransaction) {
+ // Fix for CRM-14354. If the membership is recurring, don't create a
+ // civicrm_contribution_recur record for the additional contribution
+ // (i.e., the amount NOT associated with the membership). Temporarily
+ // cache the is_recur values so we can process the additional gift as a
+ // one-off payment.
+ if (!empty($form->_values['is_recur'])) {
+ if ($form->_membershipBlock['is_separate_payment'] && !empty($form->_params['auto_renew'])) {
+ $cachedFormValue = CRM_Utils_Array::value('is_recur', $form->_values);
+ $cachedParamValue = CRM_Utils_Array::value('is_recur', $paymentParams);
+ unset($form->_values['is_recur']);
+ unset($paymentParams['is_recur']);
+ }
+ }
$contribution = CRM_Contribute_Form_Contribution_Confirm::processFormContribution(
$form,
$paymentParams,
NULL,
$contactID,
$financialType,
- TRUE, TRUE,
+ TRUE,
+ TRUE,
$isTest,
$lineItems,
$form->_bltID
);
- if ($contribution) {
- $form->_params['contributionID'] = $contribution->id;
- }
-
- $form->_params['contributionTypeID'] = $contributionTypeId;
- $form->_params['item_name'] = $form->_params['description'];
+ $paymentParams['contributionTypeID'] = $contributionTypeId;
+ $paymentParams['item_name'] = $form->_params['description'];
- if ($contribution && $form->_values['is_recur'] &&
- $contribution->contribution_recur_id
+ if ($contribution && $form->_values['is_recur'] && $contribution->contribution_recur_id
) {
- $form->_params['contributionRecurID'] = $contribution->contribution_recur_id;
+ $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id;
}
- $form->set('params', $form->_params);
- $form->postProcessPremium($premiumParams, $contribution);
-
- if ($isPaymentTransaction) {
- // add qfKey so we can send to paypal
- $form->_params['qfKey'] = $form->controller->_key;
- if ($component == 'membership') {
- return array('contribution' => $contribution);
- }
- else {
- if (!$isPayLater) {
- if (is_object($payment)) {
- // call postProcess hook before leaving
- $form->postProcessHook();
- // this does not return
- $result = $payment->doTransferCheckout($form->_params, 'contribute');
- }
- else {
- CRM_Core_Error::fatal($paymentObjError);
- }
- }
- else {
- // follow similar flow as IPN
- // send the receipt mail
- $form->set('params', $form->_params);
- if (isset($paymentParams['contribution_source'])) {
- $form->_params['source'] = $paymentParams['contribution_source'];
- }
-
- // get the price set values for receipt.
- if ($form->_priceSetId && $form->_lineItem) {
- $form->_values['lineItem'] = $form->_lineItem;
- $form->_values['priceSetID'] = $form->_priceSetId;
- }
-
- $form->_values['contribution_id'] = $contribution->id;
- $form->_values['contribution_page_id'] = $contribution->contribution_page_id;
-
- CRM_Contribute_BAO_ContributionPage::sendMail($contactID,
- $form->_values,
- $contribution->is_test
- );
- return;
- }
- }
+ $paymentParams['qfKey'] = $form->controller->_key;
+ if ($component == 'membership') {
+ return array('contribution' => $contribution);
}
- }
- elseif ($isPaymentTransaction && $form->_contributeMode) {
- if ($form->_contributeMode == 'express' && !empty($paymentParams['is_recur']) && $paymentParams['is_recur'] == 1) {
- if (is_object($payment)) {
- $result = $payment->createRecurringPayments($paymentParams);
- }
- else {
- CRM_Core_Error::fatal($paymentObjError);
- }
+ // restore cached values (part of fix for CRM-14354)
+ if (!empty($cachedFormValue)) {
+ $form->_values['is_recur'] = $cachedFormValue;
+ $paymentParams['is_recur'] = $cachedParamValue;
}
- else {
- $paymentParams['contactID'] = $contactID;
-
- // Fix for CRM-14354. If the membership is recurring, don't create a
- // civicrm_contribution_recur record for the additional contribution
- // (i.e., the amount NOT associated with the membership). Temporarily
- // cache the is_recur values so we can process the additional gift as a
- // one-off payment.
- if (!empty($form->_values['is_recur'])) {
- if ($form->_membershipBlock['is_separate_payment'] && !empty($form->_params['auto_renew'])) {
- $cachedFormValue = CRM_Utils_Array::value('is_recur', $form->_values);
- $cachedParamValue = CRM_Utils_Array::value('is_recur', $paymentParams);
- unset($form->_values['is_recur']);
- unset($paymentParams['is_recur']);
- }
- }
-
- $contribution = CRM_Contribute_Form_Contribution_Confirm::processFormContribution(
- $form,
- $paymentParams,
- NULL,
- $contactID,
- $financialType,
- TRUE,
- TRUE,
- $isTest,
- $lineItems,
- $form->_bltID
- );
-
- // restore cached values (part of fix for CRM-14354)
- if (!empty($cachedFormValue)) {
- $form->_values['is_recur'] = $cachedFormValue;
- $paymentParams['is_recur'] = $cachedParamValue;
- }
-
- $paymentParams['contributionID'] = $contribution->id;
- //CRM-15297 deprecate contributionTypeID
- $paymentParams['financialTypeID'] = $paymentParams['contributionTypeID'] = $contribution->financial_type_id;
- $paymentParams['contributionPageID'] = $contribution->contribution_page_id;
- if ($form->_values['is_recur'] && $contribution->contribution_recur_id) {
- $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id;
- }
- }
- try {
- $result = $payment->doPayment($paymentParams);
- }
- catch (\Civi\Payment\Exception\PaymentProcessorException $e) {
- // Clean up DB as appropriate.
- if (!empty($paymentParams['contributionID'])) {
- CRM_Contribute_BAO_Contribution::failPayment($paymentParams['contributionID'],
- $paymentParams['contactID'], $e->getMessage());
- }
- if (!empty($paymentParams['contributionRecurID'])) {
- CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
- }
-
- $result['is_payment_failure'] = TRUE;
- $result['error'] = $e;
- }
- }
-
- if ($result || ($form->_amount == 0.0 && !$form->_params['is_pay_later'])) {
- if ($result) {
- $form->_params = array_merge($form->_params, $result);
+ $paymentParams['contributionID'] = $contribution->id;
+ //CRM-15297 deprecate contributionTypeID
+ $paymentParams['financialTypeID'] = $paymentParams['contributionTypeID'] = $contribution->financial_type_id;
+ $paymentParams['contributionPageID'] = $contribution->contribution_page_id;
+ if (isset($paymentParams['contribution_source'])) {
+ $paymentParams['source'] = $paymentParams['contribution_source'];
}
- $form->set('params', $form->_params);
- $form->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $result));
-
- // result has all the stuff we need
- // lets archive it to a financial transaction
- if (isset($paymentParams['contribution_source'])) {
- $form->_params['source'] = $paymentParams['contribution_source'];
+ if ($form->_values['is_recur'] && $contribution->contribution_recur_id) {
+ $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id;
}
- $form->postProcessPremium($premiumParams, $contribution);
- if (is_array($result)) {
- if (!empty($result['trxn_id'])) {
- $contribution->trxn_id = $result['trxn_id'];
+ if ($form->_contributeMode) {
+ try {
+ $payment = Civi\Payment\System::singleton()->getByProcessor($form->_paymentProcessor);
+ if ($form->_contributeMode == 'notify') {
+ // We want to get rid of this & make it generic - eg. by making payment processing the last thing
+ // and always calling it first.
+ $form->postProcessHook();
+ }
+ $result = $payment->doPayment($paymentParams);
+ $form->_params = array_merge($form->_params, $result);
+ $form->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $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'];
+ }
+ $result['contribution'] = $contribution;
+ return $result;
}
- if (!empty($result['payment_status_id'])) {
- $contribution->payment_status_id = $result['payment_status_id'];
+ catch (\Civi\Payment\Exception\PaymentProcessorException $e) {
+ // Clean up DB as appropriate.
+ if (!empty($paymentParams['contributionID'])) {
+ CRM_Contribute_BAO_Contribution::failPayment($paymentParams['contributionID'],
+ $paymentParams['contactID'], $e->getMessage());
+ }
+ if (!empty($paymentParams['contributionRecurID'])) {
+ CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
+ }
+
+ $result['is_payment_failure'] = TRUE;
+ $result['error'] = $e;
+ return $result;
}
}
- $result['contribution'] = $contribution;
}
- //Do not send an email if Recurring contribution is done via Direct Mode
- //We will send email once the IPN is received.
- if (!$isPayLater) {
- return $result;
+ // Only pay later or unpaid should reach this point. The theory is that paylater should get a receipt now &
+ // processor
+ // transaction receipts should be outcome driven.
+ $form->set('params', $form->_params);
+ if (isset($paymentParams['contribution_source'])) {
+ $form->_params['source'] = $paymentParams['contribution_source'];
}
// get the price set values for receipt.
$form->_values['priceSetID'] = $form->_priceSetId;
}
- // finally send an email receipt
- if ($contribution) {
- $form->_values['contribution_id'] = $contribution->id;
- CRM_Contribute_BAO_ContributionPage::sendMail($contactID,
- $form->_values, $contribution->is_test,
- FALSE, $fieldTypes
- );
- }
+ $form->_values['contribution_id'] = $contribution->id;
+ $form->_values['contribution_page_id'] = $contribution->contribution_page_id;
+
+ CRM_Contribute_BAO_ContributionPage::sendMail($contactID,
+ $form->_values,
+ $contribution->is_test
+ );
+ return;
}
/**
"_qf_Main_display=true&qfKey={$this->_params['qfKey']}"
));
}
+ // Presumably this is for hooks to access? Not quite clear & perhaps not required.
+ $this->set('params', $this->_params);
}
/**
* @param array $premiumParams
* @param CRM_Contribute_BAO_Contribution $contribution
*/
- public function postProcessPremium($premiumParams, $contribution) {
+ protected function postProcessPremium($premiumParams, $contribution) {
$hour = $minute = $second = 0;
// assigning Premium information to receipt tpl
$selectProduct = CRM_Utils_Array::value('selectProduct', $premiumParams);
}
$paymentResult = CRM_Contribute_BAO_Contribution_Utils::processConfirm($form, $membershipParams,
- $premiumParams, $contactID,
+ $contactID,
$financialTypeID,
'membership',
array(),
$errors[1] = CRM_Core_Error::getMessages($paymentResult);
}
elseif (!empty($paymentResult['contribution'])) {
+ $this->postProcessPremium($premiumParams, $paymentResult['contribution']);
//note that this will be over-written if we are using a separate membership transaction. Otherwise there is only one
$membershipContribution = $paymentResult['contribution'];
// Save the contribution ID so that I can be used in email receipts
$financialTypeID = $this->wrangleFinancialTypeID($contributionTypeId);
$result = CRM_Contribute_BAO_Contribution_Utils::processConfirm($this, $paymentParams,
- $premiumParams, $contactID,
+ $contactID,
$financialTypeID,
'contribution',
$fieldTypes,
($this->_mode == 'test') ? 1 : 0,
$isPayLater
);
-
+ // @todo move premium processing to complete transaction if it truly is an 'after' action.
+ $this->postProcessPremium($premiumParams, $result['contribution']);
if (CRM_Utils_Array::value('contribution_status_id', $result) == 1) {
civicrm_api3('contribution', 'completetransaction', array(
'id' => $result['contribution']->id,
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2015
- * $Id$
- *
+ */
+
+/**
+ * Class CRM_Core_Payment_PayPalImpl for paypal pro, paypal standard & paypal express.
*/
class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
const CHARSET = 'iso-8859-1';
protected $_mode = NULL;
- /**
- * We only need one instance of this object. So we use the singleton
- * pattern and cache the instance in this variable
- *
- * @var object
- */
- static private $_singleton = NULL;
-
/**
* Constructor.
*
* the result in an nice formatted array (or an error object)
*/
public function doExpressCheckout(&$params) {
+
+ if (!empty($params['is_recur'])) {
+ return $this->createRecurringPayments($params);
+ }
$args = array();
$this->initialize($args, 'DoExpressCheckoutPayment');
return $membership->count();
}
- /**
- * Process the Memberships.
- *
- * @param array $membershipParams
- * Array of membership fields.
- * @param int $contactID
- * Contact id.
- * @param CRM_Contribute_Form_Contribution_Confirm $form
- * Confirmation form object.
- *
- * @param array $premiumParams
- * @param null $customFieldsFormatted
- * @param null $includeFieldTypes
- *
- * @param array $membershipDetails
- *
- * @param array $membershipTypeIDs
- *
- * @param bool $isPaidMembership
- * @param array $membershipID
- *
- * @param bool $isProcessSeparateMembershipTransaction
- *
- * @param int $financialTypeID
- * @param array $membershipLineItems
- * Line items specific to membership payment that is separate to contribution.
- * @param bool $isPayLater
- * @param bool $isPending
- *
- * @throws \CRM_Core_Exception
- */
- public static function postProcessMembership(
- $membershipParams, $contactID, &$form, $premiumParams,
- $customFieldsFormatted = NULL, $includeFieldTypes = NULL, $membershipDetails, $membershipTypeIDs, $isPaidMembership, $membershipID,
- $isProcessSeparateMembershipTransaction, $financialTypeID, $membershipLineItems, $isPayLater, $isPending) {
- $result = $membershipContribution = NULL;
- $isTest = CRM_Utils_Array::value('is_test', $membershipParams, FALSE);
- $errors = $createdMemberships = $paymentResult = array();
-
- if ($isPaidMembership) {
- if ($isProcessSeparateMembershipTransaction) {
- // If we have 2 transactions only one can use the invoice id.
- $membershipParams['invoiceID'] .= '-2';
- }
-
- $paymentResult = CRM_Contribute_BAO_Contribution_Utils::processConfirm($form, $membershipParams,
- $premiumParams, $contactID,
- $financialTypeID,
- 'membership',
- array(),
- $isTest,
- $isPayLater
- );
- if (is_a($result[1], 'CRM_Core_Error')) {
- $errors[1] = CRM_Core_Error::getMessages($paymentResult[1]);
- }
-
- if (is_a($paymentResult, 'CRM_Core_Error')) {
- $errors[1] = CRM_Core_Error::getMessages($paymentResult);
- }
- elseif (!empty($paymentResult['contribution'])) {
- //note that this will be over-written if we are using a separate membership transaction. Otherwise there is only one
- $membershipContribution = $paymentResult['contribution'];
- // Save the contribution ID so that I can be used in email receipts
- // For example, if you need to generate a tax receipt for the donation only.
- $form->_values['contribution_other_id'] = $membershipContribution->id;
- }
- }
-
- if ($isProcessSeparateMembershipTransaction) {
- try {
- $form->_lineItem = $membershipLineItems;
- if (empty($form->_params['auto_renew']) && !empty($membershipParams['is_recur'])) {
- unset($membershipParams['is_recur']);
- }
- $membershipContribution = self::processSecondaryFinancialTransaction($contactID, $form, $membershipParams, $isTest, $membershipLineItems, CRM_Utils_Array::value('minimum_fee', $membershipDetails, 0), CRM_Utils_Array::value('financial_type_id', $membershipDetails));
- }
- catch (CRM_Core_Exception $e) {
- $errors[2] = $e->getMessage();
- $membershipContribution = NULL;
- }
- }
-
- $membership = NULL;
- if (!empty($membershipContribution) && !is_a($membershipContribution, 'CRM_Core_Error')) {
- $membershipContributionID = $membershipContribution->id;
- }
-
- //@todo - why is this nested so deep? it seems like it could be just set on the calling function on the form layer
- if (isset($membershipParams['onbehalf']) && !empty($membershipParams['onbehalf']['member_campaign_id'])) {
- $form->_params['campaign_id'] = $membershipParams['onbehalf']['member_campaign_id'];
- }
- //@todo it should no longer be possible for it to get to this point & membership to not be an array
- if (is_array($membershipTypeIDs) && !empty($membershipContributionID)) {
- $typesTerms = CRM_Utils_Array::value('types_terms', $membershipParams, array());
- foreach ($membershipTypeIDs as $memType) {
- $numTerms = CRM_Utils_Array::value($memType, $typesTerms, 1);
- if (!empty($membershipContribution)) {
- $pendingStatus = CRM_Core_OptionGroup::getValue('contribution_status', 'Pending', 'name');
- $pending = ($membershipContribution->contribution_status_id == $pendingStatus) ? TRUE : FALSE;
- }
- else {
- $pending = $isPending;
- }
- $contributionRecurID = isset($form->_params['contributionRecurID']) ? $form->_params['contributionRecurID'] : NULL;
-
- $membershipSource = NULL;
- if (!empty($form->_params['membership_source'])) {
- $membershipSource = $form->_params['membership_source'];
- }
- elseif (isset($form->_values['title']) && !empty($form->_values['title'])) {
- $membershipSource = ts('Online Contribution:') . ' ' . $form->_values['title'];
- }
- $isPayLater = NULL;
- if (isset($form->_params)) {
- $isPayLater = CRM_Utils_Array::value('is_pay_later', $form->_params);
- }
- $campaignId = NULL;
- if (isset($form->_values) && is_array($form->_values) && !empty($form->_values)) {
- $campaignId = CRM_Utils_Array::value('campaign_id', $form->_params);
- if (!array_key_exists('campaign_id', $form->_params)) {
- $campaignId = CRM_Utils_Array::value('campaign_id', $form->_values);
- }
- }
-
- list($membership, $renewalMode, $dates) = self::renewMembership(
- $contactID, $memType, $isTest,
- date('YmdHis'), CRM_Utils_Array::value('cms_contactID', $membershipParams),
- $customFieldsFormatted,
- $numTerms, $membershipID, $pending,
- $contributionRecurID, $membershipSource, $isPayLater, $campaignId
- );
- $form->set('renewal_mode', $renewalMode);
- if (!empty($dates)) {
- $form->assign('mem_start_date',
- CRM_Utils_Date::customFormat($dates['start_date'], '%Y%m%d')
- );
- $form->assign('mem_end_date',
- CRM_Utils_Date::customFormat($dates['end_date'], '%Y%m%d')
- );
- }
-
- if (!empty($membershipContribution)) {
- // update recurring id for membership record
- self::updateRecurMembership($membership, $membershipContribution);
- self::linkMembershipPayment($membership, $membershipContribution);
- }
- }
- if ($form->_priceSetId && !empty($form->_useForMember) && !empty($form->_lineItem)) {
- foreach ($form->_lineItem[$form->_priceSetId] as & $priceFieldOp) {
- if (!empty($priceFieldOp['membership_type_id']) &&
- isset($createdMemberships[$priceFieldOp['membership_type_id']])
- ) {
- $membershipOb = $createdMemberships[$priceFieldOp['membership_type_id']];
- $priceFieldOp['start_date'] = $membershipOb->start_date ? CRM_Utils_Date::customFormat($membershipOb->start_date, '%B %E%f, %Y') : '-';
- $priceFieldOp['end_date'] = $membershipOb->end_date ? CRM_Utils_Date::customFormat($membershipOb->end_date, '%B %E%f, %Y') : '-';
- }
- else {
- $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A';
- }
- }
- $form->_values['lineItem'] = $form->_lineItem;
- $form->assign('lineItem', $form->_lineItem);
- }
- }
-
- if (!empty($errors)) {
- $message = self::compileErrorMessage($errors);
- throw new CRM_Core_Exception($message);
- }
- $form->_params['createdMembershipIDs'] = array();
-
- // CRM-7851 - Moved after processing Payment Errors
- //@todo - the reasoning for this being here seems a little outdated
- foreach ($createdMemberships as $createdMembership) {
- CRM_Core_BAO_CustomValueTable::postProcess(
- $form->_params,
- 'civicrm_membership',
- $createdMembership->id,
- 'Membership'
- );
- $form->_params['createdMembershipIDs'][] = $createdMembership->id;
- }
- if (count($createdMemberships) == 1) {
- //presumably this is only relevant for exactly 1 membership
- $form->_params['membershipID'] = $createdMembership->id;
- }
-
- //CRM-15232: Check if membership is created and on the basis of it use
- //membership receipt template to send payment receipt
- if (count($createdMemberships)) {
- $form->_values['isMembership'] = TRUE;
- }
- if ($form->_contributeMode == 'notify') {
- if ($form->_values['is_monetary'] && $form->_amount > 0.0 && !$form->_params['is_pay_later']) {
- // call postProcess hook before leaving
- $form->postProcessHook();
- // this does not return
- $payment = $form->_paymentProcessor['object'];
- $payment->doTransferCheckout($form->_params, 'contribute');
- }
- }
-
- if (isset($membershipContributionID)) {
- $form->_values['contribution_id'] = $membershipContributionID;
- }
-
- if ($form->_contributeMode == 'direct') {
- if (CRM_Utils_Array::value('payment_status_id', $paymentResult) == 1) {
- // Refer to CRM-16737. Payment processors 'should' return payment_status_id
- // to denote the outcome of the transaction.
- try {
- civicrm_api3('contribution', 'completetransaction', array(
- 'id' => $paymentResult['contribution']->id,
- 'trxn_id' => $paymentResult['contribution']->trxn_id,
- 'is_transactional' => FALSE,
- ));
- }
- catch (CiviCRM_API3_Exception $e) {
- // if for any reason it is already completed this will fail - e.g extensions hacking around core not completing transactions prior to CRM-15296
- // so let's be gentle here
- CRM_Core_Error::debug_log_message('contribution ' . $membershipContribution->id . ' not completed with trxn_id ' . $membershipContribution->trxn_id . ' and message ' . $e->getMessage());
- }
- }
- // Do not send an email if Recurring transaction is done via Direct Mode
- // Email will we sent when the IPN is received.
- return;
- }
-
- //finally send an email receipt
- CRM_Contribute_BAO_ContributionPage::sendMail($contactID,
- $form->_values,
- $isTest, FALSE,
- $includeFieldTypes
- );
- }
-
/**
* Function for updating a membership record's contribution_recur_id.
*