Files
enterprise-addons/l10n_uy_edi/tests/test_manual.py
T

606 lines
30 KiB
Python

from unittest.mock import patch
from odoo import Command, fields
from odoo.exceptions import UserError
from odoo.tests.common import tagged
from . import common
@tagged("-at_install", "post_install", "post_install_l10n", "manual")
class TestManual(common.TestUyEdi):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.company_uy.l10n_uy_edi_ucfe_env = "demo"
def test_10_post_invoice(self):
""" Post EDI UY invoice
* default invoice is e-ticket,
* default taxes auto applied on lines is 22% vat tax
* name after post (should have * ID name)
"""
invoice = self._create_move()
self.assertEqual(invoice.company_id, self.company_uy, "created with wrong company")
self.assertEqual(invoice.journal_id.l10n_uy_edi_type, "electronic", "Invoice is not created on EDI journal")
self.assertEqual(invoice.amount_tax, 22, "invoice taxes are not properly set")
self.assertEqual(invoice.amount_total, 122.0, "invoice taxes has not been applied to the total")
invoice.action_post()
self.assertEqual(invoice.state, "posted", "invoice has not been validate in Odoo")
self.assertEqual(invoice.name, "* %s" % invoice.id, "Not expected name")
def test_20_e_ticket_xml(self):
""" Create/post/send an e-ticket and check that the pre-generated XML is the same as the one expected """
invoice = self._create_move()
self.assertEqual(invoice.l10n_latam_document_type_id.code, "101", "Not e-ticket")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-TK", "20_e_ticket")
def test_30_e_invoice_xml(self):
""" Create e-Invoice, and check that the pre-generated xml is the same as the one expected """
invoice = self._create_move(
partner_id=self.partner_local.id,
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv").id
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "111", "Not an e-invoice")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FC", "30_e_invoice")
def test_40_e_expo_invoice(self):
""" Create an Expo e-invoice, and check that the pre-generated xml is the same as the one expected """
invoice = self._create_move(
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv_exp").id,
partner_id=self.foreign_partner.id,
invoice_incoterm_id=self.env.ref("account.incoterm_FOB").id,
l10n_uy_edi_cfe_sale_mode="1",
l10n_uy_edi_cfe_transport_route="1",
invoice_line_ids=[Command.create({"product_id": self.product_vat_22.id, "price_unit": 100.0})],
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "121", "Not Expo e-invoice")
invoice.action_post()
# IndFact lo cambié de 3 a 10
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FCE", "40_e_expo_invoice")
def test_50_e_ticket_multi_tax_xml(self):
""" Create/post/send an e-ticket with multi tax and check that the pre-generated XML is the same as the one expected """
invoice = self._create_move(
invoice_line_ids=[
Command.create({
"product_id": self.service_vat_22.id,
"price_unit": 100.0,
}),
Command.create({
"product_id": self.service_vat_10.id,
"quantity": 2,
"price_unit": 150,
}),
]
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "101", "Not e-ticket")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-TK", "50_e_ticket_multi_tax")
def test_60_another_currency(self):
""" create an invoice with different currency, also test that Incoterm/Transport is properly set for services """
invoice = self._create_move(
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv_exp").id,
partner_id=self.foreign_partner.id,
l10n_uy_edi_cfe_sale_mode="1",
l10n_uy_edi_cfe_transport_route="1",
currency_id=self.env.ref("base.USD").id,
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "121", "Not Expo e-invoice")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FCE", "60_e_invoice_another_currency")
def test_70_tax_included(self):
tax_22_included = self.tax_22.copy({"price_include_override": "tax_included", "name": "22% VAT (included)"})
tax_10_included = self.tax_10.copy({"price_include_override": "tax_included", "name": "10% VAT (included)"})
tax_0_included = self.tax_0.copy({"price_include_override": "tax_included", "name": "0% VAT (included)"})
invoice = self._create_move(
partner_id=self.partner_local.id,
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv").id,
invoice_line_ids=[
Command.create({
"product_id": self.service_vat_22.id,
"price_unit": 1000,
"tax_ids": tax_22_included,
}),
Command.create({
"product_id": self.service_vat_22.id,
"quantity": 2,
"price_unit": 150,
"tax_ids": tax_10_included,
}),
Command.create({
"product_id": self.service_vat_22.id,
"quantity": 2,
"price_unit": 150,
"tax_ids": tax_0_included,
}),
],
)
invoice.action_post()
self.assertEqual(invoice.l10n_latam_document_type_id.code, "111", "Not e-invoice")
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FC", "70_e_invoice_tax_included")
def test_80_e_ticket_credit_note(self):
""" Create a credit note, validate it, check that we do not get any error. """
invoice = self._create_move()
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-TK", "20_e_ticket")
refund = self._create_credit_note(invoice)
refund.action_post()
self.assertEqual(refund.l10n_latam_document_type_id.code, "102", "Not Credit not document type.")
self._send_and_print(refund)
self._check_cfe(refund, "e-NCTK", "80_e_ticket_credit_note")
def test_81_e_ticket_credit_note_zero_amount(self):
""" Ensure that credit note of a 0.00 e-Ticket must keep the mandatory MntCFEref reference node (DGI CODE 31). """
invoice = self._create_move(invoice_line_ids=[Command.create({
"product_id": self.service_vat_22.id,
"price_unit": 0,
})])
invoice.action_post()
self.assertEqual(invoice.amount_total, 0.0, "Original e-Ticket should have a 0.00 total.")
self._send_and_print(invoice)
refund = self._create_credit_note(invoice)
refund.action_post()
self._send_and_print(refund)
cfe = self.get_xml_tree_from_attachment(refund.l10n_uy_edi_document_id.attachment_id)
namespace = {"cfe": "http://cfe.dgi.gub.uy"}
reference = cfe.find(".//cfe:Referencia/cfe:Referencia", namespace)
mnt_cfe_ref = reference.find("cfe:MntCFEref", namespace)
self.assertIsNotNone(mnt_cfe_ref, "MntCFEref must be present even when the referenced amount is 0.00.")
self.assertEqual(mnt_cfe_ref.text, "0.00")
self.assertIsNotNone(reference.find("cfe:TpoMonedaRef", namespace), "TpoMonedaRef must be present.")
def test_90_e_ticket_debit_note(self):
""" Create a credit note, validate it, check that we do not get any error. """
invoice = self._create_move()
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-TK", "20_e_ticket")
refund = self._create_debit_note(invoice)
refund.action_post()
self.assertEqual(refund.l10n_latam_document_type_id.code, "103", "Not Debit not document type.")
self._send_and_print(refund)
self._check_cfe(refund, "e-NDTK", "90_e_ticket_debit_note")
def test_100_e_ticket_with_disclosures(self):
""" Create/post/send an e-ticket with disclosures and check that the pre-generated XML is the same as the one
expected """
item_legend = self.env['l10n_uy_edi.addenda'].create({
"type": 'item',
"is_legend": True,
"name": 'Leyenda Product/Service Detail',
"content": 'Leyenda Product/Service Detail',
"company_id": self.env.company.id
})
l10n_uy_edi_addenda_ids = self.env['l10n_uy_edi.addenda'].create({
"type": 'cfe_doc',
"is_legend": True,
"name": 'CFE Legend',
"content": 'CFE Legend',
"company_id": self.env.company.id
})
invoice = self._create_move(
l10n_uy_edi_addenda_ids=l10n_uy_edi_addenda_ids.ids,
invoice_line_ids=[Command.create({
"product_id": self.service_vat_22.id,
"price_unit": 100.0,
"l10n_uy_edi_addenda_ids": item_legend.ids,
})],
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "101", "Not e-ticket")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-TK", "100_e_ticket_disclosures")
def test_110_account_move_line_nom_and_desc(self):
"""Test account move with varied products and descriptions"""
long_name = "Product name for testing purposes that intentionally contains more than eighty chars"
products = [
self.env["product.product"].create({"name": "Product Without Description"}),
self.env["product.product"].create({"name": "Product With Description"}),
self.env["product.product"].create({"name": long_name}),
]
addenda = self.env["l10n_uy_edi.addenda"].create(
{
"content": "Addenda Content",
"is_legend": False,
}
)
invoice = self._create_move(
partner_id=self.partner_local.id,
invoice_line_ids=[
Command.create({'product_id': products[0].id}), # Without description
Command.create({'product_id': products[1].id, 'name': 'Custom Description'}), # With description
Command.create({'product_id': products[2].id}), # +80 chars without description
Command.create({'product_id': products[2].id, 'name': 'Custom Description'}), # +80 chars with description
Command.create({'product_id': products[2].id, 'l10n_uy_edi_addenda_ids': [(6, 0, [addenda.id])]}), # +80 chars with addenda
Command.create({'product_id': products[2].id, 'name': 'Custom Description', 'l10n_uy_edi_addenda_ids': [(6, 0, [addenda.id])]}), # +80 chars with desc and addenda
Command.create({'product_id': products[0].id, 'name': False}), # With description deleted by user
Command.create({'product_id': products[0].id, 'name': ''}), # With a empty string as description
],
)
for idx, line in enumerate(invoice.invoice_line_ids):
nom_item, description = invoice._l10n_uy_edi_get_line_nom_and_desc(line)
if idx == 0: # Without description
self.assertEqual(
nom_item, "Product Without Description"[:80], "NomItem mismatch for line without description"
)
self.assertEqual(description, "", "Description mismatch for line without description")
elif idx == 1: # With description
self.assertEqual(
nom_item, "Product With Description"[:80], "NomItem mismatch for line with description"
)
self.assertEqual(description, "Custom Description", "Description mismatch for line with description")
elif idx == 2: # +80 chars without description
self.assertEqual(
nom_item, long_name[:80], "NomItem mismatch for line with long name without description"
)
self.assertEqual(
description, long_name[80:], "Description mismatch for line with long name without description"
)
elif idx == 3: # +80 chars with description
self.assertEqual(nom_item, long_name[:80], "NomItem mismatch for line with long name and description")
self.assertEqual(
description,
f"{long_name[80:]}Custom Description",
"Description mismatch for line with long name and description",
)
elif idx == 4: # +80 chars with addenda
self.assertEqual(nom_item, long_name[:80], "NomItem mismatch for line with long name and addenda")
self.assertIn(
"Addenda Content", description, "Addenda content missing in description for line with addenda"
)
elif idx == 5: # +80 chars with desc and addenda
self.assertEqual(
nom_item, long_name[:80], "NomItem mismatch for line with long name, description, and addenda"
)
self.assertIn(
"Custom Description",
description,
"Custom description missing in description for line with desc and addenda",
)
self.assertIn(
"Addenda Content",
description,
"Addenda content missing in description for line with desc and addenda",
)
elif idx == 6 or idx == 7: # With description deleted by user or ""
self.assertEqual(
nom_item, "Product Without Description"[:80], "NomItem mismatch for line with deleted description"
)
self.assertEqual(description, "", "Description mismatch for line with deleted description")
def test_120_e_ticket_final_consumer(self):
""" Create/post/send an e-ticket and check that the pre-generated XML is the same as the one expected """
invoice = self._create_move(partner_id=self.env.ref("l10n_uy.partner_cfu").id)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "101", "Not e-ticket")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-TK", "120_e_ticket_final_consumer")
def test_default_doc_type_by_id(self):
dc_e_inv = self.env.ref('l10n_uy.dc_e_inv')
move = self._create_move(partner_id=self.env.ref("l10n_uy.partner_cfu").id)
self.assertEqual(move.l10n_latam_document_type_id, self.env.ref('l10n_uy.dc_e_ticket'), "The document type is not being set correctly.")
move.partner_id = self.env.ref('l10n_uy.partner_dgi').id
self.assertEqual(move.l10n_latam_document_type_id, dc_e_inv, "The expected document should be e-invoice")
def test_130_entrega_gratuita(self):
""" Create e-Invoice with line with discount 100% and it should work """
invoice = self._create_move(
partner_id=self.partner_local.id,
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv").id,
invoice_line_ids=[Command.create({
"product_id": self.service_vat_22.id,
"price_unit": 100.0,
"discount": 100.0,
})],
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "111", "Not an e-invoice")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FC", "130_entrega_gratuita")
def test_135_entrega_gratuita_zero(self):
""" Create e-Invoice with line quantity 1.0 and price_unit/price_total = 0.0 (not need discount) """
invoice = self._create_move(
partner_id=self.partner_local.id,
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv").id,
invoice_line_ids=[Command.create({
"product_id": self.service_vat_22.id,
"price_unit": 0,
})],
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "111", "Not an e-invoice")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FC", "135_entrega_gratuita_zero")
def test_140_global_discount(self):
""" Create e-Invoice with line with discount 100% and it should work """
discount = self.env["product.product"].create({
"name": "Discount Product",
"list_price": 10,
"standard_price": 10,
"type": "service",
})
discount_list = [
{"product_id": discount.id, "price_unit": -5.0, "tax_ids": self.tax_22}, # w/product
{"product_id": discount.id, "name": "", "price_unit": -2.0, "tax_ids": self.tax_22}, # w/product & wo/label
{"name": "Discount only Label", "price_unit": -20.0, "tax_ids": self.tax_0}, # wo product but w/label
{"name": "", "price_unit": -10.0, "tax_ids": self.tax_10}, # wo product or label
]
invoice = self._create_move(
ref="test_140_global_discount",
partner_id=self.partner_local.id,
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv").id,
invoice_line_ids=[
Command.create({"product_id": self.service_vat_22.id, "price_unit": 100.0, "tax_ids": self.tax_22}),
Command.create({"product_id": self.service_vat_22.id, "price_unit": 100.0, "tax_ids": self.tax_10}),
Command.create({"product_id": self.service_vat_22.id, "price_unit": 100.0, "tax_ids": self.tax_0}),
] + [Command.create(item) for item in discount_list] # Discounts
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "111", "Not an e-invoice")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FC", "140_global_discount")
def test_150_global_donwpayment(self):
""" Create e-Invoice that is a down payment
invoice_ind = 6 if self._is_downpayment() else invoice_ind
"""
down_payment = self.env["product.product"].create({
"name": "Down Payment",
"list_price": 10,
"standard_price": 10,
"type": "service",
})
invoice = self._create_move(
ref="test_150_global_donwpayment",
partner_id=self.partner_local.id,
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv").id,
invoice_line_ids=[
Command.create({"product_id": down_payment.id, "price_unit": 2000.0, "tax_ids": []}),
])
self.assertEqual(invoice.l10n_latam_document_type_id.code, "111", "Not an e-invoice")
invoice.action_post()
with patch("odoo.addons.account.models.account_move.AccountMove._is_downpayment", return_value=True), \
patch("odoo.addons.sale.models.account_move.AccountMove._is_downpayment", return_value=True), \
patch("odoo.addons.pos_sale.models.account_move.AccountMove._is_downpayment", return_value=True):
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FC", "150_global_donwpayment")
def test_160_deduct_global_donwpayment(self):
""" Create e-Invoice that is a down payment
invoice_ind = 7 if line.quantity < 0 else invoice_ind
"""
down_payment = self.env["product.product"].create({
"name": "Down Payment",
"list_price": 10,
"standard_price": 10,
"type": "service",
})
invoice = self._create_move(
ref="test_160_deduct_global_donwpayment",
partner_id=self.partner_local.id,
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv").id,
invoice_line_ids=[
Command.create({"product_id": self.service_vat_22.id, "price_unit": 10000.0, "tax_ids": self.tax_22}),
Command.create({"product_id": down_payment.id, "quantity": -1.0, "price_unit": 2000.0, "tax_ids": False}),
])
self.assertEqual(invoice.l10n_latam_document_type_id.code, "111", "Not an e-invoice")
invoice.action_post()
url = "odoo.addons.%s.models.account_move_line.AccountMoveLine._get_downpayment_lines"
result_value = invoice.invoice_line_ids.filtered(lambda x: x.quantity < 0.0)
with patch(url % "account", return_value=result_value), patch(url % "sale", return_value=result_value):
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FC", "160_deduct_global_donwpayment")
def test_170_uploaded_vendor_bill_with_global_fixed_discount(self):
""" Simulate upload xml document with global discount fixed line on vendor bill journal and test if it was
created correctly. """
new_bill = self._mock_attachment_upload(
journal=self.company_data['default_journal_purchase'],
filename='vendor_bill_with_global_fixed_discount',
)
self.assertEqual(new_bill.name, "e-FC AF4002353")
self.assertEqual(new_bill.invoice_date.strftime('%Y-%m-%d'), "2024-06-06")
self.assertEqual(new_bill.invoice_date_due.strftime('%Y-%m-%d'), "2024-06-07")
self.assertEqual(new_bill.invoice_partner_display_name, "FIERRO VIGNOLI S.A.")
global_discount_line = new_bill.invoice_line_ids\
.filtered(lambda line: line.name == 'descuento por forma de pago')
self.assertEqual(global_discount_line.price_total, -431.16)
def test_180_uploaded_vendor_bill_with_line_fixed_discount(self):
""" Simulate upload xml document with discount fixed line on vendor bill journal and test if it was created
correctly. """
new_bill = self._mock_attachment_upload(
journal=self.company_data['default_journal_purchase'],
filename='vendor_bill_with_line_fixed_discount',
)
self.assertEqual(new_bill.name, "e-FC F6557758")
self.assertEqual(new_bill.invoice_date.strftime('%Y-%m-%d'), "2024-05-31")
self.assertEqual(new_bill.invoice_date_due.strftime('%Y-%m-%d'), "2024-06-25")
self.assertEqual(new_bill.invoice_partner_display_name, "Administración Nacional de Telecomunicaciones")
def test_190_dedicated_addenda_page(self):
""" Verify that a dedicated addenda page is requested when the addenda are too long. """
def assert_narration_extra_params(invoice, narration, dedicated_addenda):
expected_extra_params = {}
if dedicated_addenda:
expected_extra_params = {
'nombreParametros': {'string': ['adenda']},
'valoresParametros': {'string': ['true']}
}
invoice.narration = narration
_, extra_params = invoice.l10n_uy_edi_document_id._get_report_params()
self.assertEqual(extra_params, expected_extra_params)
invoice = self._create_move(
invoice_line_ids=[
Command.create({
'product_id': self.service_vat_22.id,
'price_unit': 100.0,
}),
],
)
invoice.action_post()
self._send_and_print(invoice) # to generate the l10n_uy_edi.document
line_length = 140
max_lines = 6
# Test narration with exactly the maximum allowed lines (no dedicated page required)
assert_narration_extra_params(invoice, 'A' * line_length * max_lines, False) # 6 lines
# Test narration exceeding the maximum allowed lines (dedicated page required)
assert_narration_extra_params(invoice, 'A' * (line_length * max_lines + 10), True) # 6 lines and 10 chars
assert_narration_extra_params(invoice, 'A\nA\nA' + 'A' * line_length * 4, True) # 7 lines
def test_200_uploaded_vendor_bill_with_two_bills(self):
new_bills = self._mock_attachment_upload(
journal=self.company_data['default_journal_purchase'],
filename='sobre_with_2_vendor_bills',
)
self.assertRecordValues(new_bills, [
{
'name': 'e-FC A6310618',
'invoice_date': fields.Date.to_date('2024-10-03'),
'invoice_partner_display_name': 'BANCO ITAU URUGUAY S.A.',
},
{
'name': 'e-FC A6310619',
'invoice_date': fields.Date.to_date('2024-10-03'),
'invoice_partner_display_name': 'BANCO ITAU URUGUAY S.A.',
},
])
def test_210_e_invoice_xml_with_reduced_vat_tax(self):
""" Create e-Invoice, and check that the pre-generated xml is the same as the one expected """
invoice = self._create_move(
partner_id=self.partner_local.id,
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv").id
)
invoice.invoice_line_ids = [Command.set(invoice.invoice_line_ids.ids)] + [
Command.create({
'product_id': self.service_reduced_vat.id,
'quantity': 1,
'price_unit': 20,
})
]
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FC", "200_e_invoice_with_reduced_vat_tax")
def test_210_usd_company_uyu(self):
""" Test the behavior of invoices in UYU for a company in USD."""
self._configure_usd_company_currency()
invoice = self._create_move(currency_id=self.env.ref("base.UYU").id)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "101", "Not e-ticket")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-TK", "20_e_ticket")
def test_215_usd_company_usd(self):
"""Test the behavior of invoices in USD for a company in USD."""
self._configure_usd_company_currency()
invoice = self._create_move(
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv_exp").id,
partner_id=self.foreign_partner.id,
l10n_uy_edi_cfe_sale_mode="1",
l10n_uy_edi_cfe_transport_route="1",
currency_id=self.env.ref("base.USD").id,
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "121", "Not Expo e-invoice")
invoice.action_post()
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FCE", "60_e_invoice_another_currency")
def test_e_expo_invoice_global_discount(self):
""" Create an Expo e-Invoice (CFE 121) with a global discount line. The discount must be
reported in the DscRcgGlobal section with IndFactDR = 10 (Exportación y asimiladas) and
ValorDR taken from the line tax base (quantity * price_unit, not just the unit price).
MntExpoyAsim and MntTotal must be the total after applying the discount. """
invoice = self._create_move(
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv_exp").id,
partner_id=self.foreign_partner.id,
invoice_incoterm_id=self.env.ref("account.incoterm_FOB").id,
l10n_uy_edi_cfe_sale_mode="1",
l10n_uy_edi_cfe_transport_route="1",
invoice_line_ids=[
Command.create({"product_id": self.product_vat_22.id, "price_unit": 100.0}),
# quantity 2 x -5.0: ValorDR must be 10.00 (the tax base), not abs(price_unit) = 5.00
Command.create({"name": "Global Discount", "quantity": 2.0, "price_unit": -5.0, "tax_ids": self.tax_0}),
],
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "121", "Not Expo e-invoice")
invoice.action_post()
self.assertEqual(invoice.amount_total, 90.0, "Global discount not applied to the total")
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FCE", "230_e_expo_invoice_global_discount")
def test_e_expo_invoice_full_discount(self):
""" Create an Expo e-Invoice fully discounted (total = 0.0). MntExpoyAsim is a mandatory tag
for expo CFEs, so it must be reported with 0.00 value instead of being removed from the XML """
invoice = self._create_move(
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv_exp").id,
partner_id=self.foreign_partner.id,
invoice_incoterm_id=self.env.ref("account.incoterm_FOB").id,
l10n_uy_edi_cfe_sale_mode="1",
l10n_uy_edi_cfe_transport_route="1",
invoice_line_ids=[
Command.create({"product_id": self.product_vat_22.id, "price_unit": 100.0}),
Command.create({"name": "Full Discount", "price_unit": -100.0, "tax_ids": self.tax_0}),
],
)
self.assertEqual(invoice.l10n_latam_document_type_id.code, "121", "Not Expo e-invoice")
invoice.action_post()
self.assertEqual(invoice.amount_total, 0.0, "Global discount not applied to the total")
self._send_and_print(invoice)
self._check_cfe(invoice, "e-FCE", "235_e_expo_invoice_full_discount")
def test_global_discount_tax_mismatch(self):
""" A discount line whose taxes do not match the taxes of any regular line must be rejected
with a pre-send validation error (and the CFE should not be left in error state) """
invoice = self._create_move(
partner_id=self.partner_local.id,
l10n_latam_document_type_id=self.env.ref("l10n_uy.dc_e_inv").id,
invoice_line_ids=[
Command.create({"product_id": self.service_vat_22.id, "price_unit": 100.0, "tax_ids": self.tax_22}),
Command.create({"name": "Discount", "price_unit": -10.0, "tax_ids": self.tax_10}),
],
)
invoice.action_post()
with self.assertRaisesRegex(UserError, "must be associated to another line having the same taxes"):
self._send_and_print(invoice)
# Since it is an internal pre-send validation, the CFE state/error must remain unset
self.assertFalse(invoice.l10n_uy_edi_cfe_state)
self.assertFalse(invoice.l10n_uy_edi_error)