summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wells <mark@freeside.biz>2016-10-15 21:03:17 -0700
committerMark Wells <mark@freeside.biz>2016-10-15 21:03:45 -0700
commitd474212f65de3adc5f116430cc948f26da9beb5b (patch)
tree388922712055fe5eda343250a12b7fc7871f44ba
parent78d76e47e09583e51eb1acf3ca2255e5df46f319 (diff)
improve testing of prorate-sync behavior, #72928, #42108, and #34622
-rwxr-xr-xFS/t/suite/05-prorate_sync_same_day.t15
-rwxr-xr-xFS/t/suite/10-prorate_sync_same_hour.t102
-rwxr-xr-xFS/t/suite/11-prorate_sync_single_pkg.t89
3 files changed, 201 insertions, 5 deletions
diff --git a/FS/t/suite/05-prorate_sync_same_day.t b/FS/t/suite/05-prorate_sync_same_day.t
index 91a8efa..d08752e 100755
--- a/FS/t/suite/05-prorate_sync_same_day.t
+++ b/FS/t/suite/05-prorate_sync_same_day.t
@@ -5,10 +5,15 @@
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.
+Formerly 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.
+
+Revised RT#72928: The second package should be prorated one day short only
+if the rounding mode is 1 (round nearest), as the nearest day is different
+for the two packages.
=cut
@@ -81,7 +86,7 @@ foreach my $prorate_mode (1, 2, 3) {
$error = $cust->bill_and_collect;
# Check the amount billed.
- if ( $prorate_mode == 1 or $prorate_mode == 3 ) {
+ if ( $prorate_mode == 1 ) {
# it should be one day short, in March
$recur = sprintf('%.2f', $recur * 30/31);
}
diff --git a/FS/t/suite/10-prorate_sync_same_hour.t b/FS/t/suite/10-prorate_sync_same_hour.t
new file mode 100755
index 0000000..f1e3185
--- /dev/null
+++ b/FS/t/suite/10-prorate_sync_same_hour.t
@@ -0,0 +1,102 @@
+#!/usr/bin/perl
+
+=head2 DESCRIPTION
+
+Tests the effect of ordering and activating two sync_bill_date packages
+either both before or both after noon, less than an hour apart. Ref RT#42108
+and #72928.
+
+Correct: The packages should always end up with the same next bill date,
+and should be billed for a full period, except in the case where the first
+package starts at midnight and the rounding mode is "always round down".
+
+=cut
+
+use strict;
+use Test::More tests => 27;
+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.
+ foreach my $hour (0, 8, 16) {
+ diag("$hour:00");
+ 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@fake.freeside.biz',
+ payby => 'BILL',
+ 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 $hour: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 $hour:01"));
+ $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 == 3 and $hour == 0 ) {
+ # special case: a start date of midnight won't be rounded down but any
+ # later start date will, so the second package will be one day short.
+ $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]");
+ }
+}
diff --git a/FS/t/suite/11-prorate_sync_single_pkg.t b/FS/t/suite/11-prorate_sync_single_pkg.t
new file mode 100755
index 0000000..83308f5
--- /dev/null
+++ b/FS/t/suite/11-prorate_sync_single_pkg.t
@@ -0,0 +1,89 @@
+#!/usr/bin/perl
+
+=head2 DESCRIPTION
+
+Tests the effect of ordering a sync_bill_date package either before or
+after noon and billing it for two consecutive cycles, in all three prorate
+rounding modes (round nearest, round up, and round down). Ref RT#34622.
+
+Correct: It should be charged full price in both cycles regardless of
+the prorate rounding mode, as long as prorate rounding is enabled.
+
+=cut
+
+use strict;
+use Test::More tests => 18;
+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.
+ foreach my $hour (0, 8, 16) {
+ diag("$hour:00");
+ 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@fake.freeside.biz',
+ payby => 'BILL',
+ bill_location => $location,
+ ship_location => $location,
+ });
+ $error = $cust->insert;
+ BAIL_OUT("can't create test customer: $error") if $error;
+
+ my $pkg;
+ # Create and bill the package.
+ set_fixed_time(str2time("2016-03-10 $hour:00"));
+ $pkg = FS::cust_pkg->new({ pkgpart => $pkgpart });
+ $error = $cust->order_pkg({ 'cust_pkg' => $pkg });
+ BAIL_OUT("can't order package: $error") if $error;
+ $error = $cust->bill_and_collect;
+ BAIL_OUT("can't bill package: $error") if $error;
+
+ # Bill it a second time.
+ $pkg = $pkg->replace_old;
+ set_fixed_time($pkg->bill);
+ $error = $cust->bill_and_collect;
+ BAIL_OUT("can't bill package: $error") if $error;
+
+ # Check the amount billed.
+ my $recur = $part_pkg->base_recur;
+ my @cust_bill = $cust->cust_bill;
+ ok( $cust_bill[0]->charged == $recur, "first bill is $recur" )
+ or diag("first bill is ".$cust_bill[0]->charged);
+ ok( $cust_bill[1]->charged == $recur, "second bill is $recur" )
+ or diag("second bill is ".$cust_bill[1]->charged);
+
+ }
+}