File Coverage

blib/lib/Finance/Currency/Convert/KlikBCA.pm
Criterion Covered Total %
statement 43 51 84.3
branch 10 18 55.5
condition 2 2 100.0
subroutine 7 7 100.0
pod 2 2 100.0
total 64 80 80.0


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