David Vidal
6 years ago
committed by
David
22 changed files with 1231 additions and 0 deletions
-
121pos_order_mgmt/README.rst
-
1pos_order_mgmt/__init__.py
-
27pos_order_mgmt/__manifest__.py
-
149pos_order_mgmt/i18n/es.po
-
146pos_order_mgmt/i18n/pos_order_mgmt.pot
-
2pos_order_mgmt/models/__init__.py
-
24pos_order_mgmt/models/pos_config.py
-
116pos_order_mgmt/models/pos_order.py
-
10pos_order_mgmt/readme/CONFIGURE.rst
-
2pos_order_mgmt/readme/CONTRIBUTORS.rst
-
3pos_order_mgmt/readme/DESCRIPTION.rst
-
3pos_order_mgmt/readme/ROADMAP.rst
-
19pos_order_mgmt/readme/USAGE.rst
-
BINpos_order_mgmt/static/description/icon.png
-
BINpos_order_mgmt/static/description/order-mgmt-icon.png
-
BINpos_order_mgmt/static/description/order-mgmt-list.png
-
34pos_order_mgmt/static/src/css/pos.css
-
46pos_order_mgmt/static/src/js/models.js
-
389pos_order_mgmt/static/src/js/widgets.js
-
85pos_order_mgmt/static/src/xml/pos.xml
-
13pos_order_mgmt/views/assets.xml
-
41pos_order_mgmt/views/view_pos_config.xml
@ -0,0 +1,121 @@ |
|||||
|
============================== |
||||
|
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/11.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-11-0/pos-11-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/11.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. |
||||
|
#. Set *Load Done Orders* on if you want to be able to load past orders in that |
||||
|
PoS. |
||||
|
#. 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. |
||||
|
|
||||
|
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:: /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:: /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. |
||||
|
|
||||
|
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:%2011.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) |
||||
|
|
||||
|
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/11.0/pos_order_mgmt>`_ project on GitHub. |
||||
|
|
||||
|
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
@ -0,0 +1 @@ |
|||||
|
from . import models |
@ -0,0 +1,27 @@ |
|||||
|
# 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': '11.0.1.0.0', |
||||
|
'category': 'Point of Sale', |
||||
|
'author': 'GRAP, ' |
||||
|
'Tecnativa, ' |
||||
|
'Odoo Community Association (OCA)', |
||||
|
'website': 'https://github.com/OCA/pos', |
||||
|
'license': 'AGPL-3', |
||||
|
'depends': [ |
||||
|
'pos_order_return', |
||||
|
], |
||||
|
'data': [ |
||||
|
'views/assets.xml', |
||||
|
'views/view_pos_config.xml', |
||||
|
], |
||||
|
'qweb': [ |
||||
|
'static/src/xml/pos.xml' |
||||
|
], |
||||
|
'application': False, |
||||
|
'installable': True, |
||||
|
} |
@ -0,0 +1,149 @@ |
|||||
|
# 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: 2018-10-18 11:15+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: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:230 |
||||
|
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:258 |
||||
|
#, 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:229 |
||||
|
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:257 |
||||
|
#, 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: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:190 |
||||
|
#, 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:189 |
||||
|
#, 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 "" |
@ -0,0 +1,146 @@ |
|||||
|
# 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: 2018-10-18 11:15+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:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form |
||||
|
msgid "Allow to load done orders in this POS" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. 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 "" |
||||
|
|
||||
|
#. 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:230 |
||||
|
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:258 |
||||
|
#, 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:229 |
||||
|
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:257 |
||||
|
#, python-format |
||||
|
msgid "Connection error" |
||||
|
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:35 |
||||
|
#, python-format |
||||
|
msgid "Date" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_order_mgmt |
||||
|
#: model: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 |
||||
|
#: model:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form |
||||
|
msgid "Load Done Orders" |
||||
|
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 posible to load them by ticket code)." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_order_mgmt |
||||
|
#: model: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_order |
||||
|
msgid "Point of Sale Orders" |
||||
|
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 |
||||
|
#. openerp-web |
||||
|
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:71 |
||||
|
#, 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:190 |
||||
|
#, 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:189 |
||||
|
#, python-format |
||||
|
msgid "Unknown Products" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: pos_order_mgmt |
||||
|
#: model:ir.model,name:pos_order_mgmt.model_pos_config |
||||
|
msgid "pos.config" |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,2 @@ |
|||||
|
from . import pos_config |
||||
|
from . import pos_order |
@ -0,0 +1,24 @@ |
|||||
|
# 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 fields, models |
||||
|
|
||||
|
|
||||
|
class PosConfig(models.Model): |
||||
|
_inherit = 'pos.config' |
||||
|
|
||||
|
iface_load_done_order = fields.Boolean( |
||||
|
string='Load Done Orders', |
||||
|
default=True, |
||||
|
help='Allows to load already done orders in the frontend to operate ' |
||||
|
'over them, allowing reprint the tickets, return items, etc.', |
||||
|
) |
||||
|
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 posible to load them by ' |
||||
|
'ticket code).', |
||||
|
) |
@ -0,0 +1,116 @@ |
|||||
|
# 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 |
||||
|
|
||||
|
|
||||
|
class PosOrder(models.Model): |
||||
|
_inherit = 'pos.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), |
||||
|
] |
||||
|
|
||||
|
@api.model |
||||
|
def _prepare_fields_for_pos_list(self): |
||||
|
return [ |
||||
|
'name', 'pos_reference', 'partner_id', 'date_order', |
||||
|
'amount_total', 'amount_paid', 'amount_return', 'session_id', |
||||
|
'amount_tax', 'statement_ids', 'lines', 'invoice_id', |
||||
|
'returned_order_id', 'fiscal_position_id' |
||||
|
] |
||||
|
|
||||
|
@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) |
||||
|
fields = self._prepare_fields_for_pos_list() |
||||
|
return self.search_read( |
||||
|
condition, fields, 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) |
||||
|
return { |
||||
|
'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, |
||||
|
'origin_invoice_id': bool(self.invoice_id), |
||||
|
'returned_order_id': (self.returned_order_id and |
||||
|
self.returned_order_id.pos_reference or |
||||
|
False), |
||||
|
} |
||||
|
|
||||
|
@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 { |
||||
|
'statement_id': payment_line.statement_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 _process_order(self, pos_order): |
||||
|
if (not pos_order.get('return') or |
||||
|
not pos_order.get('returned_order_id')): |
||||
|
return super()._process_order(pos_order) |
||||
|
order = super(PosOrder, |
||||
|
self.with_context(do_not_check_negative_qty=True) |
||||
|
)._process_order(pos_order) |
||||
|
returned_order_id = pos_order.get('returned_order_id') |
||||
|
if isinstance(returned_order_id, int): |
||||
|
order.returned_order_id = self.browse(returned_order_id) |
||||
|
# Only if the order is returned from the browser saved orders. |
||||
|
else: |
||||
|
order.returned_order_id = self.search([ |
||||
|
('pos_reference', '=', returned_order_id)]) |
||||
|
order.returned_order_id.refund_order_ids |= order |
||||
|
return order |
@ -0,0 +1,10 @@ |
|||||
|
To configure this module, you need to: |
||||
|
|
||||
|
#. Go to *Point of Sale > Configuration > Point of Sale* and select one of |
||||
|
them. |
||||
|
#. Set *Load Done Orders* on if you want to be able to load past orders in that |
||||
|
PoS. |
||||
|
#. 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. |
@ -0,0 +1,2 @@ |
|||||
|
* David Vidal <david.vidal@tecnativa.com> |
||||
|
* Sylvain LE GAL (https://twitter.com/legalsylvain) |
@ -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. |
@ -0,0 +1,3 @@ |
|||||
|
* 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. |
@ -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:: /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:: /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. |
After Width: 560 | Height: 560 | Size: 15 KiB |
After Width: 678 | Height: 271 | Size: 26 KiB |
After Width: 825 | Height: 279 | Size: 38 KiB |
@ -0,0 +1,34 @@ |
|||||
|
/* 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; |
||||
|
} |
@ -0,0 +1,46 @@ |
|||||
|
/* 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 _PosModel_push_order = models.PosModel.prototype.push_order; |
||||
|
models.PosModel.prototype.push_order = function () { |
||||
|
var res = _PosModel_push_order.apply(this, arguments); |
||||
|
if (arguments.length && arguments[0] && arguments[0].uid) { |
||||
|
var order = this.db.get_order(arguments[0].uid); |
||||
|
if (order && order.data) { |
||||
|
var data = Object.assign({}, order.data); |
||||
|
var partner = this.db.get_partner_by_id(data.partner_id); |
||||
|
if (partner && partner.id && partner.name) { |
||||
|
data.partner_id = [partner.id, partner.name]; |
||||
|
} |
||||
|
data.date_order = moment(order.data.creation_date) |
||||
|
.format('YYYY-MM-DD HH:mm:ss'); |
||||
|
this.gui.screen_instances.orderlist.orders.unshift(data); |
||||
|
} |
||||
|
} |
||||
|
return res; |
||||
|
}; |
||||
|
|
||||
|
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.return = json.return; |
||||
|
this.returned_order_id = json.returned_order_id; |
||||
|
this.origin_name = json.origin_name; |
||||
|
}, |
||||
|
export_as_JSON: function () { |
||||
|
var res = order_super.export_as_JSON.apply(this, arguments); |
||||
|
if (this.return) { |
||||
|
res.origin_name = this.origin_name; |
||||
|
res.returned_order_id = this.returned_order_id; |
||||
|
res.return = this.return; |
||||
|
} |
||||
|
return res; |
||||
|
}, |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,389 @@ |
|||||
|
/* Copyright 2018 GRAP - Sylvain LE GAL |
||||
|
Copyright 2018 Tecnativa - David Vidal |
||||
|
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; |
||||
|
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_done_orders(); |
||||
|
}, |
||||
|
|
||||
|
auto_back: true, |
||||
|
|
||||
|
show: function () { |
||||
|
var self = this; |
||||
|
var 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 (self.orders.length === 0) { |
||||
|
this.search_done_orders(); |
||||
|
} |
||||
|
this.render_list(); |
||||
|
var search_timeout = null; |
||||
|
if (this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard) { |
||||
|
this.chrome.widget.keyboard.connect(this.$('.searchbox input')); |
||||
|
} |
||||
|
this.$('.searchbox input').on('keyup', function (event) { |
||||
|
clearTimeout(search_timeout); |
||||
|
var query = this.value; |
||||
|
search_timeout = setTimeout(function () { |
||||
|
self.perform_search(query, event.which === 13); |
||||
|
}, 70); |
||||
|
}); |
||||
|
this.$('.searchbox .search-clear').click(function () { |
||||
|
self.clear_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-return').click(function (event) { |
||||
|
self.order_list_actions(event, 'return'); |
||||
|
}); |
||||
|
this.$('.order-list-reprint').click(function (event) { |
||||
|
self.order_list_actions(event, 'print'); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
order_list_actions: function (event, action) { |
||||
|
var dataset = event.target.parentNode.dataset; |
||||
|
var self = this; |
||||
|
if (dataset.orderId) { |
||||
|
this.load_order(parseInt(dataset.orderId, 10), action); |
||||
|
} else { |
||||
|
var local_order = ''; |
||||
|
_.each(this.orders, function (order) { |
||||
|
if (order.uid === dataset.uid) { |
||||
|
order.return = action === 'return'; |
||||
|
local_order = self._prepare_order_from_order_data(order); |
||||
|
} |
||||
|
}); |
||||
|
if (local_order) { |
||||
|
this['action_' + action](local_order); |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
action_print: function (order) { |
||||
|
var receipt = order.export_for_printing(); |
||||
|
if (this.pos.config.iface_print_via_proxy) { |
||||
|
this.pos.proxy.print_receipt(QWeb.render( |
||||
|
'XmlReceipt', { |
||||
|
receipt: receipt, |
||||
|
widget: this, |
||||
|
pos: this.pos, |
||||
|
order: order, |
||||
|
orderlines: order.get_orderlines(), |
||||
|
paymentlines: order.get_paymentlines(), |
||||
|
})); |
||||
|
} else { |
||||
|
this.pos.reloaded_order = order; |
||||
|
this.gui.show_screen('receipt'); |
||||
|
this.pos.reloaded_order = false; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
action_return: function (order) { |
||||
|
this.pos.get('orders').add(order); |
||||
|
this.pos.set('selectedOrder', order); |
||||
|
return order; |
||||
|
}, |
||||
|
|
||||
|
_prepare_order_from_order_data: function (order_data) { |
||||
|
var self = this; |
||||
|
var order = new pos.Order({}, { |
||||
|
pos: this.pos, |
||||
|
temporary: !order_data.return, |
||||
|
}); |
||||
|
// Set Generic Info
|
||||
|
if (!order_data.return) { |
||||
|
order.name = order_data.pos_reference || order_data.name; |
||||
|
} |
||||
|
if (order_data.partner_id.length) { |
||||
|
order_data.partner_id = order_data.partner_id[0]; |
||||
|
} |
||||
|
order.set_client(this.pos.db.get_partner_by_id(order_data.partner_id)); |
||||
|
// Set order lines
|
||||
|
var orderLines = order_data.line_ids || order_data.lines || []; |
||||
|
_.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 { |
||||
|
// Create a new order line
|
||||
|
order.add_product(product, { |
||||
|
price: line.price_unit, |
||||
|
quantity: order_data.return ? line.qty * -1 : line.qty, |
||||
|
discount: line.discount, |
||||
|
merge: false, |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
// Set 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]; |
||||
|
_.each(order.orderlines.models, function (line) { |
||||
|
line.set_quantity(line.quantity); |
||||
|
}); |
||||
|
order.trigger('change'); |
||||
|
} |
||||
|
if (order_data.return) { |
||||
|
order.return = true; |
||||
|
// A credit note should be emited if there was an invoice
|
||||
|
order.set_to_invoice(order_data.origin_invoice_id); |
||||
|
// We'll refunded orders once they are synced
|
||||
|
order.returned_order_id = order_data.id || order_data.name; |
||||
|
order.origin_name = order_data.pos_reference || order.returned_order_id; |
||||
|
return order; |
||||
|
} |
||||
|
if (order_data.returned_order_id) { |
||||
|
order.origin_name = order_data.returned_order_id; |
||||
|
} |
||||
|
order.formatted_validation_date = moment(order_data.date_order).format('YYYY-MM-DD HH:mm:ss'); |
||||
|
// Set Payment lines
|
||||
|
var paymentLines = order_data.statement_ids || []; |
||||
|
_.each(paymentLines, function (paymentLine) { |
||||
|
var line = paymentLine; |
||||
|
// In case of local data
|
||||
|
if (line.length === 3) { |
||||
|
line = line[2]; |
||||
|
} |
||||
|
_.each(self.pos.cashregisters, function (cashregister) { |
||||
|
if (cashregister.id === line.statement_id) { |
||||
|
if (line.amount > 0) { |
||||
|
// If it is not change
|
||||
|
order.add_paymentline(cashregister); |
||||
|
order.selected_paymentline.set_amount(line.amount); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
return order; |
||||
|
}, |
||||
|
|
||||
|
load_order: function (order_id, action) { |
||||
|
this.unknown_products = []; |
||||
|
var self = this; |
||||
|
return this._rpc({ |
||||
|
model: 'pos.order', |
||||
|
method: 'load_done_order_for_pos', |
||||
|
args: [order_id], |
||||
|
}).then(function (order_data) { |
||||
|
self.gui.back(); |
||||
|
var correct_order_print = true; |
||||
|
if (action === 'return') { |
||||
|
order_data.return = true; |
||||
|
} |
||||
|
var order = self._prepare_order_from_order_data(order_data); |
||||
|
// Forbid POS Order loading if some products are unknown
|
||||
|
if (self.unknown_products.length > 0) { |
||||
|
self.gui.show_popup('error-traceback', { |
||||
|
'title': _t('Unknown Products'), |
||||
|
'body': _t('Unable to load some order lines because the ' + |
||||
|
'products are not available in the POS cache.\n\n' + |
||||
|
'Please check that lines :\n\n * ') + self.unknown_products.join("; \n *"), |
||||
|
}); |
||||
|
correct_order_print = false; |
||||
|
} |
||||
|
if (correct_order_print && action === 'print') { |
||||
|
self.action_print(order); |
||||
|
} |
||||
|
if (correct_order_print && action === 'return') { |
||||
|
self.action_return(order); |
||||
|
} |
||||
|
}).fail(function (error, event) { |
||||
|
if (parseInt(error.code, 10) === 200) { |
||||
|
// Business Logic Error, not a connection problem
|
||||
|
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(); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 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; |
||||
|
}).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 (query) { |
||||
|
var self = this; |
||||
|
this.search_done_orders(query) |
||||
|
.done(function () { |
||||
|
self.render_list(); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
clear_search: function () { |
||||
|
var self = this; |
||||
|
this.search_done_orders() |
||||
|
.done(function () { |
||||
|
self.$('.searchbox input')[0].value = ''; |
||||
|
self.$('.searchbox input').focus(); |
||||
|
self.render_list(); |
||||
|
}); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
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, |
||||
|
}; |
||||
|
|
||||
|
}); |
@ -0,0 +1,85 @@ |
|||||
|
<?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"> |
||||
|
<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 class="button order-list-reprint" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'> |
||||
|
<i class='fa fa-fw fa-print'/> |
||||
|
</span> |
||||
|
<span t-if="order.amount_total >= 0" class="button order-list-return" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'> |
||||
|
<i class='fa fa-fw fa-undo'/> |
||||
|
</span> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend="OrderWidget"> |
||||
|
<t t-jquery=".order-scroller.touch-scrollable" t-operation="before"> |
||||
|
<div class="order-returned-warning" t-if="order.return"> |
||||
|
<span>Returned order: </span><t name="order-return-uid" t-esc="order.origin_name"></t> |
||||
|
</div> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
<t t-extend="PosTicket"> |
||||
|
<t t-jquery="t[t-esc='order.name']" t-operation="after"> |
||||
|
<t t-if="order.origin_name"> |
||||
|
<br/> |
||||
|
<span name="order-origin-name">Rectifies: </span><t t-esc="order.origin_name"/> |
||||
|
</t> |
||||
|
</t> |
||||
|
</t> |
||||
|
|
||||
|
</templates> |
@ -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> |
@ -0,0 +1,41 @@ |
|||||
|
<?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="name">pos.config.form</field> |
||||
|
<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="load_done_order"> |
||||
|
<div class="o_setting_left_pane"> |
||||
|
<field name="iface_load_done_order"/> |
||||
|
</div> |
||||
|
<div class="o_setting_right_pane"> |
||||
|
<label string="Load Done Orders"/> |
||||
|
<div class="text-muted"> |
||||
|
Allow to load 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_load_done_order', '=', False)]}"> |
||||
|
<div class="o_setting_right_pane"> |
||||
|
<label string="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> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue