Files
enterprise-addons/l10n_co_dian/tests/test_commercial_events.py
T

268 lines
12 KiB
Python

import uuid
from lxml import etree
from datetime import datetime
from unittest.mock import patch
from dateutil.relativedelta import relativedelta
from odoo.exceptions import UserError
from odoo.tests import freeze_time, tagged
from odoo.addons.l10n_co_dian import xml_utils
from .common import TestCoDianCommon
@freeze_time('2024-01-30')
@tagged('post_install_l10n', 'post_install', '-at_install')
class TestCommercialEvents(TestCoDianCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
# send invoice to our own company so we don't have to switch companies when sending events
cls.yesterday = cls.frozen_today - relativedelta(days=1)
cls.invoice = cls._create_move(
partner_id=cls.company_data['company'].partner_id.id,
freeze_date=cls.yesterday,
)
cls.bill_pending_document_data = {
'state': 'invoice_accepted',
'commercial_state': 'pending',
}
# -------------------------------------------------------------------------
# HELPERS
# -------------------------------------------------------------------------
def _create_commercial_event_bill(self, invoice):
return self._create_move(
freeze_date=self.yesterday,
partner_id=self.company_data['company'].partner_id.id,
move_type='in_invoice',
invoice_date=self.yesterday,
journal_id=self.company_data['default_journal_purchase'].id,
ref=invoice.name,
l10n_co_edi_cufe_cude_ref=invoice.l10n_co_edi_cufe_cude_ref,
)
def _get_status_event(self, invoice, response_file):
with self._mock_build_and_send_request(response_file=response_file):
invoice.l10n_co_dian_action_update_event_status()
# -------------------------------------------------------------------------
# TESTS
# -------------------------------------------------------------------------
def test_accept_by_customer(self):
self._mock_send_and_print(move=self.invoice, response_file='SendBillSync_warnings.xml')
self.assertTrue(self.invoice.l10n_co_dian_attachment_id)
self.assertTrue(self.invoice.l10n_co_edi_cufe_cude_ref)
self.assertEqual(len(self.invoice.l10n_co_dian_document_ids), 1)
invoice_document_pending_values = {
'state': 'invoice_accepted',
'commercial_state': 'pending',
}
self.assertRecordValues(self.invoice.l10n_co_dian_document_ids.sorted(), [invoice_document_pending_values])
bill = self._create_commercial_event_bill(self.invoice)
with self._mock_build_and_send_request('CommercialEvent.xml'):
bill.l10n_co_dian_send_event_update_status_received()
bill_identifier = bill.l10n_co_edi_cufe_cude_ref
self.assertTrue(bill_identifier)
self.assertEqual(len(bill.l10n_co_dian_document_ids), 2)
self.assertTrue(bill.l10n_co_dian_document_ids[0].identifier)
bill_document_received_values = {
'state': 'invoice_accepted',
'commercial_state': 'received',
}
self.assertRecordValues(bill.l10n_co_dian_document_ids.sorted(), [bill_document_received_values, self.bill_pending_document_data])
# The document contains a history of the events, so will be different after each state change. It will be sent
# by email to the vendor when the commercial state is updated, check if it is correct.
validation_document = bill.l10n_co_dian_attachment_id
xml = xml_utils._unzip(validation_document.raw)
self._assert_document_dian(xml, 'l10n_co_dian/tests/attachments/commercial_event_attached_document.xml')
with self._mock_build_and_send_request('CommercialEvent.xml'):
bill.l10n_co_dian_send_event_update_status_goods_received()
self.assertRecordValues(bill, [{'l10n_co_edi_cufe_cude_ref': bill_identifier}])
self.assertEqual(len(bill.l10n_co_dian_document_ids), 3)
bill_document_goods_received_values = {
'state': 'invoice_accepted',
'commercial_state': 'goods_received',
}
self.assertRecordValues(bill.l10n_co_dian_document_ids.sorted(), [
bill_document_goods_received_values,
bill_document_received_values,
self.bill_pending_document_data,
])
with self._mock_build_and_send_request('CommercialEvent.xml'):
bill.l10n_co_dian_send_event_update_status_accepted()
self.assertRecordValues(bill, [{'l10n_co_edi_cufe_cude_ref': bill_identifier}])
self.assertEqual(len(bill.l10n_co_dian_document_ids), 4)
bill_document_accepted_values = {
'state': 'invoice_accepted',
'commercial_state': 'accepted',
}
self.assertRecordValues(bill.l10n_co_dian_document_ids.sorted(), [
bill_document_accepted_values,
bill_document_goods_received_values,
bill_document_received_values,
self.bill_pending_document_data,
])
# Check that the vendor bill PDF does not crash when the DIAN attachment is a zipped AttachedDocument.
try:
bill._l10n_co_dian_get_invoice_report_qr_code_value()
except etree.XMLSyntaxError:
self.fail("Unexpected XMLSyntaxError while generating the report QR code")
def test_get_status_event(self):
self._mock_send_and_print(move=self.invoice, response_file='SendBillSync_warnings.xml')
self.assertTrue(self.invoice.l10n_co_dian_attachment_id)
self.assertEqual(len(self.invoice.l10n_co_dian_document_ids), 1)
invoice_document_pending_values = {
'state': 'invoice_accepted',
'commercial_state': 'pending',
}
self.assertRecordValues(self.invoice.l10n_co_dian_document_ids.sorted(), [invoice_document_pending_values])
self.assertTrue(self.invoice.l10n_co_dian_document_ids.identifier)
self.assertRecordValues(self.invoice, [{
'l10n_co_edi_cufe_cude_ref': self.invoice.l10n_co_dian_document_ids.identifier,
}])
bill = self._create_commercial_event_bill(self.invoice)
# GetStatusEvent while no events have been sent yet
self._get_status_event(self.invoice, 'GetStatusEvent_no_events.xml')
self.assertEqual(len(self.invoice.l10n_co_dian_document_ids), 2)
invoice_rejected_document_values = {
'state': 'invoice_rejected',
'commercial_state': False,
}
documents = self.invoice.l10n_co_dian_document_ids.sorted()
self.assertRecordValues(self.invoice, [{
'l10n_co_edi_cufe_cude_ref': documents[-1].identifier,
}])
self.assertRecordValues(documents, [
invoice_rejected_document_values,
invoice_document_pending_values,
])
self.assertRecordValues(documents[0], [{
'message': "<p>EL CUFE o Factura consultada no tiene a la fecha eventos asociados.</p>",
}])
# Rejected commercial event
with self._mock_build_and_send_request('CommercialEventRejected.xml'):
bill.l10n_co_dian_send_event_update_status_received()
self.assertEqual(len(bill.l10n_co_dian_document_ids), 2)
self.assertRecordValues(bill.l10n_co_dian_document_ids.sorted(), [
{'state': 'invoice_rejected', 'commercial_state': 'received'},
self.bill_pending_document_data,
])
# Send the commercial event succesfully after a rejection
with self._mock_build_and_send_request('CommercialEvent.xml'):
bill.l10n_co_dian_send_event_update_status_received()
self.assertEqual(len(bill.l10n_co_dian_document_ids), 2)
bill_document_received_values = {
'state': 'invoice_accepted',
'commercial_state': 'received',
}
self.assertRecordValues(bill.l10n_co_dian_document_ids.sorted(), [bill_document_received_values, self.bill_pending_document_data])
self._get_status_event(self.invoice, 'GetStatusEvent_received.xml')
documents = self.invoice.l10n_co_dian_document_ids.sorted()
self.assertEqual(len(documents), 2)
invoice_document_received_values = {
'state': 'invoice_accepted',
'commercial_state': 'received',
}
self.assertRecordValues(documents, [
invoice_document_received_values,
invoice_document_pending_values,
])
self.assertRecordValues(self.invoice, [{
'l10n_co_edi_cufe_cude_ref': documents[-1].identifier,
}])
# GetStatusEvent after a second event
with self._mock_build_and_send_request('CommercialEvent.xml'):
bill.l10n_co_dian_send_event_update_status_goods_received()
self.assertEqual(len(bill.l10n_co_dian_document_ids), 3)
bill_document_goods_received_values = {
'state': 'invoice_accepted',
'commercial_state': 'goods_received',
}
self.assertRecordValues(bill.l10n_co_dian_document_ids.sorted(), [
bill_document_goods_received_values,
bill_document_received_values,
self.bill_pending_document_data,
])
self._get_status_event(self.invoice, 'GetStatusEvent_goods_received.xml')
documents = self.invoice.l10n_co_dian_document_ids.sorted()
self.assertEqual(len(documents), 3)
invoice_document_goods_received_values = {
'state': 'invoice_accepted',
'commercial_state': 'goods_received',
}
self.assertRecordValues(documents, [
invoice_document_goods_received_values,
invoice_document_received_values,
invoice_document_pending_values,
])
self.assertRecordValues(self.invoice, [{
'l10n_co_edi_cufe_cude_ref': documents[-1].identifier,
}])
def test_event_xml_structure(self):
self._mock_send_and_print(move=self.invoice, response_file='SendBillSync_warnings.xml')
bill = self._create_commercial_event_bill(self.invoice)
company = bill.company_id
invoice_mode = company.l10n_co_dian_operation_mode_ids.filtered(
lambda m: m.dian_software_operation_mode == 'invoice'
)
invoice_mode.dian_software_id = 'software-id'
bill.ref = 'SETP990013077'
bill.l10n_co_edi_cufe_cude_ref = 'abcdef'
uuids = iter([
uuid.UUID('9e25b182-2955-11f1-bd9d-1163e06b857c'),
uuid.UUID('9e25b1f0-2955-11f1-bd9d-1163e06b857c'),
])
with (
freeze_time(datetime(2026, 3, 26, 20, 51, 52, 742000)),
patch(f'{self.utils_path}._uuid1', lambda: next(uuids)),
):
xml, errors = self.env['account.edi.xml.ubl_dian']._export_co_send_event_update_status_invoice(bill, 'received')
self.assertFalse(errors)
self._assert_document_dian(xml, 'l10n_co_dian/tests/attachments/commercial_event_received.xml')
def test_warning_on_different_DIAN_operation_mode(self):
company = self.invoice.company_id
company.l10n_co_dian_test_environment = True
company.l10n_co_dian_certification_process = True
bill_operation_mode = company.l10n_co_dian_operation_mode_ids.filtered(
lambda mode: mode.dian_software_operation_mode == 'bill'
)
self.assertTrue(bill_operation_mode, "Bill operation mode should exist.")
company.l10n_co_dian_operation_mode_ids = [(6, 0, bill_operation_mode.ids)]
self.assertEqual(
company.l10n_co_dian_operation_mode_ids.dian_software_operation_mode,
'bill',
"Company operation mode should be set to 'bill'."
)
self.invoice.l10n_co_edi_cufe_cude_ref = 'test_cufe'
bill = self._create_commercial_event_bill(self.invoice)
with self.assertRaisesRegex(UserError, "No DIAN Operation Mode Matches"):
bill.l10n_co_dian_send_event_update_status_received()