diff --git a/pos_picking_load/README.rst b/pos_picking_load/README.rst index 3023ded6..8661ae1d 100644 --- a/pos_picking_load/README.rst +++ b/pos_picking_load/README.rst @@ -1,30 +1,45 @@ -.. 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 - - -================ -POS Picking Load -================ - +============================ +Point Of Sale - Picking Load +============================ + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-legalsylvain%2Fpos-lightgray.png?logo=github + :target: https://github.com/legalsylvain/pos/tree/10.0-mig-pos_picking_load/pos_picking_load + :alt: legalsylvain/pos + +|badge1| |badge2| |badge3| This module extends the functionality of point of sale to allow you to load your pickings in the Point of Sale, in order to add / remove products and so create a PoS Order and mark it as paid. -Detailled Use Case -================== +**Detailled Use Case** This module is usefull for the following use case * You have many Sale Orders that have generated pickings. Typically if you have connected your Odoo instance to an online store like Shop Invader, - Prestashop, Magento, or if you use light Odoo shop (```website_sale``` + Prestashop, Magento, or if you use light Odoo shop (``website_sale`` module). * Once the order validated, you prepare your pickings * The customer come in your shop to recover his order * the customer add (or remove) some products -* the customer pay his order, based on the real delivered products list. +* the customer pay his order, based on the real delivered products list + +**Table of contents** + +.. contents:: + :local: Configuration ============= @@ -35,7 +50,7 @@ To configure this module, you need to: #. Select the picking type(s) you want to see in the point of sale #. Check the box 'Available in Point of Sale' -.. figure:: static/description/stock_picking_type_form.png +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/stock_picking_type_form.png :width: 800 px Note: This box is NOT enabled by default except in demo data for the type @@ -43,13 +58,34 @@ Note: This box is NOT enabled by default except in demo data for the type #. Go to Point of Sale / Configuration / Point of Sales #. Select the Point(s) of Sales witch those you want to enable the feature -#. Check the box 'Load Pickings'. +#. Check the box 'Load Pickings' +#. Set the max quantity of pickings you want to load -.. figure:: static/description/pos_config_form.png +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/pos_config_form.png :width: 800 px Note: This box is enabled by default +**Technical Notes** + +* By default, the Point of Sale will display only the pickings if the state is + in 'Waiting Availability', 'Partially Available' or 'Ready to Transfer'. + +You can change this filter by overloading the ``_prepare_filter_for_pos`` +function of the model ``stock.picking``. + +* By default, the search of pickings will be done on the fields ``name``, + ``origin`` and ``partner_id`` of the picking. + +You can change this feature by overloading the +``_prepare_filter_query_for_pos`` function of the model ``stock.picking``. + +* By default, when the PoS order is confirmed, the original picking is + cancelled and the sale order is set to the state 'Done'. + +You can change this behaviour by overloading +``_handle_orders_with_original_picking`` function of the model ``pos.order``. + Usage ===== @@ -58,36 +94,42 @@ To use this module, you need to: * Launch the point of sale * On a new order (without lines), click on the 'Load Picking' button. -.. figure:: static/description/load_picking_01.png +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_01_load_button.png :width: 800 px * Point of sale will load available pickings. (About displayed pickings, see - 'Technical Notes' below). + 'Technical Notes' section). -.. figure:: static/description/load_picking_02.png +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_02_picking_list.png :width: 800 px -* Click on a picking will display the content of the moves (as PoS Order Lines) +* Click on a picking will check if the picking is loadable and if yes, will + display a 'Select' button. (See 'Possible Warnings' Section) -.. figure:: static/description/load_picking_03.png +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_03_confirm.png + :width: 800 px + +* Confirm the selection, by clicking on 'Select' button. It will display + the content of the moves (as PoS Order Lines) + +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_04_pos_order.png :width: 800 px The price and the discount will be the sale price and the discount set in -the according Sale Order Line, if it was found. Otherwise, discount will be to -0, and unit price will be the unit price of the product when it has been +the according Sale Order Line, if it was found. Otherwise, discount will be +set to 0, and unit price will be the unit price of the product when it has been loaded in the Point of Sale. **Related Sale Order:** -.. figure:: static/description/load_picking_04.png +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_sale_order.png :width: 800 px **Related Picking:** -.. figure:: static/description/load_picking_05.png +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_stock_picking.png :width: 800 px -* Confirm the selection, by clicking on 'Select' button. * Finally, you can add / remove products or change quantity and collect the payment. @@ -96,83 +138,77 @@ When, the order is marked as paid, the original picking will be cancelled, because Point Of Sale generates a new picking related to the real delivered products and the original Sale Order will pass to the state 'Done'. (Delivery exception is ignored). -(See 'Technical Notes' below). +(See 'Technical Notes' section). + +**Possible Warnings** Some warning messages can appear: -* if some products are not available in the Point of Sale. +* if some products are not available in the Point of Sale -.. figure:: static/description/load_picking_06.png +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_warning_product.png :width: 800 px -.. 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 +* if the partner is not available in the Point of Sale -Technical Notes -=============== +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_warning_partner.png + :width: 800 px -* By default, the following filters are applied on the pickings displayed: - * 'State' should be 'Waiting Availability', 'Partially Available' or - 'Ready to Transfer'. - * 'Invoice Control' should be 'To be invoiced'. - You can change this filter by overloading the ```_prepare_filter_for_pos``` - function of the model ```stock.picking``` +* if the picking has been still loaded in another PoS order -* By default, original Picking is cancelled and the Sale order is set to the - state 'Done'. You can change this behaviour by overloading - ```_handle_orders_with_original_picking``` function of the model - ```pos.order```. +.. figure:: https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_warning_picking_still_loaded.png + :width: 800 px Known issues / Roadmap ====================== * This module will try to get original unit price from the sale order and not - use the Current unit price of the product. (The price at which you pledged - to sell the product). + use the Current unit price of the product. + (The price at which you pledged to sell the product). Some VAT troubles will occure if a product is set with VAT marked as 'VAT included' and if in the sale order line, there are some VAT marked as - 'VAT excluded'. **The VAT settings should be consistent**. + 'VAT excluded' for exemple. + +**The VAT settings should be consistent.** 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. +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 smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. Credits ======= -Images ------- +Authors +~~~~~~~ -* Odoo Community Association: `Icon `_. +* GRAP Contributors ------------- +~~~~~~~~~~~~ + +* Sylvain LE GAL (https://twitter.com/legalsylvain) +* Stefan Rijnhart -* Sylvain Le Gal (https://twitter.com/legalsylvain) +Maintainers +~~~~~~~~~~~ -Funders -------- -The development of this module has been financially supported by: -* GRAP, Groupement Régional Alimentaire de Proximité (http://www.grap.coop) +.. |maintainer-legalsylvain| image:: https://github.com/legalsylvain.png?size=40px + :target: https://github.com/legalsylvain + :alt: legalsylvain -Maintainer ----------- +Current `maintainer `__: -.. image:: https://odoo-community.org/logo.png - :alt: Odoo Community Association - :target: https://odoo-community.org +|maintainer-legalsylvain| -This module is maintained by the OCA. +This module is part of the `legalsylvain/pos `_ project on GitHub. -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. +You are welcome to contribute. diff --git a/pos_picking_load/__init__.py b/pos_picking_load/__init__.py index a0fdc10f..042e239e 100644 --- a/pos_picking_load/__init__.py +++ b/pos_picking_load/__init__.py @@ -1,2 +1,2 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 from . import models diff --git a/pos_picking_load/__openerp__.py b/pos_picking_load/__manifest__.py similarity index 75% rename from pos_picking_load/__openerp__.py rename to pos_picking_load/__manifest__.py index 85edddf0..03e1df52 100644 --- a/pos_picking_load/__openerp__.py +++ b/pos_picking_load/__manifest__.py @@ -1,15 +1,19 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 # 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). { - 'name': 'POS Picking Load', - 'version': '8.0.1.2.0', + 'name': 'Point Of Sale - Picking Load', + 'summary': "Load and confirm stock pickings via Point Of Sale", + 'version': '10.0.1.0.0', 'author': 'GRAP,Odoo Community Association (OCA)', 'category': 'Point Of Sale', 'license': 'AGPL-3', + 'maintainers': ['legalsylvain'], + 'development_status': 'Beta', 'depends': [ + 'sale', 'point_of_sale', ], 'website': 'https://odoo-community.org/', @@ -29,4 +33,5 @@ 'qweb': [ 'static/src/xml/pos_picking_load.xml', ], + 'installable': True, } diff --git a/pos_picking_load/demo/product_template.xml b/pos_picking_load/demo/product_template.xml index 38e35a4c..a8da3db8 100644 --- a/pos_picking_load/demo/product_template.xml +++ b/pos_picking_load/demo/product_template.xml @@ -1,5 +1,7 @@ + + @@ -16,4 +18,14 @@ + + + + + + + + + + diff --git a/pos_picking_load/demo/sale_order.xml b/pos_picking_load/demo/sale_order.xml index d2059c64..13ce0f98 100644 --- a/pos_picking_load/demo/sale_order.xml +++ b/pos_picking_load/demo/sale_order.xml @@ -3,13 +3,15 @@ - picking + 5 + 100 + 20 @@ -18,12 +20,12 @@ 3 - + - - picking + + @@ -46,6 +48,6 @@ 555 - + diff --git a/pos_picking_load/i18n/fr.po b/pos_picking_load/i18n/fr.po index 952e0658..dacf7c40 100644 --- a/pos_picking_load/i18n/fr.po +++ b/pos_picking_load/i18n/fr.po @@ -1,39 +1,35 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * pos_picking_load +# * pos_picking_load # -# Translators: -# OCA Transbot , 2017 msgid "" msgstr "" -"Project-Id-Version: Odoo Server 8.0\n" +"Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-07-13 03:00+0000\n" -"PO-Revision-Date: 2017-07-13 03:00+0000\n" -"Last-Translator: OCA Transbot , 2017\n" -"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" -"Language: fr\n" +"POT-Creation-Date: 2019-01-06 18:33+0000\n" +"PO-Revision-Date: 2019-01-06 18:33+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Plural-Forms: \n" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:70 +#: code:addons/pos_picking_load/static/src/js/widget.js:242 #, python-format -msgid "--------------------------------" -msgstr "--------------------------------" +msgid "A picking is still loaded. You can not load another picking. Please create a new order." +msgstr "Un BL est déjà chargé. Vous ne pouvez pas en charger un autre. Veuillez créer une nouvelle commande." #. module: pos_picking_load -#: field:stock.picking.type,available_in_pos:0 +#: model:ir.model.fields,field_description:pos_picking_load.field_stock_picking_type_available_in_pos msgid "Available in Point Of Sale" msgstr "Disponible dans le point de vente" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/js/pos_picking_load.js:264 -#: code:addons/pos_picking_load/static/src/js/pos_picking_load.js:290 +#: code:addons/pos_picking_load/static/src/js/widget.js:211 #, python-format msgid "Can not execute this action because the POS is currently offline" msgstr "" @@ -42,113 +38,129 @@ msgstr "" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:22 +#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:27 #, python-format msgid "Cancel" msgstr "Annuler" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/js/pos_picking_load.js:263 -#: code:addons/pos_picking_load/static/src/js/pos_picking_load.js:289 +#: code:addons/pos_picking_load/static/src/js/widget.js:210 #, python-format msgid "Connection error" msgstr "Erreur de connexion" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:50 +#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:53 #, python-format msgid "Customer" msgstr "Client" #. module: pos_picking_load -#: field:sale.order,final_pos_order_id:0 -#: field:stock.picking,final_pos_order_id:0 +#: model:ir.model.fields,field_description:pos_picking_load.field_sale_order_final_pos_order_id +#: model:ir.model.fields,field_description:pos_picking_load.field_stock_picking_final_pos_order_id msgid "Final PoS Order" msgstr "Commande Finale" #. module: pos_picking_load -#: help:stock.picking.type,available_in_pos:0 -msgid "" -"If checked, associated pickings will be available in the point of sale, to " -"be changed and paid in it" -msgstr "" -"Si la case est cochée, toutes les bons de livraisons associés seront " -"disponible dans le point de vente, pour ere changé et payé au sein de celui-" -"ci" +#: model:ir.model.fields,help:pos_picking_load.field_stock_picking_type_available_in_pos +msgid "If checked, associated pickings will be available in the point of sale, to be changed and paid in it" +msgstr "Si la case est cochée, toutes les bons de livraisons associés seront disponible dans le point de vente, pour ere changé et payé au sein de celui-ci" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:5 +#: code:addons/pos_picking_load/static/src/js/widget.js:253 #, python-format msgid "Load Picking" msgstr "Charger un bon de livraison" #. module: pos_picking_load -#: field:pos.config,iface_load_picking:0 +#: model:ir.model.fields,field_description:pos_picking_load.field_pos_config_iface_load_picking msgid "Load Pickings" msgstr "Charger des bons de livraison" +#. module: pos_picking_load +#: model:ir.model.fields,field_description:pos_picking_load.field_pos_config_iface_load_picking_max_qty +msgid "Max Picking Quantity To Load" +msgstr "Quantité maximum de BL à charger" + #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:49 +#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:52 #, python-format msgid "Name" msgstr "Nom" #. module: pos_picking_load -#: field:pos.order,origin_picking_id:0 +#: model:ir.model.fields,field_description:pos_picking_load.field_pos_order_origin_picking_id msgid "Origin Picking" msgstr "Livraison d'origine" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:71 -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:79 +#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:74 +#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:82 #, python-format msgid "Origin Picking:" msgstr "BL d'origine:" #. module: pos_picking_load -#: model:ir.model,name:pos_picking_load.model_stock_picking -msgid "Picking List" -msgstr "Bon de livraison" +#. openerp-web +#: code:addons/pos_picking_load/static/src/js/widget.js:241 +#, python-format +msgid "Pending Picking" +msgstr "BL en cours + +#. module: pos_picking_load +#. openerp-web +#: code:addons/pos_picking_load/static/src/js/widget.js:131 +#: code:addons/pos_picking_load/static/src/js/widget.js:147 +#, python-format +msgid "Picking Still Loaded" +msgstr "Bon de livraison déjà chargé" #. module: pos_picking_load #: model:ir.model,name:pos_picking_load.model_pos_order -msgid "Point of Sale" -msgstr "Point de Vente" +msgid "Point of Sale Orders" +msgstr "Commandes du point de vente" #. module: pos_picking_load #: model:ir.model,name:pos_picking_load.model_sale_order msgid "Sales Order" -msgstr "Commande de ventes" +msgstr "Bon de commande" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:51 +#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:54 #, python-format msgid "Scheduled Date" msgstr "Date prévue" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:30 +#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:35 #, python-format msgid "Search Picking" msgstr "Chercher un bon de livraison" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:26 +#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:31 #, python-format msgid "Select" msgstr "Sélectionner" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:52 +#: code:addons/pos_picking_load/static/src/js/widget.js:203 +#, python-format +msgid "Server Error" +msgstr "Erreur serveur" + +#. module: pos_picking_load +#. openerp-web +#: code:addons/pos_picking_load/static/src/xml/pos_picking_load.xml:55 #, python-format msgid "Source Document" msgstr "Document d'origine" @@ -159,33 +171,37 @@ msgid "The picking type determines the picking view" msgstr "Le type de préparation détermine la vue de préparation" #. module: pos_picking_load -#: help:sale.order,final_pos_order_id:0 +#. openerp-web +#: code:addons/pos_picking_load/static/src/js/widget.js:204 +#, python-format +msgid "The server encountered an error while receiving your order." +msgstr "Le serveur a rencontré une erreur lors de la réception de votre commande." + +#. module: pos_picking_load +#: model:ir.model.fields,help:pos_picking_load.field_sale_order_final_pos_order_id msgid "This Sale Order has beend replaced by this PoS Order" -msgstr "" -"Ce bon de commande a été remplacé par cette commande via le point de vente" +msgstr "Ce bon de commande a été remplacé par cette commande via le point de vente" #. module: pos_picking_load -#: help:stock.picking,final_pos_order_id:0 -msgid "" -"This picking has been canceled, because it has been replaced by this PoS " -"Order" -msgstr "" -"Ce bon de livraison a été annulé, car il a été remplacé par cette commande " -"via le point de vente" +#: model:ir.model.fields,help:pos_picking_load.field_stock_picking_final_pos_order_id +msgid "This picking has been canceled, because it has been replaced by this PoS Order" +msgstr "Ce bon de livraison a été annulé, car il a été remplacé par cette commande via le point de vente" + +#. module: pos_picking_load +#: model:ir.model,name:pos_picking_load.model_stock_picking +msgid "Transfer" +msgstr "Transfert" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/js/pos_picking_load.js:228 +#: code:addons/pos_picking_load/static/src/js/widget.js:100 #, python-format -msgid "" -"Unable to load some picking lines because the products are not available in " -"the POS cache.\n" +msgid "Unable to load some picking lines because the products are not available in the POS cache.\n" "\n" "Please check that lines :\n" "\n" " * " -msgstr "" -"Impossible de charger certaines lignes du bon de livraison car certains " +msgstr "Impossible de charger certaines lignes du bon de livraison car certains " "produits ne sont pas disponibles dans le point de vente.\n" "\n" "Merci de vérifier les lignes suivantes :\n" @@ -194,25 +210,50 @@ msgstr "" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/js/pos_picking_load.js:239 +#: code:addons/pos_picking_load/static/src/js/widget.js:148 #, python-format -msgid "" -"Unable to load this picking because the partner is not known in the Point Of " -"Sale as a customer" -msgstr "" -"Impossible de charger ce bon de livraison car ce partenaire n'est pas " +msgid "Unable to load this picking because it has been loaded in another confirmed PoS Order :\n" +"\n" +"" +msgstr "Impossible de charger ce bon de livraison car il a déjà été chargé dans une autre commande confirmée :\n" +"\n" +"" + +#. module: pos_picking_load +#. openerp-web +#: code:addons/pos_picking_load/static/src/js/widget.js:132 +#, python-format +msgid "Unable to load this picking because it has been loaded in another draft PoS Order :\n" +"\n" +"" +msgstr "Impossible de charger ce bon de livraison car il a déjà été chargé dans une autre commande en cours :\n" +"\n" +"" + +#. module: pos_picking_load +#. openerp-web +#: code:addons/pos_picking_load/static/src/js/widget.js:118 +#, python-format +msgid "Unable to load this picking because the partner is not known in the Point Of Sale as a customer" +msgstr "Impossible de charger ce bon de livraison car ce partenaire n'est pas " "reconnu dans le point de vente comme un client" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/js/pos_picking_load.js:238 +#: code:addons/pos_picking_load/static/src/js/widget.js:117 #, python-format msgid "Unknown Partner" msgstr "Partenaire inconnu" #. module: pos_picking_load #. openerp-web -#: code:addons/pos_picking_load/static/src/js/pos_picking_load.js:227 +#: code:addons/pos_picking_load/static/src/js/widget.js:99 #, python-format msgid "Unknown Products" msgstr "Produits inconnus" + +#. module: pos_picking_load +#: model:ir.model,name:pos_picking_load.model_pos_config +msgid "pos.config" +msgstr "pos.config" + diff --git a/pos_picking_load/models/__init__.py b/pos_picking_load/models/__init__.py index d232c723..09985a88 100644 --- a/pos_picking_load/models/__init__.py +++ b/pos_picking_load/models/__init__.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 from . import sale_order from . import stock_picking from . import stock_picking_type diff --git a/pos_picking_load/models/pos_config.py b/pos_picking_load/models/pos_config.py index aa3f45c3..6806ad27 100644 --- a/pos_picking_load/models/pos_config.py +++ b/pos_picking_load/models/pos_config.py @@ -1,9 +1,9 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 # 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). -from openerp import models, fields +from odoo import models, fields class PosConfig(models.Model): diff --git a/pos_picking_load/models/pos_order.py b/pos_picking_load/models/pos_order.py index f2e3dbb4..415b2029 100644 --- a/pos_picking_load/models/pos_order.py +++ b/pos_picking_load/models/pos_order.py @@ -1,9 +1,9 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 # 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). -from openerp import models, api, fields +from odoo import models, api, fields class PosOrder(models.Model): diff --git a/pos_picking_load/models/sale_order.py b/pos_picking_load/models/sale_order.py index 594ee3c4..dc0b9014 100644 --- a/pos_picking_load/models/sale_order.py +++ b/pos_picking_load/models/sale_order.py @@ -1,9 +1,9 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 # 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). -from openerp import models, fields +from odoo import models, fields class SaleOrder(models.Model): diff --git a/pos_picking_load/models/stock_picking.py b/pos_picking_load/models/stock_picking.py index e18b8e77..8562fd8d 100644 --- a/pos_picking_load/models/stock_picking.py +++ b/pos_picking_load/models/stock_picking.py @@ -1,9 +1,9 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 # 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). -from openerp import models, api, fields +from odoo import models, api, fields class StockPicking(models.Model): @@ -15,7 +15,7 @@ class StockPicking(models.Model): help="This picking has been canceled, because it has been replaced by" " this PoS Order") - # Custom Section + # Custom Section - Picking List Part @api.model def _prepare_filter_for_pos(self, pos_session_id): picking_type_obj = self.env['stock.picking.type'] @@ -24,7 +24,6 @@ class StockPicking(models.Model): return [ ('picking_type_id', 'in', picking_types.ids), ('state', 'in', ['confirmed', 'partially_available', 'assigned']), - ('invoice_state', '=', '2binvoiced'), ] @api.model @@ -50,28 +49,33 @@ class StockPicking(models.Model): return self.search_read( condition, fields, limit=config.iface_load_picking_max_qty) - @api.multi - def load_picking_for_pos(self): - self.ensure_one() - pickinglines = [] - for line in self.move_lines.filtered(lambda x: x.state != 'cancel'): - picking_line = { - 'name': line.name, - 'product_id': line.product_id.id, - 'quantity': line.product_uom_qty, - } - sale_order_line =\ - line.procurement_id and line.procurement_id.sale_line_id - if sale_order_line: - # Get price and discount of the order if available - picking_line['price_unit'] = sale_order_line.price_unit - picking_line['discount'] = sale_order_line.discount - pickinglines.append(picking_line) + # Custom Section - Load Picking Part + @api.model + def _prepare_line_data_from_stock_move(self, move): + picking_line_data = { + 'name': move.name, + 'product_id': move.product_id.id, + 'quantity': move.product_uom_qty, + } + sale_order_line =\ + move.procurement_id and move.procurement_id.sale_line_id + if sale_order_line: + # Get price and discount of the order if available + picking_line_data['price_unit'] = sale_order_line.price_unit + picking_line_data['discount'] = sale_order_line.discount + return picking_line_data + + @api.model + def load_picking_for_pos(self, picking_id): + picking = self.browse(picking_id) + picking_lines = [] + for move in picking.move_lines.filtered(lambda x: x.state != 'cancel'): + picking_lines.append(self._prepare_line_data_from_stock_move(move)) return { - 'id': self.id, - 'name': self.name, - 'partner_id': self.partner_id.id, - 'line_ids': pickinglines, + 'id': picking.id, + 'name': picking.name, + 'partner_id': picking.partner_id.id, + 'line_ids': picking_lines, } @api.multi diff --git a/pos_picking_load/models/stock_picking_type.py b/pos_picking_load/models/stock_picking_type.py index dec2114f..b1fc4fb9 100644 --- a/pos_picking_load/models/stock_picking_type.py +++ b/pos_picking_load/models/stock_picking_type.py @@ -1,9 +1,9 @@ -# -*- coding: utf-8 -*- +# coding: utf-8 # 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). -from openerp import models, fields +from odoo import models, fields class StockPickingType(models.Model): diff --git a/pos_picking_load/readme/CONFIGURE.rst b/pos_picking_load/readme/CONFIGURE.rst new file mode 100644 index 00000000..cc7213d7 --- /dev/null +++ b/pos_picking_load/readme/CONFIGURE.rst @@ -0,0 +1,41 @@ +To configure this module, you need to: + +#. Go to Warehouse / Configuration / Types of Operation +#. Select the picking type(s) you want to see in the point of sale +#. Check the box 'Available in Point of Sale' + +.. figure:: ../static/description/stock_picking_type_form.png + :width: 800 px + +Note: This box is NOT enabled by default except in demo data for the type +'Delivery Orders' of the demo company 'YourCompany'. + +#. Go to Point of Sale / Configuration / Point of Sales +#. Select the Point(s) of Sales witch those you want to enable the feature +#. Check the box 'Load Pickings' +#. Set the max quantity of pickings you want to load + +.. figure:: ../static/description/pos_config_form.png + :width: 800 px + +Note: This box is enabled by default + +**Technical Notes** + +* By default, the Point of Sale will display only the pickings if the state is + in 'Waiting Availability', 'Partially Available' or 'Ready to Transfer'. + +You can change this filter by overloading the ``_prepare_filter_for_pos`` +function of the model ``stock.picking``. + +* By default, the search of pickings will be done on the fields ``name``, + ``origin`` and ``partner_id`` of the picking. + +You can change this feature by overloading the +``_prepare_filter_query_for_pos`` function of the model ``stock.picking``. + +* By default, when the PoS order is confirmed, the original picking is + cancelled and the sale order is set to the state 'Done'. + +You can change this behaviour by overloading +``_handle_orders_with_original_picking`` function of the model ``pos.order``. diff --git a/pos_picking_load/readme/CONTRIBUTORS.rst b/pos_picking_load/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..9e9913a0 --- /dev/null +++ b/pos_picking_load/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Sylvain LE GAL (https://twitter.com/legalsylvain) +* Stefan Rijnhart diff --git a/pos_picking_load/readme/DESCRIPTION.rst b/pos_picking_load/readme/DESCRIPTION.rst new file mode 100644 index 00000000..c0f9a60a --- /dev/null +++ b/pos_picking_load/readme/DESCRIPTION.rst @@ -0,0 +1,16 @@ +This module extends the functionality of point of sale to allow you to +load your pickings in the Point of Sale, in order to add / remove products +and so create a PoS Order and mark it as paid. + +**Detailled Use Case** + +This module is usefull for the following use case + +* You have many Sale Orders that have generated pickings. Typically if you have + connected your Odoo instance to an online store like Shop Invader, + Prestashop, Magento, or if you use light Odoo shop (``website_sale`` + module). +* Once the order validated, you prepare your pickings +* The customer come in your shop to recover his order +* the customer add (or remove) some products +* the customer pay his order, based on the real delivered products list diff --git a/pos_picking_load/readme/ROADMAP.rst b/pos_picking_load/readme/ROADMAP.rst new file mode 100644 index 00000000..ff5e888b --- /dev/null +++ b/pos_picking_load/readme/ROADMAP.rst @@ -0,0 +1,8 @@ +* This module will try to get original unit price from the sale order and not + use the Current unit price of the product. + (The price at which you pledged to sell the product). + Some VAT troubles will occure if a product is set with VAT marked as + 'VAT included' and if in the sale order line, there are some VAT marked as + 'VAT excluded' for exemple. + +**The VAT settings should be consistent.** diff --git a/pos_picking_load/readme/USAGE.rst b/pos_picking_load/readme/USAGE.rst new file mode 100644 index 00000000..8d89e6da --- /dev/null +++ b/pos_picking_load/readme/USAGE.rst @@ -0,0 +1,69 @@ +To use this module, you need to: + +* Launch the point of sale +* On a new order (without lines), click on the 'Load Picking' button. + +.. figure:: ../static/description/load_picking_01_load_button.png + :width: 800 px + +* Point of sale will load available pickings. (About displayed pickings, see + 'Technical Notes' section). + +.. figure:: ../static/description/load_picking_02_picking_list.png + :width: 800 px + +* Click on a picking will check if the picking is loadable and if yes, will + display a 'Select' button. (See 'Possible Warnings' Section) + +.. figure:: ../static/description/load_picking_03_confirm.png + :width: 800 px + +* Confirm the selection, by clicking on 'Select' button. It will display + the content of the moves (as PoS Order Lines) + +.. figure:: ../static/description/load_picking_04_pos_order.png + :width: 800 px + +The price and the discount will be the sale price and the discount set in +the according Sale Order Line, if it was found. Otherwise, discount will be +set to 0, and unit price will be the unit price of the product when it has been +loaded in the Point of Sale. + +**Related Sale Order:** + +.. figure:: ../static/description/load_picking_sale_order.png + :width: 800 px + +**Related Picking:** + +.. figure:: ../static/description/load_picking_stock_picking.png + :width: 800 px + + +* Finally, you can add / remove products or change quantity and collect the + payment. + +When, the order is marked as paid, the original picking will be cancelled, +because Point Of Sale generates a new picking related to the real delivered +products and the original Sale Order will pass to the state 'Done'. (Delivery +exception is ignored). +(See 'Technical Notes' section). + +**Possible Warnings** + +Some warning messages can appear: + +* if some products are not available in the Point of Sale + +.. figure:: ../static/description/load_picking_warning_product.png + :width: 800 px + +* if the partner is not available in the Point of Sale + +.. figure:: ../static/description/load_picking_warning_partner.png + :width: 800 px + +* if the picking has been still loaded in another PoS order + +.. figure:: ../static/description/load_picking_warning_picking_still_loaded.png + :width: 800 px diff --git a/pos_picking_load/static/description/index.html b/pos_picking_load/static/description/index.html new file mode 100644 index 00000000..e8d74e26 --- /dev/null +++ b/pos_picking_load/static/description/index.html @@ -0,0 +1,562 @@ + + + + + + +Point Of Sale - Picking Load + + + +
+

Point Of Sale - Picking Load

+ + +

Beta License: AGPL-3 legalsylvain/pos

+

This module extends the functionality of point of sale to allow you to +load your pickings in the Point of Sale, in order to add / remove products +and so create a PoS Order and mark it as paid.

+

Detailled Use Case

+

This module is usefull for the following use case

+
    +
  • You have many Sale Orders that have generated pickings. Typically if you have +connected your Odoo instance to an online store like Shop Invader, +Prestashop, Magento, or if you use light Odoo shop (website_sale +module).
  • +
  • Once the order validated, you prepare your pickings
  • +
  • The customer come in your shop to recover his order
  • +
  • the customer add (or remove) some products
  • +
  • the customer pay his order, based on the real delivered products list
  • +
+

Table of contents

+ +
+

Configuration

+

To configure this module, you need to:

+
    +
  1. Go to Warehouse / Configuration / Types of Operation
  2. +
  3. Select the picking type(s) you want to see in the point of sale
  4. +
  5. Check the box ‘Available in Point of Sale’
  6. +
+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/stock_picking_type_form.png +
+

Note: This box is NOT enabled by default except in demo data for the type +‘Delivery Orders’ of the demo company ‘YourCompany’.

+
    +
  1. Go to Point of Sale / Configuration / Point of Sales
  2. +
  3. Select the Point(s) of Sales witch those you want to enable the feature
  4. +
  5. Check the box ‘Load Pickings’
  6. +
  7. Set the max quantity of pickings you want to load
  8. +
+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/pos_config_form.png +
+

Note: This box is enabled by default

+

Technical Notes

+
    +
  • By default, the Point of Sale will display only the pickings if the state is +in ‘Waiting Availability’, ‘Partially Available’ or ‘Ready to Transfer’.
  • +
+

You can change this filter by overloading the _prepare_filter_for_pos +function of the model stock.picking.

+
    +
  • By default, the search of pickings will be done on the fields name, +origin and partner_id of the picking.
  • +
+

You can change this feature by overloading the +_prepare_filter_query_for_pos function of the model stock.picking.

+
    +
  • By default, when the PoS order is confirmed, the original picking is +cancelled and the sale order is set to the state ‘Done’.
  • +
+

You can change this behaviour by overloading +_handle_orders_with_original_picking function of the model pos.order.

+
+
+

Usage

+

To use this module, you need to:

+
    +
  • Launch the point of sale
  • +
  • On a new order (without lines), click on the ‘Load Picking’ button.
  • +
+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_01_load_button.png +
+
    +
  • Point of sale will load available pickings. (About displayed pickings, see +‘Technical Notes’ section).
  • +
+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_02_picking_list.png +
+
    +
  • Click on a picking will check if the picking is loadable and if yes, will +display a ‘Select’ button. (See ‘Possible Warnings’ Section)
  • +
+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_03_confirm.png +
+
    +
  • Confirm the selection, by clicking on ‘Select’ button. It will display +the content of the moves (as PoS Order Lines)
  • +
+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_04_pos_order.png +
+

The price and the discount will be the sale price and the discount set in +the according Sale Order Line, if it was found. Otherwise, discount will be +set to 0, and unit price will be the unit price of the product when it has been +loaded in the Point of Sale.

+

Related Sale Order:

+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_sale_order.png +
+

Related Picking:

+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_stock_picking.png +
+
    +
  • Finally, you can add / remove products or change quantity and collect the +payment.
  • +
+

When, the order is marked as paid, the original picking will be cancelled, +because Point Of Sale generates a new picking related to the real delivered +products and the original Sale Order will pass to the state ‘Done’. (Delivery +exception is ignored). +(See ‘Technical Notes’ section).

+

Possible Warnings

+

Some warning messages can appear:

+
    +
  • if some products are not available in the Point of Sale
  • +
+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_warning_product.png +
+
    +
  • if the partner is not available in the Point of Sale
  • +
+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_warning_partner.png +
+
    +
  • if the picking has been still loaded in another PoS order
  • +
+
+https://raw.githubusercontent.com/legalsylvain/pos/10.0-mig-pos_picking_load/pos_picking_load/static/description/load_picking_warning_picking_still_loaded.png +
+
+
+

Known issues / Roadmap

+
    +
  • This module will try to get original unit price from the sale order and not +use the Current unit price of the product. +(The price at which you pledged to sell the product). +Some VAT troubles will occure if a product is set with VAT marked as +‘VAT included’ and if in the sale order line, there are some VAT marked as +‘VAT excluded’ for exemple.
  • +
+

The VAT settings should be consistent.

+
+
+

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 smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • GRAP
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

Current maintainer:

+

legalsylvain

+

This module is part of the legalsylvain/pos project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/pos_picking_load/static/description/load_picking_01.png b/pos_picking_load/static/description/load_picking_01.png deleted file mode 100644 index fb871863..00000000 Binary files a/pos_picking_load/static/description/load_picking_01.png and /dev/null differ diff --git a/pos_picking_load/static/description/load_picking_01_load_button.png b/pos_picking_load/static/description/load_picking_01_load_button.png new file mode 100644 index 00000000..3f52aae1 Binary files /dev/null and b/pos_picking_load/static/description/load_picking_01_load_button.png differ diff --git a/pos_picking_load/static/description/load_picking_02.png b/pos_picking_load/static/description/load_picking_02.png deleted file mode 100644 index 0d1f3cb5..00000000 Binary files a/pos_picking_load/static/description/load_picking_02.png and /dev/null differ diff --git a/pos_picking_load/static/description/load_picking_02_picking_list.png b/pos_picking_load/static/description/load_picking_02_picking_list.png new file mode 100644 index 00000000..d23c63ad Binary files /dev/null and b/pos_picking_load/static/description/load_picking_02_picking_list.png differ diff --git a/pos_picking_load/static/description/load_picking_03.png b/pos_picking_load/static/description/load_picking_03.png deleted file mode 100644 index 2854d5c1..00000000 Binary files a/pos_picking_load/static/description/load_picking_03.png and /dev/null differ diff --git a/pos_picking_load/static/description/load_picking_03_confirm.png b/pos_picking_load/static/description/load_picking_03_confirm.png new file mode 100644 index 00000000..becc45ee Binary files /dev/null and b/pos_picking_load/static/description/load_picking_03_confirm.png differ diff --git a/pos_picking_load/static/description/load_picking_04.png b/pos_picking_load/static/description/load_picking_04.png deleted file mode 100644 index 5abc1c4c..00000000 Binary files a/pos_picking_load/static/description/load_picking_04.png and /dev/null differ diff --git a/pos_picking_load/static/description/load_picking_04_pos_order.png b/pos_picking_load/static/description/load_picking_04_pos_order.png new file mode 100644 index 00000000..91e07fca Binary files /dev/null and b/pos_picking_load/static/description/load_picking_04_pos_order.png differ diff --git a/pos_picking_load/static/description/load_picking_05.png b/pos_picking_load/static/description/load_picking_05.png deleted file mode 100644 index ca2f804d..00000000 Binary files a/pos_picking_load/static/description/load_picking_05.png and /dev/null differ diff --git a/pos_picking_load/static/description/load_picking_06.png b/pos_picking_load/static/description/load_picking_06.png deleted file mode 100644 index 1c5fa271..00000000 Binary files a/pos_picking_load/static/description/load_picking_06.png and /dev/null differ diff --git a/pos_picking_load/static/description/load_picking_sale_order.png b/pos_picking_load/static/description/load_picking_sale_order.png new file mode 100644 index 00000000..e019ede4 Binary files /dev/null and b/pos_picking_load/static/description/load_picking_sale_order.png differ diff --git a/pos_picking_load/static/description/load_picking_stock_picking.png b/pos_picking_load/static/description/load_picking_stock_picking.png new file mode 100644 index 00000000..808a126b Binary files /dev/null and b/pos_picking_load/static/description/load_picking_stock_picking.png differ diff --git a/pos_picking_load/static/description/load_picking_warning_partner.png b/pos_picking_load/static/description/load_picking_warning_partner.png new file mode 100644 index 00000000..61438a38 Binary files /dev/null and b/pos_picking_load/static/description/load_picking_warning_partner.png differ diff --git a/pos_picking_load/static/description/load_picking_warning_picking_still_loaded.png b/pos_picking_load/static/description/load_picking_warning_picking_still_loaded.png new file mode 100644 index 00000000..1a0118c0 Binary files /dev/null and b/pos_picking_load/static/description/load_picking_warning_picking_still_loaded.png differ diff --git a/pos_picking_load/static/description/load_picking_warning_product.png b/pos_picking_load/static/description/load_picking_warning_product.png new file mode 100644 index 00000000..3084d105 Binary files /dev/null and b/pos_picking_load/static/description/load_picking_warning_product.png differ diff --git a/pos_picking_load/static/description/pos_config_form.png b/pos_picking_load/static/description/pos_config_form.png index 1e58647a..27052b91 100644 Binary files a/pos_picking_load/static/description/pos_config_form.png and b/pos_picking_load/static/description/pos_config_form.png differ diff --git a/pos_picking_load/static/src/css/pos_picking_load.css b/pos_picking_load/static/src/css/pos_picking_load.css index 4845475a..afa6e7e5 100644 --- a/pos_picking_load/static/src/css/pos_picking_load.css +++ b/pos_picking_load/static/src/css/pos_picking_load.css @@ -1,11 +1,24 @@ + +/* LoadPickingScreenWidget - Header Part*/ .pos .pickinglist-screen .button.picking-button { width: 150px; } -.pos .pickinglist-screen .button.cancel { - margin-left: -180px; +.pos .pickinglist-screen .searchbox{ + top: 4px; + position: relative; +} + +.pos .pickinglist-screen .searchbox input{ + width: 300px; } +.pos .pickinglist-screen .button.validate.picking-button{ + right: 0px; +} + +/* LoadPickingScreenWidget - List Part*/ + .pos .pickinglist-screen .picking-list{ font-size: 16px; width: 100%; @@ -27,14 +40,11 @@ background: rgb(247,247,247); } -.pos .pickinglist-screen .picking-list tbody > tr:hover { - background: rgb(220,220,220); -} - -.pos .pickinglist-screen .searchbox{ - margin-top:8px; +.pos .pickinglist-screen .picking-list .highlight { + background-color: rgb(110, 200, 155) !important; + color: rgb(255, 255, 255); } -.pos .pickinglist-screen .searchbox input{ - width: 150px; +.pos .pickinglist-screen .picking-list tbody > tr:hover { + background: rgb(220,220,220); } diff --git a/pos_picking_load/static/src/js/model.js b/pos_picking_load/static/src/js/model.js new file mode 100644 index 00000000..228b98df --- /dev/null +++ b/pos_picking_load/static/src/js/model.js @@ -0,0 +1,77 @@ +/** *************************************************************************** + 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). +******************************************************************************/ + +odoo.define('pos_picking_load.model', function (require) { + "use strict"; + + var models = require('point_of_sale.models'); + + /** ********************************************************************** + Extend Model Order: + * Add getter and setter function for field 'origin_picking_id'; + */ + + var moduleOrderParent = models.Order; + models.Order = models.Order.extend({ + + load_from_picking_data: function (picking_data) { + var self = this; + + var partner = this.pos.db.get_partner_by_id( + picking_data.partner_id); + + this.set({ + 'origin_picking_id': picking_data.id, + 'origin_picking_name': picking_data.name, + }); + this.set_client(partner); + + picking_data.line_ids.forEach(function (picking_line_data) { + // Create new line and add it to the current order + var product = self.pos.db.get_product_by_id( + picking_line_data.product_id); + var order_line_data = + self.prepare_order_line_from_picking_line_data( + product, picking_line_data); + self.add_product(product, order_line_data); + }); + }, + + prepare_order_line_from_picking_line_data: function ( + product, picking_line_data) { + return { + quantity: picking_line_data.quantity, + price: picking_line_data.price_unit || product.price, + discount: picking_line_data.discount || 0.0, + }; + }, + + export_for_printing: function () { + var order = moduleOrderParent.prototype.export_for_printing.apply( + this, arguments); + order.origin_picking_name = this.get('origin_picking_name'); + return order; + }, + + export_as_JSON: function () { + var order = moduleOrderParent.prototype.export_as_JSON.apply( + this, arguments); + order.origin_picking_id = this.get('origin_picking_id'); + order.origin_picking_name = this.get('origin_picking_name'); + return order; + }, + + init_from_JSON: function (json) { + moduleOrderParent.prototype.init_from_JSON.apply(this, arguments); + this.set({ + 'origin_picking_id': json.origin_picking_id, + 'origin_picking_name': json.origin_picking_name, + }); + }, + + }); + +}); diff --git a/pos_picking_load/static/src/js/pos_picking_load.js b/pos_picking_load/static/src/js/pos_picking_load.js deleted file mode 100644 index 09762d7e..00000000 --- a/pos_picking_load/static/src/js/pos_picking_load.js +++ /dev/null @@ -1,329 +0,0 @@ -/****************************************************************************** - 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_picking_load = function(instance, local) { - - - module = instance.point_of_sale; - var QWeb = instance.web.qweb; - var _t = instance.web._t; - var round_pr = instance.web.round_precision; - - /************************************************************************* - Extend Model Order: - * Add getter and setter function for field 'origin_picking_id'; - */ - var moduleOrderParent = module.Order; - module.Order = module.Order.extend({ - - set_origin_picking_id: function(id) { - this.set({ - origin_picking_id: id, - }); - }, - - set_origin_picking_name: function(name) { - this.set({ - origin_picking_name: name, - }); - }, - - export_for_printing: function(attributes){ - var order = moduleOrderParent.prototype.export_for_printing.apply(this, arguments); - order['origin_picking_name'] = this.get('origin_picking_name'); - return order; - }, - - export_as_JSON: function() { - var order = moduleOrderParent.prototype.export_as_JSON.apply(this, arguments); - order['origin_picking_id'] = this.get('origin_picking_id'); - return order; - }, - - }); - - - /************************************************************************* - New Widget LoadPickingButtonWidget: - * On click, display a new screen to select a picking; - */ - module.LoadPickingButtonWidget = module.PosBaseWidget.extend({ - template: 'LoadPickingButtonWidget', - - renderElement: function() { - var self = this; - this._super(); - this.$el.click(function(){ - var ss = self.pos.pos_widget.screen_selector; - ss.set_current_screen('pickinglist'); - }); - }, - }); - - - /************************************************************************* - Extend PosWidget: - * Create new screen; - * Add load and save button; - */ - module.PosWidget = module.PosWidget.extend({ - build_widgets: function() { - this._super(); - - if (this.pos.config.iface_load_picking){ - // New Screen to select a picking - this.pickinglist_screen = new module.PickingListScreenWidget(this, {}); - this.pickinglist_screen.appendTo(this.$('.screens')); - this.pickinglist_screen.hide(); - this.screen_selector.screen_set.pickinglist = this.pickinglist_screen; - - // Add button - this.search_picking_button = new module.LoadPickingButtonWidget(this,{}); - this.search_picking_button.appendTo(this.pos_widget.$('li.orderline.empty')); - } - }, - }); - - - /************************************************************************* - Extend OrderWidget: - */ - module.OrderWidget = module.OrderWidget.extend({ - renderElement: function(scrollbottom){ - this._super(scrollbottom); - if (this.pos_widget.search_picking_button) { - this.pos_widget.search_picking_button.appendTo( - this.pos_widget.$('li.orderline.empty') - ); - } - } - }); - - - /************************************************************************* - New ScreenWidget PickingListScreenWidget: - * On show, display all pickings; - * on click on a picking, display the content; - * on click on 'validate', allow to use this picking; - * on click on 'cancel', display the preview screen; - */ - module.PickingListScreenWidget = module.ScreenWidget.extend({ - template: 'PickingListScreenWidget', - show_leftpane: true, - model: 'stock.picking', - current_picking_id: false, - current_picking_name: false, - - // Base functions - init: function(parent, options){ - this._super(parent, options); - }, - - start: function() { - var self = this; - this._super(); - - // Bind click buttons - this.$el.find('span.button.cancel').click(_.bind(this.clickCancelButton, this)); - this.$el.find('span.button.validate').click(_.bind(this.clickValidateButton, this)); - - // manage Search Box - var search_timeout = null; - this.$('.searchbox input').on('keyup',function(event){ - clearTimeout(search_timeout); - var query = this.value; - search_timeout = setTimeout(function(){ - self.perform_search(query); - },70); - }); - - this.$('.searchbox .search-clear').click(function(){ - self.clear_search(); - }); - }, - - show: function() { - this._super(); - var ss = this.pos.pos_widget.screen_selector; - this.pos_widget.numpad.hide(); - this.pos_widget.paypad.hide(); - this.search_pickings(); - this.$el.find('span.button.validate').hide(); - }, - - prepare_order: function(order, picking) { - var partner = this.pos.db.get_partner_by_id(picking.partner_id); - order.set_client(partner || undefined); - return order; - }, - - prepare_orderline: function(product, pickingline) { - return { - quantity: pickingline.quantity, - price: pickingline.price_unit || product.price, - discount: pickingline.discount || 0.0, - }; - }, - - // User Event - clickCancelButton: function(event) { - order = this.pos.get('selectedOrder'); - order.set_client(undefined); - order.set_origin_picking_id(undefined); - order.set_origin_picking_name(undefined); - order.get('orderLines').reset(); - this.pos_widget.order_widget.change_selected_order(); - var ss = this.pos.pos_widget.screen_selector; - ss.set_current_screen('products'); - this.pos_widget.numpad.show(); - this.pos_widget.paypad.show(); - }, - - clickValidateButton: function(event) { - order = this.pos.get('selectedOrder'); - order.set_origin_picking_id(this.current_picking_id); - order.set_origin_picking_name(this.current_picking_name); - var ss = this.pos.pos_widget.screen_selector; - ss.set_current_screen('products'); - this.pos_widget.numpad.show(); - this.pos_widget.paypad.show(); - }, - - load_picking: function(origin_picking_id) { - var self = this; - var pickingModel = new instance.web.Model(this.model); - return pickingModel.call('load_picking_for_pos', [[origin_picking_id]]) - .then(function (picking) { - self.current_picking_id = origin_picking_id; - self.current_picking_name = picking.name; - var picking_selectable = true; - var order = self.pos.get('selectedOrder'); - order = self.prepare_order(order, picking); - order.get('orderLines').reset(); - var pickinglines = picking.line_ids || []; - var unknown_products = []; - for (var i=0, len=pickinglines.length; i 0){ - self.pos_widget.screen_selector.show_popup( - 'error-traceback', { - message: _t('Unknown Products'), - comment: _t('Unable to load some picking lines because the ' + - 'products are not available in the POS cache.\n\n' + - 'Please check that lines :\n\n * ') + unknown_products.join("; \n *") - }); - picking_selectable = false; - } - // Check if the partner is unknown - if (_.isUndefined(order.get_client)) { - self.pos_widget.screen_selector.show_popup( - 'error-traceback', { - message: _t('Unknown Partner'), - comment: _t('Unable to load this picking because the partner' + - ' is not known in the Point Of Sale as a customer') - }); - picking_selectable = false; - } - - if (picking_selectable){ - self.$el.find('span.button.validate').show(); - } - else{ - self.$el.find('span.button.validate').hide(); - } - - }).fail(function (error, event){ - if (parseInt(error.code) === 200) { - // Business Logic Error, not a connection problem - self.pos_widget.screen_selector.show_popup( - 'error-traceback', { - message: error.data.message, - comment: error.data.debug - }); - } - else{ - self.pos_widget.screen_selector.show_popup('error',{ - message: _t('Connection error'), - comment: _t('Can not execute this action because the POS is currently offline'), - }); - } - event.preventDefault(); - }); - }, - - search_pickings: function(query) { - var self = this; - var pickingModel = new instance.web.Model(this.model); - return pickingModel.call('search_pickings_for_pos', [query || '', this.pos.pos_session.id]) - .then(function (result) { - self.render_list(result); - }).fail(function (error, event){ - if (parseInt(error.code) === 200) { - // Business Logic Error, not a connection problem - self.pos_widget.screen_selector.show_popup( - 'error-traceback', { - message: error.data.message, - comment: error.data.debug - } - ); - } - else{ - self.pos_widget.screen_selector.show_popup('error',{ - message: _t('Connection error'), - comment: _t('Can not execute this action because the POS is currently offline'), - }); - } - event.preventDefault(); - }); - }, - - on_click_picking: function(event){ - this.load_picking(parseInt(event.target.parentNode.dataset.pickingId, 10)); - }, - - render_list: function(pickings){ - var self = this; - var contents = this.$el[0].querySelector('.picking-list-contents'); - contents.innerHTML = ""; - var line_list = document.createDocumentFragment(); - _.each(pickings, function(picking){ - var picking_line_html = QWeb.render('LoadPickingLine',{widget: this, picking:picking}); - var picking_line = document.createElement('tbody'); - picking_line.innerHTML = picking_line_html; - picking_line = picking_line.childNodes[1]; - picking_line.addEventListener('click', self.on_click_picking); - line_list.appendChild(picking_line); - }); - contents.appendChild(line_list); - }, - - perform_search: function(query){ - this.search_pickings(query); - }, - - clear_search: function(){ - this.search_pickings(); - this.$('.searchbox input')[0].value = ''; - this.$('.searchbox input').focus(); - }, - - }); - -}; diff --git a/pos_picking_load/static/src/js/widget.js b/pos_picking_load/static/src/js/widget.js new file mode 100644 index 00000000..87627e50 --- /dev/null +++ b/pos_picking_load/static/src/js/widget.js @@ -0,0 +1,289 @@ +/** *************************************************************************** + 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). +******************************************************************************/ + +odoo.define('pos_picking_load.widget', function (require) { + "use strict"; + + var core = require('web.core'); + var framework = require('web.framework'); + var Model = require('web.DataModel'); + + var gui = require('point_of_sale.gui'); + var screens = require('point_of_sale.screens'); + + var QWeb = core.qweb; + var _t = core._t; + + + /** ********************************************************************** + New ScreenWidget LoadPickingScreenWidget: + * On show, display all pickings; + * on click on a picking, display the content; + * on click on 'validate', allow to use this picking; + * on click on 'cancel', display the preview screen; + */ + var LoadPickingScreenWidget = screens.ScreenWidget.extend({ + template: 'LoadPickingScreenWidget', + auto_back: true, + + current_picking_id: false, + current_picking_name: false, + + show: function () { + var self = this; + this._super(); + + this.renderElement(); + + // Bind functions + this.$('.back').click(_.bind(this.clickBackButton, this)); + this.$('.validate').click(_.bind(this.clickValidateButton, this)); + + // Initialize display + this.$('.validate').hide(); + + this.search_pickings(); + + this.$('.picking-list-contents').delegate( + '.picking-line', 'click', function (event) { + self.select_picking(event); + }); + + }, + + select_picking: function (event) { + var origin_picking_id = parseInt( + event.target.parentNode.dataset.pickingId, 10); + var self = this; + this.current_picking_data = false; + this.$('span.button.validate').hide(); + this.$('.picking-list .highlight').removeClass('highlight'); + + framework.blockUI(); + new Model('stock.picking').call( + 'load_picking_for_pos', [origin_picking_id]) + .then(function (picking_data) { + framework.unblockUI(); + if (self.check_picking(picking_data)) { + self.current_picking_data = picking_data; + $(event.target.parentNode).addClass('highlight'); + self.$('span.button.validate').show(); + } + }).fail(function (error, event) { + framework.unblockUI(); + self.handle_errors(error, event); + }); + }, + + check_picking: function (picking_data) { + var self = this; + + var picking_selectable = true; + + // Forbid POS Order loading if some products are unknown + var unknown_products = []; + + picking_data.line_ids.forEach(function (picking_line_data) { + var line_name = picking_line_data.name.replace('\n', ' '); + var product = self.pos.db.get_product_by_id( + picking_line_data.product_id); + if (_.isUndefined(product)) { + unknown_products.push(line_name); + } + }); + if (unknown_products.length > 0) { + self.gui.show_popup( + 'error-traceback', { + 'title': _t('Unknown Products'), + 'body': _t( + "Unable to load some picking lines because the" + + " products are not available in the POS" + + " cache.\n\n" + + "Please check that lines :\n\n * ") + + unknown_products.join("; \n *"), + }); + picking_selectable = false; + } + + // Check if the partner is unknown + var partner = self.pos.db.get_partner_by_id( + picking_data.partner_id); + + if (_.isUndefined(partner)) { + self.gui.show_popup( + 'error-traceback', { + 'title': _t('Unknown Partner'), + 'body': _t( + "Unable to load this picking because the partner" + + " is not known in the Point Of Sale" + + " as a customer"), + }); + picking_selectable = false; + } + + // Check if the picking is still loaded in another PoS tab + self.pos.db.get_unpaid_orders().forEach(function (order) { + if (order.origin_picking_id === picking_data.id) { + self.gui.show_popup( + 'error-traceback', { + 'title': _t('Picking Still Loaded'), + 'body': _t( + "Unable to load this picking because it has" + + " been loaded in another draft" + + " PoS Order :\n\n") + + order.name, + }); + picking_selectable = false; + } + }); + + // Check if the picking has still been handled in another PoS Order + self.pos.db.get_orders().forEach(function (order) { + if (order.origin_picking_id === picking_data.id) { + self.gui.show_popup( + 'error-traceback', { + 'title': _t('Picking Still Loaded'), + 'body': _t( + "Unable to load this picking because it has" + + " been loaded in another confirmed" + + " PoS Order :\n\n") + + order.name, + }); + picking_selectable = false; + } + }); + return picking_selectable; + }, + + search_pickings: function (query) { + var self = this; + return new Model('stock.picking').call( + 'search_pickings_for_pos', + [query || '', this.pos.pos_session.id]) + .then(function (result) { + self.render_list(result); + }).fail(function (error, event) { + self.handle_errors(error, event); + }); + }, + + render_list: function (pickings) { + var contents = this.$el[0].querySelector('.picking-list-contents'); + contents.innerHTML = ""; + var line_list = document.createDocumentFragment(); + _.each(pickings, function (picking) { + var picking_line_html = QWeb.render( + 'LoadPickingLine', {widget: this, picking:picking}); + var picking_line = document.createElement('tbody'); + picking_line.innerHTML = picking_line_html; + picking_line = picking_line.childNodes[1]; + line_list.appendChild(picking_line); + }); + contents.appendChild(line_list); + }, + + // User Event + clickBackButton: function () { + this.gui.back(); + }, + + clickValidateButton: function () { + var order = this.pos.get_order(); + order.load_from_picking_data(this.current_picking_data); + this.gui.show_screen('products'); + }, + + handle_errors: function (error, event) { + var self = this; + if (parseInt(error.code, 10) === 200) { + // Business Logic Error, not a connection problem + self.gui.show_popup('error-traceback', { + 'title': error.data.message || _t("Server Error"), + 'body': error.data.debug || _t( + "The server encountered an error while" + + " receiving your order."), + }); + } else { + self.gui.show_popup('error', { + 'title': _t('Connection error'), + 'body': _t( + "Can not execute this action because the POS" + + " is currently offline"), + }); + } + event.preventDefault(); + }, + }); + + gui.define_screen({ + 'name': 'load_picking', + 'widget': LoadPickingScreenWidget, + 'condition': function () { + return this.pos.config.iface_load_picking; + }, + }); + + + /** ********************************************************************** + New Widget LoadPickingButtonWidget: + * On click, display a new screen to select a picking; + */ + var LoadPickingButtonWidget = screens.ActionButtonWidget.extend({ + template: 'LoadPickingButtonWidget', + + button_click: function () { + if (_.isUndefined(this.pos.get_order().get('origin_picking_id'))) { + this.gui.show_screen('load_picking'); + } else { + this.gui.show_popup('error', { + 'title': _t('Pending Picking'), + 'body': _t( + "A picking is still loaded. You can not load" + + " another picking. Please create a new order."), + }); + } + }, + + button_text: function () { + if (! this.pos.get_order() || + _.isUndefined( + this.pos.get_order().get('origin_picking_id'))) { + return _t("Load Picking"); + } + return this.pos.get_order().get('origin_picking_name'); + }, + + is_visible: function () { + if (this.pos.get_order()) { + return ( + this.pos.get_order().get_orderlines().length === 0 || + ! _.isUndefined( + this.pos.get_order().get('origin_picking_id'))); + } + return false; + }, + + }); + + screens.define_action_button({ + 'name': 'load_picking', + 'widget': LoadPickingButtonWidget, + 'condition': function () { + return this.pos.config.iface_load_picking; + }, + }); + + screens.OrderWidget.include({ + update_summary: function () { + this._super(); + if (this.getParent().action_buttons && + this.getParent().action_buttons.load_picking) { + this.getParent().action_buttons.load_picking.renderElement(); + } + }, + }); + +}); diff --git a/pos_picking_load/static/src/xml/pos_picking_load.xml b/pos_picking_load/static/src/xml/pos_picking_load.xml index 93910a28..822bccd7 100644 --- a/pos_picking_load/static/src/xml/pos_picking_load.xml +++ b/pos_picking_load/static/src/xml/pos_picking_load.xml @@ -2,35 +2,38 @@