File Coverage

blib/lib/Finance/Currency/Convert/KlikBCA.pm
Criterion Covered Total %
statement 46 54 85.1
branch 10 18 55.5
condition 2 2 100.0
subroutine 8 8 100.0
pod 2 2 100.0
total 68 84 80.9


line stmt bran cond sub pod time code
1             package Finance::Currency::Convert::KlikBCA;
2              
3             our $DATE = '2016-10-14'; # DATE
4             our $VERSION = '0.13'; # VERSION
5              
6 2     2   20963 use 5.010001;
  2         7  
7 2     2   7 use strict;
  2         4  
  2         44  
8 2     2   8 use warnings;
  2         3  
  2         61  
9 2     2   1882 use Log::Any::IfLOG '$log';
  2         24  
  2         10  
10              
11 2     2   121 use Exporter 'import';
  2         2  
  2         1649  
12             our @EXPORT_OK = qw(get_currencies convert_currency);
13              
14             our %SPEC;
15              
16             my $url = "http://www.bca.co.id/id/Individu/Sarana/Kurs-dan-Suku-Bunga/Kurs-dan-Kalkulator";
17              
18             $SPEC{':package'} = {
19             v => 1.1,
20             summary => 'Convert currency using KlikBCA',
21             description => <<"_",
22              
23             This module can extract currency rates from the BCA/KlikBCA (Bank Central Asia's
24             internet banking) website:
25              
26             $url
27              
28             Currently only conversions from a few currencies to Indonesian Rupiah (IDR) are
29             supported.
30              
31             _
32             };
33              
34             $SPEC{get_currencies} = {
35             v => 1.1,
36             summary => 'Extract data from KlikBCA/BCA page',
37             result => {
38             description => <<'_',
39             Will return a hash containing key `currencies`.
40              
41             The currencies is a hash with currency symbols as keys and prices as values.
42              
43             Tha values is a hash with these keys: `buy_bn` and `sell_bn` (Bank Note buy/sell
44             rates), `buy_er` and `sell_er` (e-Rate buy/sell rates), `buy_ttc` and `sell_ttc`
45             (Telegraphic Transfer Counter buy/sell rates).
46              
47             _
48             },
49             };
50             sub get_currencies {
51 2     2 1 1568 require Mojo::DOM;
52 2         103583 require Parse::Number::ID;
53              
54 2         1074 my %args = @_;
55              
56             #return [543, "Test parse failure response"];
57              
58 2         5 my $page;
59 2 100       7 if ($args{_page_content}) {
60 1         3 $page = $args{_page_content};
61             } else {
62 1         460 require Mojo::UserAgent;
63 1         116498 my $ua = Mojo::UserAgent->new;
64 1         11 my $tx = $ua->get($url);
65 1 50       3293412 unless ($tx->success) {
66 0         0 my $err = $tx->error;
67 0         0 return [500, "Can't retrieve BCA page ($url): ".
68             "$err->{code} - $err->{message}"];
69             }
70 1         19 $page = $tx->res->body;
71             }
72              
73 2         529 my $dom = Mojo::DOM->new($page);
74              
75 2         239349 my %currencies;
76 2         15 my $tbody = $dom->find("tbody.text-right")->[0];
77             $tbody->find("tr")->each(
78             sub {
79 28     28   6060 my $row0 = shift;
80             my $row = $row0->find("td")->map(
81 28         59 sub { $_->text })->to_array;
  196         11554  
82             #use DD; dd $row;
83 28 50       806 next unless $row->[0] =~ /\A[A-Z]{3}\z/;
84 28         64 $currencies{$row->[0]} = {
85             sell_er => Parse::Number::ID::parse_number_id(text=>$row->[1]),
86             buy_er => Parse::Number::ID::parse_number_id(text=>$row->[2]),
87             sell_ttc => Parse::Number::ID::parse_number_id(text=>$row->[3]),
88             buy_ttc => Parse::Number::ID::parse_number_id(text=>$row->[4]),
89             sell_bn => Parse::Number::ID::parse_number_id(text=>$row->[5]),
90             buy_bn => Parse::Number::ID::parse_number_id(text=>$row->[6]),
91             };
92             }
93 2         42227 );
94              
95 2 50       207 if (keys %currencies < 3) {
96 0         0 return [543, "Check: no/too few currencies found"];
97             }
98              
99             # XXX parse update dates (mtime_er, mtime_ttc, mtime_bn)
100 2         2568 [200, "OK", {currencies=>\%currencies}];
101             }
102              
103             # used for testing only
104             our $_get_res;
105              
106             $SPEC{convert_currency} = {
107             v => 1.1,
108             summary => 'Convert currency using KlikBCA',
109             description => <<'_',
110              
111             Currently can only handle conversion `to` IDR. Dies if given other currency.
112              
113             Will warn if failed getting currencies from the webpage.
114              
115             Currency rate is not cached (retrieved from the website every time). Employ your
116             own caching.
117              
118             Will return undef if no conversion rate is available for the requested currency.
119              
120             Use `get_currencies()`, which actually retrieves and scrapes the source web
121             page, if you need the more complete result.
122              
123             _
124             args => {
125             n => {
126             schema=>'float*',
127             req => 1,
128             pos => 0,
129             },
130             from => {
131             schema=>'str*',
132             req => 1,
133             pos => 1,
134             },
135             to => {
136             schema=>'str*',
137             req => 1,
138             pos => 2,
139             },
140             which => {
141             summary => 'Select which rate to use (default is average buy+sell for e-Rate)',
142             schema => ['str*', in=>[map { my $bsa = $_; map {"${bsa}_$_"} qw(bn er ttc) } qw(buy sell avg)]],
143             description => <<'_',
144              
145             {buy,sell,avg}_{bn,er,ttc}.
146              
147             _
148             default => 'avg_er',
149             pos => 3,
150             },
151             },
152             args_as => 'array',
153             result_naked => 1,
154             };
155             sub convert_currency {
156 2     2 1 1070 my ($n, $from, $to, $which) = @_;
157              
158 2   100     11 $which //= 'avg_er';
159              
160 2 50       7 if (uc($to) ne 'IDR') {
161 0         0 die "Currently only conversion to IDR is supported".
162             " (you asked for conversion to '$to')\n";
163             }
164              
165 2 50       6 unless ($_get_res) {
166 0         0 $_get_res = get_currencies();
167 0 0       0 unless ($_get_res->[0] == 200) {
168 0         0 warn "Can't get currencies: $_get_res->[0] - $_get_res->[1]\n";
169 0         0 return undef;
170             }
171             }
172              
173 2 50       6 my $c = $_get_res->[2]{currencies}{uc $from} or return undef;
174              
175 2         3 my $rate;
176 2 100       7 if ($which =~ /\Aavg_(.+)/) {
177 1         7 $rate = ($c->{"buy_$1"} + $c->{"sell_$1"}) / 2;
178             } else {
179 1         3 $rate = $c->{$which};
180             }
181              
182 2         7 $n * $rate;
183             }
184              
185             1;
186             # ABSTRACT: Convert currency using KlikBCA
187              
188             __END__
189              
190             =pod
191              
192             =encoding UTF-8
193              
194             =head1 NAME
195              
196             Finance::Currency::Convert::KlikBCA - Convert currency using KlikBCA
197              
198             =head1 VERSION
199              
200             This document describes version 0.13 of Finance::Currency::Convert::KlikBCA (from Perl distribution Finance-Currency-Convert-KlikBCA), released on 2016-10-14.
201              
202             =head1 SYNOPSIS
203              
204             use Finance::Currency::Convert::KlikBCA qw(convert_currency);
205              
206             printf "1 USD = Rp %.0f\n", convert_currency(1, 'USD', 'IDR');
207              
208             =head1 DESCRIPTION
209              
210              
211             This module can extract currency rates from the BCA/KlikBCA (Bank Central Asia's
212             internet banking) website:
213              
214             http://www.bca.co.id/id/Individu/Sarana/Kurs-dan-Suku-Bunga/Kurs-dan-Kalkulator
215              
216             Currently only conversions from a few currencies to Indonesian Rupiah (IDR) are
217             supported.
218              
219             =head1 FUNCTIONS
220              
221              
222             =head2 convert_currency($n, $from, $to, $which) -> any
223              
224             Convert currency using KlikBCA.
225              
226             Currently can only handle conversion C<to> IDR. Dies if given other currency.
227              
228             Will warn if failed getting currencies from the webpage.
229              
230             Currency rate is not cached (retrieved from the website every time). Employ your
231             own caching.
232              
233             Will return undef if no conversion rate is available for the requested currency.
234              
235             Use C<get_currencies()>, which actually retrieves and scrapes the source web
236             page, if you need the more complete result.
237              
238             This function is not exported by default, but exportable.
239              
240             Arguments ('*' denotes required arguments):
241              
242             =over 4
243              
244             =item * B<$from>* => I<str>
245              
246             =item * B<$n>* => I<float>
247              
248             =item * B<$to>* => I<str>
249              
250             =item * B<$which> => I<str> (default: "avg_er")
251              
252             Select which rate to use (default is average buy+sell for e-Rate).
253              
254             {buy,sell,avg}_{bn,er,ttc}.
255              
256             =back
257              
258             Return value: (any)
259              
260              
261             =head2 get_currencies() -> [status, msg, result, meta]
262              
263             Extract data from KlikBCA/BCA page.
264              
265             This function is not exported by default, but exportable.
266              
267             No arguments.
268              
269             Returns an enveloped result (an array).
270              
271             First element (status) is an integer containing HTTP status code
272             (200 means OK, 4xx caller error, 5xx function error). Second element
273             (msg) is a string containing error message, or 'OK' if status is
274             200. Third element (result) is optional, the actual result. Fourth
275             element (meta) is called result metadata and is optional, a hash
276             that contains extra information.
277              
278             Return value: (any)
279              
280              
281             Will return a hash containing key C<currencies>.
282              
283             The currencies is a hash with currency symbols as keys and prices as values.
284              
285             Tha values is a hash with these keys: C<buy_bn> and C<sell_bn> (Bank Note buy/sell
286             rates), C<buy_er> and C<sell_er> (e-Rate buy/sell rates), C<buy_ttc> and C<sell_ttc>
287             (Telegraphic Transfer Counter buy/sell rates).
288              
289             =head1 HOMEPAGE
290              
291             Please visit the project's homepage at L<https://metacpan.org/release/Finance-Currency-Convert-KlikBCA>.
292              
293             =head1 SOURCE
294              
295             Source repository is at L<https://github.com/perlancar/perl-Finance-Currency-Convert-KlikBCA>.
296              
297             =head1 BUGS
298              
299             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Finance-Currency-Convert-KlikBCA>
300              
301             When submitting a bug or request, please include a test-file or a
302             patch to an existing test-file that illustrates the bug or desired
303             feature.
304              
305             =head1 AUTHOR
306              
307             perlancar <perlancar@cpan.org>
308              
309             =head1 COPYRIGHT AND LICENSE
310              
311             This software is copyright (c) 2016 by perlancar@cpan.org.
312              
313             This is free software; you can redistribute it and/or modify it under
314             the same terms as the Perl 5 programming language system itself.
315              
316             =cut