------------------------------------------------------------------------
[kivitendo-erp.git] / bin / mozilla / io.pl
index 081bc3f..524ccdb 100644 (file)
@@ -35,7 +35,7 @@
 
 use CGI;
 use CGI::Ajax;
-use List::Util qw(max first);
+use List::Util qw(min max first);
 
 use SL::CVar;
 use SL::Common;
@@ -88,6 +88,13 @@ use SL::IS;
 use SL::PE;
 use SL::AM;
 use Data::Dumper;
+
+sub _check_io_auth {
+  $auth->assert('part_service_assembly_edit   | vendor_invoice_edit       | sales_order_edit    | invoice_edit |' .
+                'request_quotation_edit       | sales_quotation_edit      | purchase_order_edit | ' .
+                'purchase_delivery_order_edit | sales_delivery_order_edit');
+}
+
 ########################################
 # Eintrag fuer Version 2.2.0 geaendert #
 # neue Optik im Rechnungsformular      #
@@ -95,9 +102,7 @@ use Data::Dumper;
 sub display_row {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit | ' .
-                'sales_delivery_order_edit  | purchase_delivery_order_edit');
+  _check_io_auth();
 
   my $numrows = shift;
 
@@ -106,6 +111,7 @@ sub display_row {
   my $is_purchase        = (first { $_ eq $form->{type} } qw(request_quotation purchase_order purchase_delivery_order)) || ($form->{script} eq 'ir.pl');
   my $show_min_order_qty =  first { $_ eq $form->{type} } qw(request_quotation purchase_order);
   my $is_delivery_order  = $form->{type} =~ /_delivery_order$/;
+  my $is_s_p_order       = (first { $_ eq $form->{type} } qw(sales_order purchase_order));
 
   if ($is_delivery_order) {
     $readonly             = ' readonly' if ($form->{closed});
@@ -117,24 +123,25 @@ sub display_row {
       $stock_in_out_title = $locale->text('Transfer To Stock');
       $stock_in_out       = 'in';
     }
+
+    retrieve_partunits();
   }
 
   # column_index
   my @header_sort = qw(runningnumber partnumber description ship qty unit sellprice_pg sellprice discount linetotal);
   my @HEADER = (
     {  id => 'runningnumber', width => 5,     value => $locale->text('No.'),                  display => 1, },
-    {  id => 'partnumber',    width => 12,    value => $locale->text('Number'),               display => 1, },
+    {  id => 'partnumber',    width => 8,     value => $locale->text('Number'),               display => 1, },
     {  id => 'description',   width => 30,    value => $locale->text('Part Description'),     display => 1, },
-    {  id => 'ship',          width => 5,     value => ($form->{type} eq 'purchase_order' ? $locale->text('Ship rcvd') : $locale->text('Ship')),                 
-       display => $form->{type} =~ /sales_order/ || ($form->{type} =~ /purchase_order/ && !($lizenzen && $form->{vc} eq "customer")) , },
+    {  id => 'ship',          width => 5,     value => $locale->text('Delivered'),            display => $is_s_p_order, },
     {  id => 'qty',           width => 5,     value => $locale->text('Qty'),                  display => 1, },
-    {  id => 'price_factor',  width => 5,     value => $locale->text('Price Factor'),         display => 1, },
+    {  id => 'price_factor',  width => 5,     value => $locale->text('Price Factor'),         display => !$is_delivery_order, },
     {  id => 'unit',          width => 5,     value => $locale->text('Unit'),                 display => 1, },
     {  id => 'license',       width => 10,    value => $locale->text('License'),              display => 0, },
     {  id => 'serialnr',      width => 10,    value => $locale->text('Serial No.'),           display => 0, },
     {  id => 'projectnr',     width => 10,    value => $locale->text('Project'),              display => 0, },
     {  id => 'sellprice',     width => 15,    value => $locale->text('Price'),                display => !$is_delivery_order, },
-    {  id => 'sellprice_pg',  width => 15,    value => $locale->text('Pricegroup'),           display => ($form->{type} =~ /^sales_/) && !$is_delivery_order,  },
+    {  id => 'sellprice_pg',  width => 8,    value => $locale->text('Pricegroup'),           display => ($form->{type} =~ /^sales_/) && !$is_delivery_order,  },
     {  id => 'discount',      width => 5,     value => $locale->text('Discount'),             display => ($form->{vc} eq 'customer') && !$is_delivery_order, },
     {  id => 'linetotal',     width => 10,    value => $locale->text('Extended'),             display => !$is_delivery_order, },
     {  id => 'bin',           width => 10,    value => $locale->text('Bin'),                  display => 0, },
@@ -143,8 +150,6 @@ sub display_row {
   my @column_index = map { $_->{id} } grep { $_->{display} } @HEADER;
 
   # cache units
-  my $dimension_units = AM->retrieve_units(\%myconfig, $form, "dimension");
-  my $service_units   = AM->retrieve_units(\%myconfig, $form, "service");
   my $all_units       = AM->retrieve_units(\%myconfig, $form);
 
   my %price_factors   = map { $_->{id} => $_->{factor} } @{ $form->{ALL_PRICE_FACTORS} };
@@ -183,20 +188,20 @@ sub display_row {
     $projectnumber_labels{$item->{"id"}} = $item->{"projectnumber"};
   }
 
+  _update_part_information();
+  _update_ship() if ($is_s_p_order);
+
   # rows
   for $i (1 .. $numrows) {
 
     # undo formatting
-    map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(qty ship discount sellprice price_new price_old) unless ($form->{simple_save});
+    map { $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"}) } qw(qty discount sellprice price_new price_old) unless ($form->{simple_save});
 
 # unit begin
     $form->{"unit_old_$i"}      ||= $form->{"unit_$i"};
     $form->{"selected_unit_$i"} ||= $form->{"unit_$i"};
 
-    my $local_units = $form->{"inventory_accno_$i"} || $form->{"assembly_$i"} ? $dimension_units 
-                    : $form->{"id_$i"}                                        ? $service_units 
-                    :                                                           $all_units;
-    if (   !$local_units->{$form->{"selected_unit_$i"}}                                          # Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
+    if (   !$all_units->{$form->{"selected_unit_$i"}}                                            # Die ausgewaehlte Einheit ist fuer diesen Artikel nicht gueltig
         || !AM->convert_unit($form->{"selected_unit_$i"}, $form->{"unit_old_$i"}, $all_units)) { # (z.B. Dimensionseinheit war ausgewaehlt, es handelt sich aber
       $form->{"unit_old_$i"} = $form->{"selected_unit_$i"} = $form->{"unit_$i"};                 # um eine Dienstleistung). Dann keinerlei Umrechnung vornehmen.
     }
@@ -223,25 +228,21 @@ sub display_row {
       $column_data{price_factor} = ' ';
     }
 
-    $column_data{"unit"} = AM->unit_select_html($local_units, "unit_$i", $this_unit, $form->{"id_$i"} ? $form->{"unit_$i"} : undef);
+    $column_data{"unit"} = AM->unit_select_html($all_units, "unit_$i", $this_unit, $form->{"id_$i"} ? $form->{"unit_$i"} : undef);
 # / unit ending
 
     $form->{"sellprice_$i"} =~ /\.(\d+)/;
     $decimalplaces = max 2, length $1;
 
     $price_factor   = $price_factors{$form->{"price_factor_id_$i"}} || 1;
-    $discount       = $form->round_amount($form->{"sellprice_$i"} * $form->{"discount_$i"} / 100, $decimalplaces);
-    $linetotal      = $form->round_amount(($form->{"sellprice_$i"} - $discount) / $price_factor, $decimalplaces);
-    $linetotal      = $form->round_amount($linetotal * $form->{"qty_$i"}, 2);
-
-    # convert " to "
-    map { $form->{"${_}_$i"} =~ s/\"/"/g } qw(partnumber description unit unit_old);
+    $discount       = $form->round_amount($form->{"qty_$i"} * $form->{"sellprice_$i"} *        $form->{"discount_$i"}  / 100 / $price_factor, 2);
+    $linetotal      = $form->round_amount($form->{"qty_$i"} * $form->{"sellprice_$i"} * (100 - $form->{"discount_$i"}) / 100 / $price_factor, 2);
 
     $column_data{runningnumber} = $cgi->textfield(-name => "runningnumber_$i", -size => 5,  -value => $i);    # HuT
     $column_data{partnumber}    = $cgi->textfield(-name => "partnumber_$i",    -size => 12, -value => $form->{"partnumber_$i"});
     $column_data{description} = ((($rows = $form->numtextrows($form->{"description_$i"}, 30, 6)) > 1) # if description is too large, use a textbox instead
-                                ? $cgi->textarea( -name => "description_$i", -default => H($form->{"description_$i"}), -rows => $rows, -columns => 30)
-                                : $cgi->textfield(-name => "description_$i",   -size => 30, -value => $form->quote($form->{"description_$i"})))
+                                ? $cgi->textarea( -name => "description_$i", -default => $form->{"description_$i"}, -rows => $rows, -columns => 30)
+                                : $cgi->textfield(-name => "description_$i",   -size => 30, -value => $form->{"description_$i"}))
                                 . $cgi->button(-value => $locale->text('L'), -onClick => "set_longdescription_window('longdescription_$i')");
 
     $form->{"qty_$i"} =~ /\.(\d+)/;
@@ -251,11 +252,14 @@ sub display_row {
     $column_data{qty} .= $cgi->button(-onclick => "calculate_qty_selection_window('qty_$i','alu_$i', 'formel_$i', $i)", -value => $locale->text('*/'))
                        . $cgi->hidden(-name => "formel_$i", -value => $form->{"formel_$i"}) . $cgi->hidden("-name" => "alu_$i", "-value" => $form->{"alu_$i"})
       if $form->{"formel_$i"};
-    $column_data{ship} = $cgi->textfield(-name => "ship_$i", -size => 5, -value => $form->format_amount(\%myconfig, $form->{"ship_$i"}));
+    $column_data{ship} = !$form->{"id_$i"} ? '' : $form->format_amount_units('amount'     => $form->{"ship_$i"} * 1,
+                                                                             'part_unit'  => $form->{"partunit_$i"},
+                                                                             'conv_units' => 'convertible_not_smaller',
+                                                                             'max_places' => 2);
 
     # build in drop down list for pricesgroups
     if ($form->{"prices_$i"}) {
-      $column_data{sellprice_pg} = qq|<select name="sellprice_pg_$i">$form->{"prices_$i"}</select>|;
+      $column_data{sellprice_pg} = qq|<select name="sellprice_pg_$i" style="width: 8em">$form->{"prices_$i"}</select>|;
       $column_data{sellprice}    = $cgi->textfield(-name => "sellprice_$i", -size => 10, -onBlur => 'check_right_number_format(this)', -value =>
                                    (($form->{"new_pricegroup_$i"} != $form->{"old_pricegroup_$i"})
                                       ? $form->format_amount(\%myconfig, $form->{"price_new_$i"}, $decimalplaces)
@@ -290,7 +294,7 @@ sub display_row {
     push @ROW2, { value => qq|<b>$projectnumber</b> | . NTI($cgi->popup_menu('-name'  => "project_id_$i",        '-values'  => \@projectnumber_values,
                                                                              '-labels' => \%projectnumber_labels, '-default' => $form->{"project_id_$i"})) };
     push @ROW2, { value => qq|<b>$reqdate</b> <input name="reqdate_$i" size="11" onBlur="check_right_date_format(this)" value="$form->{"reqdate_$i"}">| }
-      if $form->{type} =~ /order/;
+      if ($form->{type} =~ /order/ ||  $form->{type} =~ /invoice/);
     push @ROW2, { value => sprintf qq|<b>%s</b>&nbsp;<input type="checkbox" name="subtotal_$i" value="1" %s>|, 
                    $locale->text('Subtotal'), $form->{"subtotal_$i"} ? 'checked' : '' };
 
@@ -320,19 +324,17 @@ sub display_row {
                    $marge_color, $locale->text('Ertrag'),$form->{"marge_absolut_$i"}, $form->{"marge_percent_$i"},
                    $locale->text('LP'), $form->format_amount(\%myconfig, $form->{"listprice_$i"}, 2),
                    $locale->text('EK'), $form->format_amount(\%myconfig, $form->{"lastcost_$i"}, 2) }
-      if $form->{"id_$i"} && $form->{type} =~ /^sales_/ && !$is_delivery_order;
+      if $form->{"id_$i"} && ($form->{type} =~ /^sales_/ ||  $form->{type} =~ /invoice/) && !$is_delivery_order;
 # / marge calculations ending
 
     my @hidden_vars;
 
     if ($is_delivery_order) {
       map { $form->{"${_}_${i}"} = $form->format_amount(\%myconfig, $form->{"${_}_${i}"}) } qw(sellprice discount);
-      push @hidden_vars, qw(sellprice discount);
+      push @hidden_vars, qw(sellprice discount price_factor_id);
       push @hidden_vars, "stock_${stock_in_out}_sum_qty", "stock_${stock_in_out}";
     }
 
-    push @hidden_vars, qw(partunit) if ($is_purchase);
-
     my @HIDDENS = map { value => $_}, (
           $cgi->hidden("-name" => "unit_old_$i", "-value" => $form->{"selected_unit_$i"}),
           $cgi->hidden("-name" => "price_new_$i", "-value" => $form->format_amount(\%myconfig, $form->{"price_new_$i"})),
@@ -366,8 +368,7 @@ sub display_row {
 sub set_pricegroup {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   my $rowcount = shift;
   for $j (1 .. $rowcount) {
@@ -390,8 +391,7 @@ sub set_pricegroup {
 sub select_item {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   @column_index = qw(ndx partnumber description onhand unit sellprice);
 
@@ -521,8 +521,7 @@ sub select_item {
 sub item_selected {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   # replace the last row with the checked row
   $i = $form->{rowcount};
@@ -622,20 +621,23 @@ sub item_selected {
 sub new_item {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
+
+  my $price_key = ($form->{type} =~ m/request_quotation|purchase_order/) || ($form->{script} eq 'ir.pl') ? 'lastcost' : 'sellprice';
 
   # change callback
   $form->{old_callback} = $form->escape($form->{callback}, 1);
   $form->{callback}     = $form->escape("$form->{script}?action=display_form", 1);
 
   # save all form variables except action in a previousform variable
-  my $previousform = join '&', map { $form->{$_} =~ s/&/%26/; "$_=$form->{$_}" } grep { !/action/ } keys %$form;
+  my $previousform = join '&', map { my $value = $form->{$_}; $value =~ s/&/%26/; "$_=$value" } grep { !/action/ } keys %$form;
 
   push @HIDDENS,      { 'name' => 'previousform', 'value' => $form->escape($previousform, 1) };
   push @HIDDENS, map +{ 'name' => $_,             'value' => $form->{$_} },                       qw(rowcount vc);
-  push @HIDDENS, map +{ 'name' => $_,             'value' => $form->{"${_}_$form->{rowcount}"} }, qw(partnumber description unit sellprice);
+  push @HIDDENS, map +{ 'name' => $_,             'value' => $form->{"${_}_$form->{rowcount}"} }, qw(partnumber description unit);
   push @HIDDENS,      { 'name' => 'taxaccount2',  'value' => $form->{taxaccounts} };
+  push @HIDDENS,      { 'name' => $price_key,     'value' => $form->parse_amount(\%myconfig, $form->{"sellprice_$form->{rowcount}"}) };
+  push @HIDDENS,      { 'name' => 'notes',        'value' => $form->{"longdescription_$form->{rowcount}"} };
 
   $form->header();
   print $form->parse_html_template("generic/new_item", { HIDDENS => [ sort { $a->{name} cmp $b->{name} } @HIDDENS ] } );
@@ -646,8 +648,7 @@ sub new_item {
 sub check_form {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   my @a     = ();
   my $count = 0;
@@ -754,8 +755,7 @@ sub check_form {
 sub invoicetotal {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   $form->{oldinvtotal} = 0;
 
@@ -795,8 +795,7 @@ sub invoicetotal {
 sub validate_items {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   # check if items are valid
   if ($form->{rowcount} == 1) {
@@ -815,8 +814,7 @@ sub validate_items {
 sub order {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   if ($form->{second_run}) {
     $form->{print_and_post} = 0;
@@ -860,19 +858,11 @@ sub order {
   &order_links;
 
   $form->{currency}     = $currency;
-  $form->{exchangerate} = "";
-  $form->{forex}        = "";
-  $form->{exchangerate} = $exchangerate
-    if (
-        $form->{forex} = (
-                  $exchangerate =
-                    $form->check_exchangerate(
-                    \%myconfig, $form->{currency}, $form->{transdate}, $buysell
-                    )));
+  $form->{forex}        = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{transdate}, $buysell);
+  $form->{exchangerate} = $form->{forex} || '';
 
   for $i (1 .. $form->{rowcount}) {
-    map({ $form->{"${_}_${i}"} = $form->parse_amount(\%myconfig,
-                                                     $form->{"${_}_${i}"})
+    map({ $form->{"${_}_${i}"} = $form->parse_amount(\%myconfig, $form->{"${_}_${i}"})
             if ($form->{"${_}_${i}"}) }
         qw(ship qty sellprice listprice basefactor));
   }
@@ -886,8 +876,7 @@ sub order {
 sub quotation {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   if ($form->{second_run}) {
     $form->{print_and_post} = 0;
@@ -924,15 +913,8 @@ sub quotation {
   &order_links;
 
   $form->{currency}     = $currency;
-  $form->{exchangerate} = "";
-  $form->{forex}        = "";
-  $form->{exchangerate} = $exchangerate
-    if (
-        $form->{forex} = (
-                  $exchangerate =
-                    $form->check_exchangerate(
-                    \%myconfig, $form->{currency}, $form->{transdate}, $buysell
-                    )));
+  $form->{forex}        = $form->check_exchangerate( \%myconfig, $form->{currency}, $form->{transdate}, $buysell);
+  $form->{exchangerate} = $form->{forex} || '';
 
   for $i (1 .. $form->{rowcount}) {
     map({ $form->{"${_}_${i}"} = $form->parse_amount(\%myconfig,
@@ -954,8 +936,7 @@ sub request_for_quotation {
 sub edit_e_mail {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   if ($form->{second_run}) {
     $form->{print_and_post} = 0;
@@ -975,6 +956,7 @@ sub edit_e_mail {
   $form->{media}    = "email";
 
   my $attachment_filename = $form->generate_attachment_filename();
+  my $subject             = $form->{subject} || $form->generate_email_subject();
 
   $form->{"fokus"} = $form->{"email"} ? "Form.subject" : "Form.email";
   $form->header;
@@ -987,6 +969,7 @@ sub edit_e_mail {
   print $form->parse_html_template('generic/edit_email',
                                    { title           => $title,
                                      a_filename      => $attachment_filename,
+                                     subject         => $subject,
                                      _print_options_ => print_options('inline' => 1),
                                      HIDDEN          => [ map +{ name => $_, value => $form->{$_} }, @hidden_keys ],
                                      SHOW_BCC        => $myconfig{role} eq 'admin' });
@@ -997,8 +980,7 @@ sub edit_e_mail {
 sub send_email {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   my $callback = $form->{script} . "?action=edit";
   map({ $callback .= "\&${_}=" . E($form->{$_}); } qw(type id));
@@ -1025,9 +1007,7 @@ sub send_email {
 sub print_options {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit     | vendor_invoice_edit        | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit         | sales_quotation_edit       | purchase_order_edit | dunning_edit |' .
-                'sales_delivery_order_edit      | purchase_delivery_order_edit');
+  _check_io_auth();
 
   my %options = @_;
 
@@ -1141,9 +1121,7 @@ sub print_options {
 sub print {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit | ' .
-                'order_request_edit_all     | order_request_edit');
+  _check_io_auth();
 
   if ($form->{print_nextsub}) {
     call_sub($form->{print_nextsub});
@@ -1180,9 +1158,7 @@ sub print {
 sub print_form {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit     | vendor_invoice_edit        | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit         | sales_quotation_edit       | purchase_order_edit |' .
-                'sales_delivery_order_edit      | purchase_delivery_order_edit');
+  _check_io_auth();
 
   my ($old_form) = @_;
 
@@ -1377,13 +1353,7 @@ sub print_form {
   ($form->{employee}) = split /--/, $form->{employee};
 
   # create the form variables
-  if ($form->{formname} eq 'order_request') {
-    order_request_details();
-  } elsif ($form->{formname} eq 'return_material_slip') {
-    rms_details();
-  } elsif ($form->{formname} eq 'release_material_slip') {
-    rlms_details();
-  } elsif ($form->{type} =~ /_delivery_order$/) {
+  if ($form->{type} =~ /_delivery_order$/) {
     DO->order_details();
   } elsif ($order) {
     OE->order_details(\%myconfig, \%$form);
@@ -1624,7 +1594,9 @@ sub print_form {
 
 sub customer_details {
   $lxdebug->enter_sub();
+
   IS->customer_details(\%myconfig, \%$form, @_);
+
   $lxdebug->leave_sub();
 }
 
@@ -1639,8 +1611,7 @@ sub vendor_details {
 sub post_as_new {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   $form->{postasnew} = 1;
   map { delete $form->{$_} } qw(printed emailed queued);
@@ -1653,8 +1624,7 @@ sub post_as_new {
 sub ship_to {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   if ($form->{second_run}) {
     $form->{print_and_post} = 0;
@@ -1808,8 +1778,7 @@ sub ship_to {
 sub new_license {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   my $row = shift;
 
@@ -1850,8 +1819,7 @@ sub new_license {
 sub relink_accounts {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   $form->{"taxaccounts"} =~ s/\s*$//;
   $form->{"taxaccounts"} =~ s/^\s*//;
@@ -1872,16 +1840,75 @@ sub relink_accounts {
 sub set_duedate {
   $lxdebug->enter_sub();
 
-  $auth->assert('part_service_assembly_edit | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
-                'request_quotation_edit     | sales_quotation_edit | purchase_order_edit');
+  _check_io_auth();
 
   $form->get_duedate(\%myconfig);
 
-  my $q = new CGI;
-  $result = "$form->{duedate}";
-  print $q->header();
-  print $result;
+  print $cgi->header() . $form->{duedate};
+
   $lxdebug->leave_sub();
+}
+
+sub _update_part_information {
+  $lxdebug->enter_sub();
+
+  my %part_information = IC->get_basic_part_info('id'        => [ grep { $_ } map { $form->{"id_${_}"} } (1..$form->{rowcount}) ],
+                                                 'vendor_id' => $form->{vendor_id});
 
+  $form->{PART_INFORMATION} = \%part_information;
+
+  foreach my $i (1..$form->{rowcount}) {
+    next unless ($form->{"id_${i}"});
+
+    my $info                 = $form->{PART_INFORMATION}->{$form->{"id_${i}"}} || { };
+    $form->{"partunit_${i}"} = $info->{unit};
+  }
+
+  $lxdebug->leave_sub();
 }
 
+sub _update_ship {
+  $lxdebug->enter_sub();
+
+  if (!$form->{ordnumber}) {
+    map { $form->{"ship_$_"} = 0 } (1..$form->{rowcount});
+    $lxdebug->leave_sub();
+    return;
+  }
+
+  AM->retrieve_all_units();
+
+  my %ship = DO->get_shipped_qty('type'      => ($form->{type} eq 'purchase_order') ? 'purchase' : 'sales',
+                                 'ordnumber' => $form->{ordnumber},);
+
+  foreach my $i (1..$form->{rowcount}) {
+    next unless ($form->{"id_${i}"});
+
+    $form->{"ship_$i"} = 0;
+
+    my $ship_entry = $ship{$form->{"id_$i"}};
+
+    next if (!$ship_entry || ($ship_entry->{qty} <= 0));
+
+    my $rowqty =
+      ($form->{simple_save} ? $form->{"qty_$i"} : $form->parse_amount(\%myconfig, $form->{"qty_$i"}))
+      * $all_units->{$form->{"unit_$i"}}->{factor}
+      / $all_units->{$form->{"partunit_$i"}}->{factor};
+
+    $form->{"ship_$i"}  = min($rowqty, $ship_entry->{qty});
+    $ship_entry->{qty} -= $form->{"ship_$i"};
+  }
+
+  foreach my $i (1..$form->{rowcount}) {
+    next unless ($form->{"id_${i}"});
+
+    my $ship_entry = $ship{$form->{"id_$i"}};
+
+    next if (!$ship_entry || ($ship_entry->{qty} <= 0.01));
+
+    $form->{"ship_$i"} += $ship_entry->{qty};
+    $ship_entry->{qty}  = 0;
+  }
+
+  $lxdebug->leave_sub();
+}