diff --git a/l10n_br_nfse_ginfes/README.rst b/l10n_br_nfse_ginfes/README.rst new file mode 100644 index 000000000000..1b1c7f9ad5ce --- /dev/null +++ b/l10n_br_nfse_ginfes/README.rst @@ -0,0 +1,108 @@ +============== +NFS-e (Ginfes) +============== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--brazil-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-brazil/tree/12.0/l10n_br_nfse_ginfes + :alt: OCA/l10n-brazil +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-brazil-12-0/l10n-brazil-12-0-l10n_br_nfse_ginfes + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/124/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Esse módulo completa o documento criado pelo l10n_br_nfse para permite a criação e transmissão de Notas Fiscais de Serviço Eletrônicas (NFS-e) pelo sistema GINFES. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +* Este módulo tem uma depedencia do pacote python erpbrasil.edoc +* Este módulo tem uma depedencia do pacote python erpbrasil.assinatura +* Este módulo tem uma depedencia do pacote python erpbrasil.transmissao +* Este módulo tem uma depedencia do pacote python erpbrasil.base +* Este módulo tem uma depedencia do pacote python nfselib + +Configuration +============= + +É apenas necessário a instalação e configuração do módulo l10n_br_nfse. + +Usage +===== + +Após ser criado uma Nota Fiscal de Serviço Eletrônicas (NFS-e) é possível confirmá-la e transmiti-la. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* KMEE + +Contributors +~~~~~~~~~~~~ + +* Luis Felipe Mileo +* Gabriel Cardoso de Faria +* Luis Otavio Malta Conceição + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-gabrielcardoso21| image:: https://github.com/gabrielcardoso21.png?size=40px + :target: https://github.com/gabrielcardoso21 + :alt: gabrielcardoso21 +.. |maintainer-mileo| image:: https://github.com/mileo.png?size=40px + :target: https://github.com/mileo + :alt: mileo +.. |maintainer-luismalta| image:: https://github.com/luismalta.png?size=40px + :target: https://github.com/luismalta + :alt: luismalta + +Current `maintainers `__: + +|maintainer-gabrielcardoso21| |maintainer-mileo| |maintainer-luismalta| + +This module is part of the `OCA/l10n-brazil `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_br_nfse_ginfes/__init__.py b/l10n_br_nfse_ginfes/__init__.py new file mode 100644 index 000000000000..0ee8b5073e26 --- /dev/null +++ b/l10n_br_nfse_ginfes/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import tests diff --git a/l10n_br_nfse_ginfes/__manifest__.py b/l10n_br_nfse_ginfes/__manifest__.py new file mode 100644 index 000000000000..a4e4ea10fb6d --- /dev/null +++ b/l10n_br_nfse_ginfes/__manifest__.py @@ -0,0 +1,27 @@ +# Copyright 2019 KMEE INFORMATICA LTDA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "NFS-e (Ginfes)", + "summary": """ + NFS-e (Ginfes)""", + "version": "14.0.1.0.0", + "license": "AGPL-3", + "author": "KMEE, Odoo Community Association (OCA)", + "maintainers": ["gabrielcardoso21", "mileo", "luismalta"], + "website": "https://github.com/OCA/l10n-brazil", + "development_status": "Beta", + "external_dependencies": { + "python": [ + "erpbrasil.edoc", + "erpbrasil.assinatura", + "erpbrasil.transmissao", + "erpbrasil.base>=2.3.0", + "nfselib.ginfes", + "xmldiff", + ], + }, + "depends": [ + "l10n_br_nfse", + ], +} diff --git a/l10n_br_nfse_ginfes/constants/ginfes.py b/l10n_br_nfse_ginfes/constants/ginfes.py new file mode 100644 index 000000000000..d152a2216747 --- /dev/null +++ b/l10n_br_nfse_ginfes/constants/ginfes.py @@ -0,0 +1,17 @@ +RECEPCIONAR_LOTE_RPS = ["RecepcionarLoteRpsV3", "RecepcionarLoteRps"] + +CONSULTAR_SITUACAO_LOTE_RPS = ["ConsultarSituacaoLoteRpsV3", "ConsultarSituacaoLoteRps"] + +CANCELAR_NFSE = ( + [ + "CancelarNfseV3", + "CancelarNfse", + ], +) + +CONSULTAR_NFSE_POR_RPS = ( + [ + "ConsultarNfsePorRpsV3", + "ConsultarNfsePorRps", + ], +) diff --git a/l10n_br_nfse_ginfes/i18n/l10n_br_nfse_ginfes.pot b/l10n_br_nfse_ginfes/i18n/l10n_br_nfse_ginfes.pot new file mode 100644 index 000000000000..0fd8321915ed --- /dev/null +++ b/l10n_br_nfse_ginfes/i18n/l10n_br_nfse_ginfes.pot @@ -0,0 +1,69 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_br_nfse_ginfes +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: l10n_br_nfse_ginfes +#: code:addons/l10n_br_nfse_ginfes/models/document.py:300 +#, python-format +msgid "Batch not yet processed" +msgstr "" + +#. module: l10n_br_nfse_ginfes +#: model:ir.model,name:l10n_br_nfse_ginfes.model_res_company +msgid "Companies" +msgstr "" + +#. module: l10n_br_nfse_ginfes +#: model:ir.model,name:l10n_br_nfse_ginfes.model_l10n_br_fiscal_document +msgid "Fiscal Document" +msgstr "" + +#. module: l10n_br_nfse_ginfes +#: selection:res.company,provedor_nfse:0 +msgid "Ginfes" +msgstr "" + +#. module: l10n_br_nfse_ginfes +#: selection:res.company,provedor_nfse:0 +msgid "ISSNet / Nota Control" +msgstr "" + +#. module: l10n_br_nfse_ginfes +#: model:ir.model.fields,field_description:l10n_br_nfse_ginfes.field_res_company__provedor_nfse +msgid "NFSe Provider" +msgstr "" + +#. module: l10n_br_nfse_ginfes +#: code:addons/l10n_br_nfse_ginfes/models/document.py:297 +#, python-format +msgid "Not received" +msgstr "" + +#. module: l10n_br_nfse_ginfes +#: selection:res.company,provedor_nfse:0 +msgid "Paulistana" +msgstr "" + +#. module: l10n_br_nfse_ginfes +#: code:addons/l10n_br_nfse_ginfes/models/document.py:303 +#, python-format +msgid "Processed with Error" +msgstr "" + +#. module: l10n_br_nfse_ginfes +#: code:addons/l10n_br_nfse_ginfes/models/document.py:306 +#, python-format +msgid "Successfully Processed" +msgstr "" + diff --git a/l10n_br_nfse_ginfes/i18n/pt_BR.po b/l10n_br_nfse_ginfes/i18n/pt_BR.po new file mode 100644 index 000000000000..93216b96446a --- /dev/null +++ b/l10n_br_nfse_ginfes/i18n/pt_BR.po @@ -0,0 +1,61 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_br_nfse_ginfes +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-12-17 05:24+0000\n" +"Last-Translator: Marcel Savegnago \n" +"Language-Team: none\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: l10n_br_nfse_ginfes +#: model:ir.model,name:l10n_br_nfse_ginfes.model_res_company +msgid "Companies" +msgstr "Empresas" + +#. module: l10n_br_nfse_ginfes +#: model:ir.model,name:l10n_br_nfse_ginfes.model_l10n_br_fiscal_document +msgid "Fiscal Document" +msgstr "Documento Fiscal" + +#. module: l10n_br_nfse_ginfes +#: selection:res.company,provedor_nfse:0 +msgid "Ginfes" +msgstr "Ginfes" + +#. module: l10n_br_nfse_ginfes +#: code:addons/l10n_br_nfse_ginfes/models/document.py:307 +#, python-format +msgid "Lote ainda não processado" +msgstr "Lote ainda não processado" + +#. module: l10n_br_nfse_ginfes +#: model:ir.model.fields,field_description:l10n_br_nfse_ginfes.field_res_company__provedor_nfse +msgid "NFSe Provider" +msgstr "Provedor NFSe" + +#. module: l10n_br_nfse_ginfes +#: code:addons/l10n_br_nfse_ginfes/models/document.py:304 +#, python-format +msgid "Não Recebido" +msgstr "Não Recebido" + +#. module: l10n_br_nfse_ginfes +#: code:addons/l10n_br_nfse_ginfes/models/document.py:310 +#, python-format +msgid "Procesado com Erro" +msgstr "Procesado com Erro" + +#. module: l10n_br_nfse_ginfes +#: code:addons/l10n_br_nfse_ginfes/models/document.py:313 +#, python-format +msgid "Procesado com Sucesso" +msgstr "Procesado com Sucesso" diff --git a/l10n_br_nfse_ginfes/models/__init__.py b/l10n_br_nfse_ginfes/models/__init__.py new file mode 100644 index 000000000000..166dd3bd2493 --- /dev/null +++ b/l10n_br_nfse_ginfes/models/__init__.py @@ -0,0 +1,2 @@ +from . import document +from . import res_company diff --git a/l10n_br_nfse_ginfes/models/document.py b/l10n_br_nfse_ginfes/models/document.py new file mode 100644 index 000000000000..3752523db11c --- /dev/null +++ b/l10n_br_nfse_ginfes/models/document.py @@ -0,0 +1,394 @@ +# Copyright 2019 KMEE INFORMATICA LTDA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from nfselib.ginfes.v3_01.servico_enviar_lote_rps_envio import ( + EnviarLoteRpsEnvio, + ListaRpsType, + tcCpfCnpj, + tcDadosServico, + tcDadosTomador, + tcEndereco, + tcIdentificacaoPrestador, + tcIdentificacaoRps, + tcIdentificacaoTomador, + tcInfRps, + tcLoteRps, + tcRps, + tcValores, +) + +from odoo import _, models +from odoo.exceptions import UserError + +from odoo.addons.l10n_br_fiscal.constants.fiscal import ( + EVENT_ENV_HML, + EVENT_ENV_PROD, + MODELO_FISCAL_NFSE, + PROCESSADOR_OCA, + SITUACAO_EDOC_AUTORIZADA, + SITUACAO_EDOC_REJEITADA, +) + +from ..constants.ginfes import CONSULTAR_SITUACAO_LOTE_RPS, RECEPCIONAR_LOTE_RPS + + +def filter_oca_nfse(record): + if record.processador_edoc == PROCESSADOR_OCA and record.document_type_id.code in [ + MODELO_FISCAL_NFSE, + ]: + return True + return False + + +def filter_ginfes(record): + if record.company_id.provedor_nfse == "ginfes": + return True + return False + + +class Document(models.Model): + + _inherit = "l10n_br_fiscal.document" + + def _serialize(self, edocs): + edocs = super()._serialize(edocs) + for record in self.filtered(filter_oca_nfse).filtered(filter_ginfes): + edocs.append(record.serialize_nfse_ginfes()) + return edocs + + def _serialize_ginfes_dados_servico(self): + self.fiscal_line_ids.ensure_one() + dados = self._prepare_dados_servico() + return tcDadosServico( + Valores=tcValores( + ValorServicos=self.convert_type_nfselib( + tcValores, "ValorServicos", dados["valor_servicos"] + ), + ValorDeducoes=self.convert_type_nfselib( + tcValores, "ValorDeducoes", dados["valor_deducoes"] + ), + ValorPis=self.convert_type_nfselib( + tcValores, "ValorPis", dados["valor_pis"] + ), + ValorCofins=self.convert_type_nfselib( + tcValores, "ValorCofins", dados["valor_cofins"] + ), + ValorInss=self.convert_type_nfselib( + tcValores, "ValorInss", dados["valor_inss"] + ), + ValorIr=self.convert_type_nfselib( + tcValores, "ValorIr", dados["valor_ir"] + ), + ValorCsll=self.convert_type_nfselib( + tcValores, "ValorIr", dados["valor_csll"] + ), + IssRetido=self.convert_type_nfselib( + tcValores, "IssRetido", dados["iss_retido"] + ), + ValorIss=self.convert_type_nfselib( + tcValores, "ValorIss", dados["valor_iss"] + ), + ValorIssRetido=self.convert_type_nfselib( + tcValores, "ValorIssRetido", dados["valor_iss_retido"] + ), + OutrasRetencoes=self.convert_type_nfselib( + tcValores, "OutrasRetencoes", dados["outras_retencoes"] + ), + BaseCalculo=self.convert_type_nfselib( + tcValores, "BaseCalculo", dados["base_calculo"] + ), + Aliquota=self.convert_type_nfselib( + tcValores, "Aliquota", dados["aliquota"] + ), + ValorLiquidoNfse=self.convert_type_nfselib( + tcValores, "ValorLiquidoNfse", dados["valor_liquido_nfse"] + ), + ), + ItemListaServico=self.convert_type_nfselib( + tcDadosServico, "ItemListaServico", dados["item_lista_servico"] + ), + CodigoCnae=self.convert_type_nfselib( + tcDadosServico, "CodigoCnae", dados["codigo_cnae"] + ), + CodigoTributacaoMunicipio=self.convert_type_nfselib( + tcDadosServico, + "CodigoTributacaoMunicipio", + dados["codigo_tributacao_municipio"], + ), + Discriminacao=self.convert_type_nfselib( + tcDadosServico, "Discriminacao", dados["discriminacao"] + ), + CodigoMunicipio=self.convert_type_nfselib( + tcDadosServico, "CodigoMunicipio", dados["codigo_municipio"] + ), + ) + + def _serialize_ginfes_dados_tomador(self): + dados = self._prepare_dados_tomador() + return tcDadosTomador( + IdentificacaoTomador=tcIdentificacaoTomador( + CpfCnpj=tcCpfCnpj( + Cnpj=self.convert_type_nfselib(tcCpfCnpj, "Cnpj", dados["cnpj"]), + Cpf=self.convert_type_nfselib(tcCpfCnpj, "Cpf", dados["cpf"]), + ), + InscricaoMunicipal=self.convert_type_nfselib( + tcIdentificacaoTomador, + "InscricaoMunicipal", + dados["inscricao_municipal"], + ), + ), + RazaoSocial=self.convert_type_nfselib( + tcDadosTomador, "RazaoSocial", dados["razao_social"] + ), + Endereco=tcEndereco( + Endereco=self.convert_type_nfselib( + tcEndereco, "Endereco", dados["endereco"] + ), + Numero=self.convert_type_nfselib(tcEndereco, "Numero", dados["numero"]), + Complemento=self.convert_type_nfselib( + tcEndereco, "Complemento", dados["complemento"] + ), + Bairro=self.convert_type_nfselib(tcEndereco, "Bairro", dados["bairro"]), + CodigoMunicipio=self.convert_type_nfselib( + tcEndereco, "CodigoMunicipio", dados["codigo_municipio"] + ), + Uf=self.convert_type_nfselib(tcEndereco, "Uf", dados["uf"]), + Cep=self.convert_type_nfselib(tcEndereco, "Cep", dados["cep"]), + ) + or None, + ) + + def _serialize_ginfes_rps(self, dados): + + return tcRps( + InfRps=tcInfRps( + Id=dados["id"], + IdentificacaoRps=tcIdentificacaoRps( + Numero=self.convert_type_nfselib( + tcIdentificacaoRps, "Numero", dados["numero"] + ), + Serie=self.convert_type_nfselib( + tcIdentificacaoRps, "Serie", dados["serie"] + ), + Tipo=self.convert_type_nfselib( + tcIdentificacaoRps, "Tipo", dados["tipo"] + ), + ), + DataEmissao=self.convert_type_nfselib( + tcInfRps, "DataEmissao", dados["date_in_out"] + ), + NaturezaOperacao=self.convert_type_nfselib( + tcInfRps, "NaturezaOperacao", dados["natureza_operacao"] + ), + RegimeEspecialTributacao=self.convert_type_nfselib( + tcInfRps, + "RegimeEspecialTributacao", + dados["regime_especial_tributacao"], + ), + OptanteSimplesNacional=self.convert_type_nfselib( + tcInfRps, + "OptanteSimplesNacional", + dados["optante_simples_nacional"], + ), + IncentivadorCultural=self.convert_type_nfselib( + tcInfRps, "IncentivadorCultural", dados["incentivador_cultural"] + ), + Status=self.convert_type_nfselib(tcInfRps, "Status", dados["status"]), + RpsSubstituido=self.convert_type_nfselib( + tcInfRps, "RpsSubstituido", dados["rps_substitiuido"] + ), + Servico=self._serialize_ginfes_dados_servico(), + Prestador=tcIdentificacaoPrestador( + Cnpj=self.convert_type_nfselib( + tcIdentificacaoPrestador, "InscricaoMunicipal", dados["cnpj"] + ), + InscricaoMunicipal=self.convert_type_nfselib( + tcIdentificacaoPrestador, + "InscricaoMunicipal", + dados["inscricao_municipal"], + ), + ), + Tomador=self._serialize_ginfes_dados_tomador(), + IntermediarioServico=self.convert_type_nfselib( + tcInfRps, "IntermediarioServico", dados["intermediario_servico"] + ), + ConstrucaoCivil=self.convert_type_nfselib( + tcInfRps, "ConstrucaoCivil", dados["construcao_civil"] + ), + ) + ) + + def _serialize_ginfes_lote_rps(self): + dados = self._prepare_lote_rps() + return tcLoteRps( + Cnpj=self.convert_type_nfselib(tcLoteRps, "Cnpj", dados["cnpj"]), + InscricaoMunicipal=self.convert_type_nfselib( + tcLoteRps, "InscricaoMunicipal", dados["inscricao_municipal"] + ), + QuantidadeRps=1, + ListaRps=ListaRpsType(Rps=[self._serialize_ginfes_rps(dados)]), + ) + + def serialize_nfse_ginfes(self): + lote_rps = EnviarLoteRpsEnvio(LoteRps=self._serialize_ginfes_lote_rps()) + return lote_rps + + def cancel_document_ginfes(self): + for record in self.filtered(filter_oca_nfse).filtered(filter_ginfes): + processador = record._processador_erpbrasil_nfse() + processo = processador.cancela_documento( + doc_numero=int(record.document_number) + ) + + status, message = processador.analisa_retorno_cancelamento(processo) + + if not status: + raise UserError(_(message)) + + record.cancel_event_id = record.event_ids.create_event_save_xml( + company_id=record.company_id, + environment=( + EVENT_ENV_PROD if self.nfe_environment == "1" else EVENT_ENV_HML + ), + event_type="2", + xml_file=processo.envio_xml.decode("utf-8"), + document_id=record, + ) + + return status + + def _document_status(self): + for record in self.filtered(filter_oca_nfse): + processador = record._processador_erpbrasil_nfse() + processo = processador.consulta_nfse_rps( + rps_number=int(record.rps_number), + rps_serie=record.document_serie, + rps_type=int(record.rps_type), + ) + + return _( + processador.analisa_retorno_consulta( + processo, + record.document_number, + record.company_cnpj_cpf, + record.company_legal_name, + ) + ) + + @staticmethod + def _get_protocolo(record, processador, vals): + for edoc in record.serialize(): + processo = None + for p in processador.processar_documento(edoc): + processo = p + + if processo.webservice in RECEPCIONAR_LOTE_RPS: + if processo.resposta.Protocolo is None: + mensagem_completa = "" + if processo.resposta.ListaMensagemRetorno: + lista_msgs = processo.resposta.ListaMensagemRetorno + for mr in lista_msgs.MensagemRetorno: + + correcao = "" + if mr.Correcao: + correcao = mr.Correcao + + mensagem_completa += ( + mr.Codigo + + " - " + + mr.Mensagem + + " - Correção: " + + correcao + + "\n" + ) + vals["edoc_error_message"] = mensagem_completa + record._change_state(SITUACAO_EDOC_REJEITADA) + record.write(vals) + return + protocolo = processo.resposta.Protocolo + + if processo.webservice in CONSULTAR_SITUACAO_LOTE_RPS: + vals["status_code"] = processo.resposta.Situacao + + return vals, protocolo + + @staticmethod + def _set_response(record, processador, protocolo, vals): + processo = processador.consultar_lote_rps(protocolo) + + if processo.resposta: + mensagem_completa = "" + if processo.resposta.ListaMensagemRetorno: + lista_msgs = processo.resposta.ListaMensagemRetorno + for mr in lista_msgs.MensagemRetorno: + + correcao = "" + if mr.Correcao: + correcao = mr.Correcao + + mensagem_completa += ( + mr.Codigo + + " - " + + mr.Mensagem + + " - Correção: " + + correcao + + "\n" + ) + vals["edoc_error_message"] = mensagem_completa + if vals.get("status_code") == 3: + record._change_state(SITUACAO_EDOC_REJEITADA) + + if processo.resposta.ListaNfse: + xml_file = processo.retorno + for comp in processo.resposta.ListaNfse.CompNfse: + vals["document_number"] = comp.Nfse.InfNfse.Numero + vals["authorization_date"] = comp.Nfse.InfNfse.DataEmissao + vals["verify_code"] = comp.Nfse.InfNfse.CodigoVerificacao + record.authorization_event_id.set_done( + status_code=vals["status_code"], + response=vals["status_name"], + protocol_date=vals["authorization_date"], + protocol_number=protocolo, + file_response_xml=xml_file, + ) + record._change_state(SITUACAO_EDOC_AUTORIZADA) + + return vals + + def _eletronic_document_send(self): + super()._eletronic_document_send() + for record in self.filtered(filter_oca_nfse).filtered(filter_ginfes): + processador = record._processador_erpbrasil_nfse() + + protocolo = record.authorization_protocol + vals = dict() + + if not protocolo: + vals, protocolo = self._get_protocolo(record, processador, vals) + + else: + vals["status_code"] = 4 + + if vals.get("status_code") == 1: + vals["status_name"] = _("Not received") + + elif vals.get("status_code") == 2: + vals["status_name"] = _("Batch not yet processed") + + elif vals.get("status_code") == 3: + vals["status_name"] = _("Processed with Error") + + elif vals.get("status_code") == 4: + vals["status_name"] = _("Successfully Processed") + vals["authorization_protocol"] = protocolo + + if vals.get("status_code") in (3, 4): + vals = self._set_response(record, processador, protocolo, vals) + + record.write(vals) + return + + def _exec_before_SITUACAO_EDOC_CANCELADA(self, old_state, new_state): + super()._exec_before_SITUACAO_EDOC_CANCELADA(old_state, new_state) + return self.cancel_document_ginfes() diff --git a/l10n_br_nfse_ginfes/models/res_company.py b/l10n_br_nfse_ginfes/models/res_company.py new file mode 100644 index 000000000000..3c6445fa1429 --- /dev/null +++ b/l10n_br_nfse_ginfes/models/res_company.py @@ -0,0 +1,15 @@ +# Copyright 2020 - TODAY, Marcel Savegnago - Escodoo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResCompany(models.Model): + + _inherit = "res.company" + + provedor_nfse = fields.Selection( + selection_add=[ + ("ginfes", "Ginfes"), + ] + ) diff --git a/l10n_br_nfse_ginfes/readme/CONFIGURE.rst b/l10n_br_nfse_ginfes/readme/CONFIGURE.rst new file mode 100644 index 000000000000..a827a70c7ee1 --- /dev/null +++ b/l10n_br_nfse_ginfes/readme/CONFIGURE.rst @@ -0,0 +1 @@ +É apenas necessário a instalação e configuração do módulo l10n_br_nfse. diff --git a/l10n_br_nfse_ginfes/readme/CONTRIBUTORS.rst b/l10n_br_nfse_ginfes/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..72e4abef82ed --- /dev/null +++ b/l10n_br_nfse_ginfes/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Luis Felipe Mileo +* Gabriel Cardoso de Faria +* Luis Otavio Malta Conceição diff --git a/l10n_br_nfse_ginfes/readme/DESCRIPTION.rst b/l10n_br_nfse_ginfes/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..025d04716349 --- /dev/null +++ b/l10n_br_nfse_ginfes/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +Esse módulo completa o documento criado pelo l10n_br_nfse para permite a criação e transmissão de Notas Fiscais de Serviço Eletrônicas (NFS-e) pelo sistema GINFES. diff --git a/l10n_br_nfse_ginfes/readme/INSTALL.rst b/l10n_br_nfse_ginfes/readme/INSTALL.rst new file mode 100644 index 000000000000..e2c08a6648de --- /dev/null +++ b/l10n_br_nfse_ginfes/readme/INSTALL.rst @@ -0,0 +1,5 @@ +* Este módulo tem uma depedencia do pacote python erpbrasil.edoc +* Este módulo tem uma depedencia do pacote python erpbrasil.assinatura +* Este módulo tem uma depedencia do pacote python erpbrasil.transmissao +* Este módulo tem uma depedencia do pacote python erpbrasil.base +* Este módulo tem uma depedencia do pacote python nfselib diff --git a/l10n_br_nfse_ginfes/readme/ROADMAP.rst b/l10n_br_nfse_ginfes/readme/ROADMAP.rst new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/l10n_br_nfse_ginfes/readme/USAGE.rst b/l10n_br_nfse_ginfes/readme/USAGE.rst new file mode 100644 index 000000000000..f217aefe6260 --- /dev/null +++ b/l10n_br_nfse_ginfes/readme/USAGE.rst @@ -0,0 +1 @@ +Após ser criado uma Nota Fiscal de Serviço Eletrônicas (NFS-e) é possível confirmá-la e transmiti-la. diff --git a/l10n_br_nfse_ginfes/static/description/icon.png b/l10n_br_nfse_ginfes/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/l10n_br_nfse_ginfes/static/description/icon.png differ diff --git a/l10n_br_nfse_ginfes/static/description/index.html b/l10n_br_nfse_ginfes/static/description/index.html new file mode 100644 index 000000000000..0dff68800e59 --- /dev/null +++ b/l10n_br_nfse_ginfes/static/description/index.html @@ -0,0 +1,444 @@ + + + + + + +NFS-e (Ginfes) + + + +
+

NFS-e (Ginfes)

+ + +

Beta License: AGPL-3 OCA/l10n-brazil Translate me on Weblate Try me on Runbot

+

Esse módulo completa o documento criado pelo l10n_br_nfse para permite a criação e transmissão de Notas Fiscais de Serviço Eletrônicas (NFS-e) pelo sistema GINFES.

+

Table of contents

+ +
+

Installation

+
    +
  • Este módulo tem uma depedencia do pacote python erpbrasil.edoc
  • +
  • Este módulo tem uma depedencia do pacote python erpbrasil.assinatura
  • +
  • Este módulo tem uma depedencia do pacote python erpbrasil.transmissao
  • +
  • Este módulo tem uma depedencia do pacote python erpbrasil.base
  • +
  • Este módulo tem uma depedencia do pacote python nfselib
  • +
+
+
+

Configuration

+

É apenas necessário a instalação e configuração do módulo l10n_br_nfse.

+
+
+

Usage

+

Após ser criado uma Nota Fiscal de Serviço Eletrônicas (NFS-e) é possível confirmá-la e transmiti-la.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • KMEE
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainers:

+

gabrielcardoso21 mileo luismalta

+

This module is part of the OCA/l10n-brazil project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/l10n_br_nfse_ginfes/static/src/img/itajuba.png b/l10n_br_nfse_ginfes/static/src/img/itajuba.png new file mode 100644 index 000000000000..b327d17fa2af Binary files /dev/null and b/l10n_br_nfse_ginfes/static/src/img/itajuba.png differ diff --git a/l10n_br_nfse_ginfes/tests/__init__.py b/l10n_br_nfse_ginfes/tests/__init__.py new file mode 100644 index 000000000000..333821c2330f --- /dev/null +++ b/l10n_br_nfse_ginfes/tests/__init__.py @@ -0,0 +1 @@ +from . import test_fiscal_document_nfse_ginfes diff --git a/l10n_br_nfse_ginfes/tests/nfse/001_50_nfse.xml b/l10n_br_nfse_ginfes/tests/nfse/001_50_nfse.xml new file mode 100644 index 000000000000..fa03e595763c --- /dev/null +++ b/l10n_br_nfse_ginfes/tests/nfse/001_50_nfse.xml @@ -0,0 +1,71 @@ + + + 59594315000157 + 35172 + 1 + + + + + 50 + 001 + 1 + + 2020-06-04T13:58:46 + 1 + 1 + 1 + 2 + 1 + + + 100 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 5 + 0 + 0 + 0 + 0.05 + 100 + + 105 + 3101200 + 6311900 + [ODOO_DEV] Customized Odoo Development + 3132404 + + + 59594315000157 + 35172 + + + + + 81493979000189 + + + Cliente 1 SP + + Rua Samuel Morse + 135 + Brooklin + 3550308 + SP + 4576060 + + + + + + + diff --git a/l10n_br_nfse_ginfes/tests/test_fiscal_document_nfse_ginfes.py b/l10n_br_nfse_ginfes/tests/test_fiscal_document_nfse_ginfes.py new file mode 100644 index 000000000000..0443a5b6b122 --- /dev/null +++ b/l10n_br_nfse_ginfes/tests/test_fiscal_document_nfse_ginfes.py @@ -0,0 +1,71 @@ +# Copyright 2020 KMEE INFORMATICA LTDA +# Gabriel Cardoso de Faria +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging +import os +from datetime import datetime + +from xmldiff import main + +from odoo.tools import config + +from odoo.addons.l10n_br_nfse.tests.test_fiscal_document_nfse_common import ( + TestFiscalDocumentNFSeCommon, +) + +from ... import l10n_br_nfse_ginfes + +_logger = logging.getLogger(__name__) + + +class TestFiscalDocumentNFSeGinfes(TestFiscalDocumentNFSeCommon): + def setUp(self): + super(TestFiscalDocumentNFSeGinfes, self).setUp() + + self.company.provedor_nfse = "ginfes" + + def test_nfse_ginfes(self): + """Test NFS-e same state.""" + + xml_path = os.path.join( + l10n_br_nfse_ginfes.__path__[0], "tests", "nfse", "001_50_nfse.xml" + ) + + self.nfse_same_state._onchange_document_serie_id() + self.nfse_same_state._onchange_fiscal_operation_id() + self.nfse_same_state._onchange_company_id() + self.nfse_same_state.rps_number = "50" + self.nfse_same_state.document_number = "50" + + for line in self.nfse_same_state.fiscal_line_ids: + line._onchange_product_id_fiscal() + line._onchange_commercial_quantity() + line._onchange_ncm_id() + line._onchange_fiscal_operation_id() + line._onchange_fiscal_operation_line_id() + line._onchange_fiscal_taxes() + + self.nfse_same_state.action_document_confirm() + + self.nfse_same_state.document_date = datetime.strptime( + "2020-06-04T11:58:46", "%Y-%m-%dT%H:%M:%S" + ) + self.nfse_same_state.date_in_out = datetime.strptime( + "2020-06-04T11:58:46", "%Y-%m-%dT%H:%M:%S" + ) + + self.nfse_same_state.with_context(lang="pt_BR")._document_export() + + output = os.path.join( + config["data_dir"], + "filestore", + self.cr.dbname, + self.nfse_same_state.send_file_id.store_fname, + ) + _logger.info("XML file saved at %s" % (output,)) + + diff = main.diff_files(xml_path, output) + _logger.info("Diff with expected XML (if any): %s" % (diff,)) + + assert len(diff) == 0 diff --git a/requirements.txt b/requirements.txt index 9bd791a09b91..454ed4807c70 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ erpbrasil.edoc erpbrasil.edoc.pdf erpbrasil.transmissao nfelib>=2.0.0 +nfselib.ginfes nfselib.paulistana num2words phonenumbers @@ -14,3 +15,4 @@ pyyaml satcomum unidecode workalendar +xmldiff diff --git a/setup/l10n_br_nfse_ginfes/odoo/addons/l10n_br_nfse_ginfes b/setup/l10n_br_nfse_ginfes/odoo/addons/l10n_br_nfse_ginfes new file mode 120000 index 000000000000..f44df05d62df --- /dev/null +++ b/setup/l10n_br_nfse_ginfes/odoo/addons/l10n_br_nfse_ginfes @@ -0,0 +1 @@ +../../../../l10n_br_nfse_ginfes \ No newline at end of file diff --git a/setup/l10n_br_nfse_ginfes/setup.py b/setup/l10n_br_nfse_ginfes/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/l10n_br_nfse_ginfes/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)