CRM-18316 - Pledge scheduled dates are created incorrectly at the end of a month
authorjitendrapurohit <jitendra.purohit@webaccessglobal.com>
Fri, 15 Apr 2016 11:23:25 +0000 (16:53 +0530)
committerjitendrapurohit <jitendra.purohit@webaccessglobal.com>
Mon, 18 Apr 2016 05:49:51 +0000 (11:19 +0530)
minor fix

add comments

CRM/Pledge/BAO/PledgePayment.php
tests/phpunit/CRM/Pledge/BAO/PledgePaymentTest.php

index d670d575847540cb5dd1b26f181b3fb22dd53f0c..87da53ba1e9245b75c53c9dcf5e5dec1374b3f99 100644 (file)
@@ -506,28 +506,23 @@ WHERE  civicrm_pledge.id = %2
    * CRM_Utils_Date::intervalAdd( $params['frequency_unit'], $i * ($params['frequency_interval']) , calculateBaseScheduledDate( &$params )))
    *
    * @param array $params
-   * @param int $paymentNo
    *
    * @return array
    *   Next scheduled date as an array
    */
-  public static function calculateBaseScheduleDate(&$params, $paymentNo = NULL) {
+  public static function calculateBaseScheduleDate(&$params) {
     $date = array();
     $scheduled_date = CRM_Utils_Date::processDate($params['scheduled_date']);
     $date['year'] = (int) substr($scheduled_date, 0, 4);
     $date['month'] = (int) substr($scheduled_date, 4, 2);
     $date['day'] = (int) substr($scheduled_date, 6, 2);
-    $date['hour'] = (int) substr($scheduled_date, 7, 2);
-    $date['minute'] = (int) substr($scheduled_date, 9, 2);
-    $date['seconds'] = (int) substr($scheduled_date, 11, 2);
     // calculation of schedule date according to frequency day of period
     // frequency day is not applicable for daily installments
     if ($params['frequency_unit'] != 'day' && $params['frequency_unit'] != 'year') {
       if ($params['frequency_unit'] != 'week') {
         // CRM-18316: To calculate pledge scheduled dates at the end of a month.
         $date['day'] = $params['frequency_day'];
-        $interval = $paymentNo * ($params['frequency_interval']);
-        $lastDayOfMonth = date('t', mktime($date['hour'], $date['minute'], $date['seconds'], $date['month'] + $interval, 1, $date['year']));
+        $lastDayOfMonth = date('t', mktime(0, 0, 0, $date['month'], 1, $date['year']));
         if ($lastDayOfMonth < $date['day']) {
           $date['day'] = $lastDayOfMonth;
         }
@@ -566,13 +561,32 @@ WHERE  civicrm_pledge.id = %2
    *   formatted date
    */
   public static function calculateNextScheduledDate(&$params, $paymentNo, $basePaymentDate = NULL) {
+    $interval = $paymentNo * ($params['frequency_interval']);
     if (!$basePaymentDate) {
-      $basePaymentDate = self::calculateBaseScheduleDate($params, $paymentNo);
+      $basePaymentDate = self::calculateBaseScheduleDate($params);
+    }
+
+    //CRM-18316 - change $basePaymentDate for the end dates of the month eg: 29, 30 or 31.
+    if ($params['frequency_unit'] == 'month' && in_array($params['frequency_day'], array(29, 30, 31))) {
+      $frequency = $params['frequency_day'];
+      extract(date_parse($basePaymentDate));
+      $lastDayOfMonth = date('t', mktime($hour, $minute, $second, $month + $interval, 1, $year));
+      // Take the last day in case the current month is Feb or frequency_day is set to 31.
+      if (in_array($lastDayOfMonth, array(28, 29)) || $frequency == 31) {
+        $frequency = 0;
+        $interval++;
+      }
+      $basePaymentDate = array(
+        'M' => $month,
+        'd' => $frequency,
+        'Y' => $year,
+      );
     }
+
     return CRM_Utils_Date::format(
       CRM_Utils_Date::intervalAdd(
         $params['frequency_unit'],
-        $paymentNo * ($params['frequency_interval']),
+        $interval,
         $basePaymentDate
       )
     );
index 544455674f71f890af721e90398fa6eb200b4d45..96eb69a672986a15f32829c168de53f5e324d88a 100644 (file)
@@ -262,47 +262,58 @@ class CRM_Pledge_BAO_PledgePaymentTest extends CiviUnitTestCase {
       'frequency_day' => 31,
       'frequency_interval' => 1,
     );
-    $scheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 2);
-    $this->assertEquals('20110731000000', $scheduleDate);
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 2);
+    $this->assertEquals('20110731000000', $nextScheduleDate);
     // assert pledge scheduled date for month february.
-    $scheduleDateForFeb = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 9);
-    $this->assertEquals('20120229000000', $scheduleDateForFeb);
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 9);
+    $this->assertEquals('20120229000000', $nextScheduleDate);
 
     //Case: Frequency day = 31 and scheduled date = 31st of any month
     $params['scheduled_date'] = '20110131';
     $params['frequency_day'] = 31;
-    $scheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 1);
-    $this->assertEquals('20110228000000', $scheduleDate);
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 1);
+    $this->assertEquals('20110228000000', $nextScheduleDate);
 
     //Case: Frequency day = 30 and scheduled date = 30th of any month
     $params['scheduled_date'] = '20110130';
     $params['frequency_day'] = 30;
-    $scheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 3);
-    $this->assertEquals('20110430000000', $scheduleDate);
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 3);
+    $this->assertEquals('20110430000000', $nextScheduleDate);
 
     //Case: Frequency day = 30 and scheduled date = any day of month
     $params['scheduled_date'] = '20110110';
     $params['frequency_day'] = 30;
-    $scheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 4);
-    $this->assertEquals('20110530000000', $scheduleDate);
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 4);
+    $this->assertEquals('20110530000000', $nextScheduleDate);
 
     //Case: Frequency day = any and scheduled date = 31st of any month
     $params['scheduled_date'] = '20110131';
     $params['frequency_day'] = 5;
-    $scheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 5);
-    $this->assertEquals('20110605000000', $scheduleDate);
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 5);
+    $this->assertEquals('20110605000000', $nextScheduleDate);
 
-    //Case: Frequency day = any AND Satrt date = 30th of any month
+    //Case: Frequency day = any AND scheduled date = 30th of any month
     $params['scheduled_date'] = '20110130';
     $params['frequency_day'] = 10;
-    $scheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 6);
-    $this->assertEquals('20110710000000', $scheduleDate);
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 6);
+    $this->assertEquals('20110710000000', $nextScheduleDate);
 
-    //Case: Frequency day = any AND Satrt date = any day month
+    //Case: Frequency day = any AND scheduled date = any day month
     $params['scheduled_date'] = '20110124';
     $params['frequency_day'] = 6;
-    $scheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 7);
-    $this->assertEquals('20110806000000', $scheduleDate);
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 7);
+    $this->assertEquals('20110806000000', $nextScheduleDate);
+
+    //Case: Frequency day = 31 AND scheduled date = 29 Feb
+    $params['scheduled_date'] = '20160229';
+    $params['frequency_day'] = 31;
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 5);
+    $this->assertEquals('20160731000000', $nextScheduleDate);
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 6);
+    $this->assertEquals('20160831000000', $nextScheduleDate);
+    //check date for february
+    $nextScheduleDate = CRM_Pledge_BAO_PledgePayment::calculateNextScheduledDate($params, 12);
+    $this->assertEquals('20170228000000', $nextScheduleDate);
   }
 
   /**