X-Git-Url: http://wagnertech.de/gitweb/gitweb.cgi/mfinanz.git/blobdiff_plain/1f250cc904dbdce75118f73b5cae48590dc921e6..87bd35148cceaf805d14d5ed2042142a40981519:/SL/Controller/Order.pm diff --git a/SL/Controller/Order.pm b/SL/Controller/Order.pm index f82ecf5e8..193382790 100644 --- a/SL/Controller/Order.pm +++ b/SL/Controller/Order.pm @@ -4,10 +4,10 @@ use strict; use parent qw(SL::Controller::Base); use SL::Helper::Flash; -use SL::ClientJS; use SL::Presenter; use SL::Locale::String; use SL::SessionFile::Random; +use SL::PriceSource; use SL::Form; use SL::DB::Order; @@ -18,6 +18,7 @@ use SL::DB::Employee; use SL::DB::Project; use SL::DB::Default; use SL::DB::Unit; +use SL::DB::Price; use SL::Helper::DateTime; use SL::Helper::CreatePDF qw(:all); @@ -25,10 +26,11 @@ 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 ( - 'scalar --get_set_init' => [ qw(order valid_types type cv js p) ], + 'scalar --get_set_init' => [ qw(order valid_types type cv p) ], ); @@ -36,8 +38,10 @@ use Rose::Object::MakeMethods::Generic __PACKAGE__->run_before('_check_auth'); __PACKAGE__->run_before('_recalc', - only => [ qw(edit update save create_pdf) ]); + only => [ qw(edit update save save_and_delivery_order create_pdf send_email) ]); +__PACKAGE__->run_before('_get_unalterable_data', + only => [ qw(save save_and_delivery_order create_pdf send_email) ]); # # actions @@ -91,7 +95,7 @@ sub action_save { if (scalar @{ $errors }) { $self->js->flash('error', $_) foreach @{ $errors }; - return $self->js->render($self); + return $self->js->render(); } flash_later('info', $::locale->text('The order has been saved')); @@ -107,33 +111,8 @@ sub action_save { sub action_create_pdf { my ($self) = @_; - my $print_form = Form->new(''); - $print_form->{type} = 'sales_order'; - $print_form->{formname} = 'sales_order', - $print_form->{format} = 'pdf', - $print_form->{media} = 'file'; - - $self->order->flatten_to_form($print_form, format_amounts => 1); - my $pdf; - my @errors; - $print_form->throw_on_error(sub { - eval { - $print_form->prepare_for_printing; - - $pdf = 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; - }); - + 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); } @@ -142,52 +121,159 @@ sub action_create_pdf { $sfile->fh->print($pdf); $sfile->fh->close; - my $tmp_filename = $sfile->file_name; - my $pdf_filename = t8('Sales Order') . '_' . $self->order->ordnumber . '.pdf'; + my $key = join('_', Time::HiRes::gettimeofday(), int rand 1000000000000); + $::auth->set_session_value("Order::create_pdf-${key}" => $sfile->file_name); + + my $pdf_filename = t8('Sales Order') . '_' . $self->order->ordnumber . '.pdf'; $self->js - ->run('download_pdf', $tmp_filename, $pdf_filename) + ->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( - $::form->{tmp_filename}, + $tmp_filename, type => 'application/pdf', name => $::form->{pdf_filename}, ); } -sub action_customer_vendor_changed { +sub action_show_email_dialog { + my ($self) = @_; + + my $cv_method = $self->cv; + + if (!$self->order->$cv_method) { + return $self->js->flash('error', t8('Cannot send E-mail without ' . $self->cv)) + ->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) = @_; - if ($self->cv eq 'customer') { - $self->order->customer(SL::DB::Manager::Customer->find_by_or_create(id => $::form->{cv_id})); + my $mail = Mailer->new; + $mail->{from} = qq|"$::myconfig{name}" <$::myconfig{email}>|; + $mail->{$_} = $::form->{email}->{$_} for qw(to cc bcc subject message); - } elsif ($self->cv eq 'vendor') { - $self->order->vendor(SL::DB::Manager::Vendor->find_by_or_create(id => $::form->{cv_id})); + 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); } - if ($self->order->{$self->cv}->contacts && scalar @{ $self->order->{$self->cv}->contacts } > 0) { + $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_save_and_delivery_order { + my ($self) = @_; + + my $errors = $self->_save(); + + if (scalar @{ $errors }) { + $self->js->flash('error', $_) foreach @{ $errors }; + return $self->js->render(); + } + + my $delivery_order = $self->order->convert_to_delivery_order($self->order); + + flash_later('info', $::locale->text('The order has been saved')); + my @redirect_params = ( + controller => 'do.pl', + action => 'edit', + type => $delivery_order->type, + id => $delivery_order->id, + vc => $delivery_order->is_sales ? 'customer' : 'vendor', + ); + + $self->redirect_to(@redirect_params); +} + +sub action_customer_vendor_changed { + my ($self) = @_; + + my $cv_method = $self->cv; + + if ($self->order->$cv_method->contacts && scalar @{ $self->order->$cv_method->contacts } > 0) { $self->js->show('#cp_row'); } else { $self->js->hide('#cp_row'); } - if ($self->order->{$self->cv}->shipto && scalar @{ $self->order->{$self->cv}->shipto } > 0) { + if ($self->order->$cv_method->shipto && scalar @{ $self->order->$cv_method->shipto } > 0) { $self->js->show('#shipto_row'); } else { $self->js->hide('#shipto_row'); } + $self->order->taxzone_id($self->order->$cv_method->taxzone_id); + + $self->order->taxincluded(defined($self->order->$cv_method->taxincluded_checked) + ? $self->order->$cv_method->taxincluded_checked + : $::myconfig{taxincluded_checked}); + + $self->_recalc(); + $self->js - ->replaceWith('#order_cp_id', $self->build_contact_select) - ->replaceWith('#order_shipto_id', $self->build_shipto_select) - ->val('#order_taxzone_id', $self->order->{$self->cv}->taxzone_id) - ->focus('#order_' . $self->cv . '_id') - ->render($self); + ->replaceWith('#order_cp_id', $self->build_contact_select) + ->replaceWith('#order_shipto_id', $self->build_shipto_select) + ->val( '#order_taxzone_id', $self->order->taxzone_id) + ->val( '#order_taxincluded', $self->order->taxincluded) + ->focus( '#order_' . $self->cv . '_id'); + + $self->_js_redisplay_amounts_and_taxes; + $self->js->render(); } sub action_add_item { @@ -204,12 +290,17 @@ sub action_add_item { my $cv_method = $self->cv; my $cv_discount = $self->order->$cv_method? $self->order->$cv_method->discount : 0.0; + my $price = $item->sellprice; + $price ||= ($self->order->$cv_method && $self->order->$cv_method->klass) + ? (SL::DB::Manager::Price->find_by(parts_id => $part->id, pricegroup_id => $self->order->$cv_method->klass)->price || $part->sellprice) + : $part->sellprice; + my %new_attr; $new_attr{part} = $part; $new_attr{description} = $part->description if ! $item->description; $new_attr{qty} = 1.0 if ! $item->qty; $new_attr{unit} = $part->unit; - $new_attr{sellprice} = $part->sellprice if ! $item->sellprice; + $new_attr{sellprice} = $price; $new_attr{discount} = $cv_discount if ! $item->discount; # add_custom_variables adds cvars to an orderitem with no cvars for saving, but @@ -240,7 +331,7 @@ sub action_add_item { ->focus('#add_item_parts_id_name'); $self->_js_redisplay_amounts_and_taxes; - $self->js->render($self); + $self->js->render(); } sub action_recalc_amounts_and_taxes { @@ -250,7 +341,7 @@ sub action_recalc_amounts_and_taxes { $self->_js_redisplay_linetotals; $self->_js_redisplay_amounts_and_taxes; - $self->js->render($self); + $self->js->render(); } sub _js_redisplay_linetotals { @@ -311,10 +402,6 @@ sub init_cv { return $cv; } -sub init_js { - SL::ClientJS->new; -} - sub init_p { SL::Presenter->get; } @@ -392,10 +479,11 @@ sub _recalc { $self->order->currency_id($::instance_conf->get_currency_id()); my %pat = $self->order->calculate_prices_and_taxes(); + $self->{taxes} = []; foreach my $tax_chart_id (keys %{ $pat{taxes} }) { my $tax = SL::DB::Manager::Tax->find_by(chart_id => $tax_chart_id); - my @amount_keys = grep { $pat{amounts}->{$_}->{tax_id} == $tax->id } keys $pat{amounts}; + my @amount_keys = grep { $pat{amounts}->{$_}->{tax_id} == $tax->id } keys %{ $pat{amounts} }; push(@{ $self->{taxes} }, { amount => $pat{taxes}->{$tax_chart_id}, netamount => $pat{amounts}->{$amount_keys[0]}->{amount}, tax => $tax }); @@ -404,13 +492,34 @@ sub _recalc { pairwise { $a->{linetotal} = $b->{linetotal} } @{$self->order->items}, @{$pat{items}}; } -sub _save { + +sub _get_unalterable_data { my ($self) = @_; - # autovivify all cvars that are not in the form (cvars_by_config can do it) foreach my $item (@{ $self->order->items }) { - $item->cvars_by_config; + if ($item->id) { + # load data from orderitems (db) + my $db_item = SL::DB::OrderItem->new(id => $item->id)->load; + $item->$_($db_item->$_) for qw(active_discount_source active_price_source longdescription); + } else { + # set data from part (or other sources) + $item->longdescription($item->part->notes); + #$item->active_price_source(''); + #$item->active_discount_source(''); + } + + # autovivify all cvars that are not in the form (cvars_by_config can do it). + # workaround to pre-parse number-cvars (parse_custom_variable_values does not parse number values). + foreach my $var (@{ $item->cvars_by_config }) { + $var->unparsed_value($::form->parse_amount(\%::myconfig, $var->{__unparsed_value})) if ($var->config->type eq 'number' && exists($var->{__unparsed_value})); + } + $item->parse_custom_variable_values; } +} + + +sub _save { + my ($self) = @_; my $errors = []; my $db = $self->order->db; @@ -431,6 +540,9 @@ sub _pre_render { $self->{all_employees} = SL::DB::Manager::Employee->get_all(where => [ or => [ id => $self->order->employee_id, deleted => 0 ] ], sort_by => 'name'); + $self->{all_salesmen} = SL::DB::Manager::Employee->get_all(where => [ or => [ id => $self->order->salesman_id, + deleted => 0 ] ], + sort_by => 'name'); $self->{all_projects} = SL::DB::Manager::Project->get_all(where => [ or => [ id => $self->order->globalproject_id, active => 1 ] ], sort_by => 'projectnumber'); @@ -442,6 +554,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} = 'sales_order'; + $print_form->{formname} = 'sales_order', + $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'; } @@ -451,3 +597,22 @@ sub _purchase_order_type { } 1; + +__END__ + +=encoding utf-8 + +=head1 NAME + +SL::Controller::Order - controller for orders + +=head1 TODO + +Testing, PriceSources, pricefactor, units, currency, delivered, delivery order created, ... + +=head1 AUTHOR + +Bernd Bleßmann Ebernd@kivitendo-premium.deE + +=cut +