ActionBar: nicht mehr benötigte Lieferadressenmaske entfernt
[kivitendo-erp.git] / bin / mozilla / ic.pl
index 5fb8adf..2aae5cd 100644 (file)
@@ -24,7 +24,8 @@
 # GNU General Public License for more details.
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1335, USA.
 #======================================================================
 #
 # Inventory Control module
@@ -74,23 +75,6 @@ require "bin/mozilla/reportgenerator.pl";
 
 # end of main
 
-sub add {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_edit');
-
-  my $title                = 'Add ' . ucfirst $form->{item};
-  $form->{title}           = $locale->text($title);
-  $form->{callback}        = "$form->{script}?action=add&item=$form->{item}" unless $form->{callback};
-  $form->{unit_changeable} = 1;
-
-  IC->get_pricegroups(\%myconfig, \%$form);
-  &link_part;
-  &display_form;
-
-  $lxdebug->leave_sub();
-}
-
 sub search {
   $lxdebug->enter_sub();
 
@@ -100,11 +84,9 @@ sub search {
   $form->{lastsort}     = ""; # memory for which table was sort at last time
   $form->{ndxs_counter} = 0;  # counter for added entries to top100
 
-  my %is_xyz     = map { +"is_$_" => ($form->{searchitems} eq $_) } qw(part service assembly);
-
   $form->{title} = (ucfirst $form->{searchitems}) . "s";
+  $form->{title} =~ s/ys$/ies/;
   $form->{title} = $locale->text($form->{title});
-  $form->{title} = $locale->text('Assemblies') if ($is_xyz{is_assembly});
 
   $form->{CUSTOM_VARIABLES}                  = CVar->get_configs('module' => 'IC');
   ($form->{CUSTOM_VARIABLES_FILTER_CODE},
@@ -115,88 +97,11 @@ sub search {
   $form->header;
 
   $form->get_lists('partsgroup'    => 'ALL_PARTSGROUPS');
-  print $form->parse_html_template('ic/search', { %is_xyz, });
+  print $form->parse_html_template('ic/search');
 
   $lxdebug->leave_sub();
 }    #end search()
 
-sub search_update_prices {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_edit');
-
-  my $pricegroups = IC->get_pricegroups(\%myconfig, \%$form);
-
-  $form->{title} = $locale->text('Update Prices');
-
-  $form->header;
-
-  print $form->parse_html_template('ic/search_update_prices', { PRICE_ROWS => $pricegroups });
-
-  $lxdebug->leave_sub();
-}    #end search()
-
-sub confirm_price_update {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_edit');
-
-  my @errors      = ();
-  my $value_found = undef;
-
-  foreach my $idx (qw(sellprice listprice), (1..$form->{price_rows})) {
-    my $name      = $idx =~ m/\d/ ? $form->{"pricegroup_${idx}"}      : $idx eq 'sellprice' ? $locale->text('Sell Price') : $locale->text('List Price');
-    my $type      = $idx =~ m/\d/ ? $form->{"pricegroup_type_${idx}"} : $form->{"${idx}_type"};
-    my $value_idx = $idx =~ m/\d/ ? "price_${idx}" : $idx;
-    my $value     = $form->parse_amount(\%myconfig, $form->{$value_idx});
-
-    if ((0 > $value) && ($type eq 'percent')) {
-      push @errors, $locale->text('You cannot adjust the price for pricegroup "#1" by a negative percentage.', $name);
-
-    } elsif (!$value && ($form->{$value_idx} ne '')) {
-      push @errors, $locale->text('No valid number entered for pricegroup "#1".', $name);
-
-    } elsif (0 < $value) {
-      $value_found = 1;
-    }
-  }
-
-  push @errors, $locale->text('No prices will be updated because no prices have been entered.') if (!$value_found);
-
-  my $num_matches = IC->get_num_matches_for_priceupdate();
-
-  $form->header();
-
-  if (@errors) {
-    $form->show_generic_error(join('<br>', @errors), 'back_button' => 1);
-  }
-
-  $form->{nextsub} = "update_prices";
-
-  map { delete $form->{$_} } qw(action header);
-
-  print $form->parse_html_template('ic/confirm_price_update', { HIDDENS     => [ map { name => $_, value => $form->{$_} }, keys %$form ],
-                                                                num_matches => $num_matches });
-
-  $lxdebug->leave_sub();
-}
-
-sub update_prices {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_edit');
-
-  my $num_updated = IC->update_prices(\%myconfig, \%$form);
-
-  if (-1 != $num_updated) {
-    $form->redirect($locale->text('#1 prices were updated.', $num_updated));
-  } else {
-    $form->error($locale->text('Could not update prices!'));
-  }
-
-  $lxdebug->leave_sub();
-}
-
 sub top100 {
   $::lxdebug->enter_sub();
 
@@ -233,7 +138,7 @@ sub top100 {
 #  searchitems=part revers=0 lastsort=''
 #
 # filter:
-# partnumber ean description partsgroup serialnumber make model drawing microfiche
+# partnumber ean description partsgroup classification serialnumber make model drawing microfiche
 # transdatefrom transdateto
 #
 # radio:
@@ -258,9 +163,7 @@ sub generate_report {
 
   my $cvar_configs = CVar->get_configs('module' => 'IC');
 
-  $form->{title} = (ucfirst $form->{searchitems}) . "s";
-  $form->{title} =~ s/ys$/ies/;
-  $form->{title} = $locale->text($form->{title});
+  $form->{title} = $locale->text('Articles');
 
   my %column_defs = (
     'bin'                => { 'text' => $locale->text('Bin'), },
@@ -282,7 +185,7 @@ sub generate_report {
     'onhand'             => { 'text' => $locale->text('Stocked Qty'), },
     'ordnumber'          => { 'text' => $locale->text('Order Number'), },
     'partnumber'         => { 'text' => $locale->text('Part Number'), },
-    'partsgroup'         => { 'text' => $locale->text('Group'), },
+    'partsgroup'         => { 'text' => $locale->text('Partsgroup'), },
     'priceupdate'        => { 'text' => $locale->text('Updated'), },
     'quonumber'          => { 'text' => $locale->text('Quotation'), },
     'rop'                => { 'text' => $locale->text('ROP'), },
@@ -294,6 +197,7 @@ sub generate_report {
     'unit'               => { 'text' => $locale->text('Unit'), },
     'weight'             => { 'text' => $locale->text('Weight'), },
     'shop'               => { 'text' => $locale->text('Shop article'), },
+    'type_and_classific' => { 'text' => $locale->text('Type'), },
     'projectnumber'      => { 'text' => $locale->text('Project Number'), },
     'projectdescription' => { 'text' => $locale->text('Project Description'), },
   );
@@ -368,8 +272,8 @@ sub generate_report {
     transdatefrom => $locale->text('From')       . " " . $locale->date(\%myconfig, $form->{transdatefrom}, 1),
     transdateto   => $locale->text('To (time)')  . " " . $locale->date(\%myconfig, $form->{transdateto}, 1),
     partnumber    => $locale->text('Part Number')      . ": '$form->{partnumber}'",
-    partsgroup    => $locale->text('Group')            . ": '$form->{partsgroup}'",
-    partsgroup_id => $locale->text('Group')            . ": '$pg_name'",
+    partsgroup    => $locale->text('Partsgroup')       . ": '$form->{partsgroup}'",
+    partsgroup_id => $locale->text('Partsgroup')       . ": '$pg_name'",
     serialnumber  => $locale->text('Serial Number')    . ": '$form->{serialnumber}'",
     description   => $locale->text('Part Description') . ": '$form->{description}'",
     make          => $locale->text('Make')             . ": '$form->{make}'",
@@ -418,8 +322,9 @@ sub generate_report {
     $form->{l_linetotallastcost}  = $form->{searchitems} eq 'assembly' && !$form->{bom} ? "" : 'Y' if  $form->{l_lastcost};
     $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
   }
+  $form->{"l_type_and_classific"} = "Y";
 
-  if ($form->{searchitems} eq 'service') {
+  if ($form->{l_service} && !$form->{l_assembly} && !$form->{l_part}) {
 
     # remove bin, weight and rop from list
     map { $form->{"l_$_"} = "" } qw(bin weight rop);
@@ -466,14 +371,14 @@ sub generate_report {
   IC->all_parts(\%myconfig, \%$form);
 
   my @columns = qw(
-    partnumber description notes partsgroup bin onhand rop soldtotal unit listprice
+    partnumber type_and_classific description notes partsgroup bin onhand rop soldtotal unit listprice
     linetotallistprice sellprice linetotalsellprice lastcost linetotallastcost
     priceupdate weight image drawing microfiche invnumber ordnumber quonumber
     transdate name serialnumber deliverydate ean projectnumber projectdescription
     insertdate shop
   );
 
-  my $pricegroups = SL::DB::Manager::Pricegroup->get_all(sort => 'id');
+  my $pricegroups = SL::DB::Manager::Pricegroup->get_all_sorted;
   my @pricegroup_columns;
   my %column_defs_pricegroups;
   if ($form->{l_pricegroups}) {
@@ -499,6 +404,7 @@ sub generate_report {
 
   my @hidden_variables = (
     qw(l_subtotal l_linetotal searchitems itemstatus bom l_pricegroups insertdatefrom insertdateto),
+    qw(l_type_and_classific classification_id),
     @itemstatus_keys,
     @callback_keys,
     map({ "cvar_$_->{name}" } @searchable_custom_variables),
@@ -525,13 +431,15 @@ sub generate_report {
     'part'     => $locale->text('part_list'),
     'service'  => $locale->text('service_list'),
     'assembly' => $locale->text('assembly_list'),
+    'article'  => $locale->text('article_list'),
   );
 
   $report->set_options('raw_top_info_text'     => $form->parse_html_template('ic/generate_report_top', { options => \@options }),
-                       'raw_bottom_info_text'  => $form->parse_html_template('ic/generate_report_bottom'),
+                       'raw_bottom_info_text'  => $form->parse_html_template('ic/generate_report_bottom' ,
+                                                  { PART_CLASSIFICATIONS => SL::DB::Manager::PartClassification->get_all_sorted }),
                        'output_format'         => 'HTML',
                        'title'                 => $form->{title},
-                       'attachment_basename'   => $attachment_basenames{$form->{searchitems}} . strftime('_%Y%m%d', localtime time),
+                       'attachment_basename'   => 'article_list' . strftime('_%Y%m%d', localtime time),
   );
   $report->set_options_from_form();
   $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
@@ -585,7 +493,7 @@ sub generate_report {
       $soldtotal                  = 0 if ($form->{sold});
     }
 
-    my $edit_link               = build_std_url('action=edit', 'id=' . E($ref->{id}), 'callback');
+    my $edit_link               = build_std_url('script=controller.pl', 'action=Part/edit', 'part.id=' . E($ref->{id}), 'callback');
     $row->{partnumber}->{link}  = $edit_link;
     $row->{description}->{link} = $edit_link;
 
@@ -641,6 +549,8 @@ sub generate_report {
     map { $row->{$_}{link} = $ref->{$_} } qw(drawing microfiche);
 
     $row->{notes}{data} = SL::HTML::Util->strip($ref->{notes});
+    $row->{type_and_classific}{data} = $::request->presenter->type_abbreviation($ref->{part_type}).
+                                       $::request->presenter->classification_abbreviation($ref->{classification_id});
 
     $report->add_data($row);
 
@@ -652,7 +562,7 @@ sub generate_report {
          (!$next_ref->{assemblyitem} && ($same_item ne $next_ref->{ $form->{sort} })))) {
       my $row = { map { $_ => { 'class' => 'listsubtotal', } } @columns };
 
-      if (($form->{searchitems} ne 'assembly') || !$form->{bom}) {
+      if ( !$form->{l_assembly} || !$form->{bom}) {
         $row->{soldtotal}->{data} = $form->format_amount(\%myconfig, $subtotals{soldtotal});
       }
 
@@ -681,730 +591,4 @@ sub generate_report {
   $lxdebug->leave_sub();
 }    #end generate_report
 
-sub parts_subtotal {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_edit');
-
-  my (%column_data);
-  my ($column_index, $subtotalonhand, $subtotalsellprice, $subtotallastcost, $subtotallistprice) = @_;
-
-  map { $column_data{$_} = "<td>&nbsp;</td>" } @{ $column_index };
-  $$subtotalonhand = 0 if ($form->{searchitems} eq 'assembly' && $form->{bom});
-
-  $column_data{onhand} =
-      "<th class=listsubtotal align=right>"
-    . $form->format_amount(\%myconfig, $$subtotalonhand)
-    . "</th>";
-
-  $column_data{linetotalsellprice} =
-      "<th class=listsubtotal align=right>"
-    . $form->format_amount(\%myconfig, $$subtotalsellprice, 2)
-    . "</th>";
-  $column_data{linetotallistprice} =
-      "<th class=listsubtotal align=right>"
-    . $form->format_amount(\%myconfig, $$subtotallistprice, 2)
-    . "</th>";
-  $column_data{linetotallastcost} =
-      "<th class=listsubtotal align=right>"
-    . $form->format_amount(\%myconfig, $$subtotallastcost, 2)
-    . "</th>";
-
-  $$subtotalonhand    = 0;
-  $$subtotalsellprice = 0;
-  $$subtotallistprice = 0;
-  $$subtotallastcost  = 0;
-
-  print "<tr class=listsubtotal>";
-
-  map { print "\n$column_data{$_}" } @{ $column_index };
-
-  print qq|
-  </tr>
-|;
-
-  $lxdebug->leave_sub();
-}
-
-sub edit {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_details');
-
-  # show history button
-  $form->{javascript} = qq|<script type="text/javascript" src="js/show_history.js"></script>|;
-  #/show hhistory button
-  IC->get_part(\%myconfig, \%$form);
-
-  $form->{"original_partnumber"} = $form->{"partnumber"};
-
-  my $title      = 'Edit ' . ucfirst $form->{item};
-  $form->{title} = $locale->text($title);
-
-  &link_part;
-  &display_form;
-
-  $lxdebug->leave_sub();
-}
-
-sub link_part {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_details');
-
-  IC->create_links("IC", \%myconfig, \%$form);
-
-  # currencies
-  map({ $form->{selectcurrency} .= "<option>$_\n" } $::form->get_all_currencies());
-
-  # parts and assemblies have the same links
-  my $item = $form->{item};
-  if ($form->{item} eq 'assembly') {
-    $item = 'part';
-  }
-
-  # build the popup menus
-  $form->{taxaccounts} = "";
-  foreach my $key (keys %{ $form->{IC_links} }) {
-    foreach my $ref (@{ $form->{IC_links}{$key} }) {
-
-      # if this is a tax field
-      if ($key =~ /IC_tax/) {
-        if ($key =~ /\Q$item\E/) {
-          $form->{taxaccounts} .= "$ref->{accno} ";
-          $form->{"IC_tax_$ref->{accno}_description"} =
-            "$ref->{accno}--$ref->{description}";
-
-          if ($form->{id}) {
-            if ($form->{amount}{ $ref->{accno} }) {
-              $form->{"IC_tax_$ref->{accno}"} = "checked";
-            }
-          } else {
-            $form->{"IC_tax_$ref->{accno}"} = "checked";
-          }
-        }
-      } else {
-
-        $form->{"select$key"} .=
-          "<option $ref->{selected}>$ref->{accno}--$ref->{description}\n";
-        if ($form->{amount}{$key} eq $ref->{accno}) {
-          $form->{$key} = "$ref->{accno}--$ref->{description}";
-        }
-
-      }
-    }
-  }
-  chop $form->{taxaccounts};
-
-  if (($form->{item} eq "part") || ($form->{item} eq "assembly")) {
-    $form->{selectIC_income}  = $form->{selectIC_sale};
-    $form->{selectIC_expense} = $form->{selectIC_cogs};
-    $form->{IC_income}        = $form->{IC_sale};
-    $form->{IC_expense}       = $form->{IC_cogs};
-  }
-
-  delete $form->{IC_links};
-  delete $form->{amount};
-
-  $form->get_partsgroup(\%myconfig, { all => 1 });
-
-  $form->{partsgroup} = "$form->{partsgroup}--$form->{partsgroup_id}";
-
-  if (@{ $form->{all_partsgroup} }) {
-    $form->{selectpartsgroup} = qq|<option>\n|;
-    map { $form->{selectpartsgroup} .= qq|<option value="$_->{partsgroup}--$_->{id}">$_->{partsgroup}\n| } @{ $form->{all_partsgroup} };
-  }
-
-  if ($form->{item} eq 'assembly') {
-
-    foreach my $i (1 .. $form->{assembly_rows}) {
-      if ($form->{"partsgroup_id_$i"}) {
-        $form->{"partsgroup_$i"} =
-          qq|$form->{"partsgroup_$i"}--$form->{"partsgroup_id_$i"}|;
-      }
-    }
-    $form->get_partsgroup(\%myconfig);
-
-    if (@{ $form->{all_partsgroup} }) {
-      $form->{selectassemblypartsgroup} = qq|<option>\n|;
-
-      map {
-        $form->{selectassemblypartsgroup} .=
-          qq|<option value="$_->{partsgroup}--$_->{id}">$_->{partsgroup}\n|
-      } @{ $form->{all_partsgroup} };
-    }
-  }
-  $lxdebug->leave_sub();
-}
-
-sub form_header {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_details');
-
-  $form->{pg_keys}          = sub { "$_[0]->{partsgroup}--$_[0]->{id}" };
-  $form->{description_area} = ($form->{rows} = $form->numtextrows($form->{description}, 40)) > 1;
-  $form->{notes_rows}       =  max 4, $form->numtextrows($form->{notes}, 40), $form->numtextrows($form->{formel}, 40);
-
-  map { $form->{"is_$_"}  = ($form->{item} eq $_) } qw(part service assembly);
-  map { $form->{$_}       =~ s/"/&quot;/g;        } qw(unit);
-
-  $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
-                   'partsgroup'    => 'all_partsgroup',
-                   'vendors'       => 'ALL_VENDORS',
-                   'warehouses'    => { 'key'    => 'WAREHOUSES',
-                                        'bins'   => 'BINS', });
-  # leerer wert für Lager und Lagerplatz korrekt einstellt
-  # ID 0 sollte in Ordnung sein, da der Zähler sowieso höher ist
-  my $no_default_bin_entry = { 'id' => '0', description => '--', 'BINS' => [ { id => '0', description => ''} ] };
-  push @ { $form->{WAREHOUSES} }, $no_default_bin_entry;
-  if (my $max = scalar @{ $form->{WAREHOUSES} }) {
-    my ($default_warehouse_id, $default_bin_id);
-    if ($form->{action} eq 'add') { # default only for new entries
-      $default_warehouse_id = $::instance_conf->get_warehouse_id;
-      $default_bin_id       = $::instance_conf->get_bin_id;
-    }
-    $form->{warehouse_id} ||= $default_warehouse_id || $form->{WAREHOUSES}->[$max -1]->{id};
-    $form->{bin_id}       ||= $default_bin_id       ||  $form->{WAREHOUSES}->[$max -1]->{BINS}->[0]->{id};
-  }
-
-  $form->{LANGUAGES}        = SL::DB::Manager::Language->get_all_sorted;
-  $form->{translations_map} = { map { ($_->{language_id} => $_) } @{ $form->{translations} || [] } };
-
-  IC->retrieve_buchungsgruppen(\%myconfig, $form);
-  @{ $form->{BUCHUNGSGRUPPEN} } = grep { $_->{id} eq $form->{buchungsgruppen_id} || ($form->{id} && $form->{orphaned}) || !$form->{id} } @{ $form->{BUCHUNGSGRUPPEN} };
-
-  if (($form->{partnumber} ne '') && !SL::TransNumber->new(number => $form->{partnumber}, type => $form->{item}, id => $form->{id})->is_unique) {
-    flash('info', $::locale->text('This partnumber is not unique. You should change it.'));
-  }
-
-  my $units = AM->retrieve_units(\%myconfig, $form);
-  $form->{ALL_UNITS} = [ map +{ name => $_ }, sort { $units->{$a}{sortkey} <=> $units->{$b}{sortkey} } keys %$units ];
-
-  $form->{defaults} = AM->get_defaults();
-
-  $form->{CUSTOM_VARIABLES} = CVar->get_custom_variables('module' => 'IC', 'trans_id' => $form->{id});
-
-  my ($null, $partsgroup_id) = split /--/, $form->{partsgroup};
-
-  CVar->render_inputs('variables' => $form->{CUSTOM_VARIABLES}, show_disabled_message => 1, partsgroup_id => $partsgroup_id)
-    if (scalar @{ $form->{CUSTOM_VARIABLES} });
-
-  $::request->layout->use_javascript("${_}.js") for qw(ckeditor/ckeditor ckeditor/adapters/jquery kivi.PriceRule);
-  $::request->layout->add_javascripts_inline("\$(function(){kivi.PriceRule.load_price_rules_for_part(@{[ $::form->{id} * 1 ]})});") if $::form->{id};
-  $form->header;
-  #print $form->parse_html_template('ic/form_header', { ALL_PRICE_FACTORS => $form->{ALL_PRICE_FACTORS},
-  #                                                     ALL_UNITS         => $form->{ALL_UNITS},
-  #                                                     BUCHUNGSGRUPPEN   => $form->{BUCHUNGSGRUPPEN},
-  #                                                     payment_terms     => $form->{payment_terms},
-  #                                                     all_partsgroup    => $form->{all_partsgroup}});
-
-  $form->{show_edit_buttons} = $main::auth->check_right($::myconfig{login}, 'part_service_assembly_edit');
-
-  print $form->parse_html_template('ic/form_header');
-  $lxdebug->leave_sub();
-}
-
-sub form_footer {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_details');
-
-  print $form->parse_html_template('ic/form_footer');
-
-  $lxdebug->leave_sub();
-}
-
-sub makemodel_row {
-  $lxdebug->enter_sub();
-  my ($numrows) = @_;
-  #hli
-  my @mm_data = grep { any { $_ ne '' } @$_{qw(make model)} } map +{ make => $form->{"make_$_"}, model => $form->{"model_$_"}, lastcost => $form->{"lastcost_$_"}, lastupdate => $form->{"lastupdate_$_"}, sortorder => $form->{"sortorder_$_"} }, 1 .. $numrows;
-  delete @{$form}{grep { m/^make_\d+/ || m/^model_\d+/ } keys %{ $form }};
-  print $form->parse_html_template('ic/makemodel', { MM_DATA => [ @mm_data, {} ], mm_rows => scalar @mm_data + 1 });
-
-  $lxdebug->leave_sub();
-}
-
-sub assembly_row {
-  $lxdebug->enter_sub();
-  my ($numrows) = @_;
-  my (@column_index);
-  my ($nochange, $callback, $previousform, $linetotal, $line_purchase_price, $href);
-
-  @column_index = qw(runningnumber qty unit bom partnumber description partsgroup lastcost total);
-
-  if ($form->{previousform}) {
-    $nochange     = 1;
-    @column_index = qw(qty unit bom partnumber description partsgroup total);
-  } else {
-
-    # change callback
-    $form->{old_callback} = $form->{callback};
-    $callback             = $form->{callback};
-    $form->{callback}     = "$form->{script}?action=display_form";
-
-    # delete action
-    map { delete $form->{$_} } qw(action header);
-
-    # save form variables in a previousform variable
-    my %form_to_save = map   { ($_ => m/^ (?: listprice | sellprice | lastcost ) $/x ? $form->format_amount(\%myconfig, $form->{$_}) : $form->{$_}) }
-                       keys %{ $form };
-    $previousform    = $::auth->save_form_in_session(form => \%form_to_save);
-
-    $form->{callback} = $callback;
-    $form->{assemblytotal} = 0;
-    $form->{assembly_purchase_price_total} = 0;
-    $form->{weight}        = 0;
-  }
-
-  my %header = (
-   runningnumber => { text =>  $locale->text('No.'),              nowrap => 1, width => '5%',  align => 'left',},
-   qty           => { text =>  $locale->text('Qty'),              nowrap => 1, width => '10%', align => 'left',},
-   unit          => { text =>  $locale->text('Unit'),             nowrap => 1, width => '5%',  align => 'left',},
-   partnumber    => { text =>  $locale->text('Part Number'),      nowrap => 1, width => '20%', align => 'left',},
-   description   => { text =>  $locale->text('Part Description'), nowrap => 1, width => '50%', align => 'left',},
-   lastcost      => { text =>  $locale->text('Purchase Prices'),  nowrap => 1, width => '50%', align => 'right',},
-   total         => { text =>  $locale->text('Sale Prices'),      nowrap => 1,                 align => 'right',},
-   bom           => { text =>  $locale->text('BOM'),                                           align => 'center',},
-   partsgroup    => { text =>  $locale->text('Group'),                                         align => 'left',},
-  );
-
-  my @ROWS;
-
-  for my $i (1 .. $numrows) {
-    my (%row, @row_hiddens);
-
-    $form->{"partnumber_$i"} =~ s/\"/&quot;/g;
-
-    $linetotal           = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / ($form->{"price_factor_$i"} || 1), 4);
-    $line_purchase_price = $form->round_amount($form->{"lastcost_$i"} *  $form->{"qty_$i"} / ($form->{"price_factor_$i"} || 1), 4);
-    $form->{assemblytotal}                  += $linetotal;
-    $form->{assembly_purchase_price_total}  += $line_purchase_price;
-    $form->{"qty_$i"}    = $form->format_amount(\%myconfig, $form->{"qty_$i"});
-    $linetotal           = $form->format_amount(\%myconfig, $linetotal, 2);
-    $line_purchase_price = $form->format_amount(\%myconfig, $line_purchase_price, 2);
-    $href                = build_std_url("action=edit", qq|id=$form->{"id_$i"}|, "rowcount=$numrows", "currow=$i", "previousform=$previousform");
-    map { $row{$_}{data} = "" } qw(qty unit partnumber description bom partsgroup runningnumber);
-
-    # last row
-    if (($i >= 1) && ($i == $numrows)) {
-      if (!$form->{previousform}) {
-        $row{partnumber}{data}  = qq|<input name="partnumber_$i" size=15 value="$form->{"partnumber_$i"}">|;
-        $row{qty}{data}         = qq|<input name="qty_$i" size=5 value="$form->{"qty_$i"}">|;
-        $row{description}{data} = qq|<input name="description_$i" size=40 value="$form->{"description_$i"}">|;
-        $row{partsgroup}{data}  = qq|<input name="partsgroup_$i" size=10 value="$form->{"partsgroup_$i"}">|;
-      }
-    # other rows
-    } else {
-      if ($form->{previousform}) {
-        push @row_hiddens,          qw(qty bom);
-        $row{partnumber}{data}    = $form->{"partnumber_$i"};
-        $row{qty}{data}           = $form->{"qty_$i"};
-        $row{bom}{data}           = $form->{"bom_$i"} ? "x" : "&nbsp;";
-        $row{qty}{align}          = 'right';
-      } else {
-        $row{partnumber}{data}    = qq|$form->{"partnumber_$i"}|;
-        $row{partnumber}{link}     = $href;
-        $row{qty}{data}           = qq|<input name="qty_$i" size=5 value="$form->{"qty_$i"}">|;
-        $row{runningnumber}{data} = qq|<input name="runningnumber_$i" size=3 value="$i">|;
-        $row{bom}{data}   = sprintf qq|<input name="bom_$i" type=checkbox class=checkbox value=1 %s>|,
-                                       $form->{"bom_$i"} ? 'checked' : '';
-      }
-      push @row_hiddens,        qw(unit description partnumber partsgroup);
-      $row{unit}{data}        = $form->{"unit_$i"};
-      #Bei der Artikelbeschreibung und Warengruppe können Sonderzeichen verwendet
-      #werden, die den HTML Code stören. Daher sollen diese im Template escaped werden
-      #dies geschieht, wenn die Variable escape gesetzt ist
-      $row{description}{data}   = $form->{"description_$i"};
-      $row{description}{escape} = 1;
-      $row{partsgroup}{data}    = $form->{"partsgroup_$i"};
-      $row{partsgroup}{escape}  = 1;
-      $row{bom}{align}          = 'center';
-    }
-
-    $row{lastcost}{data}      = $line_purchase_price;
-    $row{total}{data}         = $linetotal;
-    $row{lastcost}{align}     = 'right';
-    $row{total}{align}        = 'right';
-    $row{deliverydate}{align} = 'right';
-
-    push @row_hiddens, qw(id sellprice lastcost weight price_factor_id price_factor);
-    $row{hiddens} = [ map +{ name => "${_}_$i", value => $form->{"${_}_$i"} }, @row_hiddens ];
-
-    push @ROWS, \%row;
-  }
-
-  print $form->parse_html_template('ic/assembly_row', { COLUMNS => \@column_index, ROWS => \@ROWS, HEADER => \%header });
-
-  $lxdebug->leave_sub();
-}
-
-sub update {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_edit');
-
-  # update checks whether pricegroups, makemodels or assembly items have been changed/added
-  # new items might have been added (and the original form might have been stored and restored)
-  # so at the end the ic form is run through check_form in io.pl
-  # The various combination of events can lead to problems with the order of parse_amount and format_amount
-  # Currently check_form parses some variables in assembly mode, but not in article or service mode
-  # This will only ever really be sanely resolved with a rewrite...
-
-  # parse pricegroups. and no, don't rely on check_form for this...
-  map { $form->{"price_$_"} = $form->parse_amount(\%myconfig, $form->{"price_$_"}) } 1 .. $form->{price_rows};
-
-  unless ($form->{item} eq 'assembly') {
-    # for assemblies check_form will parse sellprice and listprice, but not for parts or services
-    $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) for qw(sellprice listprice ve gv);
-  };
-
-  if ($form->{item} eq 'part') {
-    $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) for qw(weight rop);
-  }
-
-  # same for makemodel lastcosts
-  # but parse_amount not necessary for assembly component lastcosts
-  unless ($form->{item} eq "assembly") {
-    map { $form->{"lastcost_$_"} = $form->parse_amount(\%myconfig, $form->{"lastcost_$_"}) } 1 .. $form->{"makemodel_rows"};
-    $form->{lastcost} = $form->parse_amount(\%myconfig, $form->{lastcost});
-  }
-
-  if ($form->{item} eq "assembly") {
-    my $i = $form->{assembly_rows};
-
-    # if last row is empty check the form otherwise retrieve item
-    if (   ($form->{"partnumber_$i"} eq "")
-        && ($form->{"description_$i"} eq "")
-        && ($form->{"partsgroup_$i"}  eq "")) {
-      # no new assembly item was added
-
-      &check_form;
-
-    } else {
-      # search db for newly added assemblyitems, via partnumber or description
-      IC->assembly_item(\%myconfig, \%$form);
-
-      # form->{item_list} contains the possible matches, next check whether the
-      # match is unique or we need to call the page to select the item
-      my $rows = scalar @{ $form->{item_list} };
-
-      if ($rows) {
-        $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
-
-        if ($rows > 1) {
-          $form->{makemodel_rows}--;
-          select_item(mode => 'IC', pre_entered_qty => $form->parse_amount(\%myconfig, $form->{"qty_$i"}));
-          $::dispatcher->end_request;
-        } else {
-          map { $form->{item_list}[$i]{$_} =~ s/\"/&quot;/g }
-            qw(partnumber description unit partsgroup);
-          map { $form->{"${_}_$i"} = $form->{item_list}[0]{$_} }
-            keys %{ $form->{item_list}[0] };
-          $form->{"runningnumber_$i"} = $form->{assembly_rows};
-          $form->{assembly_rows}++;
-
-          &check_form;
-
-        }
-
-      } else {
-
-        $form->{rowcount} = $i;
-        $form->{assembly_rows}++;
-
-        &new_item;
-
-      }
-    }
-
-  } elsif (($form->{item} eq 'part') || ($form->{item} eq 'service')) {
-    &check_form;
-  }
-
-  $lxdebug->leave_sub();
-}
-
-sub save {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_edit');
-  $::form->mtime_ischanged('parts');
-  my ($parts_id, %newform, $amount, $callback);
-
-  # check if there is a part number - commented out, cause there is an automatic allocation of numbers
-  # $form->isblank("partnumber", $locale->text(ucfirst $form->{item}." Part Number missing!"));
-
-  # check if there is a description
-  $form->isblank("description", $locale->text("Part Description missing!"));
-
-  $form->error($locale->text("Inventory quantity must be zero before you can set this $form->{item} obsolete!"))
-    if $form->{obsolete} && $form->{onhand} * 1 && $form->{item} ne 'service';
-
-  if (!$form->{buchungsgruppen_id}) {
-    $form->error($locale->text("Parts must have an entry type.") . " " .
-     $locale->text("If you see this message, you most likely just setup your LX-Office and haven't added any entry types. If this is the case, the option is accessible for administrators in the System menu.")
-    );
-  }
-
-  $form->error($locale->text('Description must not be empty!')) unless $form->{description};
-  $form->error($locale->text('Partnumber must not be set to empty!')) if $form->{id} && !$form->{partnumber};
-
-  # undef warehouse_id if the empty value is selected
-  if ( ($form->{warehouse_id} == 0) && ($form->{bin_id} == 0) ) {
-    undef $form->{warehouse_id};
-    undef $form->{bin_id};
-  }
-  # save part
-  if (IC->save(\%myconfig, \%$form) == 3) {
-    $form->error($locale->text('Partnumber not unique!'));
-  }
-  # saving the history
-  if(!exists $form->{addition}) {
-    $form->{snumbers}  = qq|partnumber_| . $form->{partnumber};
-    $form->{what_done} = "part";
-    $form->{addition}  = "SAVED";
-    $form->save_history;
-  }
-  # /saving the history
-  $parts_id = $form->{id};
-
-  my $i;
-  # load previous variables
-  if ($form->{previousform}) {
-
-    # save the new form variables before splitting previousform
-    map { $newform{$_} = $form->{$_} } keys %$form;
-
-    # don't trample on previous variables
-    map { delete $form->{$_} } keys %newform;
-
-    my $ic_cvar_configs = CVar->get_configs(module => 'IC');
-    my @ic_cvar_fields  = map { "cvar_$_->{name}" } @{ $ic_cvar_configs };
-
-    # restore original values
-    $::auth->restore_form_from_session($newform{previousform}, form => $form);
-    $form->{taxaccounts} = $newform{taxaccount2};
-
-    if ($form->{item} eq 'assembly') {
-
-      # undo number formatting
-      map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) }
-        qw(weight listprice sellprice rop);
-
-      $form->{assembly_rows}--;
-      if ($newform{currow}) {
-        $i = $newform{currow};
-      } else {
-        $i = $form->{assembly_rows};
-      }
-      $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"} > 0);
-
-      $form->{sellprice} -= $form->{"sellprice_$i"} * $form->{"qty_$i"};
-      $form->{weight}    -= $form->{"weight_$i"} * $form->{"qty_$i"};
-
-      # change/add values for assembly item
-      map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit weight listprice sellprice inventory_accno income_accno expense_accno price_factor_id);
-      map { $form->{"ic_${_}_$i"} = $newform{$_} } @ic_cvar_fields;
-
-      # das ist __voll__ bekloppt, dass so auszurechnen jb 22.5.09
-      #$form->{sellprice} += $form->{"sellprice_$i"} * $form->{"qty_$i"};
-      $form->{weight}    += $form->{"weight_$i"} * $form->{"qty_$i"};
-
-    } else {
-
-      # set values for last invoice/order item
-      $i = $form->{rowcount};
-      $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"} > 0);
-
-      map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit listprice inventory_accno income_accno expense_accno sellprice lastcost price_factor_id);
-      map { $form->{"ic_${_}_$i"} = $newform{$_} } @ic_cvar_fields;
-
-      $form->{"longdescription_$i"} = $newform{notes};
-
-      $form->{"sellprice_$i"} = $newform{lastcost} if ($form->{vendor_id});
-
-      if ($form->{exchangerate} != 0) {
-        $form->{"sellprice_$i"} /= $form->{exchangerate};
-      }
-
-      map { $form->{"taxaccounts_$i"} .= "$_ " } split / /, $newform{taxaccount};
-      chop $form->{"taxaccounts_$i"};
-      foreach my $item (qw(description rate taxnumber)) {
-        my $index = $form->{"taxaccounts_$i"} . "_$item";
-        $form->{$index} = $newform{$index};
-      }
-
-      # credit remaining calculation
-      $amount = $form->{"sellprice_$i"} * (1 - $form->{"discount_$i"} / 100) * $form->{"qty_$i"};
-
-      map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"});
-      map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
-
-      $form->{creditremaining} -= $amount;
-
-      # redo number formatting, because invoice parse them!
-      map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}) } qw(weight listprice sellprice lastcost rop);
-    }
-
-    $form->{"id_$i"} = $parts_id;
-
-    # Get the actual price factor (not just the ID) for the marge calculation.
-    $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
-    foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
-      next if ($pfac->{id} != $newform{price_factor_id});
-      $form->{"marge_price_factor_$i"} = $pfac->{factor};
-      last;
-    }
-    delete $form->{ALL_PRICE_FACTORS};
-
-    delete $form->{action};
-
-    # restore original callback
-    $callback = $form->unescape($form->{callback});
-    $form->{callback} = $form->unescape($form->{old_callback});
-    delete $form->{old_callback};
-
-    $form->{makemodel_rows}--;
-
-    # put callback together
-    foreach my $key (keys %$form) {
-
-      # do single escape for Apache 2.0
-      my $value = $form->escape($form->{$key}, 1);
-      $callback .= qq|&$key=$value|;
-    }
-    $form->{callback} = $callback;
-  }
-
-  # redirect
-  $form->redirect;
-
-  $lxdebug->leave_sub();
-}
-
-sub save_as_new {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_edit');
-
-  # saving the history
-  if(!exists $form->{addition}) {
-    $form->{snumbers}  = qq|partnumber_| . $form->{partnumber};
-    $form->{addition}  = "SAVED AS NEW";
-    $form->{what_done} = "part";
-    $form->save_history;
-  }
-  # /saving the history
-  $form->{id} = 0;
-  if ($form->{"original_partnumber"} &&
-      ($form->{"partnumber"} eq $form->{"original_partnumber"})) {
-    $form->{partnumber} = "";
-  }
-  &save;
-  $lxdebug->leave_sub();
-}
-
-sub delete {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_edit');
-
-  # saving the history
-  if(!exists $form->{addition}) {
-    $form->{snumbers}  = qq|partnumber_| . $form->{partnumber};
-    $form->{addition}  = "DELETED";
-    $form->{what_done} = "part";
-    $form->save_history;
-  }
-  # /saving the history
-  my $rc = IC->delete(\%myconfig, \%$form);
-
-  # redirect
-  $form->redirect($locale->text('Item deleted!')) if ($rc > 0);
-  $form->error($locale->text('Cannot delete item!'));
-
-  $lxdebug->leave_sub();
-}
-
-sub price_row {
-  $lxdebug->enter_sub();
-
-  $auth->assert('part_service_assembly_details');
-
-  my ($numrows) = @_;
-
-  my @PRICES = map +{
-    pricegroup    => $form->{"pricegroup_$_"},
-    pricegroup_id => $form->{"pricegroup_id_$_"},
-    price         => $form->{"price_$_"},
-  }, 1 .. $numrows;
-
-  print $form->parse_html_template('ic/price_row', { PRICES => \@PRICES });
-
-  $lxdebug->leave_sub();
-}
-
-sub ajax_autocomplete {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-  my %myconfig = %main::myconfig;
-
-  $form->{column}          = 'description'     unless $form->{column} =~ /^partnumber|description$/;
-  $form->{$form->{column}} = $form->{q}           || '';
-  $form->{limit}           = ($form->{limit} * 1) || 10;
-  $form->{searchitems}   ||= '';
-
-  my @results = IC->all_parts(\%myconfig, $form);
-
-  print $form->ajax_response_header(),
-        $form->parse_html_template('ic/ajax_autocomplete');
-
-  $main::lxdebug->leave_sub();
-}
-
-sub display_form {
-  $::lxdebug->enter_sub;
-
-  $auth->assert('part_service_assembly_edit');
-
-  relink_accounts();
-
-  $::form->language_payment(\%::myconfig);
-
-  Common::webdav_folder($::form);
-
-  form_header();
-  price_row($::form->{price_rows});
-  makemodel_row(++$::form->{makemodel_rows}) if $::form->{item} =~ /^(part|service)$/;
-  assembly_row(++$::form->{assembly_rows})   if $::form->{item} eq 'assembly';
-
-  form_footer();
-
-  $::lxdebug->leave_sub;
-}
-
-sub back_to_record {
-  _check_io_auth();
-
-
-  delete @{$::form}{qw(action action_add action_back_to_record back_sub description item notes partnumber sellprice taxaccount2 unit vc)};
-
-  $::auth->restore_form_from_session($::form->{previousform}, clobber => 1);
-  $::form->{rowcount}--;
-  $::form->{action}   = 'display_form';
-  $::form->{callback} = $::form->{script} . '?' . join('&', map { $::form->escape($_) . '=' . $::form->escape($::form->{$_}) } sort keys %{ $::form });
-  $::form->redirect;
-}
-
 sub continue { call_sub($form->{"nextsub"}); }
-
-sub dispatcher {
-  my $action = first { $::form->{"action_${_}"} } qw(add back_to_record);
-  $::form->error($::locale->text('No action defined.')) unless $action;
-
-  $::form->{dispatched_action} = $action;
-  call_sub($action);
-}