Merge pull request #2062 from dlobo/CRM-13806
[civicrm-core.git] / CRM / Member / BAO / Membership.php
index ef46e7d16f40e70d7d8566c3addb24f95f968aec..5ba8d740fc1dea05300ad38f32a019a7cc9a7938 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.3                                                |
+ | CiviCRM version 4.4                                                |
  +--------------------------------------------------------------------+
  | Copyright CiviCRM LLC (c) 2004-2013                                |
  +--------------------------------------------------------------------+
@@ -66,9 +66,6 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
    */
   static function &add(&$params, &$ids) {
 
-    // get activity types for use in activity record creation
-    $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, FALSE, FALSE, 'name');
-
     if (CRM_Utils_Array::value('membership', $ids)) {
       CRM_Utils_Hook::pre('edit', 'Membership', $ids['membership'], $params);
       $oldStatus         = NULL;
@@ -96,7 +93,6 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
     $membership->save();
     $membership->free();
 
-    $session = CRM_Core_Session::singleton();
     if (empty($membership->contact_id) || empty($membership->status_id)) {
       // this means we are in renewal mode and are just updating the membership
       // record or this is an API update call and all fields are not present in the update record
@@ -142,40 +138,32 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
 
     if (CRM_Utils_Array::value('membership', $ids)) {
       if ($membership->status_id != $oldStatus) {
-        $allStatus     = CRM_Member_PseudoConstant::membershipStatus();
+        $allStatus = CRM_Member_BAO_Membership::buildOptions('status_id', 'get');
         $activityParam = array(
           'subject' => "Status changed from {$allStatus[$oldStatus]} to {$allStatus[$membership->status_id]}",
           'source_contact_id' => $membershipLog['modified_id'],
           'target_contact_id' => $membership->contact_id,
           'source_record_id' => $membership->id,
-          'activity_type_id' => array_search('Change Membership Status', $activityTypes),
+          'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Change Membership Status'),
           'status_id' => 2,
-          'version' => 3,
           'priority_id' => 2,
           'activity_date_time' => date('Y-m-d H:i:s'),
-          'is_auto' => 0,
-          'is_current_revision' => 1,
-          'is_deleted' => 0,
         );
-        $activityResult = civicrm_api('activity', 'create', $activityParam);
+        civicrm_api3('activity', 'create', $activityParam);
       }
       if (isset($membership->membership_type_id) && $membership->membership_type_id != $oldType) {
-        $membershipTypes = CRM_Member_PseudoConstant::membershipType();
+        $membershipTypes = CRM_Member_BAO_Membership::buildOptions('membership_type_id', 'get');
         $activityParam = array(
           'subject' => "Type changed from {$membershipTypes[$oldType]} to {$membershipTypes[$membership->membership_type_id]}",
           'source_contact_id' => $membershipLog['modified_id'],
           'target_contact_id' => $membership->contact_id,
           'source_record_id' => $membership->id,
-          'activity_type_id' => array_search('Change Membership Type', $activityTypes),
+          'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Change Membership Type'),
           'status_id' => 2,
-          'version' => 3,
           'priority_id' => 2,
           'activity_date_time' => date('Y-m-d H:i:s'),
-          'is_auto' => 0,
-          'is_current_revision' => 1,
-          'is_deleted' => 0,
         );
-        $activityResult = civicrm_api('activity', 'create', $activityParam);
+        civicrm_api3('activity', 'create', $activityParam);
       }
       CRM_Utils_Hook::post('edit', 'Membership', $membership->id, $membership);
     }
@@ -248,7 +236,7 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
     ) {
       $dates = array('start_date', 'end_date', 'join_date');
       foreach ($dates as $date) {
-        $$date = CRM_Utils_Date::processDate(CRM_Utils_Array::value($date, $params), NULL, TRUE, 'Ymd');
+        $$date = $params[$date] = CRM_Utils_Date::processDate(CRM_Utils_Array::value($date, $params), NULL, TRUE, 'Ymd');
       }
 
       //fix for CRM-3570, during import exclude the statuses those having is_admin = 1
@@ -261,24 +249,21 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
         $excludeIsAdmin = TRUE;
       }
 
-      $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($start_date, $end_date, $join_date,
+      $calcStatus = $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($start_date, $end_date, $join_date,
         'today', $excludeIsAdmin
       );
       if (empty($calcStatus)) {
-        if (!$skipRedirect) {
-          // Redirect the form in case of error
-          CRM_Core_Session::setStatus(ts('The membership cannot be saved.') .
-            '<br/>' .
-            ts('No valid membership status for given dates.'),
-          ts('Save Error'), 'error');
-          return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view',
-              "reset=1&force=1&cid={$params['contact_id']}&selectedChild=member"
-            ));
-        }
-        // Return the error message to the api
-        $error = array();
-        $error['is_error'] = ts('The membership cannot be saved. No valid membership status for given dates. Please provide at least start_date. Optionally end_date and join_date.');
-        return $error;
+        // Redirect the form in case of error
+        // @todo this redirect in the BAO layer is really bad & should be moved to the form layer
+        // however since we have no idea how (if) this is triggered we can't safely move / remove it
+        // NB I tried really hard to trigger this error from backoffice membership form in order to test it
+        // and am convinced form validation is complete on that form WRT this error.
+        $errorParams = array(
+          'message_title' => ts('No valid membership status for given dates.'),
+          'legacy_redirect_path' => 'civicrm/contact/view',
+          'legacy_redirect_query' => "reset=1&force=1&cid={$params['contact_id']}&selectedChild=member",
+        );
+        throw new CRM_Core_Exception(ts('The membership cannot be saved because the status cannot be calculated.'), 0, $errorParams);
       }
       $params['status_id'] = $calcStatus['id'];
     }
@@ -325,7 +310,8 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
 
     //record contribution for this membership
     if (CRM_Utils_Array::value('contribution_status_id', $params) && !CRM_Utils_Array::value('relate_contribution_id', $params)) {
-      $params['contribution'] = self::recordMembershipContribution( $params, $ids, $membership->id );
+      $memInfo = array_merge($params, array('membership_id' => $membership->id));
+      $params['contribution'] = self::recordMembershipContribution($memInfo, $ids);
     }
 
     //insert payment record for this membership
@@ -568,6 +554,23 @@ INNER JOIN  civicrm_membership_type type ON ( type.id = membership.membership_ty
     return $values;
   }
 
+  /**
+   * Function to delete membership.
+   * Wrapper for most delete calls. Use this unless you JUST want to delete related memberships w/o deleting the parent.
+   *
+   * @param int $membershipId membership id that needs to be deleted
+   *
+   * @static
+   *
+   * @return $results   no of deleted Membership on success, false otherwise
+   * @access public
+   */
+  static function del($membershipId) {
+    //delete related first and then delete parent.
+    self::deleteRelatedMemberships($membershipId);
+    return self::deleteMembership($membershipId);
+  }
+
   /**
    * Function to delete membership.
    *
@@ -583,6 +586,7 @@ INNER JOIN  civicrm_membership_type type ON ( type.id = membership.membership_ty
     $params = array('id' => $membershipId);
     $memValues = array();
     $memberships = self::getValues($params, $memValues);
+
     $membership = $memberships[$membershipId];
 
     CRM_Utils_Hook::pre('delete', 'Membership', $membershipId, $memValues);
@@ -630,6 +634,36 @@ INNER JOIN  civicrm_membership_type type ON ( type.id = membership.membership_ty
     return $results;
   }
 
+  /**
+   * Function to delete related memberships
+   *
+   * @param int $ownerMembershipId
+   * @param int $contactId
+   *
+   * @return null
+   * @static
+   */
+  static function deleteRelatedMemberships($ownerMembershipId, $contactId = NULL) {
+    if (!$ownerMembershipId && !$contactId) {
+      return;
+    }
+
+    $membership = new CRM_Member_DAO_Membership();
+    $membership->owner_membership_id = $ownerMembershipId;
+
+    if ($contactId) {
+      $membership->contact_id = $contactId;
+    }
+
+    $membership->find();
+    while ($membership->fetch()) {
+      //delete related first and then delete parent.
+      self::deleteRelatedMemberships($membership->id);
+      self::deleteMembership($membership->id);
+    }
+    $membership->free();
+  }
+
   /**
    * Function to obtain active/inactive memberships from the list of memberships passed to it.
    *
@@ -676,23 +710,16 @@ INNER JOIN  civicrm_membership_type type ON ( type.id = membership.membership_ty
    */
   static function buildMembershipBlock(&$form,
     $pageID,
+    $cid,
     $formItems = FALSE,
     $selectedMembershipTypeID = NULL,
     $thankPage = FALSE,
-    $isTest = NULL,
-    $memberContactId = NULL
+    $isTest = NULL
   ) {
 
     $separateMembershipPayment = FALSE;
     if ($form->_membershipBlock) {
       $form->_currentMemberships = array();
-      if (!$memberContactId) {
-        $session = CRM_Core_Session::singleton();
-        $cid = $session->get('userID');
-      }
-      else {
-        $cid = $memberContactId;
-      }
 
       $membershipBlock    = $form->_membershipBlock;
       $membershipTypeIds  = $membershipTypes = $radio = array();
@@ -1183,13 +1210,7 @@ AND civicrm_membership.is_test = %2";
   static function statusAvailabilty($contactId) {
     $membership = new CRM_Member_DAO_MembershipStatus();
     $membership->whereAdd('is_active=1');
-    $count = $membership->count();
-
-    if (!$count) {
-      $session = CRM_Core_Session::singleton();
-      CRM_Core_Session::setStatus(ts('There are no status present, You cannot add membership.'), ts('Deleted'), 'error');
-      return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view', "reset=1&force=1&cid={$contactId}&selectedChild=member"));
-    }
+    return $membership->count();
   }
 
   /**
@@ -1417,11 +1438,14 @@ AND civicrm_membership.is_test = %2";
         }
       }
       $message = ts('Payment Processor Error message') . ': ' . implode('<br/>', $message);
-      $session = CRM_Core_Session::singleton();
-      $session->setStatus($message);
-      CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contribute/transact',
-          "_qf_Main_display=true&qfKey={$form->_params['qfKey']}"
-        ));
+      // Redirect the form in case of error
+      // @todo this redirect in the BAO layer is really bad & should be moved to the form layer
+      // however since we have no idea how (if) this is triggered we can't safely move / remove it
+      $errorParams = array(
+        'legacy_redirect_path' => 'civicrm/contribute/transact',
+        'legacy_redirect_query' => "_qf_Main_display=true&qfKey={$form->_params['qfKey']}",
+      );
+      throw new CRM_Core_Exception($message, 0, $errorParams);
     }
 
     // CRM-7851
@@ -1463,6 +1487,10 @@ AND civicrm_membership.is_test = %2";
   }
 
   /**
+   * @todo - this form method needs to have the interaction with the form layer removed from it
+   * as a BAO function. Note that the api now supports membership renewals & it is not clear this function does anything
+   * not done by the membership.create api (with a lot less unit tests)
+   *
    * This method will renew / create the membership depending on
    * whether the given contact has a membership or not. And will add
    * the modified dates for membership and in the log table.
@@ -1502,6 +1530,8 @@ AND civicrm_membership.is_test = %2";
 
     // check is it pending. - CRM-4555
     $pending = FALSE;
+    //@todo this is a BAO function & should not inspect the form - the form should do this
+    // & pass required params to the BAO
     if (CRM_Utils_Array::value('minimum_fee', $membershipTypeDetails) > 0.0) {
       if (((isset($form->_contributeMode) && $form->_contributeMode == 'notify') ||
           CRM_Utils_Array::value('is_pay_later', $form->_params) ||
@@ -1885,36 +1915,6 @@ SELECT c.contribution_page_id as pageID
     );
   }
 
-  /**
-   * Function to delete related memberships
-   *
-   * @param int $ownerMembershipId
-   * @param int $contactId
-   *
-   * @return null
-   * @static
-   */
-  static function deleteRelatedMemberships($ownerMembershipId, $contactId = NULL) {
-    if (!$ownerMembershipId && !$contactId) {
-      return;
-    }
-
-    $membership = new CRM_Member_DAO_Membership();
-    $membership->owner_membership_id = $ownerMembershipId;
-
-    if ($contactId) {
-      $membership->contact_id = $contactId;
-    }
-
-    $membership->find();
-    while ($membership->fetch()) {
-      //delete related first and then delete parent.
-      self::deleteRelatedMemberships($membership->id);
-      self::deleteMembership($membership->id);
-    }
-    $membership->free();
-  }
-
   /**
    * Function to updated related memberships
    *
@@ -2067,7 +2067,7 @@ WHERE  civicrm_membership.contact_id = civicrm_contact.id
 
     //lets cleanup related membership if any.
     if (empty($relatedContacts)) {
-      CRM_Member_BAO_Membership::deleteRelatedMemberships($membership->id);
+      self::deleteRelatedMemberships($membership->id);
     }
     else {
       // Edit the params array
@@ -2138,7 +2138,7 @@ WHERE  civicrm_membership.contact_id = civicrm_contact.id
         CRM_Member_BAO_Membership::create($params, $relMemIds);
               $available --;
             } else { // we have run out of inherited memberships, so delete extras
-              CRM_Member_BAO_Membership::deleteMembership($params['id']);
+              self::deleteMembership($params['id']);
             }
           // we need to first check if there will remain inherited memberships, so queue it up
           } else {
@@ -2464,6 +2464,7 @@ INNER JOIN  civicrm_contact contact ON ( contact.id = membership.contact_id AND
     $allTypes      = CRM_Member_PseudoConstant::membershipType();
     $contribStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
 
+    // get only memberships with active membership types
     $query = "
 SELECT     civicrm_membership.id                    as membership_id,
            civicrm_membership.is_override           as is_override,
@@ -2479,6 +2480,8 @@ SELECT     civicrm_membership.id                    as membership_id,
            civicrm_membership.contribution_recur_id as recur_id
 FROM       civicrm_membership
 INNER JOIN civicrm_contact ON ( civicrm_membership.contact_id = civicrm_contact.id )
+INNER JOIN civicrm_membership_type ON
+  (civicrm_membership.membership_type_id = civicrm_membership_type.id AND civicrm_membership_type.is_active = 1)
 WHERE      civicrm_membership.is_test = 0";
 
     $params = array();
@@ -2494,20 +2497,6 @@ WHERE      civicrm_membership.is_test = 0";
       // echo ".";
       $processCount++;
 
-      /**
-       $count++;
-       echo $dao->contact_id . ', '. CRM_Utils_System::memory( ) . "<p>\n";
-
-       CRM_Core_Error::debug( 'fBegin', count( $GLOBALS['_DB_DATAOBJECT']['RESULTS'] ) );
-       if ( $count > 2 ) {
-       foreach ( $GLOBALS['_DB_DATAOBJECT']['RESULTS'] as $r ) {
-       CRM_Core_Error::debug( 'r', $r->query );
-       }
-       // CRM_Core_Error::debug( 'f', $GLOBALS['_DB_DATAOBJECT']['RESULTS'] );
-       exit( );
-       }
-       **/
-
       // Put common parameters into array for easy access
       $memberParams = array(
         'id' => $dao->membership_id,
@@ -2664,13 +2653,13 @@ WHERE      civicrm_membership.is_test = 0";
    * Function to record contribution record associated with membership
    *
    * @param array  $params array of submitted params
-   * @param array  $ids    array of ids
-   * @param object $membershipId  membership id
+   * @param array  $ids (param in process of being removed - try to use params)   array of ids
    *
    * @return void
    * @static
    */
-  static function recordMembershipContribution( &$params, &$ids, $membershipId ) {
+  static function recordMembershipContribution( &$params, $ids = array()) {
+    $membershipId = $params['membership_id'];
     $contributionParams = array();
     $config = CRM_Core_Config::singleton();
     $contributionParams['currency'] = $config->defaultCurrency;