improve testing of prorate-sync behavior, #72928, #42108, and #34622
[freeside.git] / FS / t / suite / 10-prorate_sync_same_hour.t
1 #!/usr/bin/perl
2
3 =head2 DESCRIPTION
4
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
7 and #72928.
8
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".
12
13 =cut
14
15 use strict;
16 use Test::More tests => 27;
17 use FS::Test;
18 use Date::Parse 'str2time';
19 use Date::Format 'time2str';
20 use Test::MockTime qw(set_fixed_time);
21 use FS::cust_main;
22 use FS::cust_pkg;
23 use FS::Conf;
24 my $FS= FS::Test->new;
25
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.
29   my $error;
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, }
38   );
39
40   BAIL_OUT("can't configure package: $error") if $error;
41
42   my $pkgpart = $part_pkg->pkgpart;
43   # Create a clean customer with no other packages.
44   foreach my $hour (0, 8, 16) {
45     diag("$hour:00");
46     my $location = FS::cust_location->new({
47         address1  => '123 Example Street',
48         city      => 'Sacramento',
49         state     => 'CA',
50         country   => 'US',
51         zip       => '94901',
52     });
53     my $cust = FS::cust_main->new({
54         agentnum      => 1,
55         refnum        => 1,
56         last          => 'Customer',
57         first         => 'Sync bill date',
58         invoice_email => 'newcustomer@fake.freeside.biz',
59         payby         => 'BILL',
60         bill_location => $location,
61         ship_location => $location,
62     });
63     $error = $cust->insert;
64     BAIL_OUT("can't create test customer: $error") if $error;
65
66     my @pkgs;
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);
78
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;
85
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);
91     }
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);
95
96     my @next_bill = map { time2str('%Y-%m-%d', $_->replace_old->get('bill')) } @pkgs;
97
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]");
101   }
102 }