Annotation of pta/pta_import.pl, Revision 1.11
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.10 schwarze 26: sub import_account ($$$$$) {
27: my ($account_name, $accounts_ref, $bookings_ref,
28: $compiled_ref, $csv_account) = @_;
29: my ($account, $amount, $booking, $credit, $date, $debit,
30: $description);
1.5 schwarze 31: chomp(my $header = <>);
1.2 schwarze 32: while (<>) {
1.5 schwarze 33: next if (/^$/);
1.1 schwarze 34: chomp;
1.3 schwarze 35: my $line = $_;
1.5 schwarze 36: foreach my $regex (@$compiled_ref) {
1.3 schwarze 37: if ($line =~ /$regex/) {
1.5 schwarze 38: $account = %$accounts_ref{$regex};
39: $booking = %$bookings_ref{$regex};
1.4 schwarze 40: last;
1.3 schwarze 41: }
42: }
1.10 schwarze 43: if ($account_name eq "chase_credit") {
44: ($date, $amount, $debit, $credit,
45: $description) =
46: import_chase_credit($account,
47: $csv_account, $line);
48: } elsif ($account_name eq "capital_one_credit") {
49: ($date, $amount, $debit, $credit,
50: $description) =
51: import_capital_one_credit($account,
52: $csv_account, $line);
53: } elsif ($account_name eq "optum_hsa") {
54: ($date, $amount, $debit, $credit,
55: $description) =
56: import_optum_hsa($account,
57: $csv_account, $line);
1.11 ! schwarze 58: } elsif ($account_name eq "sparkasse_camt") {
! 59: ($date, $amount, $debit, $credit,
! 60: $description) =
! 61: import_sparkasse_camt($account,
! 62: $csv_account, $line);
1.10 schwarze 63: } else {
64: die "undefined format: $account_name";
65: }
66: unless ($date && $booking && $debit && $credit &&
67: $amount && $description) {
1.5 schwarze 68: die "import parse error: $line";
1.3 schwarze 69: }
1.10 schwarze 70: $description =~ s/#//g;
71: print "$date $booking $debit $credit $amount " .
1.1 schwarze 72: "$description\n";
73: }
74: }
75:
1.10 schwarze 76: sub import_chase_credit ($$$) {
77: my ($account, $csv_account, $line) = @_;
78: my ($trans_date, $post_date, $description, $category,
79: $type, $amount) = split /,/, $line;
80: my ($debit, $credit);
81: $post_date =~ s#(\d+)/(\d+)/(\d+)#$3$1$2#;
82: ($amount, $debit, $credit) =
83: get_accounts_by_amount_sign($amount, $account,
84: $csv_account);
85: return ($post_date, $amount, $debit, $credit, $description);
86: }
87:
88: sub import_capital_one_credit ($$$) {
89: my ($account, $csv_account, $line) = @_;
90: my ($trans_date, $post_date, $card_num,
91: $description, $category, $csv_debit,
92: $csv_credit) = split /,/, $line;
93: $post_date =~ s/(\d+)-(\d+)-(\d+)/$1$2$3/;
94: my ($amount, $debit, $credit) =
95: get_accounts_by_csv_col($account, $csv_account,
96: $csv_debit, $csv_credit);
97: return ($post_date, $amount, $debit, $credit, $description);
98: }
99:
100: sub import_optum_hsa ($$$) {
101: my ($account, $csv_account, $line) = @_;
102: my ($date, $description, $amount,
103: $type) = split /,/, $line;
104: my ($debit, $credit);
105: $date =~ s/(\d+)-(\d+)-(\d+)/$1$2$3/;
106: $amount =~ s/\$//;
107: ($amount, $debit, $credit) =
108: get_accounts_by_amount_sign($amount, $account,
109: $csv_account);
110: return ($date, $amount, $debit, $credit, $description);
111: }
112:
1.11 ! schwarze 113: sub import_sparkasse_camt ($$$) {
! 114: my ($account, $csv_account, $line) = @_;
! 115: my @fields;
! 116: $_ = $line;
! 117: push @fields, $1 while s/"([^"]*)";?//;
! 118: $_ eq "" or die "CAMT parse error before $_ in $line";
! 119: @fields == 17 or die "not 17 but @fields fields: $line";
! 120: $fields[1] =~ s/^(\d\d)\.(\d\d)\.(\d\d)$/20$3$2$1/
! 121: or die "date parse error: $line";
! 122: $fields[14] =~ s/,/./;
! 123: return $fields[1],
! 124: get_accounts_by_amount_sign($fields[14], $account, $csv_account),
! 125: (join ' ', $fields[11], $fields[4]);
! 126: }
! 127:
1.10 schwarze 128: sub get_accounts_by_amount_sign ($$$) {
129: my ($amount, $account, $csv_account) = @_;
130: my ($debit, $credit);
131: if ($amount <= 0) {
132: $amount = substr $amount, 1;
133: $credit = $csv_account;
134: $debit = $account;
135: } else {
136: $debit = $csv_account;
137: $credit = $account;
1.5 schwarze 138: }
1.10 schwarze 139: return ($amount, $debit, $credit);
1.5 schwarze 140: }
1.9 schwarze 141:
1.10 schwarze 142: sub get_accounts_by_csv_col ($$$$) {
143: my ($account, $csv_account, $csv_debit, $csv_credit) = @_;
144: my ($amount, $debit, $credit);
145: if ($csv_debit eq "") {
146: $amount = $csv_credit;
147: $credit = $account;
148: $debit = $csv_account;
149: } else {
150: $amount = $csv_debit;
151: $credit = $csv_account;
152: $debit = $account;
153: }
154: return ($amount, $debit, $credit);
1.9 schwarze 155: }
156:
157: sub usage () {
1.10 schwarze 158: printf STDERR "usage: %s -I accountname csvfilename\n", $0;
1.9 schwarze 159: exit 1;
160: }
161:
1.1 schwarze 162: # === MAIN PROGRAM =====================================================
163:
1.10 schwarze 164: my ($csv_account, $fn, $in, $account_name, %accounts, %bookings, @compiled);
1.9 schwarze 165: getopts 'I:' or usage;
166: if ($opt_I) {
1.10 schwarze 167: $account_name = $opt_I;
168: $fn = "import_" . $account_name . ".txt";
1.9 schwarze 169: open $in, $fn or die "$fn: $!";
1.1 schwarze 170: } else {
1.9 schwarze 171: usage;
172: }
173: while (<$in>) {
174: chomp;
175: next if /^(?:#|$)/;
176: my $line = $_;
177: if (/^ACCOUNT\s+(\d+)$/) {
178: $csv_account and die "duplicate ACCOUNT line: $1";
179: $csv_account = $1;
180: next;
181: }
1.11 ! schwarze 182: /^(.*)[,;]\s+(\d+)\s+(\S+)$/ or
1.9 schwarze 183: die "$fn import parse error: $line";
184: my ($reg, $account, $booking) = ($1, $2, $3);
1.11 ! schwarze 185: if ($account_name eq 'sparkasse_camt') {
! 186: $reg =~ s/(?:^|(?<=;))(?:$|(?=;))/"[^"]*"/g;
! 187: } else {
! 188: $reg =~ s/(?:^|(?<=,))(?:$|(?=,))/[^,]*/g;
! 189: }
1.9 schwarze 190: $reg = qr/$reg/;
191: push @compiled, $reg;
192: $bookings{$reg} = $booking;
193: $accounts{$reg} = $account;
1.1 schwarze 194: }
1.9 schwarze 195: close $in;
196: $csv_account or die "no ACCOUNT line in $fn";
1.10 schwarze 197: import_account($account_name, \%accounts, \%bookings,
198: \@compiled, $csv_account);
CVSweb