summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorPierre Masereel <pim@odoo.com>2019-09-25 12:54:54 +0000
committerPierre Masereel <pim@odoo.com>2019-10-01 10:02:50 +0000
commit82e06a9f5086e5417c5371d592c99153db2dcac4 (patch)
tree2bf0812a2e92b3ed77372f62371dad1d4f79ca96 /addons
parent78994b55b6241ea95feb45b4b2826de5aabbb48c (diff)
[FIX] l10n_fr_pos_cert: inalterability check report
We've added a repport that guarantee that the blockchain of hash has not been altered. It recompute the hash and check that they are the same as the one stored. TASK-ID: 47990
Diffstat (limited to 'addons')
-rw-r--r--addons/l10n_fr_pos_cert/__init__.py1
-rw-r--r--addons/l10n_fr_pos_cert/__manifest__.py1
-rw-r--r--addons/l10n_fr_pos_cert/models/res_company.py54
-rw-r--r--addons/l10n_fr_pos_cert/report/__init__.py4
-rw-r--r--addons/l10n_fr_pos_cert/report/pos_hash_integrity.py22
-rw-r--r--addons/l10n_fr_pos_cert/report/pos_hash_integrity.xml95
-rw-r--r--addons/l10n_fr_pos_cert/views/pos_inalterability_menuitem.xml25
7 files changed, 198 insertions, 4 deletions
diff --git a/addons/l10n_fr_pos_cert/__init__.py b/addons/l10n_fr_pos_cert/__init__.py
index 4059582d30c..c4104881ea0 100644
--- a/addons/l10n_fr_pos_cert/__init__.py
+++ b/addons/l10n_fr_pos_cert/__init__.py
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
+from . import report
from odoo import api, SUPERUSER_ID
diff --git a/addons/l10n_fr_pos_cert/__manifest__.py b/addons/l10n_fr_pos_cert/__manifest__.py
index e750607a30f..9e9dce4d0cf 100644
--- a/addons/l10n_fr_pos_cert/__manifest__.py
+++ b/addons/l10n_fr_pos_cert/__manifest__.py
@@ -30,6 +30,7 @@ The module adds following features:
'views/account_views.xml',
'views/l10n_fr_pos_cert_templates.xml',
'views/pos_views.xml',
+ 'report/pos_hash_integrity.xml',
],
'qweb': ['static/src/xml/pos.xml'],
'post_init_hook': '_setup_inalterability',
diff --git a/addons/l10n_fr_pos_cert/models/res_company.py b/addons/l10n_fr_pos_cert/models/res_company.py
index 74dae578af3..5cacda61c1d 100644
--- a/addons/l10n_fr_pos_cert/models/res_company.py
+++ b/addons/l10n_fr_pos_cert/models/res_company.py
@@ -3,7 +3,8 @@
from odoo import models, api, fields, _
from odoo.exceptions import UserError
from datetime import datetime
-from odoo.fields import Datetime
+from odoo.fields import Datetime, Date
+from odoo.tools.misc import format_date
import pytz
@@ -42,3 +43,54 @@ class ResCompany(models.Model):
sequence_fields = ['l10n_fr_pos_cert_sequence_id']
company._create_secure_sequence(sequence_fields)
return res
+
+ def _action_check_pos_hash_integrity(self):
+ return self.env.ref('l10n_fr_pos_cert.action_report_pos_hash_integrity').report_action(self.id)
+
+ def _check_pos_hash_integrity(self):
+ """Checks that all posted or invoiced pos orders have still the same data as when they were posted
+ and raises an error with the result.
+ """
+ def build_order_info(order):
+ entry_reference = _('(Receipt ref.: %s)')
+ order_reference_string = order.pos_reference and entry_reference % order.pos_reference or ''
+ return [ctx_tz(order, 'date_order'), order.l10n_fr_hash, order.name, order_reference_string, ctx_tz(order, 'write_date')]
+
+ hash_verified = True
+ msg_alert = ''
+ report_dict = {}
+ if self._is_accounting_unalterable():
+ orders = self.env['pos.order'].search([('state', 'in', ['paid', 'done', 'invoiced']), ('company_id', '=', self.id),
+ ('l10n_fr_secure_sequence_number', '!=', 0)], order="l10n_fr_secure_sequence_number ASC")
+
+ if not orders:
+ msg_alert = (_('There isn\'t any order flagged for data inalterability yet for the company %s. This mechanism only runs for point of sale orders generated after the installation of the module France - Certification CGI 286 I-3 bis. - POS') % self.env.company.name)
+ hash_verified = False
+
+ previous_hash = u''
+ start_order_info = []
+ for order in orders:
+ if order.l10n_fr_hash != order._compute_hash(previous_hash=previous_hash):
+ msg_alert = (_('Corrupted data on point of sale order with id %s.') % order.id)
+ hash_verified = False
+ break
+ previous_hash = order.l10n_fr_hash
+
+ if hash_verified:
+ orders_sorted_date = orders.sorted(lambda o: o.date_order)
+ start_order_info = build_order_info(orders_sorted_date[0])
+ end_order_info = build_order_info(orders_sorted_date[-1])
+
+ report_dict.update({
+ 'first_order_name': start_order_info[2],
+ 'first_order_hash': start_order_info[1],
+ 'first_order_date': start_order_info[0],
+ 'last_order_name': end_order_info[2],
+ 'last_order_hash': end_order_info[1],
+ 'last_order_date': end_order_info[0],
+ })
+ return {
+ 'result': hash_verified and report_dict or 'None',
+ 'msg_alert': msg_alert or 'None',
+ 'printing_date': format_date(self.env, Date.to_string( Date.today())),
+ }
diff --git a/addons/l10n_fr_pos_cert/report/__init__.py b/addons/l10n_fr_pos_cert/report/__init__.py
new file mode 100644
index 00000000000..af5f8a80860
--- /dev/null
+++ b/addons/l10n_fr_pos_cert/report/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import pos_hash_integrity
diff --git a/addons/l10n_fr_pos_cert/report/pos_hash_integrity.py b/addons/l10n_fr_pos_cert/report/pos_hash_integrity.py
new file mode 100644
index 00000000000..d7c36038022
--- /dev/null
+++ b/addons/l10n_fr_pos_cert/report/pos_hash_integrity.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+
+class ReportPosHashIntegrity(models.AbstractModel):
+ _name = 'report.l10n_fr_pos_cert.report_pos_hash_integrity'
+ _description = 'Get french pos hash integrity result as PDF.'
+
+ @api.model
+ def _get_report_values(self, docids, data=None):
+ if data:
+ data.update(self.env.company._check_pos_hash_integrity())
+ else:
+ data = self.env.company._check_hash_pos_integrity()
+ return {
+ 'doc_ids' : docids,
+ 'doc_model' : self.env['res.company'],
+ 'data' : data,
+ 'docs' : self.env['res.company'].browse(self.env.company.id),
+ }
diff --git a/addons/l10n_fr_pos_cert/report/pos_hash_integrity.xml b/addons/l10n_fr_pos_cert/report/pos_hash_integrity.xml
new file mode 100644
index 00000000000..a64b3d9a0a8
--- /dev/null
+++ b/addons/l10n_fr_pos_cert/report/pos_hash_integrity.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<odoo>
+ <data>
+ <template id="report_pos_hash_integrity">
+ <t t-call="web.html_container">
+ <t t-foreach="docs" t-as="company">
+ <t t-call="web.external_layout">
+ <div class="page">
+ <div class="row" id="hash_header">
+ <div class="col-12">
+ <br/>
+ <h2>Résultat du test d'intégrité - <span t-esc="data['printing_date']"/></h2>
+ <br/>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-12" id="hash_config_review">
+ <h6>
+ Selon l’article 286 du code général des impôts français, toute livraison de bien ou prestation
+ de services ne donnant pas lieu à facturation et étant enregistrée au moyen d’un logiciel ou
+ d’un système de caisse doit satisfaire à des conditions d’inaltérabilité et de sécurisation des
+ données en vue d’un contrôle de l’administration fiscale.
+ <br/>
+ <br/>
+ Ces conditions sont respectées via une fonction de hachage des ventes du Point de Vente.
+ <br/>
+ <br/>
+ </h6>
+ </div>
+ </div>
+ <t t-if="data['result'] != 'None'">
+ <div class="row">
+ <div class="col-12" id="hash_data_consistency">
+ <br/>
+ <h3>Contrôle des données du point de vente</h3>
+ <br/>
+ <t t-if="data['result'] != 'None' and data['msg_alert'] == 'None'">
+ <h5>
+ Toutes les ventes effectuées via le Point de Vente
+ sont bien dans la chaîne de hachage.
+ </h5>
+ <br/>
+ </t>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-12" id="hash_data_consistency_table">
+ <table class="table table-bordered" style="table-layout: fixed">
+ <thead style="display: table-row-group">
+ <tr>
+ <th class="text-center" style="width: 25%" scope="col">First Hash</th>
+ <th class="text-center" style="width: 25%" scope="col">First Entry</th>
+ <th class="text-center" style="width: 25%" scope="col">Last Hash</th>
+ <th class="text-center" style="width: 25%" scope="col">Last Entry</th>
+ </tr>
+ </thead>
+ <tbody>
+ <t t-if="data['result'] != 'None'">
+ <t t-if="data['result']['first_order_hash'] != 'None'">
+ <tr>
+ <td><span t-esc="data['result']['first_order_hash']"/></td>
+ <td>
+ <span t-esc="data['result']['first_order_name']"/> <br/>
+ <span t-esc="data['result']['first_order_date']"/>
+ </td>
+ <td><span t-esc="data['result']['last_order_hash']"/></td>
+ <td>
+ <span t-esc="data['result']['last_order_name']"/> <br/>
+ <span t-esc="data['result']['last_order_date']"/>
+ </td>
+ </tr>
+ </t>
+ </t>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ <div class="row" id="hash_last_div">
+ <div class="col-12" id="hash_chain_compliant">
+ <br/>
+ <h6>
+ La chaîne de hachage est conforme: il n’est pas possible d’altérer les données
+ sans casser la chaîne de hachage pour les pièces ultérieures.
+ </h6>
+ <br/>
+ </div>
+ </div>
+ </t>
+ </div>
+ </t>
+ </t>
+ </t>
+ </template>
+ </data>
+</odoo>
diff --git a/addons/l10n_fr_pos_cert/views/pos_inalterability_menuitem.xml b/addons/l10n_fr_pos_cert/views/pos_inalterability_menuitem.xml
index 4f05afcb99f..efaab7ef24f 100644
--- a/addons/l10n_fr_pos_cert/views/pos_inalterability_menuitem.xml
+++ b/addons/l10n_fr_pos_cert/views/pos_inalterability_menuitem.xml
@@ -1,4 +1,23 @@
<odoo>
- <menuitem id="pos_fr_statements_menu" name="French Statements" parent="point_of_sale.menu_point_rep" sequence="9" />
- <menuitem action="l10n_fr.action_list_view_account_sale_closing" id="menu_account_closing" parent="pos_fr_statements_menu" sequence="90"/>
-</odoo> \ No newline at end of file
+ <report
+ id="action_report_pos_hash_integrity"
+ model="res.company"
+ string="Hash integrity result PDF"
+ report_type="qweb-pdf"
+ name="l10n_fr_pos_cert.report_pos_hash_integrity"
+ file="l10n_fr_pos_cert.report_pos_hash_integrity"
+ menu="False"
+ />
+ <record model="ir.actions.server" id="action_check_pos_hash_integrity">
+ <field name="name">POS Inalterability Check</field>
+ <field name="model_id" ref="account.model_res_company"/>
+ <field name="type">ir.actions.server</field>
+ <field name="state">code</field>
+ <field name="code">
+ action = env.company._action_check_pos_hash_integrity()
+ </field>
+ </record>
+ <menuitem id="pos_fr_statements_menu" name="French Statements" parent="point_of_sale.menu_point_rep" sequence="9" />
+ <menuitem action="l10n_fr.action_list_view_account_sale_closing" id="menu_account_closing" parent="pos_fr_statements_menu" sequence="80"/>
+ <menuitem action="l10n_fr_pos_cert.action_check_pos_hash_integrity" id="menu_check_move_integrity_reporting" parent="pos_fr_statements_menu" sequence="90"/>
+</odoo>