Browse Source

[FIX] loaded orders date to local https://github.com/OCA/pos/pull/361 cortesy @chienandalu

[FIX] compatibility with pos_restaurant https://github.com/OCA/pos/pull/339 cortesy @carlosDomatix
[FIX] add _compute_refund_order_qty
[ADD] pos order view form. Add links to original returned order and refund orders.
[IMP] when refunding an order via the 'Refund' button in back office, set the correct returned_order_id.
[IMP] Add helper on each button
[ADD] python test
[REF] JS remove useless code
[REF] Python remove useless code
[FIX] remove bad oldname
[FIX] remove gap in bill display, when it is a refund
[FIX] when reprinting a bill, the returned order name is displayed, if any
[FIX] JS lint, with OCA eslint file
[ADD] french translation
pull/378/head
Sylvain LE GAL 6 years ago
committed by OCA-git-bot
parent
commit
9946e1e0b3
  1. 1
      pos_order_mgmt/__manifest__.py
  2. 249
      pos_order_mgmt/i18n/fr.po
  3. 149
      pos_order_mgmt/i18n/pos_order_mgmt.pot
  4. 4
      pos_order_mgmt/models/pos_config.py
  5. 73
      pos_order_mgmt/models/pos_order.py
  6. 1
      pos_order_mgmt/static/src/css/pos.css
  7. 34
      pos_order_mgmt/static/src/js/models.js
  8. 204
      pos_order_mgmt/static/src/js/widgets.js
  9. 16
      pos_order_mgmt/static/src/xml/pos.xml
  10. 1
      pos_order_mgmt/tests/__init__.py
  11. 80
      pos_order_mgmt/tests/test_module.py
  12. 1
      pos_order_mgmt/views/view_pos_config.xml
  13. 22
      pos_order_mgmt/views/view_pos_order.xml

1
pos_order_mgmt/__manifest__.py

@ -18,6 +18,7 @@
'data': [
'views/assets.xml',
'views/view_pos_config.xml',
'views/view_pos_order.xml',
],
'qweb': [
'static/src/xml/pos.xml'

249
pos_order_mgmt/i18n/fr.po

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

149
pos_order_mgmt/i18n/pos_order_mgmt.pot

@ -4,8 +4,10 @@
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-07-15 20:53+0000\n"
"PO-Revision-Date: 2019-07-15 20:53+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@ -14,13 +16,33 @@ msgstr ""
"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"
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to duplicate done orders in this POS"
msgstr ""
#. module: pos_order_mgmt
#: model: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."
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to reprint done orders in this POS"
msgstr ""
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Allow to return done orders in this POS"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_copy_done_order
msgid "Allows to duplicate already done orders in the frontend"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_reprint_done_order
msgid "Allows to reprint already done orders in the frontend"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_return_done_order
msgid "Allows to return already done orders in the frontend"
msgstr ""
#. module: pos_order_mgmt
@ -39,20 +61,34 @@ msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:303
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:331
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:341
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:396
#, python-format
msgid "Can not execute this action because the POS is currently offline"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:302
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:330
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:340
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:395
#, python-format
msgid "Connection error"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:61
#, python-format
msgid "Create a new order based on this one"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:64
#, python-format
msgid "Create a refund order of this order"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:34
@ -60,6 +96,14 @@ msgstr ""
msgid "Customer"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:89
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:98
#, python-format
msgid "DUPLICATE"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:35
@ -68,31 +112,36 @@ 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."
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_copy_done_order
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Duplicate Done Orders"
msgstr ""
#. module: pos_order_mgmt
#: model: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"
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Load Done Order Max Qty."
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config_iface_load_done_order_max_qty
#: 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)."
#: model:ir.model.fields,help:pos_order_mgmt.field_pos_config__iface_load_done_order_max_qty
msgid "Maximum number of orders to load on the PoS at its init. Set it to 0 to load none (it's still possible to load them by ticket code)."
msgstr ""
#. module: pos_order_mgmt
#: model:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Maximum number orders to load"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model,name:pos_order_mgmt.model_pos_config
msgid "Point of Sale Configuration"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model,name:pos_order_mgmt.model_pos_order
msgid "Point of Sale Orders"
@ -100,7 +149,14 @@ msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:80
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:58
#, python-format
msgid "Print a duplicate for this order"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:83
#, python-format
msgid "Rectifies:"
msgstr ""
@ -112,9 +168,53 @@ msgstr ""
msgid "Ref."
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__returned_order_reference
msgid "Reference of the returned Order"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:242
#, python-format
msgid "Refund "
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__refund_order_ids
msgid "Refund Orders"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__refund_order_qty
msgid "Refund Orders Quantity"
msgstr ""
#. module: pos_order_mgmt
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_order_form
msgid "Refunds"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_reprint_done_order
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Reprint Done Orders"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_config__iface_return_done_order
#: model_terms:ir.ui.view,arch_db:pos_order_mgmt.view_pos_config_form
msgid "Return Done Orders"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model.fields,field_description:pos_order_mgmt.field_pos_order__returned_order_id
msgid "Returned Order"
msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:71
#: code:addons/pos_order_mgmt/static/src/xml/pos.xml:74
#, python-format
msgid "Returned order:"
msgstr ""
@ -128,7 +228,7 @@ msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:280
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:358
#, python-format
msgid "Unable to load some order lines because the products are not available in the POS cache.\n"
"\n"
@ -139,13 +239,8 @@ msgstr ""
#. module: pos_order_mgmt
#. openerp-web
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:279
#: code:addons/pos_order_mgmt/static/src/js/widgets.js:357
#, python-format
msgid "Unknown Products"
msgstr ""
#. module: pos_order_mgmt
#: model:ir.model,name:pos_order_mgmt.model_pos_config
msgid "pos.config"
msgstr ""

4
pos_order_mgmt/models/pos_config.py

@ -14,14 +14,12 @@ class PosConfig(models.Model):
string='Reprint Done Orders',
default=True,
help='Allows to reprint already done orders in the frontend',
oldname='iface_load_done_order',
)
iface_return_done_order = fields.Boolean(
string='Return Done Orders',
default=True,
help='Allows to return already done orders in the frontend',
oldname='iface_load_done_order',
)
iface_copy_done_order = fields.Boolean(
@ -35,6 +33,6 @@ class PosConfig(models.Model):
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 '
'Set it to 0 to load none (it\'s still possible to load them by '
'ticket code).',
)

73
pos_order_mgmt/models/pos_order.py

@ -13,17 +13,56 @@ class PosOrder(models.Model):
string='Returned Order',
readonly=True,
)
returned_order_reference = fields.Char(
related='returned_order_id.pos_reference',
string='Reference of the returned Order')
refund_order_ids = fields.One2many(
comodel_name='pos.order',
inverse_name='returned_order_id',
string='Refund Orders',
readonly=True,
)
refund_order_qty = fields.Integer(
compute='_compute_refund_order_qty',
string='Refund Orders Quantity',
)
@api.multi
@api.depends('refund_order_ids')
def _compute_refund_order_qty(self):
for order in self:
order.refund_order_qty = len(order.refund_order_ids)
@api.multi
def action_view_refund_orders(self):
self.ensure_one()
action = self.env.ref('point_of_sale.action_pos_pos_form').read()[0]
if self.refund_order_qty == 1:
action['views'] = [
(self.env.ref('point_of_sale.view_pos_pos_form').id, 'form')]
action['res_id'] = self.refund_order_ids.ids[0]
else:
action['domain'] = [('id', 'in', self.refund_order_ids.ids)]
return action
@api.multi
def refund(self):
return super(PosOrder, self.with_context(refund=True)).refund()
@api.multi
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
self.ensure_one()
order = super().copy(default=default)
if self.env.context.get('refund', False):
order.returned_order_id = self.id
return order
@api.model
def _prepare_filter_for_pos(self, pos_session_id):
return [
@ -43,9 +82,7 @@ class PosOrder(models.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'
'amount_total',
]
@api.model
@ -76,7 +113,7 @@ class PosOrder(models.Model):
payment_line = self._prepare_done_order_payment_for_pos(
payment_line)
payment_lines.append(payment_line)
return {
res = {
'id': self.id,
'date_order': self.date_order,
'pos_reference': self.pos_reference,
@ -85,11 +122,11 @@ class PosOrder(models.Model):
'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),
'to_invoice': bool(self.invoice_id),
'returned_order_id': self.returned_order_id.id,
'returned_order_reference': self.returned_order_reference,
}
return res
@api.multi
def _prepare_done_order_line_for_pos(self, order_line):
@ -115,17 +152,9 @@ class PosOrder(models.Model):
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)._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
def _order_fields(self, ui_order):
res = super()._order_fields(ui_order)
res.update({
'returned_order_id': ui_order.get('returned_order_id', False),
})
return res

1
pos_order_mgmt/static/src/css/pos.css

@ -31,4 +31,5 @@
padding: 8px 0;
background-color: rgb(239, 153, 65);
color: white;
text-align: center;
}

34
pos_order_mgmt/static/src/js/models.js

@ -6,40 +6,24 @@ odoo.define('pos_order_mgmt.models', function (require) {
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 = _.extend({}, 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;
this.returned_order_reference = json.returned_order_reference;
},
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;
}
res.returned_order_reference = this.returned_order_reference;
return res;
},
export_for_printing: function () {
var res = order_super.export_for_printing.apply(this, arguments);
res.returned_order_id = this.returned_order_id;
res.returned_order_reference = this.returned_order_reference;
return res;
},
});

204
pos_order_mgmt/static/src/js/widgets.js

@ -65,9 +65,10 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
show: function () {
var self = this;
var previous_screen;
var previous_screen = false;
if (this.pos.get_order()) {
previous_screen = this.pos.get_order().get_screen_data('previous-screen');
previous_screen = this.pos.get_order().get_screen_data(
'previous-screen');
}
if (previous_screen === 'receipt') {
this.gui.screen_instances.receipt.click_next();
@ -80,12 +81,14 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
return self.gui.show_screen(self.gui.startup_screen);
});
if (this.pos.config.iface_vkeyboard && this.chrome.widget.keyboard) {
this.chrome.widget.keyboard.connect(this.$('.searchbox input'));
if (this.pos.config.iface_vkeyboard &&
this.chrome.widget.keyboard) {
this.chrome.widget.keyboard.connect(
this.$('.searchbox input'));
}
var search_timeout = null;
this.$('.searchbox input').on('keyup', function (event) {
this.$('.searchbox input').on('keyup', function () {
self.search_query = this.value;
clearTimeout(search_timeout);
search_timeout = setTimeout(function () {
@ -105,9 +108,12 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
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++) {
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);
var orderline = this.order_cache.get_node(
order.id || order.uid);
if (!orderline) {
var orderline_html = QWeb.render('OrderLine', {
widget: this,
@ -116,7 +122,8 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
orderline = document.createElement('tbody');
orderline.innerHTML = orderline_html;
orderline = orderline.childNodes[1];
this.order_cache.cache_node(order.id || order.uid, orderline);
this.order_cache.cache_node(
order.id || order.uid, orderline);
}
if (order === this.old_order) {
orderline.classList.add('highlight');
@ -130,54 +137,50 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
this.$('.order-list-return').off('click');
this.$('.order-list-reprint').off('click');
this.$('.order-list-copy').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');
});
this.$('.order-list-copy').click(function (event) {
self.order_list_actions(event, 'copy');
});
this.$('.order-list-return').click(function (event) {
self.order_list_actions(event, 'return');
});
},
order_list_actions: function (event, action) {
var self = this;
var order_data;
var dataset = event.target.parentNode.dataset;
if (dataset.orderId) {
self.load_order_data(parseInt(dataset.orderId, 10))
.then(function (order_data) {
self.order_action(order_data, action);
})
} else {
_.each(this.orders, function (order_data) {
if (order.uid === dataset.uid) {
self.order_action(order_data, action);
}
});
}
},
order_action: function (order_data, action) {
if (this.old_order !== null) {
this.gui.back();
this['action_' + action](order_data);
}
var order = this.load_order_from_data(order_data, action);
if (!order) {
// The load of the order failed. (products not found, ...
// We cancel the action
return;
}
this['action_' + action](order_data, order);
},
action_print: function (order_data) {
var order = this.load_order_from_data(order_data, true);
if (!order) return false;
// Restore the previous name
order.name = order_data.pos_reference || order_data.name;
var receipt = order.export_for_printing();
action_print: function (order_data, order) {
// We store temporarily the current order so we can safely compute
// taxes based on fiscal position
this.pos.current_order = this.pos.get_order()
this.pos.current_order = this.pos.get_order();
this.pos.set_order(order);
if (this.pos.config.iface_print_via_proxy) {
this.pos.proxy.print_receipt(QWeb.render(
'XmlReceipt', {
receipt: receipt,
receipt: order.export_for_printing(),
widget: this,
pos: this.pos,
order: order,
@ -193,57 +196,33 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
}
},
action_copy: function(order_data) {
// Remove payments from original data
order_data.statement_ids = false;
var order = this.load_order_from_data(order_data, true);
if (!order) { return false; }
// If previous order was invoiced, we need a refund too
order.set_to_invoice(order_data.origin_invoice_id);
order.formatted_validation_date = false;
action_copy: function (order_data, order) {
order.trigger('change');
this.pos.get('orders').add(order);
this.pos.set('selectedOrder', order);
return order;
},
action_return: function (order_data) {
//var order_data = _.cloneDeep(order_data);
// Remove payments from original data
order_data.statement_ids = false;
// Invert line quantities
var order_lines = order_data.line_ids || order_data.lines || [];
_.each(order_lines, function(line) { line.qty = -1 * line.qty })
// Load from new data and change some stuff
var order = this.load_order_from_data(order_data);
if (!order) { return false; }
order.return = true;
order.name = _t("Refund ") + order.uid;;
order.origin_name = order_data.pos_reference || order.returned_order_id;
// If previous order was invoiced, we need a refund too
order.set_to_invoice(order_data.origin_invoice_id);
order.formatted_validation_date = false;
action_return: function (order_data, order) {
order.trigger('change');
// Add to pos
this.pos.get('orders').add(order);
this.pos.set('selectedOrder', order);
return order;
},
_prepare_order_from_order_data: function (order_data, temporary) {
_prepare_order_from_order_data: function (order_data, action) {
var self = this;
var order = new pos.Order({}, {
pos: this.pos,
temporary: !!temporary,
});
if (order_data.partner_id.length) {
order_data.partner_id = order_data.partner_id[0];
// Get Customer
if (order_data.partner_id) {
order.set_client(
this.pos.db.get_partner_by_id(order_data.partner_id));
}
order.set_client(this.pos.db.get_partner_by_id(order_data.partner_id));
// Set fiscal position
// Get fiscal position
if (order_data.fiscal_position && this.pos.fiscal_positions) {
var fiscal_positions = this.pos.fiscal_positions;
order.fiscal_position = fiscal_positions.filter(function (p) {
@ -252,17 +231,42 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
order.trigger('change');
}
// Set order lines
var orderLines = order_data.line_ids || order_data.lines || [];
self._prepare_orderlines_from_order_data(order, order_data, orderLines);
// Get order lines
self._prepare_orderlines_from_order_data(
order, order_data, action);
if (order_data.returned_order_id) {
order.origin_name = order_data.returned_order_id;
// Get Name
if (['print'].indexOf(action) !== -1) {
order.name = order_data.pos_reference;
} else if (['return'].indexOf(action) !== -1) {
order.name = _t("Refund ") + order.uid;
}
order.formatted_validation_date = moment(order_data.date_order).format('YYYY-MM-DD HH:mm:ss');
// Get to invoice
if (['return', 'copy'].indexOf(action) !== -1) {
// If previous order was invoiced, we need a refund too
order.set_to_invoice(order_data.to_invoice);
}
// Get returned Order
if (['print'].indexOf(action) !== -1) {
// Get the same value as the original
order.returned_order_id = order_data.returned_order_id;
order.returned_order_reference =
order_data.returned_order_reference;
} else if (['return'].indexOf(action) !== -1) {
order.returned_order_id = order_data.id;
order.returned_order_reference = order_data.pos_reference;
}
// Get Date
if (['print'].indexOf(action) !== -1) {
order.formatted_validation_date =
moment(order_data.date_order).format('YYYY-MM-DD HH:mm:ss');
}
// Set Payment lines
// Get Payment lines
if (['print'].indexOf(action) !== -1) {
var paymentLines = order_data.statement_ids || [];
_.each(paymentLines, function (paymentLine) {
var line = paymentLine;
@ -275,17 +279,23 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
if (line.amount > 0) {
// If it is not change
order.add_paymentline(cashregister);
order.selected_paymentline.set_amount(line.amount);
order.selected_paymentline.set_amount(
line.amount);
}
}
});
});
}
return order;
},
_prepare_orderlines_from_order_data: function(order, order_data, orderLines) {
_prepare_orderlines_from_order_data: function (
order, order_data, action) {
var orderLines = order_data.line_ids || order_data.lines || [];
var self = this;
_.each(orderLines, function(line) {
_.each(orderLines, function (orderLine) {
var line = orderLine;
// In case of local data
if (line.length === 3) {
line = line[2];
@ -295,10 +305,15 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
if (_.isUndefined(product)) {
self.unknown_products.push(String(line.product_id));
} else {
var qty = line.qty;
if (['return'].indexOf(action) !== -1) {
// Invert line quantities
qty *= -1;
}
// Create a new order line
order.add_product(product, {
price: line.price_unit,
quantity: line.qty,
quantity: qty,
discount: line.discount,
merge: false,
});
@ -312,7 +327,7 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
model: 'pos.order',
method: 'load_done_order_for_pos',
args: [order_id],
}).fail(function (error, event) {
}).fail(function (error) {
if (parseInt(error.code, 10) === 200) {
// Business Logic Error, not a connection problem
self.gui.show_popup(
@ -323,45 +338,33 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
} else {
self.gui.show_popup('error', {
'title': _t('Connection error'),
'body': _t('Can not execute this action because the POS is currently offline'),
'body': _t(
'Can not execute this action because the POS' +
' is currently offline'),
});
}
});
},
load_order_from_data: function(order_data) {
load_order_from_data: function (order_data, action) {
var self = this;
this.unknown_products = [];
var order = self._prepare_order_from_order_data(order_data);
var order = self._prepare_order_from_order_data(
order_data, action);
// Forbid POS Order loading if some products are unknown
if (self.unknown_products.length > 0) {
self.gui.show_popup('error-traceback', {
'title': _t('Unknown Products'),
'body': _t('Unable to load some order lines because the ' +
'products are not available in the POS cache.\n\n' +
'Please check that lines :\n\n * ') + self.unknown_products.join("; \n *"),
'Please check that lines :\n\n * ') +
self.unknown_products.join("; \n *"),
});
return false;
}
return order;
},
/* deprecated */
load_order: function (order_id) {
var self = this;
var done = new $.Deferred();
this.load_order_data(order_id)
.then(function(order_data) {
self.gui.show_screen('orderlist');
var order = self.load_order_from_data(order_data);
if (!order) { return done.fail(); }
done.resolve(order);
}).fail(function() {
done.fail();
});
return done;
},
// Search Part
search_done_orders: function (query) {
var self = this;
@ -371,6 +374,13 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
args: [query || '', this.pos.pos_session.id],
}).then(function (result) {
self.orders = result;
// Get the date in local time
_.each(self.orders, function (order) {
if (order.date_order) {
order.date_order = moment.utc(order.date_order)
.local().format('YYYY-MM-DD HH:mm:ss');
}
});
}).fail(function (error, event) {
if (parseInt(error.code, 10) === 200) {
// Business Logic Error, not a connection problem
@ -383,7 +393,9 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
} else {
self.gui.show_popup('error', {
'title': _t('Connection error'),
'body': _t('Can not execute this action because the POS is currently offline'),
'body': _t(
'Can not execute this action because the POS' +
' is currently offline'),
});
}
event.preventDefault();
@ -393,7 +405,9 @@ odoo.define('pos_order_mgmt.widgets', function (require) {
perform_search: function () {
var self = this;
return this.search_done_orders(self.search_query)
.done(function () { self.render_list(); });
.done(function () {
self.render_list();
});
},
clear_search: function () {

16
pos_order_mgmt/static/src/xml/pos.xml

@ -55,13 +55,13 @@
<td name="td_ol_date"><t t-esc='order.date_order' /></td>
<td name="td_ol_amount_total"><t t-esc='widget.format_currency(order.amount_total)' /></td>
<td name="td_ol_reprint" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'>
<span t-if="widget.pos.config.iface_reprint_done_order" class="button order-list-reprint" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'>
<span t-if="widget.pos.config.iface_reprint_done_order" class="button order-list-reprint" t-att-data-order-id="order.id" t-att-data-Uid='order.uid' title="Print a duplicate for this order">
<i class='fa fa-fw fa-print'/>
</span>
<span t-if="widget.pos.config.iface_copy_done_order" class="button order-list-copy" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'>
<span t-if="widget.pos.config.iface_copy_done_order" class="button order-list-copy" t-att-data-order-id="order.id" t-att-data-Uid='order.uid' title="Create a new order based on this one">
<i class='fa fa-fw fa-copy'/>
</span>
<span t-if="widget.pos.config.iface_return_done_order and order.amount_total >= 0" class="button order-list-return" t-att-data-order-id="order.id" t-att-data-Uid='order.uid'>
<span t-if="widget.pos.config.iface_return_done_order and order.amount_total >= 0" class="button order-list-return" t-att-data-order-id="order.id" t-att-data-Uid='order.uid' title="Create a refund order of this order">
<i class='fa fa-fw fa-undo'/>
</span>
</td>
@ -69,18 +69,18 @@
</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>
<t t-jquery=".summary" t-operation="after">
<div class="order-returned-warning" t-if="order.returned_order_id">
<span>Returned order: </span><t name="returned-order-reference" t-esc="order.returned_order_reference"></t>
</div>
</t>
</t>
<t t-extend="PosTicket">
<t t-jquery="t[t-esc='order.name']" t-operation="after">
<t t-if="order.origin_name">
<t t-if="order.returned_order_id">
<br/>
<span name="order-origin-name">Rectifies: </span><t t-esc="order.origin_name"/>
<span name="returned-order-reference">Rectifies: </span><t t-esc="order.returned_order_reference"/>
</t>
</t>
<t t-jquery=".receipt-user" t-operation="after">

1
pos_order_mgmt/tests/__init__.py

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

80
pos_order_mgmt/tests/test_module.py

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

1
pos_order_mgmt/views/view_pos_config.xml

@ -6,7 +6,6 @@
<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">

22
pos_order_mgmt/views/view_pos_order.xml

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