commit 7942a6ac9cfc05130a69c2b632367d4983fb94a3
Author: Moritz Bunkus <m.bunkus@linet.de>
Date:   Wed May 20 15:38:49 2009 +0000

    Bessere Abfragen und (Fehler-)Meldungen bei Preisupdates.
    
    Fix für Bugs 480.

diff --git a/SL/IC.pm b/SL/IC.pm
index 44b21ec62..75e3191eb 100644
--- a/SL/IC.pm
+++ b/SL/IC.pm
@@ -997,51 +997,35 @@ sub all_parts {
   $main::lxdebug->leave_sub();
 }
 
-sub update_prices {
+sub _create_filter_for_priceupdate {
   $main::lxdebug->enter_sub();
 
-  my ($self, $myconfig, $form) = @_;
+  my $self     = shift;
+  my $myconfig = \%main::myconfig;
+  my $form     = $main::form;
+
   my @where_values;
   my $where = '1 = 1';
-  my $var;
 
-  my $group;
-  my $limit;
+  foreach my $item (qw(partnumber drawing microfiche make model pg.partsgroup)) {
+    my $column = $item;
+    $column =~ s/.*\.//;
+    next unless ($form->{$column});
 
-  if ($item ne 'make') {
-    foreach my $item (qw(partnumber drawing microfiche make model pg.partsgroup)) {
-      my $column = $item;
-      $column =~ s/.*\.//;
-      next unless ($form->{$column});
-      $where .= qq| AND $item ILIKE ?|;
-      push(@where_values, '%' . $form->{$column} . '%');
-    }
+    $where .= qq| AND $item ILIKE ?|;
+    push(@where_values, '%' . $form->{$column} . '%');
   }
 
-  # special case for description
-  if ($form->{description}
-      && !(   $form->{bought}  || $form->{sold} || $form->{onorder}
-           || $form->{ordered} || $form->{rfq} || $form->{quoted})) {
-    $where .= qq| AND (p.description ILIKE ?)|;
-    push(@where_values, '%' . $form->{description} . '%');
-  }
+  foreach my $item (qw(description serialnumber)) {
+    next unless ($form->{$item});
 
-  # special case for serialnumber
-  if ($form->{l_serialnumber} && $form->{serialnumber}) {
-    $where .= qq| AND serialnumber ILIKE ?|;
-    push(@where_values, '%' . $form->{serialnumber} . '%');
+    $where .= qq| AND (${item} ILIKE ?)|;
+    push(@where_values, '%' . $form->{$item} . '%');
   }
 
 
   # items which were never bought, sold or on an order
   if ($form->{itemstatus} eq 'orphaned') {
-    $form->{onhand}  = $form->{short}   = 0;
-    $form->{bought}  = $form->{sold}    = 0;
-    $form->{onorder} = $form->{ordered} = 0;
-    $form->{rfq}     = $form->{quoted}  = 0;
-
-    $form->{transdatefrom} = $form->{transdateto} = "";
-
     $where .=
       qq| AND (p.onhand = 0)
           AND p.id NOT IN
@@ -1052,23 +1036,19 @@ sub update_prices {
               UNION
               SELECT DISTINCT parts_id FROM orderitems
             )|;
-  }
 
-  if ($form->{itemstatus} eq 'active') {
+  } elsif ($form->{itemstatus} eq 'active') {
     $where .= qq| AND p.obsolete = '0'|;
-  }
 
-  if ($form->{itemstatus} eq 'obsolete') {
+  } elsif ($form->{itemstatus} eq 'obsolete') {
     $where .= qq| AND p.obsolete = '1'|;
-    $form->{onhand} = $form->{short} = 0;
-  }
 
-  if ($form->{itemstatus} eq 'onhand') {
+  } elsif ($form->{itemstatus} eq 'onhand') {
     $where .= qq| AND p.onhand > 0|;
-  }
 
-  if ($form->{itemstatus} eq 'short') {
+  } elsif ($form->{itemstatus} eq 'short') {
     $where .= qq| AND p.onhand < p.rop|;
+
   }
 
   foreach my $column (qw(make model)) {
@@ -1077,6 +1057,72 @@ sub update_prices {
     push(@where_values, '%' . $form->{$column} . '%');
   }
 
+  $main::lxdebug->leave_sub();
+
+  return ($where, @where_values);
+}
+
+sub get_num_matches_for_priceupdate {
+  $main::lxdebug->enter_sub();
+
+  my $self     = shift;
+
+  my $myconfig = \%main::myconfig;
+  my $form     = $main::form;
+
+  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
+
+  my ($where, @where_values) = $self->_create_filter_for_priceupdate();
+
+  my $num_updated = 0;
+  my $query;
+
+  for my $column (qw(sellprice listprice)) {
+    next if ($form->{$column} eq "");
+
+    $query =
+      qq|SELECT COUNT(*)
+         FROM parts
+         WHERE id IN
+           (SELECT p.id
+            FROM parts p
+            LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+            WHERE $where)|;
+    my ($result)  = selectfirst_array_query($from, $dbh, $query, @where_values);
+    $num_updated += $result if (0 <= $result);
+  }
+
+  $query =
+    qq|SELECT COUNT(*)
+       FROM prices
+       WHERE parts_id IN
+         (SELECT p.id
+          FROM parts p
+          LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
+          WHERE $where) AND (pricegroup_id = ?)|;
+  my $sth = prepare_query($form, $dbh, $query);
+
+  for my $i (1 .. $form->{price_rows}) {
+    next if ($form->{"price_$i"} eq "");
+
+    my ($result)  = do_statement($form, $sth, $query, @where_values, conv_i($form->{"pricegroup_id_$i"}));
+    $num_updated += $result if (0 <= $result);
+  }
+  $sth->finish();
+
+  $main::lxdebug->leave_sub();
+
+  return $num_updated;
+}
+
+sub update_prices {
+  $main::lxdebug->enter_sub();
+
+  my ($self, $myconfig, $form) = @_;
+
+  my ($where, @where_values) = $self->_create_filter_for_priceupdate();
+  my $num_updated = 0;
+
   # connect to database
   my $dbh = $form->dbconnect_noauto($myconfig);
 
@@ -1098,7 +1144,8 @@ sub update_prices {
             FROM parts p
             LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
             WHERE $where)|;
-    do_query($from, $dbh, $query, $value, @where_values);
+    my $result    = do_query($from, $dbh, $query, $value, @where_values);
+    $num_updated += $result if (0 <= $result);
   }
 
   my $q_add =
@@ -1123,12 +1170,15 @@ sub update_prices {
     next if ($form->{"price_$i"} eq "");
 
     my $value = $form->parse_amount($myconfig, $form->{"price_$i"});
+    my $result;
 
     if ($form->{"pricegroup_type_$i"} eq "percent") {
-      do_statement($form, $sth_multiply, $q_multiply, ($value / 100) + 1, @where_values, conv_i($form->{"pricegroup_id_$i"}));
+      $result = do_statement($form, $sth_multiply, $q_multiply, ($value / 100) + 1, @where_values, conv_i($form->{"pricegroup_id_$i"}));
     } else {
-      do_statement($form, $sth_add, $q_add, $value, @where_values, conv_i($form->{"pricegroup_id_$i"}));
+      $result = do_statement($form, $sth_add, $q_add, $value, @where_values, conv_i($form->{"pricegroup_id_$i"}));
     }
+
+    $num_updated += $result if (0 <= $result);
   }
 
   $sth_add->finish();
@@ -1139,7 +1189,7 @@ sub update_prices {
 
   $main::lxdebug->leave_sub();
 
-  return $rc;
+  return $num_updated;
 }
 
 sub create_links {
diff --git a/bin/mozilla/ic.pl b/bin/mozilla/ic.pl
index 87c4f0177..325d01ec4 100644
--- a/bin/mozilla/ic.pl
+++ b/bin/mozilla/ic.pl
@@ -131,12 +131,42 @@ sub confirm_price_update {
 
   $auth->assert('part_service_assembly_edit');
 
+  my @errors      = ();
+  my $value_found = false;
+
+  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();
 }
@@ -146,8 +176,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!'));
   }
diff --git a/locale/de/all b/locale/de/all
index 4efbb10cc..8450cb793 100644
--- a/locale/de/all
+++ b/locale/de/all
@@ -9,6 +9,7 @@ $self->{texts} = {
   ' Date missing!'              => ' Datum fehlt!',
   ' Part Number missing!'       => ' Artikelnummer fehlt!',
   ' missing!'                   => ' fehlt!',
+  '#1 prices were updated.'     => '#1 Preise wurden aktualisiert.',
   '&lt;%account_number%&gt; -- Your account number' => '&lt;%account_number%&gt; -- Ihre Kontonummer',
   '&lt;%bank%&gt; -- Your bank' => '&lt;%bank%&gt; -- Der Name Ihrer Bank',
   '&lt;%bank_code%&gt; -- Your bank code' => '&lt;%bank_code%&gt; -- Die Bankleitzahl Ihrer Bank',
@@ -176,6 +177,7 @@ $self->{texts} = {
   'Application Error. No Format given' => 'Fehler in der Anwendung. Das Ausgabeformat fehlt.',
   'Application Error. Wrong Format' => 'Fehler in der Anwendung. Falsches Format: ',
   'Applying [% HTML.escape(file) %]:' => 'F&uuml;hre [% HTML.escape(file) %] aus:',
+  'Approximately #1 prices will be updated.' => 'Ungef�hr #1 Preise werden aktualisiert.',
   'Apr'                         => 'Apr',
   'April'                       => 'April',
   'Ar aging on %s'              => 'Offene Forderungen zum %s',
@@ -185,7 +187,7 @@ $self->{texts} = {
   'Are you sure you want to delete Quotation Number' => 'Sind Sie sicher, dass Angebotnummer gel�scht werden soll?',
   'Are you sure you want to delete Transaction' => 'Buchung wirklich l�schen?',
   'Are you sure you want to remove the marked entries from the queue?' => 'Sind Sie sicher, dass die markierten Eintr�ge von der Warteschlange gel�scht werden sollen?',
-  'Are you sure you want to update the prices' => 'Sind Sie sicher, dass Sie die Preise aktualisieren wollen?',
+  'Are you sure you want to update the prices' => 'Sind Sie sicher, dass Sie die Preise aktualisieren wollen',
   'Article Code'                => 'Artikelk�rzel',
   'Article Code missing!'       => 'Artikelk�rzel fehlt',
   'As a result, the saved onhand values of the present goods can be stored into a warehouse designated by you, or will be reset for a proper warehouse tracking' => 'Als Konsequenz k&ouml;nnen die gespeicherten Mengen entweder in ein Lager &uuml;berf&uuml;hrt werden, oder f&uuml;r eine frische Lagerverwaltung resettet werden.',
@@ -996,9 +998,11 @@ $self->{texts} = {
   'No licenses were found that match the search criteria.' => 'Es wurden keine Lizenzen gefunden, auf die die Suchkriterien zutreffen.',
   'No or an unknown authenticantion module specified in "config/authentication.pl".' => 'Es wurde kein oder ein unbekanntes Authentifizierungsmodul in "config/authentication.pl" angegeben.',
   'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
+  'No prices will be updated because no prices have been entered.' => 'Es werden keine Preise aktualisiert, weil keine g�ltigen Preis�nderungen eingegeben wurden.',
   'No problems were recognized.' => 'Es wurden keine Probleme gefunden.',
   'No unknown units where found.' => 'Es wurden keine unbekannten Einheiten gefunden.',
   'No user has been selected.'  => 'Es wurde kein Benutzer ausgew&auml;hlt.',
+  'No valid number entered for pricegroup "#1".' => 'F�r Preisgruppe "#1" wurde keine g�ltige Nummer eingegeben.',
   'No vendor has been selected yet.' => 'Es wurde noch kein Lieferant ausgew�hlt.',
   'No warehouse has been created yet or the quantity of the bins is not configured yet.' => 'Es wurde noch kein Lager angelegt, bzw. die dazugehörigen Lagerplätze sind noch nicht konfiguriert.',
   'No.'                         => 'Position',
@@ -1737,6 +1741,7 @@ $self->{texts} = {
   'You can either create a new database or chose an existing database.' => 'Sie k�nnen entweder eine neue Datenbank erstellen oder eine existierende ausw�hlen.',
   'You can only delete datasets that are not in use.' => 'Sie k&ouml;nnen nur Datenbanken l&ouml;schen, die momentan nicht in Benutzung sind.',
   'You can use the following strings in the long description and all translations. They will be replaced by their actual values by Lx-Office before they\'re output.' => 'Sie k&ouml;nnen im Langtext und allen �bersetzungen die folgenden Variablen benutzen, die vor der Ausgabe von Lx-Office automatisch ersetzt werden:',
+  'You cannot adjust the price for pricegroup "#1" by a negative percentage.' => 'Sie k�nnen den Preis f�r Preisgruppe "#1" um einen negativen Prozentwert anpassen.',
   'You cannot continue before all required modules are installed.' => 'Sie k&ouml;nnen nicht fortfahren, bevor alle ben&ouml;tigten Pakete installiert sind.',
   'You cannot continue until all unknown units have been mapped to known ones.' => 'Sie k&ouml;nnen nicht fortfahren, bis alle unbekannten Einheiten in neue Einheiten umgewandelt wurden.',
   'You cannot create an invoice for delivery orders for different customers.' => 'Sie k�nnen keine Rechnung zu Lieferscheinen f�r verschiedene Kunden erstellen.',
@@ -1841,7 +1846,6 @@ $self->{texts} = {
   'pos_eur'                     => 'E/�R',
   'pos_ustva'                   => 'UStVA',
   'posted!'                     => 'gebucht',
-  'prices updated!'             => ' Preise aktualisiert!',
   'print'                       => 'drucken',
   'proforma'                    => 'Proforma',
   'project_list'                => 'projektliste',
diff --git a/locale/de/ic b/locale/de/ic
index a43079e28..d6ded510b 100644
--- a/locale/de/ic
+++ b/locale/de/ic
@@ -3,6 +3,7 @@
 $self->{texts} = {
   ' Date missing!'              => ' Datum fehlt!',
   ' Part Number missing!'       => ' Artikelnummer fehlt!',
+  '#1 prices were updated.'     => '#1 Preise wurden aktualisiert.',
   '*/'                          => '*/',
   'A temporary file could not be created. Please verify that the directory "#1" is writeable by the webserver.' => 'Eine tempor�re Datei konnte nicht angelegt werden. Bitte stellen Sie sicher, dass das Verzeichnis "#1" vom Webserver beschrieben werden darf.',
   'ADDED'                       => 'Hinzugef�gt',
@@ -172,6 +173,8 @@ $self->{texts} = {
   'No customer has been selected yet.' => 'Es wurde noch kein Kunde ausgew�hlt.',
   'No or an unknown authenticantion module specified in "config/authentication.pl".' => 'Es wurde kein oder ein unbekanntes Authentifizierungsmodul in "config/authentication.pl" angegeben.',
   'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
+  'No prices will be updated because no prices have been entered.' => 'Es werden keine Preise aktualisiert, weil keine g�ltigen Preis�nderungen eingegeben wurden.',
+  'No valid number entered for pricegroup "#1".' => 'F�r Preisgruppe "#1" wurde keine g�ltige Nummer eingegeben.',
   'No vendor has been selected yet.' => 'Es wurde noch kein Lieferant ausgew�hlt.',
   'No.'                         => 'Position',
   'Nov'                         => 'Nov',
@@ -303,6 +306,7 @@ $self->{texts} = {
   'Warehouse management'        => 'Lagerverwaltung/Bestandsver�nderung',
   'Weight'                      => 'Gewicht',
   'Yes'                         => 'Ja',
+  'You cannot adjust the price for pricegroup "#1" by a negative percentage.' => 'Sie k�nnen den Preis f�r Preisgruppe "#1" um einen negativen Prozentwert anpassen.',
   'You do not have the permissions to access this function.' => 'Sie verf&uuml;gen nicht &uuml;ber die notwendigen Rechte, um auf diese Funktion zuzugreifen.',
   'Your PostgreSQL installationen uses UTF-8 as its encoding. Therefore you have to configure Lx-Office to use UTF-8 as well.' => 'Ihre PostgreSQL-Installation benutzt UTF-8 als Zeichensatz. Sie m�ssen deshalb Lx-Office so konfigurieren, dass es ebenfalls UTF-8 als Zeichensatz benutzt.',
   'Zipcode'                     => 'PLZ',
@@ -326,7 +330,6 @@ $self->{texts} = {
   'packing_list'                => 'Versandliste',
   'part_list'                   => 'warenliste',
   'pick_list'                   => 'Entnahmeliste',
-  'prices updated!'             => ' Preise aktualisiert!',
   'proforma'                    => 'Proforma',
   'purchase_order'              => 'Auftrag',
   'report_generator_dispatch_to is not defined.' => 'report_generator_dispatch_to ist nicht definiert.',
diff --git a/templates/webpages/ic/confirm_price_update_de.html b/templates/webpages/ic/confirm_price_update_de.html
index adee0c2f4..a8d8cdde7 100644
--- a/templates/webpages/ic/confirm_price_update_de.html
+++ b/templates/webpages/ic/confirm_price_update_de.html
@@ -10,7 +10,11 @@
 
   <h2 class="confirm">Best�tigen Sie!</h2>
 
-  <h4>Sind Sie sicher, dass Sie die Preise aktualisieren wollen?</h4>
+  <p>
+   [% LxERP.format_string('Ungef�hr #1 Preise werden aktualisiert.', num_matches) %]
+  </p>
+
+  <p>Sind Sie sicher, dass Sie die Preise aktualisieren wollen?</p>
 
   <p>
    <input name="action" class="submit" type="submit" value="Weiter">
diff --git a/templates/webpages/ic/confirm_price_update_master.html b/templates/webpages/ic/confirm_price_update_master.html
index afbecf331..03f814d59 100644
--- a/templates/webpages/ic/confirm_price_update_master.html
+++ b/templates/webpages/ic/confirm_price_update_master.html
@@ -10,7 +10,11 @@
 
   <h2 class="confirm"><translate>Confirm!</translate></h2>
 
-  <h4><translate>Are you sure you want to update the prices</translate></h4>
+  <p>
+   [% LxERP.format_string('<translate>Approximately #1 prices will be updated.</translate>', num_matches) %]
+  </p>
+
+  <p><translate>Are you sure you want to update the prices</translate>?</p>
 
   <p>
    <input name="action" class="submit" type="submit" value="<translate>Continue</translate>">
