Skip to content

Commit

Permalink
[ADD] l10n_br_mdfe: MDFe webservice tests
Browse files Browse the repository at this point in the history
  • Loading branch information
felipezago committed Oct 6, 2023
1 parent ab0461c commit e3006bf
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 41 deletions.
2 changes: 1 addition & 1 deletion l10n_br_mdfe/models/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,7 @@ def atualiza_status_mdfe(self, processo):
response=infProt.xMotivo,
protocol_date=protocol_date,
protocol_number=infProt.nProt,
file_response_xml=processo.processo_xml,
file_response_xml=processo.processo_xml.decode("utf-8"),
)
self.write(
{
Expand Down
1 change: 1 addition & 0 deletions l10n_br_mdfe/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
from . import test_mdfe_import
from . import test_mdfe_structure
from . import test_mdfe_res_partner
from . import test_mdfe_webservices
from . import test_damdfe
40 changes: 0 additions & 40 deletions l10n_br_mdfe/tests/test_damdfe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import re
from datetime import datetime

from odoo.exceptions import UserError

Expand All @@ -13,47 +12,8 @@ class MDFeDAMDFeTest(TestMDFeSerialize):
def setUp(self):
super().setUp(mdfe_list=[])

FiscalDocument = self.env["l10n_br_fiscal.document"]

self.acre_state = self.env.ref("base.state_br_ac")
self.acre_city = self.env.ref("l10n_br_base.city_1200013")
self.mdfe_document_type_id = self.env.ref("l10n_br_fiscal.document_58")
self.sn_company_id = self.env.ref("l10n_br_base.empresa_simples_nacional")
self.serie_id = self.env.ref("l10n_br_fiscal.empresa_sn_document_58_serie_1")
self.related_nfe_id = self.env.ref("l10n_br_mdfe.demo_mdfe_related_nfe")
self.formatted_related_nfe_key = FiscalDocument._format_document_key(
self.related_nfe_id.mdfe30_chNFe
)

self._create_documents()

def _get_default_document_data(self):
info_descarregamento = [
(
0,
0,
{
"state_id": self.acre_state.id,
"city_id": self.acre_city.id,
"document_type": "nfe",
"nfe_ids": [(6, 0, [self.related_nfe_id.id])],
},
)
]

return {
"document_type_id": self.mdfe_document_type_id.id,
"company_id": self.sn_company_id.id,
"document_serie_id": self.serie_id.id,
"document_date": datetime.now(),
"mdfe_initial_state_id": self.acre_state.id,
"mdfe_final_state_id": self.acre_state.id,
"mdfe_loading_city_ids": [(4, self.acre_city.id)],
"mdfe30_infMunDescarga": info_descarregamento,
"manual_fiscal_additional_data": "FISCAL ADDITIONAL DATA",
"manual_customer_additional_data": "CUSTOMER ADDITIONAL DATA",
}

def _create_documents(self):
FiscalDocument = self.env["l10n_br_fiscal.document"]
default_document_data = self._get_default_document_data()
Expand Down
39 changes: 39 additions & 0 deletions l10n_br_mdfe/tests/test_mdfe_serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ def setUp(self, mdfe_list):
"odoo.addons.l10n_br_mdfe_spec.models.v3_0.mdfe_tipos_basico_v3_00",
)

FiscalDocument = self.env["l10n_br_fiscal.document"]

self.acre_state = self.env.ref("base.state_br_ac")
self.acre_city = self.env.ref("l10n_br_base.city_1200013")
self.mdfe_document_type_id = self.env.ref("l10n_br_fiscal.document_58")
self.sn_company_id = self.env.ref("l10n_br_base.empresa_simples_nacional")
self.serie_id = self.env.ref("l10n_br_fiscal.empresa_sn_document_58_serie_1")
self.related_nfe_id = self.env.ref("l10n_br_mdfe.demo_mdfe_related_nfe")
self.formatted_related_nfe_key = FiscalDocument._format_document_key(
self.related_nfe_id.mdfe30_chNFe
)

self.mdfe_list = mdfe_list
for mdfe_data in self.mdfe_list:
mdfe = self.env.ref(mdfe_data["record_ref"])
Expand Down Expand Up @@ -223,6 +235,33 @@ def prepare_modal_ferroviario_data(self, mdfe):
),
]

def _get_default_document_data(self):
info_descarregamento = [
(
0,
0,
{
"state_id": self.acre_state.id,
"city_id": self.acre_city.id,
"document_type": "nfe",
"nfe_ids": [(6, 0, [self.related_nfe_id.id])],
},
)
]

return {
"document_type_id": self.mdfe_document_type_id.id,
"company_id": self.sn_company_id.id,
"document_serie_id": self.serie_id.id,
"document_date": datetime.now(),
"mdfe_initial_state_id": self.acre_state.id,
"mdfe_final_state_id": self.acre_state.id,
"mdfe_loading_city_ids": [(4, self.acre_city.id)],
"mdfe30_infMunDescarga": info_descarregamento,
"manual_fiscal_additional_data": "FISCAL ADDITIONAL DATA",
"manual_customer_additional_data": "CUSTOMER ADDITIONAL DATA",
}

def serialize_xml(self, mdfe_data):
mdfe = mdfe_data["mdfe"]
xml_path = os.path.join(
Expand Down
163 changes: 163 additions & 0 deletions l10n_br_mdfe/tests/test_mdfe_webservices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Copyright 2023 KMEE (Felipe Zago Rodrigues <[email protected]>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
# pylint: disable=line-too-long

from datetime import datetime
from unittest import mock

from nfelib.mdfe.bindings.v3_0.ret_cons_reci_mdfe_v3_00 import RetConsReciMdfe
from nfelib.mdfe.bindings.v3_0.ret_evento_mdfe_v3_00 import RetEventoMdfe
from nfelib.nfe.ws.edoc_legacy import (
DocumentoElectronicoAdapter as DocumentoEletronico,
analisar_retorno_raw_xsdata,
)

from odoo.fields import Datetime

from odoo.addons.l10n_br_fiscal.constants.fiscal import (
AUTORIZADO,
SITUACAO_EDOC_AUTORIZADA,
SITUACAO_EDOC_CANCELADA,
SITUACAO_EDOC_REJEITADA,
)

from .test_mdfe_serialize import TestMDFeSerialize

# flake8: noqa: B950
response_autorizada = """<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Header><mdfeCabecMsg xmlns="http://www.portalfiscal.inf.br/mdfe/wsdl/MDFeRetRecepcao"><cUF>35</cUF><versaoDados>3.00</versaoDados></mdfeCabecMsg></soap:Header><soap:Body><mdfeRetRecepcaoResult xmlns="http://www.portalfiscal.inf.br/mdfe/wsdl/MDFeRetRecepcao"><retConsReciMDFe versao="3.00" xmlns="http://www.portalfiscal.inf.br/mdfe"><tpAmb>2</tpAmb><verAplic>RS20230517152856</verAplic><nRec>359000011934294</nRec><cStat>104</cStat><xMotivo>Arquivo processado</xMotivo><cUF>35</cUF><protMDFe versao="3.00"><infProt Id="MDFe935230000069676"><tpAmb>2</tpAmb><verAplic>RS20230517152856</verAplic><chMDFe>35231005472475000102580200000700031636764375</chMDFe><dhRecbto>2023-10-06T13:00:00-03:00</dhRecbto><nProt>935230000069676</nProt><digVal>MZn64O3kFyMQ+DEP79F3gt2F0PU=</digVal><cStat>100</cStat><xMotivo>Autorizado o uso do MDF-e</xMotivo></infProt></protMDFe></retConsReciMDFe></mdfeRetRecepcaoResult></soap:Body></soap:Envelope>"""

response_rejeitada = """<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Header><mdfeCabecMsg xmlns="http://www.portalfiscal.inf.br/mdfe/wsdl/MDFeRetRecepcao"><cUF>35</cUF><versaoDados>3.00</versaoDados></mdfeCabecMsg></soap:Header><soap:Body><mdfeRetRecepcaoResult xmlns="http://www.portalfiscal.inf.br/mdfe/wsdl/MDFeRetRecepcao"><retConsReciMDFe versao="3.00" xmlns="http://www.portalfiscal.inf.br/mdfe"><tpAmb>2</tpAmb><verAplic>RS20230517152856</verAplic><nRec>359000011934276</nRec><cStat>104</cStat><xMotivo>Arquivo processado</xMotivo><cUF>35</cUF><protMDFe versao="3.00"><infProt Id="MDFe061020231333341980"><tpAmb>2</tpAmb><verAplic>RS20230517152856</verAplic><chMDFe>35231005472475000102580200000700021636572665</chMDFe><dhRecbto>2023-10-06T13:00:00-03:00</dhRecbto><cStat>204</cStat><xMotivo>Rejeição: Duplicidade de MDF-e [nProt:935230000069668][dhAut:2023-10-06T13:00:00-03:00]</xMotivo></infProt></protMDFe></retConsReciMDFe></mdfeRetRecepcaoResult></soap:Body></soap:Envelope>"""

response_cancelamento = """<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Header><mdfeCabecMsg xmlns="http://www.portalfiscal.inf.br/mdfe/wsdl/MDFeRecepcaoEvento"><cUF>35</cUF><versaoDados>3.00</versaoDados></mdfeCabecMsg></soap:Header><soap:Body><mdfeRecepcaoEventoResult xmlns="http://www.portalfiscal.inf.br/mdfe/wsdl/MDFeRecepcaoEvento"><retEventoMDFe xmlns="http://www.portalfiscal.inf.br/mdfe" versao="3.00"><infEvento Id="ID935230000069678"><tpAmb>2</tpAmb><verAplic>RS20230927085804</verAplic><cOrgao>35</cOrgao><cStat>135</cStat><xMotivo>Evento registrado e vinculado ao MDF-e</xMotivo><chMDFe>35231005472475000102580200000700041639188984</chMDFe><tpEvento>110111</tpEvento><xEvento>Cancelamento</xEvento><nSeqEvento>001</nSeqEvento><dhRegEvento>2023-10-06T13:00:00-03:00</dhRegEvento><nProt>935230000069678</nProt></infEvento></retEventoMDFe></mdfeRecepcaoEventoResult></soap:Body></soap:Envelope>"""

response_encerramento = """<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Header><mdfeCabecMsg xmlns="http://www.portalfiscal.inf.br/mdfe/wsdl/MDFeRecepcaoEvento"><cUF>35</cUF><versaoDados>3.00</versaoDados></mdfeCabecMsg></soap:Header><soap:Body><mdfeRecepcaoEventoResult xmlns="http://www.portalfiscal.inf.br/mdfe/wsdl/MDFeRecepcaoEvento"><retEventoMDFe xmlns="http://www.portalfiscal.inf.br/mdfe" versao="3.00"><infEvento Id="ID935230000069680"><tpAmb>2</tpAmb><verAplic>RS20230927085804</verAplic><cOrgao>35</cOrgao><cStat>135</cStat><xMotivo>Evento registrado e vinculado ao MDF-e</xMotivo><chMDFe>35231005472475000102580200000700011636567559</chMDFe><tpEvento>110112</tpEvento><xEvento>Encerramento</xEvento><nSeqEvento>001</nSeqEvento><dhRegEvento>2023-10-06T13:00:00-03:00</dhRegEvento><nProt>935230000069680</nProt></infEvento></retEventoMDFe></mdfeRecepcaoEventoResult></soap:Body></soap:Envelope>"""


class FakeRetorno(object):
def __init__(self, text):
self.text = text
self.content = text.encode("utf-8")

def raise_for_status(self):
pass


def mocked_mdfe_autorizada(*args, **kwargs):
result = analisar_retorno_raw_xsdata(
"nfeAutorizacaoLote",
object(),
b"<fake_post/>",
FakeRetorno(response_autorizada),
RetConsReciMdfe,
)
result.processo_xml = b"dummy"
return result


def mocked_mdfe_rejeitada(*args, **kwargs):
result = analisar_retorno_raw_xsdata(
"nfeAutorizacaoLote",
object(),
b"<fake_post/>",
FakeRetorno(response_rejeitada),
RetConsReciMdfe,
)
result.processo_xml = b"dummy"
return result


def mock_mdfe_cancelamento(*args, **kwargs):
result = analisar_retorno_raw_xsdata(
"nfeRecepcaoEvento",
object(),
b"<fake_post/>",
FakeRetorno(response_cancelamento),
RetEventoMdfe,
)
result.processo_xml = b"dummy"
return result


def mock_mdfe_encerramento(*args, **kwargs):
result = analisar_retorno_raw_xsdata(

Check warning on line 82 in l10n_br_mdfe/tests/test_mdfe_webservices.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_mdfe/tests/test_mdfe_webservices.py#L82

Added line #L82 was not covered by tests
"nfeRecepcaoEvento",
object(),
b"<fake_post/>",
FakeRetorno(response_encerramento),
RetEventoMdfe,
)
result.processo_xml = b"dummy"
return result

Check warning on line 90 in l10n_br_mdfe/tests/test_mdfe_webservices.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_mdfe/tests/test_mdfe_webservices.py#L89-L90

Added lines #L89 - L90 were not covered by tests


class TestMDFeWebServices(TestMDFeSerialize):
def setUp(self):
super().setUp(mdfe_list=[])

self.sn_company_id.district = "TEST"
self.sn_company_id.street2 = "TEST"

self.document_id = self.env["l10n_br_fiscal.document"].create(
self._get_default_document_data()
)
self.prepare_test_mdfe(self.document_id)

@mock.patch.object(DocumentoEletronico, "_post", side_effect=mocked_mdfe_autorizada)
def test_mdfe_success(self, _mock_post):
self.document_id.action_document_send()

self.assertEqual(self.document_id.state_edoc, SITUACAO_EDOC_AUTORIZADA)

cancel_wizard = (
self.env["l10n_br_fiscal.document.cancel.wizard"]
.with_context(
active_model="l10n_br_fiscal.document", active_id=self.document_id.id
)
.create(
{
"document_id": self.document_id.id,
"justification": "Era apenas um teste.",
}
)
)
with mock.patch.object(
DocumentoEletronico, "_post", side_effect=mock_mdfe_cancelamento
):
cancel_wizard.doit()

self.assertEqual(self.document_id.state_edoc, SITUACAO_EDOC_CANCELADA)
self.assertIsNotNone(self.document_id.cancel_event_id)
self.assertEqual(self.document_id.cancel_event_id.state, "done")
self.assertEqual(self.document_id.cancel_event_id.status_code, "135")
self.assertEqual(
Datetime.to_string(self.document_id.cancel_event_id.protocol_date),
"2023-10-06 13:00:00",
)

@mock.patch.object(DocumentoEletronico, "_post", side_effect=mocked_mdfe_rejeitada)
def test_mdfe_rejeitada(self, _mock_post):
self.document_id.action_document_send()
self.assertEqual(self.document_id.state_edoc, SITUACAO_EDOC_REJEITADA)

def test_atualiza_status_mdfe(self):
mock_autorizada = mock.MagicMock(spec=["resposta"])
mock_autorizada.resposta.protMDFe.infProt.cStat = AUTORIZADO[0]
mock_autorizada.resposta.protMDFe.infProt.xMotivo = "TESTE AUTORIZADO"
mock_autorizada.resposta.protMDFe.infProt.dhRecbto = datetime.now()
mock_autorizada.processo_xml = b"dummy"
self.document_id.atualiza_status_mdfe(mock_autorizada)

self.assertEqual(self.document_id.state_edoc, SITUACAO_EDOC_AUTORIZADA)
self.assertEqual(self.document_id.status_code, AUTORIZADO[0])
self.assertEqual(self.document_id.status_name, "TESTE AUTORIZADO")

def test_qrcode(self):
old_document_type = self.document_id.document_type_id
self.document_id.document_type_id = False

qr_code = self.document_id.get_mdfe_qrcode()
self.assertIsNone(qr_code)

self.document_id.document_type_id = old_document_type
qr_code = self.document_id.get_mdfe_qrcode()
self.assertIsNotNone(qr_code)

0 comments on commit e3006bf

Please sign in to comment.