diff --git a/CRM/Contribute/Form/AdditionalPayment.php b/CRM/Contribute/Form/AdditionalPayment.php index 16c6ba562b36..6491a8248e33 100644 --- a/CRM/Contribute/Form/AdditionalPayment.php +++ b/CRM/Contribute/Form/AdditionalPayment.php @@ -110,11 +110,11 @@ public function preProcess() { $this->_amtTotal = $paymentDetails['total']; if (!empty($paymentInfo['refund_due'])) { - $paymentAmt = $this->_refund = $paymentInfo['refund_due']; + $this->paymentAmount = $this->_refund = $paymentInfo['refund_due']; $this->_paymentType = 'refund'; } elseif (!empty($paymentInfo['amount_owed'])) { - $paymentAmt = $this->_owed = $paymentInfo['amount_owed']; + $this->paymentAmount = $this->_owed = $paymentInfo['amount_owed']; $this->_paymentType = 'owed'; } else { @@ -130,7 +130,7 @@ public function preProcess() { $this->assign('contributionMode', $this->_mode); $this->assign('contactId', $this->_contactID); $this->assign('paymentType', $this->_paymentType); - $this->assign('paymentAmt', abs($paymentAmt)); + $this->assign('paymentAmt', abs($this->paymentAmount)); $this->setPageTitle($this->_refund ? ts('Refund') : ts('Payment')); } @@ -336,20 +336,6 @@ public function submit($submittedValues) { if ($this->_component == 'event') { $participantId = $this->_id; } - $contributionStatuses = CRM_Core_PseudoConstant::get('CRM_Contribute_DAO_Contribution', - 'contribution_status_id', - array('labelColumn' => 'name') - ); - $contributionStatusID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $this->_contributionId, 'contribution_status_id'); - if ($contributionStatuses[$contributionStatusID] == 'Pending') { - civicrm_api3('Contribution', 'create', - array( - 'id' => $this->_contributionId, - 'contribution_status_id' => array_search('Partially paid', $contributionStatuses), - 'is_pay_later' => 0, - ) - ); - } if ($this->_mode) { // process credit card @@ -357,17 +343,13 @@ public function submit($submittedValues) { $this->processCreditCard(); } - $defaults = array(); - $contribution = civicrm_api3('Contribution', 'getsingle', array( - 'return' => array("contribution_status_id"), - 'id' => $this->_contributionId, - )); - $contributionStatusId = CRM_Utils_Array::value('contribution_status_id', $contribution); - $result = CRM_Contribute_BAO_Contribution::recordAdditionalPayment($this->_contributionId, $this->_params, $this->_paymentType, $participantId); - // Fetch the contribution & do proportional line item assignment - $params = array('id' => $this->_contributionId); - $contribution = CRM_Contribute_BAO_Contribution::retrieve($params, $defaults, $params); - CRM_Contribute_BAO_Contribution::addPayments(array($contribution), $contributionStatusId); + $payment = civicrm_api3('Payment', 'create', array_merge([ + 'contribution_id' => $this->_contributionId, + 'total_amount' => $this->_params['total_amount'], + 'payment_type' => $this->_paymentType, + 'participant_id' => $participantId, + 'mode' => $this->_mode, + ], $this->_params)); if ($this->_contributionId && CRM_Core_Permission::access('CiviMember')) { $membershipPaymentCount = civicrm_api3('MembershipPayment', 'getCount', array('contribution_id' => $this->_contributionId)); if ($membershipPaymentCount) { @@ -382,15 +364,8 @@ public function submit($submittedValues) { } $statusMsg = ts('The payment record has been processed.'); - // send email - if (!empty($result) && !empty($this->_params['is_email_receipt'])) { - $this->_params['contact_id'] = $this->_contactId; - $this->_params['contribution_id'] = $this->_contributionId; - - $sendReceipt = $this->emailReceipt($this->_params); - if ($sendReceipt) { - $statusMsg .= ' ' . ts('A receipt has been emailed to the contributor.'); - } + if (empty($payment['is_error']) && !empty($this->_params['is_email_receipt'])) { + $statusMsg .= ' ' . ts('A receipt has been emailed to the contributor.'); } CRM_Core_Session::setStatus($statusMsg, ts('Saved'), 'success'); @@ -401,7 +376,6 @@ public function processCreditCard() { $session = CRM_Core_Session::singleton(); $now = date('YmdHis'); - $fields = array(); // we need to retrieve email address if ($this->_context == 'standalone' && !empty($this->_params['is_email_receipt'])) { @@ -498,88 +472,6 @@ public function processCreditCard() { } } - /** - * Function to send email receipt. - * - * @param array $params - * - * @return bool - */ - public function emailReceipt(&$params) { - $templateEngine = CRM_Core_Smarty::singleton(); - // email receipt sending - list($contributorDisplayName, $contributorEmail, $doNotMail) = CRM_Contact_BAO_Contact::getContactDetails($params['contact_id']); - if (!$contributorEmail || $doNotMail) { - return FALSE; - } - $templateEngine->assign('contactDisplayName', $contributorDisplayName); - // send message template - if ($this->_component == 'event') { - - // fetch event information from participant ID using API - $eventId = civicrm_api3('Participant', 'getvalue', array( - 'return' => "event_id", - 'id' => $this->_id, - )); - $event = civicrm_api3('Event', 'getsingle', array('id' => $eventId)); - - $templateEngine->assign('event', $event); - $templateEngine->assign('isShowLocation', $event['is_show_location']); - if (CRM_Utils_Array::value('is_show_location', $event) == 1) { - $locationParams = array( - 'entity_id' => $eventId, - 'entity_table' => 'civicrm_event', - ); - $location = CRM_Core_BAO_Location::getValues($locationParams, TRUE); - $templateEngine->assign('location', $location); - } - } - - // assign payment info here - $paymentConfig['confirm_email_text'] = CRM_Utils_Array::value('confirm_email_text', $params); - $templateEngine->assign('paymentConfig', $paymentConfig); - - $templateEngine->assign('totalAmount', $this->_amtTotal); - - $isRefund = ($this->_paymentType == 'refund') ? TRUE : FALSE; - $templateEngine->assign('isRefund', $isRefund); - if ($isRefund) { - $templateEngine->assign('totalPaid', $this->_amtPaid); - $templateEngine->assign('refundAmount', $params['total_amount']); - } - else { - $balance = $this->_amtTotal - ($this->_amtPaid + $params['total_amount']); - $paymentsComplete = ($balance == 0) ? 1 : 0; - $templateEngine->assign('amountOwed', $balance); - $templateEngine->assign('paymentAmount', $params['total_amount']); - $templateEngine->assign('paymentsComplete', $paymentsComplete); - } - - // assign trxn details - $templateEngine->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $params)); - $templateEngine->assign('receive_date', CRM_Utils_Array::value('trxn_date', $params)); - $templateEngine->assign('paidBy', CRM_Core_PseudoConstant::getLabel( - 'CRM_Contribute_BAO_Contribution', - 'payment_instrument_id', - $params['payment_instrument_id'] - )); - $templateEngine->assign('checkNumber', CRM_Utils_Array::value('check_number', $params)); - - $sendTemplateParams = array( - 'groupName' => 'msg_tpl_workflow_contribution', - 'valueName' => 'payment_or_refund_notification', - 'contactId' => $params['contact_id'], - 'PDFFilename' => ts('notification') . '.pdf', - ); - - $sendTemplateParams['from'] = $params['from_email_address']; - $sendTemplateParams['toName'] = $contributorDisplayName; - $sendTemplateParams['toEmail'] = $contributorEmail; - - list($mailSent) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams); - return $mailSent; - } - /** * Wrapper for unit testing the post process submit function. * @@ -609,10 +501,12 @@ public function testSubmit($params, $creditCardMode = NULL, $entityType = 'contr if (!empty($paymentInfo['refund_due'])) { $this->_refund = $paymentInfo['refund_due']; $this->_paymentType = 'refund'; + $this->paymentAmount = $paymentInfo['refund_due']; } elseif (!empty($paymentInfo['amount_owed'])) { $this->_owed = $paymentInfo['amount_owed']; $this->_paymentType = 'owed'; + $this->paymentAmount = $paymentInfo['amount_owed']; } } diff --git a/CRM/Financial/BAO/Payment.php b/CRM/Financial/BAO/Payment.php index c697606dd75f..a591539118b3 100644 --- a/CRM/Financial/BAO/Payment.php +++ b/CRM/Financial/BAO/Payment.php @@ -118,123 +118,114 @@ public static function create($params) { } /** - * Send an email confirming a payment that has been received. + * Function to send email receipt. * * @param array $params * - * @return array + * @return bool */ public static function sendConfirmation($params) { - - $entities = self::loadRelatedEntities($params['id']); + if (empty($params['is_email_receipt'])) { + return; + } + $templateVars = array(); + self::assignVariablesToTemplate($templateVars, $params); + // send message template + $fromEmails = CRM_Core_BAO_Email::getFromEmail(); $sendTemplateParams = array( 'groupName' => 'msg_tpl_workflow_contribution', 'valueName' => 'payment_or_refund_notification', + 'contactId' => CRM_Utils_Array::value('contactId', $templateVars), 'PDFFilename' => ts('notification') . '.pdf', - 'contactId' => $entities['contact']['id'], - 'toName' => $entities['contact']['display_name'], - 'toEmail' => $entities['contact']['email'], - 'tplParams' => self::getConfirmationTemplateParameters($entities), ); - return CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams); + $doNotEmail = NULL; + if (!empty($templateVars['contactId'])) { + $doNotEmail = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $templateVars['contactId'], 'do_not_email'); + } + // try to send emails only if email id is present + // and the do-not-email option is not checked for that contact + if (!empty($templateVars['contributorEmail']) && empty($doNotEmail)) { + list($userName, $receiptFrom) = CRM_Core_BAO_Domain::getDefaultReceiptFrom(); + if (!empty($params['from_email_address']) && array_key_exists($params['from_email_address'], $fromEmails)) { + $receiptFrom = $params['from_email_address']; + } + $sendTemplateParams['from'] = $receiptFrom; + $sendTemplateParams['toName'] = CRM_Utils_Array::value('contributorDisplayName', $templateVars); + $sendTemplateParams['toEmail'] = $templateVars['contributorEmail']; + } + list($mailSent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams); + return $mailSent; } /** - * Load entities related to the current payment id. + * Assign template variables. * - * This gives us all the data we need to send an email confirmation but avoiding - * getting anything not tested for the confirmations. We retrieve the 'full' event as - * it has been traditionally assigned in full. - * - * @param int $id + * @param array $templateVars + * @param array $params * * @return array - * - contact = ['id' => x, 'display_name' => y, 'email' => z] - * - event = [.... full event details......] - * - contribution = ['id' => x], - * - payment = [payment info + payment summary info] */ - protected static function loadRelatedEntities($id) { - $entities = []; - $contributionID = (int) civicrm_api3('EntityFinancialTrxn', 'getvalue', [ - 'financial_trxn_id' => $id, - 'entity_table' => 'civicrm_contribution', - 'return' => 'entity_id', - ]); - $entities['contribution'] = ['id' => $contributionID]; - $entities['payment'] = array_merge(civicrm_api3('FinancialTrxn', 'getsingle', ['id' => $id]), - CRM_Contribute_BAO_Contribution::getPaymentInfo($contributionID) - ); - - $contactID = self::getPaymentContactID($contributionID); - list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID); - $entities['contact'] = ['id' => $contactID, 'display_name' => $displayName, 'email' => $email]; - - $participantRecords = civicrm_api3('ParticipantPayment', 'get', [ - 'contribution_id' => $contributionID, - 'api.Participant.get' => ['return' => 'event_id'], - 'sequential' => 1, - ])['values']; - if (!empty($participantRecords)) { - $entities['event'] = civicrm_api3('Event', 'getsingle', ['id' => $participantRecords[0]['api.Participant.get']['values'][0]['event_id']]); - if (!empty($entities['event']['is_show_location'])) { - $locationParams = [ - 'entity_id' => $entities['event']['id'], + public static function assignVariablesToTemplate(&$templateVars, $params) { + $templateVars = self::getTemplateVars($params); + $template = CRM_Core_Smarty::singleton(); + if (CRM_Utils_Array::value('component', $templateVars) == 'event') { + // fetch event information from participant ID using API + $eventId = civicrm_api3('Participant', 'getvalue', array( + 'return' => "event_id", + 'id' => $templateVars['id'], + )); + $event = civicrm_api3('Event', 'getsingle', array('id' => $eventId)); + $template->assign('event', $event); + $template->assign('isShowLocation', $event['is_show_location']); + if (CRM_Utils_Array::value('is_show_location', $event) == 1) { + $locationParams = array( + 'entity_id' => $eventId, 'entity_table' => 'civicrm_event', - ]; - $entities['location'] = CRM_Core_BAO_Location::getValues($locationParams, TRUE); + ); + $location = CRM_Core_BAO_Location::getValues($locationParams, TRUE); + $template->assign('location', $location); } + // assign payment info here + $paymentConfig['confirm_email_text'] = CRM_Utils_Array::value('confirm_email_text', $event); + $template->assign('paymentConfig', $paymentConfig); + } + $template->assign('component', CRM_Utils_Array::value('component', $templateVars)); + $template->assign('totalAmount', CRM_Utils_Array::value('amtTotal', $templateVars)); + $isRefund = ($templateVars['paymentType'] == 'refund') ? TRUE : FALSE; + $template->assign('isRefund', $isRefund); + if ($isRefund) { + $template->assign('totalPaid', CRM_Utils_Array::value('amtPaid', $templateVars)); + $template->assign('refundAmount', $params['total_amount']); + } + else { + $balance = CRM_Contribute_BAO_Contribution::getContributionBalance($params['contribution_id']); + $paymentsComplete = ($balance == 0) ? 1 : 0; + $template->assign('amountOwed', $balance); + $template->assign('paymentAmount', $params['total_amount']); + $template->assign('paymentsComplete', $paymentsComplete); + } + $template->assign('contactDisplayName', CRM_Utils_Array::value('contributorDisplayName', $templateVars)); + // assign trxn details + $template->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $params)); + $template->assign('receive_date', CRM_Utils_Array::value('trxn_date', $params)); + if (!empty($params['payment_instrument_id'])) { + $template->assign('paidBy', CRM_Core_PseudoConstant::getLabel( + 'CRM_Contribute_BAO_Contribution', + 'payment_instrument_id', + $params['payment_instrument_id'] + )); + } + $template->assign('checkNumber', CRM_Utils_Array::value('check_number', $params)); + if (!empty($params['mode'])) { + $template->assign('contributeMode', 'direct'); + $template->assign('address', CRM_Utils_Address::getFormattedBillingAddressFieldsFromParameters( + $params, + CRM_Core_BAO_LocationType::getBilling() + )); } - - return $entities; - } - - /** - * @param int $contributionID - * - * @return int - */ - public static function getPaymentContactID($contributionID) { - $contribution = civicrm_api3('Contribution', 'getsingle', [ - 'id' => $contributionID , - 'return' => ['contact_id'], - ]); - return (int) $contribution['contact_id']; - } - /** - * @param array $entities - * Related entities as an array keyed by the various entities. - * - * @return array - * Values required for the notification - * - contact_id - * - template_variables - * - event (DAO of event if relevant) - */ - public static function getConfirmationTemplateParameters($entities) { - $templateVariables = [ - 'contactDisplayName' => $entities['contact']['display_name'], - 'totalAmount' => $entities['payment']['total'], - 'amountOwed' => $entities['payment']['balance'], - 'paymentAmount' => $entities['payment']['total_amount'], - 'checkNumber' => CRM_Utils_Array::value('check_number', $entities['payment']), - 'receive_date' => $entities['payment']['trxn_date'], - 'paidBy' => CRM_Core_PseudoConstant::getLabel('CRM_Core_BAO_FinancialTrxn', 'payment_instrument_id', $entities['payment']['payment_instrument_id']), - 'isShowLocation' => (!empty($entities['event']) ? $entities['event']['is_show_location'] : FALSE), - 'location' => CRM_Utils_Array::value('location', $entities), - 'event' => CRM_Utils_Array::value('event', $entities), - 'component' => (!empty($entities['event']) ? 'event' : 'contribution'), - ]; - - return self::filterUntestedTemplateVariables($templateVariables); } - /** - * Filter out any untested variables. - * - * This just serves to highlight if any variables are added without a unit test also being added. - * - * (if hit then add a unit test for the param & add to this array). + * Function to form template variables. * * @param array $params * diff --git a/api/v3/Payment.php b/api/v3/Payment.php index a4292a5b6b71..2bb5fd8022e8 100644 --- a/api/v3/Payment.php +++ b/api/v3/Payment.php @@ -169,6 +169,16 @@ function _civicrm_api3_payment_create_spec(&$params) { 'type' => CRM_Utils_Type::T_INT, 'api.aliases' => array('payment_id'), ), + 'payment_type' => array( + 'title' => 'Payment Type', + 'type' => CRM_Utils_Type::T_STRING, + 'description' => ts("Type of payment - 'owed' or 'refund'."), + ), + 'is_email_receipt' => array( + 'title' => 'Send Email Receipt', + 'type' => CRM_Utils_Type::T_BOOLEAN, + 'description' => ts('If true, receipt is automatically emailed to contact after payment.'), + ), ); } diff --git a/tests/phpunit/CRM/Event/BAO/AdditionalPaymentTest.php b/tests/phpunit/CRM/Event/BAO/AdditionalPaymentTest.php index 8c05c65f9ba6..71bddb98395f 100644 --- a/tests/phpunit/CRM/Event/BAO/AdditionalPaymentTest.php +++ b/tests/phpunit/CRM/Event/BAO/AdditionalPaymentTest.php @@ -209,6 +209,7 @@ public function testAddPartialPayment() { * Test owed/refund info is listed on view payments. */ public function testTransactionInfo() { + $mut = new CiviMailUtils($this, TRUE); $feeAmt = 100; $amtPaid = 80; $result = $this->addParticipantWithPayment($feeAmt, $amtPaid); @@ -218,17 +219,28 @@ public function testTransactionInfo() { $submittedValues = array( 'total_amount' => 20, 'payment_instrument_id' => 3, + 'payment_type' => 'owed', + 'participant_id' => $participant['id'], + 'contribution_id' => $contributionID, + 'is_email_receipt' => TRUE, ); - CRM_Contribute_BAO_Contribution::recordAdditionalPayment($contributionID, $submittedValues, 'owed', $result['participant']['id']); + + $this->callAPISuccess('payment', 'create', $submittedValues); + $priceField = $this->callAPISuccess('PriceField', 'get', [ + 'sequential' => 1, + 'price_set_id' => $priceSetId, + 'html_type' => 'Text' + ]); //Change selection to a lower amount. - $params['price_2'] = 50; - CRM_Price_BAO_LineItem::changeFeeSelections($params, $result['participant']['id'], 'participant', $contributionID, $result['feeBlock'], $result['lineItem']); + $params["price_{$priceField['id']}"] = 50; + CRM_Price_BAO_LineItem::changeFeeSelections($params, $participant['id'], 'participant', $contributionID, $feeBlock, $lineItem, $feeAmt); //Record a refund of the remaining amount. $submittedValues['total_amount'] = 50; - CRM_Contribute_BAO_Contribution::recordAdditionalPayment($contributionID, $submittedValues, 'refund', $result['participant']['id']); - $paymentInfo = CRM_Contribute_BAO_Contribution::getPaymentInfo($result['participant']['id'], 'event', TRUE); + $submittedValues['payment_type'] = 'refund'; + $this->callAPISuccess('payment', 'create', $submittedValues); + $paymentInfo = CRM_Contribute_BAO_Contribution::getPaymentInfo($participant['id'], 'event', TRUE); $transaction = $paymentInfo['transaction']; //Assert all transaction(owed and refund) are listed on view payments. @@ -241,6 +253,18 @@ public function testTransactionInfo() { $this->assertEquals($transaction[2]['total_amount'], -50.00); $this->assertEquals($transaction[2]['status'], 'Refunded'); + + //Test email receipt for refund payment. + $mut->assertSubjects(array('Payment Receipt - Annual CiviCRM meet', 'Refund Notification - Annual CiviCRM meet')); + $mut->checkMailLog(array( + 'Dear Mr. Anthony Anderson II', + 'A refund has been issued based on changes in your registration selections', + 'Total Fees: $ 50.00', + 'You Paid: $ 50.00', + 'Refund Amount: $ 50.00', + 'Event Information and Location', + )); + $mut->stop(); } }