Merge pull request #4997 from monishdeb/CRM-15536
[civicrm-core.git] / CRM / Core / BAO / ActionSchedule.php
old mode 100644 (file)
new mode 100755 (executable)
index 8f59642..c8d7659
@@ -24,7 +24,7 @@
   | GNU Affero General Public License or the licensing of CiviCRM,     |
   | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
   +--------------------------------------------------------------------+
-*/
+ */
 
 /**
  *
@@ -71,7 +71,6 @@ class CRM_Core_BAO_ActionSchedule extends CRM_Core_DAO_ActionSchedule {
   /**
    * Get all fields of the type Date
    */
-
   public static function getDateFields() {
     $allFields = CRM_Core_BAO_CustomField::getFields('');
     $dateFields = array('birth_date' => ts('Birth Date'));
@@ -91,7 +90,6 @@ class CRM_Core_BAO_ActionSchedule extends CRM_Core_DAO_ActionSchedule {
    *
    * @return array
    *   associated array of all the drop downs in the form
-   * @static
    */
   public static function getSelection($id = NULL) {
     $mapping = self::getMapping();
@@ -325,7 +323,6 @@ class CRM_Core_BAO_ActionSchedule extends CRM_Core_DAO_ActionSchedule {
    *
    * @return array
    *   (reference)   reminder list
-   * @static
    */
   public static function &getList($namesOnly = FALSE, $entityValue = NULL, $id = NULL) {
     $activity_type = CRM_Core_PseudoConstant::activityType(TRUE, TRUE);
@@ -491,7 +488,7 @@ AND   cas.entity_value = $id AND
       foreach (array(
                  'text',
                  'html',
-                 'sms_text'
+                 'sms_text',
                ) as $elem) {
         $$elem = $smarty->fetch("string:{$$elem}");
       }
@@ -531,7 +528,7 @@ AND   cas.entity_value = $id AND
         $smsParams = array(
           'To' => $phoneNumber,
           'provider_id' => $schedule->sms_provider_id,
-          'activity_subject' => $messageSubject
+          'activity_subject' => $messageSubject,
         );
         $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type',
           'SMS',
@@ -597,7 +594,6 @@ AND   cas.entity_value = $id AND
    *   The array that holds all the db ids.
    *
    * @return CRM_Core_DAO_ActionSchedule
-   * @static
    */
   public static function add(&$params, $ids = array()) {
     $actionSchedule = new CRM_Core_DAO_ActionSchedule();
@@ -618,7 +614,6 @@ AND   cas.entity_value = $id AND
    *
    * @return CRM_Core_DAO_ActionSchedule|null
    *   object on success, null otherwise
-   * @static
    */
   public static function retrieve(&$params, &$values) {
     if (empty($params)) {
@@ -644,7 +639,6 @@ AND   cas.entity_value = $id AND
    * @param int $id
    *   ID of the Reminder to be deleted.
    *
-   * @static
    */
   public static function del($id) {
     if ($id) {
@@ -668,7 +662,6 @@ AND   cas.entity_value = $id AND
    *
    * @return Object
    *   DAO object on success, null otherwise
-   * @static
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_ActionSchedule', $id, 'is_active', $is_active);
@@ -707,16 +700,16 @@ AND   cas.entity_value = $id AND
       $activityStatusID = FALSE;
       if ($actionSchedule->record_activity) {
         if ($mapping->entity == 'civicrm_membership') {
-          $activityTypeID =
-            CRM_Core_OptionGroup::getValue('activity_type', 'Membership Renewal Reminder', 'name');
+          $activityTypeID
+            CRM_Core_OptionGroup::getValue('activity_type', 'Membership Renewal Reminder', 'name');
         }
         else {
-          $activityTypeID =
-            CRM_Core_OptionGroup::getValue('activity_type', 'Reminder Sent', 'name');
+          $activityTypeID
+            CRM_Core_OptionGroup::getValue('activity_type', 'Reminder Sent', 'name');
         }
 
-        $activityStatusID =
-          CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name');
+        $activityStatusID
+          CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name');
       }
 
       if ($mapping->entity == 'civicrm_activity') {
@@ -759,7 +752,7 @@ LEFT JOIN civicrm_option_value ov ON e.activity_type_id = ov.value AND ov.option
           'fee_amount',
           'contact_email',
           'contact_phone',
-          'balance'
+          'balance',
         );
         $extraSelect = ', ov.label as event_type, ev.title, ev.id as event_id, ev.start_date, ev.end_date, ev.summary, ev.description, address.street_address, address.city, address.state_province_id, address.postal_code, email.email as contact_email, phone.phone as contact_phone ';
 
@@ -886,8 +879,8 @@ WHERE reminder.action_schedule_id = %1 AND reminder.action_date_time IS NULL
         if ($toEmail || !(empty($toPhoneNumber) or $toDoNotSms)) {
           $to['email'] = $toEmail;
           $to['phone'] = $toPhoneNumber;
-          $result =
-            CRM_Core_BAO_ActionSchedule::sendReminder(
+          $result
+            CRM_Core_BAO_ActionSchedule::sendReminder(
               $dao->contactID,
               $to,
               $actionSchedule->id,
@@ -919,8 +912,7 @@ WHERE reminder.action_schedule_id = %1 AND reminder.action_date_time IS NULL
           $activityParams = array(
             'subject' => $actionSchedule->title,
             'details' => $actionSchedule->body_html,
-            'source_contact_id' =>
-              $session->get('userID') ? $session->get('userID') : $dao->contactID,
+            'source_contact_id' => $session->get('userID') ? $session->get('userID') : $dao->contactID,
             'target_contact_id' => $dao->contactID,
             'activity_date_time' => date('YmdHis'),
             'status_id' => $activityStatusID,
@@ -969,6 +961,7 @@ WHERE reminder.action_schedule_id = %1 AND reminder.action_date_time IS NULL
       // $limitWhere - this filtering applies only for
       // 'limit to' option
       $select = $join = $where = $limitWhere = array();
+      $selectColumns = "contact_id, entity_id, entity_table, action_schedule_id";
       $limitTo = $actionSchedule->limit_to;
       $value = explode(CRM_Core_DAO::VALUE_SEPARATOR,
         trim($actionSchedule->entity_value, CRM_Core_DAO::VALUE_SEPARATOR)
@@ -1105,6 +1098,13 @@ WHERE reminder.action_schedule_id = %1 AND reminder.action_date_time IS NULL
         $membershipStatus = CRM_Member_PseudoConstant::membershipStatus(NULL, "(is_current_member = 1 OR name = 'Expired')", 'id');
         $mStatus = implode(',', $membershipStatus);
         $where[] = "e.status_id IN ({$mStatus})";
+
+        // We are not tracking the reference date for 'repeated' schedule reminders,
+        // for further details please check CRM-15376
+        if ($actionSchedule->start_action_date && $actionSchedule->is_repeat == FALSE) {
+          $select[] = $dateField;
+          $selectColumns = "reference_date, " . $selectColumns;
+        }
       }
 
       if ($mapping->entity == 'civicrm_contact') {
@@ -1258,14 +1258,55 @@ reminder.action_schedule_id = %1";
       }
 
       $query = "
-INSERT INTO civicrm_action_log (contact_id, entity_id, entity_table, action_schedule_id)
+INSERT INTO civicrm_action_log ({$selectColumns})
 {$selectClause}
 {$fromClause}
 {$joinClause}
 LEFT JOIN {$reminderJoinClause}
 {$whereClause} {$limitWhereClause} AND {$dateClause} {$notINClause}
 ";
+
+      // In some cases reference_date got outdated due to many reason e.g. In Membership renewal end_date got extended
+      // which means reference date mismatches with the end_date where end_date may be used as the start_action_date
+      // criteria  for some schedule reminder so in order to send new reminder we INSERT new reminder with new reference_date
+      // value via UNION operation
+      if (strpos($selectColumns, 'reference_date') !== FALSE) {
+        $dateClause = str_replace('reminder.id IS NULL', 'reminder.id IS NOT NULL', $dateClause);
+        $referenceQuery = "
+INSERT INTO civicrm_action_log ({$selectColumns})
+{$selectClause}
+{$fromClause}
+{$joinClause}
+ LEFT JOIN {$reminderJoinClause}
+{$whereClause} {$limitWhereClause} {$notINClause} AND {$dateClause} AND
+ reminder.action_date_time IS NOT NULL AND
+ (reminder.reference_date IS NOT NULL AND reminder.reference_date != {$dateField})
+LIMIT 0,1
+";
+
+        // As per the usage of UNION clause above we always INSERT a new reminder if reference_date (RD)
+        // got outdated or mismatches to start_action_date criteria so we need to update RD with actual
+        // start_action_date of already sent reminder, so to prevent redeundancy in sending new reminder
+        // due to above INSERT-UNION query
+        $updateQuery = "UPDATE civicrm_action_log reminder
+ INNER JOIN {$mapping->entity} e ON e.id = reminder.entity_id AND
+ reminder.reference_date IS NOT NULL AND reminder.action_date_time IS NOT NULL
+ INNER JOIN civicrm_action_log new_reminder ON
+   new_reminder.action_schedule_id = reminder.action_schedule_id AND
+   new_reminder.reference_date = {$dateField} AND
+   new_reminder.action_date_time IS NULL
+ SET reminder.reference_date = {$dateField}
+ WHERE reminder.action_schedule_id = %1 AND reminder.reference_date IS NOT NULL AND reminder.reference_date != {$dateField}
+";
+        }
+
       CRM_Core_DAO::executeQuery($query, array(1 => array($actionSchedule->id, 'Integer')));
+
+      if (!empty($updateQuery)) {
+        CRM_Core_DAO::executeQuery($referenceQuery, array(1 => array($actionSchedule->id, 'Integer')));
+        CRM_Core_DAO::executeQuery($updateQuery, array(1 => array($actionSchedule->id, 'Integer')));
+      }
+
       $isSendToAdditionalContacts = (!is_null($limitTo) && $limitTo == 0 && (!empty($addGroup) || !empty($addWhere))) ? TRUE : FALSE;
       if ($isSendToAdditionalContacts) {
         $contactTable = "civicrm_contact c";
@@ -1339,9 +1380,10 @@ INNER JOIN {$reminderJoinClause}
         $valsqlInsertValues = CRM_Core_DAO::executeQuery($sqlInsertValues, array(
             1 => array(
               $actionSchedule->id,
-              'Integer'
-            )
-          ));
+              'Integer',
+            ),
+          )
+        );
 
         $arrValues = array();
         while ($valsqlInsertValues->fetch()) {
@@ -1494,4 +1536,5 @@ WHERE     m.owner_membership_id IS NOT NULL AND
 
     return $options;
   }
+
 }