CRM-16737 spport either payment_status_id OR contribution_status_id as processor...
authorEileen McNaughton <eileen@fuzion.co.nz>
Tue, 7 Jul 2015 10:16:53 +0000 (22:16 +1200)
committerEileen McNaughton <eileen@fuzion.co.nz>
Tue, 7 Jul 2015 10:16:53 +0000 (22:16 +1200)
In 4.6 the idea is a payment processor can return payment_status_id or contribution_status_id to denote outcome of
payment, in 4.7 contribution_status_id is to be removed

CRM/Member/Form/Membership.php
tests/phpunit/api/v3/ContributionPageTest.php

index d41d8ae775bfd45497d9ac2c315df2f013a79ce6..ee8f992bbc1bdbef3ffea558ebfdd21ab7682e8c 100644 (file)
@@ -1425,6 +1425,12 @@ WHERE   id IN ( ' . implode(' , ', array_keys($membershipType)) . ' )';
       if (isset($result['contribution_status_id'])) {
         $params['contribution_status_id'] = $result['contribution_status_id'];
       }
+      elseif (isset($result['payment_status_id'])) {
+        // CRM-16737 $result['contribution_status_id'] is deprecated in favour
+        // of payment_status_id as the payment processor only knows whether the payment is complete
+        // not whether payment completes the contribution
+        $params['contribution_status_id'] = $params['payment_status_id'];
+      }
       // do what used to happen previously
       else {
         $params['contribution_status_id'] = !empty($paymentParams['is_recur']) ? 2 : 1;
index 62267179d0563b61dbc90da30e0716e5fbe8e43d..ab7fad4a39a61a63c6c819a3e024a0cb1de30e0a 100644 (file)
@@ -263,6 +263,72 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase {
    * - create another - end date should be extended
    */
   public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecur() {
+    $this->params['is_recur'] = 1;
+    $var = array();
+    $this->params['recur_frequency_unit'] = 'month';
+    $this->setUpMembershipContributionPage();
+    $dummyPP = CRM_Core_Payment::singleton('live', $this->_paymentProcessor);
+    $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_first_success'));
+
+    $submitParams = array(
+      'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
+      'id' => (int) $this->_ids['contribution_page'],
+      'amount' => 10,
+      'billing_first_name' => 'Billy',
+      'billing_middle_name' => 'Goat',
+      'billing_last_name' => 'Gruff',
+      'email' => 'billy@goat.gruff',
+      'selectMembership' => $this->_ids['membership_type'],
+      'payment_processor' => 1,
+      'credit_card_number' => '4111111111111111',
+      'credit_card_type' => 'Visa',
+      'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
+      'cvv2' => 123,
+      'is_recur' => 1,
+      'frequency_interval' => 1,
+      'frequency_unit' => 'month',
+    );
+
+    $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
+    $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
+      'contribution_page_id' => $this->_ids['contribution_page'],
+      'contribution_status_id' => 1,
+    ));
+    $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
+    $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
+    $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
+    $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
+    $this->assertEquals(1, $membership['status_id']);
+    $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
+    //@todo - check with Joe about these not existing
+    //$this->callAPISuccess('line_item', 'getsingle', array('contribution_id' => $contribution['id'], 'entity_id' => $membership['id']));
+    //renew it with processor setting completed - should extend membership
+    $submitParams['contact_id'] = $contribution['contact_id'];
+    $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_second_success'));
+    $this->callAPISuccess('contribution_page', 'submit', $submitParams);
+    $this->callAPISuccess('contribution', 'getsingle', array(
+      'id' => array('NOT IN' => array($contribution['id'])),
+      'contribution_page_id' => $this->_ids['contribution_page'],
+      'contribution_status_id' => 1,
+    ));
+    $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
+    $this->assertEquals(date('Y-m-d', strtotime('+ 1 year', strtotime($membership['end_date']))), $renewedMembership['end_date']);
+    $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
+    $this->assertEquals(2, $recurringContribution['contribution_status_id']);
+  }
+
+  /**
+   * Test submit recurring membership with immediate confirmation (IATS style).
+   *
+   * Per CRM-16737 we are deprecating the use of contribution_status_id to indicate success in favour of
+   * payment_status_id.
+   *
+   * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
+   * processor (IATS style - denoted by returning trxn_id)
+   * - the first creates a new membership, completed contribution, in progress recurring. Check these
+   * - create another - end date should be extended
+   */
+  public function testLegacySubmitMembershipPriceSetPaymentPaymentProcessorRecur() {
     $this->params['is_recur'] = 1;
     $var = array();
     $this->params['recur_frequency_unit'] = 'month';
@@ -326,6 +392,87 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase {
    * - create another - end date should NOT be extended
    */
   public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurDelayed() {
+    $this->params['is_recur'] = 1;
+    $this->params['recur_frequency_unit'] = 'month';
+    $this->setUpMembershipContributionPage();
+    $dummyPP = CRM_Core_Payment::singleton('live', $this->_paymentProcessor);
+    $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 2));
+
+    $submitParams = array(
+      'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
+      'id' => (int) $this->_ids['contribution_page'],
+      'amount' => 10,
+      'billing_first_name' => 'Billy',
+      'billing_middle_name' => 'Goat',
+      'billing_last_name' => 'Gruff',
+      'email' => 'billy@goat.gruff',
+      'selectMembership' => $this->_ids['membership_type'],
+      'payment_processor' => 1,
+      'credit_card_number' => '4111111111111111',
+      'credit_card_type' => 'Visa',
+      'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
+      'cvv2' => 123,
+      'is_recur' => 1,
+      'frequency_interval' => 1,
+      'frequency_unit' => 'month',
+    );
+
+    $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
+    $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
+      'contribution_page_id' => $this->_ids['contribution_page'],
+      'contribution_status_id' => 2,
+    ));
+    $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
+    $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
+    $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
+    $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
+    $this->assertEquals(5, $membership['status_id']);
+    //@todo - check with Joe about these not existing
+    //$this->callAPISuccess('line_item', 'getsingle', array('contribution_id' => $contribution['id'], 'entity_id' => $membership['id']));
+    $this->callAPISuccess('contribution', 'completetransaction', array(
+      'id' => $contribution['id'],
+      'trxn_id' => 'ipn_called',
+    ));
+    $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
+    //renew it with processor setting completed - should extend membership
+    $submitParams = array_merge($submitParams, array(
+        'contact_id' => $contribution['contact_id'],
+        'is_recur' => 1,
+        'frequency_interval' => 1,
+        'frequency_unit' => 'month',
+      )
+    );
+    $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 2));
+    $this->callAPISuccess('contribution_page', 'submit', $submitParams);
+    $newContribution = $this->callAPISuccess('contribution', 'getsingle', array(
+        'id' => array(
+          'NOT IN' => array($contribution['id']),
+        ),
+        'contribution_page_id' => $this->_ids['contribution_page'],
+        'contribution_status_id' => 2,
+      )
+    );
+
+    $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
+    //no renewal as the date hasn't changed
+    $this->assertEquals($membership['end_date'], $renewedMembership['end_date']);
+    $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $newContribution['contribution_recur_id']));
+    $this->assertEquals(2, $recurringContribution['contribution_status_id']);
+  }
+
+  /**
+   * Test submit recurring membership with delayed confirmation (Authorize.net style)
+   * - we process 2 membership transactions against with a recurring contribution against a contribution page with a delayed
+   * processor (Authorize.net style - denoted by NOT returning trxn_id)
+   *
+   * Per CRM-16737 we are deprecating the use of contribution_status_id to indicate success in favour of
+   * payment_status_id.
+   *
+   * - the first creates a pending membership, pending contribution, pending recurring. Check these
+   * - complete the transaction
+   * - create another - end date should NOT be extended
+   */
+  public function testLegacySubmitMembershipPriceSetPaymentPaymentProcessorRecurDelayed() {
     $this->params['is_recur'] = 1;
     $this->params['recur_frequency_unit'] = 'month';
     $this->setUpMembershipContributionPage();