--- /dev/null
+package SL::Controller::BankImport;
+use strict;
+use Data::Dumper;
+use parent qw(SL::Controller::Base);
+
+use SL::Locale::String qw(t8);
+use SL::DB::CsvImportProfile;
+use SL::Helper::MT940;
+
+
+sub action_upload_mt940 {
+ my ($self, %params) = @_;
+
+ my $profile = SL::DB::Manager::CsvImportProfile->find_by(name => 'MT940', login => $::myconfig{login});
+ $self->render('bankimport/form', title => $::locale->text('MT940 import'), profile => $profile ? 1 : 0);
+
+}
+
+sub action_import_mt940 {
+ my ($self, %params) = @_;
+
+ die "missing file for action import" unless $::form->{file};
+
+ my $converted_data = SL::Helper::MT940::convert_mt940_data($::form->{file});
+
+ # store the converted data in a session file with a name expected by the profile type "bank_transactions"
+ my $file = SL::SessionFile->new("csv-import-bank_transactions.csv", mode => '>');
+ $file->fh->print($converted_data);
+ $file->fh->close;
+
+ my $profile = SL::DB::Manager::CsvImportProfile->find_by(name => 'MT940', login => $::myconfig{login});
+ die t8("The MT940 import needs an import profile called MT940") unless $profile;
+
+ $self->redirect_to(controller => 'controller.pl', action => 'CsvImport/test', 'profile.type' => 'bank_transactions', 'profile.id' => $profile->id, force_profile => 1);
+
+};
+
+1;
+
my $bt = SL::DB::Manager::BankTransaction->find_by( id => $::form->{bt_id} );
my $invoice = SL::DB::Manager::Invoice->find_by( id => $::form->{prop_id} );
- $invoice = SL::DB::Manager::PurchaseInvoice->find_By( id => $::form->{prop_id} ) unless $invoice;
+ $invoice = SL::DB::Manager::PurchaseInvoice->find_by( id => $::form->{prop_id} ) unless $invoice;
die unless $bt and $invoice;
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 bank_transactions mt940);
+ die "Invalid CSV import type" if none { $_ eq $::form->{profile}->{type} } qw(parts inventories customers_vendors addresses contacts projects orders bank_transactions);
$self->type($::form->{profile}->{type});
}
: $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')
: die;
if ($self->{type} eq 'customers_vendors' or $self->{type} eq 'orders' ) {
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 = $::lx_office_conf{applications}->{aqbanking};
- die "Can't find aqbanking-cli, please check your configuration file.\n" unless -f $aqbin;
- 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 = <MT>; # discard original header line
- while (<MT>) {
- $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'));
$profile ||= SL::DB::CsvImportProfile->new(type => $self->{type}, login => $::myconfig{login});
$self->profile($profile);
+ $self->worker->set_profile_defaults;
$self->profile->set_defaults;
}
: $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)
: die "Program logic error";
}
'scalar --get_set_init' => [ qw(bank_accounts_by) ],
);
+sub set_profile_defaults {
+ my ($self) = @_;
+
+ $self->controller->profile->_set_defaults(
+ charset => 'UTF8', # override charset from defaults
+ update_policy => 'skip',
+ );
+};
+
sub init_class {
my ($self) = @_;
$self->class('SL::DB::BankTransaction');
scalar => [ qw(table) ],
);
+sub set_profile_defaults {
+};
+
sub init_class {
my ($self) = @_;
$self->class('SL::DB::Contact');
'scalar --get_set_init' => [ qw(table languages_by businesses_by) ],
);
+sub set_profile_defaults {
+ my ($self) = @_;
+ $self->controller->profile->_set_defaults(table => 'customer');
+};
+
sub init_table {
my ($self) = @_;
$self->table($self->controller->profile->get('table') eq 'customer' ? 'customer' : 'vendor');
$self->class('SL::DB::Inventory');
}
+sub set_profile_defaults {
+};
+
sub init_profile {
my ($self) = @_;
$self->class(['SL::DB::Order', 'SL::DB::OrderItem']);
}
+sub set_profile_defaults {
+ my ($self) = @_;
+
+ $self->controller->profile->_set_defaults(
+ order_column => $::locale->text('Order'),
+ item_column => $::locale->text('OrderItem'),
+ max_amount_diff => 0.02,
+ );
+};
+
sub init_settings {
my ($self) = @_;
translation_columns all_pricegroups) ],
);
+sub set_profile_defaults {
+ my ($self) = @_;
+
+ my $bugru = SL::DB::Manager::Buchungsgruppe->find_by(description => { like => 'Standard%19%' });
+
+ $self->controller->profile->_set_defaults(
+ sellprice_places => 2,
+ sellprice_adjustment => 0,
+ sellprice_adjustment_type => 'percent',
+ article_number_policy => 'update_prices',
+ shoparticle_if_missing => '0',
+ parts_type => 'part',
+ default_buchungsgruppe => ($bugru ? $bugru->id : undef),
+ apply_buchungsgruppe => 'all',
+ );
+};
+
+
sub init_class {
my ($self) = @_;
$self->class('SL::DB::Part');
$self->class('SL::DB::Project');
}
+sub set_profile_defaults {
+};
+
sub init_all_cvar_configs {
my ($self) = @_;
scalar => [ qw(table) ],
);
+sub set_profile_defaults {
+};
+
sub init_class {
my ($self) = @_;
$self->class('SL::DB::Shipto');
sub set_defaults {
my ($self) = @_;
-
- if ($self->type eq 'parts') {
- my $bugru = SL::DB::Manager::Buchungsgruppe->find_by(description => { like => 'Standard%19%' });
-
- $self->_set_defaults(sellprice_places => 2,
- sellprice_adjustment => 0,
- sellprice_adjustment_type => 'percent',
- article_number_policy => 'update_prices',
- shoparticle_if_missing => '0',
- parts_type => 'part',
- default_buchungsgruppe => ($bugru ? $bugru->id : undef),
- apply_buchungsgruppe => 'all',
- );
- } elsif ($self->type eq 'orders') {
- $self->_set_defaults(order_column => $::locale->text('Order'),
- item_column => $::locale->text('OrderItem'),
- max_amount_diff => 0.02,
- );
- } elsif ($self->type eq 'mt940') {
- $self->_set_defaults(charset => 'UTF8',
- sep_char => ';',
- numberformat => '1000.00',
- update_policy => 'skip',
- );
- } elsif ($self->type eq 'bank_transactions') {
- $self->_set_defaults(charset => 'UTF8',
- update_policy => 'skip',
- );
- } else {
- $self->_set_defaults(table => 'customer');
- }
-
- # TODO: move the defaults into their own controller
- # defaults can only be set once, so use these values as default if they
- # haven't already been set above for one of the special import types
- # If the values have been set above they won't be overwritten here:
-
$self->_set_defaults(sep_char => ',',
quote_char => '"',
escape_char => '"',
my @options;
if ( $open_amount && # invoice amount not 0
+ $self->skonto_date && # check whether skonto applies
abs(abs($self->amount_less_skonto) - abs($bt->amount)) < 0.01 &&
$self->check_skonto_configuration) {
if ( $self->within_skonto_period($bt->transdate) ) {
--- /dev/null
+package SL::Helper::MT940;
+
+use strict;
+
+sub convert_mt940_data {
+ my ($mt940_data) = @_;
+
+ # takes the data from an uploaded mt940 file, converts it to csv via aqbanking and returns the converted data
+ # The uploaded file data is stored as a session file, just like the aqbanking settings file.
+
+ my $import_filename = 'bank_transfer.940';
+ my $sfile = SL::SessionFile->new($import_filename, mode => '>');
+ $sfile->fh->print($mt940_data);
+ $sfile->fh->close;
+
+ my $aqbin = $::lx_office_conf{applications}->{aqbanking};
+ die "Can't find aqbanking-cli, please check your configuration file.\n" unless -f $aqbin;
+ my $cmd = "$aqbin --cfgdir=\"" . $sfile->get_path . "\" import --importer=\"swift\" --profile=\"SWIFT-MT940\" -f " . $sfile->get_path . "/$import_filename | $aqbin --cfgdir=\"" . $sfile->get_path . "\" listtrans --exporter=\"csv\" --profile=\"AqMoney2\" ";
+
+ my $converted_data = '"empty";"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";
+
+ open my $mt, "-|", "$cmd" || die "Problem with executing aqbanking\n";
+ my $headerline = <$mt>; # discard original aqbanking header line
+ while (<$mt>) {
+ $converted_data .= $_;
+ };
+ close $mt;
+ return $converted_data;
+};
+
+1;
-3.2.1-rb
+3.2.1-unstable
'CSS style for pictures' => 'CSS Style für Bilder',
'CSV' => 'CSV',
'CSV export -- options' => 'CSV-Export -- Optionen',
- 'CSV import: MT940' => 'CSV Import: MT940',
'CSV import: bank transactions' => 'CSV Import: Bankbewegungen',
'CSV import: contacts' => 'CSV-Import: Ansprechpersonen',
'CSV import: customers and vendors' => 'CSV-Import: Kunden und Lieferanten',
'Import' => 'Import',
'Import CSV' => 'CSV-Import',
'Import Status' => 'Import Status',
+ 'Import a MT940 file:' => 'Laden Sie eine MT940 Datei hoch:',
'Import file' => 'Import-Datei',
'Import not started yet, please wait...' => 'Der Taskserver ist gerade ausgelastet. Ihr Import wird gleich gestartet, bitte warten...',
'Import preview' => 'Import-Vorschau',
'Please contact your administrator.' => 'Bitte wenden Sie sich an Ihren Administrator.',
'Please correct the settings and try again or deactivate that client.' => 'Bitte korrigieren Sie die Einstellungen und versuchen Sie es erneut, oder deaktivieren Sie diesen Mandanten.',
'Please create/copy a template named letter.tex in your client template dir' => 'Bitte erstellen / kopieren Sie eine Druckvorlage namens letter.tex in Ihren Mandantenvorlagen-Ordner',
+ 'Please create a CSV import profile called "MT940" for the import type bank transactions:' => 'Bitte erstellen Sie ein CSV Import Profil mit dem Namen "MT940" für den Importtyp Bankbewegungen',
'Please define a taxkey for the following taxes and run the update again:' => 'Bitte definieren Sie einen Steuerschlüssel für die folgenden Steuern und starten Sie dann das Update erneut:',
'Please do so in the administration area.' => 'Bitte erledigen Sie dies im Administrationsbereich.',
'Please enter a profile name.' => 'Bitte geben Sie einen Profilnamen an.',
'The GL transaction #1 has been deleted.' => 'Die Dialogbuchung #1 wurde gelöscht.',
'The IBAN is missing.' => 'Die IBAN fehlt.',
'The LDAP server "#1:#2" is unreachable. Please check config/kivitendo.conf.' => 'Der LDAP-Server "#1:#2" ist nicht erreichbar. Bitte überprüfen Sie die Angaben in config/kivitendo.conf.',
+ 'The MT940 import needs an import profile called MT940' => 'Der MT940 Import benötigt ein Importprofil mit dem Namen "MT940"',
'The SEPA export has been created.' => 'Der SEPA-Export wurde erstellt',
'The SEPA strings have been saved.' => 'Die bei SEPA-Überweisungen verwendeten Begriffe wurden gespeichert.',
'The WebDAV feature has been used.' => 'Das WebDAV-Feature wurde benutzt.',
[Cash--Bank Import--MT940]
ACCESS=bank_transaction
module=controller.pl
-action=CsvImport/new
-profile.type=mt940
+action=BankImport/upload_mt940
[Cash--Bank transactions MT940]
ACCESS=bank_transaction
--- /dev/null
+[%- USE HTML %]
+[%- USE LxERP %]
+[%- USE L %]
+[%- USE T8 %]
+
+ <div class="listtop">[% FORM.title %]</div>
+
+ [% IF profile %]
+ <p>
+ [% "Import a MT940 file:" | $T8 %]
+ </p>
+
+ <form method="post" action="controller.pl" enctype="multipart/form-data">
+ [% L.hidden_tag('action', 'BankImport/import_mt940') %]
+
+ [% L.input_tag('file', '', type => 'file', accept => '*') %]
+ [% L.submit_tag('action_import_mt940', LxERP.t8('Import')) %]
+
+ </form>
+ [% ELSE %]
+ <p>
+ [% "Please create a CSV import profile called \"MT940\" for the import type bank transactions:" | $T8 %] <a href="[% SELF.url_for(controller => 'CsvImport', action => 'new', 'profile.type' => 'bank_transactions' ) %]">CsvImport</a>
+ </p>
+ [% END %]
+++ /dev/null
-[% USE LxERP %]
-[% USE L %]
-
-<tr>
- <th align="right">[%- LxERP.t8("Existing bank transactions") %]:</th>
- <td colspan="10">
- [% opts = [ [ 'skip', LxERP.t8('Skip entry') ] , [ 'insert_new', LxERP.t8('Insert new') ] ] %]
- [% L.select_tag('settings.update_policy', opts, default = SELF.profile.get('update_policy'), style = 'width: 300px') %]
- </td>
-</tr>
-
-
[%- INCLUDE 'csv_import/_form_inventories.html' %]
[%- ELSIF SELF.type == 'orders' %]
[%- INCLUDE 'csv_import/_form_orders.html' %]
-[%- ELSIF SELF.type == 'mt940' %]
- [%- INCLUDE 'csv_import/_form_mt940.html' %]
[%- ELSIF SELF.type == 'bank_transactions' %]
[%- INCLUDE 'csv_import/_form_banktransactions.html' %]
[%- END %]