Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision fe13d7f1

Von Tamino Steinert vor 3 Monaten hinzugefügt

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

S:D:PeriodicInvoicesConfig: Monatsgrenzen beachten

Unterschiede anzeigen:

SL/DB/PeriodicInvoicesConfig.pm
5 5
use SL::DB::MetaSetup::PeriodicInvoicesConfig;
6 6
use SL::DB::Manager::PeriodicInvoicesConfig;
7 7

  
8
use Params::Validate qw(:all);
8 9
use List::Util qw(max min);
9 10

  
11
use SL::Helper::DateTime;
12

  
10 13
__PACKAGE__->meta->initialize;
11 14

  
12 15
our %PERIOD_LENGTHS             = ( o => 0, m => 1, q => 3, b => 6, y => 12 );
......
14 17
our @PERIODICITIES              = keys %PERIOD_LENGTHS;
15 18
our @ORDER_VALUE_PERIODICITIES  = keys %ORDER_VALUE_PERIOD_LENGTHS;
16 19

  
20
sub calculate_invoice_dates {
21
  my $self = shift;
22

  
23
  my %params = validate(@_, {
24
    start_date => {
25
      callbacks => { is_date => \&_is_date, },
26
      default   => $self->start_date,
27
    },
28
    end_date   => {
29
      callbacks => { is_date => \&_is_date, },
30
      default   => DateTime->today_local,
31
    },
32
  });
33

  
34
  my $start_date = DateTime->from_ymd($params{start_date});
35
  my $end_date   = DateTime->from_ymd($params{end_date});
36

  
37
  if ($self->end_date
38
      && ($self->terminated || !$self->extend_automatically_by) ) {
39
    $end_date = min($end_date, $self->end_date);
40
  }
41

  
42
  my $last_created_on_date = $self->get_previous_billed_period_start_date;
43

  
44
  my @start_dates;
45
  my $first_period_start_date = $self->first_billing_date || $self->start_date;
46
  if ($self->periodicity ne 'o') {
47
    my $billing_period_length = $self->get_billing_period_length;
48
    my $months_first_period =
49
      $first_period_start_date->year * 12 + $first_period_start_date->month;
50

  
51
    my $month_to_start = $start_date->year * 12 + $start_date->month - $months_first_period;
52
    $month_to_start += 1
53
      if add_months($first_period_start_date, $month_to_start) < $start_date;
54

  
55
    my $month_after_last_created = 0;
56
    if ($last_created_on_date) {
57
      $month_after_last_created =
58
        $last_created_on_date->year * 12 + $last_created_on_date->month - $months_first_period;
59
      $month_after_last_created += 1
60
        if add_months($first_period_start_date, $month_after_last_created) <= $last_created_on_date;
61
    }
62

  
63
    my $months_from_period_start = max(
64
      $month_to_start,
65
      $month_after_last_created,
66
      0);
67

  
68
    my $period_count = int($months_from_period_start / $billing_period_length); # floor
69
    $period_count += $months_from_period_start % $billing_period_length != 0 ? 1 : 0; # ceil
70

  
71
    my $next_period_start_date = add_months($first_period_start_date, $period_count * $billing_period_length);
72
    while ($next_period_start_date <= $end_date) {
73
      push @start_dates, $next_period_start_date;
74
      $period_count++;
75
      $next_period_start_date = add_months($first_period_start_date, $period_count * $billing_period_length);
76
    }
77
  } else { # single
78
    push @start_dates, $first_period_start_date
79
      unless $last_created_on_date
80
          || $first_period_start_date < $start_date
81
          || $first_period_start_date > $end_date;
82
  }
83

  
84
  return @start_dates;
85
}
86

  
17 87
sub get_billing_period_length {
18 88
  my $self = shift;
19 89
  return $PERIOD_LENGTHS{ $self->periodicity } || 1;
......
25 95
  return $ORDER_VALUE_PERIOD_LENGTHS{ $self->order_value_periodicity } || 1;
26 96
}
27 97

  
98
sub add_months {
99
  my ($date, $months) = @_;
100

  
101
  my $start_months_of_date = $date->month;
102
  $date = $date->clone();
103
  my $new_date = $date->clone();
104
  $new_date->add(months => $months);
105
  # stay in month: 31.01 + 1 month should be 28.02 or 29.02 (not 03.03. or 02.03)
106
  while (($start_months_of_date + $months) % 12 != $new_date->month % 12) {
107
    $new_date->add(days => -1);
108
  }
109

  
110
  # if date was at end of month -> move new date also to end of month
111
  if ($date->is_last_day_of_month()) {
112
    return DateTime->last_day_of_month(year => $new_date->year, month => $new_date->month)
113
  }
114

  
115
  return $new_date
116
};
117

  
118
sub _is_date {
119
   return !!DateTime->from_ymd($_[0]); # can also be a DateTime object
120
}
121

  
28 122
sub _log_msg {
29 123
  $::lxdebug->message(LXDebug->DEBUG1(), join('', 'SL::DB::PeriodicInvoicesConfig: ', @_));
30 124
}
......
57 151

  
58 152
  # Add the automatic extension period to the new end date as long as
59 153
  # the new end date is in the past. Then save it and get out.
60
  $end_date->add(months => $self->extend_automatically_by) while $today > $end_date;
154
  $end_date = add_months($end_date, $self->extend_automatically_by) while $today > $end_date;
61 155
  _log_msg("new end date $end_date\n");
62 156

  
63 157
  $self->end_date($end_date);
......
81 175
  return ref $date ? $date : $self->db->parse_date($date);
82 176
}
83 177

  
84
sub calculate_invoice_dates {
85
  my ($self, %params) = @_;
86

  
87
  my $period_len = $self->get_billing_period_length;
88
  my $cur_date   = ($self->first_billing_date || $self->start_date)->clone;
89
  my $end_date   = $self->terminated || !$self->extend_automatically_by ? $self->end_date : undef;
90
  $end_date    //= DateTime->today_local->add(years => 100);
91
  my $start_date = $params{past_dates} ? undef                              : $self->get_previous_billed_period_start_date;
92
  $start_date    = $start_date         ? $start_date->clone->add(days => 1) : $cur_date->clone;
93

  
94
  $start_date    = max($start_date, $params{start_date}) if $params{start_date};
95
  $end_date      = min($end_date,   $params{end_date})   if $params{end_date};
96

  
97
  if ($self->periodicity eq 'o') {
98
    return ($cur_date >= $start_date) && ($cur_date <= $end_date) ? ($cur_date) : ();
99
  }
100

  
101
  my @dates;
102

  
103
  while ($cur_date <= $end_date) {
104
    push @dates, $cur_date->clone if $cur_date >= $start_date;
105

  
106
    $cur_date->add(months => $period_len);
107
  }
108

  
109
  return @dates;
110
}
111

  
112 178
sub is_last_bill_date_in_order_value_cycle {
113
  my ($self, %params)    = @_;
179
  my $self    = shift;
180

  
181
  my %params = validate(@_, {
182
    date => { callbacks => { is_date => \&_is_date, } },
183
  });
114 184

  
115 185
  my $months_billing     = $self->get_billing_period_length;
116 186
  my $months_order_value = $self->get_order_value_period_length;
117 187

  
118 188
  return 1 if $months_billing >= $months_order_value;
119 189

  
120
  my $next_billing_date = $params{date}->clone->add(months => $months_billing);
121
  my $date_itr          = max($self->start_date, $self->first_billing_date || $self->start_date)->clone;
122

  
123
  _log_msg("is_last_billing_date_in_order_value_cycle start: id " . $self->id . " date_itr $date_itr start " . $self->start_date);
124

  
125
  $date_itr->add(months => $months_order_value) while $date_itr < $next_billing_date;
126

  
127
  _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 "
128
           . ($date_itr == $next_billing_date));
190
  my $billing_date = DateTime->from_ymd($params{date});
191
  my $first_date   = $self->first_billing_date || $self->start_date;
129 192

  
130
  return $date_itr == $next_billing_date;
193
  return (12 * ($billing_date->year - $first_date->year) + $billing_date->month + $months_billing) % $months_order_value
194
    == $first_date->month % $months_order_value;
131 195
}
132 196

  
133 197
sub disable_one_time_config {

Auch abrufbar als: Unified diff