use strict;
use vars qw( %info );
+use Tie::IxHash;
use Time::Local qw( timelocal timelocal_nocheck );
use Date::Format qw( time2str );
use List::Util qw( min );
+tie our %prorate_round_day_opts, 'Tie::IxHash',
+ 0 => 'no',
+ 1 => 'to the nearest day',
+ 2 => 'up to a full day',
+ 3 => 'down to a full day',
+;
+
%info = (
'disabled' => 1,
# define all fields that are referenced in this code
'type' => 'checkbox',
},
'prorate_round_day' => {
- 'name' => 'When prorating, round to the nearest full day',
- 'type' => 'checkbox',
+ 'name' => 'When prorating, round the prorated period',
+ 'type' => 'select',
+ 'select_options' => \%prorate_round_day_opts,
},
'prorate_defer_bill' => {
'name' => 'When prorating, defer the first bill until the '.
#so 1.005 rounds to 1.01
$charge = sprintf('%.2f', $permonth * $months + 0.00000001 );
- my $quantity = $cust_pkg->quantity || 1;
- $charge *= $quantity;
-
return sprintf('%.2f', $charge);
}
my $self = shift;
my ($cust_pkg, $sdate) = @_;
my @cutoff_days = $self->cutoff_day($cust_pkg);
- if ( ! $cust_pkg->bill
- and $self->option('prorate_defer_bill',1)
- and @cutoff_days
- ) {
- my ($mnow, $mend, $mstart) = $self->_endpoints($sdate, @cutoff_days);
- # If today is the cutoff day, set the next bill and setup both to
- # midnight today, so that the customer will be billed normally for a
- # month starting today.
- if ( $mnow - $mstart < 86400 ) {
- $cust_pkg->setup($mstart);
- $cust_pkg->bill($mstart);
- }
- else {
- $cust_pkg->bill($mend);
+ if ( @cutoff_days and $self->option('prorate_defer_bill', 1) ) {
+ if ( $cust_pkg->setup ) {
+ # Setup date is already set. Then we're being called indirectly via calc_prorate
+ # to calculate the deferred setup fee. Allow that to happen normally.
+ return 0;
+ } else {
+ # We're going to set the setup date (so that the deferred billing knows when
+ # the package started) and suppress charging the setup fee.
+ if ( $cust_pkg->bill ) {
+ # For some reason (probably user override), the bill date has been set even
+ # though the package isn't billing yet. Start billing as though that was the
+ # start date.
+ $sdate = $cust_pkg->bill;
+ $cust_pkg->setup($cust_pkg->bill);
+ }
+ # Now figure the start and end of the period that contains the start date.
+ my ($mnow, $mend, $mstart) = $self->_endpoints($sdate, @cutoff_days);
+ # If today is the cutoff day, set the next bill and setup both to
+ # midnight today, so that the customer will be billed normally for a
+ # month starting today.
+ if ( $mnow - $mstart < 86400 ) {
+ $cust_pkg->setup($mstart);
+ $cust_pkg->bill($mstart);
+ }
+ else {
+ $cust_pkg->bill($mend);
+ }
+ return 1;
}
- return 1;
}
return 0;
}
# only works for freq >= 1 month; probably can't be fixed
my ($sec, $min, $hour, $mday, $mon, $year) = (localtime($mnow))[0..5];
- if( $self->option('prorate_round_day',1) ) {
+ my $rounding_mode = $self->option('prorate_round_day',1);
+ if ( $rounding_mode == 1 ) {
# If the time is 12:00-23:59, move to the next day by adding 18
# hours to $mnow. Because of DST this can end up from 05:00 to 18:59
# but it's always within the next day.
($mday,$mon,$year) = (localtime($mnow))[3..5];
# Then set $mnow to midnight on that day.
$mnow = timelocal(0,0,0,$mday,$mon,$year);
+ } elsif ( $rounding_mode == 2 ) {
+ # Move the time back to midnight. This increases the length of the
+ # prorate interval.
+ $mnow = timelocal(0,0,0,$mday,$mon,$year);
+ ($mday,$mon,$year) = (localtime($mnow))[3..5];
+ } elsif ( $rounding_mode == 3 ) {
+ # If the time is after midnight, move it forward to the next midnight.
+ # This decreases the length of the prorate interval.
+ if ( $sec > 0 or $min > 0 or $hour > 0 ) {
+ # move to one second before midnight, then tick forward
+ $mnow = timelocal(59,59,23,$mday,$mon,$year) + 1;
+ ($mday,$mon,$year) = (localtime($mnow))[3..5];
+ }
}
my $mend;
my $mstart;