+  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];
+
+      my $object = $data_row->{object_to_save} || $data_row->{object};
+      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, $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);