Fix additional payment form to create billing address
authorEileen McNaughton <emcnaughton@wikimedia.org>
Mon, 11 Dec 2023 20:11:38 +0000 (09:11 +1300)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Mon, 11 Dec 2023 22:30:08 +0000 (11:30 +1300)
CRM/Contribute/Form/AdditionalPayment.php
templates/CRM/Contribute/Form/AdditionalPayment.tpl
tests/phpunit/CRM/Contribute/Form/AdditionalPaymentTest.php
xml/templates/message_templates/payment_or_refund_notification_html.tpl

index 974dab2ff9a0500c767b58ff3498a44447e46e3d..9e24c249286d227fcf110689243d64c494312517 100644 (file)
  * @copyright CiviCRM LLC https://civicrm.org/licensing
  */
 
+use Civi\Api4\Contribution;
 use Civi\Payment\Exception\PaymentProcessorException;
 
 /**
  * This form records additional payments needed when event/contribution is partially paid.
  */
 class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_AbstractEditPayment {
+  use CRM_Contact_Form_ContactFormTrait;
+  use CRM_Contribute_Form_ContributeFormTrait;
 
   /**
    * Id of the component entity
@@ -162,7 +165,7 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
     // Set $newCredit variable in template to control whether link to credit card mode is included
     $this->assign('newCredit', CRM_Core_Config::isEnabledBackOfficeCreditCardPayments());
 
-    $defaults['payment_instrument_id'] = \Civi\Api4\Contribution::get(FALSE)
+    $defaults['payment_instrument_id'] = Contribution::get(FALSE)
       ->addSelect('payment_instrument_id')
       ->addWhere('id', '=', $this->_contributionId)
       ->execute()->first()['payment_instrument_id'];
@@ -214,7 +217,7 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
     $this->addField('trxn_date', ['entity' => 'FinancialTrxn', 'label' => $this->isARefund() ? ts('Refund Date') : ts('Contribution Date'), 'context' => 'Contribution'], FALSE, FALSE);
 
     if ($this->_contactId && $this->_id) {
-      if ($this->_component == 'event') {
+      if ($this->_component === 'event') {
         $eventId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant', $this->_id, 'event_id', 'id');
         $event = CRM_Event_BAO_Event::getEvents(0, $eventId);
         $this->assign('eventName', $event[$eventId]);
@@ -310,9 +313,14 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
    * @throws \CRM_Core_Exception
    */
   public function submit($submittedValues) {
-    $this->_params = $submittedValues;
-    $this->beginPostProcess();
-    $this->processBillingAddress($this->_contactID, (string) $this->_contributorEmail);
+    if ($this->_mode) {
+      $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment(
+        $this->getSubmittedValue('payment_processor_id'),
+        ($this->_mode === 'test')
+      );
+    }
+    $this->assign('displayName', $this->getContactValue('display_name'));
+
     $paymentResult = [];
     if ($this->_mode) {
       // process credit card
@@ -336,7 +344,11 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
       'is_send_contribution_notification' => FALSE,
     ];
     $paymentID = civicrm_api3('Payment', 'create', $trxnsData)['id'];
-
+    $contributionAddressID = CRM_Contribute_BAO_Contribution::createAddress($this->getSubmittedValues());
+    if ($contributionAddressID) {
+      Contribution::update(FALSE)->addWhere('id', '=', $this->getContributionID())
+        ->setValues(['address_id' => $contributionAddressID])->execute();
+    }
     if ($this->getContributionID() && CRM_Core_Permission::access('CiviMember')) {
       $membershipPaymentCount = civicrm_api3('MembershipPayment', 'getCount', ['contribution_id' => $this->_contributionId]);
       if ($membershipPaymentCount) {
@@ -362,6 +374,9 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
     CRM_Core_Session::setStatus($statusMsg, ts('Saved'), 'success');
   }
 
+  /**
+   * @throws \CRM_Core_Exception
+   */
   public function processCreditCard(): ?array {
     // we need to retrieve email address
     if ($this->_context === 'standalone' && $this->getSubmittedValue('is_email_receipt')) {
@@ -369,28 +384,27 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
       $this->assign('displayName', $displayName);
     }
 
-    $this->assign('address', CRM_Utils_Address::getFormattedBillingAddressFieldsFromParameters($this->_params));
-
     // 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
     // so we copy stuff over to first_name etc.
-    $paymentParams = $this->_params;
-    $paymentParams['contactID'] = $this->_contactId;
-    $paymentParams['amount'] = $this->getSubmittedValue('total_amount');
-    $paymentParams['currency'] = $this->getCurrency();
-    CRM_Core_Payment_Form::mapParams($this->_bltID, $this->getSubmittedValues(), $paymentParams, TRUE);
-
-    $paymentParams['contributionPageID'] = NULL;
-    $paymentParams['email'] = $this->_contributorEmail;
-    $paymentParams['is_email_receipt'] = (bool) $this->getSubmittedValue('is_email_receipt');
-
-    $result = NULL;
+    $paymentParams = $this->prepareParamsForPaymentProcessor($this->getSubmittedValues() + [
+      'currency' => $this->getCurrency(),
+      'amount' => $this->getSubmittedValue('total_amount'),
+      'contact_id' => $this->getContactID(),
+      'is_email_receipt' => (bool) $this->getSubmittedValue('is_email_receipt'),
+      'email' => $this->getContactValue('email_primary.email'),
+    ]);
 
     if ($paymentParams['amount'] > 0.0) {
       try {
         // Re-retrieve the payment processor in case the form changed it, CRM-7179
         $payment = \Civi\Payment\System::singleton()->getById($this->getPaymentProcessorID());
         $result = $payment->doPayment($paymentParams);
+        return [
+          'fee_amount' => $result['fee_amount'] ?? 0,
+          'trxn_id' => $result['trxn_id'] ?? NULL,
+          'trxn_result_code' => $result['trxn_result_code'] ?? NULL,
+        ];
       }
       catch (PaymentProcessorException $e) {
         Civi::log()->error('Payment processor exception: ' . $e->getMessage());
@@ -398,16 +412,7 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
         CRM_Core_Error::statusBounce($e->getMessage(), CRM_Utils_System::url('civicrm/payment/add', $urlParams));
       }
     }
-    if (!empty($result)) {
-      $this->_params = array_merge($this->_params, $result);
-    }
-
-    $this->set('params', $this->_params);
-    return [
-      'fee_amount' => $result['fee_amount'] ?? 0,
-      'trxn_id' => $result['trxn_id'] ?? NULL,
-      'trxn_result_code' => $result['trxn_result_code'] ?? NULL,
-    ];
+    return [];
   }
 
   /**
@@ -520,6 +525,20 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
     return (int) $this->_contributionId;
   }
 
+  /**
+   * Get the contact ID in use.
+   *
+   * @api supported for external use.
+   *
+   * @return int
+   */
+  public function getContactID(): int {
+    if ($this->_contactID === NULL) {
+      $this->_contactID = $this->getContributionValue('contact_id');
+    }
+    return (int) $this->_contactID;
+  }
+
   /**
    * Get the payment processor ID.
    *
index 52d54ec903be99b5fac77134ebc75fe03bd63507..2e1ba2a37fe2a6543b62c032ef7207984863dddb 100644 (file)
   </div>
   <table class="form-layout-compressed">
     <tr>
-      <td class="label"><strong>{if $component eq 'event'}{ts}Participant{/ts}{else}{ts}Contact{/ts}{/if}</strong></td><td><strong>{$displayName}</strong></td>
+      <td class="label"><strong>{if $component eq 'event'}{ts}Participant{/ts}{else}{ts}Contact{/ts}{/if}</strong></td><td><strong>{$displayName|escape}</strong></td>
     </tr>
     {if $eventName}
       <tr>
-        <td class='label'>{ts}Event{/ts}</td><td>{$eventName}</td>
+        <td class='label'>{ts}Event{/ts}</td><td>{$eventName|escape}</td>
       </tr>
     {/if}
     <tr class="crm-payment-form-block-total_amount">
@@ -61,7 +61,7 @@
             {$form.is_email_receipt.label}
           </td>
           <td>{$form.is_email_receipt.html}
-              <span class="description">{ts 1=$email}Automatically email a receipt to %1?{/ts}</span>
+              <span class="description">{ts 1=$email|escape}Automatically email a receipt to %1?{/ts}</span>
           </td>
         </tr>
         <tr id="fromEmail" class="crm-payment-form-block-from_email_address" style="display:none;">
index 7b25b247a569cba07e41713bcaf3491961c0cd5a..ad3ea7f8446d1d56b795be65875df1e0d93cbb29 100644 (file)
@@ -9,6 +9,9 @@
  +--------------------------------------------------------------------+
  */
 
+use Civi\Api4\Country;
+use Civi\Api4\StateProvince;
+
 /**
  *  Test APIv3 civicrm_contribute_* functions
  *
@@ -137,7 +140,7 @@ class CRM_Contribute_Form_AdditionalPaymentTest extends CiviUnitTestCase {
       'This Payment Amount',
       '$70.00',
       'Billing Name and Address',
-      'Vancouver, BC 1321312',
+      'Vancouver, British Columbia 1321312',
       'Visa',
       '***********1111',
     ]);
@@ -258,7 +261,7 @@ class CRM_Contribute_Form_AdditionalPaymentTest extends CiviUnitTestCase {
       'Credit Card',
       '***********1111',
       'Billing Name and Address',
-      'Vancouver, BC 1321312',
+      'Vancouver, British Columbia 1321312',
     ]);
     $mut->stop();
     $mut->clearMessages();
@@ -371,9 +374,9 @@ class CRM_Contribute_Form_AdditionalPaymentTest extends CiviUnitTestCase {
     ];
     if ($mode) {
       $_REQUEST['mode'] = $mode;
-      $stateProvinceBC = \Civi\Api4\StateProvince::get()
+      $stateProvinceID = StateProvince::get()
         ->addWhere('abbreviation', '=', 'BC')
-        ->addWhere('country_id', '=', 1039)
+        ->addWhere('country_id.name', '=', 'Canada')
         ->execute()
         ->single();
       $submitParams += [
@@ -384,9 +387,9 @@ class CRM_Contribute_Form_AdditionalPaymentTest extends CiviUnitTestCase {
         'cvv2' => 234,
         'credit_card_type' => 'Visa',
         'billing_city-5' => 'Vancouver',
-        'billing_state_province_id-5' => $stateProvinceBC['id'],
+        'billing_state_province_id-5' => $stateProvinceID['id'],
         'billing_postal_code-5' => 1321312,
-        'billing_country_id-5' => 1228,
+        'billing_country_id-5' => Country::get()->addWhere('name', '=', 'Canada')->execute()->first()['id'],
       ];
     }
     else {
index 83600ab42926d26a6c1f118fdf952660e6ed33f1..d4922a172aa3c25163180cff520d9040fc1a8f52 100644 (file)
     <tr>
       <td>
   <table style="border: 1px solid #999; margin: 1em 0em 1em; border-collapse: collapse; width:100%;">
-    {if !empty($billingName) || !empty($address)}
+    {if {contribution.address_id.display|boolean}}
         <tr>
           <th {$headerStyle}>
               {ts}Billing Name and Address{/ts}
         </tr>
         <tr>
           <td colspan="2" {$valueStyle}>
-        {if !empty($billingName)}{$billingName}{/if}<br />
-        {if !empty($address)}{$address|nl2br}{/if}
+              {contribution.address_id.name}<br/>
+              {contribution.address_id.display}
           </td>
         </tr>
       {/if}