OE: single-dbh
[kivitendo-erp.git] / SL / Controller / CsvImport.pm
index a177401..3122037 100644 (file)
@@ -32,7 +32,7 @@ use Rose::Object::MakeMethods::Generic
 (
  scalar                  => [ qw(type profile file all_profiles all_charsets sep_char all_sep_chars quote_char all_quote_chars escape_char all_escape_chars all_buchungsgruppen all_units
                                  import_status errors headers raw_data_headers info_headers data num_importable displayable_columns file all_taxzones) ],
- 'scalar --get_set_init' => [ qw(worker task_server num_imported) ],
+ 'scalar --get_set_init' => [ qw(worker task_server num_imported mappings) ],
  'array'                 => [
    progress_tracker     => { },
    add_progress_tracker => {  interface => 'add', hash_key => 'progress_tracker' },
@@ -154,32 +154,32 @@ sub action_download_sample {
 sub action_report {
   my ($self, %params) = @_;
 
-  my $report_id = $params{report_id} || $::form->{id};
-
-  $self->{report}      = SL::DB::Manager::CsvImportReport->find_by(id => $report_id);
+  my $report_id   = $params{report_id} || $::form->{id};
+  $self->{report} = SL::DB::Manager::CsvImportReport->find_by(id => $report_id);
 
   if (!$self->{report}) {
     $::form->error(t8('No report with id #1', $report_id));
   }
-  my $num_rows         = $self->{report}->numrows;
-  my $num_cols         = SL::DB::Manager::CsvImportReportRow->get_all_count(query => [ csv_import_report_id => $report_id, row => 0 ]);
+
+  my $num_rows               = $self->{report}->numrows;
+  my $num_cols               = SL::DB::Manager::CsvImportReportRow->get_all_count(query => [ csv_import_report_id => $report_id, row => 0 ]);
 
   # manual paginating, yuck
-  my $page = $::form->{page} || 1;
-  my $pages = {};
-  $pages->{per_page}        = $::form->{per_page} || 20;
-  $pages->{max}             = SL::DB::Helper::Paginated::ceil($num_rows, $pages->{per_page}) || 1;
-  $pages->{page}             = $page < 1 ? 1
-                            : $page > $pages->{max} ? $pages->{max}
-                            : $page;
-  $pages->{common}          = [ grep { $_->{visible} } @{ SL::DB::Helper::Paginated::make_common_pages($pages->{page}, $pages->{max}) } ];
+  my $page                   = $::form->{page} || 1;
+  my $pages                  = {};
+  $pages->{per_page}         = $::form->{per_page} || 20;
+  $pages->{max}              = SL::DB::Helper::Paginated::ceil($num_rows, $pages->{per_page}) || 1;
+  $pages->{page}             = $page < 1             ? 1
+                             : $page > $pages->{max} ? $pages->{max}
+                             : $                       page;
+  $pages->{common}           = [ grep { $_->{visible} } @{ SL::DB::Helper::Paginated::make_common_pages($pages->{page}, $pages->{max}) } ];
 
   $self->{report_numheaders} = $self->{report}->numheaders;
-  my $first_row_header = 0;
-  my $last_row_header  = $self->{report_numheaders} - 1;
-  my $first_row_data   = $pages->{per_page} * ($pages->{page}-1) + $self->{report_numheaders};
-  my $last_row_data    = min($pages->{per_page} * $pages->{page}, $num_rows) + $self->{report_numheaders} - 1;
-  $self->{display_rows} = [
+  my $first_row_header       = 0;
+  my $last_row_header        = $self->{report_numheaders} - 1;
+  my $first_row_data         = $pages->{per_page} * ($pages->{page}-1) + $self->{report_numheaders};
+  my $last_row_data          = min($pages->{per_page} * $pages->{page}, $num_rows) + $self->{report_numheaders} - 1;
+  $self->{display_rows}      = [
     $first_row_header
       ..
     $last_row_header,
@@ -202,17 +202,64 @@ sub action_report {
     ]
   );
 
-  my $rows             = SL::DB::Manager::CsvImportReportRow->get_all(query => \@query);
-  my $status           = SL::DB::Manager::CsvImportReportStatus->get_all(query => \@query);
+  my $rows               = SL::DB::Manager::CsvImportReportRow   ->get_all(query => \@query);
+  my $status             = SL::DB::Manager::CsvImportReportStatus->get_all(query => \@query);
 
   $self->{report_rows}   = $self->{report}->folded_rows(rows => $rows);
   $self->{report_status} = $self->{report}->folded_status(status => $status);
-  $self->{pages} = $pages;
-  $self->{base_url} = $self->url_for(action => 'report', id => $report_id, no_layout => $params{no_layout} || $::form->{no_layout} );
+  $self->{pages}         = $pages;
+  $self->{base_url}      = $self->url_for(action => 'report', id => $report_id, no_layout => $params{no_layout} || $::form->{no_layout} );
 
   $self->render('csv_import/report', { layout => !($params{no_layout} || $::form->{no_layout}) });
 }
 
+sub action_add_empty_mapping_line {
+  my ($self) = @_;
+
+  $self->profile_from_form;
+  $self->setup_help;
+
+  $self->js
+    ->append('#csv_import_mappings', $self->render('csv_import/_mapping_item', { layout => 0, output => 0 }))
+    ->hide('#mapping_empty')
+    ->render;
+}
+
+sub action_add_mapping_from_upload {
+  my ($self) = @_;
+
+  $self->profile_from_form;
+  $self->setup_help;
+
+  my $file = SL::SessionFile->new($self->csv_file_name, mode => '<', encoding => $self->profile->get('charset'));
+  if (!$file->fh) {
+    $self->js
+      ->flash('error', t8('No file has been uploaded yet.'))
+      ->render;
+    return;
+  }
+
+  my $csv = SL::Helper::Csv->new(
+    file => $file->file_name,
+    map { $_ => $self->profile->get($_) } qw(sep_char escape_char quote_char),
+  );
+
+  $csv->_open_file;
+  my $header = $csv->check_header;
+
+  for my $field (@$header) {
+    next if $self->mappings_for_profile->{$field};
+    $self->js->append(
+      '#csv_import_mappings',
+      $self->render('csv_import/_mapping_item', { layout => 0, output => 0 }, item => { from => $field }),
+    );
+  }
+
+  $self->js
+    ->hide('#mapping_empty')
+    ->render;
+}
+
 
 #
 # filters
@@ -372,6 +419,7 @@ sub load_default_profile {
   $profile ||= SL::DB::CsvImportProfile->new(type => $self->{type}, login => $::myconfig{login});
 
   $self->profile($profile);
+  $self->mappings(SL::JSON::from_json($self->profile->get('json_mappings'))) if $self->profile->get('json_mappings');
   $self->worker->set_profile_defaults;
   $self->profile->set_defaults;
 }
@@ -416,6 +464,9 @@ sub profile_from_form {
   $self->profile->assign_attributes(%{ $::form->{profile} });
   $self->profile->settings(map({ { key => $_, value => $::form->{settings}->{$_} } } keys %{ $::form->{settings} }),
                            @settings);
+
+  $self->profile->set('json_mappings', JSON::to_json($self->mappings));
+
   $self->profile->set_defaults;
 }
 
@@ -459,6 +510,7 @@ sub save_report_single {
     file       => '',
     numrows    => scalar @{ $self->data },
     numheaders => 1,
+    test_mode  => $params{test} ? 1 : 0,
   );
 
   $report->save(cascade => 1) or die $report->db->error;
@@ -529,6 +581,7 @@ sub save_report_multi {
     file       => '',
     numrows    => scalar @{ $self->data },
     numheaders => scalar @{ $self->worker->profile },
+    test_mode  => $params{test} ? 1 : 0,
   );
 
   $report->save(cascade => 1) or die $report->db->error;
@@ -664,4 +717,12 @@ sub check_task_server {
   1;
 }
 
+sub mappings_for_profile {
+  +{ map { $_->{from} => $_->{to} } @{ $_[0]->mappings } }
+}
+
+sub init_mappings {
+  [ grep { $_->{from} } @{ $::form->{mappings} || [] } ]
+}
+
 1;