improve testing of prorate-sync behavior, #72928, #42108, and #34622
[freeside.git] / FS / t / suite / 11-prorate_sync_single_pkg.t
1 #!/usr/bin/perl
2
3 =head2 DESCRIPTION
4
5 Tests the effect of ordering a sync_bill_date package either before or
6 after noon and billing it for two consecutive cycles, in all three prorate
7 rounding modes (round nearest, round up, and round down). Ref RT#34622.
8
9 Correct: It should be charged full price in both cycles regardless of
10 the prorate rounding mode, as long as prorate rounding is enabled.
11
12 =cut
13
14 use strict;
15 use Test::More tests => 18;
16 use FS::Test;
17 use Date::Parse 'str2time';
18 use Date::Format 'time2str';
19 use Test::MockTime qw(set_fixed_time);
20 use FS::cust_main;
21 use FS::cust_pkg;
22 use FS::Conf;
23 my $FS= FS::Test->new;
24
25 foreach my $prorate_mode (1, 2, 3) {
26   diag("prorate_round_day = $prorate_mode");
27   # Create a package def with the sync_bill_date option.
28   my $error;
29   my $old_part_pkg = $FS->qsearchs('part_pkg', { pkgpart => 5 });
30   my $part_pkg = $old_part_pkg->clone;
31   BAIL_OUT("existing pkgpart 5 is not a flat monthly package")
32     unless $part_pkg->freq eq '1' and $part_pkg->plan eq 'flat';
33   $error = $part_pkg->insert(
34     options => {  $old_part_pkg->options,
35                   'sync_bill_date' => 1,
36                   'prorate_round_day' => $prorate_mode, }
37   );
38
39   BAIL_OUT("can't configure package: $error") if $error;
40
41   my $pkgpart = $part_pkg->pkgpart;
42   # Create a clean customer with no other packages.
43   foreach my $hour (0, 8, 16) {
44     diag("$hour:00");
45     my $location = FS::cust_location->new({
46         address1  => '123 Example Street',
47         city      => 'Sacramento',
48         state     => 'CA',
49         country   => 'US',
50         zip       => '94901',
51     });
52     my $cust = FS::cust_main->new({
53         agentnum      => 1,
54         refnum        => 1,
55         last          => 'Customer',
56         first         => 'Sync bill date',
57         invoice_email => 'newcustomer@fake.freeside.biz',
58         payby         => 'BILL',
59         bill_location => $location,
60         ship_location => $location,
61     });
62     $error = $cust->insert;
63     BAIL_OUT("can't create test customer: $error") if $error;
64
65     my $pkg;
66     # Create and bill the package.
67     set_fixed_time(str2time("2016-03-10 $hour:00"));
68     $pkg = FS::cust_pkg->new({ pkgpart => $pkgpart });
69     $error = $cust->order_pkg({ 'cust_pkg' => $pkg });
70     BAIL_OUT("can't order package: $error") if $error;
71     $error = $cust->bill_and_collect;
72     BAIL_OUT("can't bill package: $error") if $error;
73
74     # Bill it a second time.
75     $pkg = $pkg->replace_old;
76     set_fixed_time($pkg->bill);
77     $error = $cust->bill_and_collect;
78     BAIL_OUT("can't bill package: $error") if $error;
79
80     # Check the amount billed.
81     my $recur = $part_pkg->base_recur;
82     my @cust_bill = $cust->cust_bill;
83     ok( $cust_bill[0]->charged == $recur, "first bill is $recur" )
84       or diag("first bill is ".$cust_bill[0]->charged);
85     ok( $cust_bill[1]->charged == $recur, "second bill is $recur" )
86       or diag("second bill is ".$cust_bill[1]->charged);
87
88   }
89 }