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