Files

284 lines
10 KiB
Python
Raw Permalink Normal View History

2025-11-14 16:36:06 +01:00
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime
import os
from decimal import Decimal
from unittest.mock import MagicMock, Mock, patch
from lxml import etree
from trytond.pool import Pool
2025-11-20 13:08:49 +01:00
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
2025-11-14 16:36:06 +01:00
def get_invoice():
pool = Pool()
Address = pool.get('party.address')
Company = pool.get('company.company')
Country = pool.get('country.country')
Currency = pool.get('currency.currency')
Identifier = pool.get('party.identifier')
Invoice = pool.get('account.invoice')
InvoiceLine = pool.get('account.invoice.line')
InvoiceTax = pool.get('account.invoice.tax')
MoveLine = pool.get('account.move.line')
Party = pool.get('party.party')
PaymentTerm = pool.get('account.invoice.payment_term')
Product = pool.get('product.product')
Tax = pool.get('account.tax')
Uom = pool.get('product.uom')
address = Mock(spec=Address,
street_unstructured="St sample, 15",
street="St sample, 15\n2nd floor\nBox 1234\n",
2025-11-14 16:36:06 +01:00
city="Scranton",
postal_code="1000",
subdivision=None,
country=Mock(spec=Country,
code='US'),
)
address.building_name = "Building A"
address.country.name = "United States"
identifier = MagicMock(
spec=Identifier,
type='be_vat',
code='BE123456789')
type(identifier).iso_6523 = Identifier.iso_6523
type(identifier)._eas_type = Identifier._eas_type
2025-11-14 16:36:06 +01:00
type(identifier).eas = Identifier.eas
type(identifier).unece_code = Identifier.unece_code
party = MagicMock(
spec=Party,
addresses=[address],
identifiers=[identifier],
)
type(party).identifier_iso6523 = Party.identifier_iso6523
type(party).identifier_eas = Party.identifier_eas
party.name = "Michael Scott"
company = Mock(spec=Company,
party=Mock(
spec=Party,
addresses=[Mock(spec=Address,
street_unstructured="Main street, 42",
street="Main street, 42",
2025-11-14 16:36:06 +01:00
country=Mock(spec=Country,
code='US'))],
identifiers=[Mock(
spec=Identifier,
type='us_ein',
code='911144442')],
))
company.party.name = "Dunder Mifflin"
company.party.address_get = Mock(return_value=company.party.addresses[0])
taxes = [Mock(spec=InvoiceTax,
tax=Mock(spec=Tax,
legal_notice="Legal Notice",
unece_category_code='S',
unece_code='VAT',
type='percentage',
rate=Decimal('.1'),
),
2026-01-26 15:38:06 +01:00
base=Decimal('105.00'),
amount=Decimal('10.50'),
2025-11-14 16:36:06 +01:00
legal_notice="Legal Notice",
)]
product = Mock(spec=Product,
code="12345",
type='service',
2026-01-26 15:38:06 +01:00
unece_special_service_code=None,
2025-11-14 16:36:06 +01:00
)
product.name = "Product"
product.identifier_get.return_value = '98412345678908'
2026-01-26 15:38:06 +01:00
charge = Mock(spec=Product,
type='service',
unece_special_service_code='ZZZ',
)
charge.name = "Charge"
2025-11-14 16:36:06 +01:00
lines = [Mock(spec=InvoiceLine,
type='line',
product=product,
unit=Mock(spec=Uom,
),
quantity=1,
unit_price=Decimal('100.0000'),
amount=Decimal('100.00'),
description="Description",
invoice_taxes=taxes,
2026-01-26 15:38:06 +01:00
), Mock(spec=Invoice,
type='line',
product=charge,
quantity=1,
amount=Decimal('5.00'),
invoice_taxes=taxes,
2025-11-14 16:36:06 +01:00
)]
invoice = MagicMock(spec=Invoice,
id=-1,
__int__=Mock(return_value=-1),
type='out',
sequence_type='invoice',
number="001",
party=party,
party_lang='fr',
party_tax_identifier=identifier,
invoice_address=party.addresses[0],
company=company,
currency=Mock(spec=Currency,
code='USD',
round=lambda a: a),
invoice_date=datetime.date.today(),
reference="PO1234",
payment_term=Mock(spec=PaymentTerm, description="Direct"),
lines=lines,
line_lines=lines,
taxes=taxes,
2026-01-26 15:38:06 +01:00
untaxed_amount=Decimal('105.00'),
tax_amount=Decimal('10.50'),
total_amount=Decimal('110.50'),
amount_to_pay=Decimal('110.50'),
2025-11-14 16:36:06 +01:00
lines_to_pay=[Mock(spec=MoveLine,
maturity_date=datetime.date.today(),
2026-01-26 15:38:06 +01:00
amount=Decimal('110.50'),
2025-11-14 16:36:06 +01:00
)],
sales=[],
state='posted',
)
2026-01-26 15:38:06 +01:00
for line in invoice.lines:
line.invoice = invoice
2025-11-14 16:36:06 +01:00
return invoice
class EdocumentUblTestCase(ModuleTestCase):
"Test Edocument Ubl module"
module = 'edocument_ubl'
extras = [
'account_invoice', 'document_incoming_invoice', 'purchase', 'sale']
2025-11-14 16:36:06 +01:00
@with_transaction()
def test_Invoice_2(self):
"Test Invoice-2"
pool = Pool()
Template = pool.get('edocument.ubl.invoice')
InvoiceReport = pool.get('account.invoice', type='report')
with patch.object(InvoiceReport, 'execute') as execute:
execute.return_value = ['pdf', b'data', False, 'Invoice-1234']
invoice = get_invoice()
template = Template(invoice)
invoice_string = template.render('2')
invoice_xml = etree.fromstring(invoice_string)
schema_file = os.path.join(
os.path.dirname(__file__),
'2.4', 'maindoc', 'UBL-Invoice-2.4.xsd')
schema = etree.XMLSchema(etree.parse(schema_file))
schema.assertValid(invoice_xml)
@with_transaction()
def test_Invoice_2_Peppol_BIS_3(self):
"Test Invoice-2"
pool = Pool()
Template = pool.get('edocument.ubl.invoice')
InvoiceReport = pool.get('account.invoice', type='report')
with patch.object(InvoiceReport, 'execute') as execute:
execute.return_value = ['pdf', b'data', False, 'Invoice-1234']
invoice = get_invoice()
template = Template(invoice)
invoice_string = template.render('2', specification='peppol-bis-3')
invoice_xml = etree.fromstring(invoice_string)
schema_file = os.path.join(
os.path.dirname(__file__),
'2.4', 'maindoc', 'UBL-Invoice-2.4.xsd')
schema = etree.XMLSchema(etree.parse(schema_file))
schema.assertValid(invoice_xml)
@with_transaction()
def test_CreditNote_2(self):
"Test CreditNote-2"
pool = Pool()
Template = pool.get('edocument.ubl.invoice')
InvoiceReport = pool.get('account.invoice', type='report')
with patch.object(InvoiceReport, 'execute') as execute:
execute.return_value = ['pdf', b'data', False, 'Invoice-1234']
invoice = get_invoice()
invoice.sequence_type = 'credit_note'
for line in invoice.lines:
line.quantity *= -1
invoice.untaxed_amount *= -1
invoice.tax_amount *= -1
invoice.total_amount *= -1
invoice.amount_to_pay *= -1
for line in invoice.lines_to_pay:
line.amount *= -1
template = Template(invoice)
invoice_string = template.render('2')
invoice_xml = etree.fromstring(invoice_string)
schema_file = os.path.join(
os.path.dirname(__file__),
'2.4', 'maindoc', 'UBL-CreditNote-2.4.xsd')
schema = etree.XMLSchema(etree.parse(schema_file))
schema.assertValid(invoice_xml)
@with_transaction()
def test_CreditNote_2_Peppol_BIS_3(self):
"Test CreditNote-2"
pool = Pool()
Template = pool.get('edocument.ubl.invoice')
InvoiceReport = pool.get('account.invoice', type='report')
with patch.object(InvoiceReport, 'execute') as execute:
execute.return_value = ['pdf', b'data', False, 'Invoice-1234']
invoice = get_invoice()
invoice.sequence_type = 'credit_note'
for line in invoice.lines:
line.quantity *= -1
invoice.untaxed_amount *= -1
invoice.tax_amount *= -1
invoice.total_amount *= -1
invoice.amount_to_pay *= -1
for line in invoice.lines_to_pay:
line.amount *= -1
template = Template(invoice)
invoice_string = template.render('2', specification='peppol-bis-3')
invoice_xml = etree.fromstring(invoice_string)
schema_file = os.path.join(
os.path.dirname(__file__),
'2.4', 'maindoc', 'UBL-CreditNote-2.4.xsd')
schema = etree.XMLSchema(etree.parse(schema_file))
schema.assertValid(invoice_xml)
@with_transaction()
def test_identifier_eas(self):
"Test EAS identifier"
pool = Pool()
Identifier = pool.get('party.identifier')
2025-12-18 13:31:22 +01:00
for type, code, eas_code, eas, vatin in [
('gr_vat', '023456783',
'9933', 'el023456783', 'EL023456783'),
('eu_vat', 'EL023456783',
'9933', 'el023456783', 'EL023456783'),
('eu_vat', 'GR023456783',
'9933', 'el023456783', 'EL023456783'),
('be_vat', '0403019261',
'9925', 'be0403019261', 'BE0403019261'),
('eu_vat', 'BE0403019261',
'9925', 'be0403019261', 'BE0403019261'),
('gb_vat', '980780684',
'9932', 'gb980780684', 'GB980780684'),
('eu_vat', 'GB980780684',
'9932', 'gb980780684', 'GB980780684'),
('eu_vat', 'XI980780684',
'9932', 'gb980780684', 'GB980780684'),
]:
with self.subTest(type=type, code=code):
identifier = Identifier(type=type, code=code)
self.assertEqual(identifier.eas_code, eas_code)
self.assertEqual(identifier.eas, eas)
2025-12-18 13:31:22 +01:00
self.assertEqual(identifier.vatin, vatin)
2025-11-14 16:36:06 +01:00
del ModuleTestCase