X-Git-Url: http://wagnertech.de/git?p=kivitendo-erp.git;a=blobdiff_plain;f=SL%2FMT940.pm;fp=SL%2FMT940.pm;h=2a97e5e797461d5e585057a0757ab95a69a19e2e;hp=0000000000000000000000000000000000000000;hb=53593baa211863fbf66540cf1bcc36c8fb37257f;hpb=deb4d2dbb676d7d6f69dfe7815d6e0cb09bd4a44 diff --git a/SL/MT940.pm b/SL/MT940.pm new file mode 100644 index 000000000..2a97e5e79 --- /dev/null +++ b/SL/MT940.pm @@ -0,0 +1,138 @@ +package SL::MT940; + +use strict; +use warnings; + +use Data::Dumper; +use DateTime; +use SL::DB::Default; +use Encode; +use File::Slurp qw(read_file); + +sub _join_entries { + my ($parts, $from, $to, $separator) = @_; + + $separator //= ' '; + + return + join $separator, + grep { $_ } + map { s{^\s+|\s+$}{}g; $_ } + grep { $_ } + map { $parts->{$_} } + ($from..$to); +} + +sub parse { + my ($class, $file_name, %params) = @_; + + my ($local_bank_code, $local_account_number, %transaction, @transactions, @lines); + my $line_number = 0; + my $default_currency = substr(SL::DB::Default->get_default_currency, -1, 1); + + my $store_transaction = sub { + if (%transaction) { + push @transactions, { %transaction }; + %transaction = (); + } + }; + + my ($active_field); + foreach my $line (read_file($file_name)) { + chomp $line; + $line = Encode::decode($params{charset} // 'UTF-8', $line); + $line =~ s{\r+}{}; + $line_number++; + + my $current_field; + if ($line =~ m{^:(\d+[a-z]*):}i) { + $current_field = $1; + $active_field = $1; + } + + if (@lines && ($line =~ m{^\%})) { + $lines[-1]->[0] .= substr($line, 1); + + } elsif (@lines && ($active_field eq '86') && !$current_field) { + $lines[-1]->[0] .= $line; + + } else { + push @lines, [ $line, $line_number ]; + } + } + + foreach my $line (@lines) { + # AT MT940 has the format :25://AT20151/00797453990/EUR + # DE MT940 has the format :25:BLZ/Konto + # https://www.bankaustria.at/files/MBS_MT940_V5107.pdf + if ($line->[0] =~ m{^:25:(?://AT)?(\d+)/(\d+)}) { + + $local_bank_code = $1; + $local_account_number = $2; + + } elsif ($line->[0] =~ m{^:61: (\d{2}) (\d{2}) (\d{2}) (\d{4})? (C|D|RC|RD) ([a-zA-Z]?) (\d+) (?:, (\d*))? N (.{3}) (.*)}x) { + # 1 2 3 4 5 6 7 8 9 10 + # :61:2008060806CR952,N051NONREF + + $store_transaction->(); + + my $valuta_year = $1 * 1 + 2000; + my $valuta_month = $2; + my $valuta_day = $3; + my $trans_month = $4 ? substr($4, 0, 2) : $valuta_month; + my $trans_day = $4 ? substr($4, 2, 2) : $valuta_day; + my $debit_credit = $5; + my $currency = $6 || $default_currency; + my $amount1 = $7; + my $amount2 = $8 || 0; + my $transaction_code = $9; + my $reference = $10; + + my $valuta_date = DateTime->new_local(year => $valuta_year, month => $valuta_month, day => $valuta_day); + my $trans_date = DateTime->new_local(year => $valuta_year, month => $trans_month, day => $trans_day); + my $diff = $valuta_date->subtract_datetime($trans_date); + my $trans_year_diff = $diff->months < 6 ? 0 + : $valuta_date > $trans_date ? 1 + : -1; + $trans_date = DateTime->new_local(year => $valuta_year + $trans_year_diff, month => $trans_month, day => $trans_day); + my $sign = ($debit_credit eq 'D') || ($debit_credit eq 'RC') ? -1 : 1; + $reference =~ s{//.*}{}; + $reference = '' if $reference eq 'NONREF'; + + %transaction = ( + line_number => $line->[1], + currency => $currency, + valutadate => $valuta_date, + transdate => $trans_date, + amount => ($amount1 * 1 + ($amount2 / (10 ** length($amount2))))* $sign, + reference => $reference, + transaction_code => $transaction_code, + local_bank_code => $local_bank_code, + local_account_number => $local_account_number, + ); + + } elsif (%transaction && ($line->[0] =~ m{^:86:})) { + if ($line->[0] =~ m{^:86:\d+\?(.+)}) { + # structured + my %parts = map { ((substr($_, 0, 2) // '0') * 1 => substr($_, 2)) } split m{\?}, $1; + + $transaction{purpose} = _join_entries(\%parts, 20, 29); + $transaction{remote_name} = _join_entries(\%parts, 32, 33, ''); + $transaction{remote_bank_code} = $parts{30}; + $transaction{remote_account_number} = $parts{31}; + + } else { + # unstructured + $transaction{purpose} = substr($line->[0], 5); + } + + $store_transaction->(); + } + } + + $store_transaction->(); + + return @transactions; +} + +1;