Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 429bf6a8

Von Tamino Steinert vor 5 Monaten hinzugefügt

  • ID 429bf6a85ce5e5e00583aa5515eb01b460c9f899
  • Vorgänger 9654716e
  • Nachfolger 80db1ffd

S:B:CreatePeriodicInvoices: Nutze Auftragshelferfunktion von Config

Unterschiede anzeigen:

SL/BackgroundJob/CreatePeriodicInvoices.pm
8 8
use DateTime::Format::Strptime;
9 9
use English qw(-no_match_vars);
10 10
use List::MoreUtils qw(uniq);
11
use Params::Validate qw(:all);
11 12

  
12 13
use SL::Common;
13 14
use SL::DB::AuthUser;
......
47 48
    _log_msg("Number of configs: " . scalar(@{ $configs}));
48 49

  
49 50
    foreach my $config (@{ $configs }) {
50
      # A configuration can be set to inactive by
51
      # $config->handle_automatic_extension. Therefore the check in
52
      # ...->get_all() does not suffice.
53
      _log_msg("Config " . $config->id . " active " . $config->active);
54
      next unless $config->active;
51
      my $open_orders = $config->get_open_orders_for_period();
52
      _log_msg("Dates: " . join(' ', map { $_->reqdate->to_lxoffice } @$open_orders));
55 53

  
56
      my @dates = _calculate_dates($config);
54
      foreach my $order (@$open_orders) {
55
        my $data = $self->_create_periodic_invoice(order => $order);
56
        my $invoice = $data->{invoice};
57
        next unless $invoice;
57 58

  
58
      _log_msg("Dates: " . join(' ', map { $_->to_lxoffice } @dates));
59
        _log_msg("Invoice " . $invoice->invnumber . " posted for config ID " . $config->id . ", period start date " . $::locale->format_date(\%::myconfig, $invoice->deliverydate) . "\n");
59 60

  
60
      foreach my $date (@dates) {
61
        my $data = $self->_create_periodic_invoice($config, $date);
62
        next unless $data;
63

  
64
        _log_msg("Invoice " . $data->{invoice}->invnumber . " posted for config ID " . $config->id . ", period start date " . $::locale->format_date(\%::myconfig, $date) . "\n");
65

  
66
        push @{ $self->{posted_invoices} }, $data->{invoice};
61
        push @{ $self->{posted_invoices} }, $invoice;
67 62
        push @invoices_to_print, $data if $config->print;
68 63
        push @invoices_to_email, $data if $config->send_email;
69 64

  
......
77 72
      }
78 73
    }
79 74

  
80
    foreach my $inv ( @invoices_to_print ) { $self->_print_invoice($inv); }
81
    foreach my $inv ( @invoices_to_email ) { $self->_email_invoice($inv); }
75
    foreach my $inv_data ( @invoices_to_print ) { $self->_print_invoice($inv_data); }
76
    foreach my $inv_data ( @invoices_to_email ) { $self->_email_invoice($inv_data); }
82 77

  
83 78
    $self->_send_summary_email;
84 79

  
......
179 174
  $params{object}->$sub($str);
180 175
}
181 176

  
182
sub _adjust_sellprices_for_period_lengths {
183
  my (%params) = @_;
184

  
185
  return if $params{config}->periodicity eq 'o';
186

  
187
  my $billing_len     = $params{config}->get_billing_period_length;
188
  my $order_value_len = $params{config}->get_order_value_period_length;
189

  
190
  return if $billing_len == $order_value_len;
191

  
192
  my $is_last_invoice_in_cycle = $params{config}->is_last_bill_date_in_order_value_cycle(date => $params{period_start_date});
193

  
194
  _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");
195

  
196
  if ($order_value_len < $billing_len) {
197
    my $num_orders_per_invoice = $billing_len / $order_value_len;
198

  
199
    $_->sellprice($_->sellprice * $num_orders_per_invoice) for @{ $params{invoice}->items };
200

  
201
    return;
202
  }
203

  
204
  my $num_invoices_in_cycle = $order_value_len / $billing_len;
205

  
206
  foreach my $item (@{ $params{invoice}->items }) {
207
    my $sellprice_one_invoice = $::form->round_amount($item->sellprice * $billing_len / $order_value_len, 2);
208

  
209
    if ($is_last_invoice_in_cycle) {
210
      $item->sellprice($item->sellprice - ($num_invoices_in_cycle - 1) * $sellprice_one_invoice);
211

  
212
    } else {
213
      $item->sellprice($sellprice_one_invoice);
214
    }
215
  }
216
}
217

  
218 177
sub _create_periodic_invoice {
219
  my $self              = shift;
220
  my $config            = shift;
221
  my $period_start_date = shift;
178
  my $self  = shift;
222 179

  
223
  my $time_period_vars  = _generate_time_period_variables($config, $period_start_date);
180
  my %params = validate(@_, {
181
    order => { isa => 'SL::DB::Order' },
182
  });
183
  my $order = $params{order};
224 184

  
225
  my $invdate           = DateTime->today_local;
185
  my $period_start_date = $order->reqdate;
186
  my $config            = $order->periodic_invoices_config;
187
  my $time_period_vars  = _generate_time_period_variables($config, $period_start_date);
226 188

  
227
  my $order   = $config->order;
228 189
  my $invoice;
229 190
  if (!$self->{db_obj}->db->with_transaction(sub {
230 191
    1;                          # make Emacs happy
231 192

  
232 193
    $invoice = SL::DB::Invoice->new_from($order, honor_recurring_billing_mode => 1);
233 194

  
234
    my $tax_point = ($invoice->tax_point // $time_period_vars->{period_end_date}->[0])->clone;
235

  
236
    while ($tax_point < $period_start_date) {
237
      $tax_point->add(months => $config->get_billing_period_length);
238
    }
239

  
240 195
    my $intnotes  = $invoice->intnotes ? $invoice->intnotes . "\n\n" : '';
241
    $intnotes    .= "Automatisch am " . $invdate->to_lxoffice . " erzeugte Rechnung";
196
    $intnotes    .= "Automatisch am " . DateTime->today_local->to_lxoffice . " erzeugte Rechnung";
242 197

  
243
    $invoice->assign_attributes(deliverydate => $period_start_date,
244
                                tax_point    => $tax_point,
245
                                intnotes     => $intnotes,
246
                                employee     => $order->employee, # new_from sets employee to import user
247
                                direct_debit => $config->direct_debit,
248
                               );
198
    $invoice->assign_attributes(
199
      intnotes     => $intnotes,
200
      employee     => $order->employee, # new_from sets employee to import user
201
      direct_debit => $config->direct_debit,
202
    );
249 203

  
250 204
    _replace_vars(object => $invoice, vars => $time_period_vars, attribute => $_, attribute_format => ($_ eq 'notes' ? 'html' : 'text')) for qw(notes intnotes transaction_description);
251 205

  
......
253 207
      _replace_vars(object => $item, vars => $time_period_vars, attribute => $_, attribute_format => ($_ eq 'longdescription' ? 'html' : 'text')) for qw(description longdescription);
254 208
    }
255 209

  
256
    _adjust_sellprices_for_period_lengths(invoice => $invoice, config => $config, period_start_date => $period_start_date);
257

  
258 210
    $invoice->post(ar_id => $config->ar_chart_id) || die;
259 211

  
260 212
    foreach my $item (grep { ($_->recurring_billing_mode eq 'once') && !$_->recurring_billing_invoice_id } @{ $order->orderitems }) {
......
278 230

  
279 231
  return {
280 232
    config            => $config,
281
    period_start_date => $period_start_date,
282 233
    invoice           => $invoice,
283 234
    time_period_vars  => $time_period_vars,
284 235
  };
285 236
}
286 237

  
287
sub _calculate_dates {
288
  my ($config) = @_;
289
  return $config->calculate_invoice_dates(end_date => DateTime->today_local);
290
}
291

  
292 238
sub _send_summary_email {
293 239
  my ($self) = @_;
294 240
  my %config = %::lx_office_conf;
......
376 322
}
377 323

  
378 324
sub _print_invoice {
379
  my ($self, $data) = @_;
325
  my $self = shift;
380 326

  
381
  my $invoice       = $data->{invoice};
382
  my $config        = $data->{config};
327
    my %params = validate_with(
328
    params => \@_,
329
    spec   => {
330
      invoice => { isa => 'SL::DB::Invoice' },
331
      config  => { isa => 'SL::DB::PeriodicInvoicesConfig' },
332
    },
333
    allow_extra => 1,
334
  );
335

  
336
  my $invoice = $params{invoice};
337
  my $config  = $params{config};
383 338

  
384 339
  return unless $config->print && $config->printer_id && $config->printer->printer_command;
385 340

  
......
412 367
}
413 368

  
414 369
sub _email_invoice {
415
  my ($self, $data) = @_;
416

  
417
  $data->{config}->load;
370
  my $self = shift;
371

  
372
  my %params = validate_with(
373
    params => \@_,
374
    spec   => {
375
      invoice => { isa => 'SL::DB::Invoice' },
376
      config  => { isa => 'SL::DB::PeriodicInvoicesConfig' },
377
      time_period_vars => { type => HASHREF },
378
    },
379
    allow_extra => 1,
380
  );
418 381

  
419
  return unless $data->{config}->send_email;
382
  my $invoice = $params{invoice};
383
  my $config  = $params{config};
384
  my $time_period_vars = $params{time_period_vars};
420 385

  
421 386
  my @recipients =
422 387
    uniq
423 388
    map  { lc       }
424 389
    grep { $_       }
425 390
    map  { trim($_) }
426
    (split(m{,}, $data->{config}->email_recipient_address),
427
     $data->{config}->email_recipient_contact   ? ($data->{config}->email_recipient_contact->cp_email) : (),
428
     $data->{invoice}->{customer}->invoice_mail ? ($data->{invoice}->{customer}->invoice_mail) : ()
391
    (split(m{,}, $config->email_recipient_address),
392
     $config->email_recipient_contact   ? ($config->email_recipient_contact->cp_email) : (),
393
     $invoice->{customer}->invoice_mail ? ($invoice->{customer}->invoice_mail) : ()
429 394
    );
430 395

  
431 396
  return unless @recipients;
432 397

  
433
  my $language      = $data->{invoice}->language ? $data->{invoice}->language->template_code : undef;
398
  my $language      = $invoice->language ? $invoice->language->template_code : undef;
434 399
  my %create_params = (
435 400
    template               => scalar($self->find_template(name => 'invoice', language => $language)),
436 401
    variables              => Form->new(''),
437 402
    return                 => 'file_name',
438
    record                 => $data->{invoice},
403
    record                 => $invoice,
439 404
    variable_content_types => {
440 405
      longdescription => 'html',
441 406
      partnotes       => 'html',
......
444 409
    },
445 410
  );
446 411

  
447
  $data->{invoice}->flatten_to_form($create_params{variables}, format_amounts => 1);
412
  $invoice->flatten_to_form($create_params{variables}, format_amounts => 1);
448 413
  $create_params{variables}->prepare_for_printing;
449 414

  
450 415
  my $pdf_file_name;
......
453 418
  eval {
454 419
    $pdf_file_name = $self->create_pdf(%create_params);
455 420

  
456
    $self->_store_pdf_in_webdav        ($pdf_file_name, $data->{invoice});
457
    $self->_store_pdf_in_filemanagement($pdf_file_name, $data->{invoice});
421
    $self->_store_pdf_in_webdav        ($pdf_file_name, $invoice);
422
    $self->_store_pdf_in_filemanagement($pdf_file_name, $invoice);
458 423

  
459 424
    for (qw(email_subject email_body)) {
460 425
      _replace_vars(
461
        object           => $data->{config},
462
        invoice          => $data->{invoice},
463
        vars             => $data->{time_period_vars},
426
        object           => $config,
427
        invoice          => $invoice,
428
        vars             => $time_period_vars,
464 429
        attribute        => $_,
465 430
        attribute_format => ($_ eq 'email_body' ? 'html' : 'text')
466 431
      );
......
471 436

  
472 437
    for my $recipient (@recipients) {
473 438
      my $mail             = Mailer->new;
474
      $mail->{record_id}   = $data->{invoice}->id,
439
      $mail->{record_id}   = $invoice->id,
475 440
      $mail->{record_type} = 'invoice',
476
      $mail->{from}        = $data->{config}->email_sender || $::lx_office_conf{periodic_invoices}->{email_from};
441
      $mail->{from}        = $config->email_sender || $::lx_office_conf{periodic_invoices}->{email_from};
477 442
      $mail->{to}          = $recipient;
478 443
      $mail->{bcc}         = $global_bcc;
479
      $mail->{subject}     = $data->{config}->email_subject;
480
      $mail->{message}     = $data->{config}->email_body;
444
      $mail->{subject}     = $config->email_subject;
445
      $mail->{message}     = $config->email_body;
481 446
      $mail->{message}    .= SL::DB::Default->get->signature;
482 447
      $mail->{content_type} = 'text/html';
483 448
      $mail->{attachments} = [{
484 449
        path     => $pdf_file_name,
485
        name     => sprintf('%s %s.pdf', $label, $data->{invoice}->invnumber),
450
        name     => sprintf('%s %s.pdf', $label, $invoice->invnumber),
486 451
      }];
487 452

  
488 453
      my $error        = $mail->send;
489 454

  
490 455
      if ($error) {
491 456
        push @{ $self->{job_errors} }, $error;
492
        push @{ $self->{emailed_failed} }, [ $data->{invoice}, $error ];
457
        push @{ $self->{emailed_failed} }, [ $invoice, $error ];
493 458
        $overall_error = 1;
494 459
      }
495 460
    }
496 461

  
497
    push @{ $self->{emailed_invoices} }, $data->{invoice} unless $overall_error;
462
    push @{ $self->{emailed_invoices} }, $invoice unless $overall_error;
498 463

  
499 464
    1;
500 465

  
501 466
  } or do {
502 467
    push @{ $self->{job_errors} }, $EVAL_ERROR;
503
    push @{ $self->{emailed_failed} }, [ $data->{invoice}, $EVAL_ERROR ];
468
    push @{ $self->{emailed_failed} }, [ $invoice, $EVAL_ERROR ];
504 469
  };
505 470

  
506 471
  unlink $pdf_file_name if $pdf_file_name;
......
521 486

  
522 487
=head1 SYNOPSIS
523 488

  
524
Iterate over all periodic invoice configurations, extend them if
525
applicable, calculate the dates for which invoices have to be posted
526
and post those invoices by converting the order into an invoice for
527
each date.
489
Iterate over all periodic invoice configurations, extend the end date if
490
applicable, get all open orders from the
528 491

  
529 492
=head1 TOTO
530 493

  

Auch abrufbar als: Unified diff