]> wagnertech.de Git - kivitendo-erp.git/commitdiff
CSV-Import: Fix für reflexive Spaltennamen im Mapping
authorMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 18 Dec 2017 12:07:28 +0000 (13:07 +0100)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 18 Dec 2017 12:37:21 +0000 (13:37 +0100)
Wenn eine CSV-Datei für den Bank-Import z.B. die Spalten `currency`,
`amount`, `local_bank_number` enthalten, so schlug der Import aus
gleich zwei Gründen fehl, wenn in der CSV-Spaten-Zuordnung die Namen
alle auf sich selber abgebildet wurden, also `current` → `currency`,
`amount` → `amount` und `local_bank_number` → `local_bank_number`.

Untersuchung ergab die folgenden zwei Probleme:

1. Fehlermeldung `cannot bind reference`
2. Fehlermeldung `can't locate object method "local_bank_number" via
   package "SL::DB::BankTransaction"`

Es stellte sich heraus, dass beim Speichern der CSV-Spalten in der
Datenbank hier kivitendo gedacht hat, dass diese drei genannten
Spalten auch als Methoden auf den DB-Objekt aufrufbar wären.

Sind sie aber nicht.

Schuld war der Mechanismus, der anhand der vorhandenen
Spaltennamen-Zuordnungen (`$mapping`) und dem vorhandenen
Spaltenprofil (`$profile`) entschieden hat, welche Namen als Methoden
anzuerkennen.

Im konkreten Fall ist es so, dass es sowohl ein solches Mapping als
auch ein solches Profil gibt. In dem Fall darf aber ein Name, der zwar
als Mapping existiert, dessen gemappter Name aber im Profil nicht
existiert, auch nicht als Methodenname aufgefasst und in die `$specs`
aufgenommen werden. Statt dessen muss er als »unbekannte Spalte«
behandelt werden.

SL/Helper/Csv/Dispatcher.pm
t/helper/csv.t

index 418c184dfa90a9d858343d306f044ee20f879dd0..801e8229f2bfb2d997376bde3c7383306119c4d8 100644 (file)
@@ -130,7 +130,7 @@ sub parse_profile {
 sub _parse_profile {
   my ($self, %params) = @_;
 
-  my $profile = $params{profile};
+  my $profile = $params{profile} // {};
   my $class   = $params{class};
   my $header  = $params{header};
   my $mapping = $params{mapping};
@@ -141,7 +141,7 @@ sub _parse_profile {
     next unless $col;
     if (exists $mapping->{$col} && $profile->{$mapping->{$col}}) {
       push @specs, $self->make_spec($col, $profile->{$mapping->{$col}}, $class);
-    } elsif (exists $mapping->{$col}) {
+    } elsif (exists $mapping->{$col} && !%{ $profile }) {
       push @specs, $self->make_spec($col, $mapping->{$col}, $class);
     } elsif (exists $profile->{$col}) {
       push @specs, $self->make_spec($col, $profile->{$col}, $class);
index 99da3d38d466df451a1e0b0ac7540d59b90219b0..e3247263d1327ad70db22722d55fd1cdb5f004c3 100644 (file)
@@ -1,4 +1,4 @@
-use Test::More tests => 84;
+use Test::More tests => 86;
 
 use lib 't';
 use utf8;
@@ -809,9 +809,33 @@ $csv->parse;
 is $csv->get_objects->[0]->sellprice, 4.99, 'case insensitive mapping with profile works';
 
 
+# self-mapping with profile
+$csv = SL::Helper::Csv->new(
+  file   => \"sellprice\n4,99",        # " # make emacs happy
+  case_insensitive_header => 1,
+  profile => [{
+    profile => { sellprice => 'sellprice_as_number' },
+    mapping => { sellprice => 'sellprice' },
+    class  => 'SL::DB::Part',
+  }],
+);
+$csv->parse;
+is $csv->get_objects->[0]->sellprice, 4.99, 'self-mapping with profile works';
+
+# self-mapping without profile
+$csv = SL::Helper::Csv->new(
+  file   => \"sellprice\n4.99",        # " # make emacs happy
+  case_insensitive_header => 1,
+  profile => [{
+    mapping => { sellprice => 'sellprice' },
+    class  => 'SL::DB::Part',
+  }],
+);
+$csv->parse;
+is $csv->get_objects->[0]->sellprice, 4.99, 'self-mapping without profile works';
+
 # vim: ft=perl
 # set emacs to perl mode
 # Local Variables:
 # mode: perl
 # End:
-