Merge branch 'master' of github.com:kivitendo/kivitendo-erp
[kivitendo-erp.git] / bin / mozilla / ic.pl
index 8c915f4..837b842 100644 (file)
@@ -38,6 +38,7 @@ use List::MoreUtils qw(any);
 use SL::AM;
 use SL::CVar;
 use SL::IC;
+use SL::Helper::Flash;
 use SL::ReportGenerator;
 
 #use SL::PE;
@@ -288,7 +289,6 @@ sub update_prices {
 #  $form->header;
 #
 #  print qq|
-#<body>
 #  <form method=post action=ic.pl>
 #    <table width=100%>
 #     <tr>
@@ -388,8 +388,6 @@ sub update_prices {
 #    . $locale->text('TOP100') . qq|">
 #
 #</form>
-#</body>
-#</html>
 #|;
 #  $lxdebug->leave_sub();
 #}    #end list()
@@ -725,8 +723,6 @@ sub addtop100 {
   my $colspan = $#column_index + 1;
 
   print qq|
-<body>
-
 <table width=100%>
   <tr>
     <th class=listtop colspan=$colspan>$form->{title}</th>
@@ -977,13 +973,10 @@ sub addtop100 {
   print qq|
 <!--    <input type=hidden name=ndxs_counter value="$form->{ndxs_counter}">-->
 
-    <input class=submit type=submit name=action value="|
-    . $locale->text('choice') . qq|">
+<!--    <input class=submit type=submit name=action value="|
+    . $locale->text('choice') . qq|"> -->
 
   </form>
-
-</body>
-</html>
 |;
 
   $lxdebug->leave_sub();
@@ -1010,7 +1003,7 @@ sub addtop100 {
 #  bought sold onorder ordered rfq quoted
 #  l_partnumber l_description l_serialnumber l_unit l_listprice l_sellprice l_lastcost
 #  l_linetotal l_priceupdate l_bin l_rop l_weight l_image l_drawing l_microfiche
-#  l_partsgroup l_subtotal l_soldtotal l_deliverydate
+#  l_partsgroup l_subtotal l_soldtotal l_deliverydate l_pricegroups
 #
 # hiddens:
 #  nextsub revers lastsort sort ndxs_counter
@@ -1032,6 +1025,7 @@ sub generate_report {
     'bin'                => { 'text' => $locale->text('Bin'), },
     'deliverydate'       => { 'text' => $locale->text('deliverydate'), },
     'description'        => { 'text' => $locale->text('Part Description'), },
+    'notes'              => { 'text' => $locale->text('Notes'), },
     'drawing'            => { 'text' => $locale->text('Drawing'), },
     'ean'                => { 'text' => $locale->text('EAN'), },
     'image'              => { 'text' => $locale->text('Image'), },
@@ -1056,6 +1050,8 @@ sub generate_report {
     'transdate'          => { 'text' => $locale->text('Transdate'), },
     'unit'               => { 'text' => $locale->text('Unit'), },
     'weight'             => { 'text' => $locale->text('Weight'), },
+    'projectnumber'      => { 'text' => $locale->text('Project Number'), },
+    'projectdescription' => { 'text' => $locale->text('Project Description'), },
   );
 
   $revers     = $form->{revers};
@@ -1136,7 +1132,7 @@ sub generate_report {
     model         => $locale->text('Model')            . ": '$form->{model}'",
     drawing       => $locale->text('Drawing')          . ": '$form->{drawing}'",
     microfiche    => $locale->text('Microfiche')       . ": '$form->{microfiche}'",
-    l_soldtotal   => $locale->text('soldtotal'),
+    l_soldtotal   => $locale->text('Qty in Selected Records'),
     ean           => $locale->text('EAN')              . ": '$form->{ean}'",
   );
 
@@ -1171,7 +1167,7 @@ sub generate_report {
   }
 
   if ($form->{l_linetotal}) {
-    $form->{l_onhand} = "Y";
+    $form->{l_qty} = "Y";
     $form->{l_linetotalsellprice} = "Y" if $form->{l_sellprice};
     $form->{l_linetotallastcost}  = $form->{searchitems} eq 'assembly' && !$form->{bom} ? "" : 'Y' if  $form->{l_lastcost};
     $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
@@ -1191,34 +1187,66 @@ sub generate_report {
         || $form->{ordered}
         || $form->{rfq}
         || $form->{quoted}) {
-      $form->{l_onhand} = "Y";
+#      $form->{l_onhand} = "Y";
     } else {
       $form->{l_linetotalsellprice} = "";
       $form->{l_linetotallastcost}  = "";
     }
   }
 
+  # soldtotal doesn't make sense with more than one bsooqr option.
+  # so reset it to sold (the most common option), and issue a warning
+  my @bsooqr = qw(sold bought onorder ordered rfq quoted);
+  if ($form->{l_subtotal} && 1 < grep { $form->{$_} } @bsooqr) {
+    my $enabled       = first { $form->{$_} } @bsooqr;
+    $form->{$_}       = ''   for @bsooqr;
+    $form->{$enabled} = 'Y';
+
+    push @options, $::locale->text('Subtotal cannot distinguish betweens record types. Only one of the selected record types will be displayed: #1', $optiontexts{$enabled});
+  }
+
   IC->all_parts(\%myconfig, \%$form);
 
   my @columns = qw(
-    partnumber description partsgroup bin onhand rop soldtotal unit listprice
+    partnumber 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
+    transdate name serialnumber deliverydate ean projectnumber projectdescription
   );
 
+  my $pricegroups = SL::DB::Manager::Pricegroup->get_all(sort => 'id');
+  my @pricegroup_columns;
+  my %column_defs_pricegroups;
+  if ($form->{l_pricegroups}) {
+    @pricegroup_columns      = map { "pricegroup_" . $_->id } @{ $pricegroups };
+    %column_defs_pricegroups = map {
+      "pricegroup_" . $_->id => {
+        text    => $::locale->text('Pricegroup') . ' ' . $_->pricegroup,
+        visible => 1,
+      },
+    }  @{ $pricegroups };
+  }
+  push @columns, @pricegroup_columns;
+
   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;
 
-  %column_defs = (%column_defs,%column_defs_cvars); # nochmal die cvars als überschrift hinzufügen
-    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);
+  %column_defs = (%column_defs, %column_defs_cvars, %column_defs_pricegroups);
+  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), @pricegroup_columns;
+
+  my @hidden_variables = (
+    qw(l_subtotal l_linetotal searchitems itemstatus bom l_pricegroups),
+    @itemstatus_keys,
+    @callback_keys,
+    map({ "cvar_$_->{name}" } @searchable_custom_variables),
+    map({'cvar_'. $_->{name} .'_qtyop'} grep({$_->{type} eq 'number'} @searchable_custom_variables)),
+    map({ "l_$_" } @columns),
+  );
 
-  my @hidden_variables = (qw(l_subtotal l_linetotal searchitems itemstatus bom), @itemstatus_keys, @callback_keys,
-                              map({ "cvar_$_->{name}" } @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);
@@ -1290,12 +1318,12 @@ sub generate_report {
     $ref->{lastcost}      *= $ref->{exchangerate} / $ref->{price_factor};
 
     # use this for assemblies
-    my $onhand = $ref->{onhand};
+    my $soldtotal = $ref->{soldtotal};
 
     if ($ref->{assemblyitem}) {
       $row->{partnumber}{align}   = 'right';
-      $row->{onhand}{data}        = 0;
-      $onhand                     = 0 if ($form->{sold});
+      $row->{soldtotal}{data}     = 0;
+      $soldtotal                  = 0 if ($form->{sold});
     }
 
     my $edit_link               = build_std_url('action=edit', 'id=' . E($ref->{id}), 'callback');
@@ -1303,9 +1331,13 @@ sub generate_report {
     $row->{description}->{link} = $edit_link;
 
     foreach (qw(sellprice listprice lastcost)) {
-      $row->{$_}{data}            = $form->format_amount(\%myconfig, $ref->{$_}, -2);
+      $row->{$_}{data}            = $form->format_amount(\%myconfig, $ref->{$_}, 2);
       $row->{"linetotal$_"}{data} = $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{$_}, 2);
     }
+    foreach ( @pricegroup_columns ) {
+      $row->{$_}{data}            = $form->format_amount(\%myconfig, $ref->{"$_"}, 2);
+    };
+
 
     map { $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}); } qw(onhand rop weight soldtotal);
 
@@ -1313,18 +1345,25 @@ sub generate_report {
 
     if (!$ref->{assemblyitem}) {
       foreach my $col (@subtotal_columns) {
-        $totals{$col}    += $onhand * $ref->{$col};
-        $subtotals{$col} += $onhand * $ref->{$col};
+        $totals{$col}    += $soldtotal * $ref->{$col};
+        $subtotals{$col} += $soldtotal * $ref->{$col};
       }
 
-      $subtotals{onhand} += $onhand;
+      $subtotals{soldtotal} += $soldtotal;
     }
 
     # set module stuff
     if ($ref->{module} eq 'oe') {
-      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});
+      # für oe gibt es vier fälle, jeweils nach kunde oder lieferant unterschiedlich:
+      #
+      # | ist bestellt  | Vom Kunde bestellt |  -> edit_oe_ord_link
+      # | Anfrage       | Angebot            |  -> edit_oe_quo_link
+
+      my $edit_oe_ord_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');
+      my $edit_oe_quo_link = build_std_url("script=oe.pl", 'action=edit', 'type=' . E($ref->{cv} eq 'vendor' ? 'request_quotation' : 'sales_quotation'), 'id=' . E($ref->{trans_id}), 'callback');
+
+      $row->{ordnumber}{link} = $edit_oe_ord_link;
+      $row->{quonumber}{link} = $edit_oe_quo_link if (!$ref->{ordnumber});
 
     } else {
       $row->{invnumber}{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'type=invoice', 'id=' . E($ref->{trans_id}), 'callback');
@@ -1348,11 +1387,11 @@ sub generate_report {
       my $row = { map { $_ => { 'class' => 'listsubtotal', } } @columns };
 
       if (($form->{searchitems} ne 'assembly') || !$form->{bom}) {
-        $row->{onhand}->{data} = $form->format_amount(\%myconfig, $subtotals{onhand});
+        $row->{soldtotal}->{data} = $form->format_amount(\%myconfig, $subtotals{soldtotal});
       }
 
       map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $subtotals{$_}, 2) } @subtotal_columns;
-      map { $subtotals{$_} = 0 } ('onhand', @subtotal_columns);
+      map { $subtotals{$_} = 0 } ('soldtotal', @subtotal_columns);
 
       $report->add_data($row);
 
@@ -1362,7 +1401,7 @@ sub generate_report {
     $idx++;
   }
 
-  if ($form->{"l_linetotal"}) {
+  if ($form->{"l_linetotal"} && !$form->{report_generator_csv_options_for_import}) {
     my $row = { map { $_ => { 'class' => 'listtotal', } } @columns };
 
     map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $totals{$_}, 2) } @subtotal_columns;
@@ -1450,8 +1489,7 @@ sub link_part {
   IC->create_links("IC", \%myconfig, \%$form);
 
   # currencies
-  map({ $form->{selectcurrency} .= "<option>$_\n" }
-      split(/:/, $form->{currencies}));
+  map({ $form->{selectcurrency} .= "<option>$_\n" } $::form->get_all_currencies());
 
   # parts and assemblies have the same links
   my $item = $form->{item};
@@ -1547,12 +1585,31 @@ sub form_header {
 
   $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
                    'partsgroup'    => 'all_partsgroup',
-                   'vendors'       => 'ALL_VENDORS',);
+                   '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_default_warehouse_id;
+      $default_bin_id       = $::instance_conf->get_default_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};
+  }
 
 
   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.'));
+  }
+
   # use JavaScript Calendar or not (yes!)
   $form->{jsscript} = 1;
 
@@ -1561,7 +1618,7 @@ sub form_header {
 
   $form->{defaults} = AM->get_defaults();
 
-  $form->{fokus} = "ic.partnumber";
+  $::request->{layout}->focus("#partnumber");
 
   $form->{CUSTOM_VARIABLES} = CVar->get_custom_variables('module' => 'IC', 'trans_id' => $form->{id});
 
@@ -1632,15 +1689,15 @@ sub assembly_row {
   }
 
   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'),                                        },
+   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;
@@ -1657,7 +1714,7 @@ sub assembly_row {
     $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|;
+    $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
@@ -1677,7 +1734,8 @@ sub assembly_row {
         $row{bom}{data}           = $form->{"bom_$i"} ? "x" : "&nbsp;";
         $row{qty}{align}          = 'right';
       } else {
-        $row{partnumber}{data}    = qq|<a href=$href>$form->{"partnumber_$i"}</a>|;
+        $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>|,
@@ -1685,9 +1743,14 @@ sub assembly_row {
       }
       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';
+      #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;
@@ -1712,9 +1775,14 @@ sub update {
 
   # 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};
+  $form->{sellprice} = $form->parse_amount(\%myconfig, $form->{sellprice});
 
-  # same for lastcosts
-  map { $form->{"lastcost_$_"} = $form->parse_amount(\%myconfig, $form->{"lastcost_$_"}) } 1 .. $form->{"makemodel_rows"};
+  # 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->{listprice} = $form->parse_amount(\%myconfig, $form->{listprice});
 
   if ($form->{item} eq "assembly") {
     my $i = $form->{assembly_rows};
@@ -1793,8 +1861,12 @@ sub save {
   $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
-  $lxdebug->message($LXDebug::DEBUG1, "ic.pl: sellprice in save = $form->{sellprice}\n");
   if (IC->save(\%myconfig, \%$form) == 3) {
     $form->error($locale->text('Partnumber not unique!'));
   }
@@ -1831,7 +1903,11 @@ sub save {
         qw(weight listprice sellprice rop);
 
       $form->{assembly_rows}--;
-      $i = $newform{rowcount};
+      if ($newform{currow}) {
+        $i = $newform{currow};
+      } else {
+        $i = $form->{assembly_rows};
+      }
       $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
 
       $form->{sellprice} -= $form->{"sellprice_$i"} * $form->{"qty_$i"};
@@ -1862,8 +1938,6 @@ sub save {
         $form->{"sellprice_$i"} /= $form->{exchangerate};
       }
 
-      $lxdebug->message($LXDebug::DEBUG1, qq|sellprice_$i in previousform 2 = | . $form->{"sellprice_$i"} . qq|\n|);
-
       map { $form->{"taxaccounts_$i"} .= "$_ " } split / /, $newform{taxaccount};
       chop $form->{"taxaccounts_$i"};
       foreach my $item (qw(description rate taxnumber)) {
@@ -1912,7 +1986,6 @@ sub save {
     }
     $form->{callback} = $callback;
   }
-  $lxdebug->message($LXDebug::DEBUG1, qq|ic.pl: sellprice_$i nach sub save = | . $form->{"sellprice_$i"} . qq|\n|);
 
   # redirect
   $form->redirect;
@@ -1996,6 +2069,10 @@ sub parts_language_selection {
 
         $language->{translation}     = $translation;
         $language->{longdescription} = $longdescription;
+
+        $language->{translation_area}     = ($language->{translation_rows} = $form->numtextrows($language->{translation}, 40)) > 1;
+        $language->{longdescription_rows} = max 4, $form->numtextrows($language->{longdescription}, 40);
+
         last;
       }
     }
@@ -2042,6 +2119,9 @@ sub ajax_autocomplete {
 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';