Revision 6f45549b
Von Bernd Bleßmann vor fast 11 Jahren hinzugefügt
SL/Controller/CsvImport.pm | ||
---|---|---|
15 | 15 |
use SL::Controller::CsvImport::Part; |
16 | 16 |
use SL::Controller::CsvImport::Shipto; |
17 | 17 |
use SL::Controller::CsvImport::Project; |
18 |
use SL::Controller::CsvImport::Order; |
|
18 | 19 |
use SL::BackgroundJob::CsvImport; |
19 | 20 |
use SL::System::TaskServer; |
20 | 21 |
|
... | ... | |
125 | 126 |
my $file = SL::SessionFile->new($file_name, mode => '>', encoding => $self->profile->get('charset')); |
126 | 127 |
my $csv = Text::CSV_XS->new({ binary => 1, map { ( $_ => $self->profile->get($_) ) } qw(sep_char escape_char quote_char),}); |
127 | 128 |
|
128 |
$csv->print($file->fh, [ map { $_->{name} } @{ $self->displayable_columns } ]); |
|
129 |
$file->fh->print("\r\n"); |
|
130 |
$csv->print($file->fh, [ map { $_->{description} } @{ $self->displayable_columns } ]); |
|
131 |
$file->fh->print("\r\n"); |
|
129 |
if ($self->worker->is_multiplexed) { |
|
130 |
foreach my $ri (keys %{ $self->displayable_columns }) { |
|
131 |
$csv->print($file->fh, [ map { $_->{name} } @{ $self->displayable_columns->{$ri} } ]); |
|
132 |
$file->fh->print("\r\n"); |
|
133 |
} |
|
134 |
foreach my $ri (keys %{ $self->displayable_columns }) { |
|
135 |
$csv->print($file->fh, [ map { $_->{description} } @{ $self->displayable_columns->{$ri} } ]); |
|
136 |
$file->fh->print("\r\n"); |
|
137 |
} |
|
138 |
} else { |
|
139 |
$csv->print($file->fh, [ map { $_->{name} } @{ $self->displayable_columns } ]); |
|
140 |
$file->fh->print("\r\n"); |
|
141 |
$csv->print($file->fh, [ map { $_->{description} } @{ $self->displayable_columns } ]); |
|
142 |
$file->fh->print("\r\n"); |
|
143 |
} |
|
132 | 144 |
|
133 | 145 |
$file->fh->close; |
134 | 146 |
|
... | ... | |
158 | 170 |
: $page; |
159 | 171 |
$pages->{common} = [ grep { $_->{visible} } @{ SL::DB::Helper::Paginated::make_common_pages($pages->{cur}, $pages->{max}) } ]; |
160 | 172 |
|
173 |
$self->{report_numheaders} = $self->{report}->numheaders; |
|
174 |
my $first_row_header = 0; |
|
175 |
my $last_row_header = $self->{report_numheaders} - 1; |
|
176 |
my $first_row_data = $pages->{per_page} * ($pages->{cur}-1) + $self->{report_numheaders}; |
|
177 |
my $last_row_data = min($pages->{per_page} * $pages->{cur}, $num_rows) + $self->{report_numheaders} - 1; |
|
161 | 178 |
$self->{display_rows} = [ |
162 |
0, |
|
163 |
$pages->{per_page} * ($pages->{cur}-1) + 1 |
|
179 |
$first_row_header |
|
180 |
.. |
|
181 |
$last_row_header, |
|
182 |
$first_row_data |
|
164 | 183 |
.. |
165 |
min($pages->{per_page} * $pages->{cur}, $num_rows)
|
|
184 |
$last_row_data
|
|
166 | 185 |
]; |
167 | 186 |
|
168 | 187 |
my @query = ( |
169 | 188 |
csv_import_report_id => $report_id, |
170 | 189 |
or => [ |
171 |
row => 0, |
|
172 | 190 |
and => [ |
173 |
row => { gt => $pages->{per_page} * ($pages->{cur}-1) }, |
|
174 |
row => { le => $pages->{per_page} * $pages->{cur} }, |
|
191 |
row => { ge => $first_row_header }, |
|
192 |
row => { le => $last_row_header }, |
|
193 |
], |
|
194 |
and => [ |
|
195 |
row => { ge => $first_row_data }, |
|
196 |
row => { le => $last_row_data }, |
|
175 | 197 |
] |
176 | 198 |
] |
177 | 199 |
); |
... | ... | |
199 | 221 |
sub check_type { |
200 | 222 |
my ($self) = @_; |
201 | 223 |
|
202 |
die "Invalid CSV import type" if none { $_ eq $::form->{profile}->{type} } qw(parts customers_vendors addresses contacts projects); |
|
224 |
die "Invalid CSV import type" if none { $_ eq $::form->{profile}->{type} } qw(parts customers_vendors addresses contacts projects orders);
|
|
203 | 225 |
$self->type($::form->{profile}->{type}); |
204 | 226 |
} |
205 | 227 |
|
... | ... | |
242 | 264 |
: $self->type eq 'contacts' ? $::locale->text('CSV import: contacts') |
243 | 265 |
: $self->type eq 'parts' ? $::locale->text('CSV import: parts and services') |
244 | 266 |
: $self->type eq 'projects' ? $::locale->text('CSV import: projects') |
267 |
: $self->type eq 'orders' ? $::locale->text('CSV import: orders') |
|
245 | 268 |
: die; |
246 | 269 |
|
247 | 270 |
if ($self->{type} eq 'parts') { |
... | ... | |
363 | 386 |
$::form->{settings}->{sellprice_adjustment} = $::form->parse_amount(\%::myconfig, $::form->{settings}->{sellprice_adjustment}); |
364 | 387 |
} |
365 | 388 |
|
389 |
if ($self->type eq 'orders') { |
|
390 |
$::form->{settings}->{order_column} = 'Order'; |
|
391 |
$::form->{settings}->{item_column} = 'OrderItem'; |
|
392 |
} |
|
393 |
|
|
366 | 394 |
delete $::form->{profile}->{id}; |
367 | 395 |
$self->profile($existing_profile || SL::DB::CsvImportProfile->new(login => $::myconfig{login})); |
368 | 396 |
$self->profile->assign_attributes(%{ $::form->{profile} }); |
... | ... | |
389 | 417 |
sub save_report { |
390 | 418 |
my ($self, $report_id) = @_; |
391 | 419 |
|
420 |
if ($self->worker->is_multiplexed) { |
|
421 |
return $self->save_report_multi($report_id); |
|
422 |
} else { |
|
423 |
return $self->save_report_single($report_id); |
|
424 |
} |
|
425 |
} |
|
426 |
|
|
427 |
sub save_report_single { |
|
428 |
my ($self, $report_id) = @_; |
|
429 |
|
|
392 | 430 |
$self->track_progress(phase => 'building report', progress => 0); |
393 | 431 |
|
394 | 432 |
my $clone_profile = $self->profile->clone_and_reset_deep; |
... | ... | |
400 | 438 |
type => $self->type, |
401 | 439 |
file => '', |
402 | 440 |
numrows => scalar @{ $self->data }, |
441 |
numheaders => 1, |
|
403 | 442 |
); |
404 | 443 |
|
405 | 444 |
$report->save(cascade => 1) or die $report->db->error; |
... | ... | |
455 | 494 |
return $report->id; |
456 | 495 |
} |
457 | 496 |
|
497 |
sub save_report_multi { |
|
498 |
my ($self, $report_id) = @_; |
|
499 |
|
|
500 |
$self->track_progress(phase => 'building report', progress => 0); |
|
501 |
|
|
502 |
my $clone_profile = $self->profile->clone_and_reset_deep; |
|
503 |
$clone_profile->save; # weird bug. if this isn't saved before adding it to the report, it will default back to the last profile. |
|
504 |
|
|
505 |
my $report = SL::DB::CsvImportReport->new( |
|
506 |
session_id => $::auth->create_or_refresh_session, |
|
507 |
profile => $clone_profile, |
|
508 |
type => $self->type, |
|
509 |
file => '', |
|
510 |
numrows => scalar @{ $self->data }, |
|
511 |
numheaders => scalar @{ $self->worker->profile }, |
|
512 |
); |
|
513 |
|
|
514 |
$report->save(cascade => 1) or die $report->db->error; |
|
515 |
|
|
516 |
my $dbh = $::form->get_standard_dbh; |
|
517 |
$dbh->begin_work; |
|
518 |
|
|
519 |
my $query = 'INSERT INTO csv_import_report_rows (csv_import_report_id, col, row, value) VALUES (?, ?, ?, ?)'; |
|
520 |
my $query2 = 'INSERT INTO csv_import_report_status (csv_import_report_id, row, type, value) VALUES (?, ?, ?, ?)'; |
|
521 |
|
|
522 |
my $sth = $dbh->prepare($query); |
|
523 |
my $sth2 = $dbh->prepare($query2); |
|
524 |
|
|
525 |
# save headers |
|
526 |
my ($headers, $info_methods, $raw_methods, $methods); |
|
527 |
|
|
528 |
for my $i (0 .. $#{ $self->worker->profile }) { |
|
529 |
my $row_ident = $self->worker->profile->[$i]->{row_ident}; |
|
530 |
|
|
531 |
for my $i (0 .. $#{ $self->info_headers->{$row_ident}->{headers} }) { |
|
532 |
next unless $self->info_headers->{$row_ident}->{used}->{ $self->info_headers->{$row_ident}->{methods}->[$i] }; |
|
533 |
push @{ $headers->{$row_ident} }, $self->info_headers->{$row_ident}->{headers}->[$i]; |
|
534 |
push @{ $info_methods->{$row_ident} }, $self->info_headers->{$row_ident}->{methods}->[$i]; |
|
535 |
} |
|
536 |
for my $i (0 .. $#{ $self->headers->{$row_ident}->{headers} }) { |
|
537 |
next unless $self->headers->{$row_ident}->{used}->{ $self->headers->{$row_ident}->{headers}->[$i] }; |
|
538 |
push @{ $headers->{$row_ident} }, $self->headers->{$row_ident}->{headers}->[$i]; |
|
539 |
push @{ $methods->{$row_ident} }, $self->headers->{$row_ident}->{methods}->[$i]; |
|
540 |
} |
|
541 |
|
|
542 |
for my $i (0 .. $#{ $self->raw_data_headers->{$row_ident}->{headers} }) { |
|
543 |
next unless $self->raw_data_headers->{$row_ident}->{used}->{ $self->raw_data_headers->{$row_ident}->{headers}->[$i] }; |
|
544 |
push @{ $headers->{$row_ident} }, $self->raw_data_headers->{$row_ident}->{headers}->[$i]; |
|
545 |
push @{ $raw_methods->{$row_ident} }, $self->raw_data_headers->{$row_ident}->{headers}->[$i]; |
|
546 |
} |
|
547 |
|
|
548 |
} |
|
549 |
|
|
550 |
for my $i (0 .. $#{ $self->worker->profile }) { |
|
551 |
my $row_ident = $self->worker->profile->[$i]->{row_ident}; |
|
552 |
$sth->execute($report->id, $_, $i, $headers->{$row_ident}->[$_]) for 0 .. $#{ $headers->{$row_ident} }; |
|
553 |
} |
|
554 |
|
|
555 |
# col offsets |
|
556 |
my ($off1, $off2); |
|
557 |
for my $i (0 .. $#{ $self->worker->profile }) { |
|
558 |
my $row_ident = $self->worker->profile->[$i]->{row_ident}; |
|
559 |
my $n_info_methods = $info_methods->{$row_ident} ? scalar @{ $info_methods->{$row_ident} } : 0; |
|
560 |
my $n_methods = $methods->{$row_ident} ? scalar @{ $methods->{$row_ident} } : 0; |
|
561 |
|
|
562 |
$off1->{$row_ident} = $n_info_methods; |
|
563 |
$off2->{$row_ident} = $off1->{$row_ident} + $n_methods; |
|
564 |
} |
|
565 |
|
|
566 |
my $n_header_rows = scalar @{ $self->worker->profile }; |
|
567 |
|
|
568 |
for my $row (0 .. $#{ $self->data }) { |
|
569 |
$self->track_progress(progress => $row / @{ $self->data } * 100) if $row % 1000 == 0; |
|
570 |
my $data_row = $self->{data}[$row]; |
|
571 |
my $row_ident = $data_row->{raw_data}{datatype}; |
|
572 |
|
|
573 |
my $o1 = $off1->{$row_ident}; |
|
574 |
my $o2 = $off2->{$row_ident}; |
|
575 |
|
|
576 |
$sth->execute($report->id, $_, $row + $n_header_rows, $data_row->{info_data}{ $info_methods->{$row_ident}->[$_] }) for 0 .. $#{ $info_methods->{$row_ident} }; |
|
577 |
$sth->execute($report->id, $o1 + $_, $row + $n_header_rows, $data_row->{object}->${ \ $methods->{$row_ident}->[$_] }) for 0 .. $#{ $methods->{$row_ident} }; |
|
578 |
$sth->execute($report->id, $o2 + $_, $row + $n_header_rows, $data_row->{raw_data}{ $raw_methods->{$row_ident}->[$_] }) for 0 .. $#{ $raw_methods->{$row_ident} }; |
|
579 |
|
|
580 |
$sth2->execute($report->id, $row + $n_header_rows, 'information', $_) for @{ $data_row->{information} || [] }; |
|
581 |
$sth2->execute($report->id, $row + $n_header_rows, 'errors', $_) for @{ $data_row->{errors} || [] }; |
|
582 |
} |
|
583 |
|
|
584 |
$dbh->commit; |
|
585 |
|
|
586 |
return $report->id; |
|
587 |
} |
|
588 |
|
|
458 | 589 |
sub csv_file_name { |
459 | 590 |
my ($self) = @_; |
460 | 591 |
return "csv-import-" . $self->type . ".csv"; |
... | ... | |
474 | 605 |
: $self->{type} eq 'addresses' ? SL::Controller::CsvImport::Shipto->new(@args) |
475 | 606 |
: $self->{type} eq 'parts' ? SL::Controller::CsvImport::Part->new(@args) |
476 | 607 |
: $self->{type} eq 'projects' ? SL::Controller::CsvImport::Project->new(@args) |
608 |
: $self->{type} eq 'orders' ? SL::Controller::CsvImport::Order->new(@args) |
|
477 | 609 |
: die "Program logic error"; |
478 | 610 |
} |
479 | 611 |
|
Auch abrufbar als: Unified diff
Auftrags-Import