X-Git-Url: http://wagnertech.de/gitweb/gitweb.cgi/mfinanz.git/blobdiff_plain/6a12a968761127af91e9da8db7579be2836bcaaa..2c3ecbd0419d17ac7c7a202d491377e59bea74a1:/SL/Controller/CsvImport.pm diff --git a/SL/Controller/CsvImport.pm b/SL/Controller/CsvImport.pm index 3f65d0ef2..3122037e1 100644 --- a/SL/Controller/CsvImport.pm +++ b/SL/Controller/CsvImport.pm @@ -17,6 +17,7 @@ use SL::Controller::CsvImport::Inventory; use SL::Controller::CsvImport::Shipto; use SL::Controller::CsvImport::Project; use SL::Controller::CsvImport::Order; +use SL::Controller::CsvImport::ARTransaction; use SL::JSON; use SL::Controller::CsvImport::BankTransaction; use SL::BackgroundJob::CsvImport; @@ -30,8 +31,8 @@ use parent qw(SL::Controller::Base); 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_imported num_importable displayable_columns file all_taxzones) ], - 'scalar --get_set_init' => [ qw(worker task_server) ], + 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 mappings) ], 'array' => [ progress_tracker => { }, add_progress_tracker => { interface => 'add', hash_key => 'progress_tracker' }, @@ -100,7 +101,7 @@ sub action_result { $self->profile($profile); if ($data->{errors} and my $first_error = $data->{errors}->[0]) { - flash('error', $::locale->text('There was an error parsing the csv file: #1 in line #2.', $first_error->[2], $first_error->[0])); + flash('error', $::locale->text('There was an error parsing the csv file: #1 in line #2: #3', $first_error->[2], $first_error->[0], $first_error->[1])); } if ($data->{progress}{finished} || $data->{errors}) { @@ -153,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, @@ -201,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 @@ -224,7 +272,7 @@ sub check_auth { sub check_type { my ($self) = @_; - die "Invalid CSV import type" if none { $_ eq $::form->{profile}->{type} } qw(parts inventories customers_vendors addresses contacts projects orders); + die "Invalid CSV import type" if none { $_ eq $::form->{profile}->{type} } qw(parts inventories customers_vendors addresses contacts projects orders bank_transactions ar_transactions); $self->type($::form->{profile}->{type}); } @@ -270,10 +318,10 @@ sub render_inputs { : $self->type eq 'projects' ? $::locale->text('CSV import: projects') : $self->type eq 'orders' ? $::locale->text('CSV import: orders') : $self->type eq 'bank_transactions' ? $::locale->text('CSV import: bank transactions') - : $self->type eq 'mt940' ? $::locale->text('CSV import: MT940') + : $self->type eq 'ar_transactions' ? $::locale->text('CSV import: ar transactions') : die; - if ($self->{type} eq 'customers_vendors' or $self->{type} eq 'orders' ) { + if ($self->{type} eq 'customers_vendors' or $self->{type} eq 'orders' or $self->{type} eq 'ar_transactions' ) { $self->all_taxzones(SL::DB::Manager::TaxZone->get_all_sorted(query => [ obsolete => 0 ])); }; @@ -290,30 +338,16 @@ sub render_inputs { sub test_and_import_deferred { my ($self, %params) = @_; - $self->profile_from_form; - + if ( $::form->{force_profile} && $::form->{profile}->{id} ) { + $self->load_default_profile; + } else { + $self->profile_from_form; + }; - if ( $::form->{file} && $::form->{FILENAME} =~ /\.940$/ ) { - my $mt940_file = SL::SessionFile->new($::form->{FILENAME}, mode => '>'); - $mt940_file->fh->print($::form->{file}); - $mt940_file->fh->close; - - my $aqbin = '/usr/bin/aqbanking-cli'; - my $cmd = "$aqbin --cfgdir=\"users\" import --importer=\"swift\" --profile=\"SWIFT-MT940\" -f " . $mt940_file->file_name . " | $aqbin --cfgdir=\"users\" listtrans --exporter=\"csv\" --profile=\"AqMoney2\" "; - my $converted_mt940; - open(MT, "$cmd |"); - $converted_mt940 .= '"transaction_id";"local_bank_code";"local_account_number";"remote_bank_code";"remote_account_number";"transdate";"valutadate";"amount";"currency";"remote_name";"remote_name_1";"purpose";"purpose1";"purpose2";"purpose3";"purpose4";"purpose5";"purpose6";"purpose7";"purpose8";"purpose9";"purpose10";"purpose11"' . "\n"; - my $headerline = ; # discard original header line - while () { - $converted_mt940 .= $_; - }; + if ($::form->{file}) { my $file = SL::SessionFile->new($self->csv_file_name, mode => '>'); - $file->fh->print($converted_mt940); + $file->fh->print($::form->{file}); $file->fh->close; - } elsif ($::form->{file}) { - my $file = SL::SessionFile->new($self->csv_file_name, mode => '>'); - $file->fh->print($::form->{file}); - $file->fh->close; } my $file = SL::SessionFile->new($self->csv_file_name, mode => '<', encoding => $self->profile->get('charset')); @@ -385,6 +419,8 @@ 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; } @@ -428,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; } @@ -471,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; @@ -541,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; @@ -640,10 +681,12 @@ sub init_worker { : $self->{type} eq 'projects' ? SL::Controller::CsvImport::Project->new(@args) : $self->{type} eq 'orders' ? SL::Controller::CsvImport::Order->new(@args) : $self->{type} eq 'bank_transactions' ? SL::Controller::CsvImport::BankTransaction->new(@args) - : $self->{type} eq 'mt940' ? 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) = @_; @@ -674,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;