[BACK]Return to pta_import.pl CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / pta

Annotation of pta/pta_import.pl, Revision 1.12

1.1       schwarze    1: #!/usr/bin/perl
                      2:
                      3: # Copyright (c) 2020 Freda Bundchen
                      4:
                      5: # Permission to use, copy, modify, and distribute this software for any
                      6: # purpose with or without fee is hereby granted, provided that the above
                      7: # copyright notice and this permission notice appear in all copies.
                      8: #
                      9: # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10: # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11: # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12: # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13: # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14: # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15: # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:
                     17: use warnings;
                     18: use strict;
                     19:
1.9       schwarze   20: use Getopt::Std qw(getopts);
                     21:
                     22: our ($opt_I);
                     23:
1.1       schwarze   24: # === SUBROUTINES  =====================================================
                     25:
1.12    ! schwarze   26: sub import_account ($$$$) {
        !            27:        my ($account_name, $compiled_ref, $delim, $csv_account) = @_;
1.10      schwarze   28:        my ($account, $amount, $booking, $credit, $date, $debit,
                     29:            $description);
1.5       schwarze   30:        chomp(my $header = <>);
1.2       schwarze   31:        while (<>) {
1.5       schwarze   32:                next if (/^$/);
1.1       schwarze   33:                chomp;
1.3       schwarze   34:                my $line = $_;
1.12    ! schwarze   35:                my @fields = split /$delim/, $line;
        !            36:                my $matches = 0;
        !            37:                foreach my $selector (@$compiled_ref) {
        !            38:                        $matches = 1;
        !            39:                        for (my $i = 0; $i <= $#{$selector->{re}}; $i++) {
        !            40:                                next if $fields[$i] =~ $selector->{re}[$i];
        !            41:                                $matches = 0;
        !            42:                                last;
        !            43:                        }
        !            44:                        if ($matches) {
        !            45:                                $account = $selector->{ac};
        !            46:                                $booking = $selector->{id};
1.4       schwarze   47:                                last;
1.3       schwarze   48:                        }
                     49:                }
1.12    ! schwarze   50:                $matches or die "unmatched CSV line: $line";
1.10      schwarze   51:                if ($account_name eq "chase_credit") {
                     52:                        ($date, $amount, $debit, $credit,
                     53:                            $description) =
                     54:                            import_chase_credit($account,
                     55:                            $csv_account, $line);
                     56:                } elsif ($account_name eq "capital_one_credit") {
                     57:                        ($date, $amount, $debit, $credit,
                     58:                            $description) =
                     59:                            import_capital_one_credit($account,
                     60:                            $csv_account, $line);
                     61:                } elsif ($account_name eq "optum_hsa") {
                     62:                        ($date, $amount, $debit, $credit,
                     63:                            $description) =
                     64:                            import_optum_hsa($account,
                     65:                            $csv_account, $line);
1.11      schwarze   66:                } elsif ($account_name eq "sparkasse_camt") {
                     67:                        ($date, $amount, $debit, $credit,
                     68:                            $description) =
                     69:                            import_sparkasse_camt($account,
                     70:                            $csv_account, $line);
1.10      schwarze   71:                } else {
                     72:                        die "undefined format: $account_name";
                     73:                }
                     74:                unless ($date && $booking && $debit && $credit &&
                     75:                    $amount && $description) {
1.5       schwarze   76:                        die "import parse error: $line";
1.3       schwarze   77:                }
1.10      schwarze   78:                $description =~ s/#//g;
                     79:                print "$date $booking $debit $credit $amount " .
1.1       schwarze   80:                    "$description\n";
                     81:        }
                     82: }
                     83:
1.10      schwarze   84: sub import_chase_credit ($$$) {
                     85:        my ($account, $csv_account, $line) = @_;
                     86:        my ($trans_date, $post_date, $description, $category,
                     87:            $type, $amount) = split /,/, $line;
                     88:        my ($debit, $credit);
                     89:        $post_date =~ s#(\d+)/(\d+)/(\d+)#$3$1$2#;
                     90:        ($amount, $debit, $credit) =
                     91:            get_accounts_by_amount_sign($amount, $account,
                     92:            $csv_account);
                     93:        return ($post_date, $amount, $debit, $credit, $description);
                     94: }
                     95:
                     96: sub import_capital_one_credit ($$$) {
                     97:        my ($account, $csv_account, $line) = @_;
                     98:        my ($trans_date, $post_date, $card_num,
                     99:            $description, $category, $csv_debit,
                    100:            $csv_credit) = split /,/, $line;
                    101:        $post_date =~ s/(\d+)-(\d+)-(\d+)/$1$2$3/;
                    102:        my ($amount, $debit, $credit) =
                    103:            get_accounts_by_csv_col($account, $csv_account,
                    104:            $csv_debit, $csv_credit);
                    105:        return ($post_date, $amount, $debit, $credit, $description);
                    106: }
                    107:
                    108: sub import_optum_hsa ($$$) {
                    109:         my ($account, $csv_account, $line) = @_;
                    110:         my ($date, $description, $amount,
                    111:             $type) = split /,/, $line;
                    112:        my ($debit, $credit);
                    113:        $date =~ s/(\d+)-(\d+)-(\d+)/$1$2$3/;
                    114:        $amount =~ s/\$//;
                    115:        ($amount, $debit, $credit) =
                    116:            get_accounts_by_amount_sign($amount, $account,
                    117:            $csv_account);
                    118:        return ($date, $amount, $debit, $credit, $description);
                    119: }
                    120:
1.11      schwarze  121: sub import_sparkasse_camt ($$$) {
                    122:         my ($account, $csv_account, $line) = @_;
                    123:        my @fields;
                    124:        $_ = $line;
                    125:        push @fields, $1 while s/"([^"]*)";?//;
                    126:        $_ eq "" or die "CAMT parse error before $_ in $line";
                    127:        @fields == 17 or die "not 17 but @fields fields: $line";
                    128:        $fields[1] =~ s/^(\d\d)\.(\d\d)\.(\d\d)$/20$3$2$1/
                    129:            or die "date parse error: $line";
                    130:        $fields[14] =~ s/,/./;
                    131:        return $fields[1],
                    132:            get_accounts_by_amount_sign($fields[14], $account, $csv_account),
                    133:            (join ' ', $fields[11], $fields[4]);
                    134: }
                    135:
1.10      schwarze  136: sub get_accounts_by_amount_sign ($$$) {
                    137:        my ($amount, $account, $csv_account) = @_;
                    138:        my ($debit, $credit);
                    139:        if ($amount <= 0) {
                    140:                $amount = substr $amount, 1;
                    141:                $credit = $csv_account;
                    142:                $debit = $account;
                    143:        } else {
                    144:                $debit = $csv_account;
                    145:                $credit = $account;
1.5       schwarze  146:        }
1.10      schwarze  147:        return ($amount, $debit, $credit);
1.5       schwarze  148: }
1.9       schwarze  149:
1.10      schwarze  150: sub get_accounts_by_csv_col ($$$$) {
                    151:        my ($account, $csv_account, $csv_debit, $csv_credit) = @_;
                    152:        my ($amount, $debit, $credit);
                    153:        if ($csv_debit eq "") {
                    154:                $amount = $csv_credit;
                    155:                $credit = $account;
                    156:                $debit = $csv_account;
                    157:        } else {
                    158:                $amount = $csv_debit;
                    159:                $credit = $csv_account;
                    160:                $debit = $account;
                    161:        }
                    162:        return ($amount, $debit, $credit);
1.9       schwarze  163: }
                    164:
                    165: sub usage () {
1.10      schwarze  166:        printf STDERR "usage: %s -I accountname csvfilename\n", $0;
1.9       schwarze  167:        exit 1;
                    168: }
                    169:
1.1       schwarze  170: # === MAIN PROGRAM =====================================================
                    171:
1.12    ! schwarze  172: my ($csv_account, $fn, $in, $account_name, $delim, @compiled);
1.9       schwarze  173: getopts 'I:' or usage;
                    174: if ($opt_I) {
1.10      schwarze  175:        $account_name = $opt_I;
                    176:        $fn = "import_" . $account_name . ".txt";
1.9       schwarze  177:        open $in, $fn or die "$fn: $!";
1.1       schwarze  178: } else {
1.9       schwarze  179:        usage;
                    180: }
                    181: while (<$in>) {
                    182:        chomp;
                    183:        next if /^(?:#|$)/;
                    184:        my $line = $_;
1.12    ! schwarze  185:        if (/^ACCOUNT\s+(\S+)$/) {
1.9       schwarze  186:                $csv_account and die "duplicate ACCOUNT line: $1";
                    187:                $csv_account = $1;
                    188:                next;
                    189:        }
1.12    ! schwarze  190:        if (/^DELIM\s+(\S)$/) {
        !           191:                $delim and die "duplicate DELIM line: $1";
        !           192:                $delim = $1;
        !           193:                next;
        !           194:        }
        !           195:        $delim or die "no DELIM line in $fn";
        !           196:        s/^(.*)$delim\s+(\d+)\s+(\S+)// or
1.9       schwarze  197:            die "$fn import parse error: $line";
1.12    ! schwarze  198:        push @compiled, {
        !           199:                re => [map { qr/$_/ } split /$delim/, $1],
        !           200:                ac => $2,
        !           201:                id => $3,
        !           202:        };
1.1       schwarze  203: }
1.9       schwarze  204: close $in;
                    205: $csv_account or die "no ACCOUNT line in $fn";
1.12    ! schwarze  206: import_account($account_name, \@compiled, $delim, $csv_account);

CVSweb