[freeside-commits] branch FREESIDE_3_BRANCH updated. 23b82515ec33f78da175c2f01ef97dace3f3e669

Mark Wells mark at 420.am
Mon May 16 22:45:43 PDT 2016


The branch, FREESIDE_3_BRANCH has been updated
       via  23b82515ec33f78da175c2f01ef97dace3f3e669 (commit)
       via  296ed635739f362ee077eac1bcb67c408f600a31 (commit)
      from  a0877673b88d523c3c4ede51ff2c238285d8aeea (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 23b82515ec33f78da175c2f01ef97dace3f3e669
Author: Mark Wells <mark at freeside.biz>
Date:   Mon May 16 22:45:38 2016 -0700

    fix test #5

diff --git a/FS/t/suite/05-prorate_sync_same_day.t b/FS/t/suite/05-prorate_sync_same_day.t
index 91a8efa..315be06 100755
--- a/FS/t/suite/05-prorate_sync_same_day.t
+++ b/FS/t/suite/05-prorate_sync_same_day.t
@@ -54,6 +54,7 @@ foreach my $prorate_mode (1, 2, 3) {
       last          => 'Customer',
       first         => 'Sync bill date',
       invoice_email => 'newcustomer at fake.freeside.biz',
+      payby         => 'BILL',
       bill_location => $location,
       ship_location => $location,
   });

commit 296ed635739f362ee077eac1bcb67c408f600a31
Author: Mark Wells <mark at freeside.biz>
Date:   Mon May 16 20:58:12 2016 -0700

    prorate_round_day options to round up / down only, #42108

diff --git a/FS/FS/part_pkg/flat.pm b/FS/FS/part_pkg/flat.pm
index 2c69432..e10094e 100644
--- a/FS/FS/part_pkg/flat.pm
+++ b/FS/FS/part_pkg/flat.pm
@@ -67,8 +67,9 @@ tie my %contract_years, 'Tie::IxHash', (
                         },
     'prorate_round_day' => {
                           'name' => 'When synchronizing, round the prorated '.
-                                    'period to the nearest full day',
-                          'type' => 'checkbox',
+                                    'period',
+                          'type' => 'select',
+                          'select_options' => \%FS::part_pkg::prorate_Mixin::prorate_round_day_opts,
                         },
     'add_full_period' => { 'disabled' => 1 }, # doesn't make sense with sync?
 
diff --git a/FS/FS/part_pkg/prorate.pm b/FS/FS/part_pkg/prorate.pm
index a5f9ef6..44f2f25 100644
--- a/FS/FS/part_pkg/prorate.pm
+++ b/FS/FS/part_pkg/prorate.pm
@@ -24,9 +24,9 @@ use FS::part_pkg::flat;
                           'type' => 'checkbox',
                         },
     'prorate_round_day'=> {
-                          'name' => 'Round the prorated period to the nearest '.
-                                    'full day',
-                          'type' => 'checkbox',
+                          'name' => 'Round the prorated period',
+                          'type' => 'select',
+                          'select_options' => \%FS::part_pkg::prorate_Mixin::prorate_round_day_opts,
                         },
     'prorate_defer_bill'=> {
                         'name' => 'Defer the first bill until the billing day',
diff --git a/FS/FS/part_pkg/prorate_Mixin.pm b/FS/FS/part_pkg/prorate_Mixin.pm
index e8d42b9..26fdc35 100644
--- a/FS/FS/part_pkg/prorate_Mixin.pm
+++ b/FS/FS/part_pkg/prorate_Mixin.pm
@@ -6,6 +6,13 @@ use Time::Local qw( timelocal timelocal_nocheck );
 use Date::Format qw( time2str );
 use List::Util qw( min );
 
+tie our %prorate_round_day_opts, 'Tie::IxHash',
+  0   => 'no',
+  1   => 'to the nearest day',
+  2   => 'up to a full day',
+  3   => 'down to a full day',
+;
+
 %info = ( 
   'disabled'  => 1,
   # define all fields that are referenced in this code
@@ -16,8 +23,9 @@ use List::Util qw( min );
                 'type' => 'checkbox',
     },
     'prorate_round_day' => { 
-                'name' => 'When prorating, round to the nearest full day',
-                'type' => 'checkbox',
+                'name' => 'When prorating, round the prorated period',
+                'type' => 'select',
+                'select_options' => \%prorate_round_day_opts,
     },
     'prorate_defer_bill' => {
                 'name' => 'When prorating, defer the first bill until the '.
@@ -219,7 +227,8 @@ sub _endpoints {
 
   # only works for freq >= 1 month; probably can't be fixed
   my ($sec, $min, $hour, $mday, $mon, $year) = (localtime($mnow))[0..5];
-  if( $self->option('prorate_round_day',1) ) {
+  my $rounding_mode = $self->option('prorate_round_day',1);
+  if ( $rounding_mode == 1 ) {
     # If the time is 12:00-23:59, move to the next day by adding 18 
     # hours to $mnow.  Because of DST this can end up from 05:00 to 18:59
     # but it's always within the next day.
@@ -228,6 +237,19 @@ sub _endpoints {
     ($mday,$mon,$year) = (localtime($mnow))[3..5];
     # Then set $mnow to midnight on that day.
     $mnow = timelocal(0,0,0,$mday,$mon,$year);
+  } elsif ( $rounding_mode == 2 ) {
+    # Move the time back to midnight. This increases the length of the
+    # prorate interval.
+    $mnow = timelocal(0,0,0,$mday,$mon,$year);
+    ($mday,$mon,$year) = (localtime($mnow))[3..5];
+  } elsif ( $rounding_mode == 3 ) {
+    # If the time is after midnight, move it forward to the next midnight.
+    # This decreases the length of the prorate interval.
+    if ( $sec > 0 or $min > 0 or $hour > 0 ) {
+      # move to one second before midnight, then tick forward
+      $mnow = timelocal(59,59,23,$mday,$mon,$year) + 1;
+      ($mday,$mon,$year) = (localtime($mnow))[3..5];
+    }
   }
   my $mend;
   my $mstart;
diff --git a/FS/t/suite/05-prorate_sync_same_day.t b/FS/t/suite/05-prorate_sync_same_day.t
new file mode 100755
index 0000000..91a8efa
--- /dev/null
+++ b/FS/t/suite/05-prorate_sync_same_day.t
@@ -0,0 +1,97 @@
+#!/usr/bin/perl
+
+=head2 DESCRIPTION
+
+Tests the effect of ordering and activating two sync_bill_date packages on
+the same day. Ref RT#42108.
+
+Correct: If the packages have prorate_round_day = 1 (round nearest), or 3
+(round down) then the second package should be prorated one day short. If
+they have prorate_round_day = 2 (round up), they should be billed
+for the same amount. In both cases they should have the same next bill date.
+
+=cut
+
+use strict;
+use Test::More tests => 9;
+use FS::Test;
+use Date::Parse 'str2time';
+use Date::Format 'time2str';
+use Test::MockTime qw(set_fixed_time);
+use FS::cust_main;
+use FS::cust_pkg;
+use FS::Conf;
+my $FS= FS::Test->new;
+
+foreach my $prorate_mode (1, 2, 3) {
+  diag("prorate_round_day = $prorate_mode");
+  # Create a package def with the sync_bill_date option.
+  my $error;
+  my $old_part_pkg = $FS->qsearchs('part_pkg', { pkgpart => 5 });
+  my $part_pkg = $old_part_pkg->clone;
+  BAIL_OUT("existing pkgpart 5 is not a flat monthly package")
+    unless $part_pkg->freq eq '1' and $part_pkg->plan eq 'flat';
+  $error = $part_pkg->insert(
+    options => {  $old_part_pkg->options,
+                  'sync_bill_date' => 1,
+                  'prorate_round_day' => $prorate_mode, }
+  );
+
+  BAIL_OUT("can't configure package: $error") if $error;
+
+  my $pkgpart = $part_pkg->pkgpart;
+  # Create a clean customer with no other packages.
+  my $location = FS::cust_location->new({
+      address1  => '123 Example Street',
+      city      => 'Sacramento',
+      state     => 'CA',
+      country   => 'US',
+      zip       => '94901',
+  });
+  my $cust = FS::cust_main->new({
+      agentnum      => 1,
+      refnum        => 1,
+      last          => 'Customer',
+      first         => 'Sync bill date',
+      invoice_email => 'newcustomer at fake.freeside.biz',
+      bill_location => $location,
+      ship_location => $location,
+  });
+  $error = $cust->insert;
+  BAIL_OUT("can't create test customer: $error") if $error;
+
+  my @pkgs;
+  # Create and bill the first package.
+  set_fixed_time(str2time('2016-03-10 08:00'));
+  $pkgs[0] = FS::cust_pkg->new({ pkgpart => $pkgpart });
+  $error = $cust->order_pkg({ 'cust_pkg' => $pkgs[0] });
+  BAIL_OUT("can't order package: $error") if $error;
+  $error = $cust->bill_and_collect;
+  # Check the amount billed.
+  my ($cust_bill_pkg) = $pkgs[0]->cust_bill_pkg;
+  my $recur = $part_pkg->base_recur;
+  ok( $cust_bill_pkg->recur == $recur, "first package recur is $recur" )
+    or diag("first package recur is ".$cust_bill_pkg->recur);
+
+  # Create and bill the second package.
+  set_fixed_time(str2time('2016-03-10 16:00'));
+  $pkgs[1] = FS::cust_pkg->new({ pkgpart => $pkgpart });
+  $error = $cust->order_pkg({ 'cust_pkg' => $pkgs[1] });
+  BAIL_OUT("can't order package: $error") if $error;
+  $error = $cust->bill_and_collect;
+
+  # Check the amount billed.
+  if ( $prorate_mode == 1 or $prorate_mode == 3 ) {
+    # it should be one day short, in March
+    $recur = sprintf('%.2f', $recur * 30/31);
+  }
+  ($cust_bill_pkg) = $pkgs[1]->cust_bill_pkg;
+  ok( $cust_bill_pkg->recur == $recur, "second package recur is $recur" )
+    or diag("second package recur is ".$cust_bill_pkg->recur);
+
+  my @next_bill = map { time2str('%Y-%m-%d', $_->replace_old->get('bill')) } @pkgs;
+
+  ok( $next_bill[0] eq $next_bill[1],
+    "both packages will bill again on $next_bill[0]" )
+    or diag("first package bill date is $next_bill[0], second package is $next_bill[1]");
+}

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/part_pkg/flat.pm                |    5 +-
 FS/FS/part_pkg/prorate.pm             |    6 +-
 FS/FS/part_pkg/prorate_Mixin.pm       |   28 +++++++++-
 FS/t/suite/05-prorate_sync_same_day.t |   98 +++++++++++++++++++++++++++++++++
 4 files changed, 129 insertions(+), 8 deletions(-)
 create mode 100755 FS/t/suite/05-prorate_sync_same_day.t




More information about the freeside-commits mailing list