From aa36021ace7b4075af6d2d815e0e208b7227d9c4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bernd=20Ble=C3=9Fmann?= Date: Thu, 17 Sep 2015 12:29:44 +0200 Subject: [PATCH] Auftrags-Controller: Drucken und E-Mail --- SL/Controller/Order.pm | 158 +++++++++++++++++- locale/de/all | 4 + templates/webpages/order/form.html | 26 +++ .../webpages/order/tabs/_email_dialog.html | 65 +++++++ templates/webpages/order/tabs/basic_data.html | 30 ++++ 5 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 templates/webpages/order/tabs/_email_dialog.html diff --git a/SL/Controller/Order.pm b/SL/Controller/Order.pm index ff3aca4e3..75c636ced 100644 --- a/SL/Controller/Order.pm +++ b/SL/Controller/Order.pm @@ -5,7 +5,10 @@ use parent qw(SL::Controller::Base); use SL::Helper::Flash; use SL::Presenter; +use SL::Locale::String; +use SL::SessionFile::Random; use SL::PriceSource; +use SL::Form; use SL::DB::Order; use SL::DB::Customer; @@ -17,9 +20,12 @@ use SL::DB::Default; use SL::DB::Unit; use SL::Helper::DateTime; +use SL::Helper::CreatePDF qw(:all); use List::Util qw(max first); use List::MoreUtils qw(none pairwise); +use English qw(-no_match_vars); +use File::Spec; use Rose::Object::MakeMethods::Generic ( @@ -31,7 +37,7 @@ use Rose::Object::MakeMethods::Generic __PACKAGE__->run_before('_check_auth'); __PACKAGE__->run_before('_recalc', - only => [ qw(edit update save) ]); + only => [ qw(edit update save create_pdf send_email) ]); __PACKAGE__->run_before('_get_unalterable_data', only => [ qw(save save_and_delivery_order create_pdf send_email) ]); @@ -120,6 +126,122 @@ sub action_save { $self->redirect_to(@redirect_params); } +sub action_create_pdf { + my ($self) = @_; + + my $pdf; + my @errors = _create_pdf($self->order, \$pdf); + if (scalar @errors) { + return $self->js->flash('error', t8('Conversion to PDF failed: #1', $errors[0]))->render($self); + } + + my $sfile = SL::SessionFile::Random->new(mode => "w"); + $sfile->fh->print($pdf); + $sfile->fh->close; + + my $key = join('_', Time::HiRes::gettimeofday(), int rand 1000000000000); + $::auth->set_session_value("Order::create_pdf-${key}" => $sfile->file_name); + + my $form = Form->new; + $form->{ordnumber} = $self->order->ordnumber; + $form->{formname} = $self->type; + $form->{type} = $self->type; + $form->{language} = 'de'; + $form->{format} = 'pdf'; + + my $pdf_filename = $form->generate_attachment_filename(); + + $self->js + ->run('download_pdf', $pdf_filename, $key) + ->flash('info', t8('The PDF has been created'))->render($self); +} + +sub action_download_pdf { + my ($self) = @_; + + my $key = $::form->{key}; + my $tmp_filename = $::auth->get_session_value("Order::create_pdf-${key}"); + return $self->send_file( + $tmp_filename, + type => 'application/pdf', + name => $::form->{pdf_filename}, + ); +} + +sub action_show_email_dialog { + my ($self) = @_; + + my $cv_method = $self->cv; + + if (!$self->order->$cv_method) { + return $self->js->flash('error', $self->cv eq 'customer' ? t8('Cannot send E-mail without customer given') : t8('Cannot send E-mail without vendor given')) + ->render($self); + } + + $self->{email}->{to} = $self->order->contact->cp_email if $self->order->contact; + $self->{email}->{to} ||= $self->order->$cv_method->email; + $self->{email}->{cc} = $self->order->$cv_method->cc; + $self->{email}->{bcc} = join ', ', grep $_, $self->order->$cv_method->bcc, SL::DB::Default->get->global_bcc; + # Todo: get addresses from shipto, if any + + my $form = Form->new; + $form->{ordnumber} = $self->order->ordnumber; + $form->{formname} = $self->type; + $form->{type} = $self->type; + $form->{language} = 'de'; + $form->{format} = 'pdf'; + + $self->{email}->{subject} = $form->generate_email_subject(); + $self->{email}->{attachment_filename} = $form->generate_attachment_filename(); + $self->{email}->{message} = $form->create_email_signature(); + + my $dialog_html = $self->render('order/tabs/_email_dialog', { output => 0 }); + $self->js + ->run('show_email_dialog', $dialog_html) + ->reinit_widgets + ->render($self); +} + +# Todo: handling error messages: flash is not displayed in dialog, but in the main form +sub action_send_email { + my ($self) = @_; + + my $mail = Mailer->new; + $mail->{from} = qq|"$::myconfig{name}" <$::myconfig{email}>|; + $mail->{$_} = $::form->{email}->{$_} for qw(to cc bcc subject message); + + my $pdf; + my @errors = _create_pdf($self->order, \$pdf, {media => 'email'}); + if (scalar @errors) { + return $self->js->flash('error', t8('Conversion to PDF failed: #1', $errors[0]))->render($self); + } + + $mail->{attachments} = [{ "content" => $pdf, + "name" => $::form->{email}->{attachment_filename} }]; + + if (my $err = $mail->send) { + return $self->js->flash('error', t8('Sending E-mail: ') . $err) + ->render($self); + } + + # internal notes + my $intnotes = $self->order->intnotes; + $intnotes .= "\n\n" if $self->order->intnotes; + $intnotes .= t8('[email]') . "\n"; + $intnotes .= t8('Date') . ": " . $::locale->format_date_object(DateTime->now_local, precision => 'seconds') . "\n"; + $intnotes .= t8('To (email)') . ": " . $mail->{to} . "\n"; + $intnotes .= t8('Cc') . ": " . $mail->{cc} . "\n" if $mail->{cc}; + $intnotes .= t8('Bcc') . ": " . $mail->{bcc} . "\n" if $mail->{bcc}; + $intnotes .= t8('Subject') . ": " . $mail->{subject} . "\n\n"; + $intnotes .= t8('Message') . ": " . $mail->{message}; + + $self->js + ->val('#order_intnotes', $intnotes) + ->run('close_email_dialog') + ->render($self); +} + + sub action_customer_vendor_changed { my ($self) = @_; @@ -452,6 +574,40 @@ sub _pre_render { $::request->{layout}->use_javascript("${_}.js") for qw(ckeditor/ckeditor ckeditor/adapters/jquery); } +sub _create_pdf { + my ($order, $pdf_ref, $params) = @_; + + my $print_form = Form->new(''); + $print_form->{type} = $order->type; + $print_form->{formname} = $order->type; + $print_form->{format} = $params->{format} || 'pdf', + $print_form->{media} = $params->{media} || 'file'; + + $order->flatten_to_form($print_form, format_amounts => 1); + # flatten_to_form sets payment_terms from customer/vendor - we do not want that here + delete $print_form->{payment_terms} if !$print_form->{payment_id}; + + my @errors = (); + $print_form->throw_on_error(sub { + eval { + $print_form->prepare_for_printing; + + $$pdf_ref = SL::Helper::CreatePDF->create_pdf( + template => SL::Helper::CreatePDF->find_template(name => $print_form->{formname}), + variables => $print_form, + variable_content_types => { + longdescription => 'html', + partnotes => 'html', + notes => 'html', + }, + ); + 1; + } || push @errors, ref($EVAL_ERROR) eq 'SL::X::FormError' ? $EVAL_ERROR->getMessage : $EVAL_ERROR; + }); + + return @errors; +} + sub _sales_order_type { 'sales_order'; } diff --git a/locale/de/all b/locale/de/all index 5a47fe8c4..64c772b38 100755 --- a/locale/de/all +++ b/locale/de/all @@ -497,6 +497,8 @@ $self->{texts} = { 'Cannot save order!' => 'Auftrag kann nicht gespeichert werden!', 'Cannot save preferences!' => 'Einstellungen können nicht gespeichert werden!', 'Cannot save quotation!' => 'Angebot kann nicht gespeichert werden!', + 'Cannot send E-mail without customer given' => 'E-Mail kann nicht ohne Angabe eines Kunden evrsendet werden.', + 'Cannot send E-mail without vendor given' => 'E-Mail kann nicht ohne Angabe eines Lieferanten evrsendet werden.', 'Cannot stock negative amounts' => 'Negative Mengen können nicht eingelagert werden!', 'Cannot stock without amount' => 'Kann nicht ohne Menge einlagern!', 'Cannot storno invoice for a closed period!' => 'Das Rechnungsdatum der zu stornierenden Rechnung fällt in einen abgeschlossenen Zeitraum!', @@ -2430,6 +2432,7 @@ $self->{texts} = { 'Sellprice significant places' => 'Verkaufspreis: Nachkommastellen', 'Semicolon' => 'Semikolon', 'Sender' => 'AbsenderIn', + 'Sending E-mail: ' => 'E-Mail versenden: ', 'Sent emails can be optionally stored in the database with or without their attachments.' => 'Gesendete E-Mails können optional mit oder ohne ihre Anhänge in der Datenbank gespeichert werden.', 'Sent on' => 'Verschickt am', 'Sep' => 'Sep', @@ -2688,6 +2691,7 @@ $self->{texts} = { 'The IBAN is missing.' => 'Die IBAN fehlt.', 'The LDAP server "#1:#2" is unreachable. Please check config/kivitendo.conf.' => 'Der LDAP-Server "#1:#2" ist nicht erreichbar. Bitte überprüfen Sie die Angaben in config/kivitendo.conf.', 'The MT940 import needs an import profile called MT940' => 'Der MT940 Import benötigt ein Importprofil mit dem Namen "MT940"', + 'The PDF has been created' => 'Die PDF-Datei wurde erstellt.', 'The SEPA export has been created.' => 'Der SEPA-Export wurde erstellt', 'The SEPA strings have been saved.' => 'Die bei SEPA-Überweisungen verwendeten Begriffe wurden gespeichert.', 'The WebDAV feature has been used.' => 'Das WebDAV-Feature wurde benutzt.', diff --git a/templates/webpages/order/form.html b/templates/webpages/order/form.html index 977d41f59..63c1d1df3 100644 --- a/templates/webpages/order/form.html +++ b/templates/webpages/order/form.html @@ -31,6 +31,8 @@ [% L.hidden_tag('action', 'Order/dispatch') %] [% L.button_tag('save()', LxERP.t8('Save')) %] + [% L.button_tag('create_pdf()', LxERP.t8('Create PDF')) %] + [% L.button_tag('email()', LxERP.t8('E-mail')) %] [%- IF SELF.order.id && ( (SELF.cv == 'customer' && INSTANCE_CONF.get_sales_order_show_delete) || (SELF.cv == 'vendor' && INSTANCE_CONF.get_purchase_order_show_delete) ) %] [% L.button_tag('delete_order()', LxERP.t8('Delete'), confirm=LxERP.t8("Are you sure?")) %] [%- END %] @@ -55,6 +57,30 @@ function save() { $.post("controller.pl", data, kivi.eval_json_result); } +function create_pdf() { + if (!check_cv()) return; + var data = $('#order_form').serialize(); + data += '&action=Order/create_pdf'; + + $.post("controller.pl", data, kivi.eval_json_result); +} + +function download_pdf(pdf_filename, key) { + var data = 'action=Order/download_pdf'; + data += '&type=' + $('#type').val(); + data += '&pdf_filename=' + pdf_filename; + data += '&key=' + key; + $.download("controller.pl", data); +} + +function email() { + if (!check_cv()) return; + var data = $('#order_form').serialize(); + data += '&action=Order/show_email_dialog'; + + $.post("controller.pl", data, kivi.eval_json_result); +} + function check_cv() { if ($('#order_[%- cv_id %]').val() == '') { [%- IF SELF.cv == 'customer' %] diff --git a/templates/webpages/order/tabs/_email_dialog.html b/templates/webpages/order/tabs/_email_dialog.html new file mode 100644 index 000000000..3c6df7f76 --- /dev/null +++ b/templates/webpages/order/tabs/_email_dialog.html @@ -0,0 +1,65 @@ +[%- USE T8 %][%- USE HTML %][%- USE L %][%- USE LxERP %] + +
+

[%- 'E-mail' | $T8 %] [%- SELF.type | $T8 %]

+ + + + + + + +
+ + + + + + + + + + [%- IF AUTH.assert('email_bcc', 1) %] + + + + + [%- END %] + + + + + + + + +
[% 'To' | $T8 %][% L.input_tag("email.to", SELF.email.to, size=30, class=(SELF.email.to ? '' : 'initial_focus')) %]
[% 'Cc' | $T8 %][% L.input_tag("email.cc", SELF.email.cc, size=30) %]
[% 'Bcc' | $T8 %][% L.input_tag("email.bcc", SELF.email.bcc, size=30) %]
[% 'Subject' | $T8 %][% L.input_tag('email.subject', SELF.email.subject, size=30, class=(SELF.email.subject ? 'initial_focus' : '')) %]
[% 'Attachment name' | $T8 %][% L.input_tag("email.attachment_filename", SELF.email.attachment_filename, size=30) %]
+
+ + + + + + + + +
[% 'Message' | $T8 %]
+ [% L.textarea_tag("email.message", SELF.email.message, wrap="soft", style="width: 350px; height: 150px") %] +
+ +
+[% L.hidden_tag('action', 'Order/dispatch') %] +[% L.button_tag('send_email()', LxERP.t8('Continue')) %] +[%- LxERP.t8("Cancel") %] + + + +
diff --git a/templates/webpages/order/tabs/basic_data.html b/templates/webpages/order/tabs/basic_data.html index 3d7507139..d4dc90514 100644 --- a/templates/webpages/order/tabs/basic_data.html +++ b/templates/webpages/order/tabs/basic_data.html @@ -321,6 +321,36 @@ function row_set_keyboard_events(rows) { }); } +var email_dialog; + +function show_email_dialog(html) { + var id = 'jqueryui_popup_dialog'; + var dialog_params = { + id: id, + width: 800, + height: 500, + modal: true, + close: function(event, ui) { + email_dialog.remove(); + }, + }; + + $('#' + id).remove(); + + email_dialog = $('').appendTo('body'); + email_dialog.html(html); + email_dialog.dialog(dialog_params); + + $('.cancel').click(close_email_dialog); + + return true; +} + +close_email_dialog = function() { + email_dialog.dialog("close"); +} + + $(function(){ $('#order_[%- cv_id %]').change(reload_cv_dependend_selections); $('#add_item_parts_id').on('set_item:PartPicker', function(e,o) { $('#add_item_sellprice_as_number').val(kivi.format_amount(o.sellprice, -2)) }); -- 2.20.1