Parse-PayPal-TxDetailReport-Old

 view release on metacpan or  search on metacpan

lib/Parse/PayPal/TxDetailReport/Old.pm  view on Meta::CPAN

    }
}

$SPEC{parse_paypal_old_txdetail_report} = {
    v => 1.1,
    summary => 'Parse PayPal transaction detail report (older version, 2015 and earlier) into data structure',
    description => <<'_',

The result will be a hashref. The main key is `transactions` which will be an
arrayref of hashrefs.

Dates will be converted into Unix timestamps.

_
    args => {
        file => {
            schema => 'filename*',
            description => <<'_',

File can all be in tab-separated or comma-separated (CSV) format.

_
            pos => 0,
        },
        string => {
            schema => ['str*'],
            description => <<'_',

Instead of `file`, you can alternatively provide the file content in `string`.

_
        },
        format => {
            schema => ['str*', in=>[qw/tsv csv/]],
            description => <<'_',

If unspecified, will be deduced from the first filename's extension (/csv/ for
CSV, or /txt|tsv/ for tab-separated).

_
        },
        date_format => {
            schema => ['str*', in=>['MM/DD/YYYY', 'DD/MM/YYYY']],
            default => 'MM/DD/YYYY',
        },
    },
    args_rels => {
        req_one => ['file', 'string'],
    },
};
sub parse_paypal_old_txdetail_report {
    my %args = @_;

    my $format = $args{format};
    my $date_format = $args{date_format} // 'MM/DD/YYYY';

    my $fh;
    my $file;
    if (defined(my $str = $args{string})) {
        require IO::Scalar;
        require String::BOM;

        if (!$format) {
            $format = $str =~ /\t/ ? 'tsv' : 'csv';
        }
        $str = String::BOM::strip_bom_from_string($str);
        $fh = IO::Scalar->new(\$str);
        $file = "string";
    } elsif (defined(my $file0 = $args{file})) {
        require File::BOM;

        if (!$format) {
            $format = $file0 =~ /\.(csv)\z/i ? 'csv' : 'tsv';
        }
        open $fh, "<:encoding(utf8):via(File::BOM)", $file0
            or return [500, "Can't open file '$file': $!"];
        $file = $file0;
    } else {
        return [400, "Please specify file (or string)"];
    }

    my $res = [200, "OK", {
        format => "txdetail_old",
        transactions => [],
    }];

    my $code_parse_row = sub {
        my ($rownum, $row) = @_;

        if ($rownum == 1) {
            unless (@$row > 10 && $row->[0] eq 'Date') {
                $res = [400, "Doesn't look like old transaction detail ".
                            "format, I expect first row to be column names ".
                            "and first column header to be Date"];
                goto RETURN_RES;
            }
            $res->[2]{_transaction_columns} = $row;
            return;
        }
        my $tx = {};
        my $txcols = $res->[2]{_transaction_columns};
        for (0..$#{$row}) {
            my $field = $txcols->[$_];
            if ($field =~ /Date$/ && $row->[$_]) {
                $tx->{$field} = _parse_date($date_format, $row->[$_]);
            } else {
                $tx->{$field} = $row->[$_];
            }
        }
        push @{ $res->[2]{transactions} }, $tx;
    };

    my $csv;
    if ($format eq 'csv') {
        require Text::CSV;
        $csv = Text::CSV->new({binary=>1})
            or return [500, "Cannot use CSV: ".Text::CSV->error_diag];
    }

    if ($format eq 'csv') {
        my $rownum = 0;
        while (my $row = $csv->getline($fh)) {
            $rownum++;
            $code_parse_row->($rownum, $row);
        }
    } else {
        my $rownum = 0;
        while (my $line = <$fh>) {
            $rownum++;
            chomp($line);
            $code_parse_row->($rownum, [split /\t/, $line]);
        }
    }
    delete $res->[2]{_transaction_columns};



( run in 0.598 second using v1.01-cache-2.11-cpan-302cb4679cc )