From a5008a42bd8a223c4e6ed4c723147ca60e83c7d5 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Tue, 11 Dec 2018 13:32:24 +0100 Subject: [PATCH] [FIX] do not allow to create sale order several times; [FIX] Remove console.log ; [IMP] Do not import js files in backend [IMP] apply new readme structure [FIX] remove useless demo file [FIX] some pylint issues [REF] add maintainers and developpment status --- pos_order_to_sale_order/README.rst | 146 ++----------- pos_order_to_sale_order/__openerp__.py | 4 +- .../demo/product_template.xml | 19 -- pos_order_to_sale_order/demo/sale_order.xml | 51 ----- .../demo/stock_picking_type.xml | 7 - pos_order_to_sale_order/readme/CONFIGURE.rst | 8 + .../readme/CONTRIBUTORS.rst | 1 + .../readme/DESCRIPTION.rst | 52 +++++ pos_order_to_sale_order/readme/ROADMAP.rst | 11 + .../src/css/pos_order_to_sale_order.css | 12 ++ .../static/src/js/pos_order_to_sale_order.js | 200 +++++++++++------- .../views/pos_order_to_sale_order.xml | 5 +- 12 files changed, 232 insertions(+), 284 deletions(-) delete mode 100644 pos_order_to_sale_order/demo/product_template.xml delete mode 100644 pos_order_to_sale_order/demo/sale_order.xml delete mode 100644 pos_order_to_sale_order/demo/stock_picking_type.xml create mode 100644 pos_order_to_sale_order/readme/CONFIGURE.rst create mode 100644 pos_order_to_sale_order/readme/CONTRIBUTORS.rst create mode 100644 pos_order_to_sale_order/readme/DESCRIPTION.rst create mode 100644 pos_order_to_sale_order/readme/ROADMAP.rst create mode 100644 pos_order_to_sale_order/static/src/css/pos_order_to_sale_order.css diff --git a/pos_order_to_sale_order/README.rst b/pos_order_to_sale_order/README.rst index a8c8e8c1..21cd7854 100644 --- a/pos_order_to_sale_order/README.rst +++ b/pos_order_to_sale_order/README.rst @@ -1,135 +1,21 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html - :alt: License: AGPL-3 +**This file is going to be generated by oca-gen-addon-readme.** +*Manual changes will be overwritten.* -======================= -POS Order To Sale Order -======================= +Please provide content in the ``readme`` directory: +* **DESCRIPTION.rst** (required) +* INSTALL.rst (optional) +* CONFIGURE.rst (optional) +* **USAGE.rst** (optional, highly recommended) +* DEVELOP.rst (optional) +* ROADMAP.rst (optional) +* HISTORY.rst (optional, recommended) +* **CONTRIBUTORS.rst** (optional, highly recommended) +* CREDITS.rst (optional) -This module extends the functionality of point of sale to allow sale orders -creation from the Point of Sale. +Content of this README will also be drawn from the addon manifest, +from keys such as name, authors, maintainers, development_status, +and license. - -In the POS UI, buttons has been added to create a sale order and discard -the current POS order. - -This module is usefull in many cases, for exemple : - -* take orders with a very simple interface - -* if you have some customers that come every day in your shop, but want to - have a unique invoice at the end of the month. With that module, you can - create a sale order and deliver products every time to keep your stock value - correct, and to create a unique invoice, when you want. - - -Three options are available: - -#. '**Create a draft Order**' - A new sale order in a draft mode will be created that can be changed later. - -.. figure:: static/description/pos_create_picking_option_1.png - :width: 800 px - -#. '**Create a Confirmed Order**' - A new sale order will be created and confirmed. - -.. figure:: static/description/pos_create_picking_option_2.png - :width: 800 px - -#. '**Create Delivered Picking**' (by default) - A new sale order will be created and confirmed. the associated picking - will be marked as delivered. - -.. figure:: static/description/pos_create_picking_option_3.png - :width: 800 px - -Configuration -============= - -To configure this module, you need to: - -#. Go to Point Of Sale / Configuration / Point of Sale -#. Check the box 'Create Sale Orders' -#. Select the desired default behaviour - -.. figure:: static/description/pos_config_form.png - :width: 800 px - -Usage -===== - -.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas - :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/184/8.0 - -Technical Notes -=============== - -* Some hooks are defined in the JS file, to define custom behaviour after - having created the sale order (and the stock picking). - -* Some prepare functions are available in the sale.order model, to overload - the creation of the sale order. - -* You could be interested by another module, pos_sale_order, that completely - alter Point of Sale module, avoiding creating Pos Orders, and creating - allways Sale Orders. - This module is a WIP state, and is available here: - https://github.com/OCA/pos/pull/35 - -Known issues / Roadmap -====================== - -* Because of the poor design of the Odoo Point of Sale, some basic features - are not available by default, like pricelist, fiscal position, etc ... - For that reason, unit price will be recomputed by default, when creating the - sale order, and the unit price of the current bill will not be used. - -Note that this problem is fixed if ``pos_pricelist`` is installed. -(same repository) In that cases, the pricelist, the unit prices and the taxes -will be the same in the order, as in the displayed bill. - -.. figure:: static/description/pos_create_picking_confirm.png - :width: 800 px - - -Bug Tracker -=========== - -Bugs are tracked on `GitHub Issues -`_. In case of trouble, please -check there if your issue has already been reported. If you spotted it first, -help us smash it by providing detailed and welcomed feedback. - -Credits -======= - -Contributors ------------- - -* Sylvain Le Gal (https://twitter.com/legalsylvain) - -Funders -------- - -The development of this module has been financially supported by: - -* GRAP, Groupement Régional Alimentaire de Proximité (http://www.grap.coop) - -Maintainer ----------- - -.. image:: https://odoo-community.org/logo.png - :alt: Odoo Community Association - :target: https://odoo-community.org - -This module is maintained by the OCA. - -OCA, or the Odoo Community Association, is a nonprofit organization whose -mission is to support the collaborative development of Odoo features and -promote its widespread use. - -To contribute to this module, please visit https://odoo-community.org. +A good, one sentence summary in the manifest is also highly recommended. diff --git a/pos_order_to_sale_order/__openerp__.py b/pos_order_to_sale_order/__openerp__.py index e93e6710..1fbeb326 100644 --- a/pos_order_to_sale_order/__openerp__.py +++ b/pos_order_to_sale_order/__openerp__.py @@ -5,13 +5,15 @@ { 'name': 'PoS Order To Sale Order', - 'version': '8.0.2.0.0', + 'version': '8.0.3.0.0', 'author': 'GRAP,Odoo Community Association (OCA)', 'category': 'Point Of Sale', 'license': 'AGPL-3', 'depends': [ 'point_of_sale', ], + 'maintainers': ['legalsylvain'], + 'development_status': "Production/Stable", 'website': 'https://odoo-community.org/', 'data': [ 'views/view_pos_config.xml', diff --git a/pos_order_to_sale_order/demo/product_template.xml b/pos_order_to_sale_order/demo/product_template.xml deleted file mode 100644 index 38e35a4c..00000000 --- a/pos_order_to_sale_order/demo/product_template.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/pos_order_to_sale_order/demo/sale_order.xml b/pos_order_to_sale_order/demo/sale_order.xml deleted file mode 100644 index d2059c64..00000000 --- a/pos_order_to_sale_order/demo/sale_order.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - picking - - - - - - 5 - - - - - - 3 - - - - - - - - picking - - - - - - 15 - 10 - - - - - - 1 - - - - - - 3 - 555 - - - - - diff --git a/pos_order_to_sale_order/demo/stock_picking_type.xml b/pos_order_to_sale_order/demo/stock_picking_type.xml deleted file mode 100644 index e4c35380..00000000 --- a/pos_order_to_sale_order/demo/stock_picking_type.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/pos_order_to_sale_order/readme/CONFIGURE.rst b/pos_order_to_sale_order/readme/CONFIGURE.rst new file mode 100644 index 00000000..f77b4815 --- /dev/null +++ b/pos_order_to_sale_order/readme/CONFIGURE.rst @@ -0,0 +1,8 @@ +To configure this module, you need to: + +* Go to Point Of Sale / Configuration / Point of Sale +* Check the box 'Create Sale Orders' +* Select the desired default behaviour + +.. figure:: ../static/description/pos_config_form.png + :width: 800 px diff --git a/pos_order_to_sale_order/readme/CONTRIBUTORS.rst b/pos_order_to_sale_order/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..e1525ce0 --- /dev/null +++ b/pos_order_to_sale_order/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Sylvain LE GAL (https://www.twitter.com/legalsylvain) diff --git a/pos_order_to_sale_order/readme/DESCRIPTION.rst b/pos_order_to_sale_order/readme/DESCRIPTION.rst new file mode 100644 index 00000000..993e779e --- /dev/null +++ b/pos_order_to_sale_order/readme/DESCRIPTION.rst @@ -0,0 +1,52 @@ +This module extends the functionality of point of sale to allow sale orders +creation from the Point of Sale. + + +In the POS UI, buttons has been added to create a sale order and discard +the current POS order. + +This module is usefull in many cases, for exemple : + +* take orders with a very simple interface + +* if you have some customers that come every day in your shop, but want to + have a unique invoice at the end of the month. With that module, you can + create a sale order and deliver products every time to keep your stock value + correct, and to create a unique invoice, when you want. + + +Three options are available: + +* **Create a draft Order** + A new sale order in a draft mode will be created that can be changed later. + +.. figure:: ../static/description/pos_create_picking_option_1.png + :width: 800 px + +* **Create a Confirmed Order** + A new sale order will be created and confirmed. + +.. figure:: ../static/description/pos_create_picking_option_2.png + :width: 800 px + +* **Create Delivered Picking** (by default) + A new sale order will be created and confirmed. the associated picking + will be marked as delivered. + +.. figure:: ../static/description/pos_create_picking_option_3.png + :width: 800 px + + +**Technical Notes** + +* Some hooks are defined in the JS file, to define custom behaviour after + having created the sale order (and the stock picking). + +* Some prepare functions are available in the sale.order model, to overload + the creation of the sale order. + +* You could be interested by another module, pos_sale_order, that completely + alter Point of Sale module, avoiding creating Pos Orders, and creating + allways Sale Orders. + This module is a WIP state, and is available here: + https://github.com/OCA/pos/pull/35 diff --git a/pos_order_to_sale_order/readme/ROADMAP.rst b/pos_order_to_sale_order/readme/ROADMAP.rst new file mode 100644 index 00000000..ed6dd416 --- /dev/null +++ b/pos_order_to_sale_order/readme/ROADMAP.rst @@ -0,0 +1,11 @@ +* Because of the poor design of the Odoo Point of Sale, some basic features + are not available by default, like pricelist, fiscal position, etc ... + For that reason, unit price will be recomputed by default, when creating the + sale order, and the unit price of the current bill will not be used. + +Note that this problem is fixed if ``pos_pricelist`` is installed. +(same repository) In that cases, the pricelist, the unit prices and the taxes +will be the same in the order, as in the displayed bill. + +.. figure:: ../static/description/pos_create_picking_confirm.png + :width: 800 px diff --git a/pos_order_to_sale_order/static/src/css/pos_order_to_sale_order.css b/pos_order_to_sale_order/static/src/css/pos_order_to_sale_order.css new file mode 100644 index 00000000..11d8de8f --- /dev/null +++ b/pos_order_to_sale_order/static/src/css/pos_order_to_sale_order.css @@ -0,0 +1,12 @@ +/* + Copyright (C) 2018 - Today: GRAP (http://www.grap.coop) + @author: Sylvain LE GAL (https://twitter.com/legalsylvain) + License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +*/ + +/*Redefine here, the style defined in web module (base.css), because this file +is not loaded in the point of sale.*/ +.blockUI.blockOverlay { + background-color: black; + opacity: 0.6; +} diff --git a/pos_order_to_sale_order/static/src/js/pos_order_to_sale_order.js b/pos_order_to_sale_order/static/src/js/pos_order_to_sale_order.js index b0ca7b83..62bcdead 100644 --- a/pos_order_to_sale_order/static/src/js/pos_order_to_sale_order.js +++ b/pos_order_to_sale_order/static/src/js/pos_order_to_sale_order.js @@ -1,157 +1,207 @@ -/****************************************************************************** +/* *************************************************************************** Copyright (C) 2017 - Today: GRAP (http://www.grap.coop) @author: Sylvain LE GAL (https://twitter.com/legalsylvain) License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - *****************************************************************************/ +**************************************************************************** */ -openerp.pos_order_to_sale_order = function(instance, local) { +openerp.pos_order_to_sale_order = function (instance) { "use strict"; var module = instance.point_of_sale; var _t = instance.web._t; - /************************************************************************* - New Widget CreateSaleOrderButtonWidget: - * On click, check if there is a customer defined, - ask confirmation call server to create sale order, and delete - the current order. - */ + /* ************************************************************************ + New Widget CreateSaleOrderButtonWidget + ************************************************************************ */ module.CreateSaleOrderButtonWidget = module.PosBaseWidget.extend({ template: 'CreateSaleOrderButtonWidget', - init: function(parent, options){ + /** + * Define all the confirmation messages. + */ + init: function (parent, options) { this._super(parent, options); this.sale_order_state = options.sale_order_state; - if (this.sale_order_state == 'draft') { + if (this.sale_order_state === 'draft') { this.display_text = _t("Create Draft Order"); - this.confirmation_message = _t('Create Draft Sale Order and discard the current PoS Order?'); - this.confirmation_comment = _t("This operation will permanently discard the current PoS Order and create a draft Sale Order, based on the current order lines."); - console.log(this); - } - else if (options.sale_order_state == 'confirmed') { + this.confirmation_message = _t( + 'Create Draft Sale Order and discard the current' + + ' PoS Order?'); + this.confirmation_comment = _t( + "This operation will permanently discard the current PoS" + + " Order and create a draft Sale Order, based on the" + + " current order lines."); + } else if (options.sale_order_state === 'confirmed') { this.display_text = _t("Create Confirmed Order"); - this.confirmation_message = _t('Create Confirmed Sale Order and discard the current PoS Order?'); - this.confirmation_comment = _t("This operation will permanently discard the current PoS Order and create a confirmed Sale Order, based on the current order lines."); - } - else if (options.sale_order_state == 'delivered') { + this.confirmation_message = _t( + 'Create Confirmed Sale Order and discard the current' + + ' PoS Order?'); + this.confirmation_comment = _t( + "This operation will permanently discard the current PoS" + + " Order and create a confirmed Sale Order, based on the" + + " current order lines."); + } else if (options.sale_order_state === 'delivered') { this.display_text = _t("Create Delivered Order"); - this.confirmation_message = _t('Create Delivered Sale Order and discard the current PoS Order?'); - this.confirmation_comment = _t("This operation will permanently discard the current PoS Order and create a confirmed Sale Order, based on the current order lines. The according picking will be marked as delivered."); + this.confirmation_message = _t( + 'Create Delivered Sale Order and discard the current' + + ' PoS Order?'); + this.confirmation_comment = _t( + "This operation will permanently discard the current PoS" + + " Order and create a confirmed Sale Order, based on the" + + " current order lines. The according picking will be" + + " marked as delivered."); } - if (! this.pos.pricelist_engine){ - this.confirmation_comment += _t("\nNote if you have manually changed unit prices for some products, this changes will not been taken into account in the sale order.") + if (! this.pos.pricelist_engine) { + this.confirmation_comment += _t( + "\nNote if you have manually changed unit prices for" + + " some products, this changes will not been taken into" + + " account in the sale order.") } }, - renderElement: function() { + /** + * Define onclick function when the button to create sale order is + * clicked. + * - On click, check if there is a customer defined, + * - ask confirmation call server to create sale order, and delete + * the current order. + */ + renderElement: function () { var self = this; this._super(); - this.$el.click(function(){ + this.$el.click(function () { var current_order = self.pos.get('selectedOrder'); // Prevent empty delivery order - if (current_order.get('orderLines').length == 0){ - self.pos_widget.screen_selector.show_popup('error',{ + if (current_order.get('orderLines').length === 0) { + self.pos_widget.screen_selector.show_popup('error', { 'message': _t('Empty Order'), - 'comment': _t('There must be at least one product in your order to create Sale Order.'), + 'comment': _t( + 'There must be at least one product in your' + + ' order to create Sale Order.'), }); return; } // Check Customer - if (!current_order.get('client')){ - self.pos_widget.screen_selector.show_popup('error',{ + if (!current_order.get('client')) { + self.pos_widget.screen_selector.show_popup('error', { 'message': _t('No customer defined'), - 'comment': _t('You should select a customer in order to create a Sale Order. Please select one by clicking the order tab.'), + 'comment': _t( + 'You should select a customer in order to create' + + ' a Sale Order. Please select one by clicking' + + ' the order tab.'), }); return; } self.pos.pos_widget.screen_selector.show_popup('confirm', { message: self.confirmation_message, comment: self.confirmation_comment, - confirm: function(){ - var SaleOrderModel = new instance.web.Model('sale.order'); + confirm: function () { + var SaleOrderModel = + new instance.web.Model('sale.order'); current_order.sale_order_state = self.sale_order_state; - SaleOrderModel.call('create_order_from_pos', [self.prepare_create_sale_order(current_order)] + instance.web.blockUI(); + SaleOrderModel.call('create_order_from_pos', [ + self.prepare_create_sale_order(current_order)] ).then(function (result) { + instance.web.unblockUI(); self.hook_create_sale_order_success(result); - }).fail(function (error, event){ + }).fail(function (error, event) { + instance.web.unblockUI(); self.hook_create_sale_order_error(error, event); }); - }, }); }); }, - // Overload This function to send custom sale order data to server - prepare_create_sale_order: function(order) { + /** + * Overloadable function to send custom sale order data to server + */ + prepare_create_sale_order: function (order) { var res = order.export_as_JSON(); res.sale_order_state = this.sale_order_state; return res; }, - // Overload this function to make custom action after Sale order - // Creation success - hook_create_sale_order_success: function(result) { + /** + * Overloadable function to make custom action after Sale order + * Creation succeeded + */ + hook_create_sale_order_success: function (result) { this.pos.get('selectedOrder').destroy(); }, - // Overload this function to make custom action after Sale order - // Creation fail - hook_create_sale_order_error: function(error, event) { + /** + * Overloadable function to make custom action after Sale order + * Creation failed + */ + hook_create_sale_order_error: function (error, event) { event.preventDefault(); - if(error.code === 200 ){ + if (error.code === 200) { // Business Logic Error, not a connection problem - this.pos_widget.screen_selector.show_popup('error-traceback',{ + this.pos_widget.screen_selector.show_popup('error-traceback', { message: error.data.message, comment: error.data.debug, }); - } - else{ - // connexion problem - this.pos_widget.screen_selector.show_popup('error',{ + } else { + // Connexion problem + this.pos_widget.screen_selector.show_popup('error', { message: _t('The order could not be sent'), - comment: _t('Check your internet connection and try again.'), + comment: _t( + 'Check your internet connection and try again.'), }); } - }, }); - /************************************************************************* + /* ************************************************************************ Extend PosWidget: - * Create new buttons, depending of the configuration - */ + ************************************************************************ */ module.PosWidget = module.PosWidget.extend({ - build_widgets: function() { + + /** + * Overload build_widgets(), to create new buttons, depending of the + * configuration + */ + build_widgets: function () { this._super(); - if (this.pos.config.iface_create_draft_sale_order){ - this.create_draft_sale_order_button = new module.CreateSaleOrderButtonWidget( - this, {'sale_order_state': 'draft'}); - this.create_draft_sale_order_button.appendTo(this.pos_widget.$('ul.orderlines')); + if (this.pos.config.iface_create_draft_sale_order) { + this.create_draft_sale_order_button = + new module.CreateSaleOrderButtonWidget( + this, {'sale_order_state': 'draft'}); + this.create_draft_sale_order_button.appendTo( + this.pos_widget.$('ul.orderlines')); } - if (this.pos.config.iface_create_confirmed_sale_order){ - this.create_confirmed_sale_order_button = new module.CreateSaleOrderButtonWidget( - this, {'sale_order_state': 'confirmed'}); - this.create_confirmed_sale_order_button.appendTo(this.pos_widget.$('ul.orderlines')); + if (this.pos.config.iface_create_confirmed_sale_order) { + this.create_confirmed_sale_order_button = + new module.CreateSaleOrderButtonWidget( + this, {'sale_order_state': 'confirmed'}); + this.create_confirmed_sale_order_button.appendTo( + this.pos_widget.$('ul.orderlines')); } - if (this.pos.config.iface_create_delivered_sale_order){ - this.create_delivered_sale_order_button = new module.CreateSaleOrderButtonWidget( - this, {'sale_order_state': 'delivered'}); - this.create_delivered_sale_order_button.appendTo(this.pos_widget.$('ul.orderlines')); + if (this.pos.config.iface_create_delivered_sale_order) { + this.create_delivered_sale_order_button = + new module.CreateSaleOrderButtonWidget( + this, {'sale_order_state': 'delivered'}); + this.create_delivered_sale_order_button.appendTo( + this.pos_widget.$('ul.orderlines')); } }, }); - /************************************************************************* - Extend OrderWidget: - Overload renderElement, to display buttons when the order change. - */ + /* ************************************************************************ + Extend OrderWidget + ************************************************************************ */ module.OrderWidget = module.OrderWidget.extend({ - renderElement: function(scrollbottom){ + + /** + * Overload renderElement(), to display buttons when the order change. + */ + renderElement: function (scrollbottom) { this._super(scrollbottom); if (this.pos_widget.create_draft_sale_order_button) { this.pos_widget.create_draft_sale_order_button.appendTo( @@ -169,7 +219,7 @@ openerp.pos_order_to_sale_order = function(instance, local) { ); } - } + }, }); }; diff --git a/pos_order_to_sale_order/views/pos_order_to_sale_order.xml b/pos_order_to_sale_order/views/pos_order_to_sale_order.xml index 12d5a620..5c8992ba 100644 --- a/pos_order_to_sale_order/views/pos_order_to_sale_order.xml +++ b/pos_order_to_sale_order/views/pos_order_to_sale_order.xml @@ -2,10 +2,13 @@ -