Revision 430216b9
Von Moritz Bunkus vor fast 10 Jahren hinzugefügt
SL/BackgroundJob/CreatePeriodicInvoices.pm | ||
---|---|---|
66 | 66 |
} |
67 | 67 |
|
68 | 68 |
sub _log_msg { |
69 |
my $message = join('', @_); |
|
69 |
my $message = join('', 'SL::BackgroundJob::CreatePeriodicInvoices: ', @_);
|
|
70 | 70 |
$message .= "\n" unless $message =~ m/\n$/; |
71 | 71 |
$::lxdebug->message(LXDebug::DEBUG1(), $message); |
72 | 72 |
} |
... | ... | |
142 | 142 |
$params{object}->$sub($str); |
143 | 143 |
} |
144 | 144 |
|
145 |
sub _adjust_sellprices_for_period_lengths { |
|
146 |
my (%params) = @_; |
|
147 |
|
|
148 |
my $billing_len = $params{config}->get_billing_period_length; |
|
149 |
my $order_value_len = $params{config}->get_order_value_period_length; |
|
150 |
|
|
151 |
return if $billing_len == $order_value_len; |
|
152 |
|
|
153 |
my $is_last_invoice_in_cycle = $params{config}->is_last_bill_date_in_order_value_cycle(date => $params{period_start_date}); |
|
154 |
|
|
155 |
_log_msg("_adjust_sellprices_for_period_lengths: period_start_date $params{period_start_date} is_last_invoice_in_cycle $is_last_invoice_in_cycle billing_len $billing_len order_value_len $order_value_len"); |
|
156 |
|
|
157 |
if ($order_value_len < $billing_len) { |
|
158 |
my $num_orders_per_invoice = $billing_len / $order_value_len; |
|
159 |
|
|
160 |
$_->sellprice($_->sellprice * $num_orders_per_invoice) for @{ $params{invoice}->items }; |
|
161 |
|
|
162 |
return; |
|
163 |
} |
|
164 |
|
|
165 |
my $num_invoices_in_cycle = $order_value_len / $billing_len; |
|
166 |
|
|
167 |
foreach my $item (@{ $params{invoice}->items }) { |
|
168 |
my $sellprice_one_invoice = $::form->round_amount($item->sellprice * $billing_len / $order_value_len, 2); |
|
169 |
|
|
170 |
if ($is_last_invoice_in_cycle) { |
|
171 |
$item->sellprice($item->sellprice - ($num_invoices_in_cycle - 1) * $sellprice_one_invoice); |
|
172 |
|
|
173 |
} else { |
|
174 |
$item->sellprice($sellprice_one_invoice); |
|
175 |
} |
|
176 |
} |
|
177 |
} |
|
178 |
|
|
145 | 179 |
sub _create_periodic_invoice { |
146 | 180 |
$main::lxdebug->enter_sub(); |
147 | 181 |
|
... | ... | |
174 | 208 |
_replace_vars(object => $item, vars => $time_period_vars, attribute => $_, attribute_format => ($_ eq 'longdescription' ? 'html' : 'text')) for qw(description longdescription); |
175 | 209 |
} |
176 | 210 |
|
211 |
_adjust_sellprices_for_period_lengths(invoice => $invoice, config => $config, period_start_date => $period_start_date); |
|
212 |
|
|
177 | 213 |
$invoice->post(ar_id => $config->ar_chart_id) || die; |
178 | 214 |
|
179 | 215 |
# like $form->add_shipto, but we don't need to check for a manual exception, |
... | ... | |
210 | 246 |
period_start_date => $period_start_date) |
211 | 247 |
->save; |
212 | 248 |
|
249 |
_log_msg("_create_invoice created for period start date $period_start_date id " . $invoice->id . " number " . $invoice->invnumber . " netamount " . $invoice->netamount . " amount " . $invoice->amount); |
|
250 |
|
|
213 | 251 |
# die $invoice->transaction_description; |
214 | 252 |
})) { |
215 | 253 |
$::lxdebug->message(LXDebug->WARN(), "_create_invoice failed: " . join("\n", (split(/\n/, $self->{db_obj}->db->error))[0..2])); |
SL/DB/PeriodicInvoicesConfig.pm | ||
---|---|---|
28 | 28 |
} |
29 | 29 |
|
30 | 30 |
sub _log_msg { |
31 |
$::lxdebug->message(LXDebug->DEBUG1(), join('', @_)); |
|
31 |
$::lxdebug->message(LXDebug->DEBUG1(), join('', 'SL::DB::PeriodicInvoicesConfig: ', @_));
|
|
32 | 32 |
} |
33 | 33 |
|
34 | 34 |
sub handle_automatic_extension { |
... | ... | |
87 | 87 |
my ($self, %params) = @_; |
88 | 88 |
|
89 | 89 |
my $period_len = $self->get_billing_period_length; |
90 |
my $cur_date = $self->first_billing_date || $self->start_date;
|
|
90 |
my $cur_date = ($self->first_billing_date || $self->start_date)->clone;
|
|
91 | 91 |
my $end_date = $self->terminated ? $self->end_date : undef; |
92 | 92 |
$end_date //= DateTime->today_local->add(years => 100); |
93 |
my $start_date = $params{past_dates} ? undef : $self->get_previous_billed_period_start_date; |
|
94 |
$start_date = $start_date ? $start_date->add(days => 1) : $cur_date->clone; |
|
93 |
my $start_date = $params{past_dates} ? undef : $self->get_previous_billed_period_start_date;
|
|
94 |
$start_date = $start_date ? $start_date->clone->add(days => 1) : $cur_date->clone;
|
|
95 | 95 |
|
96 | 96 |
$start_date = max($start_date, $params{start_date}) if $params{start_date}; |
97 | 97 |
$end_date = min($end_date, $params{end_date}) if $params{end_date}; |
... | ... | |
107 | 107 |
return @dates; |
108 | 108 |
} |
109 | 109 |
|
110 |
sub is_last_bill_date_in_order_value_cycle { |
|
111 |
my ($self, %params) = @_; |
|
112 |
|
|
113 |
my $months_billing = $self->get_billing_period_length; |
|
114 |
my $months_order_value = $self->get_order_value_period_length; |
|
115 |
|
|
116 |
return 1 if $months_billing >= $months_order_value; |
|
117 |
|
|
118 |
my $next_billing_date = $params{date}->clone->add(months => $months_billing); |
|
119 |
my $date_itr = max($self->start_date, $self->first_billing_date || $self->start_date)->clone; |
|
120 |
|
|
121 |
_log_msg("is_last_billing_date_in_order_value_cycle start: id " . $self->id . " date_itr $date_itr start " . $self->start_date); |
|
122 |
|
|
123 |
$date_itr->add(months => $months_order_value) while $date_itr < $next_billing_date; |
|
124 |
|
|
125 |
_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 " |
|
126 |
. ($date_itr == $next_billing_date)); |
|
127 |
|
|
128 |
return $date_itr == $next_billing_date; |
|
129 |
} |
|
130 |
|
|
110 | 131 |
1; |
111 | 132 |
__END__ |
112 | 133 |
|
... | ... | |
192 | 213 |
will be set to 1, and the configuration will be saved. In this case |
193 | 214 |
C<undef> will be returned. |
194 | 215 |
|
216 |
=item C<is_last_billing_date_in_order_value_cycle %params> |
|
217 |
|
|
218 |
Determines whether or not the mandatory parameter C<date>, an instance |
|
219 |
of L<DateTime>, is the last billing date within the cycle given by the |
|
220 |
order value periodicity. Returns a truish value if this is the case |
|
221 |
and a falsish value otherwise. |
|
222 |
|
|
223 |
This check is always true if the billing periodicity is longer than or |
|
224 |
equal to the order value periodicity. For example, if you have an |
|
225 |
order whose value is given for three months and you bill every six |
|
226 |
months and you have twice the order value on each invoice, meaning |
|
227 |
each invoice is itself the last invoice for not only one but two order |
|
228 |
value cycles. |
|
229 |
|
|
230 |
Otherwise (if the order value periodicity is longer than the billing |
|
231 |
periodicity) this function iterates over all eligible dates starting |
|
232 |
with C<first_billing_date> (or C<start_date> if C<first_billing_date> |
|
233 |
is unset) and adding the order value length with each step. If the |
|
234 |
date given by the C<date> parameter plus the billing period length |
|
235 |
equals one of those dates then the given date is indeed the date of |
|
236 |
the last invoice in that particular order value cycle. |
|
237 |
|
|
195 | 238 |
=back |
196 | 239 |
|
197 | 240 |
=head1 BUGS |
Auch abrufbar als: Unified diff
Wiederkehrende Rechnungen: Berechnung für Auftragswertperiodizität angepasst