CsvImport Waren: Preisupdate auch bei Erzeugnissen u. Dienstleistungen ermöglichen.
authorBernd Bleßmann <bernd@kivitendo-premium.de>
Wed, 14 May 2014 14:13:40 +0000 (16:13 +0200)
committerBernd Bleßmann <bernd@kivitendo-premium.de>
Wed, 14 May 2014 14:54:01 +0000 (16:54 +0200)
Zusätzlich beim Preisupdate prüfen, ob vorhandene Artikel von einem anderen Typ
als angegeben sind, falls in der CSV-Datei angegeben.

Problem war, dass Artikelnummern jetzt über Waren, Dienstleistungen und
Erzeugnisse eindeutig sind. Um aber schon vorhandene Artikel zu finden,
wurde nur nach dem angegenbenen oder eingestellten Typ gesucht. Der
voreingestellte Typ ist Waren, dabei werden Dienstleistungen und Erzeugnisse
nicht gefunden und es wurde versucht, den entspr. Eintrag neu als Ware
anzulegen, allerdings ist die Artikelnummer ja schon vergeben und es kam zu
einem DB-Fehler.

SL/Controller/CsvImport/Part.pm
locale/de/all
locale/en/all
templates/webpages/csv_import/form.html

index 8b9cb13..34bdd73 100644 (file)
@@ -16,6 +16,8 @@ use SL::DB::Price;
 use SL::DB::Translation;
 use SL::DB::Unit;
 
+use List::MoreUtils qw(none);
+
 use parent qw(SL::Controller::CsvImport::Base);
 
 use Rose::Object::MakeMethods::Generic
@@ -204,31 +206,35 @@ sub check_existing {
   my $object = $entry->{object};
 
   if ($object->partnumber && $self->parts_by->{partnumber}{$object->partnumber}) {
-    $entry->{part} = SL::DB::Manager::Part->find_by(
-      SL::DB::Manager::Part->type_filter($object->type),
-      ( partnumber => $object->partnumber )                 x!! $object->partnumber,
-    );
+    $entry->{part} = SL::DB::Manager::Part->find_by(partnumber => $object->partnumber);
   }
 
   if ($entry->{part}) {
     if ($self->settings->{article_number_policy} eq 'update_prices') {
-      map { $entry->{part}->$_( $object->$_ ) if defined $object->$_ } qw(sellprice listprice lastcost);
+      if ($self->settings->{parts_type} eq 'mixed' && $entry->{part}->type ne $object->type) {
+        push(@{$entry->{errors}}, $::locale->text('Skipping due to existing entry in database with different type'));
+      } else {
+        map { $entry->{part}->$_( $object->$_ ) if defined $object->$_ } qw(sellprice listprice lastcost);
 
-      # merge prices
-      my %prices_by_pricegroup_id = map { $_->pricegroup->id => $_ } $entry->{part}->prices, $object->prices;
-      $entry->{part}->prices(grep { $_ } map { $prices_by_pricegroup_id{$_->id} } @{ $self->all_pricegroups });
+        # merge prices
+        my %prices_by_pricegroup_id = map { $_->pricegroup->id => $_ } $entry->{part}->prices, $object->prices;
+        $entry->{part}->prices(grep { $_ } map { $prices_by_pricegroup_id{$_->id} } @{ $self->all_pricegroups });
 
-      push @{ $entry->{information} }, $::locale->text('Updating prices of existing entry in database');
-      $entry->{object_to_save} = $entry->{part};
+        push @{ $entry->{information} }, $::locale->text('Updating prices of existing entry in database');
+        $entry->{object_to_save} = $entry->{part};
+      }
     } elsif ( $self->settings->{article_number_policy} eq 'skip' ) {
       push(@{$entry->{errors}}, $::locale->text('Skipping due to existing entry in database'));
+
     } else {
       $object->partnumber('####');
+      push(@{$entry->{errors}}, $::locale->text('Skipping, for assemblies are not importable (yet)')) if $object->type eq 'assembly';
     }
+  } else {
+    push(@{$entry->{errors}}, $::locale->text('Skipping, for assemblies are not importable (yet)')) if $object->type eq 'assembly';
   }
 }
 
-
 sub handle_prices {
   my ($self, $entry) = @_;
 
@@ -258,16 +264,24 @@ sub check_type {
   if ($type eq 'mixed') {
     $type = $entry->{raw_data}->{type} =~ m/^p/i ? 'part'
           : $entry->{raw_data}->{type} =~ m/^s/i ? 'service'
+          : $entry->{raw_data}->{type} =~ m/^a/i ? 'assembly'
           :                                        undef;
   }
 
-  $entry->{object}->income_accno_id(  $bg->income_accno_id_0 );
-  $entry->{object}->expense_accno_id( $bg->expense_accno_id_0 );
+  $entry->{object}->assembly($type eq 'assembly');
+
+  $entry->{object}->income_accno_id( $bg->income_accno_id_0 );
+
+  if ($type eq 'part' || $type eq 'service') {
+    $entry->{object}->expense_accno_id( $bg->expense_accno_id_0 );
+  }
 
   if ($type eq 'part') {
     $entry->{object}->inventory_accno_id( $bg->inventory_accno_id );
+  }
+
 
-  } elsif ($type ne 'service') {
+  if (none { $_ eq $type } qw(part service assembly)) {
     push @{ $entry->{errors} }, $::locale->text('Error: Invalid part type');
     return 0;
   }
index 5fb5508..9c2a9fc 100755 (executable)
@@ -251,6 +251,7 @@ $self->{texts} = {
   'Article type'                => 'Artikeltyp',
   '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.',
   'Assemblies'                  => 'Erzeugnisse',
+  'Assemblies can not be imported (yet). But the type column is used for sanity checks on price updates in order to prevent that articles with the wrong type will be updated.' => 'Erzeugnisse können (noch) nicht importiert werden. Aber die Typ-Spalte wird für Plausibilitätsprüfungen bei Preisaktualisierungen verwendet, um zu verhindern, dass Artikel vom falschen Typ aktualisiert werden.',
   'Assembly'                    => 'Erzeugnis',
   'Assembly Description'        => 'Erzeugnis-Beschreibung',
   'Assembly Number'             => 'Erzeugnis-Nummer',
@@ -2151,6 +2152,8 @@ $self->{texts} = {
   'Skip'                        => 'Überspringen',
   'Skip entry'                  => 'Eintrag überspringen',
   'Skipping due to existing entry in database' => 'Wegen existierendem Eintrag mit selber Nummer übersprungen',
+  'Skipping due to existing entry in database with different type' => 'Wegen existierendem Eintrag von unterschiedlichem Artikeltyp übersprungen',
+  'Skipping, for assemblies are not importable (yet)' => 'Übersprungen, da Erzeugnisse (noch) nicht importiert werden können',
   'Skonto'                      => 'Skonto',
   'Skonto Terms'                => 'Zahlungsziel Skonto',
   'So far you could use one partnumber for severel parts, for example a service and an article.' => 'Bisher war es möglich eine Artikelnummer für mehrere Artikel zu verwenden, zum Beispiel eine Artikelnummer für eine Dienstleistung, eine Ware und ein Erzeugnis.',
@@ -2650,7 +2653,7 @@ $self->{texts} = {
   'Trial balance between %s and %s' => 'Summen- und Saldenlisten vom %s bis zum %s',
   'Trying to call a sub without a name' => 'Es wurde versucht, eine Unterfunktion ohne Namen aufzurufen.',
   'Type'                        => 'Typ',
-  'Type can be either \'part\' or \'service\'.' => 'Der Typ kann entweder \'part\' (für Waren) oder \'service\' (für Dienstleistungen) enthalten.',
+  'Type can be either \'part\', \'service\' or \'assembly\'.' => 'Der Typ kann entweder \'part\' (für Waren), \'service\' (für Dienstleistungen) oder \'assembly\' (für Erzeugnisse) enthalten.',
   'Type of Business'            => 'Kunden-/Lieferantentyp',
   'Type of Customer'            => 'Kundentyp',
   'Type of Vendor'              => 'Lieferantentyp',
index af1bf99..30a729a 100644 (file)
@@ -232,6 +232,7 @@ $self->{texts} = {
   'Article type'                => '',
   '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' => '',
   'Assemblies'                  => '',
+  'Assemblies can not be imported (yet). But the type column is used for sanity checks on price updates in order to prevent that articles with the wrong type will be updated.' => '',
   'Assembly'                    => '',
   'Assembly Description'        => '',
   'Assembly Number'             => '',
@@ -2345,7 +2346,7 @@ $self->{texts} = {
   'Trial balance between %s and %s' => '',
   'Trying to call a sub without a name' => '',
   'Type'                        => '',
-  'Type can be either \'part\' or \'service\'.' => '',
+  'Type can be either \'part\', \'service\' or \'assembly\'.' => '',
   'Type of Business'            => '',
   'Type of Customer'            => '',
   'Type of Vendor'              => '',
index cbe4977..24af07e 100644 (file)
    <p>
     [3]:
     [% LxERP.t8("If the article type is set to 'mixed' then a column called 'type' must be present.") %]
-    [% LxERP.t8("Type can be either 'part' or 'service'.") %]
+    [% LxERP.t8("Type can be either 'part', 'service' or 'assembly'.") %]
+    [% LxERP.t8("Assemblies can not be imported (yet). But the type column is used for sanity checks on price updates in order to prevent that articles with the wrong type will be updated.") %]
    </p>
 
 [%- ELSIF SELF.type == 'orders' %]