Nicht abgfangene Typenkonvertierung in ca.pl
[kivitendo-erp.git] / bin / mozilla / ic.pl
index 5f16184..3042403 100644 (file)
 
 use POSIX qw(strftime);
 use List::Util qw(max);
+use List::MoreUtils qw(any);
 
+use SL::AM;
+use SL::CVar;
 use SL::IC;
 use SL::ReportGenerator;
 
 #use SL::PE;
 
-use strict;
+use strict;
 #use warnings;
 
 # global imports
-our ($form, $locale, %myconfig, $lxdebug);
+our ($form, $locale, %myconfig, $lxdebug, $auth);
 
 require "bin/mozilla/io.pl";
 require "bin/mozilla/invoice_io.pl";
@@ -99,10 +102,16 @@ sub search {
 
   $form->{title} = (ucfirst $form->{searchitems}) . "s";
   $form->{title} = $locale->text($form->{title});
-  $form->{title} = $locale->text('Assemblies') if ($is_xyz{assembly});
+  $form->{title} = $locale->text('Assemblies') if ($is_xyz{is_assembly});
 
   $form->{jsscript} = 1;
 
+  $form->{CUSTOM_VARIABLES}                  = CVar->get_configs('module' => 'IC');
+  ($form->{CUSTOM_VARIABLES_FILTER_CODE},
+   $form->{CUSTOM_VARIABLES_INCLUSION_CODE}) = CVar->render_search_options('variables'      => $form->{CUSTOM_VARIABLES},
+                                                                           'include_prefix' => 'l_',
+                                                                           'include_value'  => 'Y');
+
   $form->header;
 
   print $form->parse_html_template('ic/search', { %is_xyz,
@@ -130,12 +139,42 @@ sub confirm_price_update {
 
   $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";
-  $form->header;
 
   map { delete $form->{$_} } qw(action header);
 
-  print $form->parse_html_template('ic/confirm_price_update', { HIDDENS => [ map { name => $_, value => $form->{$_} }, keys %$form ] });
+  print $form->parse_html_template('ic/confirm_price_update', { HIDDENS     => [ map { name => $_, value => $form->{$_} }, keys %$form ],
+                                                                num_matches => $num_matches });
 
   $lxdebug->leave_sub();
 }
@@ -145,8 +184,10 @@ sub update_prices {
 
   $auth->assert('part_service_assembly_edit');
 
-  if (IC->update_prices(\%myconfig, \%$form)) {
-    $form->redirect($form->{update_count} . $locale->text('prices updated!'));
+  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!'));
   }
@@ -574,9 +615,6 @@ sub addtop100 {
     }
   }
 
-  $form->{l_lastcost} = ""
-    if ($form->{searchitems} eq 'assembly' && !$form->{bom});
-
   foreach my $item (@columns) {
     if ($form->{"l_$item"} eq "Y") {
       push @column_index, $item;
@@ -979,12 +1017,14 @@ sub generate_report {
 
   my ($revers, $lastsort, $description);
 
+  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});
 
-  my $revers     = $form->{revers};
-  my $lastsort   = $form->{lastsort};
+  $revers     = $form->{revers};
+  $lastsort   = $form->{lastsort};
 
   # sorting and direction of sorting
   # ToDO: change this to the simpler field+direction method
@@ -1114,14 +1154,18 @@ sub generate_report {
     }
   }
 
-  $form->{l_lastcost} = "" if ($form->{searchitems} eq 'assembly' && !$form->{bom});
-
   IC->all_parts(\%myconfig, \%$form);
 
   my @columns =
     qw(partnumber description partsgroup bin onhand rop unit listprice linetotallistprice sellprice linetotalsellprice lastcost linetotallastcost
        priceupdate weight image drawing microfiche invnumber ordnumber quonumber name serialnumber soldtotal deliverydate);
 
+  my @includeable_custom_variables = grep { $_->{includeable} } @{ $cvar_configs };
+  my @searchable_custom_variables  = grep { $_->{searchable} }  @{ $cvar_configs };
+  my %column_defs_cvars            = map { +"cvar_$_->{name}" => { 'text' => $_->{description} } } @includeable_custom_variables;
+
+  push @columns, map { "cvar_$_->{name}" } @includeable_custom_variables;
+
   my %column_defs = (
     'bin'                => { 'text' => $locale->text('Bin'), },
     'deliverydate'       => { 'text' => $locale->text('deliverydate'), },
@@ -1148,12 +1192,13 @@ sub generate_report {
     'soldtotal'          => { 'text' => $locale->text('soldtotal'), },
     'unit'               => { 'text' => $locale->text('Unit'), },
     'weight'             => { 'text' => $locale->text('Weight'), },
+    %column_defs_cvars,
   );
 
   map { $column_defs{$_}->{visible} = $form->{"l_$_"} ? 1 : 0 } @columns;
   map { $column_defs{$_}->{align}   = 'right' } qw(onhand sellprice listprice lastcost linetotalsellprice linetotallastcost linetotallistprice rop weight soldtotal);
 
-  my @hidden_variables = (qw(l_subtotal l_linetotal searchitems itemstatus bom), @itemstatus_keys, @callback_keys, map { "l_$_" } @columns);
+  my @hidden_variables = (qw(l_subtotal l_linetotal searchitems itemstatus bom), @itemstatus_keys, @callback_keys, @searchable_custom_variables, map { "l_$_" } @columns);
   my $callback         = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
 
   my @sort_full        = qw(partnumber description onhand soldtotal deliverydate);
@@ -1190,12 +1235,27 @@ sub generate_report {
 
   $report->set_sort_indicator($form->{sort}, $form->{revers} ? 0 : 1);
 
+  CVar->add_custom_variables_to_report('module'         => 'IC',
+                                       'trans_id_field' => 'id',
+                                       'configs'        => $cvar_configs,
+                                       'column_defs'    => \%column_defs,
+                                       'data'           => $form->{parts});
+
+  CVar->add_custom_variables_to_report('module'         => 'IC',
+                                       'sub_module'     => sub { $_[0]->{ioi} },
+                                       'trans_id_field' => 'ioi_id',
+                                       'configs'        => $cvar_configs,
+                                       'column_defs'    => \%column_defs,
+                                       'data'           => $form->{parts});
+
   my @subtotal_columns = qw(sellprice listprice lastcost);
   my %subtotals = map { $_ => 0 } ('onhand', @subtotal_columns);
   my %totals    = map { $_ => 0 } @subtotal_columns;
   my $idx       = 0;
   my $same_item = $form->{parts}[0]{ $form->{sort} } if (scalar @{ $form->{parts} });
 
+  my $defaults  = AM->get_defaults();
+
   # postprocess parts
   foreach my $ref (@{ $form->{parts} }) {
 
@@ -1228,6 +1288,8 @@ sub generate_report {
 
     map { $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}); } qw(onhand rop weight soldtotal);
 
+    $row->{weight}->{data} .= ' ' . $defaults->{weightunit};
+
     if (!$ref->{assemblyitem}) {
       foreach my $col (@subtotal_columns) {
         $totals{$col}    += $onhand * $ref->{$col};
@@ -1239,7 +1301,7 @@ sub generate_report {
 
     # set module stuff
     if ($ref->{module} eq 'oe') {
-      my $edit_oe_link = build_std_url("script=oe.pl", 'action=edit', 'type=' . E($ref->{customer_id} ne '' ? 'sales_order' : 'purchase_order'), 'id=' . E($ref->{trans_id}), 'callback');
+      my $edit_oe_link = build_std_url("script=oe.pl", 'action=edit', 'type=' . E($ref->{cv} eq 'vendor' ? 'purchase_order' : 'sales_order'), 'id=' . E($ref->{trans_id}), 'callback');
       $row->{ordnumber}{link} = $edit_oe_link;
       $row->{quonumber}{link} = $edit_oe_link if (!$ref->{ordnumber});
 
@@ -1455,7 +1517,7 @@ sub form_header {
 
   $auth->assert('part_service_assembly_edit');
 
-  $form->{eur}              = $eur; # config dumps into namespace - yuck
+  $form->{eur}              = $main::eur; # config dumps into namespace - yuck
   $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);
@@ -1464,7 +1526,9 @@ sub form_header {
   map { $form->{$_}       =~ s/"/&quot;/g;        } qw(unit);
 
   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
-                   'partsgroup'    => 'all_partsgroup');
+                   'partsgroup'    => 'all_partsgroup',
+                   'vendors'       => 'ALL_VENDORS',);
+
 
   IC->retrieve_buchungsgruppen(\%myconfig, $form);
   @{ $form->{BUCHUNGSGRUPPEN} } = grep { $_->{id} eq $form->{buchungsgruppen_id} || ($form->{id} && $form->{orphaned}) || !$form->{id} } @{ $form->{BUCHUNGSGRUPPEN} };
@@ -1472,17 +1536,25 @@ sub form_header {
   # use JavaScript Calendar or not (yes!)
   $form->{jsscript} = 1;
 
-  $units = AM->retrieve_units(\%myconfig, $form);
+  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->{fokus} = "ic.partnumber";
 
+  $form->{CUSTOM_VARIABLES} = CVar->get_custom_variables('module' => 'IC', 'trans_id' => $form->{id});
+
+  CVar->render_inputs('variables' => $form->{CUSTOM_VARIABLES}, show_disabled_message => 1)
+    if (scalar @{ $form->{CUSTOM_VARIABLES} });
+
   $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}});
+  #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}});
+  print $form->parse_html_template('ic/form_header');
   $lxdebug->leave_sub();
 }
 
@@ -1501,6 +1573,7 @@ sub makemodel_row {
   my ($numrows) = @_;
 
   my @mm_data = grep { any { $_ ne '' } @$_{qw(make model)} } map +{ make => $form->{"make_$_"}, model => $form->{"model_$_"} }, 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();
@@ -1509,13 +1582,12 @@ sub makemodel_row {
 sub assembly_row {
   $lxdebug->enter_sub();
   my ($numrows) = @_;
-  my (@column_index, %column_data, %column_header);
-  my ($nochange, $callback, $previousform, $linetotal, $href);
+  my (@column_index);
+  my ($nochange, $callback, $previousform, $linetotal, $line_purchase_price, $href);
 
-  our ($deliverydate); # ToDO: cjeck if this indeed comes from global context
+  our ($deliverydate); # ToDO: check if this indeed comes from global context
 
-  @column_index =
-    qw(runningnumber qty unit bom partnumber description partsgroup total);
+  @column_index = qw(runningnumber qty unit bom partnumber description partsgroup lastcost total);
 
   if ($form->{previousform}) {
     $nochange     = 1;
@@ -1530,149 +1602,90 @@ sub assembly_row {
     # delete action
     map { delete $form->{$_} } qw(action header);
 
-    $previousform = "";
-
     # save form variables in a previousform variable
-    foreach my $key (sort keys %$form) {
+    $previousform = $form->escape($form->escape(join '&', map {
+      sprintf "%s=%s", Q($_), /^listprice|lastcost|sellprice$/ ? $form->format_amount(\%myconfig, $form->{$_}) : $form->{$_}
+    } grep { ref $form->{$_} eq '' && $form->{$_} } grep { !/^select/ } sort keys %$form ));
 
-      # escape ampersands
-      $form->{$key} =~ s/&/%26/g;
-      $previousform .= qq|$key=$form->{$key}&|;
-    }
-    chop $previousform;
-    $previousform = $form->escape($form->escape($previousform, 1));
     $form->{callback} = $callback;
-
     $form->{assemblytotal} = 0;
+    $form->{assembly_purchase_price_total} = 0;
     $form->{weight}        = 0;
-
   }
-  $column_header{runningnumber} =
-    qq|<th nowrap width=5%>| . $locale->text('No.') . qq|</th>|;
-  $column_header{qty} =
-    qq|<th align=left nowrap width=10%>| . $locale->text('Qty') . qq|</th>|;
-  $column_header{unit} =
-    qq|<th align=left nowrap width=5%>| . $locale->text('Unit') . qq|</th>|;
-  $column_header{partnumber} =
-      qq|<th align=left nowrap width=20%>|
-    . $locale->text('Part Number')
-    . qq|</th>|;
-  $column_header{description} =
-    qq|<th nowrap width=50%>| . $locale->text('Part Description') . qq|</th>|;
-  $column_header{total} =
-    qq|<th align=right nowrap>| . $locale->text('Extended') . qq|</th>|;
-  $column_header{bom}        = qq|<th>| . $locale->text('BOM') . qq|</th>|;
-  $column_header{partsgroup} = qq|<th>| . $locale->text('Group') . qq|</th>|;
 
-  print qq|
-  <tr class=listheading>
-    <th class=listheading>| . $locale->text('Individual Items') . qq|</th>
-  </tr>
-  <tr>
-    <td>
-      <table width=100%>
-        <tr>
-|;
-
-  map { print "\n$column_header{$_}" } @column_index;
+  my %header = (
+   runningnumber => { text =>  $locale->text('No.'),              nowrap => 1, width => '5%'  },
+   qty           => { text =>  $locale->text('Qty'),              nowrap => 1, width => '10%' },
+   unit          => { text =>  $locale->text('Unit'),             nowrap => 1, width => '5%'  },
+   partnumber    => { text =>  $locale->text('Part Number'),      nowrap => 1, width => '20%' },
+   description   => { text =>  $locale->text('Part Description'), nowrap => 1, width => '50%' },
+   lastcost      => { text =>  $locale->text('Purchase Prices'),  nowrap => 1, width => '50%' },
+   total         => { text =>  $locale->text('Sale Prices'),      nowrap => 1,                },
+   bom           => { text =>  $locale->text('BOM'),                                          },
+   partsgroup    => { text =>  $locale->text('Group'),                                        },
+  );
 
-  print qq|
-        </tr>
-|;
+  my @ROWS;
 
   for my $i (1 .. $numrows) {
-    $form->{"partnumber_$i"} =~ s/\"/&quot;/g;
-
-    $linetotal =
-      $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
-    $form->{assemblytotal} += $linetotal;
-
-    $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+    my (%row, @row_hiddens);
 
-    $linetotal = $form->format_amount(\%myconfig, $linetotal, 2);
+    $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                = qq|$form->{script}?action=edit&id=$form->{"id_$i"}&rowcount=$i&previousform=$previousform|;
+    map { $row{$_}{data} = "" } qw(qty unit partnumber description bom partsgroup runningnumber);
+
+    # last row
     if (($i >= 1) && ($i == $numrows)) {
-
-      if ($nochange) {
-        map { $column_data{$_} = qq|<td></td>| }
-          qw(qty unit partnumber description bom partsgroup);
-      } else {
-
-        map { $column_data{$_} = qq|<td></td>| } qw(runningnumber unit bom);
-
-        $column_data{qty} =
-          qq|<td><input name="qty_$i" size=5 value="$form->{"qty_$i"}"></td>|;
-        $column_data{partnumber} =
-          qq|<td><input name="partnumber_$i" size=15 value="$form->{"partnumber_$i"}"></td>|;
-        $column_data{description} =
-          qq|<td><input name="description_$i" size=40 value="$form->{"description_$i"}"></td>|;
-        $column_data{partsgroup} =
-          qq|<td><input name="partsgroup_$i" size=10 value="$form->{"partsgroup_$i"}"></td>|;
-
+      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}) {
-        $column_data{partnumber} =
-          qq|<td><input type=hidden name="partnumber_$i" value="$form->{"partnumber_$i"}">$form->{"partnumber_$i"}</td>|;
-        $column_data{qty} =
-          qq|<td align=right><input type=hidden name="qty_$i" value="$form->{"qty_$i"}">$form->{"qty_$i"}</td>|;
-
-        $column_data{bom} =
-          qq|<td align=center><input type=hidden name="bom_$i" value=$form->{"bom_$i"}>|;
-        $column_data{bom} .= ($form->{"bom_$i"}) ? "x" : "&nbsp;";
-        $column_data{bom} .= qq|</td>|;
-
-        $column_data{partsgroup} =
-          qq|<td><input type=hidden name="partsgroup_$i" value="$form->{"partsgroup_$i"}">$form->{"partsgroup_$i"}</td>|;
-
+        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 {
-        $href =
-          qq|$form->{script}?action=edit&id=$form->{"id_$i"}&rowcount=$i&previousform=$previousform|;
-        $column_data{partnumber} =
-          qq|<td><input type=hidden name="partnumber_$i" value="$form->{"partnumber_$i"}"><a href=$href>$form->{"partnumber_$i"}</a></td>|;
-        $column_data{runningnumber} =
-          qq|<td><input name="runningnumber_$i" size=3 value="$i"></td>|;
-        $column_data{qty} =
-          qq|<td><input name="qty_$i" size=5 value="$form->{"qty_$i"}"></td>|;
-
-        $form->{"bom_$i"} = ($form->{"bom_$i"}) ? "checked" : "";
-        $column_data{bom} =
-          qq|<td align=center><input name="bom_$i" type=checkbox class=checkbox value=1 $form->{"bom_$i"}></td>|;
-
-        $column_data{partsgroup} =
-          qq|<td><input type=hidden name="partsgroup_$i" value="$form->{"partsgroup_$i"}">$form->{"partsgroup_$i"}</td>|;
+        $row{partnumber}{data}    = qq|<a href=$href>$form->{"partnumber_$i"}</a>|;
+        $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' : '';
       }
-
-      $column_data{unit} =
-        qq|<td><input type=hidden name="unit_$i" value="$form->{"unit_$i"}">$form->{"unit_$i"}</td>|;
-      $column_data{description} =
-        qq|<td><input type=hidden name="description_$i" value="$form->{"description_$i"}">$form->{"description_$i"}</td>|;
+      push @row_hiddens,        qw(unit description partnumber partsgroup);
+      $row{unit}{data}        = $form->{"unit_$i"};
+      $row{description}{data} = $form->{"description_$i"};
+      $row{partsgroup}{data}  = $form->{"partsgroup_$i"};
+      $row{bom}{align}        = 'center';
     }
 
-    $column_data{total} = qq|<td align=right>$linetotal</td>|;
-
-    $column_data{deliverydate} = qq|<td align=right>$deliverydate</td>|;
-
-    print qq|
-        <tr>|;
+    $row{lastcost}{data}      = $line_purchase_price;
+    $row{total}{data}         = $linetotal;
+    $row{deliverydate}{data}  = $deliverydate;
+    $row{lastcost}{align}     = 'right';
+    $row{total}{align}        = 'right';
+    $row{deliverydate}{align} = 'right';
 
-    map { print "\n$column_data{$_}" } @column_index;
+    push @row_hiddens, qw(id sellprice lastcost weight price_factor_id price_factor);
+    $row{hiddens} = [ map +{ name => "${_}_$i", value => $form->{"${_}_$i"} }, @row_hiddens ];
 
-    print qq|
-        </tr>
-  <input type=hidden name="id_$i" value=$form->{"id_$i"}>
-  <input type=hidden name="sellprice_$i" value=$form->{"sellprice_$i"}>
-  <input type=hidden name="weight_$i" value=$form->{"weight_$i"}>
-|;
+    push @ROWS, \%row;
   }
 
-  print qq|
-      </table>
-    </td>
-  </tr>
-|;
+  print $form->parse_html_template('ic/assembly_row', { COLUMNS => \@column_index, ROWS => \@ROWS, HEADER => \%header });
 
   $lxdebug->leave_sub();
 }
@@ -1680,6 +1693,9 @@ sub assembly_row {
 sub update {
   $lxdebug->enter_sub();
 
+  # 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};
+
   if ($form->{item} eq "assembly") {
     my $i = $form->{assembly_rows};
 
@@ -1745,13 +1761,8 @@ sub save {
   # check if there is a description
   $form->isblank("description", $locale->text("Part Description missing!"));
 
-  if ($form->{obsolete}) {
-    $form->error(
-      $locale->text(
-        "Inventory quantity must be zero before you can set this $form->{item} obsolete!"
-      ))
-      if ($form->{onhand} * 1);
-  }
+  $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.") . " " .
@@ -1788,6 +1799,9 @@ sub save {
     # 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 };
+
     # now take it apart and restore original values
     foreach my $item (split /&/, $previousform) {
       my ($key, $value) = split m/=/, $item, 2;
@@ -1811,8 +1825,10 @@ sub save {
 
       # 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;
 
-      $form->{sellprice} += $form->{"sellprice_$i"} * $form->{"qty_$i"};
+      # 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 {
@@ -1822,6 +1838,7 @@ sub save {
       $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
 
       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};
 
@@ -1954,12 +1971,12 @@ sub parts_language_selection {
 
   $auth->assert('part_service_assembly_edit');
 
-  our ($onload);
+  our ($onload, $callback);
 
   my $languages = IC->retrieve_languages(\%myconfig, $form);
 
   if ($form->{language_values} ne "") {
-    foreach $item (split(/---\+\+\+---/, $form->{language_values})) {
+    foreach my $item (split(/---\+\+\+---/, $form->{language_values})) {
       my ($language_id, $translation, $longdescription) = split(/--\+\+--/, $item);
 
       foreach my $language (@{ $languages }) {