From 00db862fdf891182563ef8a1342347e939da9075 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 24 Apr 2018 17:03:42 +0200 Subject: [PATCH] [MIG] pos_order_return: Migration to 10.0 --- .../README.rst | 43 ++-- .../__init__.py | 2 + pos_order_return/__manifest__.py | 28 +++ .../demo/product_product.xml | 4 +- pos_order_return/i18n/es.po | 210 ++++++++++++++++++ .../i18n/fr.po | 0 pos_order_return/models/__init__.py | 4 + pos_order_return/models/pos_order.py | 198 +++++++++++++++++ pos_order_return/models/product_template.py | 13 ++ pos_order_return/static/description/icon.png | Bin 0 -> 7876 bytes .../initial_pos_order_required.png | Bin .../description/partial_return_wizard.png | Bin .../description/product_returnable_bottle.png | Bin .../description/returned_qty_over_initial.png | Bin .../sum_returned_qty_over_initial.png | Bin .../img/product_returnable_bottle-image.jpg | Bin pos_order_return/tests/__init__.py | 3 + .../tests/test_pos_order_return.py | 102 +++++++++ .../views/pos_order_view.xml | 29 ++- .../views/product_product_view.xml | 7 +- pos_order_return/wizard/__init__.py | 3 + .../wizard/pos_partial_return_wizard.py | 72 ++++++ .../pos_partial_return_wizard_view.xml | 7 +- pos_return_order/__openerp__.py | 28 --- pos_return_order/models/__init__.py | 6 - pos_return_order/models/pos_order.py | 80 ------- pos_return_order/models/pos_order_line.py | 65 ------ .../models/pos_partial_return_wizard.py | 40 ---- .../models/pos_partial_return_wizard_line.py | 28 --- pos_return_order/models/product_template.py | 15 -- pos_return_order/static/description/icon.png | Bin 4697 -> 0 bytes pos_return_order/views/action.xml | 20 -- .../views/pos_order_line_view.xml | 23 -- 33 files changed, 687 insertions(+), 343 deletions(-) rename {pos_return_order => pos_order_return}/README.rst (65%) rename {pos_return_order => pos_order_return}/__init__.py (67%) create mode 100644 pos_order_return/__manifest__.py rename {pos_return_order => pos_order_return}/demo/product_product.xml (83%) create mode 100644 pos_order_return/i18n/es.po rename {pos_return_order => pos_order_return}/i18n/fr.po (100%) create mode 100644 pos_order_return/models/__init__.py create mode 100644 pos_order_return/models/pos_order.py create mode 100644 pos_order_return/models/product_template.py create mode 100644 pos_order_return/static/description/icon.png rename {pos_return_order => pos_order_return}/static/description/initial_pos_order_required.png (100%) rename {pos_return_order => pos_order_return}/static/description/partial_return_wizard.png (100%) rename {pos_return_order => pos_order_return}/static/description/product_returnable_bottle.png (100%) rename {pos_return_order => pos_order_return}/static/description/returned_qty_over_initial.png (100%) rename {pos_return_order => pos_order_return}/static/description/sum_returned_qty_over_initial.png (100%) rename {pos_return_order => pos_order_return}/static/img/product_returnable_bottle-image.jpg (100%) create mode 100644 pos_order_return/tests/__init__.py create mode 100644 pos_order_return/tests/test_pos_order_return.py rename {pos_return_order => pos_order_return}/views/pos_order_view.xml (59%) rename {pos_return_order => pos_order_return}/views/product_product_view.xml (68%) create mode 100644 pos_order_return/wizard/__init__.py create mode 100644 pos_order_return/wizard/pos_partial_return_wizard.py rename {pos_return_order/views => pos_order_return/wizard}/pos_partial_return_wizard_view.xml (83%) delete mode 100644 pos_return_order/__openerp__.py delete mode 100644 pos_return_order/models/__init__.py delete mode 100644 pos_return_order/models/pos_order.py delete mode 100644 pos_return_order/models/pos_order_line.py delete mode 100644 pos_return_order/models/pos_partial_return_wizard.py delete mode 100644 pos_return_order/models/pos_partial_return_wizard_line.py delete mode 100644 pos_return_order/models/product_template.py delete mode 100644 pos_return_order/static/description/icon.png delete mode 100644 pos_return_order/views/action.xml delete mode 100644 pos_return_order/views/pos_order_line_view.xml diff --git a/pos_return_order/README.rst b/pos_order_return/README.rst similarity index 65% rename from pos_return_order/README.rst rename to pos_order_return/README.rst index bd5c6e35..24a1eb4a 100644 --- a/pos_return_order/README.rst +++ b/pos_order_return/README.rst @@ -1,10 +1,10 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: https://www.gnu.org/licenses/agpl :alt: License: AGPL-3 -================== -PoS - Return Order -================== +================ +PoS Order Return +================ This module extends the functionality of odoo Point Of Sale about POS Order returns. @@ -15,46 +15,48 @@ one. A link is created between the returned Order and the initial Order. A link is created between the returned Order Line and the initial Order Line. -Implemented Features -==================== +Usage +===== + +Select an PoS Order an choose either *Return Products* (full return of the +order) or *Partial Return*. In this case, a wizard allows to select just some +products and quantities to return: -* A wizard that allow to select just some products to return: +.. image:: /pos_order_return/static/description/partial_return_wizard.png -.. image:: /pos_return_order/static/description/partial_return_wizard.png +Register the refund payment to finish the return. If the original order was +invoiced, a refund invoice will be made. Implemented Constraints -======================= +----------------------- * User can not return more products than the initial quantity: -.. image:: /pos_return_order/static/description/returned_qty_over_initial.png +.. image:: /pos_order_return/static/description/returned_qty_over_initial.png * If a line has been partially refund, only a reduced quantity can be returned: -.. image:: /pos_return_order/static/description/sum_returned_qty_over_initial.png +.. image:: /pos_order_return/static/description/sum_returned_qty_over_initial.png * It is not possible to set a negative quantity if the initial Pos Order is not indicated: -.. image:: /pos_return_order/static/description/initial_pos_order_required.png +.. image:: /pos_order_return/static/description/initial_pos_order_required.png Configuration ============= -In some case, you want to let the possibility to allow negative quantity +In some cases, you may want to let the possibility to allow negative quantity in a PoS Order, without mentioning initial order. This can happen for special -products like returnable products, ... +products like returnable products, etc. In that case, a checkbox is possible on Product Form View to allow such case -.. image:: /pos_return_order/static/description/product_returnable_bottle.png - -Usage -===== +.. image:: /pos_order_return/static/description/product_returnable_bottle.png .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/184/9.0 + :target: https://runbot.odoo-community.org/runbot/184/10.0 Bug Tracker =========== @@ -71,6 +73,7 @@ Contributors ------------ * Sylvain LE GAL +* David Vidal Funders ------- diff --git a/pos_return_order/__init__.py b/pos_order_return/__init__.py similarity index 67% rename from pos_return_order/__init__.py rename to pos_order_return/__init__.py index a0fdc10f..35e7c960 100644 --- a/pos_return_order/__init__.py +++ b/pos_order_return/__init__.py @@ -1,2 +1,4 @@ # -*- coding: utf-8 -*- + from . import models +from . import wizard diff --git a/pos_order_return/__manifest__.py b/pos_order_return/__manifest__.py new file mode 100644 index 00000000..1f28a3f1 --- /dev/null +++ b/pos_order_return/__manifest__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Copyright 2016-2018 Sylvain LE GAL (https://twitter.com/legalsylvain) +# Copyright 2018 David Vidal +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + 'name': 'Point of Sale Order Return', + 'version': '10.0.1.0.0', + 'category': 'Point Of Sale', + 'author': 'La Louve, ' + 'GRAP, ' + 'Tecnativa, ' + 'Odoo Community Association (OCA)', + 'license': 'AGPL-3', + 'website': 'https://www.github.com/OCA/pos', + 'depends': [ + 'point_of_sale', + ], + 'data': [ + 'wizard/pos_partial_return_wizard_view.xml', + 'views/pos_order_view.xml', + 'views/product_product_view.xml', + ], + 'demo': [ + 'demo/product_product.xml', + ], + 'installable': True, +} diff --git a/pos_return_order/demo/product_product.xml b/pos_order_return/demo/product_product.xml similarity index 83% rename from pos_return_order/demo/product_product.xml rename to pos_order_return/demo/product_product.xml index ea4dc8b8..67ead223 100644 --- a/pos_return_order/demo/product_product.xml +++ b/pos_order_return/demo/product_product.xml @@ -2,17 +2,15 @@ - Returnable Bottle RET-BOTL - - + diff --git a/pos_order_return/i18n/es.po b/pos_order_return/i18n/es.po new file mode 100644 index 00000000..c9dfd971 --- /dev/null +++ b/pos_order_return/i18n/es.po @@ -0,0 +1,210 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * pos_order_return +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-05-03 12:50+0000\n" +"PO-Revision-Date: 2018-05-03 12:50+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_return +#: model:ir.model.fields,field_description:pos_order_return.field_product_product_pos_allow_negative_qty +#: model:ir.model.fields,field_description:pos_order_return.field_product_template_pos_allow_negative_qty +msgid "Allow Negative Quantity on PoS" +msgstr "Allow Negative Quantity on PoS" + +#. module: pos_order_return +#: model:ir.ui.view,arch_db:pos_order_return.view_partial_return_wizard_form +msgid "Cancel" +msgstr "Cancelar" + +#. module: pos_order_return +#: model:ir.model.fields,help:pos_order_return.field_pos_partial_return_wizard_line_max_returnable_qty +msgid "Compute maximum quantity that can be returned for this line, depending of the quantity of the line and other possible refunds." +msgstr "Calcula la cantidad máxima que puede ser devuelta para esta línea, dependiendo de la cantidad de la línea y otras devoluciones anteriores" + +#. module: pos_order_return +#: model:ir.ui.view,arch_db:pos_order_return.view_partial_return_wizard_form +msgid "Confirm" +msgstr "Confirmar" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_create_uid +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_create_date +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_create_date +msgid "Created on" +msgstr "Creado el" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_display_name +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_display_name +msgid "Display Name" +msgstr "Nombre a mostrar" + +#. module: pos_order_return +#: code:addons/pos_order_return/models/pos_order.py:186 +#, python-format +msgid "For legal and traceability reasons, you can not set a negative quantity (%d %s of %s), without using return wizard." +msgstr "Por razones legales y de trazabilidad, no puede establecer una cantidad negativa (%d %s of %s), sin en el asistente de devoluciones." + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_id +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_id +msgid "ID" +msgstr "ID" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_initial_qty +msgid "Initial Quantity" +msgstr "Cantidad inicial" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard___last_update +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line___last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_write_uid +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_write_date +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_write_date +msgid "Last Updated on" +msgstr "Última actualización el" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_pos_order_line_id +msgid "Line To Return" +msgstr "Línea a devolver" + +#. module: pos_order_return +#: model:ir.model,name:pos_order_return.model_pos_order_line +msgid "Lines of Point of Sale" +msgstr "Líneas del Terminal Punto de Venta" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_ids +#: model:ir.ui.view,arch_db:pos_order_return.view_partial_return_wizard_form +msgid "Lines to Return" +msgstr "Líneas a devolver" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_order_id +msgid "Order to Return" +msgstr "Pedido a devolver" + +#. module: pos_order_return +#: model:ir.ui.view,arch_db:pos_order_return.view_partial_return_wizard_form +#: model:ir.ui.view,arch_db:pos_order_return.view_pos_order_form +msgid "Partial Return" +msgstr "Devolición parcial" + +#. module: pos_order_return +#: model:ir.actions.act_window,name:pos_order_return.action_pos_partial_return_wizard +msgid "Partial Return Wizard" +msgstr "Asistente de devolución parcial" + +#. module: pos_order_return +#: model:ir.model,name:pos_order_return.model_pos_order +msgid "Point of Sale Orders" +msgstr "Pedidos del TPV" + +#. module: pos_order_return +#: model:ir.model,name:pos_order_return.model_product_template +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: pos_order_return +#: model:ir.model.fields,help:pos_order_return.field_pos_partial_return_wizard_line_initial_qty +msgid "Quantity of Product initially sold" +msgstr "Cantidad de producto vendida inicialmente" + +#. module: pos_order_return +#: model:ir.ui.view,arch_db:pos_order_return.view_pos_order_form +#: model:ir.ui.view,arch_db:pos_order_return.view_pos_order_line_form +msgid "Refund" +msgstr "Factura rectificativa" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_order_line_refund_line_ids +msgid "Refund Lines" +msgstr "Líneas de devolución" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_order_refund_order_ids +msgid "Refund Orders" +msgstr "Pedidos de devolución" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_order_refund_order_qty +msgid "Refund Orders Quantity" +msgstr "Cantidad de pedidos de devolución" + +#. module: pos_order_return +#: model:product.product,name:pos_order_return.product_product_returnable_bottle +#: model:product.template,name:pos_order_return.product_product_returnable_bottle_product_template +msgid "Returnable Bottle" +msgstr "Botella retornable" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_max_returnable_qty +msgid "Returnable Quantity" +msgstr "Cantidad retornable" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_order_line_returned_line_id +#: model:ir.model.fields,field_description:pos_order_return.field_pos_order_returned_order_id +msgid "Returned Order" +msgstr "Pedido devuelto" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_qty +msgid "Returned Quantity" +msgstr "Cantidad devuelta" + +#. module: pos_order_return +#: model:ir.model.fields,field_description:pos_order_return.field_pos_partial_return_wizard_line_wizard_id +msgid "Wizard" +msgstr "Asistente" + +#. module: pos_order_return +#: code:addons/pos_order_return/models/pos_order.py:175 +#, python-format +msgid "You can not return %d %s of %s because some refunds has been yet done.\n" +" Maximum quantity allowed : %d %s." +msgstr "No puede devolver %d %s de %s porque ya se ha devuelto una parte.\n" +" Catidad máxima permitida : %d %s." + +#. module: pos_order_return +#: code:addons/pos_order_return/models/pos_order.py:166 +#, python-format +msgid "You can not return %d %s of %s because the original Order line only mentions %d %s." +msgstr "No puede devolver %d %s de %s porque el pedido original solo menciona %d %s." + +#. module: pos_order_return +#: model:ir.model,name:pos_order_return.model_pos_partial_return_wizard +msgid "pos.partial.return.wizard" +msgstr "pos.partial.return.wizard" + +#. module: pos_order_return +#: model:ir.model,name:pos_order_return.model_pos_partial_return_wizard_line +msgid "pos.partial.return.wizard.line" +msgstr "pos.partial.return.wizard.line" + diff --git a/pos_return_order/i18n/fr.po b/pos_order_return/i18n/fr.po similarity index 100% rename from pos_return_order/i18n/fr.po rename to pos_order_return/i18n/fr.po diff --git a/pos_order_return/models/__init__.py b/pos_order_return/models/__init__.py new file mode 100644 index 00000000..b848178c --- /dev/null +++ b/pos_order_return/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +from . import product_template +from . import pos_order diff --git a/pos_order_return/models/pos_order.py b/pos_order_return/models/pos_order.py new file mode 100644 index 00000000..5ed229a8 --- /dev/null +++ b/pos_order_return/models/pos_order.py @@ -0,0 +1,198 @@ +# -*- coding: utf-8 -*- +# Copyright 2016-2018 Sylvain LE GAL (https://twitter.com/legalsylvain) +# Copyright 2018 David Vidal +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class PosOrder(models.Model): + _inherit = 'pos.order' + + returned_order_id = fields.Many2one( + comodel_name='pos.order', + string='Returned Order', + readonly=True, + ) + 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', + ) + + def _compute_refund_order_qty(self): + order_data = self.env['pos.order'].read_group( + [('returned_order_id', 'in', self.ids)], + ['returned_order_id'], ['returned_order_id'] + ) + mapped_data = dict( + [(order['returned_order_id'][0], order['returned_order_id_count']) + for order in order_data]) + for order in self: + order.refund_order_qty = mapped_data.get(order.id, 0) + + def _blank_refund(self, res): + self.ensure_one() + new_order = self.browse(res['res_id']) + new_order.returned_order_id = self + # Remove created lines and recreate and link Lines + new_order.lines.unlink() + return new_order + + def _prepare_invoice(self): + res = super(PosOrder, self)._prepare_invoice() + if not self.returned_order_id: + return res + res.update({ + 'origin': self.name, + 'type': 'out_refund', + 'refund_invoice_id': self.returned_order_id.invoice_id.id, + }) + return res + + def _action_create_invoice_line(self, line=False, invoice_id=False): + line = super(PosOrder, self + )._action_create_invoice_line(line, invoice_id) + if not self.returned_order_id: + return line + # Goes to refund invoice thus it should be positive + line.quantity = -line.quantity + return line + + def _action_pos_order_invoice(self): + """Wrap common process""" + self.action_pos_order_invoice() + self.invoice_id.sudo().action_invoice_open() + self.account_move = self.invoice_id.move_id + + def refund(self): + # Call super to use original refund algorithm (session management, ...) + ctx = dict(self.env.context, do_not_check_negative_qty=True) + res = super(PosOrder, self.with_context(ctx)).refund() + new_order = self._blank_refund(res) + for line in self.lines: + qty = - line.max_returnable_qty([]) + if qty != 0: + copy_line = line.copy() + copy_line.write({ + 'order_id': new_order.id, + 'returned_line_id': line.id, + 'qty': qty, + }) + return res + + def partial_refund(self, partial_return_wizard): + ctx = dict(self.env.context, partial_refund=True) + res = self.with_context(ctx).refund() + new_order = self._blank_refund(res) + for wizard_line in partial_return_wizard.line_ids: + qty = -wizard_line.qty + if qty != 0: + copy_line = wizard_line.pos_order_line_id.copy() + copy_line.write({ + 'order_id': new_order.id, + 'returned_line_id': wizard_line.pos_order_line_id.id, + 'qty': qty, + }) + return res + + def action_pos_order_paid(self): + if self.returned_order_id and self.returned_order_id.invoice_id: + self._action_pos_order_invoice() + return super(PosOrder, self).action_pos_order_paid() + + def _create_picking_return(self): + self.ensure_one() + picking = self.returned_order_id.picking_id + ctx = dict(self.env.context, + active_ids=picking.ids, active_id=picking.id) + wizard = self.env['stock.return.picking'].with_context(ctx).create({}) + # Discard not returned lines + wizard.product_return_moves.filtered( + lambda x: x.product_id not in self.mapped( + 'lines.product_id')).unlink() + to_return = {} + for product in self.lines.mapped('product_id'): + to_return[product] = -sum( + self.lines.filtered( + lambda x: x.product_id == product).mapped('qty')) + for move in wizard.product_return_moves: + if to_return[move.product_id] < move.quantity: + move.quantity = to_return[move.product_id] + to_return[move.product_id] -= move.quantity + return wizard + + def create_picking(self): + """Odoo bases return picking if the quantities are negative, but it's + not linked to the original one""" + res = super(PosOrder, self.filtered(lambda x: not x.returned_order_id) + ).create_picking() + for order in self.filtered('returned_order_id'): + wizard = order._create_picking_return() + res = wizard.create_returns() + order.write({'picking_id': res['res_id']}) + return res + + +class PosOrderLine(models.Model): + _inherit = 'pos.order.line' + + returned_line_id = fields.Many2one( + comodel_name='pos.order.line', + string='Returned Order', + readonly=True, + ) + refund_line_ids = fields.One2many( + comodel_name='pos.order.line', + inverse_name='returned_line_id', + string='Refund Lines', + readonly=True, + ) + + @api.model + def max_returnable_qty(self, ignored_line_ids): + qty = self.qty + for refund_line in self.refund_line_ids: + if refund_line.id not in ignored_line_ids: + qty += refund_line.qty + return qty + + @api.constrains('returned_line_id', 'qty') + def _check_return_qty(self): + if self.env.context.get('do_not_check_negative_qty', False): + return True + for line in self: + if line.returned_line_id and -line.qty > line.returned_line_id.qty: + raise ValidationError(_( + "You can not return %d %s of %s because the original " + "Order line only mentions %d %s." + ) % (-line.qty, line.product_id.uom_id.name, + line.product_id.name, line.returned_line_id.qty, + line.product_id.uom_id.name)) + if (line.returned_line_id and + -line.qty > + line.returned_line_id.max_returnable_qty([line.id])): + raise ValidationError(_( + "You can not return %d %s of %s because some refunds" + " has been yet done.\n Maximum quantity allowed :" + " %d %s." + ) % (-line.qty, line.product_id.uom_id.name, + line.product_id.name, + line.returned_line_id.max_returnable_qty([line.id]), + line.product_id.uom_id.name)) + if (not line.returned_line_id and + line.qty < 0 and not + line.product_id.product_tmpl_id.pos_allow_negative_qty): + raise ValidationError(_( + "For legal and traceability reasons, you can not set a" + " negative quantity (%d %s of %s), without using " + "return wizard." + ) % (line.qty, line.product_id.uom_id.name, + line.product_id.name)) diff --git a/pos_order_return/models/product_template.py b/pos_order_return/models/product_template.py new file mode 100644 index 00000000..f87215f1 --- /dev/null +++ b/pos_order_return/models/product_template.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# Copyright 2016-2018 Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = 'product.template' + + pos_allow_negative_qty = fields.Boolean( + string='Allow Negative Quantity on PoS', + ) diff --git a/pos_order_return/static/description/icon.png b/pos_order_return/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3134d33e23e7cade405a6aeae08b8939194c0437 GIT binary patch literal 7876 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 - + + + Partial Return Wizard + ir.actions.act_window + pos.partial.return.wizard + form + form + new + + pos.order @@ -34,4 +40,17 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + pos.order.line + + + + + + + + + + + diff --git a/pos_return_order/views/product_product_view.xml b/pos_order_return/views/product_product_view.xml similarity index 68% rename from pos_return_order/views/product_product_view.xml rename to pos_order_return/views/product_product_view.xml index 0638cd18..587a1b85 100644 --- a/pos_return_order/views/product_product_view.xml +++ b/pos_order_return/views/product_product_view.xml @@ -1,9 +1,6 @@ - + diff --git a/pos_order_return/wizard/__init__.py b/pos_order_return/wizard/__init__.py new file mode 100644 index 00000000..601ba34d --- /dev/null +++ b/pos_order_return/wizard/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import pos_partial_return_wizard diff --git a/pos_order_return/wizard/pos_partial_return_wizard.py b/pos_order_return/wizard/pos_partial_return_wizard.py new file mode 100644 index 00000000..63a209b2 --- /dev/null +++ b/pos_order_return/wizard/pos_partial_return_wizard.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +# Copyright 2016-2018 Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + + +class PosPartialReturnWizard(models.TransientModel): + _name = 'pos.partial.return.wizard' + + order_id = fields.Many2one( + comodel_name='pos.order', + string='Order to Return', + ) + line_ids = fields.One2many( + comodel_name='pos.partial.return.wizard.line', + inverse_name='wizard_id', + string='Lines to Return', + ) + + def confirm(self): + self.ensure_one() + return self[0].order_id.partial_refund(self[0]) + + @api.model + def default_get(self, fields): + order_obj = self.env['pos.order'] + res = super(PosPartialReturnWizard, self).default_get(fields) + order = order_obj.browse(self.env.context.get('active_id', False)) + if order: + line_ids = [] + for line in order.lines: + line_ids.append((0, 0, { + 'pos_order_line_id': line.id, + 'initial_qty': line.qty, + 'max_returnable_qty': line.max_returnable_qty([]), + })) + res.update({ + 'order_id': order.id, + 'line_ids': line_ids}) + return res + + +class PosPartialReturnWizardLine(models.TransientModel): + _name = 'pos.partial.return.wizard.line' + + wizard_id = fields.Many2one( + comodel_name='pos.partial.return.wizard', + string='Wizard', + ) + pos_order_line_id = fields.Many2one( + comodel_name='pos.order.line', + required=True, + readonly=True, + string='Line To Return', + ) + initial_qty = fields.Float( + string='Initial Quantity', + readonly=True, + help="Quantity of Product initially sold", + ) + max_returnable_qty = fields.Float( + string='Returnable Quantity', + readonly=True, + help="Compute maximum quantity that can be returned for this line, " + "depending of the quantity of the line and other possible " + "refunds.", + ) + qty = fields.Float( + string='Returned Quantity', + default=0.0, + ) diff --git a/pos_return_order/views/pos_partial_return_wizard_view.xml b/pos_order_return/wizard/pos_partial_return_wizard_view.xml similarity index 83% rename from pos_return_order/views/pos_partial_return_wizard_view.xml rename to pos_order_return/wizard/pos_partial_return_wizard_view.xml index 486b8a7a..9f2a3c59 100644 --- a/pos_return_order/views/pos_partial_return_wizard_view.xml +++ b/pos_order_return/wizard/pos_partial_return_wizard_view.xml @@ -1,9 +1,6 @@ - + diff --git a/pos_return_order/__openerp__.py b/pos_return_order/__openerp__.py deleted file mode 100644 index d483f52f..00000000 --- a/pos_return_order/__openerp__.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2016-Today: La Louve () -# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - -{ - 'name': 'Point of Sale Return Order', - 'version': '9.0.1.0.0', - 'category': 'Point Of Sale', - 'summary': 'Point of Sale Return Order', - 'author': 'La Louve, GRAP, Odoo Community Association (OCA)', - 'website': 'http://www.lalouve.net', - 'depends': [ - 'point_of_sale', - ], - 'data': [ - 'views/action.xml', - 'views/pos_order_view.xml', - 'views/pos_order_line_view.xml', - 'views/product_product_view.xml', - 'views/pos_partial_return_wizard_view.xml', - ], - 'demo': [ - 'demo/product_product.xml', - ], - 'installable': True, -} diff --git a/pos_return_order/models/__init__.py b/pos_return_order/models/__init__.py deleted file mode 100644 index e78bd216..00000000 --- a/pos_return_order/models/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- -from . import product_template -from . import pos_order -from . import pos_order_line -from . import pos_partial_return_wizard -from . import pos_partial_return_wizard_line diff --git a/pos_return_order/models/pos_order.py b/pos_return_order/models/pos_order.py deleted file mode 100644 index 353f68e3..00000000 --- a/pos_return_order/models/pos_order.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2016-Today: La Louve () -# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - -from openerp import fields, models, api -from openerp.addons import decimal_precision as dp - - -class PosOrder(models.Model): - _inherit = 'pos.order' - - # Column Section - returned_order_id = fields.Many2one( - comodel_name='pos.order', string='Returned Order', readonly=True) - - 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', - digits=dp.get_precision('Product Unit of Measure')) - - # Compute Section - @api.multi - def _compute_refund_order_qty(self): - for order in self: - order.refund_order_qty = len(order.refund_order_ids) - - @api.multi - def _blank_refund(self): - self.ensure_one() - - # Call super to use original refund algorithm (session management, ...) - ctx = self.env.context.copy() - ctx.update({'do_not_check_negative_qty': True}) - res = super(PosOrder, self.with_context(ctx)).refund() - - # Link Order - original_order = self[0] - new_order = self.browse(res['res_id']) - new_order.returned_order_id = original_order.id - - # Remove created lines and recreate and link Lines - new_order.lines.unlink() - return res, new_order - - # Action Section - @api.multi - def refund(self): - res, new_order = self._blank_refund() - - for line in self[0].lines: - qty = - line.max_returnable_qty([]) - if qty != 0: - copy_line = line.copy() - copy_line.write({ - 'order_id': new_order.id, - 'returned_line_id': line.id, - 'qty': qty, - }) - return res - - # Action Section - @api.multi - def partial_refund(self, partial_return_wizard): - res, new_order = self._blank_refund() - - for wizard_line in partial_return_wizard.line_ids: - qty = - wizard_line.qty - if qty != 0: - copy_line = wizard_line.pos_order_line_id.copy() - copy_line.write({ - 'order_id': new_order.id, - 'returned_line_id': wizard_line.pos_order_line_id.id, - 'qty': qty, - }) - return res diff --git a/pos_return_order/models/pos_order_line.py b/pos_return_order/models/pos_order_line.py deleted file mode 100644 index a800910c..00000000 --- a/pos_return_order/models/pos_order_line.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2016-Today: La Louve () -# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - -from openerp import fields, models, api -from openerp.exceptions import ValidationError -from openerp.tools.translate import _ - - -class PosOrderLine(models.Model): - _inherit = 'pos.order.line' - - # Column Section - returned_line_id = fields.Many2one( - comodel_name='pos.order.line', string='Returned Order', - readonly=True) - - refund_line_ids = fields.One2many( - comodel_name='pos.order.line', inverse_name='returned_line_id', - string='Refund Lines', readonly=True) - - # Compute Section - @api.model - def max_returnable_qty(self, ignored_line_ids): - qty = self.qty - for refund_line in self.refund_line_ids: - if refund_line.id not in ignored_line_ids: - qty += refund_line.qty - return qty - - # Constraint Section - @api.one - @api.constrains('returned_line_id', 'qty') - def _check_return_qty(self): - if self.env.context.get('do_not_check_negative_qty', False): - return True - if self.returned_line_id: - if - self.qty > self.returned_line_id.qty: - raise ValidationError(_( - "You can not return %d %s of %s because the original" - " Order line only mentions %d %s.") % ( - - self.qty, self.product_id.uom_id.name, - self.product_id.name, self.returned_line_id.qty, - self.product_id.uom_id.name)) - elif - self.qty >\ - self.returned_line_id.max_returnable_qty([self.id]): - raise ValidationError(_( - "You can not return %d %s of %s because some refunds" - " has been yet done.\n Maximum quantity allowed :" - " %d %s.") % ( - - self.qty, self.product_id.uom_id.name, - self.product_id.name, - self.returned_line_id.max_returnable_qty([self.id]), - self.product_id.uom_id.name)) - else: - if self.qty < 0 and\ - not self.product_id.product_tmpl_id.pos_allow_negative_qty: - raise ValidationError(_( - "For legal and traceability reasons, you can not set a" - " negative quantity (%d %s of %s), without using return" - " wizard.") % ( - self.qty, self.product_id.uom_id.name, - self.product_id.name)) diff --git a/pos_return_order/models/pos_partial_return_wizard.py b/pos_return_order/models/pos_partial_return_wizard.py deleted file mode 100644 index 49949287..00000000 --- a/pos_return_order/models/pos_partial_return_wizard.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2016-Today: La Louve () -# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from openerp import models, fields, api - - -class PosPartialReturnWizard(models.TransientModel): - _name = 'pos.partial.return.wizard' - - order_id = fields.Many2one( - comodel_name='pos.order', string='Order to Return') - - line_ids = fields.One2many( - comodel_name='pos.partial.return.wizard.line', - inverse_name='wizard_id', string='Lines to Return') - - @api.multi - def confirm(self): - self.ensure_one() - return self[0].order_id.partial_refund(self[0]) - - @api.model - def default_get(self, fields): - order_obj = self.env['pos.order'] - res = super(PosPartialReturnWizard, self).default_get(fields) - order = order_obj.browse(self.env.context.get('active_id', False)) - if order: - line_ids = [] - for line in order.lines: - line_ids.append((0, 0, { - 'pos_order_line_id': line.id, - 'initial_qty': line.qty, - 'max_returnable_qty': line.max_returnable_qty([]), - })) - res.update({ - 'order_id': order.id, - 'line_ids': line_ids}) - return res diff --git a/pos_return_order/models/pos_partial_return_wizard_line.py b/pos_return_order/models/pos_partial_return_wizard_line.py deleted file mode 100644 index 9dea2435..00000000 --- a/pos_return_order/models/pos_partial_return_wizard_line.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2016-Today: La Louve () -# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from openerp import fields, models - - -class PosPartialReturnWizardLine(models.TransientModel): - _name = 'pos.partial.return.wizard.line' - - wizard_id = fields.Many2one( - comodel_name='pos.partial.return.wizard', string='Wizard') - - pos_order_line_id = fields.Many2one( - comodel_name='pos.order.line', required=True, readonly=True, - string='Line To Return') - - initial_qty = fields.Float( - string='Initial Quantity', readonly=True, - help="Quantity of Product initially sold") - - max_returnable_qty = fields.Float( - string='Returnable Quantity', readonly=True, - help="Compute maximum quantity that can be returned for this line," - " depending of the quantity of the line and other possible refunds.") - - qty = fields.Float(string='Returned Quantity', default=0.0) diff --git a/pos_return_order/models/product_template.py b/pos_return_order/models/product_template.py deleted file mode 100644 index 0c2073b6..00000000 --- a/pos_return_order/models/product_template.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2016-Today: La Louve () -# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - -from openerp import fields, models - - -class ProductTemplate(models.Model): - _inherit = 'product.template' - - # Column Section - pos_allow_negative_qty = fields.Boolean( - string='Allow Negative Quantity on PoS') diff --git a/pos_return_order/static/description/icon.png b/pos_return_order/static/description/icon.png deleted file mode 100644 index ccb7888744085e1a02be7200662ed013b1d06bce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4697 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 bn=AYuME&c+LxdT;00000NkvXXu0mjfNOJ$l diff --git a/pos_return_order/views/action.xml b/pos_return_order/views/action.xml deleted file mode 100644 index 6ff589cd..00000000 --- a/pos_return_order/views/action.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - Partial Return Wizard - ir.actions.act_window - pos.partial.return.wizard - form - form - new - - - - diff --git a/pos_return_order/views/pos_order_line_view.xml b/pos_return_order/views/pos_order_line_view.xml deleted file mode 100644 index 669e9323..00000000 --- a/pos_return_order/views/pos_order_line_view.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - pos.order.line - - - - - - - - - - - -