Add batch update via profile for cases and refactor to use shared core classes
authorMatthew Wire <devel@mrwire.co.uk>
Thu, 14 Dec 2017 14:24:16 +0000 (23:24 +0900)
committerMatthew Wire <devel@mrwire.co.uk>
Sun, 28 Jan 2018 16:33:03 +0000 (23:33 +0700)
14 files changed:
CRM/Case/Form/Task.php
CRM/Case/Form/Task/Batch.php [new file with mode: 0644]
CRM/Case/Form/Task/PickProfile.php [new file with mode: 0644]
CRM/Case/Task.php
CRM/Contact/BAO/Contact/Utils.php
CRM/Core/BAO/UFField.php
CRM/Core/BAO/UFGroup.php
CRM/Core/Form/Task.php [new file with mode: 0644]
CRM/Core/Form/Task/Batch.php [new file with mode: 0644]
CRM/Core/Form/Task/PickProfile.php [new file with mode: 0644]
templates/CRM/Case/Form/Task/Batch.tpl [new file with mode: 0644]
templates/CRM/Case/Form/Task/PickProfile.tpl [new file with mode: 0644]
templates/CRM/Core/Form/Task/Batch.tpl [new file with mode: 0644]
templates/CRM/Core/Form/Task/PickProfile.tpl [new file with mode: 0644]

index d8e93ccfb16aa673ef7d65a94c5cebc38b2ad505..5e608ec90f458adb2477c7e481c012e7bec034cc 100644 (file)
  */
 
 /**
- *
  * @package CRM
  * @copyright CiviCRM LLC (c) 2004-2017
  */
 
 /**
- * This class generates task actions for CiviEvent.
+ * This class generates form task actions for CiviCase.
  */
-class CRM_Case_Form_Task extends CRM_Core_Form {
+class CRM_Case_Form_Task extends CRM_Core_Form_Task {
 
-  /**
-   * The task being performed
-   *
-   * @var int
-   */
-  protected $_task;
-
-  /**
-   * The additional clause that we restrict the search with
-   *
-   * @var string
-   */
-  protected $_componentClause = NULL;
-
-  /**
-   * The array that holds all the component ids
-   *
-   * @var array
-   */
-  protected $_componentIds;
-
-  /**
-   * The array that holds all the case ids
-   *
-   * @var array
-   */
-  public $_caseIds;
-
-  /**
-   * Build all the data structures needed to build the form.
-   */
-  public function preProcess() {
-    self::preProcessCommon($this);
-  }
-
-  /**
-   * @param CRM_Core_Form $form
-   * @param bool $useTable
-   */
-  public static function preProcessCommon(&$form, $useTable = FALSE) {
-    $form->_caseIds = array();
-
-    $values = $form->controller->exportValues($form->get('searchFormName'));
-
-    $form->_task = $values['task'];
-    $caseTasks = CRM_Case_Task::tasks();
-    $form->assign('taskName', $caseTasks[$form->_task]);
-
-    $ids = array();
-    if ($values['radio_ts'] == 'ts_sel') {
-      foreach ($values as $name => $value) {
-        if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) {
-          $ids[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN);
-        }
-      }
-    }
-    else {
-      $queryParams = $form->get('queryParams');
-      $query = new CRM_Contact_BAO_Query($queryParams, NULL, NULL, FALSE, FALSE,
-        CRM_Contact_BAO_Query::MODE_CASE
-      );
-      $query->_distinctComponentClause = " ( civicrm_case.id )";
-      $query->_groupByComponentClause = " GROUP BY civicrm_case.id ";
-      $result = $query->searchQuery(0, 0, NULL);
-      while ($result->fetch()) {
-        $ids[] = $result->case_id;
-      }
-    }
-
-    if (!empty($ids)) {
-      $form->_componentClause = ' civicrm_case.id IN ( ' . implode(',', $ids) . ' ) ';
-      $form->assign('totalSelectedCases', count($ids));
-    }
-
-    $form->_caseIds = $form->_componentIds = $ids;
-
-    //set the context for redirection for any task actions
-    $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $form);
-    $urlParams = 'force=1';
-    if (CRM_Utils_Rule::qfKey($qfKey)) {
-      $urlParams .= "&qfKey=$qfKey";
-    }
-
-    $session = CRM_Core_Session::singleton();
-    $searchFormName = strtolower($form->get('searchFormName'));
-    if ($searchFormName == 'search') {
-      $session->replaceUserContext(CRM_Utils_System::url('civicrm/case/search', $urlParams));
-    }
-    else {
-      $session->replaceUserContext(CRM_Utils_System::url("civicrm/contact/search/$searchFormName",
-        $urlParams
-      ));
-    }
-  }
-
-  /**
-   * Given the signer id, compute the contact id
-   * since its used for things like send email
-   */
-  public function setContactIDs() {
-    $this->_contactIds = &CRM_Core_DAO::getContactIDsFromComponent($this->_caseIds,
-      'civicrm_case_contact'
-    );
-  }
-
-  /**
-   * Simple shell that derived classes can call to add buttons to
-   * the form with a customized title for the main Submit
-   *
-   * @param string $title
-   *   Title of the main button.
-   * @param string $nextType
-   *   Button type for the form after processing.
-   * @param string $backType
-   * @param bool $submitOnce
-   */
-  public function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) {
-    $this->addButtons(array(
-        array(
-          'type' => $nextType,
-          'name' => $title,
-          'isDefault' => TRUE,
-        ),
-        array(
-          'type' => $backType,
-          'name' => ts('Cancel'),
-        ),
-      )
-    );
-  }
+  // Must be set to entity table name (eg. civicrm_participant) by child class
+  static $tableName = 'civicrm_case';
+  // Must be set to entity shortname (eg. event)
+  static $entityShortname = 'case';
 
 }
diff --git a/CRM/Case/Form/Task/Batch.php b/CRM/Case/Form/Task/Batch.php
new file mode 100644 (file)
index 0000000..77897c1
--- /dev/null
@@ -0,0 +1,118 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2017
+ */
+
+/**
+ * This class provides the functionality for batch profile update for cases
+ */
+class CRM_Case_Form_Task_Batch extends CRM_Core_Form_Task_Batch {
+
+  // Must be set to entity table name (eg. civicrm_participant) by child class
+  static $tableName = 'civicrm_case';
+  // Must be set to entity shortname (eg. event)
+  static $entityShortname = 'case';
+
+  /**
+   * Process the form after the input has been submitted and validated.
+   *
+   * @return void
+   */
+  public function postProcess() {
+    $params = $this->exportValues();
+
+    if (!isset($params['field'])) {
+      CRM_Core_Session::setStatus(ts('No updates have been saved.'), ts('Not Saved'), 'alert');
+      return;
+    }
+
+    $customFields = array();
+    $dateFields = array(
+      'case_created_date',
+      'case_start_date',
+      'case_end_date',
+      'case_modified_date',
+    );
+    foreach ($params['field'] as $key => $value) {
+      $value['id'] = $key;
+
+      if (!empty($value['case_type'])) {
+        $caseTypeId = $value['case_type_id'] = $value['case_type'][1];
+      }
+      unset($value['case_type']);
+
+      // Get the case status
+      $daoClass = 'CRM_Case_DAO_Case';
+      $caseStatus = CRM_Utils_Array::value('case_status', $value);
+      if (!$caseStatus) {
+        // default to existing status ID
+        $caseStatus = CRM_Core_DAO::getFieldValue($daoClass, $key, 'status_id');
+      }
+      $value['status_id'] = $caseStatus;
+      unset($value['case_status']);
+
+      foreach ($dateFields as $val) {
+        if (isset($value[$val])) {
+          $value[$val] = CRM_Utils_Date::processDate($value[$val]);
+        }
+      }
+      if (empty($customFields)) {
+        if (empty($value['case_type_id'])) {
+          $caseTypeId = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $key, 'case_type_id');
+        }
+
+        // case type custom data
+        $customFields = CRM_Core_BAO_CustomField::getFields('Case', FALSE, FALSE, $caseTypeId);
+
+        $customFields = CRM_Utils_Array::crmArrayMerge($customFields,
+          CRM_Core_BAO_CustomField::getFields('Case',
+            FALSE, FALSE, NULL, NULL, TRUE
+          )
+        );
+      }
+      //check for custom data
+      $value['custom'] = CRM_Core_BAO_CustomField::postProcess($params['field'][$key],
+        $key,
+        'Case',
+        $caseTypeId
+      );
+
+      $case = CRM_Case_BAO_Case::add($value);
+
+      // add custom field values
+      if (!empty($value['custom']) && is_array($value['custom'])) {
+        CRM_Core_BAO_CustomValueTable::store($value['custom'], 'civicrm_case', $case->id);
+      }
+    }
+
+    CRM_Core_Session::setStatus(ts('Your updates have been saved.'), ts('Saved'), 'success');
+  }
+
+}
diff --git a/CRM/Case/Form/Task/PickProfile.php b/CRM/Case/Form/Task/PickProfile.php
new file mode 100644 (file)
index 0000000..4dd07cf
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2017
+ */
+
+/**
+ * This class provides the functionality for batch profile update for case
+ */
+class CRM_Case_Form_Task_PickProfile extends CRM_Core_Form_Task_PickProfile {
+
+  /**
+   * Must be set to entity table name (eg. civicrm_participant) by child class
+   *
+   * @var string
+   */
+  static $tableName = 'civicrm_case';
+
+  /**
+   * Must be set to entity shortname (eg. event)
+   *
+   * @var string
+   */
+  static $entityShortname = 'case';
+
+}
index 5af2aaaf1c9d066ffcd98e8947b7fe1daf60a373..1b67e4611e836b46b889eaf0bdd850d71f03f5ea 100644 (file)
@@ -91,6 +91,14 @@ class CRM_Case_Task {
           'class' => 'CRM_Case_Form_Task_PDF',
           'result' => FALSE,
         ),
+        6 => array(
+          'title' => ts('Update multiple cases'),
+          'class' => array(
+            'CRM_Case_Form_Task_PickProfile',
+            'CRM_Case_Form_Task_Batch',
+          ),
+          'result' => FALSE,
+        ),
       );
 
       //CRM-4418, check for delete
index 662e8662271bba347e1dc841dfe1194662cc70be..c94d038fc38cca21d98f8d77fae0c461c5a0c613 100644 (file)
@@ -679,7 +679,7 @@ LEFT JOIN  civicrm_email ce ON ( ce.contact_id=c.id AND ce.is_primary = 1 )
   public static function contactDetails($componentIds, $componentName, $returnProperties = array()) {
     $contactDetails = array();
     if (empty($componentIds) ||
-      !in_array($componentName, array('CiviContribute', 'CiviMember', 'CiviEvent', 'Activity'))
+      !in_array($componentName, array('CiviContribute', 'CiviMember', 'CiviEvent', 'Activity', 'CiviCase'))
     ) {
       return $contactDetails;
     }
@@ -704,6 +704,9 @@ LEFT JOIN  civicrm_email ce ON ( ce.contact_id=c.id AND ce.is_primary = 1 )
       $compTable = 'civicrm_activity';
       $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
     }
+    elseif ($componentName == 'CiviCase') {
+      $compTable = 'civicrm_case';
+    }
     else {
       $compTable = 'civicrm_participant';
     }
@@ -723,6 +726,12 @@ LEFT JOIN  civicrm_email ce ON ( ce.contact_id=c.id AND ce.is_primary = 1 )
             $from[$value] = "
 INNER JOIN civicrm_activity_contact acs ON (acs.activity_id = {$compTable}.id AND acs.record_type_id = {$sourceID})
 INNER JOIN civicrm_contact contact ON ( contact.id = acs.contact_id )";
+          }
+          elseif ($componentName == 'CiviCase') {
+            $select[] = "contact.$property as $property";
+            $from[$value] = "
+INNER JOIN civicrm_case_contact ccs ON (ccs.case_id = {$compTable}.id)
+INNER JOIN civicrm_contact contact ON ( contact.id = ccs.contact_id )";
           }
           else {
             $select[] = "$property as $property";
index 10dccc79db1286851ed85bfbdfff1986ee062d88..cf5430293f3c2bd130e9a1aaf401f3e79089d9dd 100644 (file)
@@ -994,10 +994,7 @@ SELECT  id
         CRM_Utils_Array::remove($caseFields,
           'case_id',
           'case_type',
-          'case_start_date',
-          'case_end_date',
           'case_role',
-          'case_status',
           'case_deleted'
         );
       }
index f2e64af8018e34115bf049d7980a9403daef5821..04f33fbb37caaa3fd2da9a101c72a16a81183a9c 100644 (file)
@@ -2243,6 +2243,14 @@ AND    ( entity_id IS NULL OR entity_id <= 0 )
       $form->add('text', $name, $title, $attributes, $required);
       $form->addRule($name, ts('Please enter the duration as number of minutes (integers only).'), 'positiveInteger');
     }
+    elseif ($fieldName == 'case_status') {
+      $form->add('select', $name, $title,
+        array(
+          '' => ts('- select -'),
+        ) + CRM_Case_BAO_Case::buildOptions('case_status_id', 'create'),
+        $required
+      );
+    }
     else {
       if (substr($fieldName, 0, 3) === 'is_' or substr($fieldName, 0, 7) === 'do_not_') {
         $form->add('advcheckbox', $name, $title, $attributes, $required);
@@ -2508,25 +2516,30 @@ AND    ( entity_id IS NULL OR entity_id <= 0 )
       }
     }
 
-    //Handling Contribution Part of the batch profile
+    // Handling Contribution Part of the batch profile
     if (CRM_Core_Permission::access('CiviContribute') && $component == 'Contribute') {
       self::setComponentDefaults($fields, $componentId, $component, $defaults);
     }
 
-    //Handling Event Participation Part of the batch profile
+    // Handling Event Participation Part of the batch profile
     if (CRM_Core_Permission::access('CiviEvent') && $component == 'Event') {
       self::setComponentDefaults($fields, $componentId, $component, $defaults);
     }
 
-    //Handling membership Part of the batch profile
+    // Handling membership Part of the batch profile
     if (CRM_Core_Permission::access('CiviMember') && $component == 'Membership') {
       self::setComponentDefaults($fields, $componentId, $component, $defaults);
     }
 
-    //Handling Activity Part of the batch profile
+    // Handling Activity Part of the batch profile
     if ($component == 'Activity') {
       self::setComponentDefaults($fields, $componentId, $component, $defaults);
     }
+
+    // Handling Case Part of the batch profile
+    if (CRM_Core_Permission::access('CiviCase') && $component == 'Case') {
+      self::setComponentDefaults($fields, $componentId, $component, $defaults);
+    }
   }
 
   /**
@@ -3173,7 +3186,7 @@ AND    ( entity_id IS NULL OR entity_id <= 0 )
    */
   public static function setComponentDefaults(&$fields, $componentId, $component, &$defaults, $isStandalone = FALSE) {
     if (!$componentId ||
-      !in_array($component, array('Contribute', 'Membership', 'Event', 'Activity'))
+      !in_array($component, array('Contribute', 'Membership', 'Event', 'Activity', 'Case'))
     ) {
       return;
     }
@@ -3203,6 +3216,12 @@ AND    ( entity_id IS NULL OR entity_id <= 0 )
         $componentBAOName = 'Activity';
         $componentSubType = array('activity_type_id');
         break;
+
+      case 'Case':
+        $componentBAO = 'CRM_Case_BAO_Case';
+        $componentBAOName = 'Case';
+        $componentSubType = array('case_type_id');
+        break;
     }
 
     $values = array();
@@ -3242,6 +3261,9 @@ AND    ( entity_id IS NULL OR entity_id <= 0 )
       elseif ($name == 'membership_status') {
         $defaults[$fldName] = $values['status_id'];
       }
+      elseif ($name == 'case_status') {
+        $defaults[$fldName] = $values['case_status_id'];
+      }
       elseif (CRM_Core_BAO_CustomField::getKeyID($name, TRUE) !== array(NULL, NULL)) {
         if (empty($formattedGroupTree)) {
           //get the groupTree as per subTypes.
diff --git a/CRM/Core/Form/Task.php b/CRM/Core/Form/Task.php
new file mode 100644 (file)
index 0000000..0a92bd4
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2017
+ */
+
+/**
+ * This is a shared parent class for form task actions.
+ */
+abstract class CRM_Core_Form_Task extends CRM_Core_Form {
+
+  /**
+   * The task being performed
+   *
+   * @var int
+   */
+  protected $_task;
+
+  /**
+   * The additional clause that we restrict the search with
+   *
+   * @var string
+   */
+  protected $_componentClause = NULL;
+
+  /**
+   * The array that holds all the component ids
+   *
+   * @var array
+   */
+  protected $_componentIds;
+
+  /**
+   * The array that holds all the case ids
+   *
+   * @var array
+   */
+  public $_entityIds;
+
+  /**
+   * The array that holds all the contact ids
+   *
+   * @var array
+   */
+  public $_contactIds;
+
+  // Must be set to entity table name (eg. civicrm_participant) by child class
+  static $tableName = NULL;
+  // Must be set to entity shortname (eg. event)
+  static $entityShortname = NULL;
+
+  /**
+   * Build all the data structures needed to build the form.
+   */
+  public function preProcess() {
+    $this->_entityIds = array();
+
+    $values = $this->controller->exportValues($this->get('searchFormName'));
+
+    $this->_task = $values['task'];
+    $className = 'CRM_' . ucfirst($this::$entityShortname) . '_Task';
+    $entityTasks = $className::tasks();
+    $this->assign('taskName', $entityTasks[$this->_task]);
+
+    $ids = array();
+    if ($values['radio_ts'] == 'ts_sel') {
+      foreach ($values as $name => $value) {
+        if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) {
+          $ids[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN);
+        }
+      }
+    }
+    else {
+      $queryParams = $this->get('queryParams');
+      $sortOrder = NULL;
+      if ($this->get(CRM_Utils_Sort::SORT_ORDER)) {
+        $sortOrder = $this->get(CRM_Utils_Sort::SORT_ORDER);
+      }
+
+      $query = new CRM_Contact_BAO_Query($queryParams, NULL, NULL, FALSE, FALSE,
+        CRM_Contact_BAO_Query::MODE_CASE
+      );
+      $query->_distinctComponentClause = " ( " . $this::$tableName . ".id )";
+      $query->_groupByComponentClause = " GROUP BY " . $this::$tableName . ".id ";
+      $result = $query->searchQuery(0, 0, $sortOrder);
+      $selector = $this::$entityShortname . '_id';
+      while ($result->fetch()) {
+        $ids[] = $result->$selector;
+      }
+    }
+
+    if (!empty($ids)) {
+      $this->_componentClause = ' ' . $this::$tableName . '.id IN ( ' . implode(',', $ids) . ' ) ';
+      $this->assign('totalSelected' . ucfirst($this::$entityShortname) . 's', count($ids));
+    }
+
+    $this->_entityIds = $this->_componentIds = $ids;
+
+    //set the context for redirection for any task actions
+    $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $this);
+    $urlParams = 'force=1';
+    if (CRM_Utils_Rule::qfKey($qfKey)) {
+      $urlParams .= "&qfKey=$qfKey";
+    }
+
+    $session = CRM_Core_Session::singleton();
+    $searchFormName = strtolower($this->get('searchFormName'));
+    if ($searchFormName == 'search') {
+      $session->replaceUserContext(CRM_Utils_System::url('civicrm/' . $this::$entityShortname . '/search', $urlParams));
+    }
+    else {
+      $session->replaceUserContext(CRM_Utils_System::url("civicrm/contact/search/$searchFormName",
+        $urlParams
+      ));
+    }
+  }
+
+  /**
+   * Given the signer id, compute the contact id
+   * since its used for things like send email
+   */
+  public function setContactIDs() {
+    $this->_contactIds = &CRM_Core_DAO::getContactIDsFromComponent($this->_entityIds,
+      $this::$tableName
+    );
+  }
+
+  /**
+   * Simple shell that derived classes can call to add buttons to
+   * the form with a customized title for the main Submit
+   *
+   * @param string $title
+   *   Title of the main button.
+   * @param string $nextType
+   *   Button type for the form after processing.
+   * @param string $backType
+   * @param bool $submitOnce
+   */
+  public function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) {
+    $this->addButtons(array(
+        array(
+          'type' => $nextType,
+          'name' => $title,
+          'isDefault' => TRUE,
+        ),
+        array(
+          'type' => $backType,
+          'name' => ts('Cancel'),
+        ),
+      )
+    );
+  }
+
+}
diff --git a/CRM/Core/Form/Task/Batch.php b/CRM/Core/Form/Task/Batch.php
new file mode 100644 (file)
index 0000000..daf5f40
--- /dev/null
@@ -0,0 +1,212 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2017
+ */
+
+/**
+ * This class provides the functionality for batch profile update
+ */
+class CRM_Core_Form_Task_Batch extends CRM_Core_Form_Task {
+
+  /**
+   * The title of the group.
+   *
+   * @var string
+   */
+  protected $_title;
+
+  /**
+   * Maximum profile fields that will be displayed.
+   */
+  protected $_maxFields = 9;
+
+  /**
+   * @var array Fields that belong to this UF Group
+   */
+  protected $_fields;
+
+  // Must be set to entity table name (eg. civicrm_participant) by child class
+  static $tableName = NULL;
+  // Must be set to entity shortname (eg. event)
+  static $entityShortname = NULL;
+
+  /**
+   * Build all the data structures needed to build the form.
+   *
+   * @return void
+   */
+  public function preProcess() {
+    // initialize the task and row fields
+    parent::preProcess();
+
+    // get the contact read only fields to display.
+    $readOnlyFields = array_merge(array('sort_name' => ts('Name')),
+      CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
+        'contact_autocomplete_options',
+        TRUE, NULL, FALSE, 'name', TRUE
+      )
+    );
+    // get the read only field data.
+    $returnProperties = array_fill_keys(array_keys($readOnlyFields), 1);
+    $contactDetails = CRM_Contact_BAO_Contact_Utils::contactDetails($this->_entityIds,
+      'Civi' . ucfirst($this::$entityShortname), $returnProperties
+    );
+
+    $this->assign('contactDetails', $contactDetails);
+    $this->assign('readOnlyFields', $readOnlyFields);
+  }
+
+  /**
+   * Build the form object.
+   *
+   *
+   * @return void
+   */
+  public function buildQuickForm() {
+    $ufGroupId = $this->get('ufGroupId');
+
+    if (!$ufGroupId) {
+      throw new InvalidArgumentException('ufGroupId is missing');
+    }
+    $this->_title = ts("Update multiple %1s", array(1 => $this::$entityShortname)) . ' - ' . CRM_Core_BAO_UFGroup::getTitle($ufGroupId);
+    CRM_Utils_System::setTitle($this->_title);
+
+    $this->addDefaultButtons(ts('Save'));
+    $this->_fields = CRM_Core_BAO_UFGroup::getFields($ufGroupId, FALSE, CRM_Core_Action::VIEW);
+
+    // remove file type field and then limit fields
+    $suppressFields = FALSE;
+    $removeHtmlTypes = array('File');
+    foreach ($this->_fields as $name => $field) {
+      if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name) &&
+        in_array($this->_fields[$name]['html_type'], $removeHtmlTypes)
+      ) {
+        $suppressFields = TRUE;
+        unset($this->_fields[$name]);
+      }
+
+      //fix to reduce size as we are using this field in grid
+      if (is_array($field['attributes']) && !empty($this->_fields[$name]['attributes']['size']) && $this->_fields[$name]['attributes']['size'] > 19) {
+        //shrink class to "form-text-medium"
+        $this->_fields[$name]['attributes']['size'] = 19;
+      }
+    }
+
+    $this->_fields = array_slice($this->_fields, 0, $this->_maxFields);
+
+    $this->addButtons(array(
+      array(
+        'type' => 'submit',
+        'name' => ts('Update ' . ucfirst($this::$entityShortname) . 's)'),
+        'isDefault' => TRUE,
+      ),
+      array(
+        'type' => 'cancel',
+        'name' => ts('Cancel'),
+      ),
+    ));
+
+    $this->assign('profileTitle', $this->_title);
+    $this->assign('componentIds', $this->_entityIds);
+
+    $customFields = CRM_Core_BAO_CustomField::getFields(ucfirst($this::$entityShortname));
+    foreach ($this->_entityIds as $entityId) {
+      $typeId = CRM_Core_DAO::getFieldValue('CRM_' . ucfirst($this::$entityShortname) . '_DAO_' . ucfirst($this::$entityShortname), $entityId, $this::$entityShortname . '_type_id');
+      foreach ($this->_fields as $name => $field) {
+        if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
+          $customValue = CRM_Utils_Array::value($customFieldID, $customFields);
+          $entityColumnValue = array();
+          if (!empty($customValue['extends_entity_column_value'])) {
+            $entityColumnValue = explode(CRM_Core_DAO::VALUE_SEPARATOR,
+              $customValue['extends_entity_column_value']
+            );
+          }
+          if ((CRM_Utils_Array::value($typeId, $entityColumnValue)) ||
+            CRM_Utils_System::isNull($entityColumnValue[$typeId])
+          ) {
+            CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $entityId);
+          }
+        }
+        else {
+          // handle non custom fields
+          CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $entityId);
+        }
+      }
+    }
+
+    $this->assign('fields', $this->_fields);
+
+    // don't set the status message when form is submitted.
+    $buttonName = $this->controller->getButtonName('submit');
+    if ($suppressFields && $buttonName != '_qf_Batch_next') {
+      CRM_Core_Session::setStatus(ts("File type field(s) in the selected profile are not supported for Update multiple %1s", array(1 => $this::$entityShortname)), ts('Unsupported Field Type'), 'error');
+    }
+
+    $this->addDefaultButtons(ts('Update ' . ucfirst($this::$entityShortname) . 's'));
+
+    $taskComponent['lc'] = $this::$entityShortname;
+    $taskComponent['ucfirst'] = ucfirst($this::$entityShortname);
+    $this->assign('taskComponent', $taskComponent);
+  }
+
+  /**
+   * Set default values for the form.
+   *
+   * @return array $defaults
+   */
+  public function setDefaultValues() {
+    if (empty($this->_fields)) {
+      return array();
+    }
+
+    $defaults = array();
+    foreach ($this->_entityIds as $entityId) {
+      CRM_Core_BAO_UFGroup::setProfileDefaults(NULL, $this->_fields, $defaults, FALSE, $entityId, ucfirst($this::$entityShortname));
+    }
+
+    return $defaults;
+  }
+
+  /**
+   * Process the form after the input has been submitted and validated.
+   * Normally the child class will override this
+   *
+   * @return void
+   */
+  public function postProcess() {
+    $params = $this->exportValues();
+
+    if (!isset($params['field'])) {
+      CRM_Core_Session::setStatus(ts("No updates have been saved."), ts('Not Saved'), 'alert');
+      return;
+    }
+  }
+
+}
diff --git a/CRM/Core/Form/Task/PickProfile.php b/CRM/Core/Form/Task/PickProfile.php
new file mode 100644 (file)
index 0000000..5a68358
--- /dev/null
@@ -0,0 +1,170 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2017
+ */
+
+/**
+ * This class provides the functionality for batch profile update for case
+ */
+abstract class CRM_Core_Form_Task_PickProfile extends CRM_Core_Form_Task {
+
+  /**
+   * The title of the group
+   *
+   * @var string
+   */
+  protected $_title;
+
+  /**
+   * Maximum entities that should be allowed to update
+   *
+   * @var int
+   */
+  protected $_maxEntities = 100;
+
+  /**
+   * Variable to store redirect path
+   *
+   * @var string
+   */
+  protected $_userContext;
+
+  /**
+   * Must be set to entity table name (eg. civicrm_participant) by child class
+   *
+   * @var string
+   */
+  static $tableName = NULL;
+
+  /**
+   * Must be set to entity shortname (eg. event)
+   *
+   * @var string
+   */
+  static $entityShortname = NULL;
+
+  /**
+   * Build all the data structures needed to build the form.
+   *
+   * @return void
+   */
+  public function preProcess() {
+    // initialize the task and row fields
+    parent::preProcess();
+    $session = CRM_Core_Session::singleton();
+    $this->_userContext = $session->readUserContext();
+
+    CRM_Utils_System::setTitle(ts('Update multiple ' . $this::$entityShortname . 's'));
+
+    // validations
+    if (count($this->_entityIds) > $this->_maxEntities) {
+      CRM_Core_Session::setStatus(ts("The maximum number of %3 you can select for Update multiple %3 is %1. You have selected %2. Please select fewer %3 from your search results and try again.", array(
+        1 => $this->_maxEntities,
+        2 => count($this->_entityIds),
+        3 => $this::$entityShortname . 's',
+      )), ts('Update multiple records error'), 'error');
+      CRM_Utils_System::redirect($this->_userContext);
+    }
+  }
+
+  /**
+   * Build the form object.
+   *
+   * @return void
+   */
+  public function buildQuickForm() {
+    $types = array(ucfirst($this::$entityShortname));
+    $profiles = CRM_Core_BAO_UFGroup::getProfiles($types, TRUE);
+
+    if (empty($profiles)) {
+      CRM_Core_Session::setStatus(
+        ts("You will need to create a Profile containing the %1 fields you want to edit before you can use Update multiple %2. Navigate to Administer > Customize Data and Screens > Profiles to configure a Profile. Consult the online Administrator documentation for more information.",
+          array(
+            1 => $types[0],
+            2 => $this::$entityShortname . 's',
+          )),
+        ts('Update multiple records error'),
+        'error'
+      );
+      CRM_Utils_System::redirect($this->_userContext);
+    }
+
+    $this->add('select',
+      'uf_group_id',
+      ts('Select Profile'),
+      array(
+        '' => ts('- select profile -'),
+      ) + $profiles,
+      TRUE
+    );
+    $this->addDefaultButtons(ts('Continue'));
+
+    $taskComponent['lc'] = $this::$entityShortname;
+    $taskComponent['ucfirst'] = ucfirst($this::$entityShortname);
+    $this->assign('taskComponent', $taskComponent);
+  }
+
+  /**
+   * Add local and global form rules.
+   *
+   * @return void
+   */
+  public function addRules() {
+    $this->addFormRule(array('CRM_' . ucfirst($this::$entityShortname) . '_Form_Task_PickProfile', 'formRule'));
+  }
+
+  /**
+   * Global validation rules for the form.
+   *
+   * @param array $fields
+   *   Posted values of the form.
+   *
+   * @return bool|array
+   *   true if no errors, else array of errors
+   */
+  public static function formRule($fields) {
+    return TRUE;
+  }
+
+  /**
+   * Process the form after the input has been submitted and validated.
+   *
+   * @return void
+   */
+  public function postProcess() {
+    $params = $this->exportValues();
+
+    $this->set('ufGroupId', $params['uf_group_id']);
+
+    // also reset the batch page so it gets new values from the db
+    $this->controller->resetPage('Batch');
+  }
+
+}
diff --git a/templates/CRM/Case/Form/Task/Batch.tpl b/templates/CRM/Case/Form/Task/Batch.tpl
new file mode 100644 (file)
index 0000000..4d596a4
--- /dev/null
@@ -0,0 +1,26 @@
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+*}
+{include file="CRM/Core/Form/Task/Batch.tpl"}
\ No newline at end of file
diff --git a/templates/CRM/Case/Form/Task/PickProfile.tpl b/templates/CRM/Case/Form/Task/PickProfile.tpl
new file mode 100644 (file)
index 0000000..9a9e053
--- /dev/null
@@ -0,0 +1,26 @@
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+*}
+{include file="CRM/Core/Form/Task/PickProfile.tpl"}
diff --git a/templates/CRM/Core/Form/Task/Batch.tpl b/templates/CRM/Core/Form/Task/Batch.tpl
new file mode 100644 (file)
index 0000000..5c87edc
--- /dev/null
@@ -0,0 +1,66 @@
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+*}
+<div class="crm-block crm-form-block crm-{$taskComponent.lc}-task-batch-form-block">
+<div class="help">
+    {ts 1=$taskComponent.lc 2=$taskComponent.ucfirst}Update field values for each %1 as needed. Click <strong>Update %2s</strong> below to save all your changes. To set a field to the same value for ALL rows, enter that value for the first %1 and then click the <strong>Copy icon</strong> (next to the column title).{/ts}
+</div>
+         <div class="crm-submit-buttons">
+            {if $fields}{$form._qf_Batch_refresh.html}{/if} &nbsp;{include file="CRM/common/formButtons.tpl" location="top"}
+         </div>
+         <table class="crm-copy-fields">
+         <thead class="sticky">
+            <tr class="columnheader">
+             {foreach from=$readOnlyFields item=fTitle key=fName}
+              <th>{$fTitle}</th>
+           {/foreach}
+
+              {foreach from=$fields item=field key=fieldName}
+                <td><img  src="{$config->resourceBase}i/copy.png" alt="{ts 1=$field.title}Click to copy %1 from row one to all rows.{/ts}" fname="{$field.name}" class="action-icon" title="{ts}Click here to copy the value in row one to ALL rows.{/ts}" />{$field.title}</td>
+             {/foreach}
+            </tr>
+          </thead>
+            {foreach from=$componentIds item=mid}
+             <tr class="{cycle values="odd-row,even-row"}" entity_id="{$mid}">
+
+        {foreach from=$readOnlyFields item=fTitle key=fName}
+           <td>{$contactDetails.$mid.$fName}</td>
+        {/foreach}
+
+              {foreach from=$fields item=field key=fieldName}
+                {assign var=n value=$field.name}
+                <td class="compressed">{$form.field.$mid.$n.html}</td>
+              {/foreach}
+             </tr>
+            {/foreach}
+           </tr>
+         </table>
+         <div class="crm-submit-buttons">
+            {if $fields}{$form._qf_Batch_refresh.html}{/if} &nbsp;{include file="CRM/common/formButtons.tpl" location="bottom"}
+         </div>
+</div>
+
+{*include batch copy js js file*}
+{include file="CRM/common/batchCopy.tpl"}
diff --git a/templates/CRM/Core/Form/Task/PickProfile.tpl b/templates/CRM/Core/Form/Task/PickProfile.tpl
new file mode 100644 (file)
index 0000000..0c06e0e
--- /dev/null
@@ -0,0 +1,40 @@
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+*}
+<div class="crm-form crm-form-block crm-{$taskComponent.lc}-task-pickprofile-form-block">
+<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
+   <table class="form-layout-compressed">
+     <tr class="crm-{$taskComponent.lc}-task-pickprofile-form-block-uf_group_id">
+       <td class="label">{$form.uf_group_id.label}</td><td>{$form.uf_group_id.html}</td>
+     </tr>
+     <tr>
+       <td></td>
+       <td>
+         {assign var="ucfirst" value=$taskComponent.ucfirst}
+         {include file="CRM/$ucfirst/Form/Task.tpl"}</td>
+     </tr>
+ </table>
+   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
+</div>