From 336c6a538336947cae68fdfc7dd65768d2db37f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Todorovich?= Date: Fri, 14 Jun 2019 08:50:51 +0000 Subject: [PATCH] - Make search_query a property - Fix search clear button - Refactor load_order and actions This refactors load_data into two functions: load_order_data and load_order_from_data. Also, when executing actions, instead of sending the order as an argument, only the order_data will be sent. The action method is responsible for generating the order data (if that's what it needs) All the refund logic has been extracted from the various methods, and it's now in action_return. Now, returns have a specific 'Refund XXXX' name. - IMP Allow to duplicate done orders from the POS - IMP filter by customer name, too, when searching --- pos_order_mgmt/README.rst | 3 + pos_order_mgmt/models/pos_config.py | 8 + pos_order_mgmt/models/pos_order.py | 7 +- pos_order_mgmt/readme/CONTRIBUTORS.rst | 1 + pos_order_mgmt/static/src/js/widgets.js | 190 ++++++++++++++--------- pos_order_mgmt/static/src/xml/pos.xml | 3 + pos_order_mgmt/views/view_pos_config.xml | 11 ++ 7 files changed, 147 insertions(+), 76 deletions(-) diff --git a/pos_order_mgmt/README.rst b/pos_order_mgmt/README.rst index c1d40dc6..83839e3d 100644 --- a/pos_order_mgmt/README.rst +++ b/pos_order_mgmt/README.rst @@ -106,7 +106,10 @@ Contributors * David Vidal * Sylvain LE GAL (https://twitter.com/legalsylvain) +* Carlos Martínez * Pierrick Brun +* Iván Todorovich + Maintainers ~~~~~~~~~~~ diff --git a/pos_order_mgmt/models/pos_config.py b/pos_order_mgmt/models/pos_config.py index e2196a2b..ddd4d814 100644 --- a/pos_order_mgmt/models/pos_config.py +++ b/pos_order_mgmt/models/pos_config.py @@ -16,12 +16,20 @@ class PosConfig(models.Model): help='Allows to reprint already done orders in the frontend', oldname='iface_load_done_order', ) + iface_return_done_order = fields.Boolean( string='Return Done Orders', default=True, help='Allows to return already done orders in the frontend', oldname='iface_load_done_order', ) + + iface_copy_done_order = fields.Boolean( + string='Duplicate Done Orders', + default=True, + help='Allows to duplicate already done orders in the frontend', + ) + iface_load_done_order_max_qty = fields.Integer( string='Max. Done Orders Quantity To Load', default=10, diff --git a/pos_order_mgmt/models/pos_order.py b/pos_order_mgmt/models/pos_order.py index 59f0e612..11c43cdf 100644 --- a/pos_order_mgmt/models/pos_order.py +++ b/pos_order_mgmt/models/pos_order.py @@ -33,9 +33,10 @@ class PosOrder(models.Model): @api.model def _prepare_filter_query_for_pos(self, pos_session_id, query): return [ - '|', + '|', '|', ('name', 'ilike', query), ('pos_reference', 'ilike', query), + ('partner_id.display_name', 'ilike', query), ] @api.model @@ -57,8 +58,8 @@ class PosOrder(models.Model): condition += [('config_id', '=', config.id)] else: # Search globally by criteria - condition += self._prepare_filter_query_for_pos(pos_session_id, - query) + condition += self._prepare_filter_query_for_pos( + pos_session_id, query) field_names = self._prepare_fields_for_pos_list() return self.search_read( condition, field_names, limit=config.iface_load_done_order_max_qty) diff --git a/pos_order_mgmt/readme/CONTRIBUTORS.rst b/pos_order_mgmt/readme/CONTRIBUTORS.rst index bdac6f44..e49bf7b1 100644 --- a/pos_order_mgmt/readme/CONTRIBUTORS.rst +++ b/pos_order_mgmt/readme/CONTRIBUTORS.rst @@ -2,3 +2,4 @@ * Sylvain LE GAL (https://twitter.com/legalsylvain) * Carlos Martínez * Pierrick Brun +* Iván Todorovich diff --git a/pos_order_mgmt/static/src/js/widgets.js b/pos_order_mgmt/static/src/js/widgets.js index ce696308..18dbeb62 100644 --- a/pos_order_mgmt/static/src/js/widgets.js +++ b/pos_order_mgmt/static/src/js/widgets.js @@ -1,5 +1,6 @@ /* Copyright 2018 GRAP - Sylvain LE GAL Copyright 2018 Tecnativa - David Vidal + Copyright 2019 Druidoo - Ivan Todorovich License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */ odoo.define('pos_order_mgmt.widgets', function (require) { "use strict"; @@ -56,7 +57,8 @@ odoo.define('pos_order_mgmt.widgets', function (require) { this.order_cache = new DomCache(); this.orders = []; this.unknown_products = []; - this.search_done_orders(); + this.search_query = false; + this.perform_search(); }, auto_back: true, @@ -77,24 +79,25 @@ odoo.define('pos_order_mgmt.widgets', function (require) { this.$('.back').click(function () { return self.gui.show_screen(self.gui.startup_screen); }); - if (self.orders.length === 0) { - this.search_done_orders(); - } - this.render_list(); - var search_timeout = null; + if (this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard) { this.chrome.widget.keyboard.connect(this.$('.searchbox input')); } + + var search_timeout = null; this.$('.searchbox input').on('keyup', function (event) { + self.search_query = this.value; clearTimeout(search_timeout); - var query = this.value; search_timeout = setTimeout(function () { - self.perform_search(query, event.which === 13); + self.perform_search(); }, 70); }); + this.$('.searchbox .search-clear').click(function () { self.clear_search(); }); + + this.perform_search(); }, render_list: function () { @@ -126,34 +129,46 @@ odoo.define('pos_order_mgmt.widgets', function (require) { // button events. this.$('.order-list-return').off('click'); this.$('.order-list-reprint').off('click'); + this.$('.order-list-copy').off('click'); this.$('.order-list-return').click(function (event) { self.order_list_actions(event, 'return'); }); this.$('.order-list-reprint').click(function (event) { self.order_list_actions(event, 'print'); }); + this.$('.order-list-copy').click(function(event) { + self.order_list_actions(event, 'copy'); + }); }, order_list_actions: function (event, action) { - var dataset = event.target.parentNode.dataset; var self = this; + var order_data; + var dataset = event.target.parentNode.dataset; if (dataset.orderId) { - this.load_order(parseInt(dataset.orderId, 10), action); + self.load_order_data(parseInt(dataset.orderId, 10)) + .then(function(order_data) { + self.order_action(order_data, action); + }) } else { - var local_order = ''; - _.each(this.orders, function (order) { + _.each(this.orders, function (order_data) { if (order.uid === dataset.uid) { - order.return = action === 'return'; - local_order = self._prepare_order_from_order_data(order); + self.order_action(order_data, action); } }); - if (local_order) { - this['action_' + action](local_order); - } } }, - action_print: function (order) { + order_action: function(order_data, action) { + this.gui.back(); + this['action_' + action](order_data); + }, + + action_print: function (order_data) { + var order = this.load_order_from_data(order_data, true); + if (!order) return false; + // Restore the previous name + order.name = order_data.pos_reference || order_data.name; var receipt = order.export_for_printing(); // We store temporarily the current order so we can safely compute // taxes based on fiscal position @@ -178,26 +193,56 @@ odoo.define('pos_order_mgmt.widgets', function (require) { } }, - action_return: function (order) { + action_copy: function(order_data) { + // Remove payments from original data + order_data.statement_ids = false; + var order = this.load_order_from_data(order_data, true); + if (!order) { return false; } + // If previous order was invoiced, we need a refund too + order.set_to_invoice(order_data.origin_invoice_id); + order.formatted_validation_date = false; + order.trigger('change'); this.pos.get('orders').add(order); this.pos.set('selectedOrder', order); return order; }, - _prepare_order_from_order_data: function (order_data) { + action_return: function (order_data) { + //var order_data = _.cloneDeep(order_data); + // Remove payments from original data + order_data.statement_ids = false; + // Invert line quantities + var order_lines = order_data.line_ids || order_data.lines || []; + _.each(order_lines, function(line) { line.qty = -1 * line.qty }) + // Load from new data and change some stuff + var order = this.load_order_from_data(order_data); + if (!order) { return false; } + order.return = true; + order.name = _t("Refund ") + order.uid;; + order.origin_name = order_data.pos_reference || order.returned_order_id; + // If previous order was invoiced, we need a refund too + order.set_to_invoice(order_data.origin_invoice_id); + order.formatted_validation_date = false; + order.trigger('change'); + // Add to pos + this.pos.get('orders').add(order); + this.pos.set('selectedOrder', order); + return order; + }, + + _prepare_order_from_order_data: function (order_data, temporary) { var self = this; var order = new pos.Order({}, { pos: this.pos, - temporary: !order_data.return, + temporary: !!temporary, }); - // Set Generic Info - if (!order_data.return) { - order.name = order_data.pos_reference || order_data.name; - } + if (order_data.partner_id.length) { order_data.partner_id = order_data.partner_id[0]; } + order.set_client(this.pos.db.get_partner_by_id(order_data.partner_id)); + // Set fiscal position if (order_data.fiscal_position && this.pos.fiscal_positions) { var fiscal_positions = this.pos.fiscal_positions; @@ -206,23 +251,17 @@ odoo.define('pos_order_mgmt.widgets', function (require) { })[0]; order.trigger('change'); } + // Set order lines var orderLines = order_data.line_ids || order_data.lines || []; self._prepare_orderlines_from_order_data(order, order_data, orderLines); - if (order_data.return) { - order.return = true; - // A credit note should be emited if there was an invoice - order.set_to_invoice(order_data.origin_invoice_id); - // We'll refunded orders once they are synced - order.returned_order_id = order_data.id || order_data.name; - order.origin_name = order_data.pos_reference || order.returned_order_id; - order.trigger('change'); - return order; - } + if (order_data.returned_order_id) { order.origin_name = order_data.returned_order_id; } + order.formatted_validation_date = moment(order_data.date_order).format('YYYY-MM-DD HH:mm:ss'); + // Set Payment lines var paymentLines = order_data.statement_ids || []; _.each(paymentLines, function (paymentLine) { @@ -243,6 +282,7 @@ odoo.define('pos_order_mgmt.widgets', function (require) { }); return order; }, + _prepare_orderlines_from_order_data: function(order, order_data, orderLines) { var self = this; _.each(orderLines, function(line) { @@ -258,7 +298,7 @@ odoo.define('pos_order_mgmt.widgets', function (require) { // Create a new order line order.add_product(product, { price: line.price_unit, - quantity: order_data.return ? line.qty * -1 : line.qty, + quantity: line.qty, discount: line.discount, merge: false, }); @@ -266,36 +306,12 @@ odoo.define('pos_order_mgmt.widgets', function (require) { }); }, - load_order: function (order_id, action) { - this.unknown_products = []; + load_order_data: function(order_id) { var self = this; return this._rpc({ model: 'pos.order', method: 'load_done_order_for_pos', args: [order_id], - }).then(function (order_data) { - self.gui.back(); - var correct_order_print = true; - if (action === 'return') { - order_data.return = true; - } - var order = self._prepare_order_from_order_data(order_data); - // Forbid POS Order loading if some products are unknown - if (self.unknown_products.length > 0) { - self.gui.show_popup('error-traceback', { - 'title': _t('Unknown Products'), - 'body': _t('Unable to load some order lines because the ' + - 'products are not available in the POS cache.\n\n' + - 'Please check that lines :\n\n * ') + self.unknown_products.join("; \n *"), - }); - correct_order_print = false; - } - if (correct_order_print && action === 'print') { - self.action_print(order); - } - if (correct_order_print && action === 'return') { - self.action_return(order); - } }).fail(function (error, event) { if (parseInt(error.code, 10) === 200) { // Business Logic Error, not a connection problem @@ -310,10 +326,42 @@ odoo.define('pos_order_mgmt.widgets', function (require) { 'body': _t('Can not execute this action because the POS is currently offline'), }); } - event.preventDefault(); }); }, + load_order_from_data: function(order_data) { + var self = this; + this.unknown_products = []; + var order = self._prepare_order_from_order_data(order_data); + // Forbid POS Order loading if some products are unknown + if (self.unknown_products.length > 0) { + self.gui.show_popup('error-traceback', { + 'title': _t('Unknown Products'), + 'body': _t('Unable to load some order lines because the ' + + 'products are not available in the POS cache.\n\n' + + 'Please check that lines :\n\n * ') + self.unknown_products.join("; \n *"), + }); + return false; + } + return order; + }, + + /* deprecated */ + load_order: function (order_id) { + var self = this; + var done = new $.Deferred(); + this.load_order_data(order_id) + .then(function(order_data) { + self.gui.show_screen('orderlist'); + var order = self.load_order_from_data(order_data); + if (!order) { return done.fail(); } + done.resolve(order); + }).fail(function() { + done.fail(); + }); + return done; + }, + // Search Part search_done_orders: function (query) { var self = this; @@ -342,22 +390,18 @@ odoo.define('pos_order_mgmt.widgets', function (require) { }); }, - perform_search: function (query) { + perform_search: function() { var self = this; - this.search_done_orders(query) - .done(function () { - self.render_list(); - }); + return this.search_done_orders(self.search_query) + .done(function () { self.render_list(); }); }, clear_search: function () { var self = this; - this.search_done_orders() - .done(function () { - self.$('.searchbox input')[0].value = ''; - self.$('.searchbox input').focus(); - self.render_list(); - }); + self.$('.searchbox input')[0].value = ''; + self.$('.searchbox input').focus(); + self.search_query = false; + self.perform_search(); }, }); diff --git a/pos_order_mgmt/static/src/xml/pos.xml b/pos_order_mgmt/static/src/xml/pos.xml index 6eb9f3be..728d2762 100644 --- a/pos_order_mgmt/static/src/xml/pos.xml +++ b/pos_order_mgmt/static/src/xml/pos.xml @@ -58,6 +58,9 @@ + + + diff --git a/pos_order_mgmt/views/view_pos_config.xml b/pos_order_mgmt/views/view_pos_config.xml index fd1a35fa..aa5c540c 100644 --- a/pos_order_mgmt/views/view_pos_config.xml +++ b/pos_order_mgmt/views/view_pos_config.xml @@ -33,6 +33,17 @@ +
+
+ +
+
+
+