Parse-PayPal-TxFinderReport
view release on metacpan or search on metacpan
lib/Parse/PayPal/TxFinderReport.pm view on Meta::CPAN
Dates will be converted into Unix timestamps.
_
args => {
file => {
schema => ['filename*'],
description => <<'_',
File can be in tab-separated or comma-separated (CSV) format.
_
pos => 0,
},
string => {
schema => ['str*'],
description => <<'_',
Instead of `files`, you can alternatively provide the file contents in
`strings`.
_
},
format => {
schema => ['str*', in=>[qw/tsv csv/]],
description => <<'_',
If unspecified, will be deduced from the filename's extension (/csv/i for
CSV, or /txt|tsv|tab/i for tab-separated).
_
},
date_format => {
schema => ['str*', in=>['MM/DD/YYYY', 'DD/MM/YYYY']],
default => 'MM/DD/YYYY',
},
thousands_sep => {
schema => ['str*', in=>['.', '', ',']],
default => ',',
},
decimal_point => {
schema => ['str*', in=>['.', ',']],
default => '.',
},
},
args_rels => {
req_one => ['file', 'string'],
},
};
sub parse_paypal_txfinder_report {
my %args = @_;
my $format = $args{format};
my $date_format = $args{date_format} // 'MM/DD/YYYY';
my $thousands_sep = $args{thousands_sep} // ',';
my $decimal_point = $args{decimal_point} // '.';
my $handle;
my $file;
if (defined(my $str0 = $args{string})) {
require IO::Scalar;
require String::BOM;
if (!$format) {
$format = $str0 =~ /\t/ ? 'tsv' : 'csv';
}
my $str = String::BOM::strip_bom_from_string($str0);
$handle = IO::Scalar->new(\$str);
$file = "(string)";
} elsif (defined(my $file = $args{file})) {
require File::BOM;
if (!$format) {
$format = $file =~ /\.(csv)\z/i ? 'csv' : 'tsv';
}
open $handle, "<:encoding(utf8):via(File::BOM)", $file
or return [500, "Can't open file '$file': $!"];
} else {
return [400, "Please specify files (or strings)"];
}
my $res = [200, "OK", {
format => "txfinder",
transactions => [],
}];
my $column_names;
my $variant; # STR="Search Transaction Results", TF="Transaction Finder"
my $state; # header, data, postamble
my $code_parse_row = sub {
my ($row, $rownum) = @_;
if ($rownum == 1) {
return [412, "There are no rows"] unless @$row;
if ($row->[0] eq 'Search Transactions Results') {
$variant = 'STR';
} elsif ($row->[0] eq 'Transaction Finder') {
$variant = 'TF';
} else {
return [400, "Doesn't find signature in first row"];
}
$state = 'header';
return;
}
if ($state eq 'postamble') {
return $res;
}
if (!@$row || @$row == 1 && $row->[0] eq '') {
if ($state eq 'header') {
$state = 'data';
} elsif ($state eq 'data') {
$state = 'postamble';
}
return;
}
if ($state eq 'header') {
# set column names as the last row in header
$column_names = $row;
return;
}
if ($state eq 'data') {
return if $row->[0] eq 'Total';
my $hash = {};
for (0..@$row) {
my $key = $column_names->[$_] // "";
last unless length $key;
my $v;
if ($key =~ /^Date$/) {
$v = _parse_date($date_format, $row->[$_]);
} elsif ($key =~ /Amount|Fee/) {
$v = _parse_num($thousands_sep, $decimal_point, $row->[$_]);
} else {
$v = $row->[$_];
}
$hash->{$key} = $v;
}
push @{ $res->[2]{transactions} }, $hash;
( run in 2.145 seconds using v1.01-cache-2.11-cpan-c966e8aa7e8 )