CRM-16454 towards allowing offsite backoffice processors, lock in current renewal...
authorEileen McNaughton <eileen@fuzion.co.nz>
Sun, 12 Jul 2015 12:45:40 +0000 (00:45 +1200)
committerEileen McNaughton <eileen@fuzion.co.nz>
Sun, 12 Jul 2015 12:45:40 +0000 (00:45 +1200)
CRM/Contribute/BAO/Contribution.php
CRM/Core/Payment.php
CRM/Member/Form/Membership.php
CRM/Member/Form/MembershipRenewal.php
templates/CRM/common/customData.tpl
tests/phpunit/CRM/Member/Form/MembershipRenewalTest.php

index bafa07c1c398205ec04cc84b2c15675422c901f0..36d37426b65ad2bb126f4f6404f42f6e63a0388b 100644 (file)
@@ -229,7 +229,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
    * @return CRM_Contribute_BAO_Contribution|null
    *   The found object or null
    */
-  public static function &getValues($params, &$values, &$ids) {
+  public static function getValues($params, &$values, &$ids) {
     if (empty($params)) {
       return NULL;
     }
@@ -271,6 +271,62 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
     }
   }
 
+  /**
+   * @param $params
+   * @param $billingLocationTypeID
+   *
+   * @return array
+   */
+  protected static function getBillingAddressParams($params, $billingLocationTypeID) {
+    $hasBillingField = FALSE;
+    $billingFields = array(
+      'street_address',
+      'city',
+      'state_province_id',
+      'postal_code',
+      'country_id',
+    );
+
+    //build address array
+    $addressParams = array();
+    $addressParams['location_type_id'] = $billingLocationTypeID;
+    $addressParams['is_billing'] = 1;
+
+    $billingFirstName = CRM_Utils_Array::value('billing_first_name', $params);
+    $billingMiddleName = CRM_Utils_Array::value('billing_middle_name', $params);
+    $billingLastName = CRM_Utils_Array::value('billing_last_name', $params);
+    $addressParams['address_name'] = "{$billingFirstName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingMiddleName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingLastName}";
+
+    foreach ($billingFields as $value) {
+      $addressParams[$value] = CRM_Utils_Array::value("billing_{$value}-{$billingLocationTypeID}", $params);
+      if (!empty($addressParams[$value])) {
+        $hasBillingField = TRUE;
+      }
+    }
+    return array($hasBillingField, $addressParams);
+  }
+
+  /**
+   * Get address params ready to be passed to the payment processor.
+   *
+   * We need address params in a couple of formats. For the payment processor we wan state_province_id-5.
+   * To create an address we need state_province_id.
+   *
+   * @param array $params
+   * @param int $billingLocationTypeID
+   *
+   * @return array
+   */
+  public static function getPaymentProcessorReadyAddressParams($params, $billingLocationTypeID) {
+    list($hasBillingField, $addressParams) = self::getBillingAddressParams($params, $billingLocationTypeID);
+    foreach ($addressParams as $name => $field) {
+      if (substr($name, 0, 8) == 'billing_') {
+        $addressParams[substr($name, 9)] = $addressParams[$field];
+      }
+    }
+    return array($hasBillingField, $addressParams);
+  }
+
   /**
    * Get the number of terms for this contribution for a given membership type
    * based on querying the line item table and relevant price field values
@@ -1299,31 +1355,7 @@ LEFT JOIN civicrm_option_value contribution_status ON (civicrm_contribution.cont
    *   address id
    */
   public static function createAddress($params, $billingLocationTypeID) {
-    $hasBillingField = FALSE;
-    $billingFields = array(
-      'street_address',
-      'city',
-      'state_province_id',
-      'postal_code',
-      'country_id',
-    );
-
-    //build address array
-    $addressParams = array();
-    $addressParams['location_type_id'] = $billingLocationTypeID;
-    $addressParams['is_billing'] = 1;
-
-    $billingFirstName = CRM_Utils_Array::value('billing_first_name', $params);
-    $billingMiddleName = CRM_Utils_Array::value('billing_middle_name', $params);
-    $billingLastName = CRM_Utils_Array::value('billing_last_name', $params);
-    $addressParams['address_name'] = "{$billingFirstName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingMiddleName}" . CRM_Core_DAO::VALUE_SEPARATOR . "{$billingLastName}";
-
-    foreach ($billingFields as $value) {
-      $addressParams[$value] = CRM_Utils_Array::value("billing_{$value}-{$billingLocationTypeID}", $params);
-      if (!empty($addressParams[$value])) {
-        $hasBillingField = TRUE;
-      }
-    }
+    list($hasBillingField, $addressParams) = self::getBillingAddressParams($params, $billingLocationTypeID);
     if ($hasBillingField) {
       $address = CRM_Core_BAO_Address::add($addressParams, FALSE);
       return $address->id;
index b5731feccddaeae4156b83c301927982385144f7..5d60d321ee53e8d8eec4ff4784e64f95dfcbf9b7 100644 (file)
@@ -678,7 +678,7 @@ abstract class CRM_Core_Payment {
       if (is_array($result) && !isset($result['payment_status_id'])) {
         if (!empty($params['is_recur'])) {
           // See comment block.
-          $paymentParams['payment_status_id'] = array_search('Pending', $statuses);
+          $result['payment_status_id'] = array_search('Pending', $statuses);
         }
         else {
           $result['payment_status_id'] = array_search('Completed', $statuses);
index 34c727bd1cfbd3003e1907c432b947c3bf39263f..6eaf26414738098322e3607d59cb2b129b8d66f8 100644 (file)
@@ -723,10 +723,8 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
 
     $this->addFormRule(array('CRM_Member_Form_Membership', 'formRule'), $this);
 
-    $mailingInfo = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
-      'mailing_backend'
-    );
-    $this->assign('outBound_option', $mailingInfo['outBound_option']);
+    $this->assign('outBound_option', CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
+      'mailing_backend'));
 
     parent::buildQuickForm();
   }
@@ -1010,6 +1008,7 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
     }
 
     CRM_Core_BAO_UFGroup::getValues($formValues['contact_id'], $customFields, $customValues, FALSE, $members);
+    $form->assign('customValues', $customValues);
 
     if ($form->_mode) {
       $name = '';
@@ -1091,7 +1090,6 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
       $form->assign('membership_name', CRM_Member_PseudoConstant::membershipType($membership->membership_type_id));
     }
 
-    $form->assign('customValues', $customValues);
     $isBatchProcess = is_a($form, 'CRM_Batch_Form_Entry');
     if ((empty($form->_contributorDisplayName) || empty($form->_contributorEmail)) || $isBatchProcess) {
       // in this case the form is being called statically from the batch editing screen
index 2ddd44319d8c2f997611d459d1d7e0be97b7cd3e..48d5460d054d3b2623a21daded5b166cefea1e93 100644 (file)
@@ -446,33 +446,6 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
     CRM_Core_Session::setStatus($statusMsg, ts('Complete'), 'success');
   }
 
-  /**
-   * Determine if the form has a pending status.
-   *
-   * @deprecated
-   *
-   * @param CRM_Core_Form $form
-   * @param int $membershipID
-   *
-   * @return bool
-   */
-  public static function extractPendingFormValue($form, $membershipID) {
-    $membershipTypeDetails = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($membershipID);
-    $pending = FALSE;
-    // @todo function was shared by 2 not-very-related forms & the below may include irrelevant stuff.
-    if (CRM_Utils_Array::value('minimum_fee', $membershipTypeDetails) > 0.0) {
-      if (((isset($form->_contributeMode) && $form->_contributeMode == 'notify') || !empty($form->_params['is_pay_later'])
-        ) &&
-        (($form->_values['is_monetary'] && $form->_amount > 0.0) ||
-          CRM_Utils_Array::value('record_contribution', $form->_params)
-        )
-      ) {
-        $pending = TRUE;
-      }
-    }
-    return $pending;
-  }
-
   /**
    * Process form submission.
    *
@@ -486,6 +459,25 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
     $now = CRM_Utils_Date::getToday(NULL, 'YmdHis');
     $this->convertDateFieldsToMySQL($this->_params);
     $this->assign('receive_date', $this->_params['receive_date']);
+    $this->processBillingAddress($now);
+    $this->_params['total_amount'] = CRM_Utils_Array::value('total_amount', $this->_params,
+      CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $this->_memType, 'minimum_fee')
+    );
+    $this->_membershipId = $this->_id;
+    $customFieldsFormatted = CRM_Core_BAO_CustomField::postProcess($this->_params,
+      $this->_id,
+      'Membership'
+    );
+    if (empty($this->_params['financial_type_id'])) {
+      $this->_params['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $this->_memType, 'financial_type_id');
+    }
+
+    $this->assign('membershipID', $this->_id);
+    $this->assign('contactID', $this->_contactID);
+    $this->assign('module', 'Membership');
+    $this->assign('receiptType', 'membership renewal');
+    $this->_params['currencyID'] = CRM_Core_Config::singleton()->defaultCurrency;
+    $this->_params['invoice_id'] = $this->_params['invoiceID'] = md5(uniqid(rand(), TRUE));
 
     if (!empty($this->_params['send_receipt'])) {
       $this->_params['receipt_date'] = $now;
@@ -496,61 +488,14 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
     }
 
     if ($this->_mode) {
-      $this->_params['total_amount'] = CRM_Utils_Array::value('total_amount', $this->_params,
-        CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $this->_memType, 'minimum_fee')
-      );
-      if (empty($this->_params['financial_type_id'])) {
-        $this->_params['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $this->_memType, 'financial_type_id');
-      }
-
-      $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($this->_params['payment_processor_id']);
-
-      $fields = array();
-
-      // set email for primary location.
-      $fields['email-Primary'] = 1;
-      $this->_params['email-5'] = $this->_params['email-Primary'] = $this->_contributorEmail;
       $this->_params['register_date'] = $now;
-
-      // also add location name to the array
-      $this->_params["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $this->_params) . ' ' . CRM_Utils_Array::value('billing_middle_name', $this->_params) . ' ' . CRM_Utils_Array::value('billing_last_name', $this->_params);
-
-      $this->_params["address_name-{$this->_bltID}"] = trim($this->_params["address_name-{$this->_bltID}"]);
-
-      $fields["address_name-{$this->_bltID}"] = 1;
-
-      $fields["email-{$this->_bltID}"] = 1;
-
-      $nameFields = array('first_name', 'middle_name', 'last_name');
-
-      foreach ($nameFields as $name) {
-        $fields[$name] = 1;
-        if (array_key_exists("billing_$name", $this->_params)) {
-          $this->_params[$name] = $this->_params["billing_{$name}"];
-          $this->_params['preserveDBName'] = TRUE;
-        }
-      }
-
-      //here we are setting up the billing contact - if different from the member they are already created
-      // but they will get billing details assigned
-      CRM_Contact_BAO_Contact::createProfileContact($this->_params, $fields,
-        $this->_contributorContactID, NULL, NULL,
-        CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type')
-      );
-
-      // add all the additional payment params we need
-      $this->_params["state_province-{$this->_bltID}"] = $this->_params["billing_state_province-{$this->_bltID}"]
-        = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]);
-      $this->_params["country-{$this->_bltID}"] = $this->_params["billing_country-{$this->_bltID}"]
-        = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]);
+      $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($this->_params['payment_processor_id']);
 
       $this->_params['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($this->_params);
       $this->_params['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($this->_params);
       $this->_params['description'] = ts('Office Credit Card Membership Renewal Contribution');
       $this->_params['ip_address'] = CRM_Utils_System::ipAddress();
       $this->_params['amount'] = $this->_params['total_amount'];
-      $this->_params['currencyID'] = CRM_Core_Config::singleton()->defaultCurrency;
-      $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
@@ -564,19 +509,17 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
 
       CRM_Core_Payment_Form::mapParams($this->_bltID, $this->_params, $paymentParams, TRUE);
 
-      $payment = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
+      $payment = $this->_paymentProcessor['object'];
 
       if (!empty($this->_params['auto_renew'])) {
         $contributionRecurParams = $this->processRecurringContribution($paymentParams);
         $paymentParams = array_merge($paymentParams, $contributionRecurParams);
       }
+
       $result = $payment->doPayment($paymentParams);
+      $this->_params = array_merge($this->_params, $result);
 
-      if ($result) {
-        $this->_params = array_merge($this->_params, $result);
-      }
-      $this->_params['contribution_status_id'] = 1;
-      $this->_params['invoice_id'] = $this->_params['invoiceID'];
+      $this->_params['contribution_status_id'] = $result['payment_status_id'];
       $this->_params['trxn_id'] = $result['trxn_id'];
       $this->_params['payment_instrument_id'] = 1;
       $this->_params['is_test'] = ($this->_mode == 'live') ? 0 : 1;
@@ -586,16 +529,6 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
 
     $renewalDate = !empty($this->_params['renewal_date']) ? $renewalDate = CRM_Utils_Date::processDate($this->_params['renewal_date']) : NULL;
 
-    // This set is probably obsolete.
-    $this->set('renewalDate', $renewalDate);
-
-    $this->_membershipId = $this->_id;
-
-    $customFieldsFormatted = CRM_Core_BAO_CustomField::postProcess($this->_params,
-      $this->_id,
-      'Membership'
-    );
-
     // check for test membership.
     $isTestMembership = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_membershipId, 'is_test');
 
@@ -606,6 +539,7 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
     }
 
     //if contribution status is pending then set pay later
+    $this->_params['is_pay_later'] = FALSE;
     if ($this->_params['contribution_status_id'] == array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus())) {
       $this->_params['is_pay_later'] = 1;
     }
@@ -617,23 +551,15 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
     if (!empty($this->_params['membership_source'])) {
       $membershipSource = $this->_params['membership_source'];
     }
-    $isPayLater = NULL;
-    if (isset($this->_params)) {
-      $isPayLater = CRM_Utils_Array::value('is_pay_later', $this->_params);
-    }
-    $campaignId = NULL;
-    if (isset($this->_values) && is_array($this->_values) && !empty($this->_values)) {
-      $campaignId = CRM_Utils_Array::value('campaign_id', $this->_params);
-      if (!array_key_exists('campaign_id', $this->_params)) {
-        $campaignId = CRM_Utils_Array::value('campaign_id', $this->_values);
-      }
-    }
+
+    $isPending = ($this->_params['contribution_status_id'] == 2) ? TRUE :FALSE;
 
     list($renewMembership) = CRM_Member_BAO_Membership::renewMembership(
       $this->_contactID, $this->_params['membership_type_id'][1], $isTestMembership,
       $renewalDate, NULL, $customFieldsFormatted, $numRenewTerms, $this->_membershipId,
-      self::extractPendingFormValue($this, $this->_params['membership_type_id'][1]),
-      $contributionRecurID, $membershipSource, $isPayLater, $campaignId
+      $isPending,
+      $contributionRecurID, $membershipSource, $this->_params['is_pay_later'], CRM_Utils_Array::value('campaign_id',
+      $this->_params)
     );
 
     $endDate = CRM_Utils_Date::processDate($renewMembership->end_date);
@@ -721,16 +647,13 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
       if (!empty($this->_params['contribution_id'])) {
         $this->assign('contributionID', $this->_params['contribution_id']);
       }
-      $this->assign('membershipID', $this->_id);
-      $this->assign('contactID', $this->_contactID);
-      $this->assign('module', 'Membership');
-      $this->assign('receiptType', 'membership renewal');
-      $this->assign('mem_start_date', CRM_Utils_Date::customFormat($renewMembership->start_date));
-      $this->assign('mem_end_date', CRM_Utils_Date::customFormat($renewMembership->end_date));
+
       $this->assign('membership_name', CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType',
         $renewMembership->membership_type_id
       ));
       $this->assign('customValues', $customValues);
+      $this->assign('mem_start_date', CRM_Utils_Date::customFormat($renewMembership->start_date));
+      $this->assign('mem_end_date', CRM_Utils_Date::customFormat($renewMembership->end_date));
       if ($this->_mode) {
         // assign the address formatted up for display
         $addressParts = array(
@@ -817,4 +740,36 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
     $this->assign('billingName', $name);
   }
 
+  /**
+   * Add the billing address to the contact who paid.
+   */
+  protected function processBillingAddress() {
+    $fields = array();
+
+    // set email for primary location.
+    $fields['email-Primary'] = 1;
+    $this->_params['email-5'] = $this->_params['email-Primary'] = $this->_contributorEmail;
+
+    // also add location name to the array
+    $this->_params["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $this->_params) . ' ' . CRM_Utils_Array::value('billing_middle_name', $this->_params) . ' ' . CRM_Utils_Array::value('billing_last_name', $this->_params);
+
+    $this->_params["address_name-{$this->_bltID}"] = trim($this->_params["address_name-{$this->_bltID}"]);
+
+    $fields["address_name-{$this->_bltID}"] = 1;
+    $fields["email-{$this->_bltID}"] = 1;
+
+    list($hasBillingField, $addressParams) = CRM_Contribute_BAO_Contribution::getPaymentProcessorReadyAddressParams($this->_params, $this->_bltID);
+
+    $addressParams['preserveDBName'] = TRUE;
+    if ($hasBillingField) {
+      $addressParams = array_merge($this->_params, $addressParams);
+      //here we are setting up the billing contact - if different from the member they are already created
+      // but they will get billing details assigned
+      CRM_Contact_BAO_Contact::createProfileContact($addressParams, $fields,
+        $this->_contributorContactID, NULL, NULL,
+        CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type')
+      );
+    }
+  }
+
 }
index 0b8d6467d8d35f4f45913afd4d5d0844fdf57edb..4811c80fac011b87b39d186eadbc6b0072035d95 100644 (file)
@@ -82,7 +82,7 @@
       else if (subName && subName != 'null') {
         fname += subName;
       }
-      
+
       CRM.loadPage(dataUrl, {target: fname});
     };
   })(CRM.$);
index 5367dfc080d5c7a5f408b54ba72edd95ddb48e88..1980689fa186b7e397a0d67c33f8ad2525a7eddc 100644 (file)
@@ -141,6 +141,7 @@ class CRM_Member_Form_MembershipRenewalTest extends CiviUnitTestCase {
         'civicrm_membership_type',
         'civicrm_membership',
         'civicrm_uf_match',
+        'civicrm_address',
       )
     );
     $this->callAPISuccess('contact', 'delete', array('id' => 17, 'skip_undelete' => TRUE));
@@ -272,6 +273,171 @@ class CRM_Member_Form_MembershipRenewalTest extends CiviUnitTestCase {
       'contribution_id' => $contribution['id'],
     ), 1);
 
+    $this->callAPISuccessGetSingle('address', array(
+      'contact_id' => $this->_individualId,
+      'street_address' => '10 Test St',
+       'postal_code' => 90210,
+    ));
+  }
+
+  /**
+   * Test the submit function of the membership form.
+   */
+  public function testSubmitPayLater() {
+    $form = $this->getForm(NULL);
+    $this->createLoggedInUser();
+    $originalMembership = $this->callAPISuccessGetSingle('membership', array());
+    $params = array(
+      'cid' => $this->_individualId,
+      'join_date' => date('m/d/Y', time()),
+      'start_date' => '',
+      'end_date' => '',
+      // This format reflects the 23 being the organisation & the 25 being the type.
+      'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID),
+      'auto_renew' => '0',
+      'max_related' => '',
+      'num_terms' => '2',
+      'source' => '',
+      'total_amount' => '50.00',
+      //Member dues, see data.xml
+      'financial_type_id' => '2',
+      'soft_credit_type_id' => '',
+      'soft_credit_contact_id' => '',
+      'payment_instrument_id' => 4,
+      'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
+      'receipt_text_signup' => 'Thank you text',
+      'payment_processor_id' => $this->_paymentProcessorID,
+      'record_contribution' => TRUE,
+      'trxn_id' => 777,
+      'contribution_status_id' => 2,
+    );
+    $form->_contactID = $this->_individualId;
+
+    $form->testSubmit($params);
+    $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
+    $this->assertEquals(strtotime($membership['end_date']), strtotime($originalMembership['end_date']));
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array(
+      'contact_id' => $this->_individualId,
+      'contribution_status_id' => 2,
+    ));
+    $this->assertEquals($contribution['trxn_id'], 777);
+
+    $this->callAPISuccessGetCount('LineItem', array(
+      'entity_id' => $membership['id'],
+      'entity_table' => 'civicrm_membership',
+      'contribution_id' => $contribution['id'],
+    ), 1);
+  }
+
+  /**
+   * Test the submit function of the membership form.
+   */
+  public function testSubmitPayLaterWithBilling() {
+    $form = $this->getForm(NULL);
+    $this->createLoggedInUser();
+    $originalMembership = $this->callAPISuccessGetSingle('membership', array());
+    $params = array(
+      'cid' => $this->_individualId,
+      'join_date' => date('m/d/Y', time()),
+      'start_date' => '',
+      'end_date' => '',
+      // This format reflects the 23 being the organisation & the 25 being the type.
+      'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID),
+      'auto_renew' => '0',
+      'max_related' => '',
+      'num_terms' => '2',
+      'source' => '',
+      'total_amount' => '50.00',
+      //Member dues, see data.xml
+      'financial_type_id' => '2',
+      'soft_credit_type_id' => '',
+      'soft_credit_contact_id' => '',
+      'payment_instrument_id' => 4,
+      'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
+      'receipt_text_signup' => 'Thank you text',
+      'payment_processor_id' => $this->_paymentProcessorID,
+      'record_contribution' => TRUE,
+      'trxn_id' => 777,
+      'contribution_status_id' => 2,
+      'billing_first_name' => 'Test',
+      'billing_middlename' => 'Last',
+      'billing_street_address-5' => '10 Test St',
+      'billing_city-5' => 'Test',
+      'billing_state_province_id-5' => '1003',
+      'billing_postal_code-5' => '90210',
+      'billing_country_id-5' => '1228',
+    );
+    $form->_contactID = $this->_individualId;
+
+    $form->testSubmit($params);
+    $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
+    $this->assertEquals(strtotime($membership['end_date']), strtotime($originalMembership['end_date']));
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array(
+      'contact_id' => $this->_individualId,
+      'contribution_status_id' => 2,
+    ));
+    $this->assertEquals($contribution['trxn_id'], 777);
+
+    $this->callAPISuccessGetCount('LineItem', array(
+      'entity_id' => $membership['id'],
+      'entity_table' => 'civicrm_membership',
+      'contribution_id' => $contribution['id'],
+    ), 1);
+    $this->callAPISuccessGetSingle('address', array(
+      'contact_id' => $this->_individualId,
+      'street_address' => '10 Test St',
+      'postal_code' => 90210,
+    ));
+  }
+
+  /**
+   * Test the submit function of the membership form.
+   */
+  public function testSubmitComplete() {
+    $form = $this->getForm(NULL);
+    $this->createLoggedInUser();
+    $originalMembership = $this->callAPISuccessGetSingle('membership', array());
+    $params = array(
+      'cid' => $this->_individualId,
+      'join_date' => date('m/d/Y', time()),
+      'start_date' => '',
+      'end_date' => '',
+      // This format reflects the 23 being the organisation & the 25 being the type.
+      'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID),
+      'auto_renew' => '0',
+      'max_related' => '',
+      'num_terms' => '2',
+      'source' => '',
+      'total_amount' => '50.00',
+      //Member dues, see data.xml
+      'financial_type_id' => '2',
+      'soft_credit_type_id' => '',
+      'soft_credit_contact_id' => '',
+      'payment_instrument_id' => 4,
+      'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
+      'receipt_text_signup' => 'Thank you text',
+      'payment_processor_id' => $this->_paymentProcessorID,
+      'record_contribution' => TRUE,
+      'trxn_id' => 777,
+      'contribution_status_id' => 1,
+    );
+    $form->_contactID = $this->_individualId;
+
+    $form->testSubmit($params);
+    $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
+    $this->assertEquals(strtotime($membership['end_date']), strtotime('+ 2 years',
+      strtotime($originalMembership['end_date'])));
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array(
+      'contact_id' => $this->_individualId,
+      'contribution_status_id' => 1,
+    ));
+
+    $this->assertEquals($contribution['trxn_id'], 777);
+    $this->callAPISuccessGetCount('LineItem', array(
+      'entity_id' => $membership['id'],
+      'entity_table' => 'civicrm_membership',
+      'contribution_id' => $contribution['id'],
+    ), 1);
   }
 
   /**
@@ -279,14 +445,16 @@ class CRM_Member_Form_MembershipRenewalTest extends CiviUnitTestCase {
    *
    * We need to instantiate the form to run preprocess, which means we have to trick it about the request method.
    *
+   * @param string $mode
+   *
    * @return \CRM_Member_Form_MembershipRenewal
    */
-  protected function getForm() {
+  protected function getForm($mode = 'test') {
     $form = new CRM_Member_Form_MembershipRenewal();
     $_SERVER['REQUEST_METHOD'] = 'GET';
     $form->controller = new CRM_Core_Controller();
     $form->_bltID = 5;
-    $form->_mode = 'test';
+    $form->_mode = $mode;
     $form->_id = $this->_membershipID;
     $form->preProcess();
     return $form;