nfcom 0.1.2

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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +115 -0
  3. data/.ruby-version +1 -0
  4. data/CHANGELOG.md +66 -0
  5. data/LICENSE +21 -0
  6. data/README.md +280 -0
  7. data/Rakefile +22 -0
  8. data/examples/.env.example +41 -0
  9. data/examples/emitir_nota.rb +91 -0
  10. data/examples/rails_initializer.rb +72 -0
  11. data/lib/nfcom/builder/danfe_com.rb +564 -0
  12. data/lib/nfcom/builder/qrcode.rb +68 -0
  13. data/lib/nfcom/builder/signature.rb +156 -0
  14. data/lib/nfcom/builder/xml_builder.rb +362 -0
  15. data/lib/nfcom/client.rb +106 -0
  16. data/lib/nfcom/configuration.rb +134 -0
  17. data/lib/nfcom/errors.rb +27 -0
  18. data/lib/nfcom/helpers/consulta.rb +28 -0
  19. data/lib/nfcom/models/assinante.rb +146 -0
  20. data/lib/nfcom/models/destinatario.rb +138 -0
  21. data/lib/nfcom/models/emitente.rb +105 -0
  22. data/lib/nfcom/models/endereco.rb +123 -0
  23. data/lib/nfcom/models/fatura/codigo_de_barras/formato_44.rb +52 -0
  24. data/lib/nfcom/models/fatura/codigo_de_barras.rb +57 -0
  25. data/lib/nfcom/models/fatura.rb +172 -0
  26. data/lib/nfcom/models/item.rb +353 -0
  27. data/lib/nfcom/models/nota.rb +398 -0
  28. data/lib/nfcom/models/total.rb +60 -0
  29. data/lib/nfcom/parsers/autorizacao.rb +28 -0
  30. data/lib/nfcom/parsers/base.rb +30 -0
  31. data/lib/nfcom/parsers/consulta.rb +34 -0
  32. data/lib/nfcom/parsers/inutilizacao.rb +23 -0
  33. data/lib/nfcom/parsers/status.rb +23 -0
  34. data/lib/nfcom/utils/certificate.rb +109 -0
  35. data/lib/nfcom/utils/compressor.rb +47 -0
  36. data/lib/nfcom/utils/helpers.rb +141 -0
  37. data/lib/nfcom/utils/response_decompressor.rb +47 -0
  38. data/lib/nfcom/utils/xml_authorized.rb +29 -0
  39. data/lib/nfcom/utils/xml_cleaner.rb +68 -0
  40. data/lib/nfcom/validators/business_rules.rb +45 -0
  41. data/lib/nfcom/validators/schema_validator.rb +316 -0
  42. data/lib/nfcom/validators/xml_validator.rb +29 -0
  43. data/lib/nfcom/version.rb +5 -0
  44. data/lib/nfcom/webservices/autorizacao.rb +36 -0
  45. data/lib/nfcom/webservices/base.rb +96 -0
  46. data/lib/nfcom/webservices/consulta.rb +59 -0
  47. data/lib/nfcom/webservices/inutilizacao.rb +71 -0
  48. data/lib/nfcom/webservices/status.rb +64 -0
  49. data/lib/nfcom.rb +98 -0
  50. data/nfcom.gemspec +42 -0
  51. metadata +242 -0
@@ -0,0 +1,353 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nfcom
4
+ module Models
5
+ # Representa um item (serviço) da NF-COM
6
+ #
7
+ # Cada item correspone a um serviço de comunicação/telecomunicação
8
+ # prestado ao cliente, como plano de internet, TV por assinatura, etc.
9
+ #
10
+ # @example Adicionar item de internet à nota
11
+ # nota = Nfcom::Models::Nota.new
12
+ #
13
+ # nota.add_item(
14
+ # codigo_servico: '0303',
15
+ # descricao: 'Plano Fibra 100MB',
16
+ # classe_consumo: '0303',
17
+ # cfop: '5307',
18
+ # unidade: 'UN',
19
+ # quantidade: 1,
20
+ # valor_unitario: 99.90
21
+ # )
22
+ #
23
+ # @example Item com desconto
24
+ # nota.add_item(
25
+ # codigo_servico: '0303',
26
+ # descricao: 'Plano Fibra 200MB',
27
+ # classe_consumo: '0303',
28
+ # cfop: '5307',
29
+ # valor_unitario: 149.90,
30
+ # valor_desconto: 20.00 # Desconto promocional
31
+ # )
32
+ # # Valor total = 149.90 - 20.00 = 129.90
33
+ #
34
+ # @example Múltiplos serviços na mesma nota
35
+ # # Internet
36
+ # nota.add_item(
37
+ # codigo_servico: '0303',
38
+ # descricao: 'Internet 100MB',
39
+ # classe_consumo: '0303',
40
+ # cfop: '5307',
41
+ # valor_unitario: 99.90
42
+ # )
43
+ #
44
+ # # TV por assinatura
45
+ # nota.add_item(
46
+ # codigo_servico: '0304',
47
+ # descricao: 'TV Premium',
48
+ # classe_consumo: '0304',
49
+ # cfop: '5307',
50
+ # valor_unitario: 79.90
51
+ # )
52
+ #
53
+ # Códigos de Serviço (Telecomunicações):
54
+ # - '0303' - Serviço de Internet
55
+ # - '0304' - TV por Assinatura
56
+ # - '0305' - Telefonia
57
+ #
58
+ # Classes de Consumo (mesmos códigos):
59
+ # - '0303' - Internet
60
+ # - '0304' - TV
61
+ # - '0305' - Telefonia
62
+ #
63
+ # CFOPs comuns:
64
+ # - '5307' - Prestação de serviço de comunicação (dentro do estado)
65
+ # - '6307' - Prestação de serviço de comunicação (fora do estado)
66
+ #
67
+ # Atributos obrigatórios:
68
+ # - codigo_servico (código do serviço de telecomunicação)
69
+ # - descricao (descrição do serviço/plano)
70
+ # - classe_consumo (classificação do consumo)
71
+ # - cfop (Código Fiscal de Operações)
72
+ # - valor_unitario (valor do serviço, maior que zero)
73
+ # - quantidade (quantidade de unidades, padrão: 1)
74
+ #
75
+ # Atributos opcionais:
76
+ # - valor_desconto (desconto aplicado, padrão: 0.00)
77
+ # - valor_outras_despesas (outras despesas acessórias, padrão: 0.00)
78
+ # - unidade (unidade de medida, padrão: 'UN')
79
+ # - codigo_beneficio_fiscal (código de benefício fiscal, se aplicável)
80
+ #
81
+ # Cálculo automático:
82
+ # - valor_total = (quantidade x valor_unitario) - valor_desconto + valor_outras_despesas
83
+ # - O número do item é atribuído automaticamente ao adicionar na nota
84
+ #
85
+ # Validações automáticas:
86
+ # - Todos os campos obrigatórios devem estar presentes
87
+ # - Valor unitário deve ser maior que zero
88
+ # - Quantidade deve ser maior que zero
89
+ class Item # rubocop:disable Metrics/ClassLength
90
+ include Utils::Helpers
91
+
92
+ attr_accessor :numero_item, :codigo_servico, :descricao,
93
+ :quantidade, :valor_unitario, :valor_total,
94
+ :valor_desconto, :valor_outras_despesas,
95
+ :cfop, :codigo_beneficio_fiscal
96
+
97
+ attr_reader :classe_consumo, :unidade
98
+
99
+ def classe_consumo=(value)
100
+ @classe_consumo = if value.is_a?(Symbol)
101
+ CLASSES_CONSUMO[value]
102
+ else
103
+ value.to_s
104
+ end
105
+ end
106
+
107
+ def unidade=(value)
108
+ @unidade = if value.is_a?(Symbol)
109
+ UNIDADES_MEDIDA[value]
110
+ else
111
+ value.to_i
112
+ end
113
+ end
114
+
115
+ # Códigos de serviço principais para provedor de internet
116
+ CODIGOS_SERVICO = {
117
+ internet: '0303',
118
+ tv_assinatura: '0304',
119
+ telefonia: '0305'
120
+ }.freeze
121
+
122
+ CLASSES_CONSUMO = {
123
+ # Grupo 010 - Assinatura
124
+ assinatura_telefonia: '0100101',
125
+ assinatura_dados: '0100201',
126
+ assinatura_tv: '0100301',
127
+ assinatura_multimidia: '0100401',
128
+
129
+ # Grupo 020 - Habilitação
130
+ habilitacao_telefonia: '0200101',
131
+ habilitacao_dados: '0200201',
132
+ habilitacao_tv: '0200301',
133
+
134
+ # Grupo 030 - Serviço Medido
135
+ medido_chamadas_locais: '0300101',
136
+ medido_longa_distancia_nacional: '0300102',
137
+ medido_longa_distancia_internacional: '0300103',
138
+ medido_roaming_originadas: '0300104',
139
+ medido_roaming_recebidas: '0300105',
140
+ medido_adicional_chamada: '0300106',
141
+ medido_numeros_especiais: '0300107',
142
+ medido_sms: '0300108',
143
+ medido_mms: '0300109',
144
+ medido_dados: '0300201',
145
+ medido_pay_per_view: '0300301',
146
+ medido_multimidia: '0300401',
147
+
148
+ # Grupo 040 - Serviço Não Medido
149
+ nao_medido_telefonia: '0400101',
150
+ nao_medido_dados: '0400201',
151
+ nao_medido_tv: '0400301',
152
+ nao_medido_internet: '0400401',
153
+ nao_medido_multimidia: '0400501',
154
+
155
+ # Grupo 045 - Serviços Combinados
156
+ combinados_voz_dados_mensagens: '0450101',
157
+
158
+ # Grupo 050 - Serviço Pré-pago
159
+ prepago_cartao_telefone_fixo: '0500101',
160
+ prepago_recarga_fixo: '0500102',
161
+ prepago_recarga_movel: '0500201',
162
+ prepago_recarga_scm: '0500301',
163
+ prepago_recarga_tv: '0500401',
164
+ prepago_antecipacao: '0500501',
165
+ prepago_repasse: '0500601',
166
+
167
+ # Grupo 060 - Outros Serviços
168
+ outros_facilidades: '0600101',
169
+ outros_streaming: '0600201',
170
+ outros_rastreamento: '0600301',
171
+ outros_publicidade: '0600401',
172
+ outros_publicidade_radio_tv: '0600402',
173
+ outros_gerais: '0600501',
174
+ outros_valor_adicionado: '0600601',
175
+
176
+ # Grupo 070 - Cessão Meios de Rede
177
+ cessao_interconexao: '0700101',
178
+ cessao_roaming: '0700201',
179
+ cessao_eild: '0700301',
180
+ cessao_icms_proporcional: '0700401',
181
+ cessao_icms_consumo_proprio: '0700501',
182
+ cessao_icms_complementar: '0700601',
183
+
184
+ # Grupo 080 - Disponibilização de Equipamentos
185
+ equip_telefone: '0800101',
186
+ equip_identificador: '0800201',
187
+ equip_modem: '0800301',
188
+ equip_rack: '0800401',
189
+ equip_sala: '0800501',
190
+ equip_roteador: '0800601',
191
+ equip_servidor: '0800701',
192
+ equip_multiplexador: '0800801',
193
+ equip_decodificador: '0800901',
194
+ equip_outros: '0801001',
195
+ equip_fibra_apagada: '0801101',
196
+ equip_capacidade_satelital: '0801201',
197
+ equip_antenas: '0801301',
198
+ equip_dutos_postes: '0801401',
199
+
200
+ # Grupo 100 - Cobrança Própria
201
+ cobranca_seguros: '1000101',
202
+ cobranca_parcelamento: '1000201',
203
+ cobranca_juros: '1000301',
204
+ cobranca_multa_mora: '1000401',
205
+ cobranca_multa_fidelizacao: '1000402',
206
+ cobranca_meses_anteriores: '1000501',
207
+ cobranca_correcao_monetaria: '1000601',
208
+ cobranca_taxas: '1000701',
209
+ cobranca_adiantamento_radiodifusao: '1000801',
210
+ cobranca_venda_mercadorias: '1000901',
211
+
212
+ # Grupo 110 - Cobrança de Terceiros
213
+ terceiros_servicos: '1100101',
214
+ terceiros_seguros: '1100201',
215
+ terceiros_juros: '1100301',
216
+ terceiros_multa: '1100401',
217
+ terceiros_meses_anteriores: '1100501',
218
+ terceiros_correcao: '1100601',
219
+ terceiros_doacoes: '1100701',
220
+ terceiros_equipamentos: '1100801',
221
+ terceiros_venda_mercadorias: '1100901',
222
+
223
+ # Grupo 120 - Cobrança Centralizada
224
+ centralizada_item: '1200101',
225
+
226
+ # Grupo 130 - Cofaturamento
227
+ cofaturamento_item: '1300101',
228
+
229
+ # Grupo 590 - Deduções
230
+ deducao_impugnacao: '5900101',
231
+ deducao_ajuste: '5900201',
232
+ deducao_multa_interrupcao: '5900301',
233
+ deducao_pagamento_duplicidade: '5900401',
234
+ deducao_outras: '5900501'
235
+ }.freeze
236
+
237
+ UNIDADES_MEDIDA = {
238
+ minuto: 1, # Minuto
239
+ mb: 2, # Megabyte
240
+ gb: 3, # Gigabyte
241
+ un: 4 # Unidade/Unit (padrão para assinaturas)
242
+ }.freeze
243
+
244
+ def initialize(attributes = {})
245
+ @unidade = 4 # Padrão: UN (Unidade)
246
+ @quantidade = 1
247
+ @valor_desconto = 0.0
248
+ @valor_outras_despesas = 0.0
249
+
250
+ attributes.each do |key, value|
251
+ send("#{key}=", value) if respond_to?("#{key}=")
252
+ end
253
+
254
+ calcular_valor_total if @valor_total.nil?
255
+ end
256
+
257
+ def valido?
258
+ erros.empty?
259
+ end
260
+
261
+ def erros # rubocop:disable Metrics/MethodLength
262
+ errors = []
263
+
264
+ # Validações de campos obrigatórios
265
+ errors << 'Código de serviço é obrigatório' if codigo_servico.to_s.strip.empty?
266
+ errors << 'Descrição é obrigatória' if descricao.to_s.strip.empty?
267
+ errors << 'Classe de consumo é obrigatória' if classe_consumo.to_s.strip.empty?
268
+ errors << 'CFOP é obrigatório' if cfop.to_s.strip.empty?
269
+
270
+ # Validações de valores numéricos
271
+ errors << 'Valor unitário é obrigatório' if valor_unitario.nil?
272
+ errors << 'Quantidade é obrigatória' if quantidade.nil?
273
+
274
+ # Validações lógicas
275
+ errors << 'Valor unitário deve ser maior que zero' if valor_unitario && valor_unitario.to_f <= 0
276
+ errors << 'Quantidade deve ser maior que zero' if quantidade && quantidade.to_f <= 0
277
+
278
+ # Validações declarativas de formato/schema
279
+ campos = {}
280
+
281
+ # Campos obrigatórios - validar formato apenas se não estiverem vazios
282
+ unless codigo_servico.to_s.strip.empty?
283
+ campos[:codigo_servico] = { valor: codigo_servico, validador: :er47, nome: 'Código de serviço', max: 60 }
284
+ end
285
+
286
+ unless descricao.to_s.strip.empty?
287
+ campos[:descricao] = { valor: descricao, validador: :er47, nome: 'Descrição', max: 120 }
288
+ end
289
+
290
+ unless classe_consumo.to_s.strip.empty?
291
+ campos[:classe_consumo] = { valor: classe_consumo, validador: :er2, nome: 'Classe de consumo' }
292
+ end
293
+
294
+ campos[:cfop] = { valor: cfop, validador: :er73, nome: 'CFOP' } unless cfop.to_s.strip.empty?
295
+
296
+ # Unidade (D8 - domain: 1, 2, 3, 4)
297
+ if unidade && !unidade.to_s.strip.empty?
298
+ campos[:unidade] = { valor: unidade.to_s, validador: :d8, nome: 'Unidade de medida' }
299
+ end
300
+
301
+ # Quantidade (ER31 - 11 posições, 0-4 decimais)
302
+ if quantidade&.to_f&.positive?
303
+ campos[:quantidade] = { valor: formatar_decimal(quantidade, 4), validador: :er31, nome: 'Quantidade' }
304
+ end
305
+
306
+ # Valor unitário (ER39 - 13 posições, 2-8 decimais)
307
+ if valor_unitario&.to_f&.positive?
308
+ campos[:valor_unitario] =
309
+ { valor: formatar_decimal(valor_unitario, 8), validador: :er39, nome: 'Valor unitário' }
310
+ end
311
+
312
+ # Campos opcionais - validar formato apenas se informados
313
+ if valor_desconto&.to_f&.positive?
314
+ campos[:valor_desconto] =
315
+ { valor: formatar_decimal(valor_desconto, 2), validador: :er37, nome: 'Valor de desconto' }
316
+ end
317
+
318
+ if valor_outras_despesas&.to_f&.positive?
319
+ campos[:valor_outras_despesas] =
320
+ { valor: formatar_decimal(valor_outras_despesas, 2), validador: :er37, nome: 'Valor de outras despesas' }
321
+ end
322
+
323
+ if valor_total&.to_f&.positive?
324
+ campos[:valor_total] = { valor: formatar_decimal(valor_total, 8), validador: :er39, nome: 'Valor total' }
325
+ end
326
+
327
+ if classe_consumo.to_s.strip.empty?
328
+ errors << 'Classe de consumo é obrigatória'
329
+ elsif !CLASSES_CONSUMO.values.include?(classe_consumo.to_s)
330
+ errors << "Classe de consumo inválida. Use um dos valores: #{CLASSES_CONSUMO.values.join(', ')}"
331
+ end
332
+
333
+ # Add unidade validation
334
+ errors << 'Unidade de medida inválida. Use: 1=Minuto, 2=MB, 3=GB, 4=UN' unless [1, 2, 3,
335
+ 4].include?(unidade.to_i)
336
+ # Executar validações declarativas
337
+ errors.concat(Validators::SchemaValidator.validar_campos(campos))
338
+
339
+ errors
340
+ end
341
+
342
+ def calcular_valor_total
343
+ @valor_total = (quantidade.to_f * valor_unitario.to_f) -
344
+ valor_desconto.to_f +
345
+ valor_outras_despesas.to_f
346
+ end
347
+
348
+ def valor_liquido
349
+ valor_total.to_f
350
+ end
351
+ end
352
+ end
353
+ end