FixFitid.pl

From GnuCash
Jump to: navigation, search
#!/usr/bin/perl
#
# A quick script to fix non unique FITID ids in HSBC ofx downloads
# makes a new unique id from the other details, so should match
# a new overlapping download on a later date.
#
# usage:
#  FixFitid.pl bad_file.ofx > new_file.ofx
#
# It writes to std out, do pipe the output somewhere.
use strict;
use warnings;
use Data::Dumper;
exit main(@ARGV);
 
our %seen_md5;
BEGIN {$/="</STMTTRN>"}
 
sub main{
    while (my $frag = <>)
    {
        my $href = parseDetails($frag);
        my $md5 = genMD5($href);
        $frag =  editFITID($frag,$md5);
        print $frag;
    }
}
 
 
sub parseDetails{
    my $fragment = shift;
    my %ret;
    foreach my $part (qw(TRNTYPE DTPOSTED TRNAMT NAME MEMO FITID)){
        if ($fragment =~ /<$part>(.*)<\/$part>/ )
        {
            $ret{$part} = $1;
        }
        else
        {
            $ret{$part} = "";
            next if $part eq "MEMO";
            print STDERR "Failed to find $part in '$fragment'";
        }
    }
    $ret{DTPOSTED} =~ s/^(\d{8}).*/$1/;
    return \%ret;
}
 
sub genMD5{
    my $href = shift;
    my $string = join(" # ",@$href{qw(TRNTYPE DTPOSTED TRNAMT NAME MEMO)});
    my $md5 = `echo '$string' | md5sum`;
    $md5 =~ s/^(\S+).*/$1/s;
    while ($seen_md5{$md5}){
        $md5 = `echo '$md5' | md5sum`;
        $md5 =~ s/^(\S+).*/$1/s;
        #Handle multiple purchases with identical info.
        print STDERR "Duplicate MD5. Same transaction on same day. Progressing MD5 to $md5";
    }
    $seen_md5{$md5}++;
    return $md5;
}
 
sub editFITID{
    my $fragment = shift;
    my $md5 = shift;
    $fragment =~ s/<FITID>.*<\/FITID>/<FITID>$md5<\/FITID>/;
    return $fragment
}