return $trxn;
}
+ /**
+ * Send an email confirming a payment that has been received.
+ *
+ * @param array $params
+ *
+ * @return array
+ */
+ public static function sendConfirmation($params) {
+
+ $entities = self::loadRelatedEntities($params['id']);
+ $sendTemplateParams = array(
+ 'groupName' => 'msg_tpl_workflow_contribution',
+ 'valueName' => 'payment_or_refund_notification',
+ '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);
+ }
+
+ /**
+ * Load entities related to the current payment id.
+ *
+ * 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
+ *
+ * @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']]);
+ }
+
+ 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'],
+ 'event' => NULL,
+ 'component' => 'contribution',
+ ];
+ if (!empty($entities['event'])) {
+ $templateVariables['component'] = 'event';
+ $templateVariables['event'] = $entities['event'];
+ }
+
+ 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).
+ *
+ * @param array $params
+ *
+ * @return array
+ */
+ public static function filterUntestedTemplateVariables($params) {
+ $testedTemplateVariables = [
+ 'contactDisplayName',
+ 'totalAmount',
+ 'amountOwed',
+ 'paymentAmount',
+ 'event',
+ 'component',
+ ];
+ // Need to do these before switching the form over...
+ $todoParams = [
+ 'isRefund',
+ 'totalPaid',
+ 'refundAmount',
+ 'paymentsComplete',
+ 'receive_date',
+ 'paidBy',
+ 'checkNumber',
+ 'contributeMode',
+ 'isAmountzero',
+ 'billingName',
+ 'address',
+ 'credit_card_type',
+ 'credit_card_number',
+ 'credit_card_exp_date',
+ 'isShowLocation',
+ 'location',
+ 'eventEmail',
+ '$event.participant_role',
+ ];
+ $filteredParams = [];
+ foreach ($testedTemplateVariables as $templateVariable) {
+ // This will cause an a-notice if any are NOT set - by design. Ensuring
+ // they are set prevents leakage.
+ $filteredParams[$templateVariable] = $params[$templateVariable];
+ }
+ return $filteredParams;
+ }
+
}
),
);
}
+
+/**
+ * Send a payment confirmation.
+ *
+ * @param array $params
+ * Input parameters.
+ *
+ * @return array
+ * @throws Exception
+ */
+function civicrm_api3_payment_sendconfirmation($params) {
+ $allowedParams = [
+ 'receipt_from_email',
+ 'receipt_from_name',
+ 'cc_receipt',
+ 'bcc_receipt',
+ 'receipt_text',
+ 'id',
+ ];
+ $input = array_intersect_key($params, array_flip($allowedParams));
+ // use either the contribution or membership receipt, based on whether it’s a membership-related contrib or not
+ $result = CRM_Financial_BAO_Payment::sendConfirmation($input);
+ return civicrm_api3_create_success([
+ $params['id'] => [
+ 'is_sent' => $result[0],
+ 'subject' => $result[1],
+ 'message_txt' => $result[2],
+ 'message_html' => $result[3],
+ ]]);
+}
+
+/**
+ * Adjust Metadata for sendconfirmation action.
+ *
+ * The metadata is used for setting defaults, documentation & validation.
+ *
+ * @param array $params
+ * Array of parameters determined by getfields.
+ */
+function _civicrm_api3_payment_sendconfirmation_spec(&$params) {
+ $params['id'] = array(
+ 'api.required' => 1,
+ 'title' => ts('Payment ID'),
+ 'type' => CRM_Utils_Type::T_INT,
+ );
+}
));
}
+ /**
+ * Test email receipt for partial payment.
+ */
+ public function testPaymentEmailReceipt() {
+ $mut = new CiviMailUtils($this);
+ list($lineItems, $contribution) = $this->createParticipantWithContribution();
+ $params = array(
+ 'contribution_id' => $contribution['id'],
+ 'total_amount' => 50,
+ );
+ $payment = $this->callAPISuccess('payment', 'create', $params);
+ $this->checkPaymentResult($payment, [
+ $payment['id'] => [
+ 'from_financial_account_id' => 7,
+ 'to_financial_account_id' => 6,
+ 'total_amount' => 50,
+ 'status_id' => 1,
+ 'is_payment' => 1,
+ ],
+ ]);
+
+ $this->callAPISuccess('Payment', 'sendconfirmation', ['id' => $payment['id']]);
+ $mut->assertSubjects(['Payment Receipt - Annual CiviCRM meet']);
+ $mut->checkMailLog(array(
+ 'Dear Mr. Anthony Anderson II',
+ 'Total Fees: $ 300.00',
+ 'This Payment Amount: $ 50.00',
+ 'Balance Owed: $ 100.00', //150 was paid in the 1st payment.
+ 'Event Information and Location',
+ ));
+ $mut->stop();
+ }
+
/**
* Test create payment api with no line item in params
*/