Fill invoice source amounts instead of checking amounts from UBL
Closes #14624
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Fill invoice source amounts instead of checking amounts
|
||||
* Filter the MIME type of the additional documents allowed by the specification
|
||||
* Use VATEX as tax exemption reason code
|
||||
* Add support for Python 3.14
|
||||
|
||||
@@ -282,7 +282,6 @@ class Invoice(Model):
|
||||
invoice, attachments = cls.parser(namespace)(root)
|
||||
invoice.save()
|
||||
invoice.update_taxes()
|
||||
cls.checker(namespace)(root, invoice)
|
||||
attachments = list(attachments)
|
||||
for attachment in attachments:
|
||||
attachment.resource = invoice
|
||||
@@ -298,15 +297,6 @@ class Invoice(Model):
|
||||
cls._parse_credit_note_2),
|
||||
}.get(namespace)
|
||||
|
||||
@classmethod
|
||||
def checker(cls, namespace):
|
||||
return {
|
||||
'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2': (
|
||||
cls._check_invoice_2),
|
||||
'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2': (
|
||||
cls._check_credit_note_2),
|
||||
}.get(namespace)
|
||||
|
||||
@classmethod
|
||||
def _parse_invoice_2(cls, root):
|
||||
pool = Pool()
|
||||
@@ -406,6 +396,41 @@ class Invoice(Model):
|
||||
'./{*}LegalMonetaryTotal/{*}PayableRoundingAmount')
|
||||
is not None)):
|
||||
invoice.cash_rounding = True
|
||||
|
||||
if tax_exlusive_amount := root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}TaxExclusiveAmount'):
|
||||
untaxed_amount = Decimal(tax_exlusive_amount)
|
||||
|
||||
if allowance_total_amount := root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}AllowanceTotalAmount'):
|
||||
allowance_total_amount = Decimal(allowance_total_amount)
|
||||
untaxed_amount -= allowance_total_amount
|
||||
|
||||
if charge_total_amount := root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}ChargeTotalAmount'):
|
||||
charge_total_amount = Decimal(charge_total_amount)
|
||||
untaxed_amount += charge_total_amount
|
||||
|
||||
invoice.source_untaxed_amount = untaxed_amount
|
||||
|
||||
tax_amount = sum(Decimal(amount.text) for amount in root.iterfind(
|
||||
'./{*}TaxTotal/{*}TaxAmount'))
|
||||
invoice.source_tax_amount = tax_amount
|
||||
|
||||
payable_amount = Decimal(
|
||||
root.findtext('./{*}LegalMonetaryTotal/{*}PayableAmount'))
|
||||
prepaid_amount = Decimal(
|
||||
root.findtext('./{*}LegalMonetaryTotal/{*}PrepaidAmount')
|
||||
or 0)
|
||||
total_amount = payable_amount + prepaid_amount
|
||||
if not getattr(invoice, 'cash_rounding', False):
|
||||
payable_rounding_amount = Decimal(
|
||||
root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}PayableRoundingAmount')
|
||||
or 0)
|
||||
total_amount -= payable_rounding_amount
|
||||
invoice.source_total_amount = total_amount
|
||||
|
||||
return invoice, cls._parse_2_attachments(root)
|
||||
|
||||
@classmethod
|
||||
@@ -682,6 +707,41 @@ class Invoice(Model):
|
||||
'./{*}LegalMonetaryTotal/{*}PayableRoundingAmount')
|
||||
is not None):
|
||||
invoice.cash_rounding = True
|
||||
|
||||
if tax_exlusive_amount := root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}TaxExclusiveAmount'):
|
||||
untaxed_amount = Decimal(tax_exlusive_amount)
|
||||
|
||||
if allowance_total_amount := root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}AllowanceTotalAmount'):
|
||||
allowance_total_amount = Decimal(allowance_total_amount)
|
||||
untaxed_amount -= allowance_total_amount
|
||||
|
||||
if charge_total_amount := root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}ChargeTotalAmount'):
|
||||
charge_total_amount = Decimal(charge_total_amount)
|
||||
untaxed_amount += charge_total_amount
|
||||
|
||||
invoice.source_untaxed_amount = -untaxed_amount
|
||||
|
||||
tax_amount = sum(Decimal(amount.text) for amount in root.iterfind(
|
||||
'./{*}TaxTotal/{*}TaxAmount'))
|
||||
invoice.source_tax_amount = -tax_amount
|
||||
|
||||
payable_amount = Decimal(
|
||||
root.findtext('./{*}LegalMonetaryTotal/{*}PayableAmount'))
|
||||
prepaid_amount = Decimal(
|
||||
root.findtext('./{*}LegalMonetaryTotal/{*}PrepaidAmount')
|
||||
or 0)
|
||||
total_amount = payable_amount + prepaid_amount
|
||||
if not getattr(invoice, 'cash_rounding', False):
|
||||
payable_rounding_amount = Decimal(
|
||||
root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}PayableRoundingAmount')
|
||||
or 0)
|
||||
total_amount -= payable_rounding_amount
|
||||
invoice.source_total_amount = -total_amount
|
||||
|
||||
return invoice, cls._parse_2_attachments(root)
|
||||
|
||||
@classmethod
|
||||
@@ -1259,74 +1319,6 @@ class Invoice(Model):
|
||||
attachment.name = name
|
||||
yield attachment
|
||||
|
||||
@classmethod
|
||||
def _check_invoice_2(cls, root, invoice):
|
||||
pool = Pool()
|
||||
Lang = pool.get('ir.lang')
|
||||
lang = Lang.get()
|
||||
|
||||
payable_amount = Decimal(
|
||||
root.findtext('./{*}LegalMonetaryTotal/{*}PayableAmount'))
|
||||
prepaid_amount = Decimal(
|
||||
root.findtext('./{*}LegalMonetaryTotal/{*}PrepaidAmount')
|
||||
or 0)
|
||||
amount = payable_amount + prepaid_amount
|
||||
if not getattr(invoice, 'cash_rounding', False):
|
||||
payable_rounding_amount = Decimal(
|
||||
root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}PayableRoundingAmount')
|
||||
or 0)
|
||||
amount -= payable_rounding_amount
|
||||
if invoice.total_amount != amount:
|
||||
raise InvoiceError(gettext(
|
||||
'edocument_ubl.msg_invoice_total_amount_different',
|
||||
invoice=invoice.rec_name,
|
||||
total_amount=lang.format_number(invoice.total_amount),
|
||||
amount=lang.format_number(amount)))
|
||||
|
||||
tax_total = sum(Decimal(amount.text) for amount in root.iterfind(
|
||||
'./{*}TaxTotal/{*}TaxAmount'))
|
||||
if invoice.tax_amount != tax_total:
|
||||
raise InvoiceError(gettext(
|
||||
'edocument_ubl.msg_invoice_tax_amount_different',
|
||||
invoice=invoice.rec_name,
|
||||
tax_amount=lang.format_number(invoice.tax_amount),
|
||||
tax_total=lang.format_number(tax_total)))
|
||||
|
||||
@classmethod
|
||||
def _check_credit_note_2(cls, root, invoice):
|
||||
pool = Pool()
|
||||
Lang = pool.get('ir.lang')
|
||||
lang = Lang.get()
|
||||
|
||||
payable_amount = Decimal(
|
||||
root.findtext('./{*}LegalMonetaryTotal/{*}PayableAmount'))
|
||||
prepaid_amount = Decimal(
|
||||
root.findtext('./{*}LegalMonetaryTotal/{*}PrepaidAmount')
|
||||
or 0)
|
||||
amount = payable_amount + prepaid_amount
|
||||
if not getattr(invoice, 'cash_rounding', False):
|
||||
payable_rounding_amount = Decimal(
|
||||
root.findtext(
|
||||
'./{*}LegalMonetaryTotal/{*}PayableRoundingAmount')
|
||||
or 0)
|
||||
amount -= payable_rounding_amount
|
||||
if -invoice.total_amount != amount:
|
||||
raise InvoiceError(gettext(
|
||||
'edocument_ubl.msg_invoice_total_amount_different',
|
||||
invoice=invoice.rec_name,
|
||||
total_amount=lang.format_number(-invoice.total_amount),
|
||||
amount=lang.format_number(amount)))
|
||||
|
||||
tax_total = sum(Decimal(amount.text) for amount in root.iterfind(
|
||||
'./{*}TaxTotal/{*}TaxAmount'))
|
||||
if -invoice.tax_amount != tax_total:
|
||||
raise InvoiceError(gettext(
|
||||
'edocument_ubl.msg_invoice_tax_amount_different',
|
||||
invoice=invoice.rec_name,
|
||||
tax_amount=lang.format_number(-invoice.tax_amount),
|
||||
tax_total=lang.format_number(tax_total)))
|
||||
|
||||
|
||||
class Invoice_Bank(metaclass=PoolMeta):
|
||||
__name__ = 'edocument.ubl.invoice'
|
||||
|
||||
@@ -24,11 +24,5 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="text">Could not find tax for:
|
||||
%(tax_category)s</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_invoice_total_amount_different">
|
||||
<field name="text">The total amount %(total_amount)s of the invoice "%(invoice)s" is different from the amount %(amount)s.</field>
|
||||
</record>
|
||||
<record model="ir.message" id="msg_invoice_tax_amount_different">
|
||||
<field name="text">The tax amount %(tax_amount)s of the invoice "%(invoice)s" is different from the tax total %(tax_total)s.</field>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
|
||||
@@ -79,6 +79,11 @@ Parse the UBL invoice::
|
||||
... Decimal('-1729.00') if cash_rounding else Decimal('-1728.70'))
|
||||
>>> invoice.tax_amount
|
||||
Decimal('-292.20')
|
||||
>>> assertEqual(invoice.source_untaxed_amount, Decimal('-1436.50'))
|
||||
>>> assertEqual(invoice.source_tax_amount, Decimal('-292.20'))
|
||||
>>> assertEqual(
|
||||
... invoice.source_total_amount,
|
||||
... Decimal('-1729.00') if cash_rounding else Decimal('-1728.70'))
|
||||
>>> len(invoice.lines)
|
||||
7
|
||||
|
||||
|
||||
@@ -79,6 +79,11 @@ Parse the UBL invoice::
|
||||
... Decimal('1729.00') if cash_rounding else Decimal('1728.70'))
|
||||
>>> invoice.tax_amount
|
||||
Decimal('292.20')
|
||||
>>> assertEqual(invoice.source_untaxed_amount, Decimal('1436.50'))
|
||||
>>> assertEqual(invoice.source_tax_amount, Decimal('292.20'))
|
||||
>>> assertEqual(
|
||||
... invoice.source_total_amount,
|
||||
... Decimal('1729.00') if cash_rounding else Decimal('1728.70'))
|
||||
>>> len(invoice.lines)
|
||||
7
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ UBL 2 Invoice Parse Trivial
|
||||
Imports::
|
||||
|
||||
>>> import datetime as dt
|
||||
>>> from decimal import Decimal
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.account.tests.tools import create_chart
|
||||
@@ -46,6 +47,9 @@ Parse the UBL invoice::
|
||||
>>> assertEqual(invoice.company, company)
|
||||
>>> invoice.total_amount
|
||||
Decimal('100.00')
|
||||
>>> invoice.source_untaxed_amount
|
||||
>>> assertEqual(invoice.source_tax_amount, Decimal('0.00'))
|
||||
>>> assertEqual(invoice.source_total_amount, Decimal('100.00'))
|
||||
>>> line, = invoice.lines
|
||||
>>> line.description
|
||||
'Cotter pin, MIL-SPEC'
|
||||
|
||||
Reference in New Issue
Block a user