summaryrefslogtreecommitdiff
path: root/addons/account/models/company.py
diff options
context:
space:
mode:
authorFlorian Gilbert <flg@odoo.com>2019-08-22 10:03:26 +0000
committerFlorian Gilbert <flg@odoo.com>2019-09-25 11:26:02 +0000
commitab483a3a6610a09391ec00e9c1c49489ca4a4f12 (patch)
tree0882cebae27345110d8049970e37eaa3fea11991 /addons/account/models/company.py
parent02dfe1e8e789ee783f58f667efdf47c017585298 (diff)
[IMP] account: Add restrict mode and normal mode for account move.
This commit deletes account_cancel module and squash it into account. The 'update_posted' field is changed by 'restrict_mode_hash_table' field. If 'restrict_mode_hash_table' is true, you have a hash chain on your account journal. These hash chains prove the inalterability of your accounting. l10n_fr_certification module is deleted and all hashing method are moved in account module. Now, you can download a PDF report about your inalterability in the company settings. If you have l10n_fr or l10n_post_cert installed you have more information on this report like the inalterability of pos orders, etc. Task ID: 2039160
Diffstat (limited to 'addons/account/models/company.py')
-rw-r--r--addons/account/models/company.py81
1 files changed, 80 insertions, 1 deletions
diff --git a/addons/account/models/company.py b/addons/account/models/company.py
index e40265d4f64..7116dafff8c 100644
--- a/addons/account/models/company.py
+++ b/addons/account/models/company.py
@@ -6,7 +6,7 @@ from dateutil.relativedelta import relativedelta
from odoo import fields, models, api, _
from odoo.exceptions import ValidationError, UserError, RedirectWarning
-from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT
+from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT, format_date
from odoo.tools.float_utils import float_round, float_is_zero
from odoo.tools import date_utils
from odoo.tests.common import Form
@@ -553,3 +553,82 @@ class ResCompany(models.Model):
"Please go to Account Configuration and select or install a fiscal localization.")
raise RedirectWarning(msg, action.id, _("Go to the configuration panel"))
return account
+
+ @api.model
+ def _action_check_hash_integrity(self):
+ return self.env.ref('account.action_report_account_hash_integrity').report_action(self.id)
+
+ def _check_hash_integrity(self):
+ """Checks that all posted moves have still the same data as when they were posted
+ and raises an error with the result.
+ """
+ def build_move_info(move):
+ return(move.name, move.inalterable_hash, fields.Date.to_string(move.date))
+
+ journals = self.env['account.journal'].search([('company_id', '=', self.id)])
+ results_by_journal = {
+ 'results': [],
+ 'printing_date': format_date(self.env, fields.Date.to_string(fields.Date.today()))
+ }
+
+ for journal in journals:
+ rslt = {
+ 'journal_name': journal.name,
+ 'journal_code': journal.code,
+ 'restricted_by_hash_table': journal.restrict_mode_hash_table and 'V' or 'X',
+ 'msg_cover': '',
+ 'first_hash': 'None',
+ 'first_move_name': 'None',
+ 'first_move_date': 'None',
+ 'last_hash': 'None',
+ 'last_move_name': 'None',
+ 'last_move_date': 'None',
+ }
+ if not journal.restrict_mode_hash_table:
+ rslt.update({'msg_cover': _('This journal is not in strict mode.')})
+ results_by_journal['results'].append(rslt)
+ continue
+
+ all_moves_count = self.env['account.move'].search_count([('state', '=', 'posted'), ('journal_id', '=', journal.id)])
+ moves = self.env['account.move'].search([('state', '=', 'posted'), ('journal_id', '=', journal.id),
+ ('secure_sequence_number', '!=', 0)], order="secure_sequence_number ASC")
+ if not moves:
+ rslt.update({
+ 'msg_cover': _('There isn\'t any journal entry flagged for data inalterability yet for this journal.'),
+ })
+ results_by_journal['results'].append(rslt)
+ continue
+
+ previous_hash = u''
+ start_move_info = []
+ hash_corrupted = False
+ for move in moves:
+ if move.inalterable_hash != move._compute_hash(previous_hash=previous_hash):
+ rslt.update({'msg_cover': _('Corrupted data on journal entry with id %s.') % move.id})
+ results_by_journal['results'].append(rslt)
+ hash_corrupted = True
+ break
+ if not previous_hash:
+ #save the date and sequence number of the first move hashed
+ start_move_info = build_move_info(move)
+ previous_hash = move.inalterable_hash
+ end_move_info = build_move_info(move)
+
+ if hash_corrupted:
+ continue
+
+ rslt.update({
+ 'first_move_name': start_move_info[0],
+ 'first_hash': start_move_info[1],
+ 'first_move_date': format_date(self.env, start_move_info[2]),
+ 'last_move_name': end_move_info[0],
+ 'last_hash': end_move_info[1],
+ 'last_move_date': format_date(self.env, end_move_info[2]),
+ })
+ if len(moves) == all_moves_count:
+ rslt.update({'msg_cover': _('All entries are hashed.')})
+ else:
+ rslt.update({'msg_cover': _('Entries are hashed from %s (%s)') % (start_move_info[0], format_date(self.env, start_move_info[2]))})
+ results_by_journal['results'].append(rslt)
+
+ return results_by_journal