line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package WebService::BR::Vindi; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
14036
|
use 5.010001; |
|
1
|
|
|
|
|
4
|
|
4
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
20
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
51
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our @ISA = qw(); |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# Preloaded methods go here. |
13
|
1
|
|
|
1
|
|
460
|
use MIME::Base64; |
|
1
|
|
|
|
|
574
|
|
|
1
|
|
|
|
|
55
|
|
14
|
1
|
|
|
1
|
|
215
|
use JSON::XS; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
use utf8; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# Configura as URLs de destino baseado na tag raiz |
18
|
|
|
|
|
|
|
$WebService::BR::Vindi::Target = { |
19
|
|
|
|
|
|
|
prod => { |
20
|
|
|
|
|
|
|
'*' => 'https://app.vindi.com.br:443/api/v1', |
21
|
|
|
|
|
|
|
}, |
22
|
|
|
|
|
|
|
}; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Error messages translator |
25
|
|
|
|
|
|
|
$WebService::BR::Vindi::ErrorMessages = { |
26
|
|
|
|
|
|
|
# First is the id |
27
|
|
|
|
|
|
|
global => { |
28
|
|
|
|
|
|
|
invalid_parameter => { |
29
|
|
|
|
|
|
|
__look_for__ => 'parameter', |
30
|
|
|
|
|
|
|
payment_company_code => 'Número do Cartão de Crédito parece ser inválido.', |
31
|
|
|
|
|
|
|
card_expiration => 'Data de validade do Cartão inválida: %s.', |
32
|
|
|
|
|
|
|
card_number => 'Número do Cartão %s.', |
33
|
|
|
|
|
|
|
merchant => 'Erro interno: %s.', |
34
|
|
|
|
|
|
|
}, |
35
|
|
|
|
|
|
|
}, |
36
|
|
|
|
|
|
|
}; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# |
39
|
|
|
|
|
|
|
# @param $type Tipo da requisição (nome do end-point) |
40
|
|
|
|
|
|
|
# @return $URL URL de destino a utilizar para a requisição |
41
|
|
|
|
|
|
|
# |
42
|
|
|
|
|
|
|
sub _getURL { |
43
|
|
|
|
|
|
|
my $class = shift; |
44
|
|
|
|
|
|
|
if ( exists( $WebService::BR::Vindi::Target->{$class->{target}}->{$_[0]} ) ) { |
45
|
|
|
|
|
|
|
return $WebService::BR::Vindi::Target->{$class->{target}}->{$_[0]}; |
46
|
|
|
|
|
|
|
} else { |
47
|
|
|
|
|
|
|
return $WebService::BR::Vindi::Target->{$class->{target}}->{'*'}."/$_[0]"; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# |
52
|
|
|
|
|
|
|
# Contrutor |
53
|
|
|
|
|
|
|
# |
54
|
|
|
|
|
|
|
sub new { |
55
|
|
|
|
|
|
|
my $self = shift; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
my $class = $#_ == 0 && ref($_[0]) eq 'HASH' ? $_[0] : { @_ }; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
require LWP::UserAgent; |
60
|
|
|
|
|
|
|
require HTTP::Request::Common; |
61
|
|
|
|
|
|
|
require IO::Socket::SSL; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
#IO::Socket::SSL::set_ctx_defaults( |
64
|
|
|
|
|
|
|
# SSL_verify_mode => 0, |
65
|
|
|
|
|
|
|
# SSL_version => "TLSv1" |
66
|
|
|
|
|
|
|
#); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
$class->{target} ||= 'prod'; |
69
|
|
|
|
|
|
|
$class->{timeout} ||= 120; |
70
|
|
|
|
|
|
|
$class->{charset} ||= 'UTF-8'; |
71
|
|
|
|
|
|
|
$class->{api_key} ||= ''; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
$class->{ua} ||= LWP::UserAgent->new( agent => 'WebService-BR-Vindi.pm', |
74
|
|
|
|
|
|
|
timeout => $class->{timeout} || 120 ); |
75
|
|
|
|
|
|
|
$class->{ua}->ssl_opts( verify_hostname => 0 ); |
76
|
|
|
|
|
|
|
$class->{ua}->env_proxy; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# JSON helper |
79
|
|
|
|
|
|
|
$class->{json} = JSON::XS->new->allow_nonref->utf8; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
bless( $class, $self ); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# |
86
|
|
|
|
|
|
|
# Make the next request (only the first next request) failsafe: if it fails, send it to the Message Bus. |
87
|
|
|
|
|
|
|
# |
88
|
|
|
|
|
|
|
sub failsafe { |
89
|
|
|
|
|
|
|
die 'You need to specify the "app" parameter to the constructor to use this feature (this is a proprietary implementation).' if !$_[0]->{app}; |
90
|
|
|
|
|
|
|
$_[0]->{failsafe} = 1; |
91
|
|
|
|
|
|
|
$_[0]; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub ua { shift->{ua} } |
95
|
|
|
|
|
|
|
sub json { shift->{json} } |
96
|
|
|
|
|
|
|
sub app { shift->{app} } |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# |
101
|
|
|
|
|
|
|
# Faz uma requisição |
102
|
|
|
|
|
|
|
# |
103
|
|
|
|
|
|
|
# @param $Endpoint Tipo da Requisição (equivalente à tag raiz, exemplo: "requisicao-transacao") |
104
|
|
|
|
|
|
|
# \%Params HASH a enviar com os dados (será convertido em JSON string). |
105
|
|
|
|
|
|
|
# @param $Endpoint Tipo da Requisição (equivalente à tag raiz, exemplo: "requisicao-transacao") |
106
|
|
|
|
|
|
|
# $Params JSON string a enviar com os dados. |
107
|
|
|
|
|
|
|
# |
108
|
|
|
|
|
|
|
sub post { |
109
|
|
|
|
|
|
|
my $class = shift; |
110
|
|
|
|
|
|
|
$class->{response} = $class->request( 'post', @_ ); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
sub get { |
113
|
|
|
|
|
|
|
my $class = shift; |
114
|
|
|
|
|
|
|
$class->{response} = $class->request( 'get', @_ ); |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
sub put { |
117
|
|
|
|
|
|
|
my $class = shift; |
118
|
|
|
|
|
|
|
$class->{response} = $class->request( 'put', @_ ); |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
sub delete { |
121
|
|
|
|
|
|
|
my $class = shift; |
122
|
|
|
|
|
|
|
$class->{response} = $class->request( 'delete', @_ ); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# |
127
|
|
|
|
|
|
|
# Custom helpers |
128
|
|
|
|
|
|
|
# |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# |
131
|
|
|
|
|
|
|
# Delete all objects of a given kind |
132
|
|
|
|
|
|
|
# |
133
|
|
|
|
|
|
|
# @param $endpoint Endpoint, optionally with a query filter specification of what objects to delete |
134
|
|
|
|
|
|
|
# |
135
|
|
|
|
|
|
|
sub delete_all { |
136
|
|
|
|
|
|
|
my $class = shift; |
137
|
|
|
|
|
|
|
my $endpoint = shift; |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
my ( $object, $query ) = split( /\?/, $endpoint ); |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# Get objects that match the query |
142
|
|
|
|
|
|
|
my $all = $class->get( $endpoint ); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
my @deleted = (); |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# If we got data, delete one by one |
147
|
|
|
|
|
|
|
if ( $all && $all->{$object} && $#{$all->{$object}} > -1 ) { |
148
|
|
|
|
|
|
|
for my $row ( @{ $all->{$object} } ) { |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
warn "delete( $object/$row->{id} )..." if $class->{debug}; |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
my $res = $class->delete( "$object/$row->{id}" ); |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
if ( $res && ref( $res ) && $res->{ErrorStatus} ) { |
155
|
|
|
|
|
|
|
} else { |
156
|
|
|
|
|
|
|
push( @deleted, $row->{id} ); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
return { deleted => [ @deleted ] }; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# |
166
|
|
|
|
|
|
|
# Retorna resposata da última requisição como HASHREF |
167
|
|
|
|
|
|
|
# |
168
|
|
|
|
|
|
|
# @return \%Response |
169
|
|
|
|
|
|
|
# |
170
|
|
|
|
|
|
|
sub response { |
171
|
|
|
|
|
|
|
if ( $_[0]->{response}->is_success ) { |
172
|
|
|
|
|
|
|
$_[0]->{json}->decode( $_[0]->{response}->decoded_content ); |
173
|
|
|
|
|
|
|
} else { |
174
|
|
|
|
|
|
|
{ ErrorStatus => $_[0]->{response}->status_line }; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# |
179
|
|
|
|
|
|
|
# Retorna resposata da última requisição como HASHREF |
180
|
|
|
|
|
|
|
# |
181
|
|
|
|
|
|
|
# @return \%Response |
182
|
|
|
|
|
|
|
# |
183
|
|
|
|
|
|
|
sub responseAsJSON { |
184
|
|
|
|
|
|
|
if ( $_[0]->{response}->is_success ) { |
185
|
|
|
|
|
|
|
$_[0]->{response}->decoded_content; |
186
|
|
|
|
|
|
|
} else { |
187
|
|
|
|
|
|
|
$_[0]->{json}->encode( { ErrorStatus => $_[0]->{response}->status_line } ); |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# |
192
|
|
|
|
|
|
|
# Realiza uma requisição de dados. Uso interno. |
193
|
|
|
|
|
|
|
# |
194
|
|
|
|
|
|
|
# @see #get #post #put #delete |
195
|
|
|
|
|
|
|
# @param $Method get post etc |
196
|
|
|
|
|
|
|
# $Endpoint script name, relative |
197
|
|
|
|
|
|
|
# $Data Dados a enviar (em geral o JSON) |
198
|
|
|
|
|
|
|
# \%Headers Cabeçalhos a enviar (nenhum necessário em geral) |
199
|
|
|
|
|
|
|
# |
200
|
|
|
|
|
|
|
sub request { |
201
|
|
|
|
|
|
|
my $class = shift; |
202
|
|
|
|
|
|
|
my $Method = shift || 'get'; |
203
|
|
|
|
|
|
|
my $Endpoint = shift; |
204
|
|
|
|
|
|
|
my $Content = shift; |
205
|
|
|
|
|
|
|
my $Headers = shift || {}; |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Encode $Content in to JSON string if needed |
209
|
|
|
|
|
|
|
$Content = ref( $Content ) ? |
210
|
|
|
|
|
|
|
$class->{json}->encode( $Content ) : |
211
|
|
|
|
|
|
|
$Content; |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
( $Endpoint, my $QueryStr ) = split( /\?/, $Endpoint ); |
215
|
|
|
|
|
|
|
my $URL = $class->_getURL( $Endpoint ).( $QueryStr ? "?$QueryStr" : '' ); |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
warn "REQUEST [$URL]: ".$Content if $class->{debug}; |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
my $res; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# POST |
222
|
|
|
|
|
|
|
$res = $class->{ua}->$Method( |
223
|
|
|
|
|
|
|
$URL, |
224
|
|
|
|
|
|
|
# Content_Type => 'application/x-www-form-urlencoded', |
225
|
|
|
|
|
|
|
Content_Type => 'application/json', |
226
|
|
|
|
|
|
|
Content_Charset => 'text/json;charset=UTF-8', |
227
|
|
|
|
|
|
|
Authorization => "Basic ".MIME::Base64::encode_base64( $class->{api_key} ), |
228
|
|
|
|
|
|
|
%{$Headers}, |
229
|
|
|
|
|
|
|
Content => $Content, |
230
|
|
|
|
|
|
|
); |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# Debug only |
233
|
|
|
|
|
|
|
warn "RESPONSE CODE: ".$res->status_line if $class->{debug}; |
234
|
|
|
|
|
|
|
warn "RESPOSSE DATA: ".$res->decoded_content if $class->{debug}; |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# return $res; |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# Sucesso |
242
|
|
|
|
|
|
|
if ( $res->is_success ) { |
243
|
|
|
|
|
|
|
$class->{failsafe} = 0; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
return $class->translateErrors( $class->{json}->decode( $res->decoded_content ) ); |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# Erro |
248
|
|
|
|
|
|
|
} else { |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# Send it to Message Queue if on failsafe mode |
251
|
|
|
|
|
|
|
if ( $class->{failsafe} ) { |
252
|
|
|
|
|
|
|
$class->app->message->post( |
253
|
|
|
|
|
|
|
'Vindi', |
254
|
|
|
|
|
|
|
{ METHOD => $Method, |
255
|
|
|
|
|
|
|
PATH => $Endpoint.( $QueryStr ? "?$QueryStr" : '' ), |
256
|
|
|
|
|
|
|
DATA => $Content || undef, |
257
|
|
|
|
|
|
|
LOG => $res->decoded_content || '', |
258
|
|
|
|
|
|
|
}); |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
my $err = { ErrorStatus => $res->status_line }; |
262
|
|
|
|
|
|
|
eval { |
263
|
|
|
|
|
|
|
my $json = $class->{json}->decode( $res->decoded_content ); |
264
|
|
|
|
|
|
|
$err = $class->translateErrors( $json ) if $json->{errors} && $json->{errors}->[0]; |
265
|
|
|
|
|
|
|
}; |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
$class->{failsafe} = 0; |
268
|
|
|
|
|
|
|
return $err; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# |
275
|
|
|
|
|
|
|
# Translete Vindi error messages into human friendly messages |
276
|
|
|
|
|
|
|
# |
277
|
|
|
|
|
|
|
sub translateErrors { |
278
|
|
|
|
|
|
|
my $class = shift; |
279
|
|
|
|
|
|
|
my $json = shift; |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# Internal/unknown error? |
282
|
|
|
|
|
|
|
if ( !ref( $json ) ) { |
283
|
|
|
|
|
|
|
warn $json if $class->{debug}; |
284
|
|
|
|
|
|
|
return { ErrorStatus => 'Erro ao comunicar com a operadora de Cobrança. Por favor verifique os dados passados e tente novamente mais tarde.' }; |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# Translate it |
287
|
|
|
|
|
|
|
} elsif ( $json->{errors} ) { |
288
|
|
|
|
|
|
|
my $map = $WebService::BR::Vindi::ErrorMessages->{global}; |
289
|
|
|
|
|
|
|
my $errors = {}; |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# Translate error by error |
292
|
|
|
|
|
|
|
for my $error ( @{ $json->{errors} } ) { |
293
|
|
|
|
|
|
|
# By "id" |
294
|
|
|
|
|
|
|
if ( # Error id found on error map |
295
|
|
|
|
|
|
|
$map->{ $error->{id} } && |
296
|
|
|
|
|
|
|
# Error object has the parameter it looks for |
297
|
|
|
|
|
|
|
$error->{ $map->{ $error->{id} }->{__look_for__} } && |
298
|
|
|
|
|
|
|
# The value of the parameter of the error has an entry on the map to translate it |
299
|
|
|
|
|
|
|
$map->{ $error->{id} }->{ $error->{ $map->{ $error->{id} }->{__look_for__} } } ) { |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
my $uid = $error->{id}.':'.$error->{ $map->{ $error->{id} }->{__look_for__} }; |
302
|
|
|
|
|
|
|
$errors->{ $uid } ||= { messages => [], error => $map->{ $error->{id} }->{ $error->{ $map->{ $error->{id} }->{__look_for__} } } }; |
303
|
|
|
|
|
|
|
push( @{ $errors->{ $uid }->{messages} }, $error->{message} ) if $#{$errors->{ $uid }->{messages}} == -1 || $errors->{ $uid }->{messages}->[-1] ne $error->{message}; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
# We have a translation |
308
|
|
|
|
|
|
|
if ( $#{ [ keys %{$errors} ] } > -1 ) { |
309
|
|
|
|
|
|
|
return { ErrorStatus => join( '; ', map { sprintf( $_->{error}, join( ', ', @{$_->{messages}} ) ) } values( %{$errors} ) ), |
310
|
|
|
|
|
|
|
errors => $json->{errors} }; |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# No error found on ErrorMessage map |
313
|
|
|
|
|
|
|
} else { |
314
|
|
|
|
|
|
|
return { ErrorStatus => "Erro ao comunicar com a operadora de Cobrança ($json->{errors}->[0]->{id}: $json->{errors}->[0]->{parameter}: $json->{errors}->[0]->{message}). Por favor verifique os dados passados e tente novamente mais tarde.", |
315
|
|
|
|
|
|
|
errors => $json->{errors} }; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# No errors, pass it on. |
319
|
|
|
|
|
|
|
} else { |
320
|
|
|
|
|
|
|
return $json; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# |
326
|
|
|
|
|
|
|
# Retorna o nome da badeira do cartão baseado no número |
327
|
|
|
|
|
|
|
# |
328
|
|
|
|
|
|
|
# @param $numero Numero do cartao |
329
|
|
|
|
|
|
|
# @return $bandeira Badeira do cartão, já no formato Vindi a ser enviado no JSON. |
330
|
|
|
|
|
|
|
# |
331
|
|
|
|
|
|
|
sub cardtype { |
332
|
|
|
|
|
|
|
my $number = $_[1]; |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
my $type = 'unknown'; |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
if ( $number =~ /^4[0-9]{12}(?:[0-9]{3})/ ) { |
337
|
|
|
|
|
|
|
$type = 'visa'; |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
} elsif ( $number =~ /^5[1-5][0-9]{14}/ ) { |
340
|
|
|
|
|
|
|
$type = 'mastercard'; |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
} elsif ( $number =~ /^3[47][0-9]{13}/ ) { |
343
|
|
|
|
|
|
|
$type = 'amex'; |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
} elsif ( $number =~ /^3(?:0[0-5]|[68][0-9])[0-9]{11}/ ) { |
346
|
|
|
|
|
|
|
$type = 'diners'; |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
} elsif ( $number =~ /^6(?:011|5[0-9]{2})[0-9]{12}/ ) { |
349
|
|
|
|
|
|
|
$type = 'discover'; |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
} elsif ( $number =~ /^(?:2131|1800|35\d{3})\d{11}/ ) { |
352
|
|
|
|
|
|
|
$type = 'jcb'; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
# TODO: "elo" e "aura" |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
return $type; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
1; |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
__END__ |