332 lines
18 KiB
Python
332 lines
18 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from freezegun import freeze_time
|
|
|
|
from odoo.addons.l10n_es_reports.tests.common import TestEsAccountReportsCommon
|
|
from odoo import fields
|
|
from odoo.tests import tagged
|
|
|
|
|
|
@tagged('post_install_l10n', 'post_install', '-at_install')
|
|
class TestBOEGeneration(TestEsAccountReportsCommon):
|
|
""" Basic tests checking the generation of BOE files is still possible.
|
|
"""
|
|
|
|
def _check_boe_111_to_303(self, modelo_number):
|
|
self.init_invoice('out_invoice', partner=self.spanish_partner, amounts=[10000], invoice_date=fields.Date.today(), taxes=self.spanish_test_tax, post=True)
|
|
report = self.env.ref('l10n_es.mod_%s' % modelo_number)
|
|
options = self._generate_options(report, fields.Date.from_string('2020-12-01'), fields.Date.from_string('2020-12-31'))
|
|
self._check_boe_export(report, options, modelo_number)
|
|
|
|
@freeze_time('2020-12-22')
|
|
def test_boe_mod_111(self):
|
|
self._check_boe_111_to_303('111')
|
|
|
|
@freeze_time('2020-12-22')
|
|
def test_boe_mod_115(self):
|
|
self._check_boe_111_to_303('115')
|
|
|
|
@freeze_time('2020-12-22')
|
|
def test_boe_mod_130(self):
|
|
self._check_boe_111_to_303('130')
|
|
|
|
@freeze_time('2020-12-22')
|
|
def test_boe_mod_303(self):
|
|
self._check_boe_111_to_303('303')
|
|
|
|
@freeze_time('2020-12-22')
|
|
def test_boe_mod_347(self):
|
|
invoice = self.init_invoice('out_invoice', partner=self.spanish_partner, amounts=[10000], invoice_date=fields.Date.today())
|
|
invoice.l10n_es_reports_mod347_invoice_type = 'regular'
|
|
invoice._post()
|
|
spanish_partner_2 = self.env['res.partner'].create({
|
|
# ES Partner with vat not starting with 'ES', should still be included in 347
|
|
'name': 'Partner 2',
|
|
'street': "Avenida de los Informes Financieros, 43",
|
|
'zip': 4242,
|
|
'city': "Madrid",
|
|
'country_id': self.env.ref('base.es').id,
|
|
'state_id': self.env.ref('base.state_es_m').id,
|
|
'vat': '74280274A',
|
|
})
|
|
invoice_2 = self.init_invoice('out_invoice', partner=spanish_partner_2, amounts=[5000], invoice_date=fields.Date.today())
|
|
invoice_2.action_post()
|
|
invoice_3 = self.init_invoice('out_invoice', partner=spanish_partner_2, amounts=[4000], invoice_date=fields.Date.today())
|
|
invoice_3.l10n_es_reports_mod347_invoice_type = 'insurance'
|
|
invoice_3._post()
|
|
report = self.env.ref('l10n_es_reports.mod_347')
|
|
options = self._generate_options(report, fields.Date.from_string('2020-01-01'), fields.Date.from_string('2020-12-31'))
|
|
self._check_boe_export(report, options, 347)
|
|
|
|
# Check file content
|
|
report._get_lines(options)
|
|
handler = self.env[report.custom_handler_model_name]
|
|
vals = handler.export_boe(options)
|
|
expected = [
|
|
# For information about data position, see page 7 & 16 of
|
|
# https://sede.agenciatributaria.gob.es/static_files/Sede/Disenyo_registro/DR_300_399/archivos/347.pdf
|
|
# 1,347,year,company vat
|
|
"13472020A12345674COMPANY_1_DATA T BECAUSE I AM ACCOUNTMAN! 3470000000002 0000000000000000000002 000000001900000000000000 000000000000000 ",
|
|
# 2,347,year,company vat,partner vat
|
|
"23472020A1234567474280274A PARTNER 2 D28 B 000000000400000X 000000000000000 0000000000000000000 000000000000000 000000000000000 000000000000000 000000000000000 000000000000000 000000000000000 000000000400000 000000000000000 000000000000000000000 ",
|
|
"23472020A12345674A12345674 BERNARDO GANADOR D28 B 000000001000000 000000000000000 0000000000000000000 000000000000000 000000000000000 000000000000000 000000000000000 000000000000000 000000000000000 000000001000000 000000000000000 000000000000000000000 ",
|
|
"23472020A1234567474280274A PARTNER 2 D28 B 000000000500000 000000000000000 0000000000000000000 000000000000000 000000000000000 000000000000000 000000000000000 000000000000000 000000000000000 000000000500000 000000000000000 000000000000000000000 ",
|
|
]
|
|
for generated_line, expected_line in zip(vals['file_content'].decode('utf-8').splitlines(), expected):
|
|
self.assertEqual(generated_line, expected_line)
|
|
|
|
handler._retrieve_boe_manual_wizard(options, 347).write({
|
|
'complementary_declaration': True,
|
|
'substitutive_declaration': True,
|
|
})
|
|
vals = handler.export_boe(options)
|
|
header_line = vals['file_content'].decode('utf-8').splitlines()[0]
|
|
self.assertEqual('C', header_line[120], "Complementary declaration should use 'C'")
|
|
self.assertEqual('S', header_line[121], "Substitutive declaration should use 'S'")
|
|
|
|
@freeze_time('2020-12-22')
|
|
def test_boe_mod_349(self):
|
|
self.partner_a.write({
|
|
'country_id': self.env.ref('base.be').id,
|
|
'vat': "BE0477472701",
|
|
})
|
|
invoice = self.init_invoice('out_invoice', partner=self.partner_a, amounts=[10000], invoice_date=fields.Date.today())
|
|
invoice.l10n_es_reports_mod349_invoice_type = 'E'
|
|
invoice._post()
|
|
report = self.env.ref('l10n_es_reports.mod_349')
|
|
options = self._generate_options(report, fields.Date.from_string('2020-12-01'), fields.Date.from_string('2020-12-31'))
|
|
self._check_boe_export(report, options, 349)
|
|
|
|
@freeze_time('2020-12-22')
|
|
def test_boe_mod_390(self):
|
|
report = self.env.ref('l10n_es.mod_390')
|
|
options = self._generate_options(report, '2020-01-01', '2020-12-31')
|
|
self._check_boe_export(report, options, 390, additional_context={
|
|
'default_physical_person_name': "Bernard Gagnant",
|
|
'default_principal_activity': "Selling",
|
|
'default_principal_iae_epigrafe': "EAAA",
|
|
'default_principal_code_activity': "AAA",
|
|
'default_judicial_person_name': "Bebert",
|
|
'default_judicial_person_nif': "123",
|
|
'default_judicial_person_procuration_date': '2020-01-01',
|
|
'default_judicial_person_notary': "Maître Gagnant",
|
|
})
|
|
|
|
@freeze_time('2020-12-22')
|
|
def test_boe_mod_347_with_cash_payment(self):
|
|
cash_journal = self.env['account.journal'].create({
|
|
'name': 'Cash Journal Test',
|
|
'type': 'cash',
|
|
'company_id': self.company_data['company'].id,
|
|
'code': 'CASHBOE',
|
|
})
|
|
invoice = self.init_invoice('out_invoice', partner=self.spanish_partner, amounts=[1000], invoice_date=fields.Date.today())
|
|
invoice.l10n_es_reports_mod347_invoice_type = 'regular'
|
|
invoice._post()
|
|
self.env['account.payment.register'].with_context(active_ids=invoice.ids, active_model='account.move').create({
|
|
'amount': 1000,
|
|
'payment_date': invoice.date,
|
|
'journal_id': cash_journal.id,
|
|
})._create_payments()
|
|
|
|
other_spanish_partner = self.env['res.partner'].create({
|
|
'name': "Other Partner",
|
|
'state_id': self.env.ref('base.state_es_m').id,
|
|
'country_id': self.env.ref('base.es').id,
|
|
'vat': "ESA12345674",
|
|
})
|
|
other_invoice = self.init_invoice('out_invoice', partner=other_spanish_partner, amounts=[4000], invoice_date=fields.Date.today())
|
|
other_invoice.l10n_es_reports_mod347_invoice_type = 'regular'
|
|
other_invoice._post()
|
|
self.env['account.payment.register'].with_context(active_ids=other_invoice.ids, active_model='account.move').create({
|
|
'amount': 4000,
|
|
'payment_date': other_invoice.date,
|
|
'journal_id': cash_journal.id,
|
|
})._create_payments()
|
|
|
|
report = self.env.ref('l10n_es_reports.mod_347')
|
|
options = self._generate_options(report, '2020-01-01', '2020-12-31')
|
|
wizard_model = self.env[report.custom_handler_model_name]
|
|
wizard_action = wizard_model.open_boe_wizard(options, 347)
|
|
wizard = self.env[wizard_action['res_model']].with_context(wizard_action['context']).create({})
|
|
options['l10n_es_reports_boe_wizard_id'] = wizard.id
|
|
|
|
boe_result = self.env[report.custom_handler_model_name].export_boe(options)
|
|
self.assertTrue(self.spanish_partner.name.upper() not in boe_result['file_content'].decode())
|
|
# Only the other partner is above the 3 005,06 € threshold must be reported
|
|
self.assertIn(other_spanish_partner.name.upper(), boe_result['file_content'].decode())
|
|
|
|
@freeze_time('2025-05-15')
|
|
def test_boe_includes_null_lines_mod_349(self):
|
|
"""
|
|
Test that the mod 349 boe report contains the rectification lines even when the total rectification sum to 0
|
|
"""
|
|
partner = self.env['res.partner'].create({
|
|
'name': 'Test',
|
|
'company_id': self.company_data['company'].id,
|
|
'company_type': 'company',
|
|
'country_id': self.env['res.country'].search([('code', '=', 'BE')]).id,
|
|
'vat': 'BE0477472701',
|
|
})
|
|
invoice = self.init_invoice('out_invoice', partner=partner, amounts=[1000], invoice_date='2025-03-15')
|
|
invoice.action_post()
|
|
|
|
credit_note_wizard = self.env['account.move.reversal'].with_context({
|
|
'active_ids': invoice.id,
|
|
'active_id': invoice.id,
|
|
'active_model': 'account.move',
|
|
}).create({
|
|
'reason': 'modify', # 'reason' can still be used to indicate purpose
|
|
'journal_id': invoice.journal_id.id,
|
|
})
|
|
credit_note_wizard.modify_moves()
|
|
|
|
report = self.env.ref('l10n_es_reports.mod_349')
|
|
options = self._generate_options(report, fields.Date.from_string('2025-05-01'), fields.Date.from_string('2025-05-31'))
|
|
wizard_action = self.env['l10n_es.mod349.tax.report.handler'].open_boe_wizard(options, '349')
|
|
wizard = self.env[wizard_action['res_model']].with_context(wizard_action['context']).create({})
|
|
options['l10n_es_reports_boe_wizard_id'] = wizard.id
|
|
|
|
boe_file = self.env['l10n_es.mod349.tax.report.handler'].export_boe(options)
|
|
|
|
# This string represents a rectification record included in the BOE export.
|
|
# It contains:
|
|
# - the year (2025),
|
|
# - the period,
|
|
# - the rectified tax base (0.00),
|
|
# - and the previously declared tax base (1000.00).
|
|
# Under REGISTRO DE RECTIFICACIONES https://www.boe.es/buscar/doc.php?id=BOE-A-2010-5098
|
|
self.assertIn('20250300000000000000000000100000', boe_file['file_content'].decode('utf-8'))
|
|
|
|
@freeze_time('2025-05-15')
|
|
def test_only_include_credit_note_in_rectification_mod_349(self):
|
|
"""
|
|
Test that in model 349 only the credit notes are included in the computation of the rectification line
|
|
"""
|
|
partner = self.env['res.partner'].create({
|
|
'name': 'Test',
|
|
'company_id': self.company_data['company'].id,
|
|
'company_type': 'company',
|
|
'country_id': self.env['res.country'].search([('code', '=', 'BE')]).id,
|
|
'vat': 'BE0477472701',
|
|
})
|
|
|
|
invoice = self.init_invoice('out_invoice', partner=partner, amounts=[1000], invoice_date='2025-03-15')
|
|
invoice.action_post()
|
|
|
|
reversal_wizard = self.env['account.move.reversal'].with_context({
|
|
'active_ids': invoice.id,
|
|
'active_id': invoice.id,
|
|
'active_model': 'account.move',
|
|
}).create({
|
|
'reason': 'refund',
|
|
'journal_id': invoice.journal_id.id,
|
|
})
|
|
reversal = reversal_wizard.reverse_moves()
|
|
refund = self.env['account.move'].browse(reversal.get('res_id'))
|
|
refund.line_ids.write({'price_unit': 500.0})
|
|
refund.action_post()
|
|
|
|
self.env['account.payment.register'].with_context(active_model='account.move', active_ids=invoice.ids).create({
|
|
'amount': 250.0,
|
|
})._create_payments()
|
|
|
|
report = self.env.ref('l10n_es_reports.mod_349')
|
|
options = self._generate_options(report, fields.Date.from_string('2025-05-01'), fields.Date.from_string('2025-05-31'))
|
|
wizard_action = self.env['l10n_es.mod349.tax.report.handler'].open_boe_wizard(options, '349')
|
|
wizard = self.env[wizard_action['res_model']].with_context(wizard_action['context']).create({})
|
|
options['l10n_es_reports_boe_wizard_id'] = wizard.id
|
|
|
|
boe_file = self.env['l10n_es.mod349.tax.report.handler'].export_boe(options)
|
|
|
|
# Those strings represent a rectification record included in the BOE export.
|
|
# It contains:
|
|
# - the year (2025),
|
|
# - the period,
|
|
# - the rectified tax base (0.00),
|
|
# - and the previously declared tax base (1000.00).
|
|
# Under REGISTRO DE RECTIFICACIONES https://www.boe.es/buscar/doc.php?id=BOE-A-2010-5098
|
|
|
|
# Here the new value should be 500 and not 250 because the payment should not count in the rectification line
|
|
self.assertIn('20250300000000500000000000100000', boe_file['file_content'].decode('utf-8'))
|
|
self.assertNotIn('20250300000000250000000000100000', boe_file['file_content'].decode('utf-8'))
|
|
|
|
@freeze_time('2025-05-15')
|
|
def test_boe_excludes_current_period_rectification_lines(self):
|
|
"""
|
|
Test that moves from the current period are not included as rectification lines in the boe report
|
|
"""
|
|
partner = self.env['res.partner'].create({
|
|
'name': 'Test',
|
|
'company_id': self.company_data['company'].id,
|
|
'company_type': 'company',
|
|
'country_id': self.env['res.country'].search([('code', '=', 'BE')]).id,
|
|
'vat': 'BE0477472701',
|
|
})
|
|
previous_period_invoice = self.init_invoice('out_invoice', partner=partner, amounts=[1000], invoice_date='2025-03-15')
|
|
previous_period_invoice.action_post()
|
|
|
|
credit_note_wizard_previous = self.env['account.move.reversal'].with_context({
|
|
'active_ids': previous_period_invoice.id,
|
|
'active_id': previous_period_invoice.id,
|
|
'active_model': 'account.move',
|
|
}).create({
|
|
'reason': 'modify',
|
|
'journal_id': previous_period_invoice.journal_id.id,
|
|
})
|
|
credit_note_wizard_previous.reverse_moves()
|
|
|
|
current_period_invoice = self.init_invoice('out_invoice', partner=partner, amounts=[1000], invoice_date='2025-05-15')
|
|
current_period_invoice.action_post()
|
|
|
|
credit_note_wizard_current = self.env['account.move.reversal'].with_context({
|
|
'active_ids': current_period_invoice.id,
|
|
'active_id': current_period_invoice.id,
|
|
'active_model': 'account.move',
|
|
}).create({
|
|
'reason': 'modify',
|
|
'journal_id': current_period_invoice.journal_id.id,
|
|
})
|
|
credit_note_wizard_current.reverse_moves()
|
|
|
|
report = self.env.ref('l10n_es_reports.mod_349')
|
|
options = self._generate_options(report, fields.Date.from_string('2025-05-01'), fields.Date.from_string('2025-05-31'))
|
|
wizard_action = self.env['l10n_es.mod349.tax.report.handler'].open_boe_wizard(options, '349')
|
|
wizard = self.env[wizard_action['res_model']].with_context(wizard_action['context']).create({})
|
|
options['l10n_es_reports_boe_wizard_id'] = wizard.id
|
|
|
|
boe_file = self.env['l10n_es.mod349.tax.report.handler'].export_boe(options)
|
|
# This string represents a rectification record included in the BOE export.
|
|
# It contains:
|
|
# - the year (2025),
|
|
# - the period (here 5 which is the current period),
|
|
# - the rectified tax base (0.00),
|
|
# - and the previously declared tax base (1000.00).
|
|
# Under REGISTRO DE RECTIFICACIONES https://www.boe.es/buscar/doc.php?id=BOE-A-2010-5098
|
|
self.assertNotIn('20250500000000000000000000100000', boe_file['file_content'].decode('utf-8'))
|
|
|
|
@freeze_time('2020-12-22')
|
|
def test_boe_button_branch_allowed(self):
|
|
"""
|
|
Test when a parent company has branches with different VATs and not all
|
|
branches are in the company selector
|
|
"""
|
|
parent_company = self.company_data['company']
|
|
self.env['res.company'].create({
|
|
'name': 'ES Branch',
|
|
'parent_id': parent_company.id,
|
|
'vat': 'B88431804',
|
|
'country_id': self.env.ref('base.es').id,
|
|
})
|
|
report = self.env.ref('l10n_es.mod_390').with_context(
|
|
allowed_company_ids=parent_company.ids,
|
|
)
|
|
options = self._generate_options(report, '2020-01-01', '2020-12-31')
|
|
boe_button = next(b for b in options['buttons'] if b.get('action_param') == 390)
|
|
action = boe_button.get('error_action') or boe_button['action']
|
|
wizard_action = report.dispatch_report_action(options, action, boe_button['action_param'])
|
|
self.assertEqual(
|
|
'l10n_es_reports.aeat.boe.mod390.export.wizard',
|
|
wizard_action['res_model'],
|
|
)
|