10 use File::Slurp qw(read_file);
 
  13   my ($parts, $from, $to, $separator) = @_;
 
  20     map  { s{^\s+|\s+$}{}g; $_ }
 
  27   my ($class, $file_name, %params) = @_;
 
  29   my ($local_bank_code, $local_account_number, %transaction, @transactions, @lines);
 
  31   my $default_currency = substr(SL::DB::Default->get_default_currency, -1, 1);
 
  33   my $store_transaction = sub {
 
  35       push @transactions, { %transaction };
 
  41   foreach my $line (read_file($file_name)) {
 
  43     $line = Encode::decode($params{charset} // 'UTF-8', $line);
 
  48     if ($line =~ m{^:(\d+[a-z]*):}i) {
 
  53     if (@lines && ($line =~ m{^\%})) {
 
  54       $lines[-1]->[0] .= substr($line, 1);
 
  56     } elsif (@lines && ($active_field eq '86') && !$current_field) {
 
  57       $lines[-1]->[0] .= $line;
 
  60       push @lines, [ $line, $line_number ];
 
  64   foreach my $line (@lines) {
 
  65     # AT MT940 has the format  :25://AT20151/00797453990/EUR
 
  66     # DE MT940 has the format  :25:BLZ/Konto
 
  67     # https://www.bankaustria.at/files/MBS_MT940_V5107.pdf
 
  68     if ($line->[0] =~ m{^:25:(?://AT)?(\d+)/(\d+)}) {
 
  70       $local_bank_code      = $1;
 
  71       $local_account_number = $2;
 
  73     } 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) {
 
  74       #                            1       2       3       4        5           6           7          8         9      10
 
  75       # :61:2008060806CR952,N051NONREF
 
  77       $store_transaction->();
 
  79       my $valuta_year      = $1 * 1 + 2000;
 
  80       my $valuta_month     = $2;
 
  82       my $trans_month      = $4 ? substr($4, 0, 2) : $valuta_month;
 
  83       my $trans_day        = $4 ? substr($4, 2, 2) : $valuta_day;
 
  84       my $debit_credit     = $5;
 
  85       my $currency         = $6 || $default_currency;
 
  87       my $amount2          = $8 || 0;
 
  88       my $transaction_code = $9;
 
  91       my $valuta_date      = DateTime->new_local(year => $valuta_year, month => $valuta_month, day => $valuta_day);
 
  92       my $trans_date       = DateTime->new_local(year => $valuta_year, month => $trans_month,  day => $trans_day);
 
  93       my $diff             = $valuta_date->subtract_datetime($trans_date);
 
  94       my $trans_year_diff  = $diff->months < 6           ?  0
 
  95                            : $valuta_date  > $trans_date ?  1
 
  97       $trans_date          = DateTime->new_local(year => $valuta_year + $trans_year_diff, month => $trans_month,  day => $trans_day);
 
  98       my $sign             = ($debit_credit eq 'D') || ($debit_credit eq 'RC') ? -1 : 1;
 
  99       $reference           =~ s{//.*}{};
 
 100       $reference           = '' if $reference eq 'NONREF';
 
 103         line_number          => $line->[1],
 
 104         currency             => $currency,
 
 105         valutadate           => $valuta_date,
 
 106         transdate            => $trans_date,
 
 107         amount               => ($amount1 * 1 + ($amount2 / (10 ** length($amount2))))* $sign,
 
 108         reference            => $reference,
 
 109         transaction_code     => $transaction_code,
 
 110         local_bank_code      => $local_bank_code,
 
 111         local_account_number => $local_account_number,
 
 114     } elsif (%transaction && ($line->[0] =~ m{^:86:})) {
 
 115       if ($line->[0] =~ m{^:86:\d+\?(.+)}) {
 
 117         my %parts = map { ((substr($_, 0, 2) // '0') * 1 => substr($_, 2)) } split m{\?}, $1;
 
 119         $transaction{purpose}               = _join_entries(\%parts, 20, 29);
 
 120         $transaction{remote_name}           = _join_entries(\%parts, 32, 33, '');
 
 121         $transaction{remote_bank_code}      = $parts{30};
 
 122         $transaction{remote_account_number} = $parts{31};
 
 126         $transaction{purpose} = substr($line->[0], 5);
 
 129       $store_transaction->();
 
 133   $store_transaction->();
 
 135   return @transactions;