+sub save_report {
+ my ($self, %params) = @_;
+
+ if ($self->worker->is_multiplexed) {
+ return $self->save_report_multi(%params);
+ } else {
+ return $self->save_report_single(%params);
+ }
+}
+
+sub save_report_single {
+ my ($self, %params) = @_;
+
+ $self->track_progress(phase => 'building report', progress => 0);
+
+ my $report = SL::DB::CsvImportReport->new(
+ session_id => $params{session_id},
+ profile_id => $self->profile->id,
+ type => $self->type,
+ file => '',
+ numrows => scalar @{ $self->data },
+ numheaders => 1,
+ test_mode => $params{test} ? 1 : 0,
+ );
+
+ $report->save(cascade => 1) or die $report->db->error;
+
+ SL::DB->client->with_transaction(sub {
+ my $dbh = SL::DB->client->dbh;
+
+ my $query = 'INSERT INTO csv_import_report_rows (csv_import_report_id, col, row, value) VALUES (?, ?, ?, ?)';
+ my $query2 = 'INSERT INTO csv_import_report_status (csv_import_report_id, row, type, value) VALUES (?, ?, ?, ?)';
+
+ my $sth = $dbh->prepare($query);
+ my $sth2 = $dbh->prepare($query2);
+
+ # save headers
+ my (@headers, @info_methods, @raw_methods, @methods);
+
+ for my $i (0 .. $#{ $self->info_headers->{headers} }) {
+ next unless $self->info_headers->{used}->{ $self->info_headers->{methods}->[$i] };
+ push @headers, $self->info_headers->{headers}->[$i];
+ push @info_methods, $self->info_headers->{methods}->[$i];
+ }
+ for my $i (0 .. $#{ $self->headers->{headers} }) {
+ next unless $self->headers->{used}->{ $self->headers->{headers}->[$i] };
+ push @headers, $self->headers->{headers}->[$i];
+ push @methods, $self->headers->{methods}->[$i];
+ }
+ for my $i (0 .. $#{ $self->raw_data_headers->{headers} }) {
+ next unless $self->raw_data_headers->{used}->{ $self->raw_data_headers->{headers}->[$i] };
+ push @headers, $self->raw_data_headers->{headers}->[$i];
+ push @raw_methods, $self->raw_data_headers->{headers}->[$i];
+ }
+
+ do_statement($::form, $sth, $query, $report->id, $_, 0, $headers[$_]) for 0 .. $#headers;
+
+ # col offsets
+ my $o1 = @info_methods;
+ my $o2 = $o1 + @methods;
+
+ for my $row (0 .. $#{ $self->data }) {
+ $self->track_progress(progress => $row / @{ $self->data } * 100) if $row % 1000 == 0;
+ my $data_row = $self->{data}[$row];
+
+ do_statement($::form, $sth, $query, $report->id, $_, $row + 1, $data_row->{info_data}{ $info_methods[$_] }) for 0 .. $#info_methods;
+ do_statement($::form, $sth, $query, $report->id, $o1 + $_, $row + 1, $data_row->{object}->${ \ $methods[$_] }) for 0 .. $#methods;
+ do_statement($::form, $sth, $query, $report->id, $o2 + $_, $row + 1, $data_row->{raw_data}{ $raw_methods[$_] }) for 0 .. $#raw_methods;
+
+ do_statement($::form, $sth2, $query2, $report->id, $row + 1, 'information', $_) for @{ $data_row->{information} || [] };
+ do_statement($::form, $sth2, $query2, $report->id, $row + 1, 'errors', $_) for @{ $data_row->{errors} || [] };
+ }
+ 1;
+ }) or do { die SL::DB->client->error };
+
+ return $report->id;
+}
+
+sub save_report_multi {
+ my ($self, %params) = @_;
+
+ $self->track_progress(phase => 'building report', progress => 0);
+
+ my $report = SL::DB::CsvImportReport->new(
+ session_id => $params{session_id},
+ profile_id => $self->profile->id,
+ type => $self->type,
+ 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;
+
+ SL::DB->client->with_transaction(sub {
+ my $dbh = SL::DB->client->dbh;
+
+ my $query = 'INSERT INTO csv_import_report_rows (csv_import_report_id, col, row, value) VALUES (?, ?, ?, ?)';
+ my $query2 = 'INSERT INTO csv_import_report_status (csv_import_report_id, row, type, value) VALUES (?, ?, ?, ?)';
+
+ my $sth = $dbh->prepare($query);
+ my $sth2 = $dbh->prepare($query2);
+
+ # save headers
+ my ($headers, $info_methods, $raw_methods, $methods);
+
+ for my $i (0 .. $#{ $self->worker->profile }) {
+ my $row_ident = $self->worker->profile->[$i]->{row_ident};
+
+ for my $i (0 .. $#{ $self->info_headers->{$row_ident}->{headers} }) {
+ next unless $self->info_headers->{$row_ident}->{used}->{ $self->info_headers->{$row_ident}->{methods}->[$i] };
+ push @{ $headers->{$row_ident} }, $self->info_headers->{$row_ident}->{headers}->[$i];
+ push @{ $info_methods->{$row_ident} }, $self->info_headers->{$row_ident}->{methods}->[$i];
+ }
+ for my $i (0 .. $#{ $self->headers->{$row_ident}->{headers} }) {
+ next unless $self->headers->{$row_ident}->{used}->{ $self->headers->{$row_ident}->{headers}->[$i] };
+ push @{ $headers->{$row_ident} }, $self->headers->{$row_ident}->{headers}->[$i];
+ push @{ $methods->{$row_ident} }, $self->headers->{$row_ident}->{methods}->[$i];
+ }
+
+ for my $i (0 .. $#{ $self->raw_data_headers->{$row_ident}->{headers} }) {
+ next unless $self->raw_data_headers->{$row_ident}->{used}->{ $self->raw_data_headers->{$row_ident}->{headers}->[$i] };
+ push @{ $headers->{$row_ident} }, $self->raw_data_headers->{$row_ident}->{headers}->[$i];
+ push @{ $raw_methods->{$row_ident} }, $self->raw_data_headers->{$row_ident}->{headers}->[$i];
+ }
+
+ }
+
+ for my $i (0 .. $#{ $self->worker->profile }) {
+ my $row_ident = $self->worker->profile->[$i]->{row_ident};
+ do_statement($::form, $sth, $query, $report->id, $_, $i, $headers->{$row_ident}->[$_]) for 0 .. $#{ $headers->{$row_ident} };
+ }
+
+ # col offsets
+ my ($off1, $off2);
+ for my $i (0 .. $#{ $self->worker->profile }) {
+ my $row_ident = $self->worker->profile->[$i]->{row_ident};
+ my $n_info_methods = $info_methods->{$row_ident} ? scalar @{ $info_methods->{$row_ident} } : 0;
+ my $n_methods = $methods->{$row_ident} ? scalar @{ $methods->{$row_ident} } : 0;
+
+ $off1->{$row_ident} = $n_info_methods;
+ $off2->{$row_ident} = $off1->{$row_ident} + $n_methods;
+ }
+
+ my $n_header_rows = scalar @{ $self->worker->profile };
+
+ for my $row (0 .. $#{ $self->data }) {
+ $self->track_progress(progress => $row / @{ $self->data } * 100) if $row % 1000 == 0;
+ my $data_row = $self->{data}[$row];
+ my $row_ident = $data_row->{raw_data}{datatype};
+
+ my $o1 = $off1->{$row_ident};
+ my $o2 = $off2->{$row_ident};
+
+ do_statement($::form, $sth, $query, $report->id, $_, $row + $n_header_rows, $data_row->{info_data}{ $info_methods->{$row_ident}->[$_] }) for 0 .. $#{ $info_methods->{$row_ident} };
+ do_statement($::form, $sth, $query, $report->id, $o1 + $_, $row + $n_header_rows, $data_row->{object}->${ \ $methods->{$row_ident}->[$_] }) for 0 .. $#{ $methods->{$row_ident} };
+ do_statement($::form, $sth, $query, $report->id, $o2 + $_, $row + $n_header_rows, $data_row->{raw_data}{ $raw_methods->{$row_ident}->[$_] }) for 0 .. $#{ $raw_methods->{$row_ident} };
+
+ do_statement($::form, $sth2, $query2, $report->id, $row + $n_header_rows, 'information', $_) for @{ $data_row->{information} || [] };
+ do_statement($::form, $sth2, $query2, $report->id, $row + $n_header_rows, 'errors', $_) for @{ $data_row->{errors} || [] };
+ }
+ 1;
+ }) or do { die SL::DB->client->error };
+
+ return $report->id;
+}
+
+sub init_worker {
+ my $self = shift;
+
+ my @args = (controller => $self);
+
+ if ( $self->file() ) {
+ push(@args, file => $self->file());
+ }
+
+ return $self->{type} eq 'customers_vendors' ? SL::Controller::CsvImport::CustomerVendor->new(@args)
+ : $self->{type} eq 'contacts' ? SL::Controller::CsvImport::Contact->new(@args)
+ : $self->{type} eq 'addresses' ? SL::Controller::CsvImport::Shipto->new(@args)
+ : $self->{type} eq 'parts' ? SL::Controller::CsvImport::Part->new(@args)
+ : $self->{type} eq 'inventories' ? SL::Controller::CsvImport::Inventory->new(@args)
+ : $self->{type} eq 'projects' ? SL::Controller::CsvImport::Project->new(@args)
+ : $self->{type} eq 'orders' ? SL::Controller::CsvImport::Order->new(@args)
+ : $self->{type} eq 'delivery_orders' ? SL::Controller::CsvImport::DeliveryOrder->new(@args)
+ : $self->{type} eq 'bank_transactions' ? SL::Controller::CsvImport::BankTransaction->new(@args)
+ : $self->{type} eq 'ar_transactions' ? SL::Controller::CsvImport::ARTransaction->new(@args)
+ : die "Program logic error";
+}
+
+sub init_num_imported { 0 }
+
+sub setup_help {
+ my ($self) = @_;
+
+ $self->worker->setup_displayable_columns;
+}
+
+sub track_progress {
+ my ($self, %params) = @_;
+
+ for my $tracker ($self->progress_tracker) {
+ $tracker->track_progress(%params);
+ }
+}
+
+sub init_task_server {
+ SL::System::TaskServer->new;
+}
+
+sub cleanup_reports {
+ SL::DB::Manager::CsvImportReport->cleanup;
+}
+
+sub check_task_server {
+ if (!$::auth->client->{task_server_user_id}) {
+ flash('error', t8('The task server is required for this module but not enabled for the current client. Please enable it for the client "#1" in the administration section.', $::auth->client->{name}));
+ }
+
+ return 1 if $_[0]->task_server->is_running;
+
+ flash('warning', t8('The task server is not running at the moment but needed for this module'));
+
+ 1;
+}
+
+sub mappings_for_profile {
+ +{ map { $_->{from} => $_->{to} } @{ $_[0]->mappings } }
+}
+
+sub init_mappings {
+ [ grep { $_->{from} } @{ $::form->{mappings} || [] } ]
+}
+
+sub setup_render_inputs_action_bar {
+ my ($self, %params) = @_;
+
+ for my $bar ($::request->layout->get('actionbar')) {
+ $bar->add(
+ action => [
+ t8('Preview'),
+ submit => [ '#form', { action => 'CsvImport/test' } ],
+ accesskey => 'enter',
+ not_if => ($self->profile && $self->profile->get('dont_edit_profile')),
+ ],
+ action => [
+ t8('Import'),
+ submit => [ '#form', { action => 'CsvImport/import' } ],
+ disabled => t8('The test import has not been executed yet.'),
+ id => 'action_import',
+ ],
+ );
+ }
+}
+