Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision fe13d7f1

Von Tamino Steinert vor 9 Monaten hinzugefügt

  • ID fe13d7f1dc63b7a512c97b73a18bd8777539318a
  • Vorgänger d4ec5f32
  • Nachfolger 3e714a7f

S:D:PeriodicInvoicesConfig: Monatsgrenzen beachten

Unterschiede anzeigen:

SL/DB/PeriodicInvoicesConfig.pm
use SL::DB::MetaSetup::PeriodicInvoicesConfig;
use SL::DB::Manager::PeriodicInvoicesConfig;
use Params::Validate qw(:all);
use List::Util qw(max min);
use SL::Helper::DateTime;
__PACKAGE__->meta->initialize;
our %PERIOD_LENGTHS = ( o => 0, m => 1, q => 3, b => 6, y => 12 );
......
our @PERIODICITIES = keys %PERIOD_LENGTHS;
our @ORDER_VALUE_PERIODICITIES = keys %ORDER_VALUE_PERIOD_LENGTHS;
sub calculate_invoice_dates {
my $self = shift;
my %params = validate(@_, {
start_date => {
callbacks => { is_date => \&_is_date, },
default => $self->start_date,
},
end_date => {
callbacks => { is_date => \&_is_date, },
default => DateTime->today_local,
},
});
my $start_date = DateTime->from_ymd($params{start_date});
my $end_date = DateTime->from_ymd($params{end_date});
if ($self->end_date
&& ($self->terminated || !$self->extend_automatically_by) ) {
$end_date = min($end_date, $self->end_date);
}
my $last_created_on_date = $self->get_previous_billed_period_start_date;
my @start_dates;
my $first_period_start_date = $self->first_billing_date || $self->start_date;
if ($self->periodicity ne 'o') {
my $billing_period_length = $self->get_billing_period_length;
my $months_first_period =
$first_period_start_date->year * 12 + $first_period_start_date->month;
my $month_to_start = $start_date->year * 12 + $start_date->month - $months_first_period;
$month_to_start += 1
if add_months($first_period_start_date, $month_to_start) < $start_date;
my $month_after_last_created = 0;
if ($last_created_on_date) {
$month_after_last_created =
$last_created_on_date->year * 12 + $last_created_on_date->month - $months_first_period;
$month_after_last_created += 1
if add_months($first_period_start_date, $month_after_last_created) <= $last_created_on_date;
}
my $months_from_period_start = max(
$month_to_start,
$month_after_last_created,
0);
my $period_count = int($months_from_period_start / $billing_period_length); # floor
$period_count += $months_from_period_start % $billing_period_length != 0 ? 1 : 0; # ceil
my $next_period_start_date = add_months($first_period_start_date, $period_count * $billing_period_length);
while ($next_period_start_date <= $end_date) {
push @start_dates, $next_period_start_date;
$period_count++;
$next_period_start_date = add_months($first_period_start_date, $period_count * $billing_period_length);
}
} else { # single
push @start_dates, $first_period_start_date
unless $last_created_on_date
|| $first_period_start_date < $start_date
|| $first_period_start_date > $end_date;
}
return @start_dates;
}
sub get_billing_period_length {
my $self = shift;
return $PERIOD_LENGTHS{ $self->periodicity } || 1;
......
return $ORDER_VALUE_PERIOD_LENGTHS{ $self->order_value_periodicity } || 1;
}
sub add_months {
my ($date, $months) = @_;
my $start_months_of_date = $date->month;
$date = $date->clone();
my $new_date = $date->clone();
$new_date->add(months => $months);
# stay in month: 31.01 + 1 month should be 28.02 or 29.02 (not 03.03. or 02.03)
while (($start_months_of_date + $months) % 12 != $new_date->month % 12) {
$new_date->add(days => -1);
}
# if date was at end of month -> move new date also to end of month
if ($date->is_last_day_of_month()) {
return DateTime->last_day_of_month(year => $new_date->year, month => $new_date->month)
}
return $new_date
};
sub _is_date {
return !!DateTime->from_ymd($_[0]); # can also be a DateTime object
}
sub _log_msg {
$::lxdebug->message(LXDebug->DEBUG1(), join('', 'SL::DB::PeriodicInvoicesConfig: ', @_));
}
......
# Add the automatic extension period to the new end date as long as
# the new end date is in the past. Then save it and get out.
$end_date->add(months => $self->extend_automatically_by) while $today > $end_date;
$end_date = add_months($end_date, $self->extend_automatically_by) while $today > $end_date;
_log_msg("new end date $end_date\n");
$self->end_date($end_date);
......
return ref $date ? $date : $self->db->parse_date($date);
}
sub calculate_invoice_dates {
my ($self, %params) = @_;
my $period_len = $self->get_billing_period_length;
my $cur_date = ($self->first_billing_date || $self->start_date)->clone;
my $end_date = $self->terminated || !$self->extend_automatically_by ? $self->end_date : undef;
$end_date //= DateTime->today_local->add(years => 100);
my $start_date = $params{past_dates} ? undef : $self->get_previous_billed_period_start_date;
$start_date = $start_date ? $start_date->clone->add(days => 1) : $cur_date->clone;
$start_date = max($start_date, $params{start_date}) if $params{start_date};
$end_date = min($end_date, $params{end_date}) if $params{end_date};
if ($self->periodicity eq 'o') {
return ($cur_date >= $start_date) && ($cur_date <= $end_date) ? ($cur_date) : ();
}
my @dates;
while ($cur_date <= $end_date) {
push @dates, $cur_date->clone if $cur_date >= $start_date;
$cur_date->add(months => $period_len);
}
return @dates;
}
sub is_last_bill_date_in_order_value_cycle {
my ($self, %params) = @_;
my $self = shift;
my %params = validate(@_, {
date => { callbacks => { is_date => \&_is_date, } },
});
my $months_billing = $self->get_billing_period_length;
my $months_order_value = $self->get_order_value_period_length;
return 1 if $months_billing >= $months_order_value;
my $next_billing_date = $params{date}->clone->add(months => $months_billing);
my $date_itr = max($self->start_date, $self->first_billing_date || $self->start_date)->clone;
_log_msg("is_last_billing_date_in_order_value_cycle start: id " . $self->id . " date_itr $date_itr start " . $self->start_date);
$date_itr->add(months => $months_order_value) while $date_itr < $next_billing_date;
_log_msg("is_last_billing_date_in_order_value_cycle end: refdate $params{date} next_billing_date $next_billing_date date_itr $date_itr months_billing $months_billing months_order_value $months_order_value result "
. ($date_itr == $next_billing_date));
my $billing_date = DateTime->from_ymd($params{date});
my $first_date = $self->first_billing_date || $self->start_date;
return $date_itr == $next_billing_date;
return (12 * ($billing_date->year - $first_date->year) + $billing_date->month + $months_billing) % $months_order_value
== $first_date->month % $months_order_value;
}
sub disable_one_time_config {

Auch abrufbar als: Unified diff