br-utils 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +446 -22
  3. data/lib/brazilian-utils/area-code-utils.rb +60 -0
  4. data/lib/brazilian-utils/bank-account-utils.rb +82 -0
  5. data/lib/brazilian-utils/bank-utils.rb +61 -0
  6. data/lib/brazilian-utils/boleto-utils.rb +139 -0
  7. data/lib/brazilian-utils/caepf-utils.rb +91 -0
  8. data/lib/brazilian-utils/cbo-utils.rb +74 -0
  9. data/lib/brazilian-utils/cei-utils.rb +79 -0
  10. data/lib/brazilian-utils/cep-utils.rb +25 -1
  11. data/lib/brazilian-utils/certidao-utils.rb +171 -0
  12. data/lib/brazilian-utils/cfop-utils.rb +74 -0
  13. data/lib/brazilian-utils/cnae-utils.rb +104 -0
  14. data/lib/brazilian-utils/cnh-utils.rb +53 -0
  15. data/lib/brazilian-utils/cno-utils.rb +76 -0
  16. data/lib/brazilian-utils/cnpj-utils.rb +125 -12
  17. data/lib/brazilian-utils/cns-utils.rb +110 -0
  18. data/lib/brazilian-utils/cpf-utils.rb +13 -0
  19. data/lib/brazilian-utils/credit-card-utils.rb +47 -0
  20. data/lib/brazilian-utils/csosn-utils.rb +55 -0
  21. data/lib/brazilian-utils/cst-utils.rb +103 -0
  22. data/lib/brazilian-utils/currency-utils.rb +347 -228
  23. data/lib/brazilian-utils/data/area_codes.json +676 -0
  24. data/lib/brazilian-utils/data/banks.json +357 -0
  25. data/lib/brazilian-utils/data/cbo.json +1 -0
  26. data/lib/brazilian-utils/data/cfop.json +1 -0
  27. data/lib/brazilian-utils/data/cnae.json +1 -0
  28. data/lib/brazilian-utils/data/csosn.json +42 -0
  29. data/lib/brazilian-utils/data/cst.json +294 -0
  30. data/lib/brazilian-utils/data/legal_nature.json +900 -0
  31. data/lib/brazilian-utils/data/municipalities.json +1 -0
  32. data/lib/brazilian-utils/data/ncm.json +1 -0
  33. data/lib/brazilian-utils/data/states.json +218 -0
  34. data/lib/brazilian-utils/date-utils.rb +504 -256
  35. data/lib/brazilian-utils/iban-utils.rb +120 -0
  36. data/lib/brazilian-utils/ie-utils.rb +84 -0
  37. data/lib/brazilian-utils/legal-nature-utils.rb +238 -235
  38. data/lib/brazilian-utils/legal-process-utils.rb +31 -3
  39. data/lib/brazilian-utils/license-plate-utils.rb +21 -5
  40. data/lib/brazilian-utils/municipality-utils.rb +58 -0
  41. data/lib/brazilian-utils/ncm-utils.rb +91 -0
  42. data/lib/brazilian-utils/nfe-key-utils.rb +158 -0
  43. data/lib/brazilian-utils/number-utils.rb +123 -0
  44. data/lib/brazilian-utils/passport-utils.rb +65 -0
  45. data/lib/brazilian-utils/phone-utils.rb +491 -280
  46. data/lib/brazilian-utils/pis-utils.rb +16 -1
  47. data/lib/brazilian-utils/pix-key-utils.rb +70 -0
  48. data/lib/brazilian-utils/pix-payload-utils.rb +253 -0
  49. data/lib/brazilian-utils/registro-profissional-utils.rb +112 -0
  50. data/lib/brazilian-utils/renavam-utils.rb +14 -0
  51. data/lib/brazilian-utils/state-utils.rb +105 -0
  52. data/lib/brazilian-utils/text-utils.rb +105 -0
  53. data/lib/brazilian-utils/vin-utils.rb +46 -0
  54. data/lib/brazilian-utils/voter-id-utils.rb +36 -0
  55. metadata +39 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7410285ed2d94f3143069921599888b0c3c4055be41f25454e32e4e8f61a38f3
4
- data.tar.gz: 4e6fb1f71012f46622c7a3e4dc78bf26eaa7ac864d7122f1c1ece3bc912bb94e
3
+ metadata.gz: 1c2e9ee6353f18f2494f431e3201e35e383fba59e408f91cd14403bdb15bf557
4
+ data.tar.gz: a4bea9b7cafb5c06357b9cd979f8175bd4626d47d01a184060768ffc15fa1ddc
5
5
  SHA512:
6
- metadata.gz: 2f3644c35d9e2332c02efefe4736ca7b0faab1c342edd5390ff706ba03b1773f7f52680e233010643de5a4077b6b55c5e246228a1485094427587a32cbc595ef
7
- data.tar.gz: 7d6813dd96f7b6f0db6953c014ecb9609a33e95666ccee310deab668767c7fe92c677c7b6b669661a629fcd056316b670831e131864f90d942fbc178c56bc79b
6
+ metadata.gz: 0f887d1e9ef322f6e4984f72a92cbf28cb0119baa67d8f580c2d0b332d8a36f6a0aa6b5eb914fa9d5287e2c20b181cd4755facc501e5494f25c78361bf5340d3
7
+ data.tar.gz: 20a36907438077ab108aa96b874c429b4bea1d0d284f7e1fe896de93dba1176e5e04b52a0347a08c3e174def4ae2674172d72866fd7f4ab88c1b118a7e7d21fa
data/README.md CHANGED
@@ -17,18 +17,45 @@ Utilitários para trabalhar com formatos de dados brasileiros:
17
17
 
18
18
  - **CPF** - Validação, formatação e geração
19
19
  - **CNH** - Validação de Carteira Nacional de Habilitação
20
- - **CNPJ** - Validação, formatação e geração
20
+ - **CNS** - Validação e formatação do Cartão Nacional de Saúde
21
+ - **Passaporte** - Validação, formatação e geração de números de passaporte
22
+ - **Certidão de Registro Civil** - Validação e extração de dados da matrícula (nascimento/casamento/óbito)
23
+ - **Registro Profissional** - Validação de OAB, CRM, CRO, CRP e CRC
24
+ - **CNPJ** - Validação, formatação e geração (v1 numérico e v2 alfanumérico)
25
+ - **Inscrição Estadual (IE)** - Validação por UF
21
26
  - **CEP** - Validação, formatação e busca via API ViaCEP
22
27
  - **Moeda** - Formatação de Real (R$) e conversão para extenso
23
- - **Data** - Verificação de feriados e conversão para texto
28
+ - **Bancos** - Consulta de instituições financeiras (código COMPE/ISPB)
29
+ - **Conta Bancária** - Validação estrutural de agência e conta
30
+ - **IBAN** - Validação, formatação e extração de dados do IBAN brasileiro
31
+ - **Cartão de Crédito/Débito** - Validação via algoritmo de Luhn
32
+ - **Chave Pix** - Identificação e validação de chaves Pix (CPF/CNPJ/email/telefone/EVP)
33
+ - **Payload Pix** - Validação, leitura e geração de BR Code (Pix Copia e Cola)
34
+ - **Data** - Verificação de feriados, dias úteis e conversão para texto
24
35
  - **Email** - Validação (RFC 5322)
25
36
  - **Natureza Jurídica** - Validação de códigos oficiais
26
37
  - **Processos Judiciais** - Validação, formatação e geração
38
+ - **CAEPF** - Validação, formatação e extração de dados
39
+ - **CNO** - Validação e formatação do Cadastro Nacional de Obras
40
+ - **CEI** - Validação e formatação de CEI
41
+ - **CBO** - Validação e consulta da Classificação Brasileira de Ocupações
42
+ - **CFOP** - Validação e consulta do Código Fiscal de Operações e Prestações
43
+ - **CNAE** - Validação, formatação e consulta de atividade econômica
44
+ - **NCM** - Validação e formatação da Nomenclatura Comum do Mercosul
45
+ - **CSOSN** - Validação de código de situação da operação no Simples Nacional
46
+ - **CST** - Validação de Código de Situação Tributária (ICMS/IPI/PIS-COFINS)
27
47
  - **Placas de Veículos** - Validação e conversão (antigo/Mercosul)
48
+ - **VIN/Chassi** - Validação de número de chassi (VIN)
28
49
  - **Telefone** - Validação e formatação (móvel/fixo)
29
50
  - **PIS** - Validação, formatação e geração (PIS/PASEP)
30
51
  - **RENAVAM** - Validação de registro de veículos
31
52
  - **Título de Eleitor** - Validação, formatação e geração
53
+ - **DDD** - Consulta de código de área por estado
54
+ - **Estados (UF)** - Consulta de estado, região e fuso horário
55
+ - **Municípios** - Consulta de municípios por código IBGE
56
+ - **Chave de Acesso NF-e/DF-e** - Validação, formatação e extração de dados
57
+ - **Números por Extenso** - Conversão de números para texto
58
+ - **Texto** - Capitalização e remoção de acentos
32
59
 
33
60
  ### 💾 Instalação
34
61
 
@@ -49,36 +76,193 @@ BrazilianUtils::CPFUtils.is_valid('11144477735') # => true
49
76
  BrazilianUtils::CPFUtils.format_cpf('11144477735') # => "111.444.777-35"
50
77
  BrazilianUtils::CPFUtils.generate # => "12345678901"
51
78
 
79
+ # CNS (Cartão Nacional de Saúde)
80
+ require 'brazilian-utils/cns-utils'
81
+ BrazilianUtils::CNSUtils.is_valid('123456789010000') # => true
82
+ BrazilianUtils::CNSUtils.format('123456789010001') # => "123 4567 8901 0001"
83
+
84
+ # Passaporte
85
+ require 'brazilian-utils/passport-utils'
86
+ BrazilianUtils::PassportUtils.is_valid('CL125167') # => true
87
+ BrazilianUtils::PassportUtils.format('acd12736') # => "ACD12736"
88
+ BrazilianUtils::PassportUtils.generate # => "LB809567"
89
+
90
+ # Certidão de Registro Civil
91
+ require 'brazilian-utils/certidao-utils'
92
+ BrazilianUtils::CertidaoUtils.is_valid('10453901552013100012021000012321') # => true
93
+ BrazilianUtils::CertidaoUtils.format('10453901552013100012021000012321')
94
+ # => "104539 01 55 2013 1 00012 021 0000123 21"
95
+ BrazilianUtils::CertidaoUtils.get_info('10453901552013100012021000012321')
96
+ # => {registryCns: "104539", acervo: "01", service: "55", year: 2013, type: "birth", ...}
97
+
98
+ # Registro Profissional (OAB/CRM/CRO/CRP/CRC)
99
+ require 'brazilian-utils/registro-profissional-utils'
100
+ BrazilianUtils::RegistroProfissionalUtils.is_valid(value: '123456/SP', council: 'OAB') # => true
101
+ BrazilianUtils::RegistroProfissionalUtils.is_valid(value: '06/12345', council: 'CRP') # => true
102
+
52
103
  # CNPJ
53
104
  require 'brazilian-utils/cnpj-utils'
54
105
  BrazilianUtils::CNPJUtils.is_valid('34665388000161') # => true
55
106
  BrazilianUtils::CNPJUtils.format_cnpj('34665388000161') # => "34.665.388/0001-61"
107
+ # CNPJ v2 (alfanumérico, IN RFB 2.119)
108
+ BrazilianUtils::CNPJUtils.valid?('12ABC345000188', version: 2) # => true
109
+ BrazilianUtils::CNPJUtils.generate(version: 2) # => "12ABC345000188" (alfanumérico)
110
+
111
+ # Inscrição Estadual (IE)
112
+ require 'brazilian-utils/ie-utils'
113
+ BrazilianUtils::IEUtils.is_valid('110042490114', 'SP') # => true
114
+ BrazilianUtils::IEUtils.is_valid('12345678', 'RJ') # => true
56
115
 
57
116
  # CEP
58
117
  require 'brazilian-utils/cep-utils'
59
118
  BrazilianUtils::CEPUtils.format_cep('01310100') # => "01310-100"
60
119
  BrazilianUtils::CEPUtils.get_address('01310100') # => {...endereço completo...}
61
120
 
62
- # Telefone
63
- require 'brazilian-utils/phone-utils'
64
- BrazilianUtils::PhoneUtils.is_valid('11987654321') # => true
65
- BrazilianUtils::PhoneUtils.format('11987654321') # => "(11)98765-4321"
121
+ # Moeda
122
+ require 'brazilian-utils/currency-utils'
123
+ BrazilianUtils::CurrencyUtils.format_currency(1234.56) # => "1.234,56"
124
+ BrazilianUtils::CurrencyUtils.number_to_text(1234.56) # => "mil duzentos e trinta e quatro reais..."
125
+
126
+ # Bancos
127
+ require 'brazilian-utils/bank-utils'
128
+ BrazilianUtils::BankUtils.get_by_code('341') # => {code: "341", ispb: "60701190", name: "ITAÚ UNIBANCO S.A."}
129
+ BrazilianUtils::BankUtils.get_by_ispb('00000000') # => {code: "001", ispb: "00000000", name: "Banco do Brasil S.A."}
130
+
131
+ # Conta Bancária
132
+ require 'brazilian-utils/bank-account-utils'
133
+ BrazilianUtils::BankAccountUtils.is_valid(bankCode: '001', agency: '1234', account: '123456', digit: 'X') # => true
134
+
135
+ # IBAN
136
+ require 'brazilian-utils/iban-utils'
137
+ BrazilianUtils::IBANUtils.is_valid('BR1500000000000010932840814P2') # => true
138
+ BrazilianUtils::IBANUtils.format('BR1500000000000010932840814P2')
139
+ # => "BR15 0000 0000 0000 1093 2840 814P 2"
140
+
141
+ # Cartão de Crédito/Débito
142
+ require 'brazilian-utils/credit-card-utils'
143
+ BrazilianUtils::CreditCardUtils.is_valid('4111111111111111') # => true (Visa)
144
+ BrazilianUtils::CreditCardUtils.is_valid('4111111111111112') # => false (falha no dígito de Luhn)
145
+
146
+ # Chave Pix
147
+ require 'brazilian-utils/pix-key-utils'
148
+ BrazilianUtils::PixKeyUtils.is_valid('123.456.789-09') # => true
149
+ BrazilianUtils::PixKeyUtils.get_info('123.456.789-09') # => {type: "cpf", value: "12345678909"}
150
+
151
+ # Payload Pix (BR Code)
152
+ require 'brazilian-utils/pix-payload-utils'
153
+ payload = BrazilianUtils::PixPayloadUtils.generate(
154
+ key: '123.456.789-09', merchantName: 'Fulano de Tal', merchantCity: 'Brasília'
155
+ )
156
+ BrazilianUtils::PixPayloadUtils.is_valid(payload) # => true
157
+ BrazilianUtils::PixPayloadUtils.get_info(payload)
158
+ # => {merchantName: "Fulano de Tal", merchantCity: "Brasilia", pointOfInitiation: "static", key: "12345678909"}
159
+
160
+ # Data
161
+ require 'brazilian-utils/date-utils'
162
+ BrazilianUtils::DateUtils.is_holiday(Date.new(2024, 1, 1)) # => true
163
+ BrazilianUtils::DateUtils.is_business_day(Date.new(2024, 3, 4)) # => true
164
+ BrazilianUtils::DateUtils.add_business_days(Date.new(2024, 3, 1), 1) # => #<Date: 2024-03-04>
165
+
166
+ # CAEPF
167
+ require 'brazilian-utils/caepf-utils'
168
+ BrazilianUtils::CAEPFUtils.is_valid('293.118.610/001-84') # => true
169
+ BrazilianUtils::CAEPFUtils.format('29311861000184') # => "293.118.610/001-84"
170
+
171
+ # CNO
172
+ require 'brazilian-utils/cno-utils'
173
+ BrazilianUtils::CNOUtils.is_valid('11.084.01680/62') # => true
174
+ BrazilianUtils::CNOUtils.format('111130137368') # => "11.113.01373/68"
175
+
176
+ # CEI
177
+ require 'brazilian-utils/cei-utils'
178
+ BrazilianUtils::CEIUtils.is_valid('11.583.00249/85') # => true
179
+ BrazilianUtils::CEIUtils.format('277297118187') # => "27.729.71181/87"
180
+
181
+ # CBO
182
+ require 'brazilian-utils/cbo-utils'
183
+ BrazilianUtils::CBOUtils.is_valid('2124-05') # => true
184
+ BrazilianUtils::CBOUtils.get('212405') # => {code: "212405", description: "Analista de desenvolvimento de sistemas"}
185
+
186
+ # CFOP
187
+ require 'brazilian-utils/cfop-utils'
188
+ BrazilianUtils::CFOPUtils.is_valid('5102') # => true
189
+ BrazilianUtils::CFOPUtils.get('5102')[:description] # => "Venda de mercadoria adquirida ou recebida de terceiros..."
190
+
191
+ # CNAE
192
+ require 'brazilian-utils/cnae-utils'
193
+ BrazilianUtils::CNAEUtils.is_valid('6201-5/01') # => true
194
+ BrazilianUtils::CNAEUtils.get('6201501')
195
+ # => {code: "6201501", description: "DESENVOLVIMENTO DE PROGRAMAS DE COMPUTADOR SOB ENCOMENDA"}
196
+
197
+ # NCM
198
+ require 'brazilian-utils/ncm-utils'
199
+ BrazilianUtils::NCMUtils.is_valid('2203.00.00') # => true
200
+ BrazilianUtils::NCMUtils.format('84713012') # => "8471.30.12"
201
+
202
+ # CSOSN
203
+ require 'brazilian-utils/csosn-utils'
204
+ BrazilianUtils::CSOSNUtils.is_valid('101') # => true
205
+ BrazilianUtils::CSOSNUtils.get_description('101') # => "Tributada pelo Simples Nacional com permissão de crédito"
206
+
207
+ # CST (ICMS/IPI/PIS-COFINS)
208
+ require 'brazilian-utils/cst-utils'
209
+ BrazilianUtils::CSTUtils.is_valid('110') # => true (ICMS)
210
+ BrazilianUtils::CSTUtils.is_valid('07', tax: 'pis') # => true
66
211
 
67
212
  # Placa de Veículo
68
213
  require 'brazilian-utils/license-plate-utils'
69
214
  BrazilianUtils::LicensePlateUtils.is_valid('ABC1234') # => true
70
215
  BrazilianUtils::LicensePlateUtils.convert_to_mercosul('ABC1234') # => "ABC1C34"
71
216
 
217
+ # VIN (Chassi)
218
+ require 'brazilian-utils/vin-utils'
219
+ BrazilianUtils::VINUtils.is_valid('1HGCM82633A004352') # => true
220
+ BrazilianUtils::VINUtils.is_valid('1M8GDM9AXKP042788') # => true (dígito verificador X)
221
+
222
+ # Telefone
223
+ require 'brazilian-utils/phone-utils'
224
+ BrazilianUtils::PhoneUtils.is_valid('11987654321') # => true
225
+ BrazilianUtils::PhoneUtils.format('987654321') # => "98765-4321"
226
+ BrazilianUtils::PhoneUtils.format('11987654321', mask: :ddd) # => "(11) 98765-4321"
227
+
72
228
  # Título de Eleitor
73
229
  require 'brazilian-utils/voter-id-utils'
74
230
  BrazilianUtils::VoterIdUtils.is_valid_voter_id('690847092828') # => true
75
231
  BrazilianUtils::VoterIdUtils.format('690847092828') # => "6908 4709 28 28"
76
232
  BrazilianUtils::VoterIdUtils.generate('SP') # => "123456780140"
77
233
 
78
- # Moeda
79
- require 'brazilian-utils/currency-utils'
80
- BrazilianUtils::CurrencyUtils.format_currency(1234.56) # => "R$ 1.234,56"
81
- BrazilianUtils::CurrencyUtils.number_to_text(1234.56) # => "mil duzentos e trinta e quatro reais..."
234
+ # DDD
235
+ require 'brazilian-utils/area-code-utils'
236
+ BrazilianUtils::AreaCodeUtils.get_info('11')
237
+ # => {areaCode: 11, stateCode: "SP", stateName: "São Paulo", regionCode: "SE", regionName: "Sudeste", stateCodes: ["SP"]}
238
+ BrazilianUtils::AreaCodeUtils.list_by_state('SP') # => [11, 12, 13, 14, 15, 16, 17, 18, 19]
239
+
240
+ # Estados (UF)
241
+ require 'brazilian-utils/state-utils'
242
+ BrazilianUtils::StateUtils.get_by_ibge_code('35')
243
+ # => {code: "SP", name: "São Paulo", regionCode: "SE", regionName: "Sudeste", ibgeCode: 35}
244
+ BrazilianUtils::StateUtils.get_timezone('AM') # => "America/Manaus"
245
+
246
+ # Municípios
247
+ require 'brazilian-utils/municipality-utils'
248
+ BrazilianUtils::MunicipalityUtils.get_by_code('3550308') # => {code: "3550308", name: "São Paulo", stateCode: "SP"}
249
+ BrazilianUtils::MunicipalityUtils.list('DF') # => [{code: "5300108", name: "Brasília", stateCode: "DF"}]
250
+
251
+ # Chave de Acesso NF-e/DF-e
252
+ require 'brazilian-utils/nfe-key-utils'
253
+ BrazilianUtils::NfeKeyUtils.is_valid('35170458716523000119550010000000121000123458') # => true
254
+ BrazilianUtils::NfeKeyUtils.format('35170458716523000119550010000000121000123458')
255
+ # => "3517 0458 7165 2300 0119 5500 1000 0000 1210 0012 3458"
256
+
257
+ # Números por Extenso
258
+ require 'brazilian-utils/number-utils'
259
+ BrazilianUtils::NumberUtils.convert_to_words(123) # => "cento e vinte e três"
260
+ BrazilianUtils::NumberUtils.convert_to_words(1, gender: :feminine) # => "uma"
261
+
262
+ # Texto
263
+ require 'brazilian-utils/text-utils'
264
+ BrazilianUtils::TextUtils.capitalize('fulano de tal') # => "Fulano de Tal"
265
+ BrazilianUtils::TextUtils.remove_accents('São Paulo') # => "Sao Paulo"
82
266
  ```
83
267
 
84
268
  ### 📚 Documentação Detalhada
@@ -100,6 +284,34 @@ Para exemplos completos de cada utilitário, consulte a pasta [`examples/`](exam
100
284
  - [`PISUtils`](lib/brazilian-utils/pis-utils.rb) - PIS/PASEP
101
285
  - [`RENAVAMUtils`](lib/brazilian-utils/renavam-utils.rb) - RENAVAM
102
286
  - [`CNHUtils`](lib/brazilian-utils/cnh-utils.rb) - CNH
287
+ - [`TextUtils`](lib/brazilian-utils/text-utils.rb) - Capitalização e remoção de acentos
288
+ - [`NumberUtils`](lib/brazilian-utils/number-utils.rb) - Números por extenso
289
+ - [`StateUtils`](lib/brazilian-utils/state-utils.rb) - Estados brasileiros (UF)
290
+ - [`AreaCodeUtils`](lib/brazilian-utils/area-code-utils.rb) - DDDs
291
+ - [`BankUtils`](lib/brazilian-utils/bank-utils.rb) - Bancos (código COMPE/ISPB)
292
+ - [`BankAccountUtils`](lib/brazilian-utils/bank-account-utils.rb) - Contas bancárias
293
+ - [`MunicipalityUtils`](lib/brazilian-utils/municipality-utils.rb) - Municípios (código IBGE)
294
+ - [`CFOPUtils`](lib/brazilian-utils/cfop-utils.rb) - CFOP
295
+ - [`CNAEUtils`](lib/brazilian-utils/cnae-utils.rb) - CNAE
296
+ - [`CBOUtils`](lib/brazilian-utils/cbo-utils.rb) - CBO
297
+ - [`NCMUtils`](lib/brazilian-utils/ncm-utils.rb) - NCM
298
+ - [`CSOSNUtils`](lib/brazilian-utils/csosn-utils.rb) - CSOSN
299
+ - [`CSTUtils`](lib/brazilian-utils/cst-utils.rb) - CST (ICMS/IPI/PIS-COFINS)
300
+ - [`CEIUtils`](lib/brazilian-utils/cei-utils.rb) - CEI
301
+ - [`CNOUtils`](lib/brazilian-utils/cno-utils.rb) - CNO
302
+ - [`CNSUtils`](lib/brazilian-utils/cns-utils.rb) - Cartão Nacional de Saúde
303
+ - [`CAEPFUtils`](lib/brazilian-utils/caepf-utils.rb) - CAEPF
304
+ - [`CertidaoUtils`](lib/brazilian-utils/certidao-utils.rb) - Certidão de registro civil
305
+ - [`CreditCardUtils`](lib/brazilian-utils/credit-card-utils.rb) - Cartão de crédito/débito (Luhn)
306
+ - [`VINUtils`](lib/brazilian-utils/vin-utils.rb) - Chassi (VIN)
307
+ - [`PassportUtils`](lib/brazilian-utils/passport-utils.rb) - Passaporte
308
+ - [`IBANUtils`](lib/brazilian-utils/iban-utils.rb) - IBAN brasileiro
309
+ - [`NfeKeyUtils`](lib/brazilian-utils/nfe-key-utils.rb) - Chave de acesso NF-e/DF-e
310
+ - [`PixKeyUtils`](lib/brazilian-utils/pix-key-utils.rb) - Chave Pix
311
+ - [`PixPayloadUtils`](lib/brazilian-utils/pix-payload-utils.rb) - Payload Pix (BR Code)
312
+ - [`RegistroProfissionalUtils`](lib/brazilian-utils/registro-profissional-utils.rb) - OAB/CRM/CRO/CRP/CRC
313
+ - [`IEUtils`](lib/brazilian-utils/ie-utils.rb) - Inscrição Estadual (IE)
314
+ - [`BoletoUtils`](lib/brazilian-utils/boleto-utils.rb) - Boleto bancário
103
315
 
104
316
  ---
105
317
 
@@ -111,18 +323,45 @@ Utilities for working with Brazilian data formats:
111
323
 
112
324
  - **CPF** - Validation, formatting, and generation
113
325
  - **CNH** - Driver's license validation
114
- - **CNPJ** - Company tax ID validation, formatting, and generation
326
+ - **CNS** - National Health Card (Cartão Nacional de Saúde) validation and formatting
327
+ - **Passport** - Validation, formatting, and generation of passport numbers
328
+ - **Civil Registry Certificate** - Validation and field extraction for registration numbers (birth/marriage/death)
329
+ - **Professional Registration** - Validation for OAB, CRM, CRO, CRP, and CRC councils
330
+ - **CNPJ** - Company tax ID validation, formatting, and generation (v1 numeric and v2 alphanumeric)
331
+ - **State Registration (IE)** - Validation per state (UF)
115
332
  - **CEP** - Postal code validation, formatting, and address lookup (ViaCEP API)
116
333
  - **Currency** - Brazilian Real (R$) formatting and text conversion
117
- - **Date** - Holiday checking and date-to-text conversion
334
+ - **Banks** - Financial institution lookup (COMPE/ISPB code)
335
+ - **Bank Account** - Structural agency and account validation
336
+ - **IBAN** - Validation, formatting, and field extraction for the Brazilian IBAN
337
+ - **Credit/Debit Card** - Luhn algorithm validation
338
+ - **Pix Key** - Identification and validation of Pix keys (CPF/CNPJ/email/phone/EVP)
339
+ - **Pix Payload** - Validation, parsing, and generation of BR Code (Pix Copy and Paste)
340
+ - **Date** - Holiday checking, business-day calculations, and date-to-text conversion
118
341
  - **Email** - Email validation (RFC 5322)
119
342
  - **Legal Nature** - Official business entity code validation
120
343
  - **Legal Process** - Judicial process ID validation, formatting, and generation
344
+ - **CAEPF** - Validation, formatting, and field extraction
345
+ - **CNO** - National Construction Registry validation and formatting
346
+ - **CEI** - Validation and formatting
347
+ - **CBO** - Brazilian Occupation Classification validation and lookup
348
+ - **CFOP** - Tax Operation Code validation and lookup
349
+ - **CNAE** - Economic activity code validation, formatting, and lookup
350
+ - **NCM** - Mercosul Common Nomenclature validation and formatting
351
+ - **CSOSN** - Simples Nacional tax situation code validation
352
+ - **CST** - Tax Situation Code validation (ICMS/IPI/PIS-COFINS)
121
353
  - **License Plate** - Vehicle plate validation and format conversion (old/Mercosul)
354
+ - **VIN/Chassis** - Vehicle identification number (VIN) validation
122
355
  - **Phone** - Mobile and landline validation and formatting
123
356
  - **PIS** - Social security number validation, formatting, and generation
124
357
  - **RENAVAM** - Vehicle registration validation
125
358
  - **Voter ID** - Voter registration validation, formatting, and generation
359
+ - **Area Code** - DDD lookup by state
360
+ - **States (UF)** - State, region, and timezone lookup
361
+ - **Municipalities** - Municipality lookup by IBGE code
362
+ - **NF-e/DF-e Access Key** - Validation, formatting, and field extraction
363
+ - **Number to Words** - Convert numbers to text
364
+ - **Text** - Capitalization and accent removal
126
365
 
127
366
  ### 💾 Installation
128
367
 
@@ -143,36 +382,193 @@ BrazilianUtils::CPFUtils.is_valid('11144477735') # => true
143
382
  BrazilianUtils::CPFUtils.format_cpf('11144477735') # => "111.444.777-35"
144
383
  BrazilianUtils::CPFUtils.generate # => "12345678901"
145
384
 
385
+ # CNS (National Health Card)
386
+ require 'brazilian-utils/cns-utils'
387
+ BrazilianUtils::CNSUtils.is_valid('123456789010000') # => true
388
+ BrazilianUtils::CNSUtils.format('123456789010001') # => "123 4567 8901 0001"
389
+
390
+ # Passport
391
+ require 'brazilian-utils/passport-utils'
392
+ BrazilianUtils::PassportUtils.is_valid('CL125167') # => true
393
+ BrazilianUtils::PassportUtils.format('acd12736') # => "ACD12736"
394
+ BrazilianUtils::PassportUtils.generate # => "LB809567"
395
+
396
+ # Civil Registry Certificate
397
+ require 'brazilian-utils/certidao-utils'
398
+ BrazilianUtils::CertidaoUtils.is_valid('10453901552013100012021000012321') # => true
399
+ BrazilianUtils::CertidaoUtils.format('10453901552013100012021000012321')
400
+ # => "104539 01 55 2013 1 00012 021 0000123 21"
401
+ BrazilianUtils::CertidaoUtils.get_info('10453901552013100012021000012321')
402
+ # => {registryCns: "104539", acervo: "01", service: "55", year: 2013, type: "birth", ...}
403
+
404
+ # Professional Registration (OAB/CRM/CRO/CRP/CRC)
405
+ require 'brazilian-utils/registro-profissional-utils'
406
+ BrazilianUtils::RegistroProfissionalUtils.is_valid(value: '123456/SP', council: 'OAB') # => true
407
+ BrazilianUtils::RegistroProfissionalUtils.is_valid(value: '06/12345', council: 'CRP') # => true
408
+
146
409
  # CNPJ
147
410
  require 'brazilian-utils/cnpj-utils'
148
411
  BrazilianUtils::CNPJUtils.is_valid('34665388000161') # => true
149
412
  BrazilianUtils::CNPJUtils.format_cnpj('34665388000161') # => "34.665.388/0001-61"
413
+ # CNPJ v2 (alphanumeric, IN RFB 2.119)
414
+ BrazilianUtils::CNPJUtils.valid?('12ABC345000188', version: 2) # => true
415
+ BrazilianUtils::CNPJUtils.generate(version: 2) # => "12ABC345000188" (alphanumeric)
416
+
417
+ # State Registration (IE)
418
+ require 'brazilian-utils/ie-utils'
419
+ BrazilianUtils::IEUtils.is_valid('110042490114', 'SP') # => true
420
+ BrazilianUtils::IEUtils.is_valid('12345678', 'RJ') # => true
150
421
 
151
422
  # CEP (Postal Code)
152
423
  require 'brazilian-utils/cep-utils'
153
424
  BrazilianUtils::CEPUtils.format_cep('01310100') # => "01310-100"
154
425
  BrazilianUtils::CEPUtils.get_address('01310100') # => {...complete address...}
155
426
 
156
- # Phone
157
- require 'brazilian-utils/phone-utils'
158
- BrazilianUtils::PhoneUtils.is_valid('11987654321') # => true
159
- BrazilianUtils::PhoneUtils.format('11987654321') # => "(11)98765-4321"
427
+ # Currency
428
+ require 'brazilian-utils/currency-utils'
429
+ BrazilianUtils::CurrencyUtils.format_currency(1234.56) # => "1.234,56"
430
+ BrazilianUtils::CurrencyUtils.number_to_text(1234.56) # => "mil duzentos e trinta e quatro reais..."
431
+
432
+ # Banks
433
+ require 'brazilian-utils/bank-utils'
434
+ BrazilianUtils::BankUtils.get_by_code('341') # => {code: "341", ispb: "60701190", name: "ITAÚ UNIBANCO S.A."}
435
+ BrazilianUtils::BankUtils.get_by_ispb('00000000') # => {code: "001", ispb: "00000000", name: "Banco do Brasil S.A."}
436
+
437
+ # Bank Account
438
+ require 'brazilian-utils/bank-account-utils'
439
+ BrazilianUtils::BankAccountUtils.is_valid(bankCode: '001', agency: '1234', account: '123456', digit: 'X') # => true
440
+
441
+ # IBAN
442
+ require 'brazilian-utils/iban-utils'
443
+ BrazilianUtils::IBANUtils.is_valid('BR1500000000000010932840814P2') # => true
444
+ BrazilianUtils::IBANUtils.format('BR1500000000000010932840814P2')
445
+ # => "BR15 0000 0000 0000 1093 2840 814P 2"
446
+
447
+ # Credit/Debit Card
448
+ require 'brazilian-utils/credit-card-utils'
449
+ BrazilianUtils::CreditCardUtils.is_valid('4111111111111111') # => true (Visa)
450
+ BrazilianUtils::CreditCardUtils.is_valid('4111111111111112') # => false (Luhn check digit fails)
451
+
452
+ # Pix Key
453
+ require 'brazilian-utils/pix-key-utils'
454
+ BrazilianUtils::PixKeyUtils.is_valid('123.456.789-09') # => true
455
+ BrazilianUtils::PixKeyUtils.get_info('123.456.789-09') # => {type: "cpf", value: "12345678909"}
456
+
457
+ # Pix Payload (BR Code)
458
+ require 'brazilian-utils/pix-payload-utils'
459
+ payload = BrazilianUtils::PixPayloadUtils.generate(
460
+ key: '123.456.789-09', merchantName: 'Fulano de Tal', merchantCity: 'Brasília'
461
+ )
462
+ BrazilianUtils::PixPayloadUtils.is_valid(payload) # => true
463
+ BrazilianUtils::PixPayloadUtils.get_info(payload)
464
+ # => {merchantName: "Fulano de Tal", merchantCity: "Brasilia", pointOfInitiation: "static", key: "12345678909"}
465
+
466
+ # Date
467
+ require 'brazilian-utils/date-utils'
468
+ BrazilianUtils::DateUtils.is_holiday(Date.new(2024, 1, 1)) # => true
469
+ BrazilianUtils::DateUtils.is_business_day(Date.new(2024, 3, 4)) # => true
470
+ BrazilianUtils::DateUtils.add_business_days(Date.new(2024, 3, 1), 1) # => #<Date: 2024-03-04>
471
+
472
+ # CAEPF
473
+ require 'brazilian-utils/caepf-utils'
474
+ BrazilianUtils::CAEPFUtils.is_valid('293.118.610/001-84') # => true
475
+ BrazilianUtils::CAEPFUtils.format('29311861000184') # => "293.118.610/001-84"
476
+
477
+ # CNO
478
+ require 'brazilian-utils/cno-utils'
479
+ BrazilianUtils::CNOUtils.is_valid('11.084.01680/62') # => true
480
+ BrazilianUtils::CNOUtils.format('111130137368') # => "11.113.01373/68"
481
+
482
+ # CEI
483
+ require 'brazilian-utils/cei-utils'
484
+ BrazilianUtils::CEIUtils.is_valid('11.583.00249/85') # => true
485
+ BrazilianUtils::CEIUtils.format('277297118187') # => "27.729.71181/87"
486
+
487
+ # CBO
488
+ require 'brazilian-utils/cbo-utils'
489
+ BrazilianUtils::CBOUtils.is_valid('2124-05') # => true
490
+ BrazilianUtils::CBOUtils.get('212405') # => {code: "212405", description: "Analista de desenvolvimento de sistemas"}
491
+
492
+ # CFOP
493
+ require 'brazilian-utils/cfop-utils'
494
+ BrazilianUtils::CFOPUtils.is_valid('5102') # => true
495
+ BrazilianUtils::CFOPUtils.get('5102')[:description] # => "Venda de mercadoria adquirida ou recebida de terceiros..."
496
+
497
+ # CNAE
498
+ require 'brazilian-utils/cnae-utils'
499
+ BrazilianUtils::CNAEUtils.is_valid('6201-5/01') # => true
500
+ BrazilianUtils::CNAEUtils.get('6201501')
501
+ # => {code: "6201501", description: "DESENVOLVIMENTO DE PROGRAMAS DE COMPUTADOR SOB ENCOMENDA"}
502
+
503
+ # NCM
504
+ require 'brazilian-utils/ncm-utils'
505
+ BrazilianUtils::NCMUtils.is_valid('2203.00.00') # => true
506
+ BrazilianUtils::NCMUtils.format('84713012') # => "8471.30.12"
507
+
508
+ # CSOSN
509
+ require 'brazilian-utils/csosn-utils'
510
+ BrazilianUtils::CSOSNUtils.is_valid('101') # => true
511
+ BrazilianUtils::CSOSNUtils.get_description('101') # => "Tributada pelo Simples Nacional com permissão de crédito"
512
+
513
+ # CST (ICMS/IPI/PIS-COFINS)
514
+ require 'brazilian-utils/cst-utils'
515
+ BrazilianUtils::CSTUtils.is_valid('110') # => true (ICMS)
516
+ BrazilianUtils::CSTUtils.is_valid('07', tax: 'pis') # => true
160
517
 
161
518
  # License Plate
162
519
  require 'brazilian-utils/license-plate-utils'
163
520
  BrazilianUtils::LicensePlateUtils.is_valid('ABC1234') # => true
164
521
  BrazilianUtils::LicensePlateUtils.convert_to_mercosul('ABC1234') # => "ABC1C34"
165
522
 
523
+ # VIN (Chassis)
524
+ require 'brazilian-utils/vin-utils'
525
+ BrazilianUtils::VINUtils.is_valid('1HGCM82633A004352') # => true
526
+ BrazilianUtils::VINUtils.is_valid('1M8GDM9AXKP042788') # => true (check digit is X)
527
+
528
+ # Phone
529
+ require 'brazilian-utils/phone-utils'
530
+ BrazilianUtils::PhoneUtils.is_valid('11987654321') # => true
531
+ BrazilianUtils::PhoneUtils.format('987654321') # => "98765-4321"
532
+ BrazilianUtils::PhoneUtils.format('11987654321', mask: :ddd) # => "(11) 98765-4321"
533
+
166
534
  # Voter ID
167
535
  require 'brazilian-utils/voter-id-utils'
168
536
  BrazilianUtils::VoterIdUtils.is_valid_voter_id('690847092828') # => true
169
537
  BrazilianUtils::VoterIdUtils.format('690847092828') # => "6908 4709 28 28"
170
538
  BrazilianUtils::VoterIdUtils.generate('SP') # => "123456780140"
171
539
 
172
- # Currency
173
- require 'brazilian-utils/currency-utils'
174
- BrazilianUtils::CurrencyUtils.format_currency(1234.56) # => "R$ 1.234,56"
175
- BrazilianUtils::CurrencyUtils.number_to_text(1234.56) # => "mil duzentos e trinta e quatro reais..."
540
+ # Area Code (DDD)
541
+ require 'brazilian-utils/area-code-utils'
542
+ BrazilianUtils::AreaCodeUtils.get_info('11')
543
+ # => {areaCode: 11, stateCode: "SP", stateName: "São Paulo", regionCode: "SE", regionName: "Sudeste", stateCodes: ["SP"]}
544
+ BrazilianUtils::AreaCodeUtils.list_by_state('SP') # => [11, 12, 13, 14, 15, 16, 17, 18, 19]
545
+
546
+ # States (UF)
547
+ require 'brazilian-utils/state-utils'
548
+ BrazilianUtils::StateUtils.get_by_ibge_code('35')
549
+ # => {code: "SP", name: "São Paulo", regionCode: "SE", regionName: "Sudeste", ibgeCode: 35}
550
+ BrazilianUtils::StateUtils.get_timezone('AM') # => "America/Manaus"
551
+
552
+ # Municipalities
553
+ require 'brazilian-utils/municipality-utils'
554
+ BrazilianUtils::MunicipalityUtils.get_by_code('3550308') # => {code: "3550308", name: "São Paulo", stateCode: "SP"}
555
+ BrazilianUtils::MunicipalityUtils.list('DF') # => [{code: "5300108", name: "Brasília", stateCode: "DF"}]
556
+
557
+ # NF-e/DF-e Access Key
558
+ require 'brazilian-utils/nfe-key-utils'
559
+ BrazilianUtils::NfeKeyUtils.is_valid('35170458716523000119550010000000121000123458') # => true
560
+ BrazilianUtils::NfeKeyUtils.format('35170458716523000119550010000000121000123458')
561
+ # => "3517 0458 7165 2300 0119 5500 1000 0000 1210 0012 3458"
562
+
563
+ # Number to Words
564
+ require 'brazilian-utils/number-utils'
565
+ BrazilianUtils::NumberUtils.convert_to_words(123) # => "cento e vinte e três"
566
+ BrazilianUtils::NumberUtils.convert_to_words(1, gender: :feminine) # => "uma"
567
+
568
+ # Text
569
+ require 'brazilian-utils/text-utils'
570
+ BrazilianUtils::TextUtils.capitalize('fulano de tal') # => "Fulano de Tal"
571
+ BrazilianUtils::TextUtils.remove_accents('São Paulo') # => "Sao Paulo"
176
572
  ```
177
573
 
178
574
  ### 📚 Full Documentation
@@ -187,13 +583,41 @@ For detailed examples of each utility, check the [`examples/`](examples/) folder
187
583
  - [`LicensePlateUtils`](lib/brazilian-utils/license-plate-utils.rb) - Vehicle plates
188
584
  - [`VoterIdUtils`](lib/brazilian-utils/voter-id-utils.rb) - Voter IDs
189
585
  - [`CurrencyUtils`](lib/brazilian-utils/currency-utils.rb) - Currency formatting
190
- - [`DateUtils`](lib/brazilian-utils/date-utils.rb) - Holidays and date text
586
+ - [`DateUtils`](lib/brazilian-utils/date-utils.rb) - Holidays, business days, and date text
191
587
  - [`EmailUtils`](lib/brazilian-utils/email-utils.rb) - Email validation
192
588
  - [`LegalNatureUtils`](lib/brazilian-utils/legal-nature-utils.rb) - Legal nature codes
193
589
  - [`LegalProcessUtils`](lib/brazilian-utils/legal-process-utils.rb) - Legal process IDs
194
590
  - [`PISUtils`](lib/brazilian-utils/pis-utils.rb) - PIS/PASEP
195
591
  - [`RENAVAMUtils`](lib/brazilian-utils/renavam-utils.rb) - Vehicle registration
196
592
  - [`CNHUtils`](lib/brazilian-utils/cnh-utils.rb) - Driver's license
593
+ - [`TextUtils`](lib/brazilian-utils/text-utils.rb) - Capitalization and accent removal
594
+ - [`NumberUtils`](lib/brazilian-utils/number-utils.rb) - Numbers to words
595
+ - [`StateUtils`](lib/brazilian-utils/state-utils.rb) - Brazilian states (UF)
596
+ - [`AreaCodeUtils`](lib/brazilian-utils/area-code-utils.rb) - Area codes (DDD)
597
+ - [`BankUtils`](lib/brazilian-utils/bank-utils.rb) - Banks (COMPE/ISPB code)
598
+ - [`BankAccountUtils`](lib/brazilian-utils/bank-account-utils.rb) - Bank accounts
599
+ - [`MunicipalityUtils`](lib/brazilian-utils/municipality-utils.rb) - Municipalities (IBGE code)
600
+ - [`CFOPUtils`](lib/brazilian-utils/cfop-utils.rb) - CFOP
601
+ - [`CNAEUtils`](lib/brazilian-utils/cnae-utils.rb) - CNAE
602
+ - [`CBOUtils`](lib/brazilian-utils/cbo-utils.rb) - CBO
603
+ - [`NCMUtils`](lib/brazilian-utils/ncm-utils.rb) - NCM
604
+ - [`CSOSNUtils`](lib/brazilian-utils/csosn-utils.rb) - CSOSN
605
+ - [`CSTUtils`](lib/brazilian-utils/cst-utils.rb) - CST (ICMS/IPI/PIS-COFINS)
606
+ - [`CEIUtils`](lib/brazilian-utils/cei-utils.rb) - CEI
607
+ - [`CNOUtils`](lib/brazilian-utils/cno-utils.rb) - CNO
608
+ - [`CNSUtils`](lib/brazilian-utils/cns-utils.rb) - National Health Card
609
+ - [`CAEPFUtils`](lib/brazilian-utils/caepf-utils.rb) - CAEPF
610
+ - [`CertidaoUtils`](lib/brazilian-utils/certidao-utils.rb) - Civil registry certificate
611
+ - [`CreditCardUtils`](lib/brazilian-utils/credit-card-utils.rb) - Credit/debit card (Luhn)
612
+ - [`VINUtils`](lib/brazilian-utils/vin-utils.rb) - Chassis (VIN)
613
+ - [`PassportUtils`](lib/brazilian-utils/passport-utils.rb) - Passport
614
+ - [`IBANUtils`](lib/brazilian-utils/iban-utils.rb) - Brazilian IBAN
615
+ - [`NfeKeyUtils`](lib/brazilian-utils/nfe-key-utils.rb) - NF-e/DF-e access key
616
+ - [`PixKeyUtils`](lib/brazilian-utils/pix-key-utils.rb) - Pix key
617
+ - [`PixPayloadUtils`](lib/brazilian-utils/pix-payload-utils.rb) - Pix payload (BR Code)
618
+ - [`RegistroProfissionalUtils`](lib/brazilian-utils/registro-profissional-utils.rb) - OAB/CRM/CRO/CRP/CRC
619
+ - [`IEUtils`](lib/brazilian-utils/ie-utils.rb) - State registration (IE)
620
+ - [`BoletoUtils`](lib/brazilian-utils/boleto-utils.rb) - Bank slip (boleto)
197
621
 
198
622
  ---
199
623
 
@@ -251,7 +675,7 @@ Most utilities follow these patterns:
251
675
  - `generate(uf)` - Generate for specific state
252
676
 
253
677
  **Currency:**
254
- - `format_currency(value)` - Format as R$ X.XXX,XX
678
+ - `format_currency(value)` - Format as X.XXX,XX (pass `symbol: true` for "R$ X.XXX,XX")
255
679
  - `number_to_text(value)` - Convert to Brazilian Portuguese text
256
680
 
257
681
  **Date:**
@@ -0,0 +1,60 @@
1
+ require 'json'
2
+
3
+ module BrazilianUtils
4
+ # Utilities for looking up Brazilian area codes (DDD), sourced from the
5
+ # Anatel Plano Geral de Numeração.
6
+ module AreaCodeUtils
7
+ DATA_FILE = File.join(File.dirname(__FILE__), 'data', 'area_codes.json')
8
+
9
+ # @private
10
+ def self.load_data
11
+ @data ||= JSON.parse(File.read(DATA_FILE))
12
+ end
13
+
14
+ private_class_method :load_data
15
+
16
+ # @private
17
+ def self.to_symbolized(row)
18
+ {
19
+ areaCode: row['areaCode'],
20
+ stateCode: row['stateCode'],
21
+ stateName: row['stateName'],
22
+ regionCode: row['regionCode'],
23
+ regionName: row['regionName'],
24
+ stateCodes: row['stateCodes']
25
+ }
26
+ end
27
+
28
+ private_class_method :to_symbolized
29
+
30
+ # Returns the state and region a DDD (area code) belongs to.
31
+ #
32
+ # @param area_code [String, Integer]
33
+ # @return [Hash, nil]
34
+ def self.get_info(area_code)
35
+ return nil if area_code.nil?
36
+
37
+ str = area_code.to_s.strip
38
+ return nil unless str.match?(/\A\d+\z/)
39
+
40
+ row = load_data.find { |r| r['areaCode'] == str.to_i }
41
+ row && to_symbolized(row)
42
+ end
43
+
44
+ # Returns every DDD that serves a state, sorted ascending.
45
+ #
46
+ # @param state_code [String]
47
+ # @return [Array<Integer>]
48
+ def self.list_by_state(state_code)
49
+ return [] unless state_code.is_a?(String)
50
+
51
+ normalized = state_code.strip.upcase
52
+ return [] if normalized.empty?
53
+
54
+ load_data
55
+ .select { |r| r['stateCodes'].include?(normalized) }
56
+ .map { |r| r['areaCode'] }
57
+ .sort
58
+ end
59
+ end
60
+ end