Browse Source

Merge PR #337 into 12.0

Signed-off-by legalsylvain
pull/378/head
OCA-git-bot 5 years ago
parent
commit
9f4f4689e6
  1. 128
      pos_order_mgmt/README.rst
  2. 1
      pos_order_mgmt/__init__.py
  3. 28
      pos_order_mgmt/__manifest__.py
  4. 172
      pos_order_mgmt/i18n/es.po
  5. 249
      pos_order_mgmt/i18n/fr.po
  6. 244
      pos_order_mgmt/i18n/pos_order_mgmt.pot
  7. 2
      pos_order_mgmt/models/__init__.py
  8. 38
      pos_order_mgmt/models/pos_config.py
  9. 160
      pos_order_mgmt/models/pos_order.py
  10. 12
      pos_order_mgmt/readme/CONFIGURE.rst
  11. 5
      pos_order_mgmt/readme/CONTRIBUTORS.rst
  12. 3
      pos_order_mgmt/readme/DESCRIPTION.rst
  13. 5
      pos_order_mgmt/readme/ROADMAP.rst
  14. 19
      pos_order_mgmt/readme/USAGE.rst
  15. BIN
      pos_order_mgmt/static/description/icon.png
  16. 474
      pos_order_mgmt/static/description/index.html
  17. BIN
      pos_order_mgmt/static/description/order-mgmt-icon.png
  18. BIN
      pos_order_mgmt/static/description/order-mgmt-list.png
  19. 35
      pos_order_mgmt/static/src/css/pos.css
  20. 30
      pos_order_mgmt/static/src/js/models.js
  21. 464
      pos_order_mgmt/static/src/js/widgets.js
  22. 104
      pos_order_mgmt/static/src/xml/pos.xml
  23. 1
      pos_order_mgmt/tests/__init__.py
  24. 80
      pos_order_mgmt/tests/test_module.py
  25. 13
      pos_order_mgmt/views/assets.xml
  26. 63
      pos_order_mgmt/views/view_pos_config.xml
  27. 22
      pos_order_mgmt/views/view_pos_order.xml
  28. 2
      setup/_metapackage/VERSION.txt
  29. 1
      setup/_metapackage/setup.py
  30. 1
      setup/pos_order_mgmt/odoo/addons/pos_order_mgmt
  31. 6
      setup/pos_order_mgmt/setup.py

128
pos_order_mgmt/README.rst

@ -0,0 +1,128 @@
==============================
POS Frontend Orders Management
==============================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! 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-OCA%2Fpos-lightgray.png?logo=github
:target: https://github.com/OCA/pos/tree/12.0/pos_order_mgmt
:alt: OCA/pos
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/pos-12-0/pos-12-0-pos_order_mgmt
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/184/12.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module extends the functionality of the PoS frontend allowing to load
already done PoS Orders in order to be able to operate over them, being able to
reprint past tickets or return them.
**Table of contents**
.. contents::
:local:
Configuration
=============
To configure this module, you need to:
#. Go to *Point of Sale > Configuration > Point of Sale* and select one of
them.
#. Change *Max Done Orders Quantity To Load* to your desired amount (10 by
default). Please note that the more you load, the more it will take to load
them in the session opening. You can also set it to 0 and you'll just be
able to load them from the order list screen.
#. Set *Reprint Done Orders* on if you want to be able to reprint past orders
in that PoS.
#. Set *Return Done Orders* on if you want to be able to return past orders
in that PoS.
Usage
=====
Once the PoS is loaded, you'll find a shopping trolley icon (🛒) in the top
bar that grants access to the order list screen.
.. image:: https://raw.githubusercontent.com/OCA/pos/12.0/pos_order_mgmt/static/description/order-mgmt-icon.png
There you can find the number of past orders loaded according to your
configuration (see Configuration) as well as the orders you checked out in
the current session:
.. image:: https://raw.githubusercontent.com/OCA/pos/12.0/pos_order_mgmt/static/description/order-mgmt-list.png
#. You can see their totals as well as their custumers if registered.
#. You can reprint their tickets clicking on the printer icon (⎙).
#. You can return them pressing on the arrow icon (↶).
#. You have a search input as well that lets you find past tickets by its
reference number.
NOTE: You'll need your PoS to be online to be able to search or return a past
ticket.
Known issues / Roadmap
======================
* It's possible to return the same order over and over. To avoid so, we should
load and control if there's a returned line id associated with the original
order. That would be a great improvement for future revisions.
This feature is implemented in the module ``pos_order_return`` in the back
office part, but not in front office part (implemented in this this module).
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pos/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 <https://github.com/OCA/pos/issues/new?body=module:%20pos_order_mgmt%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* GRAP
* Tecnativa
Contributors
~~~~~~~~~~~~
* David Vidal <david.vidal@tecnativa.com>
* Sylvain LE GAL (https://twitter.com/legalsylvain)
* Carlos Martínez <carlos@domatix.com>
* Pierrick Brun <pierrick.brun@akretion.com>
* Iván Todorovich <ivan.todorovich@druidoo.io>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
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.
This module is part of the `OCA/pos <https://github.com/OCA/pos/tree/12.0/pos_order_mgmt>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

1
pos_order_mgmt/__init__.py

@ -0,0 +1 @@
from . import models

28
pos_order_mgmt/__manifest__.py

@ -0,0 +1,28 @@
# Copyright 2018 GRAP - Sylvain LE GAL
# Copyright 2018 Tecnativa S.L. - David Vidal
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': 'POS Frontend Orders Management',
'summary': 'Manage old POS Orders from the frontend',
'version': '12.0.1.0.1',
'category': 'Point of Sale',
'author': 'GRAP, '
'Tecnativa, '
'Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/pos',
'license': 'AGPL-3',
'depends': [
'point_of_sale',
],
'data': [
'views/assets.xml',
'views/view_pos_config.xml',
'views/view_pos_order.xml',
],
'qweb': [
'static/src/xml/pos.xml'
],
'application': False,
'installable': True,
}

172
pos_order_mgmt/i18n/es.po

@ -0,0 +1,172 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_order_mgmt
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-18 11:15+0000\n"
"PO-Revision-Date: 2019-03-01 15:53+0000\n"
"Last-Translator: Marta Vázquez Rodríguez <vazrodmar@gmail.com>\n"
"Language-Team: \n"
"Language: es\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"
"X-Generator: Weblate 3.4\n"
#. module: pos_order_mgmt
#: model:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to load done orders in this POS"
msgstr "Permitir cargar pedidos en este PdV"
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config_iface_load_done_order
msgid ""
"Allows to load already done orders in the frontend to operate over them, "
"allowing reprint the tickets, return items, etc."
msgstr ""
"Permite cargar pedidos ya realizados desde el PdV para operar sobre ellos: "
"reimprimir tickes, devoluciónes, etc."
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:36
#, python-format
msgid "Amount Total"
msgstr "Importe Total"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:17
#, python-format
msgid "Back"
msgstr "Volver"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:303
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:331
#, python-format
msgid "Can not execute this action because the POS is currently offline"
msgstr ""
"No se puede ejecutar esta acción porque el PdV está sin línea en este momento"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:302
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:330
#, python-format
msgid "Connection error"
msgstr "Error de conexión"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:34
#, python-format
msgid "Customer"
msgstr "Cliente"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:35
#, python-format
msgid "Date"
msgstr "Fecha"
#. module: pos_order_mgmt
#: model:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Load Done Order Max Qty."
msgstr "Nº Máximo de Ventas a Cargar."
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config_iface_load_done_order
#: model:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Load Done Orders"
msgstr "Cargar Ventas Realizadas"
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config_iface_load_done_order_max_qty
msgid "Max. Done Orders Quantity To Load"
msgstr "Nº Máximo de Ventas Realizadas a Cargar"
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config_iface_load_done_order_max_qty
msgid ""
"Maximum number of orders to load on the PoS at its init. Set it to 0 to load "
"none (it's still posible to load them by ticket code)."
msgstr ""
"Número máximo de ventas a cargar en el PdV cuando este se inicia. "
"Establézcalo a 0 para no cargar ninguna (es posible cargarlas por referencia "
"del ticket)."
#. module: pos_order_mgmt
#: model:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Maximum number orders to load"
msgstr "Ventas máximas a cargar"
#. module: pos_order_mgmt
#: model:ir.model,name:pos_order_mgmt.model_pos_order
msgid "Point of Sale Orders"
msgstr "Ventas del Punto de Venta"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:80
#, python-format
msgid "Rectifies:"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:33
#, python-format
msgid "Ref."
msgstr "'Ref.'"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:71
#, python-format
msgid "Returned order:"
msgstr "Devolución de venta:"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:21
#, python-format
msgid "Search Order"
msgstr "Buscar Venta"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:280
#, python-format
msgid ""
"Unable to load some order lines because the products are not available in "
"the POS cache.\n"
"\n"
"Please check that lines :\n"
"\n"
" * "
msgstr ""
"No fue posible cargar algunas líneas porque los pedidos no están disponibles "
"en la caché del PdV.\n"
"\n"
"Por favor, compruebe estas líneas :\n"
"\n"
" * "
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:279
#, python-format
msgid "Unknown Products"
msgstr "Productos desconocidos"
#. module: pos_order_mgmt
#: model:ir.model,name:pos_order_mgmt.model_pos_config
msgid "pos.config"
msgstr "'pos.config'"

249
pos_order_mgmt/i18n/fr.po

@ -0,0 +1,249 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_order_mgmt
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-07-15 20:54+0000\n"
"PO-Revision-Date: 2019-07-15 20:54+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: \n"
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to duplicate done orders in this POS"
msgstr "Autoriser à dupliquer des commandes réalisées dans l'interface tactile"
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to reprint done orders in this POS"
msgstr "Autoriser à réimprimer des commandes réalisées dans l'interface tactile"
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to return done orders in this POS"
msgstr "Autoriser à rembourser des commandes réalisées dans l'interface tactile"
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_copy_done_order
msgid "Allows to duplicate already done orders in the frontend"
msgstr "Autoriser à dupliquer des commandes réalisées dans l'interface tactile"
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_reprint_done_order
msgid "Allows to reprint already done orders in the frontend"
msgstr "Autoriser à réimprimer des commandes réalisées dans l'interface tactile"
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_return_done_order
msgid "Allows to return already done orders in the frontend"
msgstr "Autoriser à rembourser des commandes réalisées dans l'interface tactile"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:36
#, python-format
msgid "Amount Total"
msgstr "Total"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:17
#, python-format
msgid "Back"
msgstr "Retour"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:341
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:396
#, python-format
msgid "Can not execute this action because the POS is currently offline"
msgstr "Vous ne pouvez pas exécuter cette action, car le Point de Vente est actuellement hors ligne"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:340
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:395
#, python-format
msgid "Connection error"
msgstr "Erreur de connexion"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:61
#, python-format
msgid "Create a new order based on this one"
msgstr "Créer une nouvelle commande basée sur celle-ci"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:64
#, python-format
msgid "Create a refund order of this order"
msgstr "Rembourser cette commande"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:34
#, python-format
msgid "Customer"
msgstr "Client"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:89
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:98
#, python-format
msgid "DUPLICATE"
msgstr "DUPLICATA"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:35
#, python-format
msgid "Date"
msgstr "Date"
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_copy_done_order
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Duplicate Done Orders"
msgstr "Copier une commande réalisées"
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Load Done Order Max Qty."
msgstr "Quantité maximale de commandes à charger"
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_load_done_order_max_qty
msgid "Max. Done Orders Quantity To Load"
msgstr "Quantité maximale de commandes à charger"
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_load_done_order_max_qty
msgid "Maximum number of orders to load on the PoS at its init. Set it to 0 to load none (it's still possible to load them by ticket code)."
msgstr ""
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Maximum number orders to load"
msgstr "Nombre maximum de commande à charger"
#. module: pos_order_mgmt
#: model:ir.model,name:pos_order_mgmt.model_pos_config
msgid "Point of Sale Configuration"
msgstr "Paramétrage du point de vente"
#. module: pos_order_mgmt
#: model:ir.model,name:pos_order_mgmt.model_pos_order
msgid "Point of Sale Orders"
msgstr "Commandes du point de vente"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:58
#, python-format
msgid "Print a duplicate for this order"
msgstr "Imprimer un duplicata de cette commande"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:83
#, python-format
msgid "Rectifies:"
msgstr "Rectifie : "
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:33
#, python-format
msgid "Ref."
msgstr "Réf."
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__returned_order_reference
msgid "Reference of the returned Order"
msgstr "Réference de la vente retournée"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:242
#, python-format
msgid "Refund "
msgstr "Rembourse "
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__refund_order_ids
msgid "Refund Orders"
msgstr "Commandes remboursées"
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__refund_order_qty
msgid "Refund Orders Quantity"
msgstr "Nombre de remboursement"
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_order_form
msgid "Refunds"
msgstr "Remboursements"
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_reprint_done_order
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Reprint Done Orders"
msgstr "Réimprimer le ticket d'une commande réalisée"
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_return_done_order
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Return Done Orders"
msgstr "Retourner une commande réalisée"
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__returned_order_id
msgid "Returned Order"
msgstr "Commande retournée"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:74
#, python-format
msgid "Returned order:"
msgstr "Commande retournée:"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:21
#, python-format
msgid "Search Order"
msgstr "Recherche une commande"
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:358
#, python-format
msgid "Unable to load some order 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 de ticket car les produits ne sont pas disponible dans le point de vente\n"
"Veuillez vérifier les lignes suivantes : \n"
"\n"
" * "
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:357
#, python-format
msgid "Unknown Products"
msgstr "Produit inconnu"

244
pos_order_mgmt/i18n/pos_order_mgmt.pot

@ -0,0 +1,244 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_order_mgmt
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \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: \n"
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to duplicate done orders in this POS"
msgstr ""
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to reprint done orders in this POS"
msgstr ""
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to return done orders in this POS"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_copy_done_order
msgid "Allows to duplicate already done orders in the frontend"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_reprint_done_order
msgid "Allows to reprint already done orders in the frontend"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_return_done_order
msgid "Allows to return already done orders in the frontend"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:36
#, python-format
msgid "Amount Total"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:17
#, python-format
msgid "Back"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:341
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:396
#, python-format
msgid "Can not execute this action because the POS is currently offline"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:340
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:395
#, python-format
msgid "Connection error"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:61
#, python-format
msgid "Create a new order based on this one"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:64
#, python-format
msgid "Create a refund order of this order"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:34
#, python-format
msgid "Customer"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:89
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:98
#, python-format
msgid "DUPLICATE"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:35
#, python-format
msgid "Date"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_copy_done_order
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Duplicate Done Orders"
msgstr ""
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Load Done Order Max Qty."
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_load_done_order_max_qty
msgid "Max. Done Orders Quantity To Load"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_load_done_order_max_qty
msgid "Maximum number of orders to load on the PoS at its init. Set it to 0 to load none (it's still possible to load them by ticket code)."
msgstr ""
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Maximum number orders to load"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model,name:pos_order_mgmt.model_pos_config
msgid "Point of Sale Configuration"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model,name:pos_order_mgmt.model_pos_order
msgid "Point of Sale Orders"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:58
#, python-format
msgid "Print a duplicate for this order"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:83
#, python-format
msgid "Rectifies:"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:33
#, python-format
msgid "Ref."
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__returned_order_reference
msgid "Reference of the returned Order"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:242
#, python-format
msgid "Refund "
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__refund_order_ids
msgid "Refund Orders"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__refund_order_qty
msgid "Refund Orders Quantity"
msgstr ""
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_order_form
msgid "Refunds"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_reprint_done_order
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Reprint Done Orders"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_return_done_order
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Return Done Orders"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__returned_order_id
msgid "Returned Order"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:74
#, python-format
msgid "Returned order:"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:21
#, python-format
msgid "Search Order"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:358
#, python-format
msgid "Unable to load some order lines because the products are not available in the POS cache.\n"
"\n"
"Please check that lines :\n"
"\n"
" * "
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:357
#, python-format
msgid "Unknown Products"
msgstr ""

2
pos_order_mgmt/models/__init__.py

@ -0,0 +1,2 @@
from . import pos_config
from . import pos_order

38
pos_order_mgmt/models/pos_config.py

@ -0,0 +1,38 @@
# Copyright 2018 GRAP - Sylvain LE GAL
# Copyright 2018 Tecnativa S.L. - David Vidal
# Copyright 2019 Coop IT Easy SCRLfs
# Pierrick Brun <pierrick.brun@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class PosConfig(models.Model):
_inherit = 'pos.config'
iface_reprint_done_order = fields.Boolean(
string='Reprint Done Orders',
default=True,
help='Allows to reprint already done orders in the frontend',
)
iface_return_done_order = fields.Boolean(
string='Return Done Orders',
default=True,
help='Allows to return already done orders in the frontend',
)
iface_copy_done_order = fields.Boolean(
string='Duplicate Done Orders',
default=True,
help='Allows to duplicate already done orders in the frontend',
)
iface_load_done_order_max_qty = fields.Integer(
string='Max. Done Orders Quantity To Load',
default=10,
required=True,
help='Maximum number of orders to load on the PoS at its init. '
'Set it to 0 to load none (it\'s still possible to load them by '
'ticket code).',
)

160
pos_order_mgmt/models/pos_order.py

@ -0,0 +1,160 @@
# Copyright 2018 GRAP - Sylvain LE GAL
# Copyright 2018 Tecnativa S.L. - David Vidal
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, models, fields
class PosOrder(models.Model):
_inherit = 'pos.order'
returned_order_id = fields.Many2one(
comodel_name='pos.order',
string='Returned Order',
readonly=True,
)
returned_order_reference = fields.Char(
related='returned_order_id.pos_reference',
string='Reference of the returned Order')
refund_order_ids = fields.One2many(
comodel_name='pos.order',
inverse_name='returned_order_id',
string='Refund Orders',
readonly=True,
)
refund_order_qty = fields.Integer(
compute='_compute_refund_order_qty',
string='Refund Orders Quantity',
)
@api.multi
@api.depends('refund_order_ids')
def _compute_refund_order_qty(self):
for order in self:
order.refund_order_qty = len(order.refund_order_ids)
@api.multi
def action_view_refund_orders(self):
self.ensure_one()
action = self.env.ref('point_of_sale.action_pos_pos_form').read()[0]
if self.refund_order_qty == 1:
action['views'] = [
(self.env.ref('point_of_sale.view_pos_pos_form').id, 'form')]
action['res_id'] = self.refund_order_ids.ids[0]
else:
action['domain'] = [('id', 'in', self.refund_order_ids.ids)]
return action
@api.multi
def refund(self):
return super(PosOrder, self.with_context(refund=True)).refund()
@api.multi
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
self.ensure_one()
order = super().copy(default=default)
if self.env.context.get('refund', False):
order.returned_order_id = self.id
return order
@api.model
def _prepare_filter_for_pos(self, pos_session_id):
return [
('state', 'in', ['paid', 'done', 'invoiced']),
]
@api.model
def _prepare_filter_query_for_pos(self, pos_session_id, query):
return [
'|', '|',
('name', 'ilike', query),
('pos_reference', 'ilike', query),
('partner_id.display_name', 'ilike', query),
]
@api.model
def _prepare_fields_for_pos_list(self):
return [
'name', 'pos_reference', 'partner_id', 'date_order',
'amount_total',
]
@api.model
def search_done_orders_for_pos(self, query, pos_session_id):
session_obj = self.env['pos.session']
config = session_obj.browse(pos_session_id).config_id
condition = self._prepare_filter_for_pos(pos_session_id)
if not query:
# Search only this POS orders
condition += [('config_id', '=', config.id)]
else:
# Search globally by criteria
condition += self._prepare_filter_query_for_pos(
pos_session_id, query)
field_names = self._prepare_fields_for_pos_list()
return self.search_read(
condition, field_names, limit=config.iface_load_done_order_max_qty)
@api.multi
def _prepare_done_order_for_pos(self):
self.ensure_one()
order_lines = []
payment_lines = []
for order_line in self.lines:
order_line = self._prepare_done_order_line_for_pos(order_line)
order_lines.append(order_line)
for payment_line in self.statement_ids:
payment_line = self._prepare_done_order_payment_for_pos(
payment_line)
payment_lines.append(payment_line)
res = {
'id': self.id,
'date_order': self.date_order,
'pos_reference': self.pos_reference,
'name': self.name,
'partner_id': self.partner_id.id,
'fiscal_position': self.fiscal_position_id.id,
'line_ids': order_lines,
'statement_ids': payment_lines,
'to_invoice': bool(self.invoice_id),
'returned_order_id': self.returned_order_id.id,
'returned_order_reference': self.returned_order_reference,
}
return res
@api.multi
def _prepare_done_order_line_for_pos(self, order_line):
self.ensure_one()
return {
'product_id': order_line.product_id.id,
'qty': order_line.qty,
'price_unit': order_line.price_unit,
'discount': order_line.discount,
}
@api.multi
def _prepare_done_order_payment_for_pos(self, payment_line):
self.ensure_one()
return {
'journal_id': payment_line.journal_id.id,
'amount': payment_line.amount,
}
@api.multi
def load_done_order_for_pos(self):
self.ensure_one()
return self._prepare_done_order_for_pos()
@api.model
def _order_fields(self, ui_order):
res = super()._order_fields(ui_order)
res.update({
'returned_order_id': ui_order.get('returned_order_id', False),
})
return res

12
pos_order_mgmt/readme/CONFIGURE.rst

@ -0,0 +1,12 @@
To configure this module, you need to:
#. Go to *Point of Sale > Configuration > Point of Sale* and select one of
them.
#. Change *Max Done Orders Quantity To Load* to your desired amount (10 by
default). Please note that the more you load, the more it will take to load
them in the session opening. You can also set it to 0 and you'll just be
able to load them from the order list screen.
#. Set *Reprint Done Orders* on if you want to be able to reprint past orders
in that PoS.
#. Set *Return Done Orders* on if you want to be able to return past orders
in that PoS.

5
pos_order_mgmt/readme/CONTRIBUTORS.rst

@ -0,0 +1,5 @@
* David Vidal <david.vidal@tecnativa.com>
* Sylvain LE GAL (https://twitter.com/legalsylvain)
* Carlos Martínez <carlos@domatix.com>
* Pierrick Brun <pierrick.brun@akretion.com>
* Iván Todorovich <ivan.todorovich@druidoo.io>

3
pos_order_mgmt/readme/DESCRIPTION.rst

@ -0,0 +1,3 @@
This module extends the functionality of the PoS frontend allowing to load
already done PoS Orders in order to be able to operate over them, being able to
reprint past tickets or return them.

5
pos_order_mgmt/readme/ROADMAP.rst

@ -0,0 +1,5 @@
* It's possible to return the same order over and over. To avoid so, we should
load and control if there's a returned line id associated with the original
order. That would be a great improvement for future revisions.
This feature is implemented in the module ``pos_order_return`` in the back
office part, but not in front office part (implemented in this this module).

19
pos_order_mgmt/readme/USAGE.rst

@ -0,0 +1,19 @@
Once the PoS is loaded, you'll find a shopping trolley icon (🛒) in the top
bar that grants access to the order list screen.
.. image:: ../static/description/order-mgmt-icon.png
There you can find the number of past orders loaded according to your
configuration (see Configuration) as well as the orders you checked out in
the current session:
.. image:: ../static/description/order-mgmt-list.png
#. You can see their totals as well as their custumers if registered.
#. You can reprint their tickets clicking on the printer icon (⎙).
#. You can return them pressing on the arrow icon (↶).
#. You have a search input as well that lets you find past tickets by its
reference number.
NOTE: You'll need your PoS to be online to be able to search or return a past
ticket.

BIN
pos_order_mgmt/static/description/icon.png

After

Width: 560  |  Height: 560  |  Size: 15 KiB

474
pos_order_mgmt/static/description/index.html

@ -0,0 +1,474 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" />
<title>POS Frontend Orders Management</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="pos-frontend-orders-management">
<h1 class="title">POS Frontend Orders Management</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/pos/tree/12.0/pos_order_mgmt"><img alt="OCA/pos" src="https://img.shields.io/badge/github-OCA%2Fpos-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/pos-12-0/pos-12-0-pos_order_mgmt"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/184/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module extends the functionality of the PoS frontend allowing to load
already done PoS Orders in order to be able to operate over them, being able to
reprint past tickets or return them.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id3">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id8">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id1">Configuration</a></h1>
<p>To configure this module, you need to:</p>
<ol class="arabic simple">
<li>Go to <em>Point of Sale &gt; Configuration &gt; Point of Sale</em> and select one of
them.</li>
<li>Change <em>Max Done Orders Quantity To Load</em> to your desired amount (10 by
default). Please note that the more you load, the more it will take to load
them in the session opening. You can also set it to 0 and you’ll just be
able to load them from the order list screen.</li>
<li>Set <em>Reprint Done Orders</em> on if you want to be able to reprint past orders
in that PoS.</li>
<li>Set <em>Return Done Orders</em> on if you want to be able to return past orders
in that PoS.</li>
</ol>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
<p>Once the PoS is loaded, you’ll find a shopping trolley icon (🛒) in the top
bar that grants access to the order list screen.</p>
<img alt="https://raw.githubusercontent.com/OCA/pos/12.0/pos_order_mgmt/static/description/order-mgmt-icon.png" src="https://raw.githubusercontent.com/OCA/pos/12.0/pos_order_mgmt/static/description/order-mgmt-icon.png" />
<p>There you can find the number of past orders loaded according to your
configuration (see Configuration) as well as the orders you checked out in
the current session:</p>
<img alt="https://raw.githubusercontent.com/OCA/pos/12.0/pos_order_mgmt/static/description/order-mgmt-list.png" src="https://raw.githubusercontent.com/OCA/pos/12.0/pos_order_mgmt/static/description/order-mgmt-list.png" />
<ol class="arabic simple">
<li>You can see their totals as well as their custumers if registered.</li>
<li>You can reprint their tickets clicking on the printer icon (⎙).</li>
<li>You can return them pressing on the arrow icon (↶).</li>
<li>You have a search input as well that lets you find past tickets by its
reference number.</li>
</ol>
<p>NOTE: You’ll need your PoS to be online to be able to search or return a past
ticket.</p>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id3">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>It’s possible to return the same order over and over. To avoid so, we should
load and control if there’s a returned line id associated with the original
order. That would be a great improvement for future revisions.
This feature is implemented in the module <tt class="docutils literal">pos_order_return</tt> in the back
office part, but not in front office part (implemented in this this module).</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id4">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/pos/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/pos/issues/new?body=module:%20pos_order_mgmt%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id5">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id6">Authors</a></h2>
<ul class="simple">
<li>GRAP</li>
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id7">Contributors</a></h2>
<ul class="simple">
<li>David Vidal &lt;<a class="reference external" href="mailto:david.vidal&#64;tecnativa.com">david.vidal&#64;tecnativa.com</a>&gt;</li>
<li>Sylvain LE GAL (<a class="reference external" href="https://twitter.com/legalsylvain">https://twitter.com/legalsylvain</a>)</li>
<li>Carlos Martínez &lt;<a class="reference external" href="mailto:carlos&#64;domatix.com">carlos&#64;domatix.com</a>&gt;</li>
<li>Pierrick Brun &lt;<a class="reference external" href="mailto:pierrick.brun&#64;akretion.com">pierrick.brun&#64;akretion.com</a>&gt;</li>
<li>Iván Todorovich &lt;<a class="reference external" href="mailto:ivan.todorovich&#64;druidoo.io">ivan.todorovich&#64;druidoo.io</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id8">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/pos/tree/12.0/pos_order_mgmt">OCA/pos</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

BIN
pos_order_mgmt/static/description/order-mgmt-icon.png

After

Width: 678  |  Height: 271  |  Size: 26 KiB

BIN
pos_order_mgmt/static/description/order-mgmt-list.png

After

Width: 825  |  Height: 279  |  Size: 38 KiB

35
pos_order_mgmt/static/src/css/pos.css

@ -0,0 +1,35 @@
/* Copyright 2018 Tecnativa - David Vidal
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
*/
.order-list-button {
font-size: 20px;
}
.order-line .button {
cursor: pointer;
top: 0px;
line-height: 32px;
padding: 3px 13px;
font-size: 20px;
background: rgb(230, 230, 230);
margin-left: 12px;
border-radius: 3px;
border: solid 1px rgb(209, 209, 209);
transition: all 150ms linear;
}
.order-line .button:active {
background: black;
border-color: black;
color: white;
}
.order-returned-warning {
font-size: 16px;
font-style: italic;
padding: 8px 0;
background-color: rgb(239, 153, 65);
color: white;
text-align: center;
}

30
pos_order_mgmt/static/src/js/models.js

@ -0,0 +1,30 @@
/* Copyright 2018 Tecnativa - David Vidal
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */
odoo.define('pos_order_mgmt.models', function (require) {
'use strict';
var models = require('point_of_sale.models');
var order_super = models.Order.prototype;
models.Order = models.Order.extend({
init_from_JSON: function (json) {
order_super.init_from_JSON.apply(this, arguments);
this.returned_order_id = json.returned_order_id;
this.returned_order_reference = json.returned_order_reference;
},
export_as_JSON: function () {
var res = order_super.export_as_JSON.apply(this, arguments);
res.returned_order_id = this.returned_order_id;
res.returned_order_reference = this.returned_order_reference;
return res;
},
export_for_printing: function () {
var res = order_super.export_for_printing.apply(this, arguments);
res.returned_order_id = this.returned_order_id;
res.returned_order_reference = this.returned_order_reference;
return res;
},
});
});

464
pos_order_mgmt/static/src/js/widgets.js

@ -0,0 +1,464 @@
/* Copyright 2018 GRAP - Sylvain LE GAL
Copyright 2018 Tecnativa - David Vidal
Copyright 2019 Druidoo - Ivan Todorovich
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */
odoo.define('pos_order_mgmt.widgets', function (require) {
"use strict";
var core = require('web.core');
var _t = core._t;
var PosBaseWidget = require('point_of_sale.BaseWidget');
var screens = require('point_of_sale.screens');
var gui = require('point_of_sale.gui');
var chrome = require('point_of_sale.chrome');
var pos = require('point_of_sale.models');
var QWeb = core.qweb;
var ScreenWidget = screens.ScreenWidget;
var DomCache = screens.DomCache;
screens.ReceiptScreenWidget.include({
render_receipt: function () {
if (!this.pos.reloaded_order) {
return this._super();
}
var order = this.pos.reloaded_order;
this.$('.pos-receipt-container').html(QWeb.render('PosTicket', {
widget: this,
pos: this.pos,
order: order,
receipt: order.export_for_printing(),
orderlines: order.get_orderlines(),
paymentlines: order.get_paymentlines(),
}));
this.pos.from_loaded_order = true;
},
click_next: function () {
if (!this.pos.from_loaded_order) {
return this._super();
}
this.pos.from_loaded_order = false;
// When reprinting a loaded order we temporarily set it as the
// active one. When we get out from the printing screen, we set
// it back to the one that was active
if (this.pos.current_order) {
this.pos.set_order(this.pos.current_order);
this.pos.current_order = false;
}
return this.gui.show_screen(this.gui.startup_screen);
},
});
var OrderListScreenWidget = ScreenWidget.extend({
template: 'OrderListScreenWidget',
init: function (parent, options) {
this._super(parent, options);
this.order_cache = new DomCache();
this.orders = [];
this.unknown_products = [];
this.search_query = false;
this.perform_search();
},
auto_back: true,
show: function () {
var self = this;
var previous_screen = false;
if (this.pos.get_order()) {
previous_screen = this.pos.get_order().get_screen_data(
'previous-screen');
}
if (previous_screen === 'receipt') {
this.gui.screen_instances.receipt.click_next();
this.gui.show_screen('orderlist');
}
this._super();
this.renderElement();
this.old_order = this.pos.get_order();
this.$('.back').click(function () {
return self.gui.show_screen(self.gui.startup_screen);
});
if (this.pos.config.iface_vkeyboard &&
this.chrome.widget.keyboard) {
this.chrome.widget.keyboard.connect(
this.$('.searchbox input'));
}
var search_timeout = null;
this.$('.searchbox input').on('keyup', function () {
self.search_query = this.value;
clearTimeout(search_timeout);
search_timeout = setTimeout(function () {
self.perform_search();
}, 70);
});
this.$('.searchbox .search-clear').click(function () {
self.clear_search();
});
this.perform_search();
},
render_list: function () {
var self = this;
var orders = this.orders;
var contents = this.$el[0].querySelector('.order-list-contents');
contents.innerHTML = "";
for (
var i = 0, len = Math.min(orders.length, 1000); i < len; i++
) {
var order = orders[i];
var orderline = this.order_cache.get_node(
order.id || order.uid);
if (!orderline) {
var orderline_html = QWeb.render('OrderLine', {
widget: this,
order: order,
});
orderline = document.createElement('tbody');
orderline.innerHTML = orderline_html;
orderline = orderline.childNodes[1];
this.order_cache.cache_node(
order.id || order.uid, orderline);
}
if (order === this.old_order) {
orderline.classList.add('highlight');
} else {
orderline.classList.remove('highlight');
}
contents.appendChild(orderline);
}
// FIXME: Everytime the list is rendered we need to reassing the
// button events.
this.$('.order-list-return').off('click');
this.$('.order-list-reprint').off('click');
this.$('.order-list-copy').off('click');
this.$('.order-list-reprint').click(function (event) {
self.order_list_actions(event, 'print');
});
this.$('.order-list-copy').click(function (event) {
self.order_list_actions(event, 'copy');
});
this.$('.order-list-return').click(function (event) {
self.order_list_actions(event, 'return');
});
},
order_list_actions: function (event, action) {
var self = this;
var dataset = event.target.parentNode.dataset;
self.load_order_data(parseInt(dataset.orderId, 10))
.then(function (order_data) {
self.order_action(order_data, action);
});
},
order_action: function (order_data, action) {
if (this.old_order !== null) {
this.gui.back();
}
var order = this.load_order_from_data(order_data, action);
if (!order) {
// The load of the order failed. (products not found, ...
// We cancel the action
return;
}
this['action_' + action](order_data, order);
},
action_print: function (order_data, order) {
// We store temporarily the current order so we can safely compute
// taxes based on fiscal position
this.pos.current_order = this.pos.get_order();
this.pos.set_order(order);
if (this.pos.config.iface_print_via_proxy) {
this.pos.proxy.print_receipt(QWeb.render(
'XmlReceipt', {
receipt: order.export_for_printing(),
widget: this,
pos: this.pos,
order: order,
orderlines: order.get_orderlines(),
paymentlines: order.get_paymentlines(),
}));
this.pos.set_order(this.pos.current_order);
this.pos.current_order = false;
} else {
this.pos.reloaded_order = order;
this.gui.show_screen('receipt');
this.pos.reloaded_order = false;
}
},
action_copy: function (order_data, order) {
order.trigger('change');
this.pos.get('orders').add(order);
this.pos.set('selectedOrder', order);
return order;
},
action_return: function (order_data, order) {
order.trigger('change');
this.pos.get('orders').add(order);
this.pos.set('selectedOrder', order);
return order;
},
_prepare_order_from_order_data: function (order_data, action) {
var self = this;
var order = new pos.Order({}, {
pos: this.pos,
});
// Get Customer
if (order_data.partner_id) {
order.set_client(
this.pos.db.get_partner_by_id(order_data.partner_id));
}
// Get fiscal position
if (order_data.fiscal_position && this.pos.fiscal_positions) {
var fiscal_positions = this.pos.fiscal_positions;
order.fiscal_position = fiscal_positions.filter(function (p) {
return p.id === order_data.fiscal_position;
})[0];
order.trigger('change');
}
// Get order lines
self._prepare_orderlines_from_order_data(
order, order_data, action);
// Get Name
if (['print'].indexOf(action) !== -1) {
order.name = order_data.pos_reference;
} else if (['return'].indexOf(action) !== -1) {
order.name = _t("Refund ") + order.uid;
}
// Get to invoice
if (['return', 'copy'].indexOf(action) !== -1) {
// If previous order was invoiced, we need a refund too
order.set_to_invoice(order_data.to_invoice);
}
// Get returned Order
if (['print'].indexOf(action) !== -1) {
// Get the same value as the original
order.returned_order_id = order_data.returned_order_id;
order.returned_order_reference =
order_data.returned_order_reference;
} else if (['return'].indexOf(action) !== -1) {
order.returned_order_id = order_data.id;
order.returned_order_reference = order_data.pos_reference;
}
// Get Date
if (['print'].indexOf(action) !== -1) {
order.formatted_validation_date =
moment(order_data.date_order).format('YYYY-MM-DD HH:mm:ss');
}
// Get Payment lines
if (['print'].indexOf(action) !== -1) {
var paymentLines = order_data.statement_ids || [];
_.each(paymentLines, function (paymentLine) {
var line = paymentLine;
// In case of local data
if (line.length === 3) {
line = line[2];
}
_.each(self.pos.cashregisters, function (cashregister) {
if (cashregister.journal.id === line.journal_id) {
if (line.amount > 0) {
// If it is not change
order.add_paymentline(cashregister);
order.selected_paymentline.set_amount(
line.amount);
}
}
});
});
}
return order;
},
_prepare_orderlines_from_order_data: function (
order, order_data, action) {
var orderLines = order_data.line_ids || order_data.lines || [];
var self = this;
_.each(orderLines, function (orderLine) {
var line = orderLine;
// In case of local data
if (line.length === 3) {
line = line[2];
}
var product = self.pos.db.get_product_by_id(line.product_id);
// Check if product are available in pos
if (_.isUndefined(product)) {
self.unknown_products.push(String(line.product_id));
} else {
var qty = line.qty;
if (['return'].indexOf(action) !== -1) {
// Invert line quantities
qty *= -1;
}
// Create a new order line
order.add_product(product, {
price: line.price_unit,
quantity: qty,
discount: line.discount,
merge: false,
});
}
});
},
load_order_data: function (order_id) {
var self = this;
return this._rpc({
model: 'pos.order',
method: 'load_done_order_for_pos',
args: [order_id],
}).fail(function (error) {
if (parseInt(error.code, 10) === 200) {
// Business Logic Error, not a connection problem
self.gui.show_popup(
'error-traceback', {
'title': error.data.message,
'body': error.data.debug,
});
} else {
self.gui.show_popup('error', {
'title': _t('Connection error'),
'body': _t(
'Can not execute this action because the POS' +
' is currently offline'),
});
}
});
},
load_order_from_data: function (order_data, action) {
var self = this;
this.unknown_products = [];
var order = self._prepare_order_from_order_data(
order_data, action);
// Forbid POS Order loading if some products are unknown
if (self.unknown_products.length > 0) {
self.gui.show_popup('error-traceback', {
'title': _t('Unknown Products'),
'body': _t('Unable to load some order lines because the ' +
'products are not available in the POS cache.\n\n' +
'Please check that lines :\n\n * ') +
self.unknown_products.join("; \n *"),
});
return false;
}
return order;
},
// Search Part
search_done_orders: function (query) {
var self = this;
return this._rpc({
model: 'pos.order',
method: 'search_done_orders_for_pos',
args: [query || '', this.pos.pos_session.id],
}).then(function (result) {
self.orders = result;
// Get the date in local time
_.each(self.orders, function (order) {
if (order.date_order) {
order.date_order = moment.utc(order.date_order)
.local().format('YYYY-MM-DD HH:mm:ss');
}
});
}).fail(function (error, event) {
if (parseInt(error.code, 10) === 200) {
// Business Logic Error, not a connection problem
self.gui.show_popup(
'error-traceback', {
'title': error.data.message,
'body': error.data.debug,
}
);
} 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();
});
},
perform_search: function () {
var self = this;
return this.search_done_orders(self.search_query)
.done(function () {
self.render_list();
});
},
clear_search: function () {
var self = this;
self.$('.searchbox input')[0].value = '';
self.$('.searchbox input').focus();
self.search_query = false;
self.perform_search();
},
});
gui.define_screen({
name: 'orderlist',
widget: OrderListScreenWidget,
});
var ListOrderButtonWidget = PosBaseWidget.extend({
template: 'ListOrderButtonWidget',
init: function (parent, options) {
var opts = options || {};
this._super(parent, opts);
this.action = opts.action;
this.label = opts.label;
},
button_click: function () {
this.gui.show_screen('orderlist');
},
renderElement: function () {
var self = this;
this._super();
this.$el.click(function () {
self.button_click();
});
},
});
var widgets = chrome.Chrome.prototype.widgets;
widgets.push({
'name': 'list_orders',
'widget': ListOrderButtonWidget,
'prepend': '.pos-rightheader',
'args': {
'label': 'All Orders',
},
});
return {
ListOrderButtonWidget: ListOrderButtonWidget,
OrderListScreenWidget: OrderListScreenWidget,
};
});

104
pos_order_mgmt/static/src/xml/pos.xml

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="ListOrderButtonWidget">
<t t-if="widget.pos.config.iface_load_done_order_max_qty">
<div class="header-button order-list-button">
<i class='fa fa-fw fa-shopping-cart'/>
</div>
</t>
</t>
<t t-name="OrderListScreenWidget">
<div class="clientlist-screen screen">
<div class="screen-content">
<section class="top-content">
<span class='button back'>
<i class='fa fa-angle-double-left'></i>
Back
</span>
<span class='searchbox'>
<input placeholder='Search Order' />
<span class='search-clear'></span>
</span>
<span class='searchbox'></span>
</section>
<section class="full-content">
<div class="window">
<section class="subwindow">
<div class="subwindow-container">
<div class="subwindow-container-fix touch-scrollable scrollable-y">
<table class="client-list">
<thead>
<th name="th_ol_ref">Ref.</th>
<th name="th_ol_customer">Customer</th>
<th name="th_ol_date">Date</th>
<th name="th_ol_amount_total">Amount Total</th>
<th name="th_ol_reprint"/>
</thead>
<tbody class="order-list-contents">
</tbody>
</table>
</div>
</div>
</section>
</div>
</section>
</div>
</div>
</t>
<t t-name="OrderLine">
<tr class='order-line' t-att-data-id='order.id' t-att-data-Uid='order.uid'>
<td name="td_ol_name"><t t-esc='order.pos_reference or order.name' /></td>
<td name="td_ol_customer"><t t-esc='order.partner_id[1]' /></td>
<td name="td_ol_date"><t t-esc='order.date_order' /></td>
<td name="td_ol_amount_total"><t t-esc='widget.format_currency(order.amount_total)' /></td>
<td name="td_ol_reprint" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'>
<span t-if="widget.pos.config.iface_reprint_done_order" class="button order-list-reprint" t-att-data-order-id="order.id" t-att-data-Uid='order.uid' title="Print a duplicate for this order">
<i class='fa fa-fw fa-print'/>
</span>
<span t-if="widget.pos.config.iface_copy_done_order" class="button order-list-copy" t-att-data-order-id="order.id" t-att-data-Uid='order.uid' title="Create a new order based on this one">
<i class='fa fa-fw fa-copy'/>
</span>
<span t-if="widget.pos.config.iface_return_done_order and order.amount_total >= 0" class="button order-list-return" t-att-data-order-id="order.id" t-att-data-Uid='order.uid' title="Create a refund order of this order">
<i class='fa fa-fw fa-undo'/>
</span>
</td>
</tr>
</t>
<t t-extend="OrderWidget">
<t t-jquery=".summary" t-operation="after">
<div class="order-returned-warning" t-if="order.returned_order_id">
<span>Returned order: </span><t name="returned-order-reference" t-esc="order.returned_order_reference"></t>
</div>
</t>
</t>
<t t-extend="PosTicket">
<t t-jquery="t[t-esc='order.name']" t-operation="after">
<t t-if="order.returned_order_id">
<br/>
<span name="returned-order-reference">Rectifies: </span><t t-esc="order.returned_order_reference"/>
</t>
</t>
<t t-jquery=".receipt-user" t-operation="after">
<t t-if="pos.reloaded_order">
<br/>
<div style='text-align:center'>DUPLICATE</div>
<br/>
</t>
</t>
</t>
<t t-extend="XmlReceipt">
<t t-jquery=".orderlines" t-operation="before">
<t t-if="pos.current_order">
<div>DUPLICATE</div>
<br/>
</t>
</t>
</t>
</templates>

1
pos_order_mgmt/tests/__init__.py

@ -0,0 +1 @@
from . import test_module

80
pos_order_mgmt/tests/test_module.py

@ -0,0 +1,80 @@
# Copyright (C) 2019 - 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 odoo import fields
from odoo.tests.common import TransactionCase
class TestModule(TransactionCase):
def setUp(self):
super(TestModule, self).setUp()
# Get Registry
self.PosOrder = self.env['pos.order']
self.AccountPayment = self.env['account.payment']
# Get Object
self.pos_product = self.env.ref('point_of_sale.whiteboard_pen')
self.pricelist = self.env.ref('product.list0')
self.partner = self.env.ref('base.res_partner_12')
# Create a new pos config and open it
self.pos_config = self.env.ref('point_of_sale.pos_config_main').copy()
self.pos_config.open_session_cb()
# Test Section
def test_load_order(self):
order = self._create_order()
orders_data = self.PosOrder.search_done_orders_for_pos(
[], self.pos_config.current_session_id.id)
self.assertEqual(len(orders_data), 1)
self.assertEqual(
orders_data[0]['id'], order.id)
detail_data = order.load_done_order_for_pos()
self.assertEqual(
len(detail_data.get('line_ids', [])), 1,
"Loading order detail failed")
def _create_order(self):
# Create order
order_data = {
'id': u'0006-001-0010',
'to_invoice': True,
'data': {
'pricelist_id': self.pricelist.id,
'user_id': 1,
'name': 'Order 0006-001-0010',
'partner_id': self.partner.id,
'amount_paid': 0.9,
'pos_session_id': self.pos_config.current_session_id.id,
'lines': [[0, 0, {
'product_id': self.pos_product.id,
'price_unit': 0.9,
'qty': 1,
'price_subtotal': 0.9,
'price_subtotal_incl': 0.9,
}]],
'statement_ids': [[0, 0, {
'journal_id': self.pos_config.journal_ids[0].id,
'amount': 0.9,
'name': fields.Datetime.now(),
'account_id':
self.env.user.partner_id.property_account_receivable_id.id,
'statement_id':
self.pos_config.current_session_id.statement_ids[0].id,
}]],
'creation_date': u'2018-09-27 15:51:03',
'amount_tax': 0,
'fiscal_position_id': False,
'uid': u'00001-001-0001',
'amount_return': 0,
'sequence_number': 1,
'amount_total': 0.9,
}}
result = self.PosOrder.create_from_ui([order_data])
order = self.PosOrder.browse(result[0])
return order

13
pos_order_mgmt/views/assets.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets" inherit_id="point_of_sale.assets">
<xpath expr="." position="inside">
<script type="text/javascript" src="/pos_order_mgmt/static/src/js/widgets.js"/>
<script type="text/javascript" src="/pos_order_mgmt/static/src/js/models.js"/>
<link rel="stylesheet" href="/pos_order_mgmt/static/src/css/pos.css"/>
</xpath>
</template>
</odoo>

63
pos_order_mgmt/views/view_pos_config.xml

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2018 GRAP - Sylvain LE GAL
Copyright 2018 Tecnativa - David Vidal
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="view_pos_config_form" model="ir.ui.view">
<field name="model">pos.config</field>
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='receipt']" position="inside">
<div class="col-xs-12 col-md-6 o_setting_box" id="reprint_done_order">
<div class="o_setting_left_pane">
<field name="iface_reprint_done_order"/>
</div>
<div class="o_setting_right_pane">
<label string="Reprint Done Orders" for="iface_reprint_done_order"/>
<div class="text-muted">
Allow to reprint done orders in this POS
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" id="return_done_order">
<div class="o_setting_left_pane">
<field name="iface_return_done_order"/>
</div>
<div class="o_setting_right_pane">
<label string="Return Done Orders" for="iface_return_done_order"/>
<div class="text-muted">
Allow to return done orders in this POS
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" id="copy_done_order">
<div class="o_setting_left_pane">
<field name="iface_copy_done_order"/>
</div>
<div class="o_setting_right_pane">
<label string="Duplicate Done Orders" for="iface_copy_done_order"/>
<div class="text-muted">
Allow to duplicate done orders in this POS
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" id="load_done_order_max_qty"
attrs="{'invisible': [('iface_reprint_done_order', '=', False),
('iface_return_done_order', '=', False)]}">
<div class="o_setting_right_pane">
<label string="Load Done Order Max Qty." for="iface_load_done_order_max_qty"/>
<div class="text-muted">
Maximum number orders to load
</div>
<div class="content-group mt16">
<field name="iface_load_done_order_max_qty" class="oe_inline"/>
</div>
</div>
</div>
</xpath>
</field>
</record>
</odoo>

22
pos_order_mgmt/views/view_pos_order.xml

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2018 GRAP - Sylvain LE GAL
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="view_pos_order_form" model="ir.ui.view">
<field name="model">pos.order</field>
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/>
<field name="arch" type="xml">
<field name="session_id" position="after">
<field name="returned_order_id" attrs="{'invisible': [('returned_order_id', '=', False)]}" />
</field>
<xpath expr="//div[@name='button_box']" position="inside">
<button name="action_view_refund_orders" type="object" icon="fa-undo" class="oe_stat_button" attrs="{'invisible': [('refund_order_qty', '=', 0)]}">
<field string="Refunds" name="refund_order_qty" widget="statinfo"/>
</button>
</xpath>
</field>
</record>
</odoo>

2
setup/_metapackage/VERSION.txt

@ -1 +1 @@
12.0.20190320.0
12.0.20190718.0

1
setup/_metapackage/setup.py

@ -9,6 +9,7 @@ setuptools.setup(
version=version,
install_requires=[
'odoo12-addon-pos_access_right',
'odoo12-addon-pos_order_mgmt',
'odoo12-addon-pos_ticket_logo',
],
classifiers=[

1
setup/pos_order_mgmt/odoo/addons/pos_order_mgmt

@ -0,0 +1 @@
../../../../pos_order_mgmt

6
setup/pos_order_mgmt/setup.py

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
Loading…
Cancel
Save