CRM-17636 fix for items not being recorded correctly (modified_date, invoice_id,...
[civicrm-core.git] / CRM / Member / Form.php
index 47b220cd5bbd726522cbf533c0d7706970f11d0c..cea4b87d49c3e08292ce631b0b15a5e21c9a9cf1 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.6                                                |
+ | CiviCRM version 4.7                                                |
  +--------------------------------------------------------------------+
  | Copyright CiviCRM LLC (c) 2004-2015                                |
  +--------------------------------------------------------------------+
@@ -29,8 +29,6 @@
  *
  * @package CRM
  * @copyright CiviCRM LLC (c) 2004-2015
- * $Id$
- *
  */
 
 /**
@@ -58,26 +56,63 @@ class CRM_Member_Form extends CRM_Contribute_Form_AbstractEditPayment {
    */
   protected $_fromEmails = array();
 
-  public function preProcess() {
-    $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'add');
-    $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'membership');
-    $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
-    $this->_contactID = CRM_Utils_Request::retrieve('cid', 'Positive', $this);
-    $this->_mode = CRM_Utils_Request::retrieve('mode', 'String', $this);
+  /**
+   * Details of all enabled membership types.
+   *
+   * @var array
+   */
+  protected $allMembershipTypeDetails = array();
 
-    $this->assign('context', $this->_context);
-    $this->assign('membershipMode', $this->_mode);
-    $this->assign('contactID', $this->_contactID);
+  /**
+   * Array of membership type IDs and whether they permit autorenewal.
+   *
+   * @var array
+   */
+  protected $membershipTypeRenewalStatus = array();
 
-    if ($this->_mode) {
-      $this->assignPaymentRelatedVariables();
+  /**
+   * Price set ID configured for the form.
+   *
+   * @var int
+   */
+  public $_priceSetId;
+
+  /**
+   * Price set details as an array.
+   *
+   * @var array
+   */
+  public $_priceSet;
+
+  /**
+   * Values submitted to the form, processed along the way.
+   *
+   * @var array
+   */
+  protected $_params = array();
+
+  public function preProcess() {
+    // Check for edit permission.
+    if (!CRM_Core_Permission::checkActionPermission('CiviMember', $this->_action)) {
+      CRM_Core_Error::fatal(ts('You do not have permission to access this page.'));
     }
+    parent::preProcess();
+    $params = array();
+    $params['context'] = CRM_Utils_Request::retrieve('context', 'String', $this, FALSE, 'membership');
+    $params['id'] = CRM_Utils_Request::retrieve('id', 'Positive', $this);
+    $params['mode'] = CRM_Utils_Request::retrieve('mode', 'String', $this);
 
-    if ($this->_id) {
-      $this->_memType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_id, 'membership_type_id');
-      $this->_membershipIDs[] = $this->_id;
+    $this->setContextVariables($params);
+
+    $this->assign('context', $this->_context);
+    $this->assign('membershipMode', $this->_mode);
+    $this->allMembershipTypeDetails = CRM_Member_BAO_Membership::buildMembershipTypeValues($this, array(), TRUE);
+    foreach ($this->allMembershipTypeDetails as $index => $membershipType) {
+      if ($membershipType['auto_renew']) {
+        $this->_recurMembershipTypes[$index] = $membershipType;
+        $this->membershipTypeRenewalStatus[$index] = $membershipType['auto_renew'];
+      }
     }
-    $this->_fromEmails = CRM_Core_BAO_Email::getFromEmail();
   }
 
   /**
@@ -93,14 +128,13 @@ class CRM_Member_Form extends CRM_Contribute_Form_AbstractEditPayment {
     if (isset($this->_id)) {
       $params = array('id' => $this->_id);
       CRM_Member_BAO_Membership::retrieve($params, $defaults);
-    }
+      if (isset($defaults['minimum_fee'])) {
+        $defaults['minimum_fee'] = CRM_Utils_Money::format($defaults['minimum_fee'], NULL, '%a');
+      }
 
-    if (isset($defaults['minimum_fee'])) {
-      $defaults['minimum_fee'] = CRM_Utils_Money::format($defaults['minimum_fee'], NULL, '%a');
-    }
-
-    if (isset($defaults['status'])) {
-      $this->assign('membershipStatus', $defaults['status']);
+      if (isset($defaults['status'])) {
+        $this->assign('membershipStatus', $defaults['status']);
+      }
     }
 
     if ($this->_action & CRM_Core_Action::ADD) {
@@ -119,10 +153,9 @@ class CRM_Member_Form extends CRM_Contribute_Form_AbstractEditPayment {
 
   /**
    * Build the form object.
-   *
-   * @return void
    */
   public function buildQuickForm() {
+
     if ($this->_mode) {
       $this->add('select', 'payment_processor_id',
         ts('Payment Processor'),
@@ -131,6 +164,32 @@ class CRM_Member_Form extends CRM_Contribute_Form_AbstractEditPayment {
       );
       CRM_Core_Payment_Form::buildPaymentForm($this, $this->_paymentProcessor, FALSE, TRUE);
     }
+    // Build the form for auto renew. This is displayed when in credit card mode or update mode.
+    // The reason for showing it in update mode is not that clear.
+    if ($this->_mode || ($this->_action & CRM_Core_Action::UPDATE)) {
+      if (!empty($this->_recurPaymentProcessors)) {
+        $this->assign('allowAutoRenew', TRUE);
+      }
+
+      $autoRenewElement = $this->addElement('checkbox', 'auto_renew', ts('Membership renewed automatically'),
+        NULL, array('onclick' => "showHideByValue('auto_renew','','send-receipt','table-row','radio',true); showHideNotice( );")
+      );
+      if ($this->_action & CRM_Core_Action::UPDATE) {
+        $autoRenewElement->freeze();
+      }
+
+      $this->assign('recurProcessor', json_encode($this->_recurPaymentProcessors));
+      $this->addElement('checkbox',
+        'auto_renew',
+        ts('Membership renewed automatically'),
+        NULL,
+        array('onclick' => "buildReceiptANDNotice( );")
+      );
+
+      $this->assignPaymentRelatedVariables();
+    }
+    $this->assign('autoRenewOptions', json_encode($this->membershipTypeRenewalStatus));
+
     if ($this->_action & CRM_Core_Action::RENEW) {
       $this->addButtons(array(
           array(
@@ -223,6 +282,38 @@ class CRM_Member_Form extends CRM_Contribute_Form_AbstractEditPayment {
     }
   }
 
+  /**
+   * Set variables in a way that can be accessed from different places.
+   *
+   * This is part of refactoring for unit testability on the submit function.
+   *
+   * @param array $params
+   */
+  protected function setContextVariables($params) {
+    $variables = array(
+      'action' => '_action',
+      'context' => '_context',
+      'id' => '_id',
+      'cid' => '_contactID',
+      'mode' => '_mode',
+    );
+    foreach ($variables as $paramKey => $classVar) {
+      if (isset($params[$paramKey]) && !isset($this->$classVar)) {
+        $this->$classVar = $params[$paramKey];
+      }
+    }
+
+    if ($this->_mode) {
+      $this->assignPaymentRelatedVariables();
+    }
+
+    if ($this->_id) {
+      $this->_memType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_id, 'membership_type_id');
+      $this->_membershipIDs[] = $this->_id;
+    }
+    $this->_fromEmails = CRM_Core_BAO_Email::getFromEmail();
+  }
+
   /**
    * Create a recurring contribution record.
    *
@@ -239,13 +330,13 @@ class CRM_Member_Form extends CRM_Contribute_Form_AbstractEditPayment {
     $contributionRecurParams = array(
       'contact_id' => $paymentParams['contactID'],
       'amount' => $paymentParams['total_amount'],
+      'contribution_status_id' => 'Pending',
       'payment_processor_id' => $paymentParams['payment_processor_id'],
-      'campaign_id' => CRM_Utils_Array::value('campaign_id', $paymentParams),
+      'campaign_id' => $paymentParams['campaign_id'],
       'financial_type_id' => $paymentParams['financial_type_id'],
-      'is_email_receipt' => CRM_Utils_Array::value('is_email_receipt', $paymentParams),
-      // This is not great as it could also be direct debit - but is consistent with elsewhere & all need fixing.
-      'payment_instrument_id' => 1,
-      'invoice_id' => CRM_Utils_Array::value('invoiceID ', $paymentParams),
+      'is_email_receipt' => $paymentParams['is_email_receipt'],
+      'payment_instrument_id' => $paymentParams['payment_instrument_id'],
+      'invoice_id' => $paymentParams['invoice_id'],
     );
 
     $mapping = array(
@@ -268,4 +359,110 @@ class CRM_Member_Form extends CRM_Contribute_Form_AbstractEditPayment {
     return $returnParams;
   }
 
+  /**
+   * Ensure price parameters are set.
+   *
+   * If they are not set it means a quick config option has been chosen so we
+   * fill them in here to make the two flows the same. They look like 'price_2' => 2 etc.
+   *
+   * @param array $formValues
+   */
+  protected function ensurePriceParamsAreSet(&$formValues) {
+    foreach ($formValues as $key => $value) {
+      if ((substr($key, 0, 6) == 'price_') && is_int(substr($key, 7))) {
+        return;
+      }
+    }
+    $priceFields = CRM_Member_BAO_Membership::setQuickConfigMembershipParameters(
+      $formValues['membership_type_id'][0],
+      $formValues['membership_type_id'][1],
+      $formValues['total_amount'],
+      $this->_priceSetId
+    );
+    $formValues = array_merge($formValues, $priceFields['price_fields']);
+  }
+
+  /**
+   * Get the details for the selected price set.
+   *
+   * @param array $params
+   *   Parameters submitted to the form.
+   *
+   * @return array
+   */
+  protected static function getPriceSetDetails($params) {
+    $priceSetID = CRM_Utils_Array::value('price_set_id', $params);
+    if ($priceSetID) {
+      return CRM_Price_BAO_PriceSet::getSetDetail($priceSetID);
+    }
+    else {
+      $priceSet = CRM_Price_BAO_PriceSet::getDefaultPriceSet('membership');
+      $priceSet = reset($priceSet);
+      return CRM_Price_BAO_PriceSet::getSetDetail($priceSet['setID']);
+    }
+  }
+
+  /**
+   * Get the selected price set id.
+   *
+   * @param array $params
+   *   Parameters submitted to the form.
+   *
+   * @return int
+   */
+  protected static function getPriceSetID($params) {
+    $priceSetID = CRM_Utils_Array::value('price_set_id', $params);
+    if (!$priceSetID) {
+      $priceSetDetails = self::getPriceSetDetails($params);
+      return key($priceSetDetails);
+    }
+    return $priceSetID;
+  }
+
+  /**
+   * Store parameters relating to price sets.
+   *
+   * @param array $formValues
+   *
+   * @return array
+   */
+  protected function setPriceSetParameters($formValues) {
+    $this->_priceSetId = self::getPriceSetID($formValues);
+    $priceSetDetails = self::getPriceSetDetails($formValues);
+    $this->_priceSet = $priceSetDetails[$this->_priceSetId];
+    // process price set and get total amount and line items.
+    $this->ensurePriceParamsAreSet($formValues);
+    return $formValues;
+  }
+
+  /**
+   * Assign billing name to the template.
+   */
+  protected function assignBillingName() {
+    $name = '';
+    if (!empty($this->_params['billing_first_name'])) {
+      $name = $this->_params['billing_first_name'];
+    }
+
+    if (!empty($this->_params['billing_middle_name'])) {
+      $name .= " {$this->_params['billing_middle_name']}";
+    }
+
+    if (!empty($this->_params['billing_last_name'])) {
+      $name .= " {$this->_params['billing_last_name']}";
+    }
+    $this->assign('billingName', $name);
+  }
+
+  /**
+   * Wrapper function for unit tests.
+   *
+   * @param array $formValues
+   */
+  public function testSubmit($formValues) {
+    $this->_memType = $formValues['membership_type_id'][1];
+    $this->_params = $formValues;
+    $this->submit();
+  }
+
 }