focus_nfe 1.0.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.
- checksums.yaml +7 -0
- data/.git-hooks/pre_push/steep.rb +18 -0
- data/.git-hooks/pre_push/yard_doc.rb +18 -0
- data/.gitattributes +1 -0
- data/.overcommit.yml +69 -0
- data/.rspec +3 -0
- data/.yardopts +11 -0
- data/CHANGELOG.md +77 -0
- data/CLAUDE.md +118 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +348 -0
- data/Rakefile +105 -0
- data/data/schemas/schema_cte.json +2793 -0
- data/data/schemas/schema_cte_os.json +1335 -0
- data/data/schemas/schema_cte_os_transporte_rodoviario.json +109 -0
- data/data/schemas/schema_cte_transporte_aereo.json +115 -0
- data/data/schemas/schema_cte_transporte_aquaviario.json +174 -0
- data/data/schemas/schema_cte_transporte_dutoviario.json +65 -0
- data/data/schemas/schema_cte_transporte_ferroviario.json +144 -0
- data/data/schemas/schema_cte_transporte_multimodal.json +45 -0
- data/data/schemas/schema_cte_transporte_rodoviario.json +78 -0
- data/data/schemas/schema_dce.json +549 -0
- data/data/schemas/schema_mdfe.json +1102 -0
- data/data/schemas/schema_mdfe_transporte_aereo.json +44 -0
- data/data/schemas/schema_mdfe_transporte_aquaviario.json +209 -0
- data/data/schemas/schema_mdfe_transporte_ferroviario.json +99 -0
- data/data/schemas/schema_mdfe_transporte_rodoviario.json +628 -0
- data/data/schemas/schema_nfcom.json +1859 -0
- data/data/schemas/schema_nfe.json +4750 -0
- data/data/schemas/schema_nfe_forma_pagamento.json +97 -0
- data/data/schemas/schema_nfe_item.json +2574 -0
- data/data/schemas/schema_nfgas.json +2316 -0
- data/data/schemas/schema_nfse_nacional.json +1847 -0
- data/data/schemas/schema_nfse_recebida.json +548 -0
- data/lib/focus_nfe/client.rb +162 -0
- data/lib/focus_nfe/configuration.rb +104 -0
- data/lib/focus_nfe/errors.rb +123 -0
- data/lib/focus_nfe/esquemas/campo.rb +171 -0
- data/lib/focus_nfe/esquemas/catalogo.rb +34 -0
- data/lib/focus_nfe/esquemas/decimal.rb +66 -0
- data/lib/focus_nfe/esquemas/esquema.rb +72 -0
- data/lib/focus_nfe/esquemas/validador.rb +87 -0
- data/lib/focus_nfe/http/adapter.rb +25 -0
- data/lib/focus_nfe/http/adapters/net_http.rb +99 -0
- data/lib/focus_nfe/http/authentication.rb +23 -0
- data/lib/focus_nfe/http/connection.rb +118 -0
- data/lib/focus_nfe/http/logging.rb +100 -0
- data/lib/focus_nfe/http/response.rb +75 -0
- data/lib/focus_nfe/modelos/documento.rb +113 -0
- data/lib/focus_nfe/modelos/inutilizacao.rb +75 -0
- data/lib/focus_nfe/modelos/pagina.rb +54 -0
- data/lib/focus_nfe/recursos/backups.rb +17 -0
- data/lib/focus_nfe/recursos/base.rb +91 -0
- data/lib/focus_nfe/recursos/ceps.rb +16 -0
- data/lib/focus_nfe/recursos/cfops.rb +16 -0
- data/lib/focus_nfe/recursos/cnaes.rb +16 -0
- data/lib/focus_nfe/recursos/cnpjs.rb +13 -0
- data/lib/focus_nfe/recursos/concerns/baixavel.rb +41 -0
- data/lib/focus_nfe/recursos/concerns/baixavel_eventos.rb +34 -0
- data/lib/focus_nfe/recursos/concerns/cancelavel.rb +25 -0
- data/lib/focus_nfe/recursos/concerns/conciliavel.rb +66 -0
- data/lib/focus_nfe/recursos/concerns/consultavel.rb +26 -0
- data/lib/focus_nfe/recursos/concerns/corrigivel.rb +45 -0
- data/lib/focus_nfe/recursos/concerns/corrigivel_cte.rb +60 -0
- data/lib/focus_nfe/recursos/concerns/emitivel.rb +51 -0
- data/lib/focus_nfe/recursos/concerns/enviavel.rb +40 -0
- data/lib/focus_nfe/recursos/concerns/eventavel.rb +46 -0
- data/lib/focus_nfe/recursos/concerns/inutilizavel.rb +96 -0
- data/lib/focus_nfe/recursos/concerns/listavel.rb +22 -0
- data/lib/focus_nfe/recursos/concerns/localizavel.rb +22 -0
- data/lib/focus_nfe/recursos/concerns/notificavel.rb +23 -0
- data/lib/focus_nfe/recursos/concerns/removivel.rb +20 -0
- data/lib/focus_nfe/recursos/concerns/visualizavel.rb +28 -0
- data/lib/focus_nfe/recursos/cte.rb +35 -0
- data/lib/focus_nfe/recursos/cte_os.rb +29 -0
- data/lib/focus_nfe/recursos/ctes_recebidas.rb +38 -0
- data/lib/focus_nfe/recursos/dce.rb +16 -0
- data/lib/focus_nfe/recursos/emails_bloqueados.rb +31 -0
- data/lib/focus_nfe/recursos/empresas.rb +35 -0
- data/lib/focus_nfe/recursos/mdfe.rb +78 -0
- data/lib/focus_nfe/recursos/municipios.rb +60 -0
- data/lib/focus_nfe/recursos/ncms.rb +16 -0
- data/lib/focus_nfe/recursos/nfce.rb +19 -0
- data/lib/focus_nfe/recursos/nfcom.rb +16 -0
- data/lib/focus_nfe/recursos/nfe.rb +106 -0
- data/lib/focus_nfe/recursos/nfes_recebidas.rb +56 -0
- data/lib/focus_nfe/recursos/nfgas.rb +16 -0
- data/lib/focus_nfe/recursos/nfse.rb +18 -0
- data/lib/focus_nfe/recursos/nfse_nacional.rb +16 -0
- data/lib/focus_nfe/recursos/nfses_nacionais_recebidas.rb +21 -0
- data/lib/focus_nfe/recursos/webhooks.rb +22 -0
- data/lib/focus_nfe/version.rb +6 -0
- data/lib/focus_nfe/webhook.rb +68 -0
- data/lib/focus_nfe.rb +124 -0
- data/sig/focus_nfe/client.rbs +38 -0
- data/sig/focus_nfe/configuration.rbs +29 -0
- data/sig/focus_nfe/errors.rbs +59 -0
- data/sig/focus_nfe/esquemas/campo.rbs +47 -0
- data/sig/focus_nfe/esquemas/catalogo.rbs +8 -0
- data/sig/focus_nfe/esquemas/decimal.rbs +25 -0
- data/sig/focus_nfe/esquemas/esquema.rbs +30 -0
- data/sig/focus_nfe/esquemas/validador.rbs +20 -0
- data/sig/focus_nfe/http/adapter.rbs +7 -0
- data/sig/focus_nfe/http/adapters/net_http.rbs +25 -0
- data/sig/focus_nfe/http/authentication.rbs +9 -0
- data/sig/focus_nfe/http/connection.rbs +32 -0
- data/sig/focus_nfe/http/logging.rbs +30 -0
- data/sig/focus_nfe/http/response.rbs +28 -0
- data/sig/focus_nfe/modelos/documento.rbs +34 -0
- data/sig/focus_nfe/modelos/inutilizacao.rbs +24 -0
- data/sig/focus_nfe/modelos/pagina.rbs +21 -0
- data/sig/focus_nfe/recursos/backups.rbs +7 -0
- data/sig/focus_nfe/recursos/base.rbs +25 -0
- data/sig/focus_nfe/recursos/ceps.rbs +10 -0
- data/sig/focus_nfe/recursos/cfops.rbs +10 -0
- data/sig/focus_nfe/recursos/cnaes.rbs +10 -0
- data/sig/focus_nfe/recursos/cnpjs.rbs +7 -0
- data/sig/focus_nfe/recursos/concerns/baixavel.rbs +12 -0
- data/sig/focus_nfe/recursos/concerns/baixavel_eventos.rbs +14 -0
- data/sig/focus_nfe/recursos/concerns/cancelavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/conciliavel.rbs +15 -0
- data/sig/focus_nfe/recursos/concerns/consultavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/corrigivel.rbs +15 -0
- data/sig/focus_nfe/recursos/concerns/corrigivel_cte.rbs +17 -0
- data/sig/focus_nfe/recursos/concerns/emitivel.rbs +14 -0
- data/sig/focus_nfe/recursos/concerns/enviavel.rbs +15 -0
- data/sig/focus_nfe/recursos/concerns/eventavel.rbs +12 -0
- data/sig/focus_nfe/recursos/concerns/inutilizavel.rbs +20 -0
- data/sig/focus_nfe/recursos/concerns/listavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/localizavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/notificavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/removivel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/visualizavel.rbs +9 -0
- data/sig/focus_nfe/recursos/cte.rbs +17 -0
- data/sig/focus_nfe/recursos/cte_os.rbs +17 -0
- data/sig/focus_nfe/recursos/ctes_recebidas.rbs +14 -0
- data/sig/focus_nfe/recursos/dce.rbs +10 -0
- data/sig/focus_nfe/recursos/emails_bloqueados.rbs +12 -0
- data/sig/focus_nfe/recursos/empresas.rbs +12 -0
- data/sig/focus_nfe/recursos/mdfe.rbs +21 -0
- data/sig/focus_nfe/recursos/municipios.rbs +19 -0
- data/sig/focus_nfe/recursos/ncms.rbs +10 -0
- data/sig/focus_nfe/recursos/nfce.rbs +12 -0
- data/sig/focus_nfe/recursos/nfcom.rbs +10 -0
- data/sig/focus_nfe/recursos/nfe.rbs +23 -0
- data/sig/focus_nfe/recursos/nfes_recebidas.rbs +16 -0
- data/sig/focus_nfe/recursos/nfgas.rbs +10 -0
- data/sig/focus_nfe/recursos/nfse.rbs +11 -0
- data/sig/focus_nfe/recursos/nfse_nacional.rbs +10 -0
- data/sig/focus_nfe/recursos/nfses_nacionais_recebidas.rbs +11 -0
- data/sig/focus_nfe/recursos/webhooks.rbs +11 -0
- data/sig/focus_nfe/webhook.rbs +11 -0
- data/sig/focus_nfe.rbs +10 -0
- data/spec/focus_nfe/client_spec.rb +208 -0
- data/spec/focus_nfe/configuration_spec.rb +121 -0
- data/spec/focus_nfe/errors_mapping_spec.rb +68 -0
- data/spec/focus_nfe/errors_spec.rb +107 -0
- data/spec/focus_nfe/esquemas/campo_spec.rb +291 -0
- data/spec/focus_nfe/esquemas/decimal_spec.rb +54 -0
- data/spec/focus_nfe/esquemas/esquema_spec.rb +73 -0
- data/spec/focus_nfe/esquemas/validador_spec.rb +167 -0
- data/spec/focus_nfe/esquemas_spec.rb +42 -0
- data/spec/focus_nfe/http/adapter_spec.rb +8 -0
- data/spec/focus_nfe/http/adapters/net_http_spec.rb +181 -0
- data/spec/focus_nfe/http/authentication_spec.rb +24 -0
- data/spec/focus_nfe/http/connection_spec.rb +255 -0
- data/spec/focus_nfe/http/logging_spec.rb +83 -0
- data/spec/focus_nfe/http/response_spec.rb +161 -0
- data/spec/focus_nfe/modelos/documento_spec.rb +150 -0
- data/spec/focus_nfe/modelos/inutilizacao_spec.rb +91 -0
- data/spec/focus_nfe/modelos/pagina_spec.rb +77 -0
- data/spec/focus_nfe/recursos/backups_spec.rb +29 -0
- data/spec/focus_nfe/recursos/base_spec.rb +56 -0
- data/spec/focus_nfe/recursos/ceps_spec.rb +16 -0
- data/spec/focus_nfe/recursos/cfops_spec.rb +16 -0
- data/spec/focus_nfe/recursos/cnaes_spec.rb +20 -0
- data/spec/focus_nfe/recursos/cnpjs_spec.rb +11 -0
- data/spec/focus_nfe/recursos/concerns/emitivel_validacao_spec.rb +158 -0
- data/spec/focus_nfe/recursos/cte_os_spec.rb +9 -0
- data/spec/focus_nfe/recursos/cte_spec.rb +9 -0
- data/spec/focus_nfe/recursos/ctes_recebidas_spec.rb +56 -0
- data/spec/focus_nfe/recursos/dce_spec.rb +8 -0
- data/spec/focus_nfe/recursos/emails_bloqueados_spec.rb +29 -0
- data/spec/focus_nfe/recursos/empresas_spec.rb +45 -0
- data/spec/focus_nfe/recursos/mdfe_spec.rb +100 -0
- data/spec/focus_nfe/recursos/municipios_spec.rb +58 -0
- data/spec/focus_nfe/recursos/ncms_spec.rb +16 -0
- data/spec/focus_nfe/recursos/nfce_spec.rb +10 -0
- data/spec/focus_nfe/recursos/nfcom_spec.rb +8 -0
- data/spec/focus_nfe/recursos/nfe_spec.rb +262 -0
- data/spec/focus_nfe/recursos/nfes_recebidas_spec.rb +87 -0
- data/spec/focus_nfe/recursos/nfgas_spec.rb +8 -0
- data/spec/focus_nfe/recursos/nfse_nacional_spec.rb +8 -0
- data/spec/focus_nfe/recursos/nfse_spec.rb +9 -0
- data/spec/focus_nfe/recursos/nfses_nacionais_recebidas_spec.rb +17 -0
- data/spec/focus_nfe/recursos/webhooks_spec.rb +22 -0
- data/spec/focus_nfe/webhook_spec.rb +66 -0
- data/spec/focus_nfe_global_configuration_spec.rb +70 -0
- data/spec/focus_nfe_require_spec.rb +87 -0
- data/spec/focus_nfe_spec.rb +11 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/support/shared_examples/recurso_fiscal.rb +445 -0
- data/spec/support/shared_examples/recurso_leitura.rb +217 -0
- data/tools/pull_fields.rb +62 -0
- metadata +420 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Modelos
|
|
5
|
+
# Objeto de valor imutável que representa o estado fiscal de um documento.
|
|
6
|
+
# Encapsula o corpo (Hash) das respostas de emissão e consulta — que
|
|
7
|
+
# compartilham o mesmo schema — expondo os campos comuns e predicados de
|
|
8
|
+
# status. Campos não mapeados continuam acessíveis via {#[]}/{#dados}.
|
|
9
|
+
class Documento
|
|
10
|
+
# @return [FocusNfe::HTTP::Response, nil] resposta original que originou o documento (nil em webhooks inbound)
|
|
11
|
+
attr_reader :response
|
|
12
|
+
|
|
13
|
+
# @return [String, nil] referência informada na chamada (nem sempre presente no corpo)
|
|
14
|
+
attr_reader :ref
|
|
15
|
+
|
|
16
|
+
# @return [Hash] corpo cru da resposta
|
|
17
|
+
attr_reader :dados
|
|
18
|
+
|
|
19
|
+
# @return [String, nil] status do documento na Focus NFe (ex.: +autorizado+)
|
|
20
|
+
def status = dados["status"]
|
|
21
|
+
|
|
22
|
+
# @return [String, nil] código de status retornado pela SEFAZ
|
|
23
|
+
def status_sefaz = dados["status_sefaz"]
|
|
24
|
+
|
|
25
|
+
# @return [String, nil] mensagem descritiva retornada pela SEFAZ
|
|
26
|
+
def mensagem_sefaz = dados["mensagem_sefaz"]
|
|
27
|
+
|
|
28
|
+
# @return [String, nil] chave de acesso do documento autorizado
|
|
29
|
+
def chave_nfe = dados["chave_nfe"]
|
|
30
|
+
|
|
31
|
+
# @return [String, nil] número do documento fiscal
|
|
32
|
+
def numero = dados["numero"]
|
|
33
|
+
|
|
34
|
+
# @return [String, nil] série do documento fiscal
|
|
35
|
+
def serie = dados["serie"]
|
|
36
|
+
|
|
37
|
+
# @return [String, nil] caminho relativo do XML da nota na Focus NFe
|
|
38
|
+
def caminho_xml_nota_fiscal = dados["caminho_xml_nota_fiscal"]
|
|
39
|
+
|
|
40
|
+
# @return [String, nil] caminho relativo do PDF (DANFe/DACTe/DANFSe) na Focus NFe
|
|
41
|
+
def caminho_danfe = dados["caminho_danfe"]
|
|
42
|
+
|
|
43
|
+
# @return [String, nil] caminho relativo do XML da carta de correção na Focus NFe
|
|
44
|
+
def caminho_xml_carta_correcao = dados["caminho_xml_carta_correcao"]
|
|
45
|
+
|
|
46
|
+
# @return [String, nil] caminho relativo do PDF da carta de correção na Focus NFe
|
|
47
|
+
def caminho_pdf_carta_correcao = dados["caminho_pdf_carta_correcao"]
|
|
48
|
+
|
|
49
|
+
# @return [String, nil] número sequencial da carta de correção emitida
|
|
50
|
+
def numero_carta_correcao = dados["numero_carta_correcao"]
|
|
51
|
+
|
|
52
|
+
# Constrói um {Documento} a partir de uma {HTTP::Response}.
|
|
53
|
+
#
|
|
54
|
+
# @param response [FocusNfe::HTTP::Response] resposta de emissão/consulta
|
|
55
|
+
# @param ref [String, nil] referência conhecida pela chamada, injetada quando ausente do corpo
|
|
56
|
+
# @return [FocusNfe::Modelos::Documento]
|
|
57
|
+
def self.from_response(response, ref: nil)
|
|
58
|
+
new(dados: response.body, ref: ref, response: response)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Constrói um {Documento} a partir do corpo já parseado de um webhook
|
|
62
|
+
# inbound — sem {HTTP::Response} associada.
|
|
63
|
+
#
|
|
64
|
+
# @param corpo [Hash] corpo do webhook, com o mesmo schema das respostas
|
|
65
|
+
# @param ref [String, nil] referência conhecida, injetada quando ausente do corpo
|
|
66
|
+
# @return [FocusNfe::Modelos::Documento]
|
|
67
|
+
def self.from_payload(corpo, ref: nil)
|
|
68
|
+
new(dados: corpo, ref: ref)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @param dados [Object] corpo da resposta/webhook (usa {} quando não é Hash)
|
|
72
|
+
# @param ref [String, nil] referência conhecida pela chamada
|
|
73
|
+
# @param response [FocusNfe::HTTP::Response, nil] resposta original, quando houver
|
|
74
|
+
def initialize(dados:, ref: nil, response: nil)
|
|
75
|
+
@response = response
|
|
76
|
+
@dados = dados.is_a?(Hash) ? dados : {}
|
|
77
|
+
@ref = ref || @dados["ref"]
|
|
78
|
+
freeze
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @param chave [String] nome do campo no corpo da resposta
|
|
82
|
+
# @return [Object, nil] valor do campo cru
|
|
83
|
+
def [](chave)
|
|
84
|
+
dados[chave]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @return [Boolean]
|
|
88
|
+
def autorizado?
|
|
89
|
+
status == "autorizado"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @return [Boolean]
|
|
93
|
+
def cancelado?
|
|
94
|
+
status == "cancelado"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @return [Boolean]
|
|
98
|
+
def processando?
|
|
99
|
+
status == "processando_autorizacao"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @return [Boolean]
|
|
103
|
+
def erro?
|
|
104
|
+
status.to_s.start_with?("erro")
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @return [Boolean]
|
|
108
|
+
def denegado?
|
|
109
|
+
status == "denegado"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Modelos
|
|
5
|
+
# Objeto de valor imutável que representa o resultado de uma inutilização de
|
|
6
|
+
# numeração. Encapsula o corpo (Hash) da resposta — tanto da criação
|
|
7
|
+
# (+POST+) quanto de cada item da consulta (+GET+) — expondo os campos comuns
|
|
8
|
+
# e o predicado de status. Campos não mapeados continuam acessíveis via
|
|
9
|
+
# {#[]}/{#dados}. Diferente de {Documento}, não carrega +ref+: a inutilização
|
|
10
|
+
# é uma operação de coleção, sem referência por documento.
|
|
11
|
+
class Inutilizacao
|
|
12
|
+
# @return [FocusNfe::HTTP::Response, nil] resposta original; +nil+ para itens de uma consulta
|
|
13
|
+
attr_reader :response
|
|
14
|
+
|
|
15
|
+
# @return [Hash] corpo cru da resposta (ou do item)
|
|
16
|
+
attr_reader :dados
|
|
17
|
+
|
|
18
|
+
# @return [String, nil] status da inutilização na SEFAZ (ex.: +autorizado+)
|
|
19
|
+
def status = dados["status"]
|
|
20
|
+
|
|
21
|
+
# @return [String, nil] código de status retornado pela SEFAZ
|
|
22
|
+
def status_sefaz = dados["status_sefaz"]
|
|
23
|
+
|
|
24
|
+
# @return [String, nil] mensagem descritiva retornada pela SEFAZ
|
|
25
|
+
def mensagem_sefaz = dados["mensagem_sefaz"]
|
|
26
|
+
|
|
27
|
+
# @return [String, nil] protocolo de autorização da SEFAZ (campo +protocolo_sefaz+)
|
|
28
|
+
def protocolo = dados["protocolo_sefaz"]
|
|
29
|
+
|
|
30
|
+
# @return [String, nil] série da numeração inutilizada
|
|
31
|
+
def serie = dados["serie"]
|
|
32
|
+
|
|
33
|
+
# @return [String, nil] número inicial da faixa inutilizada
|
|
34
|
+
def numero_inicial = dados["numero_inicial"]
|
|
35
|
+
|
|
36
|
+
# @return [String, nil] número final da faixa inutilizada
|
|
37
|
+
def numero_final = dados["numero_final"]
|
|
38
|
+
|
|
39
|
+
# Constrói uma {Inutilizacao} a partir de uma {HTTP::Response} de criação.
|
|
40
|
+
#
|
|
41
|
+
# @param response [FocusNfe::HTTP::Response] resposta da inutilização
|
|
42
|
+
# @return [FocusNfe::Modelos::Inutilizacao]
|
|
43
|
+
def self.from_response(response)
|
|
44
|
+
new(dados: response.body.is_a?(Hash) ? response.body : {}, response: response)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Constrói uma {Inutilizacao} a partir de um item cru de uma consulta.
|
|
48
|
+
#
|
|
49
|
+
# @param item [Hash] item da resposta de consulta
|
|
50
|
+
# @return [FocusNfe::Modelos::Inutilizacao]
|
|
51
|
+
def self.from_item(item)
|
|
52
|
+
new(dados: item.is_a?(Hash) ? item : {})
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @param dados [Hash] corpo cru da resposta (ou do item)
|
|
56
|
+
# @param response [FocusNfe::HTTP::Response, nil] resposta original, quando houver
|
|
57
|
+
def initialize(dados:, response: nil)
|
|
58
|
+
@dados = dados
|
|
59
|
+
@response = response
|
|
60
|
+
freeze
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @param chave [String] nome do campo no corpo da resposta
|
|
64
|
+
# @return [Object, nil] valor do campo cru
|
|
65
|
+
def [](chave)
|
|
66
|
+
dados[chave]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [Boolean]
|
|
70
|
+
def autorizado?
|
|
71
|
+
status == "autorizado"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Modelos
|
|
5
|
+
# Coleção paginada de uma resposta de listagem. Encapsula o corpo (Array de
|
|
6
|
+
# Hashes crus) e os cabeçalhos de sincronização incremental, expondo os itens
|
|
7
|
+
# de forma enumerável. Itens permanecem como Hash — modelos leves nas
|
|
8
|
+
# auxiliares/recebidas, conforme a arquitetura.
|
|
9
|
+
class Pagina
|
|
10
|
+
include Enumerable
|
|
11
|
+
|
|
12
|
+
# @return [FocusNfe::HTTP::Response] resposta original da listagem
|
|
13
|
+
attr_reader :response
|
|
14
|
+
|
|
15
|
+
# @return [Array] itens da página (corpo cru da resposta)
|
|
16
|
+
attr_reader :itens
|
|
17
|
+
|
|
18
|
+
# @return [Integer, nil] total de registros disponíveis (cabeçalho +X-Total-Count+)
|
|
19
|
+
attr_reader :total
|
|
20
|
+
|
|
21
|
+
# @return [Integer, nil] maior versão presente (cabeçalho +X-Max-Version+), para sincronização incremental
|
|
22
|
+
attr_reader :versao_maxima
|
|
23
|
+
|
|
24
|
+
# Constrói uma {Pagina} a partir de uma {HTTP::Response} de listagem.
|
|
25
|
+
#
|
|
26
|
+
# @param response [FocusNfe::HTTP::Response] resposta de uma listagem
|
|
27
|
+
# @return [FocusNfe::Modelos::Pagina]
|
|
28
|
+
def self.from_response(response)
|
|
29
|
+
new(response: response)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @param response [FocusNfe::HTTP::Response] resposta de uma listagem
|
|
33
|
+
def initialize(response:)
|
|
34
|
+
@response = response
|
|
35
|
+
@itens = response.body.is_a?(Array) ? response.body : []
|
|
36
|
+
@total = response.headers["X-Total-Count"]&.to_i
|
|
37
|
+
@versao_maxima = response.headers["X-Max-Version"]&.to_i
|
|
38
|
+
freeze
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Itera os itens da página.
|
|
42
|
+
#
|
|
43
|
+
# @yieldparam item [Object] item cru da listagem
|
|
44
|
+
# @return [self, Enumerator] +self+ quando há bloco; um Enumerator caso contrário
|
|
45
|
+
def each(&)
|
|
46
|
+
return to_enum(:each) unless block_given?
|
|
47
|
+
|
|
48
|
+
itens.each(&)
|
|
49
|
+
self
|
|
50
|
+
end
|
|
51
|
+
alias cada each
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
# Consulta de backups mensais de XML/DANFE por CNPJ. O recurso responde em
|
|
6
|
+
# +GET /backups/{cnpj}.json+ com as URLs dos pacotes ZIP por mês.
|
|
7
|
+
class Backups < Base
|
|
8
|
+
caminho_base "backups"
|
|
9
|
+
|
|
10
|
+
# @param cnpj [String] CNPJ da empresa (14 dígitos)
|
|
11
|
+
# @return [Array<Hash>] lista de backups mensais (+mes+, +danfes+, +xmls+)
|
|
12
|
+
def consultar(cnpj)
|
|
13
|
+
connection.get("#{caminho_referencia(cnpj)}.json").body
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
module FocusNfe
|
|
6
|
+
module Recursos
|
|
7
|
+
# Base dos recursos da API. Guarda a {HTTP::Connection} e o +caminho_base+
|
|
8
|
+
# declarado por cada recurso, e oferece os utilitários compartilhados pelos
|
|
9
|
+
# mixins de comportamento ({Concerns::Emitivel}, {Concerns::Consultavel}, {Concerns::Cancelavel}, …):
|
|
10
|
+
# montagem do caminho por referência e validação client-side da +ref+.
|
|
11
|
+
class Base
|
|
12
|
+
# @return [Regexp] formato aceito para a +ref+ (alfanumérico, hífen ou underscore)
|
|
13
|
+
REFERENCIA = /\A[\w-]+\z/
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
# Declara (ou lê) o caminho base do recurso, sem o prefixo +/v2+.
|
|
17
|
+
#
|
|
18
|
+
# @param valor [String, nil] caminho a declarar; omitido apenas lê o atual
|
|
19
|
+
# @return [String, nil] caminho base efetivo da classe
|
|
20
|
+
def caminho_base(valor = nil)
|
|
21
|
+
@caminho_base = valor unless valor.nil?
|
|
22
|
+
@caminho_base
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Declara (ou lê) o caminho da prévia do recurso, sem o prefixo +/v2+.
|
|
26
|
+
# Usado por {Concerns::Visualizavel}; cada documento com prévia o declara
|
|
27
|
+
# (ex.: +"nfe/danfe"+).
|
|
28
|
+
#
|
|
29
|
+
# @param valor [String, nil] caminho a declarar; omitido apenas lê o atual
|
|
30
|
+
# @return [String, nil] caminho de prévia efetivo da classe
|
|
31
|
+
def caminho_base_previa(valor = nil)
|
|
32
|
+
@caminho_base_previa = valor unless valor.nil?
|
|
33
|
+
@caminho_base_previa
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @param connection [FocusNfe::HTTP::Connection] conexão do cliente
|
|
38
|
+
def initialize(connection)
|
|
39
|
+
@connection = connection
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [String, nil] caminho base declarado pela classe do recurso
|
|
43
|
+
def caminho_base
|
|
44
|
+
self.class.caminho_base
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @return [String, nil] caminho de prévia declarado pela classe do recurso
|
|
48
|
+
def caminho_base_previa
|
|
49
|
+
self.class.caminho_base_previa
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
attr_reader :connection
|
|
55
|
+
|
|
56
|
+
# Monta o caminho do recurso escapando o segmento dinâmico, para que um
|
|
57
|
+
# identificador com +/+, +?+, +#+ ou +..+ não sequestre o path nem injete
|
|
58
|
+
# query na requisição autenticada (identificadores comuns — dígitos, hífen,
|
|
59
|
+
# underscore, ponto — passam intactos).
|
|
60
|
+
#
|
|
61
|
+
# @param ref [String] referência/identificador do documento
|
|
62
|
+
# @return [String] caminho do recurso para a referência (ex.: "nfe/pedido-42")
|
|
63
|
+
def caminho_referencia(ref)
|
|
64
|
+
"#{caminho_base}/#{URI.encode_www_form_component(ref)}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Valida a +ref+ client-side antes de qualquer requisição, evitando uma ida
|
|
68
|
+
# à API por um erro trivial de formato.
|
|
69
|
+
#
|
|
70
|
+
# @param ref [String] referência informada
|
|
71
|
+
# @return [void]
|
|
72
|
+
# @raise [ArgumentError] se a +ref+ não for alfanumérica (hífen/underscore permitidos)
|
|
73
|
+
def validar_referencia!(ref)
|
|
74
|
+
return if ref.is_a?(String) && ref.match?(REFERENCIA)
|
|
75
|
+
|
|
76
|
+
raise ArgumentError, "referência inválida: #{ref.inspect} (esperado alfanumérico, hífen ou underscore)"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Esquemas extras a validar além do esquema de topo, dependentes do payload.
|
|
80
|
+
# Cada par associa a chave de um objeto aninhado no payload ao nome do
|
|
81
|
+
# esquema que o valida. Recursos com esquema dinâmico (CTe, CTe OS, MDFe)
|
|
82
|
+
# sobrescrevem este método para, conforme os +dados+, escolher o sub-esquema.
|
|
83
|
+
#
|
|
84
|
+
# @param _dados [Hash] payload de emissão (chaves String)
|
|
85
|
+
# @return [Hash{String => String}] chave aninhada no payload => nome do esquema
|
|
86
|
+
def esquemas_extras(_dados)
|
|
87
|
+
{}
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
# Consulta de CEPs. +consultar(cep)+ devolve o endereço de um CEP; +buscar+
|
|
6
|
+
# filtra endereços por UF/logradouro/localidade/código IBGE.
|
|
7
|
+
class Ceps < Base
|
|
8
|
+
include Concerns::Localizavel
|
|
9
|
+
include Concerns::Listavel
|
|
10
|
+
|
|
11
|
+
caminho_base "ceps"
|
|
12
|
+
|
|
13
|
+
alias buscar listar
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
# Consulta de CFOPs (Código Fiscal de Operações e Prestações).
|
|
6
|
+
# +consultar(codigo)+ busca um CFOP; +buscar+ filtra por código/descrição.
|
|
7
|
+
class Cfops < Base
|
|
8
|
+
include Concerns::Localizavel
|
|
9
|
+
include Concerns::Listavel
|
|
10
|
+
|
|
11
|
+
caminho_base "cfops"
|
|
12
|
+
|
|
13
|
+
alias buscar listar
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
# Consulta de códigos CNAE. +consultar(codigo)+ busca um CNAE; +buscar+ filtra
|
|
6
|
+
# por código/descrição. O caminho da API é +codigos_cnae+.
|
|
7
|
+
class Cnaes < Base
|
|
8
|
+
include Concerns::Localizavel
|
|
9
|
+
include Concerns::Listavel
|
|
10
|
+
|
|
11
|
+
caminho_base "codigos_cnae"
|
|
12
|
+
|
|
13
|
+
alias buscar listar
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
# Consulta de CNPJ. +consultar(cnpj)+ devolve os dados cadastrais da empresa
|
|
6
|
+
# com o endereço aninhado.
|
|
7
|
+
class Cnpjs < Base
|
|
8
|
+
include Concerns::Localizavel
|
|
9
|
+
|
|
10
|
+
caminho_base "cnpjs"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
module Concerns
|
|
6
|
+
# Comportamento de download (+GET /<base>/<identificador>.<formato>+). Devolve
|
|
7
|
+
# os bytes crus da resposta (+raw_body+); o eventual +302+ para URL pré-assinada
|
|
8
|
+
# (PDFs) é seguido pelo adaptador sem reenviar a autenticação.
|
|
9
|
+
module Baixavel
|
|
10
|
+
# Baixa o documento no formato indicado, devolvendo os bytes crus.
|
|
11
|
+
#
|
|
12
|
+
# @param identificador [String] chave ou referência do documento
|
|
13
|
+
# @param formato [String, Symbol] extensão desejada (+json+, +xml+, +pdf+, +html+)
|
|
14
|
+
# @return [String] corpo cru da resposta (bytes)
|
|
15
|
+
# @raise [FocusNfe::Errors::HttpError] em respostas não-2xx
|
|
16
|
+
def download(identificador, formato:)
|
|
17
|
+
response = connection.get("#{caminho_referencia(identificador)}.#{URI.encode_www_form_component(formato)}")
|
|
18
|
+
response.raw_body
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param identificador [String] chave ou referência do documento
|
|
22
|
+
# @return [String] JSON cru do documento
|
|
23
|
+
def download_json(identificador)
|
|
24
|
+
download(identificador, formato: :json)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @param identificador [String] chave ou referência do documento
|
|
28
|
+
# @return [String] XML cru do documento
|
|
29
|
+
def download_xml(identificador)
|
|
30
|
+
download(identificador, formato: :xml)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @param identificador [String] chave ou referência do documento
|
|
34
|
+
# @return [String] PDF (DANFe/DACTe/DANFSe) cru do documento
|
|
35
|
+
def download_pdf(identificador)
|
|
36
|
+
download(identificador, formato: :pdf)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
module Concerns
|
|
6
|
+
# Download do XML de eventos fiscais de um documento
|
|
7
|
+
# (+GET /<base>/<chave>/<evento>.xml+). Devolve os bytes crus (+raw_body+).
|
|
8
|
+
# Opt-in: só recursos que expõem cancelamento e carta de correção — as notas
|
|
9
|
+
# (NF-e) e conhecimentos (CT-e) recebidos.
|
|
10
|
+
module BaixavelEventos
|
|
11
|
+
# @param chave [String] chave de acesso do documento
|
|
12
|
+
# @return [String, nil] XML do último cancelamento
|
|
13
|
+
def download_xml_cancelamento(chave)
|
|
14
|
+
download_xml_evento(chave, evento: "cancelamento")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @param chave [String] chave de acesso do documento
|
|
18
|
+
# @return [String, nil] XML da última carta de correção
|
|
19
|
+
def download_xml_carta_correcao(chave)
|
|
20
|
+
download_xml_evento(chave, evento: "carta_correcao")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# @param chave [String] chave de acesso do documento
|
|
26
|
+
# @param evento [String] sub-caminho do evento (ex.: +cancelamento+)
|
|
27
|
+
# @return [String, nil] XML cru do evento
|
|
28
|
+
def download_xml_evento(chave, evento:)
|
|
29
|
+
connection.get("#{caminho_referencia(chave)}/#{evento}.xml").raw_body
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
module Concerns
|
|
6
|
+
# Comportamento de cancelamento (+DELETE /<base>/<ref>+ com +justificativa+ no
|
|
7
|
+
# corpo). Devolve o {Modelos::Documento} com o estado fiscal resultante.
|
|
8
|
+
module Cancelavel
|
|
9
|
+
# Cancela um documento já emitido.
|
|
10
|
+
#
|
|
11
|
+
# @param ref [String] referência do documento
|
|
12
|
+
# @param justificativa [String] motivo do cancelamento exigido pela SEFAZ
|
|
13
|
+
# @return [FocusNfe::Modelos::Documento]
|
|
14
|
+
# @raise [ArgumentError] se a +ref+ for inválida
|
|
15
|
+
# @raise [FocusNfe::Errors::HttpError] em respostas não-2xx
|
|
16
|
+
def cancelar(ref, justificativa:)
|
|
17
|
+
validar_referencia!(ref)
|
|
18
|
+
|
|
19
|
+
response = connection.delete(caminho_referencia(ref), body: { justificativa: justificativa })
|
|
20
|
+
Modelos::Documento.from_response(response, ref: ref)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
module Concerns
|
|
6
|
+
# Comportamento de Conciliação Financeira (ECONF): registro, consulta e
|
|
7
|
+
# cancelamento por número de protocolo num sub-caminho da referência
|
|
8
|
+
# (+/<base>/<ref>/econf+). Devolve o {Modelos::Documento} com o estado do
|
|
9
|
+
# evento. Uso compartilhado por NF-e e NFC-e.
|
|
10
|
+
module Conciliavel
|
|
11
|
+
# Registra um evento de conciliação financeira sobre o documento autorizado.
|
|
12
|
+
#
|
|
13
|
+
# @param ref [String] referência do documento
|
|
14
|
+
# @param detalhes_pagamento [Array<Hash>] pagamentos a conciliar (1 a 100)
|
|
15
|
+
# @return [FocusNfe::Modelos::Documento]
|
|
16
|
+
# @raise [ArgumentError] se a +ref+ for inválida
|
|
17
|
+
# @raise [FocusNfe::Errors::HttpError] em respostas não-2xx
|
|
18
|
+
def registrar_econf(ref, detalhes_pagamento:)
|
|
19
|
+
validar_referencia!(ref)
|
|
20
|
+
|
|
21
|
+
response = connection.post("#{caminho_referencia(ref)}/econf",
|
|
22
|
+
body: { detalhes_pagamento: detalhes_pagamento })
|
|
23
|
+
Modelos::Documento.from_response(response, ref: ref)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Consulta um evento de conciliação financeira pelo número de protocolo.
|
|
27
|
+
#
|
|
28
|
+
# @param ref [String] referência do documento
|
|
29
|
+
# @param numero_protocolo [String] protocolo devolvido no registro do ECONF
|
|
30
|
+
# @return [FocusNfe::Modelos::Documento]
|
|
31
|
+
# @raise [ArgumentError] se a +ref+ for inválida
|
|
32
|
+
# @raise [FocusNfe::Errors::HttpError] em respostas não-2xx
|
|
33
|
+
def consultar_econf(ref, numero_protocolo)
|
|
34
|
+
validar_referencia!(ref)
|
|
35
|
+
|
|
36
|
+
response = connection.get(caminho_econf(ref, numero_protocolo))
|
|
37
|
+
Modelos::Documento.from_response(response, ref: ref)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Cancela um evento de conciliação financeira pelo número de protocolo. Havendo
|
|
41
|
+
# mais de um ECONF na mesma nota, cancele do mais antigo ao mais recente.
|
|
42
|
+
#
|
|
43
|
+
# @param ref [String] referência do documento
|
|
44
|
+
# @param numero_protocolo [String] protocolo devolvido no registro do ECONF
|
|
45
|
+
# @return [FocusNfe::Modelos::Documento]
|
|
46
|
+
# @raise [ArgumentError] se a +ref+ for inválida
|
|
47
|
+
# @raise [FocusNfe::Errors::HttpError] em respostas não-2xx
|
|
48
|
+
def cancelar_econf(ref, numero_protocolo)
|
|
49
|
+
validar_referencia!(ref)
|
|
50
|
+
|
|
51
|
+
response = connection.delete(caminho_econf(ref, numero_protocolo))
|
|
52
|
+
Modelos::Documento.from_response(response, ref: ref)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
# @param ref [String] referência do documento
|
|
58
|
+
# @param numero_protocolo [String] protocolo do ECONF (escapado no caminho)
|
|
59
|
+
# @return [String] caminho do ECONF por protocolo
|
|
60
|
+
def caminho_econf(ref, numero_protocolo)
|
|
61
|
+
"#{caminho_referencia(ref)}/econf/#{URI.encode_www_form_component(numero_protocolo)}"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
module Concerns
|
|
6
|
+
# Comportamento de consulta (+GET /<base>/<ref>+). Devolve o {Modelos::Documento}
|
|
7
|
+
# com o estado fiscal atual do documento.
|
|
8
|
+
module Consultavel
|
|
9
|
+
# Consulta o estado de um documento já emitido.
|
|
10
|
+
#
|
|
11
|
+
# @param ref [String] referência do documento
|
|
12
|
+
# @param completa [Boolean] quando +true+, pede a resposta completa (+completa=1+)
|
|
13
|
+
# @return [FocusNfe::Modelos::Documento]
|
|
14
|
+
# @raise [ArgumentError] se a +ref+ for inválida
|
|
15
|
+
# @raise [FocusNfe::Errors::HttpError] em respostas não-2xx
|
|
16
|
+
def consultar(ref, completa: false)
|
|
17
|
+
validar_referencia!(ref)
|
|
18
|
+
|
|
19
|
+
params = completa ? { completa: 1 } : {}
|
|
20
|
+
response = connection.get(caminho_referencia(ref), params: params)
|
|
21
|
+
Modelos::Documento.from_response(response, ref: ref)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FocusNfe
|
|
4
|
+
module Recursos
|
|
5
|
+
module Concerns
|
|
6
|
+
# Comportamento de Carta de Correção Eletrônica (CC-e): +POST
|
|
7
|
+
# /<base>/<ref>/carta_correcao+ com o texto da correção no corpo. Devolve o
|
|
8
|
+
# {Modelos::Documento} com o estado fiscal da CC-e.
|
|
9
|
+
module Corrigivel
|
|
10
|
+
# @return [Range] faixa de tamanho aceita para o texto da correção
|
|
11
|
+
TAMANHO_CORRECAO = (15..1000)
|
|
12
|
+
|
|
13
|
+
# Emite uma Carta de Correção Eletrônica sobre um documento autorizado.
|
|
14
|
+
#
|
|
15
|
+
# @param ref [String] referência do documento
|
|
16
|
+
# @param correcao [String] texto da correção (15 a 1000 caracteres)
|
|
17
|
+
# @param data_evento [String, nil] data/hora do evento em ISO 8601; omitida usa a data atual
|
|
18
|
+
# @return [FocusNfe::Modelos::Documento]
|
|
19
|
+
# @raise [ArgumentError] se a +ref+ ou a +correcao+ forem inválidas
|
|
20
|
+
# @raise [FocusNfe::Errors::HttpError] em respostas não-2xx
|
|
21
|
+
def corrigir(ref, correcao:, data_evento: nil)
|
|
22
|
+
validar_referencia!(ref)
|
|
23
|
+
validar_correcao!(correcao)
|
|
24
|
+
|
|
25
|
+
body = { correcao: correcao }
|
|
26
|
+
body[:data_evento] = data_evento if data_evento
|
|
27
|
+
response = connection.post("#{caminho_referencia(ref)}/carta_correcao", body: body)
|
|
28
|
+
Modelos::Documento.from_response(response, ref: ref)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# @param correcao [String] texto informado
|
|
34
|
+
# @return [void]
|
|
35
|
+
# @raise [ArgumentError] se não for String ou estiver fora de 15..1000 caracteres
|
|
36
|
+
def validar_correcao!(correcao)
|
|
37
|
+
return if correcao.is_a?(String) && TAMANHO_CORRECAO.cover?(correcao.length)
|
|
38
|
+
|
|
39
|
+
raise ArgumentError,
|
|
40
|
+
"correção inválida: esperado String com #{TAMANHO_CORRECAO.min} a #{TAMANHO_CORRECAO.max} caracteres"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|