19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:31:16 +01:00
parent 89c6e82fe7
commit 1b82c20a58
572 changed files with 43570 additions and 53303 deletions

View file

@ -1,18 +1,22 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from unittest import skip
from . import common
from odoo.tests import tagged
from odoo import Command
from odoo.tests import Form, tagged
from odoo.tools.float_utils import float_split_str
from odoo.exceptions import ValidationError
@tagged('post_install_l10n', '-at_install', 'post_install')
class TestManual(common.TestAr):
class TestArManual(common.TestArCommon):
@classmethod
def setUpClass(cls):
super(TestManual, cls).setUpClass()
cls.journal = cls._create_journal(cls, 'preprinted')
super().setUpClass()
cls.journal = cls._create_journal('preprinted')
cls.partner = cls.res_partner_adhoc
cls._create_test_invoices_like_demo(cls)
cls._create_test_invoices_like_demo()
def test_01_create_invoice(self):
""" Create and validate an invoice for a Responsable Inscripto
@ -21,31 +25,33 @@ class TestManual(common.TestAr):
* Properly set the tax amount of the product / partner
* Proper fiscal position (this case not fiscal position is selected)
"""
invoice = self._create_invoice()
invoice = self._create_invoice_ar()
self.assertEqual(invoice.company_id, self.company_ri, 'created with wrong company')
self.assertEqual(invoice.amount_tax, 21, 'invoice taxes are not properly set')
self.assertEqual(invoice.amount_total, 121.0, 'invoice taxes has not been applied to the total')
self.assertEqual(invoice.l10n_latam_document_type_id, self.document_type['invoice_a'], 'selected document type should be Factura A')
self._post(invoice)
self.assertEqual(invoice.state, 'posted', 'invoice has not been validate in Odoo')
self.assertEqual(invoice.name, 'FA-A %05d-00000002' % self.journal.l10n_ar_afip_pos_number, 'Invoice number is wrong')
self.assertEqual(invoice.name, 'FA-A %05d-00000001' % self.journal.l10n_ar_afip_pos_number, 'Invoice number is wrong')
self.assertEqual(invoice.sequence_prefix, 'FA-A %05d-' % self.journal.l10n_ar_afip_pos_number)
self.assertEqual(invoice.sequence_number, 1)
def test_02_fiscal_position(self):
# ADHOC SA > IVA Responsable Inscripto > Without Fiscal Positon
invoice = self._create_invoice({'partner': self.partner})
invoice = self._create_invoice_ar(partner_id=self.partner)
self.assertFalse(invoice.fiscal_position_id, 'Fiscal position should be set to empty')
# Consumidor Final > IVA Responsable Inscripto > Without Fiscal Positon
invoice = self._create_invoice({'partner': self.partner_cf})
invoice = self._create_invoice_ar(partner_id=self.partner_cf)
self.assertFalse(invoice.fiscal_position_id, 'Fiscal position should be set to empty')
# Montana Sur > IVA Liberado - Ley Nº 19.640 > Compras / Ventas Zona Franca > IVA Exento
invoice = self._create_invoice({'partner': self.res_partner_montana_sur})
self.assertEqual(invoice.fiscal_position_id, self._search_fp('Compras / Ventas Zona Franca'))
invoice = self._create_invoice_ar(partner_id=self.res_partner_montana_sur)
self.assertEqual(invoice.fiscal_position_id, self._search_fp('Purchases / Sales Free Trade Zone'))
# Barcelona food > Cliente / Proveedor del Exterior > > IVA Exento
invoice = self._create_invoice({'partner': self.res_partner_barcelona_food})
self.assertEqual(invoice.fiscal_position_id, self._search_fp('Compras / Ventas al exterior'))
invoice = self._create_invoice_ar(partner_id=self.res_partner_barcelona_food)
self.assertEqual(invoice.fiscal_position_id, self._search_fp('Purchases / Sales abroad'))
def test_03_corner_cases(self):
""" Mono partner of type Service and VAT 21 """
@ -99,7 +105,83 @@ class TestManual(common.TestAr):
self._prepare_multicurrency_values()
self._post(self.demo_invoices['test_invoice_10'])
def test_15_corner_cases(self):
def test_15_liquido_producto_sales(self):
""" Manual Numbering: Sales and not POS (Liquido Producto) """
# Verify that the default sales journals ara created as is ARCA POS
self.assertTrue(self.journal.l10n_ar_is_pos)
# If we create an invoice it will not use manual numbering
invoice = self._create_invoice_ar()
self.assertFalse(invoice.l10n_latam_manual_document_number)
# Create a new sale journal that is not ARCA POS
self.journal = self._create_journal('preprinted', data={'l10n_ar_is_pos': False})
self.assertFalse(self.journal.l10n_ar_is_pos)
doc_27_lu_a = self.env.ref('l10n_ar.dc_liq_uci_a')
payment_term_id = self.env.ref("account.account_payment_term_end_following_month")
# 60, 61, 27, 28, 45, 46
# In this case manual numbering should be True and the latam document numer should be required
with self.assertRaisesRegex(AssertionError, 'l10n_latam_document_number is a required field'):
with Form(self.env['account.move'].with_context(default_move_type='out_invoice')) as invoice_form:
invoice_form.ref = "demo_liquido_producto_1: Vendor bill liquido producto (DOC 186)"
invoice_form.partner_id = self.res_partner_adhoc
invoice_form.invoice_payment_term_id = payment_term_id
invoice_form.journal_id = self.journal
invoice_form.l10n_latam_document_type_id = doc_27_lu_a
invoice = invoice_form.save()
# Adding the document number will let us to save and validate the number without any problems
with Form(self.env['account.move'].with_context(default_move_type='out_invoice')) as invoice_form:
invoice_form.ref = "demo_liquido_producto_1: Vendor bill liquido producto (DOC 186)"
invoice_form.partner_id = self.res_partner_adhoc
invoice_form.invoice_payment_term_id = payment_term_id
invoice_form.journal_id = self.journal
invoice_form.l10n_latam_document_type_id = doc_27_lu_a
invoice_form.l10n_latam_document_number = "00077-00000077"
invoice = invoice_form.save()
def test_16_liquido_producto_purchase(self):
""" Manual Numbering: Purchase POS/ NOT POS (Liquido Producto) """
# By default purchase journals ar not ARCA POS journal
purchase_not_pos_journal = self.env["account.journal"].search([
('type', '=', 'purchase'), ('company_id', '=', self.env.company.id), ('l10n_latam_use_documents', '=', True)])
self.assertFalse(purchase_not_pos_journal.l10n_ar_is_pos)
doc_60_lp_a = self.env.ref('l10n_ar.dc_a_cvl')
payment_term_id = self.env.ref("account.account_payment_term_end_following_month")
with self.assertRaisesRegex(AssertionError, 'l10n_latam_document_number is a required field'):
with Form(self.env['account.move'].with_context(default_move_type='in_invoice')) as bill_form:
bill_form.ref = "demo_liquido_producto_1: Vendor bill liquido producto (DOC 186)"
bill_form.partner_id = self.res_partner_adhoc
bill_form.invoice_payment_term_id = payment_term_id
bill_form.invoice_date = '2023-02-09'
bill_form.l10n_latam_document_type_id = doc_60_lp_a
bill = bill_form.save()
self.assertEqual(bill.journal_id, purchase_not_pos_journal)
# Create a new journal that is an ARCA POS
purchase_pos_journal = self._create_journal('preprinted', data={'type': 'purchase', 'l10n_ar_is_pos': True})
with Form(self.env['account.move'].with_context(default_move_type='in_invoice')) as bill_form:
bill_form.ref = "demo_liquido_producto_1: Vendor bill liquido producto (DOC 186)"
bill_form.partner_id = self.res_partner_adhoc
bill_form.invoice_payment_term_id = payment_term_id
bill_form.invoice_date = '2023-02-09'
bill_form.journal_id = purchase_pos_journal
bill_form.l10n_latam_document_type_id = doc_60_lp_a
bill_form.l10n_latam_document_number = "00077-00000077"
bill = bill_form.save()
# If we create an invoice it will not use manual numbering
self.assertFalse(bill.l10n_latam_manual_document_number)
def test_17_corner_cases(self):
""" RI partner with VAT exempt and 21. Test price unit digits """
self._post(self.demo_invoices['test_invoice_4'])
decimal_price_digits_setting = self.env.ref('product.decimal_price').digits
@ -113,61 +195,217 @@ class TestManual(common.TestAr):
if len_l10n_ar_price_unit_digits == len_line_price_unit_digits == decimal_price_digits_setting:
self.assertEqual(l10n_ar_price_unit_decimal_part, line_price_unit_decimal_part)
def _get_simple_detail_ar_tax(self, invoice):
""" Get the simple detail_ar_tax list of tuples with the vat group name and the amount
[("vat_taxes", float), ("other_taxes", float)] """
return [
(item.get('group'), item.get('tax_amount'))
for item in invoice._l10n_ar_get_invoice_totals_for_report().get('detail_ar_tax')
]
def test_16_invoice_b_tax_breakdown_1(self):
def test_18_invoice_b_tax_breakdown_1(self):
""" Display Both VAT and Other Taxes """
invoice1 = self._create_invoice_from_dict({
'ref': 'test_invoice_20: Final Consumer Invoice B with multiple vat/perceptions/internal/other/national taxes',
"move_type": 'out_invoice',
"partner_id": self.partner_cf,
"company_id": self.company_ri,
"invoice_date": "2021-03-20",
"invoice_line_ids": [
{'product_id': self.service_iva_21, 'price_unit': 124.3, 'quantity': 3, 'name': 'Support Services 8',
'tax_ids': [(6, 0, [self.tax_21.id, self.tax_perc_iibb.id])]},
{'product_id': self.service_iva_27, 'price_unit': 2250.0, 'quantity': 1,
'tax_ids': [(6, 0, [self.tax_27.id, self.tax_national.id])]},
{'product_id': self.product_iva_105_perc, 'price_unit': 1740.0, 'quantity': 1,
'tax_ids': [(6, 0, [self.tax_10_5.id, self.tax_internal.id])]},
{'product_id': self.product_iva_105_perc, 'price_unit': 10000.0, 'quantity': 1,
'tax_ids': [(6, 0, [self.tax_0.id, self.tax_other.id])]},
invoice = self._create_invoice_ar(
ref='test_invoice_20: Final Consumer Invoice B with multiple vat/perceptions/internal/other/national taxes',
partner_id=self.partner_cf,
company_id=self.company_ri,
invoice_date="2021-03-20",
invoice_line_ids=[
self._prepare_invoice_line(product_id=self.service_iva_21, price_unit=124.3, quantity=3, name='Support Services 8', tax_ids=self.tax_21 + self.tax_perc_iibb),
self._prepare_invoice_line(product_id=self.service_iva_27, price_unit=2250.0, tax_ids=self.tax_27 + self.tax_national),
self._prepare_invoice_line(product_id=self.product_iva_105_perc, price_unit=1740.0, tax_ids=self.tax_10_5 + self.tax_internal),
self._prepare_invoice_line(product_id=self.product_iva_105_perc, price_unit=10000.0, tax_ids=self.tax_0 + self.tax_other),
],
)
results = invoice._l10n_ar_get_invoice_custom_tax_summary_for_report()
self.assertEqual(results, [
{
'tax_amount_currency': 868.51,
'formatted_tax_amount_currency': '868.51',
'name': 'VAT Content $',
},
{
'tax_amount_currency': 142.20,
'formatted_tax_amount_currency': '142.20',
'name': 'Other National Ind. Taxes $',
},
])
self._assert_tax_totals_summary(invoice._l10n_ar_get_invoice_totals_for_report(), {
'same_tax_base': False,
'currency_id': self.currency.id,
'base_amount_currency': 15373.61,
'tax_amount_currency': 100.0,
'total_amount_currency': 15473.61,
'subtotals': [
{
'name': "Untaxed Amount",
'base_amount_currency': 15373.61,
'tax_amount_currency': 100.0,
'tax_groups': [
{
'id': self.tax_perc_iibb.tax_group_id.id,
'base_amount_currency': 372.9,
'tax_amount_currency': 0.0,
'display_base_amount_currency': 372.9,
},
{
'id': self.tax_other.tax_group_id.id,
'base_amount_currency': 10000.0,
'tax_amount_currency': 100.0,
'display_base_amount_currency': False,
},
],
},
],
})
self.assertEqual(self._get_simple_detail_ar_tax(invoice1), [("vat", 868.51), ("other", 142.20)])
def test_17_invoice_b_tax_breakdown_2(self):
def test_19_invoice_b_tax_breakdown_2(self):
""" Display only Other Taxes (VAT taxes are 0) """
invoice2 = self._create_invoice_from_dict({
'ref': 'test_invoice_21: inal Consumer Invoice B with 0 tax and internal tax',
"move_type": 'out_invoice',
"partner_id": self.partner_cf,
"company_id": self.company_ri,
"invoice_date": "2021-03-20",
"invoice_line_ids": [
{'product_id': self.product_iva_105_perc, 'price_unit': 10000.0, 'quantity': 1,
'tax_ids': [(6, 0, [self.tax_no_gravado.id, self.tax_internal.id])]},
],
})
self.assertEqual(self._get_simple_detail_ar_tax(invoice2), [("vat", 0.0), ("other", 300.0)])
invoice = self._create_invoice_ar(
ref='test_invoice_21: Final Consumer Invoice B with 0 tax and internal tax',
partner_id=self.partner_cf,
company_id=self.company_ri,
invoice_date="2021-03-20",
invoice_line_ids=[self._prepare_invoice_line(product_id=self.product_iva_105_perc, price_unit=10000.0, tax_ids=self.tax_no_gravado + self.tax_internal)],
)
results = invoice._l10n_ar_get_invoice_custom_tax_summary_for_report()
self.assertEqual(results, [
{
'tax_amount_currency': 300.00,
'formatted_tax_amount_currency': '300.00',
'name': 'Other National Ind. Taxes $'
},
{
'formatted_tax_amount_currency': '0.00',
'name': 'VAT Content $',
'tax_amount_currency': 0.0
}
def test_18_invoice_b_tax_breakdown_3(self):
])
self._assert_tax_totals_summary(invoice._l10n_ar_get_invoice_totals_for_report(), {
'same_tax_base': True,
'currency_id': self.currency.id,
'base_amount_currency': 10300.0,
'tax_amount_currency': 0.0,
'total_amount_currency': 10300.0,
'subtotals': [],
})
def test_20_invoice_b_tax_breakdown_3(self):
""" Display only Other Taxes (VAT taxes are 0 and non other taxes) """
invoice3 = self._create_invoice_from_dict({
'ref': 'test_invoice_22: Final Consumer Invoice B with 0 only',
invoice = self._create_invoice_ar(
ref='test_invoice_22: Final Consumer Invoice B with only 0 tax',
partner_id=self.partner_cf,
company_id=self.company_ri,
invoice_date="2021-03-20",
invoice_line_ids=[self._prepare_invoice_line(product_id=self.product_iva_105_perc, price_unit=10000.0, tax_ids=self.tax_no_gravado)],
)
results = invoice._l10n_ar_get_invoice_custom_tax_summary_for_report()
self.assertEqual(results, [
{
'tax_amount_currency': 0.0,
'formatted_tax_amount_currency': '0.00',
'name': 'VAT Content $'
},
])
self._assert_tax_totals_summary(invoice._l10n_ar_get_invoice_totals_for_report(), {
'same_tax_base': True,
'currency_id': self.currency.id,
'base_amount_currency': 10000.0,
'tax_amount_currency': 0.0,
'total_amount_currency': 10000.0,
'subtotals': [],
})
def test_l10n_ar_prices_and_taxes(self):
invoice = self.env['account.move'].create({
"move_type": 'out_invoice',
"partner_id": self.partner_cf,
"company_id": self.company_ri,
"invoice_date": "2021-03-20",
"partner_id": self.partner_cf.id,
"invoice_date": "2020-01-21",
"invoice_line_ids": [
{'product_id': self.product_iva_105_perc, 'price_unit': 10000.0, 'quantity': 1,
'tax_ids': [(6, 0, [self.tax_no_gravado.id])]},
Command.create({
'product_id': self.product_iva_105_perc.id,
'quantity': 24.0,
'price_unit': 5470.0,
'discount': 5.0,
'tax_ids': [Command.set(self.tax_21.ids)],
}),
],
})
self.assertEqual(self._get_simple_detail_ar_tax(invoice3), [("vat", 0.0)])
invoice_line = invoice.invoice_line_ids
# Included in VAT
l10n_ar_values = invoice_line._l10n_ar_prices_and_taxes()
self.assertAlmostEqual(l10n_ar_values['price_unit'], 6618.7)
self.assertAlmostEqual(l10n_ar_values['price_subtotal'], 150906.36)
self.assertAlmostEqual(l10n_ar_values['price_net'], 6287.765)
# Not include in VAT
doc_27_lu_a = self.env.ref('l10n_ar.dc_liq_uci_a')
invoice.l10n_latam_document_type_id = doc_27_lu_a
l10n_ar_values = invoice_line._l10n_ar_prices_and_taxes()
self.assertAlmostEqual(l10n_ar_values['price_unit'], 5470.0)
self.assertAlmostEqual(l10n_ar_values['price_subtotal'], 124716.0)
self.assertAlmostEqual(l10n_ar_values['price_net'], 5196.5)
def test_l10n_ar_vat_with_non_numeric_value(self):
with self.assertRaises(ValidationError) as e:
with Form(self.partner) as partner_form:
partner_form.l10n_latam_identification_type_id = self.env.ref("l10n_ar.it_dni")
partner_form.vat = "test"
self.assertIn('Only numbers allowed for "DNI"', str(e.exception))
def test_create_debit_note_for_credit_note(self):
"""
Test that it is possible to create a debit note from a credit note
"""
invoice = self.init_invoice('out_invoice', partner=self.partner_afip, products=[self.product_a], post=True)
credit_note_wizard = self.env['account.move.reversal'].with_context({
'active_ids': invoice.ids,
'active_model': 'account.move',
}).create({
'reason': 'credit note',
'journal_id': invoice.journal_id.id,
})
credit_note_wizard.refund_moves()
invoice.reversal_move_ids.action_post()
debit_note_wizard = self.env['account.debit.note'].with_context({
'active_ids': invoice.reversal_move_ids.ids,
'active_model': 'account.move',
}).create({
'reason': 'debit_note',
})
debit_note_wizard.create_debit()
self.assertTrue(invoice.reversal_move_ids.debit_note_ids)
@skip("TODO: failing test. 'Fix' the rounding error")
def test_l10n_ar_rounding_01(self):
self.env.company.tax_calculation_rounding_method = 'round_globally'
currency_usd = self.env.ref('base.USD')
currency_usd.active = True
self.env['res.currency.rate'].create([{
'name': '2025-04-01',
'inverse_company_rate': 1066.50,
'currency_id': currency_usd.id,
'company_id': self.env.company.id,
}])
tax_02 = self.percent_tax(0.2)
invoice_a = self._create_invoice_ar(
invoice_date='2025-04-02',
currency_id=currency_usd,
invoice_line_ids=[self._prepare_invoice_line(price_unit=124, tax_ids=tax_02)],
)
self.assertEqual(invoice_a.amount_total, invoice_a.invoice_line_ids.price_total, 'The invoice total should match the line total since there is only one line.')
tax_lines_a = invoice_a.line_ids \
.filtered(lambda x: x.tax_line_id) \
.sorted(lambda x: (x.move_id.id, x.tax_line_id.id, x.tax_ids.ids, x.tax_repartition_line_id.id))
self.env.company.tax_calculation_rounding_method = 'round_per_line'
invoice_b = self._create_invoice_ar(
invoice_date='2025-04-02',
currency_id=currency_usd,
invoice_line_ids=[self._prepare_invoice_line(price_unit=124, tax_ids=tax_02)],
)
self.assertEqual(invoice_b.amount_total, invoice_b.invoice_line_ids.price_total, 'The invoice total should match the line total since there is only one line.')
tax_lines_b = invoice_b.line_ids \
.filtered(lambda x: x.tax_line_id) \
.sorted(lambda x: (x.move_id.id, x.tax_line_id.id, x.tax_ids.ids, x.tax_repartition_line_id.id))
self.assertEqual(tax_lines_a.balance, tax_lines_b.balance, 'Tax balances should be equal since both invoices have a single line and the total matches the line amount.')