1 package SL::Controller::Letter;
4 use parent qw(SL::Controller::Base);
8 use POSIX qw(strftime);
9 use SL::Controller::Helper::GetModels;
10 use SL::Controller::Helper::ReportGenerator;
13 use SL::DB::LetterDraft;
15 use SL::Helper::Flash qw(flash flash_later);
16 use SL::Helper::CreatePDF;
17 use SL::Helper::PrintOptions;
18 use SL::Locale::String qw(t8);
21 use SL::ReportGenerator;
25 use Rose::Object::MakeMethods::Generic (
26 'scalar --get_set_init' => [ qw(letter all_employees models webdav_objects is_sales) ],
29 __PACKAGE__->run_before('check_auth_edit');
30 __PACKAGE__->run_before('check_auth_report', only => [ qw(list) ]);
32 use constant TEXT_CREATED_FOR_VALUES => (qw(presskit fax letter));
33 use constant PAGE_CREATED_FOR_VALUES => (qw(sketch 1 2));
37 subject => t8('Subject'),
38 letternumber => t8('Letternumber'),
39 customer_id => t8('Customer'),
40 vendor_id => t8('Vendor'),
41 contact => t8('Contact'),
47 my ($self, %params) = @_;
49 return if $self->load_letter_draft(%params);
51 $self->letter->employee_id(SL::DB::Manager::Employee->current->id);
52 $self->letter->salesman_id(SL::DB::Manager::Employee->current->id);
55 title => t8('Add Letter'),
56 language_id => $params{language_id},
61 my ($self, %params) = @_;
63 return $self->action_add
64 unless $::form->{letter} || $::form->{draft};
66 if ($::form->{draft}) {
67 $self->letter(SL::DB::Letter->new_from_draft($::form->{draft}{id}));
68 $self->is_sales($self->letter->is_sales);
72 title => t8('Edit Letter'),
77 my ($self, %params) = @_;
79 my $letter = $self->_update;
81 if (!$self->check_letter($letter)) {
82 return $self->_display;
88 flash('error', t8('There was an error saving the letter'));
89 return $self->_display;
92 flash('info', t8('Letter saved!'));
97 sub action_update_contacts {
100 my $letter = $self->letter;
102 if (!$self->letter->has_customer_vendor) {
106 SL::Presenter->get->select_tag('letter.cp_id', [], value_key => 'cp_id', title_key => 'full_name')
111 my $contacts = $letter->customer_vendor->contacts;
114 if ( $letter->contact
115 && $letter->contact->cp_cv_id
116 && $letter->contact->cp_cv_id == $letter->customer_vendor_id) {
117 $default = $letter->contact->cp_id;
125 SL::Presenter->get->select_tag('letter.cp_id', $contacts, default => $default, value_key => 'cp_id', title_key => 'full_name')
130 sub action_save_letter_draft {
131 my ($self, %params) = @_;
135 my $letter_draft = SL::DB::LetterDraft->new_from_letter($self->_update);
137 if (!$letter_draft->save) {
138 flash('error', t8('There was an error saving the letter draft'));
139 return $self->_display;
142 flash('info', t8('Draft for this Letter saved!'));
148 my ($self, %params) = @_;
150 if (!$self->letter->delete) {
151 flash('error', t8('An error occured. Letter could not be deleted.'));
152 return $self->action_update;
155 flash_later('info', t8('Letter deleted'));
156 $self->redirect_to(action => 'list');
159 sub action_delete_letter_drafts {
160 my ($self, %params) = @_;
162 my @ids = grep { /^checked_(.*)/ && $::form->{$_} } keys %$::form;
164 SL::DB::Manager::LetterDraft->delete_all(query => [ ids => \@ids ]) if @ids;
166 $self->redirect_to(action => 'add');
170 my ($self, %params) = @_;
172 $self->make_filter_summary;
173 $self->prepare_report;
175 my $letters = $self->models->get;
176 $self->report_generator_list_objects(report => $self->{report}, objects => $letters);
180 sub action_print_letter {
181 my ($self, %params) = @_;
183 my $display_form = $::form->{display_form} || "display_form";
184 my $letter = $self->_update;
186 my ($template_file, @template_files) = SL::Helper::CreatePDF->find_template(
188 printer_id => $::form->{printer_id},
189 language_id => $::form->{language_id},
190 formname => 'letter',
194 if (!defined $template_file) {
195 $::form->error($::locale->text('Cannot find matching template for this print request. Please contact your template maintainer. I tried these: #1.', join ', ', map { "'$_'"} @template_files));
200 %result = SL::Template::LaTeX->parse_and_create_pdf(
206 formname => 'letter',
207 language => SL::DB::Language->new,
209 format => $::form->{format},
210 media => $::form->{media},
211 printer => SL::DB::Manager::Printer->find_by_or_create(id => $::form->{printer_id} || undef),
212 today => DateTime->today,
216 die $result{error} if $result{error};
218 $::form->{type} = 'letter';
219 $::form->{formname} = 'letter';
220 $::form->{letternumber} = $letter->letternumber;
221 my $attachment_name = $::form->generate_attachment_filename;
223 if ($::instance_conf->get_webdav_documents) {
224 my $webdav_file = SL::Webdav::File->new(
225 filename => $attachment_name,
226 webdav => SL::Webdav->new(
228 number => $letter->letternumber,
232 $webdav_file->store(file => $result{file_name});
235 # set some form defaults for printing webdav copy variables
236 if ( $::form->{media} eq 'email') {
237 my $mail = Mailer->new;
238 my $signature = $::myconfig{signature};
239 $mail->{$_} = $params{email}->{$_} for qw(to cc subject message bcc);
240 $mail->{from} = qq|"$::myconfig{name}" <$::myconfig{email}>|;
241 $mail->{attachments} = [{ filename => $result{file_name},
242 name => $params{email}->{attachment_filename} }];
243 $mail->{message} .= "\n-- \n$signature";
244 $mail->{message} =~ s/\r//g;
247 unlink $result{file_name};
249 flash_later('info', t8('The email has been sent.'));
250 $self->redirect_to(action => 'edit', 'letter.id' => $letter->id);
255 if (!$::form->{printer_id} || $::form->{media} eq 'screen') {
256 $self->send_file($result{file_name}, name => $attachment_name);
257 unlink $result{file_name};
262 my $printer = SL::DB::Printer->new(id => $::form->{printer_id})->load;
263 $printer->print_document(
264 copies => $::form->{copies},
265 file_name => $result{file_name},
268 unlink $result{file_name};
270 flash_later('info', t8('The documents have been sent to the printer \'#1\'.', $printer->printer_description));
271 $self->redirect_to(action => 'edit', 'letter.id' => $letter->id, media => 'printer', printer_id => $::form->{printer_id});
274 unlink $result{file_name} if $result{file_name};
275 $::form->error(t8("Creating the PDF failed:") . " " . $@);
280 my ($self, $name_selected) = @_;
283 letter => $self->_update,
287 sub action_skip_draft {
289 $self->action_add(skip_drafts => 1);
292 sub action_delete_drafts {
295 my @ids = @{ $::form->{ids} || [] };
296 SL::DB::Manager::LetterDraft->delete_all(where => [ id => \@ids ]) if @ids;
298 $self->action_add(skip_drafts => 1);
301 sub action_edit_email {
304 my $letter = $self->_update;
305 $self->export_letter_to_form($letter);
307 $::form->{formname} = "letter";
308 $::form->{type} = "letter";
309 $::form->{letternumber} = $self->letter->letternumber;
312 my $value = $letter->$_;
313 $value = $value->to_kivitendo if ref($_) =~ m{Date};
315 { name => "letter.$_", value => $value }
316 } ($letter->meta->columns);
319 script => 'controller.pl',
320 title => t8('Send letter via e-mail'),
321 email => $letter->contact ? $letter->contact->cp_email : '',
322 subject => $::form->generate_email_subject,
323 a_filename => $::form->generate_attachment_filename,
324 action => 'Letter/send_email',
326 SHOW_BCC => $::auth->assert('email_bcc', 'may fail'),
329 $self->render('generic/edit_email', %vars);
332 sub action_send_email {
335 $::form->{media} = 'email';
336 $self->action_print_letter(
338 to => $::form->{email},
339 map { ($_ => $::form->{$_}) } qw(cc bcc subject attachment_filename message)
347 my ($self, %params) = @_;
349 $::request->{layout}->use_javascript("${_}.js") for qw(ckeditor/ckeditor ckeditor/adapters/jquery);
351 my $letter = $self->letter;
353 $params{title} ||= t8('Edit Letter');
355 $::form->{type} = 'letter'; # needed for print_options
356 $::form->{vc} = $letter->is_sales ? 'customer' : 'vendor'; # needs to be for _get_contacts...
358 $::request->layout->add_javascripts('customer_or_vendor_selection.js');
359 $::request->layout->add_javascripts('edit_part_window.js');
361 $::form->{language_id} ||= $params{language_id};
362 $::form->{printers} = SL::DB::Manager::Printer->get_all_sorted;
364 $self->render('letter/edit',
366 TCF => [ map { key => $_, value => t8(ucfirst $_) }, TEXT_CREATED_FOR_VALUES() ],
367 PCF => [ map { key => $_, value => t8(ucfirst $_) }, PAGE_CREATED_FOR_VALUES() ],
369 employees => $self->all_employees,
370 print_options => SL::Helper::PrintOptions->get_print_options (
371 options => { no_postscript => 1,
372 no_opendocument => 1,
380 my ($self, %params) = @_;
382 my $letter = $self->letter;
385 $self->set_greetings;
393 my $report = SL::ReportGenerator->new(\%::myconfig, $::form);
394 $self->{report} = $report;
396 my @columns = qw(date subject letternumber customer_id vendor_id contact date);
397 my @sortable = qw(date subject letternumber customer_id vendor_id contact date);
400 date => { text => t8('Date'), sub => sub { $_[0]->date_as_date } },
401 subject => { text => t8('Subject'), sub => sub { $_[0]->subject },
402 obj_link => sub { $self->url_for(action => 'edit', 'letter.id' => $_[0]->id, callback => $self->models->get_callback) } },
403 letternumber => { text => t8('Letternumber'), sub => sub { $_[0]->letternumber },
404 obj_link => sub { $self->url_for(action => 'edit', 'letter.id' => $_[0]->id, callback => $self->models->get_callback) } },
405 customer_id => { text => t8('Customer'), sub => sub { SL::DB::Manager::Customer->find_by_or_create(id => $_[0]->customer_id)->displayable_name }, visible => $self->is_sales },
406 vendor_id => { text => t8('Vendor'), sub => sub { SL::DB::Manager::Vendor->find_by_or_create(id => $_[0]->vendor_id)->displayable_name }, visible => !$self->is_sales},
407 contact => { text => t8('Contact'), sub => sub { $_[0]->contact ? $_[0]->contact->full_name : '' } },
410 $column_defs{$_}{text} = $sort_columns{$_} for keys %column_defs;
412 $report->set_options(
413 std_column_visibility => 1,
414 controller_class => 'Letter',
415 output_format => 'HTML',
416 top_info_text => t8('Letters'),
417 title => t8('Letters'),
418 allow_pdf_export => 1,
419 allow_csv_export => 1,
422 $report->set_columns(%column_defs);
423 $report->set_column_order(@columns);
424 $report->set_export_options(qw(list filter is_sales));
425 $report->set_options_from_form;
427 $self->models->disable_plugin('paginated') if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
428 $self->models->add_additional_url_params(is_sales => $self->is_sales);
429 $self->models->finalize;
430 $self->models->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable);
432 $report->set_options(
433 raw_top_info_text => $self->render('letter/report_top', { output => 0 }),
434 raw_bottom_info_text => $self->render('letter/report_bottom', { output => 0 }, models => $self->models),
435 attachment_basename => t8('letters_list') . strftime('_%Y%m%d', localtime time),
439 sub make_filter_summary {
442 my $filter = $::form->{filter} || {};
445 my $employee = $filter->{employee_id} ? SL::DB::Employee->new(id => $filter->{employee_id})->load->name : '';
446 my $salesman = $filter->{salesman_id} ? SL::DB::Employee->new(id => $filter->{salesman_id})->load->name : '';
449 [ $filter->{"letternumber:substr::ilike"}, t8('Number') ],
450 [ $filter->{"subject:substr::ilike"}, t8('Subject') ],
451 [ $filter->{"body:substr::ilike"}, t8('Body') ],
452 [ $filter->{"date:date::ge"}, t8('From Date') ],
453 [ $filter->{"date:date::le"}, t8('To Date') ],
454 [ $employee, t8('Employee') ],
455 [ $salesman, t8('Salesman') ],
460 my @flags = map { $flags{$_} } @{ $filter->{part}{type} || [] };
463 push @filter_strings, $_ if $_;
466 push @filter_strings, "$_->[1]: $_->[0]" if $_->[0];
469 $self->{filter_summary} = join ', ', @filter_strings;
472 sub load_letter_draft {
473 my ($self, %params) = @_;
475 return 0 if $params{skip_drafts};
477 my $letter_drafts = SL::DB::Manager::LetterDraft->get_all(
479 SL::DB::Manager::Letter->is_sales_filter($self->is_sales),
483 return unless @$letter_drafts;
485 $self->render('letter/load_drafts',
486 title => t8('Letter Draft'),
487 LETTER_DRAFTS => $letter_drafts,
495 my $letter = $self->letter;
497 return unless $letter;
498 return if $letter->date;
500 $letter->date(DateTime->today)
504 my ($self, $letter) = @_;
506 $letter ||= $self->letter;
510 if (!$letter->subject) {
511 flash('error', t8('The subject is missing.'));
514 if (!$letter->body) {
515 flash('error', t8('The body is missing.'));
518 if (!$letter->employee_id) {
519 flash('error', t8('The employee is missing.'));
527 my ($self, $letter) = @_;
529 $letter ||= $self->letter;
531 return if $letter->letternumber;
533 $letter->letternumber(SL::TransNumber->new(type => 'letter', id => $self->{id}, number => $self->{letternumber})->create_unique);
538 my $letter = $self->letter;
540 return unless $letter;
541 return if $letter->greeting;
543 $letter->greeting(t8('Dear Sir or Madam,'));
546 sub export_letter_to_form {
547 my ($self, $letter) = @_;
550 $letter ||= $self->letter;
552 for ($letter->meta->columns) {
553 if ((ref $_) =~ /Date/i) {
554 $::form->{$_->name} = $letter->$_->to_kivitendo;
556 $::form->{$_->name} = $letter->$_;
564 my $letter = SL::DB::Manager::Letter->find_by_or_create(id => $::form->{letter}{id} || 0)
565 ->assign_attributes(%{ $::form->{letter} });
567 if ($letter->cp_id) {
568 # $letter->customer_vendor_id($letter->contact->cp_cv_id);
569 # contacts don't have language_id yet
570 # $letter->greeting(GenericTranslations->get(
571 # translation_type => 'greetings::' . ($letter->contact->cp_gender eq 'f' ? 'female' : 'male'),
572 # language_id => $letter->contact->language_id,
573 # allow_fallback => 1
577 $self->is_sales($letter->is_sales);
585 SL::Controller::Helper::GetModels->new(
589 SL::DB::Manager::Letter->is_sales_filter($self->is_sales),
591 sorted => \%sort_columns,
592 with_objects => [ 'contact', 'salesman', 'employee' ],
596 sub init_all_employees {
597 SL::DB::Manager::Employee->get_all(query => [ deleted => 0 ]);
600 sub init_webdav_objects {
603 return [] if !$self->letter || !$self->letter->letternumber || !$::instance_conf->get_webdav;
605 my $webdav = SL::Webdav->new(
607 number => $self->letter->letternumber,
610 my $webdav_path = $webdav->webdav_path;
611 my @all_objects = $webdav->get_all_objects;
614 +{ name => $_->filename,
616 link => File::Spec->catdir($webdav_path, $_->filename),
622 die 'is_sales must be set' unless defined $::form->{is_sales};
626 sub check_auth_edit {
627 $::auth->assert('sales_letter_edit');
630 sub check_auth_report {
631 $::auth->assert('sales_letter_report');
642 SL::Controller::Letter - Letters CRUD and printing
646 Simple letter CRUD controller with drafting capabilities.
648 copy to webdav is crap
652 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>