mirror of
https://github.com/bringout/oca-ocb-accounting.git
synced 2026-04-22 07:02:03 +02:00
Initial commit: Accounting packages
This commit is contained in:
commit
4ef34c2317
2661 changed files with 1709616 additions and 0 deletions
|
|
@ -0,0 +1,269 @@
|
|||
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||||
from odoo.models import Model
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import Form
|
||||
from odoo import fields
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import format_date
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestAccountMoveInalterableHash(AccountTestInvoicingCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
|
||||
def test_account_move_inalterable_hash(self):
|
||||
"""Test that we cannot alter a field used for the computation of the inalterable hash"""
|
||||
self.company_data['default_journal_sale'].restrict_mode_hash_table = True
|
||||
move = self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000], post=True)
|
||||
|
||||
with self.assertRaisesRegex(UserError, "You cannot overwrite the values ensuring the inalterability of the accounting."):
|
||||
move.inalterable_hash = 'fake_hash'
|
||||
with self.assertRaisesRegex(UserError, "You cannot overwrite the values ensuring the inalterability of the accounting."):
|
||||
move.secure_sequence_number = 666
|
||||
with self.assertRaisesRegex(UserError, "You cannot edit the following fields due to restrict mode being activated.*"):
|
||||
move.name = "fake name"
|
||||
with self.assertRaisesRegex(UserError, "You cannot edit the following fields due to restrict mode being activated.*"):
|
||||
move.date = fields.Date.from_string('2023-01-02')
|
||||
with self.assertRaisesRegex(UserError, "You cannot edit the following fields due to restrict mode being activated.*"):
|
||||
move.company_id = 666
|
||||
with self.assertRaisesRegex(UserError, "You cannot edit the following fields due to restrict mode being activated.*"):
|
||||
move.write({
|
||||
'company_id': 666,
|
||||
'date': fields.Date.from_string('2023-01-03')
|
||||
})
|
||||
|
||||
with self.assertRaisesRegex(UserError, "You cannot edit the following fields.*Account.*"):
|
||||
move.line_ids[0].account_id = move.line_ids[1]['account_id']
|
||||
with self.assertRaisesRegex(UserError, "You cannot edit the following fields.*Partner.*"):
|
||||
move.line_ids[0].partner_id = 666
|
||||
|
||||
# The following fields are not part of the hash so they can be modified
|
||||
move.ref = "bla"
|
||||
move.line_ids[0].date_maturity = fields.Date.from_string('2023-01-02')
|
||||
|
||||
def test_account_move_hash_integrity_report(self):
|
||||
"""Test the hash integrity report"""
|
||||
moves = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-02", amounts=[1000, 2000])
|
||||
)
|
||||
moves.action_post()
|
||||
|
||||
# No records to be hashed because the restrict mode is not activated yet
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0] # First journal
|
||||
self.assertEqual(integrity_check['msg_cover'], 'This journal is not in strict mode.')
|
||||
|
||||
# No records to be hashed even if the restrict mode is activated because the hashing is not retroactive
|
||||
self.company_data['default_journal_sale'].restrict_mode_hash_table = True
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertEqual(integrity_check['msg_cover'], 'There isn\'t any journal entry flagged for data inalterability yet for this journal.')
|
||||
|
||||
# Everything should be correctly hashed and verified
|
||||
new_moves = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-03", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-04", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_a, "2023-01-05", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-06", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_a, "2023-01-07", amounts=[1000, 2000])
|
||||
)
|
||||
new_moves.action_post()
|
||||
moves |= new_moves
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertRegex(integrity_check['msg_cover'], f'Entries are hashed from {moves[2].name}.*')
|
||||
self.assertEqual(integrity_check['first_move_date'], format_date(self.env, fields.Date.to_string(moves[2].date)))
|
||||
self.assertEqual(integrity_check['last_move_date'], format_date(self.env, fields.Date.to_string(moves[-1].date)))
|
||||
|
||||
# Let's change one of the fields used by the hash. It should be detected by the integrity report.
|
||||
# We need to bypass the write method of account.move to do so.
|
||||
Model.write(moves[4], {'date': fields.Date.from_string('2023-01-07')})
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertEqual(integrity_check['msg_cover'], f'Corrupted data on journal entry with id {moves[4].id}.')
|
||||
|
||||
# Revert the previous change
|
||||
Model.write(moves[4], {'date': fields.Date.from_string("2023-01-05")})
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertRegex(integrity_check['msg_cover'], f'Entries are hashed from {moves[2].name}.*')
|
||||
|
||||
# Let's try with the one of the subfields
|
||||
Model.write(moves[-1].line_ids[0], {'partner_id': self.partner_b.id})
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertEqual(integrity_check['msg_cover'], f'Corrupted data on journal entry with id {moves[-1].id}.')
|
||||
|
||||
# Let's try with the inalterable_hash field itself
|
||||
Model.write(moves[-1].line_ids[0], {'partner_id': self.partner_a.id}) # Revert the previous change
|
||||
Model.write(moves[-1], {'inalterable_hash': 'fake_hash'})
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertEqual(integrity_check['msg_cover'], f'Corrupted data on journal entry with id {moves[-1].id}.')
|
||||
|
||||
def test_account_move_hash_versioning_1(self):
|
||||
"""We are updating the hash algorithm. We want to make sure that we do not break the integrity report.
|
||||
This test focuses on the case where the user has only moves with the old hash algorithm."""
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000], post=True) # Not hashed
|
||||
self.company_data['default_journal_sale'].restrict_mode_hash_table = True
|
||||
moves = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-02", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-03", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-04", amounts=[1000, 2000])
|
||||
)
|
||||
moves.with_context(hash_version=1).action_post()
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertRegex(integrity_check['msg_cover'], f'Entries are hashed from {moves[0].name}.*')
|
||||
self.assertEqual(integrity_check['first_move_date'], format_date(self.env, fields.Date.to_string(moves[0].date)))
|
||||
self.assertEqual(integrity_check['last_move_date'], format_date(self.env, fields.Date.to_string(moves[-1].date)))
|
||||
|
||||
# Let's change one of the fields used by the hash. It should be detected by the integrity report
|
||||
# independently of the hash version used. I.e. we first try the v1 hash, then the v2 hash and neither should work.
|
||||
# We need to bypass the write method of account.move to do so.
|
||||
Model.write(moves[1], {'date': fields.Date.from_string('2023-01-07')})
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertEqual(integrity_check['msg_cover'], f'Corrupted data on journal entry with id {moves[1].id}.')
|
||||
|
||||
def test_account_move_hash_versioning_2(self):
|
||||
"""We are updating the hash algorithm. We want to make sure that we do not break the integrity report.
|
||||
This test focuses on the case where the user has only moves with the new hash algorithm."""
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000], post=True) # Not hashed
|
||||
self.company_data['default_journal_sale'].restrict_mode_hash_table = True
|
||||
moves = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-02", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-03", amounts=[1000, 2000])
|
||||
)
|
||||
moves.action_post()
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertRegex(integrity_check['msg_cover'], f'Entries are hashed from {moves[0].name}.*')
|
||||
self.assertEqual(integrity_check['first_move_date'], format_date(self.env, fields.Date.to_string(moves[0].date)))
|
||||
self.assertEqual(integrity_check['last_move_date'], format_date(self.env, fields.Date.to_string(moves[-1].date)))
|
||||
|
||||
# Let's change one of the fields used by the hash. It should be detected by the integrity report
|
||||
# independently of the hash version used. I.e. we first try the v1 hash, then the v2 hash and neither should work.
|
||||
# We need to bypass the write method of account.move to do so.
|
||||
Model.write(moves[1], {'date': fields.Date.from_string('2023-01-07')})
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertEqual(integrity_check['msg_cover'], f'Corrupted data on journal entry with id {moves[1].id}.')
|
||||
|
||||
def test_account_move_hash_versioning_v1_to_v2(self):
|
||||
"""We are updating the hash algorithm. We want to make sure that we do not break the integrity report.
|
||||
This test focuses on the case where the user has moves with both hash algorithms."""
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000], post=True) # Not hashed
|
||||
self.company_data['default_journal_sale'].restrict_mode_hash_table = True
|
||||
moves_v1 = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-02", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-03", amounts=[1000, 2000])
|
||||
)
|
||||
moves_v1.with_context(hash_version=1).action_post()
|
||||
fields_v1 = moves_v1.with_context(hash_version=1)._get_integrity_hash_fields()
|
||||
moves_v2 = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-02", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-03", amounts=[1000, 2000])
|
||||
)
|
||||
moves_v2.with_context(hash_version=2).action_post()
|
||||
fields_v2 = moves_v2._get_integrity_hash_fields()
|
||||
self.assertNotEqual(fields_v1, fields_v2) # Make sure two different hash algorithms were used
|
||||
|
||||
moves = moves_v1 | moves_v2
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertRegex(integrity_check['msg_cover'], f'Entries are hashed from {moves[0].name}.*')
|
||||
self.assertEqual(integrity_check['first_move_date'], format_date(self.env, fields.Date.to_string(moves[0].date)))
|
||||
self.assertEqual(integrity_check['last_move_date'], format_date(self.env, fields.Date.to_string(moves[-1].date)))
|
||||
|
||||
# Let's change one of the fields used by the hash. It should be detected by the integrity report
|
||||
# independently of the hash version used. I.e. we first try the v1 hash, then the v2 hash and neither should work.
|
||||
# We need to bypass the write method of account.move to do so.
|
||||
Model.write(moves[4], {'date': fields.Date.from_string('2023-01-07')})
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertEqual(integrity_check['msg_cover'], f'Corrupted data on journal entry with id {moves[4].id}.')
|
||||
|
||||
# Let's revert the change and make sure that we cannot use the v1 after the v2.
|
||||
# This means we don't simply check whether the move is correctly hashed with either algorithms,
|
||||
# but that we can only use v2 after v1 and not go back to v1 afterwards.
|
||||
Model.write(moves[4], {'date': fields.Date.from_string("2023-01-02")}) # Revert the previous change
|
||||
moves_v1_bis = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-10", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-11", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-12", amounts=[1000, 2000])
|
||||
)
|
||||
moves_v1_bis.with_context(hash_version=1).action_post()
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertEqual(integrity_check['msg_cover'], f'Corrupted data on journal entry with id {moves_v1_bis[0].id}.')
|
||||
|
||||
def test_account_move_hash_versioning_3(self):
|
||||
"""
|
||||
Version 2 does not take into account floating point representation issues.
|
||||
Test that version 3 covers correctly this case
|
||||
"""
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000],
|
||||
post=True) # Not hashed
|
||||
self.company_data['default_journal_sale'].restrict_mode_hash_table = True
|
||||
moves_v3 = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[30*0.17, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-02", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-03", amounts=[1000, 2000])
|
||||
)
|
||||
moves_v3.action_post()
|
||||
|
||||
# invalidate cache
|
||||
moves_v3[0].line_ids[0].invalidate_recordset()
|
||||
|
||||
integrity_check_v3 = moves_v3.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertRegex(integrity_check_v3['msg_cover'], f'Entries are hashed from {moves_v3[0].name}.*')
|
||||
|
||||
def test_account_move_hash_versioning_v2_to_v3(self):
|
||||
"""
|
||||
We are updating the hash algorithm. We want to make sure that we do not break the integrity report.
|
||||
This test focuses on the case with version 2 and version 3.
|
||||
"""
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000],
|
||||
post=True) # Not hashed
|
||||
self.company_data['default_journal_sale'].restrict_mode_hash_table = True
|
||||
moves_v2 = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-02", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-03", amounts=[1000, 2000])
|
||||
)
|
||||
moves_v2.with_context(hash_version=2).action_post()
|
||||
|
||||
moves_v3 = (
|
||||
self.init_invoice("out_invoice", self.partner_a, "2023-01-01", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-02", amounts=[1000, 2000])
|
||||
| self.init_invoice("out_invoice", self.partner_b, "2023-01-03", amounts=[1000, 2000])
|
||||
)
|
||||
moves_v3.with_context(hash_version=3).action_post()
|
||||
|
||||
moves = moves_v2 | moves_v3
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertRegex(integrity_check['msg_cover'], f'Entries are hashed from {moves[0].name}.*')
|
||||
self.assertEqual(integrity_check['first_move_date'],
|
||||
format_date(self.env, fields.Date.to_string(moves[0].date)))
|
||||
self.assertEqual(integrity_check['last_move_date'],
|
||||
format_date(self.env, fields.Date.to_string(moves[-1].date)))
|
||||
|
||||
Model.write(moves[1], {'date': fields.Date.from_string('2023-01-07')})
|
||||
integrity_check = moves.company_id._check_hash_integrity()['results'][0]
|
||||
self.assertEqual(integrity_check['msg_cover'], f'Corrupted data on journal entry with id {moves[1].id}.')
|
||||
|
||||
def test_account_move_hash_with_cash_rounding(self):
|
||||
# Enable inalterable hash
|
||||
self.company_data['default_journal_sale'].restrict_mode_hash_table = True
|
||||
# Required for `invoice_cash_rounding_id` to be visible in the view
|
||||
self.env.user.groups_id += self.env.ref('account.group_cash_rounding')
|
||||
# Test 'add_invoice_line' rounding
|
||||
invoice = self.init_invoice('out_invoice', products=self.product_a+self.product_b)
|
||||
move_form = Form(invoice)
|
||||
# Add a cash rounding having 'add_invoice_line'.
|
||||
move_form.invoice_cash_rounding_id = self.cash_rounding_a
|
||||
with move_form.invoice_line_ids.edit(0) as line_form:
|
||||
line_form.price_unit = 999.99
|
||||
move_form.save()
|
||||
|
||||
# Should not raise
|
||||
invoice.action_post()
|
||||
|
||||
self.assertEqual(invoice.amount_total, 1410.0)
|
||||
self.assertEqual(invoice.amount_untaxed, 1200.0)
|
||||
self.assertEqual(invoice.amount_tax, 210)
|
||||
self.assertEqual(len(invoice.invoice_line_ids), 2)
|
||||
self.assertEqual(len(invoice.line_ids), 6)
|
||||
Loading…
Add table
Add a link
Reference in a new issue