use List::Util qw( min );
use FS::UI::bytecount;
use FS::Conf;
+use Time::Local 'timelocal';
#ask FS::UID to run this stuff for us later
FS::UID->install_callback( sub {
}
sub calc_setup {
- my($self, $cust_pkg, $sdate, $details, $param ) = @_;
+ my($self, $cust_pkg, $time, $details, $param ) = @_;
- return 0 if $self->prorate_setup($cust_pkg, $sdate);
+ return 0 if $self->prorate_setup($cust_pkg, $time);
my $i = 0;
my $count = $self->option( 'additional_count', 'quiet' ) || 0;
push @$details, $self->option( 'additional_info' . $i++ );
}
- my $charge = $self->unit_setup($cust_pkg, $sdate, $details);
+ my $charge = $self->unit_setup($cust_pkg, $time, $details);
my $discount = 0;
if ( $charge > 0 ) {
$param->{'setup_charge'} = $charge;
- $discount = $self->calc_discount($cust_pkg, $sdate, $details, $param);
+ $discount = $self->calc_discount($cust_pkg, \$time, $details, $param);
delete $param->{'setup_charge'};
}
}
sub unit_setup {
- my($self, $cust_pkg, $sdate, $details ) = @_;
+ my($self, $cust_pkg, $time, $details ) = @_;
$self->option('setup_fee', 1) || 0;
}
sub cutoff_day {
my $self = shift;
my $cust_pkg = shift;
+ my $cust_main = $cust_pkg->cust_main;
+ # force it to act like a prorate package, is what this means
+ # because we made a distinction once between prorate and flat packages
+ if ( $cust_main->force_prorate_day and $cust_main->prorate_day ) {
+ return ( $cust_main->prorate_day );
+ }
if ( $self->option('sync_bill_date',1) ) {
my $next_bill = $cust_pkg->cust_main->next_bill_date;
- if ( defined($next_bill) ) {
- # careful here. if the prorate calculation is going to round to
- # the nearest day, this needs to always return the same result
- if ( $self->option('prorate_round_day', 1) ) {
- my $hour = (localtime($next_bill))[2];
- $next_bill += 64800 if $hour >= 12;
- }
+ if ( $next_bill ) {
return (localtime($next_bill))[3];
+ } else {
+ # This is the customer's only active package and hasn't been billed
+ # yet, so set the cutoff day to either today or tomorrow, whichever
+ # would result in a full period after rounding.
+ my $setup = $cust_pkg->setup; # because it's "now"
+ my $rounding_mode = $self->option('prorate_round_day',1);
+ return () if !$setup or !$rounding_mode;
+ my ($sec, $min, $hour, $mday, $mon, $year) = localtime($setup);
+
+ if ( ( $rounding_mode == 1 and $hour >= 12 )
+ or ( $rounding_mode == 3 and ( $sec > 0 or $min > 0 or $hour > 0 ))
+ ) {
+ # then the prorate period will be rounded down to start from
+ # midnight tomorrow, so the cutoff day should be the current day +
+ # 1.
+ $setup = timelocal(59,59,23,$mday,$mon,$year) + 1;
+ $mday = (localtime($setup))[3];
+ }
+ # otherwise, it will be rounded up, so leave the cutoff day at today.
+ return $mday;
}
}
return ();
$amount = $amount * ($edate - $time) / ($edate - $cust_bill_pkg->sdate);
}
- # calculate tax adjustment. we're not doing full credit_lineitems here
- # (e.g. not applying the credit to the past billing of this package)
- # so just include the adjustment in the source record with the rest
- # of the credit
- my %tax_adjust = FS::cust_credit->calculate_tax_adjustment(
- 'custnum' => $cust_pkg->custnum,
- 'billpkgnums' => [ $cust_bill_pkg->billpkgnum ],
- 'setuprecurs' => [ 'recur' ],
- 'amounts' => [ $amount ],
- );
- $amount += $tax_adjust{taxtotal};
-
- $amount = sprintf('%.2f', $amount); # ensure that amounts add up right
$credit += $amount;
- } # foreach $cust_bill_pkg
-
+ }
sprintf('%.2f', $credit);
}