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 )