5 Tests the effect of ordering and activating two sync_bill_date packages
6 either both before or both after noon, less than an hour apart. Ref RT#42108
9 Correct: The packages should always end up with the same next bill date,
10 and should be billed for a full period, except in the case where the first
11 package starts at midnight and the rounding mode is "always round down".
16 use Test::More tests => 27;
18 use Date::Parse 'str2time';
19 use Date::Format 'time2str';
20 use Test::MockTime qw(set_fixed_time);
24 my $FS= FS::Test->new;
26 foreach my $prorate_mode (1, 2, 3) {
27 diag("prorate_round_day = $prorate_mode");
28 # Create a package def with the sync_bill_date option.
30 my $old_part_pkg = $FS->qsearchs('part_pkg', { pkgpart => 5 });
31 my $part_pkg = $old_part_pkg->clone;
32 BAIL_OUT("existing pkgpart 5 is not a flat monthly package")
33 unless $part_pkg->freq eq '1' and $part_pkg->plan eq 'flat';
34 $error = $part_pkg->insert(
35 options => { $old_part_pkg->options,
36 'sync_bill_date' => 1,
37 'prorate_round_day' => $prorate_mode, }
40 BAIL_OUT("can't configure package: $error") if $error;
42 my $pkgpart = $part_pkg->pkgpart;
43 # Create a clean customer with no other packages.
44 foreach my $hour (0, 8, 16) {
46 my $location = FS::cust_location->new({
47 address1 => '123 Example Street',
53 my $cust = FS::cust_main->new({
57 first => 'Sync bill date',
58 invoice_email => 'newcustomer@fake.freeside.biz',
60 bill_location => $location,
61 ship_location => $location,
63 $error = $cust->insert;
64 BAIL_OUT("can't create test customer: $error") if $error;
67 # Create and bill the first package.
68 set_fixed_time(str2time("2016-03-10 $hour:00"));
69 $pkgs[0] = FS::cust_pkg->new({ pkgpart => $pkgpart });
70 $error = $cust->order_pkg({ 'cust_pkg' => $pkgs[0] });
71 BAIL_OUT("can't order package: $error") if $error;
72 $error = $cust->bill_and_collect;
73 # Check the amount billed.
74 my ($cust_bill_pkg) = $pkgs[0]->cust_bill_pkg;
75 my $recur = $part_pkg->base_recur;
76 ok( $cust_bill_pkg->recur == $recur, "first package recur is $recur" )
77 or diag("first package recur is ".$cust_bill_pkg->recur);
79 # Create and bill the second package.
80 set_fixed_time(str2time("2016-03-10 $hour:01"));
81 $pkgs[1] = FS::cust_pkg->new({ pkgpart => $pkgpart });
82 $error = $cust->order_pkg({ 'cust_pkg' => $pkgs[1] });
83 BAIL_OUT("can't order package: $error") if $error;
84 $error = $cust->bill_and_collect;
86 # Check the amount billed.
87 if ( $prorate_mode == 3 and $hour == 0 ) {
88 # special case: a start date of midnight won't be rounded down but any
89 # later start date will, so the second package will be one day short.
90 $recur = sprintf('%.2f', $recur * 30/31);
92 ($cust_bill_pkg) = $pkgs[1]->cust_bill_pkg;
93 ok( $cust_bill_pkg->recur == $recur, "second package recur is $recur" )
94 or diag("second package recur is ".$cust_bill_pkg->recur);
96 my @next_bill = map { time2str('%Y-%m-%d', $_->replace_old->get('bill')) } @pkgs;
98 ok( $next_bill[0] eq $next_bill[1],
99 "both packages will bill again on $next_bill[0]" )
100 or diag("first package bill date is $next_bill[0], second package is $next_bill[1]");