]> wagnertech.de Git - mfinanz.git/blobdiff - SL/Controller/Order.pm
Auftrags-Controller: Doku und Kommentare
[mfinanz.git] / SL / Controller / Order.pm
index cd13a928952830b34d3af13c672fe8a482610f15..c129999b088ebcda4e12f5eb6409d096eb971939 100644 (file)
@@ -48,7 +48,7 @@ use Rose::Object::MakeMethods::Generic
 __PACKAGE__->run_before('_check_auth');
 
 __PACKAGE__->run_before('_recalc',
-                        only => [ qw(update save save_and_delivery_order print create_pdf send_email) ]);
+                        only => [ qw(save save_and_delivery_order print create_pdf send_email) ]);
 
 __PACKAGE__->run_before('_get_unalterable_data',
                         only => [ qw(save save_and_delivery_order print create_pdf send_email) ]);
@@ -57,6 +57,7 @@ __PACKAGE__->run_before('_get_unalterable_data',
 # actions
 #
 
+# add a new order
 sub action_add {
   my ($self) = @_;
 
@@ -73,6 +74,7 @@ sub action_add {
   );
 }
 
+# edit an existing order
 sub action_edit {
   my ($self) = @_;
 
@@ -88,19 +90,7 @@ sub action_edit {
   );
 }
 
-sub action_update {
-  my ($self) = @_;
-
-  $self->_pre_render();
-  $self->render(
-    'order/form',
-    title => $self->type eq _sales_order_type()    ? $::locale->text('Edit Sales Order')
-           : $self->type eq _purchase_order_type() ? $::locale->text('Edit Purchase Order')
-           : '',
-    %{$self->{template_args}}
-  );
-}
-
+# delete the order
 sub action_delete {
   my ($self) = @_;
 
@@ -120,6 +110,7 @@ sub action_delete {
   $self->redirect_to(@redirect_params);
 }
 
+# save the order
 sub action_save {
   my ($self) = @_;
 
@@ -140,6 +131,14 @@ sub action_save {
   $self->redirect_to(@redirect_params);
 }
 
+# print the order
+#
+# This is called if "print" is pressed in the print dialog.
+# If PDF creation was requested and succeeded, the pdf is stored in a session
+# file and the filename is stored as session value with an unique key. A
+# javascript function with this key is then called. This function calls the
+# download action below (action_download_pdf), which offers the file for
+# download.
 sub action_print {
   my ($self) = @_;
 
@@ -189,26 +188,16 @@ sub action_print {
     $::auth->set_session_value("Order::create_pdf-${key}" => $sfile->file_name);
 
     $self->js
-    ->run('download_pdf', $pdf_filename, $key)
+    ->run('kivi.Order.download_pdf', $pdf_filename, $key)
     ->flash('info', t8('The PDF has been created'));
 
   } elsif ($media eq 'printer') {
     # printer
     my $printer_id = $::form->{print_options}->{printer_id};
-    my $printer;
-    $printer = SL::DB::Printer->new(id => $printer_id)->load if $printer_id;
-    if (!$printer) {
-      return $self->js->flash('error', t8('Printer not found.'))->render;
-    }
-
-    my $command = SL::Template::create(type => 'ShellCommand', form => Form->new(''))->parse($printer->printer_command);
-
-    for my $i (1 .. $copies) {
-      open my $out, '|-', $command or die $!;
-      binmode $out;
-      print $out $pdf;
-      close $out;
-    }
+    SL::DB::Printer->new(id => $printer_id)->load->print_document(
+      copies  => $copies,
+      content => $pdf,
+    );
 
     $self->js->flash('info', t8('The PDF has been printed'));
   }
@@ -234,6 +223,9 @@ sub action_print {
   $self->js->render;
 }
 
+# offer pdf for download
+#
+# It needs to get the key for the session value to get the pdf file.
 sub action_download_pdf {
   my ($self) = @_;
 
@@ -246,6 +238,7 @@ sub action_download_pdf {
   );
 }
 
+# open the email dialog
 sub action_show_email_dialog {
   my ($self) = @_;
 
@@ -275,11 +268,13 @@ sub action_show_email_dialog {
 
   my $dialog_html = $self->render('order/tabs/_email_dialog', { output => 0 });
   $self->js
-      ->run('show_email_dialog', $dialog_html)
+      ->run('kivi.Order.show_email_dialog', $dialog_html)
       ->reinit_widgets
       ->render($self);
 }
 
+# send email
+#
 # Todo: handling error messages: flash is not displayed in dialog, but in the main form
 sub action_send_email {
   my ($self) = @_;
@@ -315,10 +310,12 @@ sub action_send_email {
 
   $self->js
       ->val('#order_intnotes', $intnotes)
-      ->run('close_email_dialog')
+      ->run('kivi.Order.close_email_dialog')
       ->render($self);
 }
 
+# save the order and redirect to the frontend subroutine for a new
+# delivery order
 sub action_save_and_delivery_order {
   my ($self) = @_;
 
@@ -339,6 +336,9 @@ sub action_save_and_delivery_order {
   $self->redirect_to(@redirect_params);
 }
 
+# set form elements in respect of a changed customer or vendor
+#
+# This action is called on an change of the customer/vendor picker.
 sub action_customer_vendor_changed {
   my ($self) = @_;
 
@@ -383,6 +383,7 @@ sub action_customer_vendor_changed {
   $self->js->render();
 }
 
+# called if a unit in an existing item row is changed
 sub action_unit_changed {
   my ($self) = @_;
 
@@ -395,12 +396,13 @@ sub action_unit_changed {
   $self->_recalc();
 
   $self->js
-    ->run('update_sellprice', $::form->{item_id}, $item->sellprice_as_number);
+    ->run('kivi.Order.update_sellprice', $::form->{item_id}, $item->sellprice_as_number);
   $self->_js_redisplay_linetotals;
   $self->_js_redisplay_amounts_and_taxes;
   $self->js->render();
 }
 
+# add an item row for a new item entered in the input row
 sub action_add_item {
   my ($self) = @_;
 
@@ -423,21 +425,23 @@ sub action_add_item {
   $self->js
     ->append('#row_table_id', $row_as_html)
     ->val('.add_item_input', '')
-    ->run('init_row_handlers')
-    ->run('row_table_scroll_down')
-    ->run('renumber_positions')
+    ->run('kivi.Order.init_row_handlers')
+    ->run('kivi.Order.row_table_scroll_down')
+    ->run('kivi.Order.renumber_positions')
     ->focus('#add_item_parts_id_name');
 
   $self->_js_redisplay_amounts_and_taxes;
   $self->js->render();
 }
 
+# open the dialog for entering multiple items at once
 sub action_show_multi_items_dialog {
   require SL::DB::PartsGroup;
   $_[0]->render('order/tabs/_multi_items_dialog', { layout => 0 },
                 all_partsgroups => SL::DB::Manager::PartsGroup->get_all);
 }
 
+# update the filter results in the multi item dialog
 sub action_multi_items_update_result {
   my $max_count = 100;
 
@@ -458,6 +462,7 @@ sub action_multi_items_update_result {
   }
 }
 
+# add item rows for multiple items add once
 sub action_add_multi_items {
   my ($self) = @_;
 
@@ -484,16 +489,17 @@ sub action_add_multi_items {
   }
 
   $self->js
-    ->run('close_multi_items_dialog')
-    ->run('init_row_handlers')
-    ->run('row_table_scroll_down')
-    ->run('renumber_positions')
+    ->run('kivi.Order.close_multi_items_dialog')
+    ->run('kivi.Order.init_row_handlers')
+    ->run('kivi.Order.row_table_scroll_down')
+    ->run('kivi.Order.renumber_positions')
     ->focus('#add_item_parts_id_name');
 
   $self->_js_redisplay_amounts_and_taxes;
   $self->js->render();
 }
 
+# recalculate all linetotals, amounts and taxes and redisplay them
 sub action_recalc_amounts_and_taxes {
   my ($self) = @_;
 
@@ -504,6 +510,7 @@ sub action_recalc_amounts_and_taxes {
   $self->js->render();
 }
 
+# redisplay item rows if the are sorted by an attribute
 sub action_reorder_items {
   my ($self) = @_;
 
@@ -523,10 +530,11 @@ sub action_reorder_items {
     @to_sort = sort { $b->{order_by} cmp $a->{order_by} } @to_sort;
   }
   $self->js
-    ->run('redisplay_items', \@to_sort)
+    ->run('kivi.Order.redisplay_items', \@to_sort)
     ->render;
 }
 
+# show the popup to choose a price/discount source
 sub action_price_popup {
   my ($self) = @_;
 
@@ -536,6 +544,11 @@ sub action_price_popup {
   $self->render_price_dialog($item);
 }
 
+# get the longdescription for an item if the dialog to enter/change the
+# longdescription was opened and the longdescription is empty
+#
+# If this item is new, get the longdescription from Part.
+# Get it from OrderItem else.
 sub action_get_item_longdescription {
   my $longdescription;
 
@@ -547,13 +560,12 @@ sub action_get_item_longdescription {
   $_[0]->render(\ $longdescription, { type => 'text' });
 }
 
-
 sub _js_redisplay_linetotals {
   my ($self) = @_;
 
   my @data = map {$::form->format_amount(\%::myconfig, $_->{linetotal}, 2, 0)} @{ $self->order->items_sorted };
   $self->js
-    ->run('redisplay_linetotals', \@data);
+    ->run('kivi.Order.redisplay_linetotals', \@data);
 }
 
 sub _js_redisplay_amounts_and_taxes {
@@ -614,6 +626,7 @@ sub init_order {
   $_[0]->_make_order;
 }
 
+# model used to filter/display the parts in the multi-items dialog
 sub init_multi_items_models {
   SL::Controller::Helper::GetModels->new(
     controller     => $_[0],
@@ -646,6 +659,9 @@ sub _check_auth {
   $::auth->assert($right);
 }
 
+# build the selection box for contacts
+#
+# Needed, if customer/vendor changed.
 sub build_contact_select {
   my ($self) = @_;
 
@@ -658,6 +674,9 @@ sub build_contact_select {
   );
 }
 
+# build the selection box for shiptos
+#
+# Needed, if customer/vendor changed.
 sub build_shipto_select {
   my ($self) = @_;
 
@@ -670,6 +689,9 @@ sub build_shipto_select {
   );
 }
 
+# build the rows for displaying taxes
+#
+# Called if amounts where recalculated and redisplayed.
 sub build_tax_rows {
   my ($self) = @_;
 
@@ -710,6 +732,12 @@ sub _load_order {
   $self->order(SL::DB::Manager::Order->find_by(id => $::form->{id}));
 }
 
+# load or create a new order object
+#
+# And assign changes from the for to this object.
+# If the order is loaded from db, check if items are deleted in the form,
+# remove them form the object and collect them for removing from db on saving.
+# Then create/update items from form (via _make_item) and add them.
 sub _make_order {
   my ($self) = @_;
 
@@ -746,7 +774,8 @@ sub _make_order {
   return $order;
 }
 
-
+# create or update items from form
+#
 # Make item objects from form values. For items already existing read from db.
 # Create a new item else. And assign attributes.
 sub _make_item {
@@ -768,6 +797,9 @@ sub _make_item {
   return $item;
 }
 
+# create a new item
+#
+# This is used to add one (or more) items
 sub _new_item {
   my ($record, $attr) = @_;
 
@@ -823,6 +855,9 @@ sub _new_item {
   return $item;
 }
 
+# recalculate prices and taxes
+#
+# Using the PriceTaxCalclulator. Store linetotals in the item objects.
 sub _recalc {
   my ($self) = @_;
 
@@ -843,7 +878,9 @@ sub _recalc {
   pairwise { $a->{linetotal} = $b->{linetotal} } @{$self->order->items}, @{$pat{items}};
 }
 
-
+# get data for saving, printing, ..., that is not changed in the form
+#
+# Only cvars for now.
 sub _get_unalterable_data {
   my ($self) = @_;
 
@@ -857,7 +894,9 @@ sub _get_unalterable_data {
   }
 }
 
-
+# delete the order
+#
+# And remove related files in the spool directory
 sub _delete {
   my ($self) = @_;
 
@@ -877,7 +916,9 @@ sub _delete {
   return $errors;
 }
 
-
+# save the order
+#
+# And delete items that are deleted in the form.
 sub _save {
   my ($self) = @_;
 
@@ -946,7 +987,7 @@ sub _pre_render {
                                                 } } @all_objects;
   }
 
-  $::request->{layout}->use_javascript("${_}.js")  for qw(kivi.SalesPurchase ckeditor/ckeditor ckeditor/adapters/jquery);
+  $::request->{layout}->use_javascript("${_}.js")  for qw(kivi.SalesPurchase kivi.Order ckeditor/ckeditor ckeditor/adapters/jquery);
 }
 
 sub _create_pdf {
@@ -965,8 +1006,6 @@ sub _create_pdf {
   $print_form->{language_id} = $params->{language}->id            if $print_form->{language};
 
   $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};
 
   # search for the template
   my ($template_file, @template_files) = SL::Helper::CreatePDF->find_template(
@@ -1011,3 +1050,188 @@ sub _purchase_order_type {
 }
 
 1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Controller::Order - controller for orders
+
+=head1 SYNOPSIS
+
+This is a new form to enter orders, completely rewritten with the use
+of controller and java script techniques.
+
+The aim is to provide the user a better expirience and a faster flow
+of work. Also the code should be more readable, more reliable and
+better to maintain.
+
+=head2 key features
+
+=over 2
+
+=item *
+One input row, so that input happens every time at the same place.
+
+=item *
+Use of pickers where possible.
+
+=item *
+Possibility to enter more than one item at once.
+
+=item *
+Save order only on "save" (and "save and delivery order"-workflow). No
+hidden save on "print" or "email". 
+
+=item *
+Item list in a scrollable area, so that the workflow buttons stay at
+the bottom.
+
+=item *
+Reordering item rows with drag and drop is possible. Sorting item rows is
+possible (by partnumber, description, qty, sellprice and discount for now).
+
+=item *
+No "update" is necessary. All entries and calculations are managed
+with ajax-calls and the page does only reload on "save".
+
+=item *
+User can see changes immediately, because of the use of java script
+and ajax.
+
+=back
+
+=head1 CODE
+
+=head2 layout
+
+=over 2
+
+=item *
+SL/Controller/Order.pm: the controller
+
+=item *
+template/webpages/order/form.html: main form
+
+=item *
+template/webpages/order/tabs/basic_data.html: main tab for basic_data
+
+This is the only tab here for now. "linked records" and "webdav" tabs are reused
+from generic code.
+
+=over 3
+
+=item *
+template/webpages/order/tabs/_item_input.html: the input line for items
+
+=item *
+template/webpages/order/tabs/_row.html: one row for already entered items
+
+=item *
+template/webpages/order/tabs/_tax_row.html: displaying tax information
+
+=item *
+template/webpages/order/tabs/_multi_items_dialog.html: dialog for entering more
+than one item at once
+
+=item *
+template/webpages/order/tabs/_multi_items_result.html: results for the filter in
+the multi items dialog
+
+=item *
+template/webpages/order/tabs/_price_sources_dialog.html: dialog for selecting
+price and discount sources
+
+=item *
+template/webpages/order/tabs/_email_dialog.html: email dialog
+
+=back
+
+=item *
+js/kivi.Order.js: java script functions
+
+=back
+
+=head1 TODO
+
+=over 2
+
+=item *
+
+testing
+
+
+=item *
+
+currency
+
+
+=item *
+
+customer/vendor details ('D'-button)
+
+
+=item *
+
+credit limit
+
+
+=item *
+
+more workflows (save as new / invoice)
+
+
+=item *
+
+price sources: little symbols showing better price / better discount
+
+
+=item *
+
+custom shipto address
+
+
+=item *
+
+periodic invoices
+
+
+=item *
+
+more details on second row (marge, ...)
+
+
+=item *
+
+language / part translations
+
+
+=item *
+
+access rights
+
+
+=item *
+
+preset salesman from customer
+
+
+=item *
+
+display weights
+
+
+=item *
+
+force project if enabled in client config
+
+
+=back
+
+=head1 AUTHOR
+
+Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
+
+=cut