From 9e5ea29e347e677067445ab87e41bdc0d5386ad7 Mon Sep 17 00:00:00 2001 From: Pierre Masereel Date: Tue, 17 Sep 2019 07:24:54 +0000 Subject: [PATCH] [FIX] l10n_fr_pos_cert: display hash on receipt When an order is sent to the server from the point of sale, a unique hash is generated by the server. This hash must be printed on the receipt to allow the comparison between the receipt and the data on the server and guarantee the unalterability of the data on the server. TASK-ID: 47990 --- addons/l10n_fr_pos_cert/__manifest__.py | 2 + addons/l10n_fr_pos_cert/static/src/js/pos.js | 73 ++++++++++++++ .../l10n_fr_pos_cert/static/src/xml/pos.xml | 12 +++ .../views/l10n_fr_pos_cert_templates.xml | 10 ++ addons/point_of_sale/models/pos_order.py | 8 +- addons/point_of_sale/static/src/js/models.js | 9 +- addons/point_of_sale/static/src/js/screens.js | 95 ++++++++++++------- 7 files changed, 170 insertions(+), 39 deletions(-) create mode 100644 addons/l10n_fr_pos_cert/static/src/js/pos.js create mode 100644 addons/l10n_fr_pos_cert/static/src/xml/pos.xml create mode 100644 addons/l10n_fr_pos_cert/views/l10n_fr_pos_cert_templates.xml diff --git a/addons/l10n_fr_pos_cert/__manifest__.py b/addons/l10n_fr_pos_cert/__manifest__.py index d77b39faf5f..59b8022cdc1 100644 --- a/addons/l10n_fr_pos_cert/__manifest__.py +++ b/addons/l10n_fr_pos_cert/__manifest__.py @@ -28,6 +28,8 @@ The module adds following features: 'data': [ 'views/pos_inalterability_menuitem.xml', 'views/account_views.xml', + 'views/l10n_fr_pos_cert_templates.xml', ], + 'qweb': ['static/src/xml/pos.xml'], 'post_init_hook': '_setup_inalterability', } diff --git a/addons/l10n_fr_pos_cert/static/src/js/pos.js b/addons/l10n_fr_pos_cert/static/src/js/pos.js new file mode 100644 index 00000000000..8634181937d --- /dev/null +++ b/addons/l10n_fr_pos_cert/static/src/js/pos.js @@ -0,0 +1,73 @@ +odoo.define('l10n_fr_pos_cert.pos', function (require) { +"use strict"; + +var models = require('point_of_sale.models'); +var screens = require('point_of_sale.screens'); +var rpc = require('web.rpc'); +var session = require('web.session'); + +models.PosModel = models.PosModel.extend({ + is_french_country: function(){ + var french_countries = ['FR', 'MF', 'MQ', 'NC', 'PF', 'RE', 'GF', 'GP', 'TF']; + return _.contains(french_countries, this.company.country.code); + } +}); + + +var _super_order = models.Order.prototype; +models.Order = models.Order.extend({ + initialize: function() { + _super_order.initialize.apply(this,arguments); + this.l10n_fr_hash = this.l10n_fr_hash || false; + this.save_to_db(); + }, + export_for_printing: function() { + var result = _super_order.export_for_printing.apply(this,arguments); + result.l10n_fr_hash = this.get_l10n_fr_hash(); + return result; + }, + set_l10n_fr_hash: function (l10n_fr_hash){ + this.l10n_fr_hash = l10n_fr_hash; + }, + get_l10n_fr_hash: function() { + return this.l10n_fr_hash; + }, + wait_for_push_order: function() { + var result = _super_order.wait_for_push_order.apply(this,arguments); + result = Boolean(result || this.pos.is_french_country()); + return result; + } +}); + + +screens.PaymentScreenWidget.include({ + post_push_order_resolve: function (order, server_ids) { + if (this.pos.is_french_country()) { + var _super = this._super; + var args = arguments; + var self = this; + var get_hash_prom = new Promise (function (resolve, reject) { + rpc.query({ + model: 'pos.order', + method: 'search_read', + domain: [['id', 'in', server_ids]], + fields: ['l10n_fr_hash'], + context: session.user_context, + }).then(function (result) { + order.set_l10n_fr_hash(result[0].l10n_fr_hash || false); + }).finally(function () { + _super.apply(self, args).then(function () { + resolve(); + }).catch(function (error) { + reject(error); + }); + }); + }); + return get_hash_prom; + } + else { + return this._super(arguments); + } + }, +}); +}); diff --git a/addons/l10n_fr_pos_cert/static/src/xml/pos.xml b/addons/l10n_fr_pos_cert/static/src/xml/pos.xml new file mode 100644 index 00000000000..9cfda4f3444 --- /dev/null +++ b/addons/l10n_fr_pos_cert/static/src/xml/pos.xml @@ -0,0 +1,12 @@ + + + + + + +
+
+
+
+ +
diff --git a/addons/l10n_fr_pos_cert/views/l10n_fr_pos_cert_templates.xml b/addons/l10n_fr_pos_cert/views/l10n_fr_pos_cert_templates.xml new file mode 100644 index 00000000000..750335b4c37 --- /dev/null +++ b/addons/l10n_fr_pos_cert/views/l10n_fr_pos_cert_templates.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 39b1b51a981..9176fffac1d 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -615,7 +615,7 @@ class PosOrder(models.Model): } @api.model - def action_receipt_to_customer(self, name, client, ticket, invoice_id=False): + def action_receipt_to_customer(self, name, client, ticket, order_ids=False): template_obj = self.env['mail.mail'] message = "

Dear %s,
Here is your electronic ticket from the %s.

" % (client['name'], name) template_data = { @@ -625,8 +625,8 @@ class PosOrder(models.Model): 'email_to': client['email'] } - if invoice_id: - report = self.env.ref('point_of_sale.pos_invoice_report').render_qweb_pdf(invoice_id) + if order_ids and self.env['pos.order'].browse(order_ids[0]).account_move: + report = self.env.ref('point_of_sale.pos_invoice_report').render_qweb_pdf(order_ids[0]) attachment = self.env['ir.attachment'].create({ 'name': name, 'type': 'binary', @@ -634,7 +634,7 @@ class PosOrder(models.Model): 'datas_fname': name + '.pdf', 'store_fname': name, 'res_model': 'account.move', - 'res_id': invoice_id, + 'res_id': order_ids[0], 'mimetype': 'application/x-pdf' }) template_data['attachment_ids'] = attachment diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 29d882f5878..cc00ad884ee 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -214,7 +214,7 @@ exports.PosModel = Backbone.Model.extend({ }, },{ model: 'res.country', - fields: ['name', 'vat_label'], + fields: ['name', 'vat_label', 'code'], loaded: function(self,countries){ self.countries = countries; self.company.country = null; @@ -909,14 +909,14 @@ exports.PosModel = Backbone.Model.extend({ self.chrome.do_action('point_of_sale.pos_invoice_report',{additional_context:{ active_ids:order_server_id, }}).then(function () { - resolveInvoiced(); + resolveInvoiced(order_server_id); resolveDone(); }).guardedCatch(function (error) { rejectInvoiced({code:401, message:'Backend Invoice', data:{order: order}}); rejectDone(); }); } else if (order_server_id.length) { - resolveInvoiced(order_server_id[0]); + resolveInvoiced(order_server_id); resolveDone(); } else { // The order has been pushed separately in batch when @@ -3013,6 +3013,9 @@ exports.Order = Backbone.Model.extend({ get_screen_data: function(key){ return this.screen_data[key]; }, + wait_for_push_order: function () { + return this.is_to_email(); + }, }); var OrderCollection = Backbone.Collection.extend({ diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 9f96c103bcd..08cfff68d02 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -2374,35 +2374,61 @@ var PaymentScreenWidget = ScreenWidget.extend({ invoiced.catch(this._handleFailedPushForInvoice.bind(this, order, false)); - invoiced.then(function (value) { + invoiced.then(function (server_ids) { self.invoicing = false; - self.send_receipt_to_customer(value || false); - self.gui.show_screen('receipt'); + var post_push_promise = []; + post_push_promise = self.post_push_order_resolve(order, server_ids); + post_push_promise.then(function () { + self.gui.show_screen('receipt'); + }).catch(function (error) { + self.gui.show_screen('receipt'); + if (error) { + self.gui.show_popup('error',{ + 'title': "Error: no internet connection", + 'body': error, + }); + } + }); }); } else { - if (order.is_to_email()){ - var ordered = this.pos.push_order(order); - ordered.then(function() { - self.send_receipt_to_customer(false); - self.gui.show_screen('receipt'); - }); - ordered.catch(function(value) { - order.set_to_email(false); - self.gui.show_screen('receipt'); - self.gui.show_popup('error',{ - 'title': "Error: no internet connection", - 'body': "There is no internet connection, impossible to send the email.", - }); - }); + var ordered = this.pos.push_order(order); + if (order.wait_for_push_order()){ + var server_ids = []; + ordered.then(function (ids) { + server_ids = ids; + }).finally(function() { + var post_push_promise = []; + post_push_promise = self.post_push_order_resolve(order, server_ids); + post_push_promise.then(function () { + self.gui.show_screen('receipt'); + }).catch(function (error) { + self.gui.show_screen('receipt'); + if (error) { + self.gui.show_popup('error',{ + 'title': "Error: no internet connection", + 'body': error, + }); + } + }); + }); } else { - this.pos.push_order(order); self.gui.show_screen('receipt'); } } }, + post_push_order_resolve: function(order, server_ids){ + var self = this; + if (order.is_to_email()) { + var email_promise = self.send_receipt_to_customer(server_ids); + return email_promise; + } + else { + return Promise.resolve(); + } + }, // Check if the order is paid, then sends it to the backend, // and complete the sale process @@ -2412,29 +2438,34 @@ var PaymentScreenWidget = ScreenWidget.extend({ } }, - send_receipt_to_customer: function(invoice_server_id) { + send_receipt_to_customer: function(order_server_ids) { var order = this.pos.get_order(); - if(order.is_to_email()){ - var data = { - widget: this, - pos: order.pos, - order: order, - receipt: order.export_for_printing(), - orderlines: order.get_orderlines(), - paymentlines: order.get_paymentlines(), - } + var data = { + widget: this, + pos: order.pos, + order: order, + receipt: order.export_for_printing(), + orderlines: order.get_orderlines(), + paymentlines: order.get_paymentlines(), + }; - var receipt = QWeb.render('OrderReceipt', data); - var printer = new Printer(); + var receipt = QWeb.render('OrderReceipt', data); + var printer = new Printer(); + return new Promise(function (resolve, reject) { printer.htmlToImg(receipt).then(function(ticket) { rpc.query({ model: 'pos.order', method: 'action_receipt_to_customer', - args: [order.get_name(), order.get_client(), ticket, invoice_server_id], + args: [order.get_name(), order.get_client(), ticket, order_server_ids], + }).then(function() { + resolve(); + }).catch(function () { + order.set_to_email(false); + reject("There is no internet connection, impossible to send the email."); }); }); - } + }); }, }); gui.define_screen({name:'payment', widget: PaymentScreenWidget});