diff options
| author | Florian Gilbert <flg@odoo.com> | 2019-08-22 10:03:26 +0000 |
|---|---|---|
| committer | Florian Gilbert <flg@odoo.com> | 2019-09-25 11:26:02 +0000 |
| commit | ab483a3a6610a09391ec00e9c1c49489ca4a4f12 (patch) | |
| tree | 0882cebae27345110d8049970e37eaa3fea11991 /addons/account/models/company.py | |
| parent | 02dfe1e8e789ee783f58f667efdf47c017585298 (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.py | 81 |
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 |
