From 6ebe757d5adb89c761b960321a1085ec0342f43d Mon Sep 17 00:00:00 2001 From: Jordi Ballester Date: Thu, 27 Jul 2017 18:17:19 +0200 Subject: [PATCH 01/93] init branch --- rma_account/README.rst | 51 +++++ rma_account/__init__.py | 5 + rma_account/__openerp__.py | 24 ++ rma_account/demo/rma_operation.xml | 44 ++++ rma_account/models/__init__.py | 7 + rma_account/models/invoice.py | 87 +++++++ rma_account/models/rma_operation.py | 13 ++ rma_account/models/rma_order.py | 145 ++++++++++++ rma_account/models/rma_order_line.py | 132 +++++++++++ rma_account/views/invoice_view.xml | 73 ++++++ rma_account/views/rma_operation_view.xml | 26 +++ rma_account/views/rma_order_line_view.xml | 89 ++++++++ rma_account/views/rma_order_view.xml | 68 ++++++ rma_account/wizards/__init__.py | 7 + rma_account/wizards/rma_add_invoice.py | 112 +++++++++ rma_account/wizards/rma_add_invoice.xml | 90 ++++++++ .../rma_order_line_make_supplier_rma.py | 19 ++ rma_account/wizards/rma_refund.py | 216 ++++++++++++++++++ rma_account/wizards/rma_refund.xml | 85 +++++++ 19 files changed, 1293 insertions(+) create mode 100644 rma_account/README.rst create mode 100644 rma_account/__init__.py create mode 100644 rma_account/__openerp__.py create mode 100644 rma_account/demo/rma_operation.xml create mode 100644 rma_account/models/__init__.py create mode 100644 rma_account/models/invoice.py create mode 100644 rma_account/models/rma_operation.py create mode 100644 rma_account/models/rma_order.py create mode 100644 rma_account/models/rma_order_line.py create mode 100644 rma_account/views/invoice_view.xml create mode 100644 rma_account/views/rma_operation_view.xml create mode 100644 rma_account/views/rma_order_line_view.xml create mode 100644 rma_account/views/rma_order_view.xml create mode 100644 rma_account/wizards/__init__.py create mode 100644 rma_account/wizards/rma_add_invoice.py create mode 100644 rma_account/wizards/rma_add_invoice.xml create mode 100644 rma_account/wizards/rma_order_line_make_supplier_rma.py create mode 100644 rma_account/wizards/rma_refund.py create mode 100644 rma_account/wizards/rma_refund.xml diff --git a/rma_account/README.rst b/rma_account/README.rst new file mode 100644 index 00000000..eadfe985 --- /dev/null +++ b/rma_account/README.rst @@ -0,0 +1,51 @@ +.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg + :alt: License LGPL-3 + +=========== +RMA Account +=========== + +This module integrates Return Merchandise Authorizations (RMA) with invoices, + allowing to: + +#. Create complete RMA's using existing invoices as a reference. +#. Create refunds from RMA. + +Usage +===== + +RMA are accessible though Inventory menu. There's four menus, divided by type +. Users can access to the list of RMA or RMA lines. + +Create an RMA: +#. Select a partner. Fill the rma lines by selecting an invoice. +#. Request approval and approve. +#. Click on RMA Lines button. +#. Click on more and select an option: "Receive products", "Create Delivery + Order, Create Refund". +#. Go back to the RMA. Set the RMA to done if not further action is required. + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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. + + +Credits +======= + +Contributors +------------ + +* Jordi Ballester Alomar +* Aaron Henriquez + + +Maintainer +---------- + +This module is maintained by Eficent. diff --git a/rma_account/__init__.py b/rma_account/__init__.py new file mode 100644 index 00000000..4105ff51 --- /dev/null +++ b/rma_account/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from . import models +from . import wizards diff --git a/rma_account/__openerp__.py b/rma_account/__openerp__.py new file mode 100644 index 00000000..43522ee7 --- /dev/null +++ b/rma_account/__openerp__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +{ + 'name': 'RMA Account', + 'version': '9.0.1.0.0', + 'license': 'LGPL-3', + 'category': 'RMA', + 'summary': 'Integrates RMA with Invoice Processing', + 'author': "Eficent", + 'website': 'http://www.github.com/OCA/rma', + 'depends': ['account', 'rma'], + 'demo': ['demo/rma_operation.xml'], + 'data': ['views/rma_order_view.xml', + 'views/rma_operation_view.xml', + 'views/rma_order_line_view.xml', + 'views/invoice_view.xml', + 'wizards/rma_add_invoice.xml', + 'wizards/rma_refund.xml', + ], + 'installable': True, + 'auto_install': True, +} diff --git a/rma_account/demo/rma_operation.xml b/rma_account/demo/rma_operation.xml new file mode 100644 index 00000000..a312d6db --- /dev/null +++ b/rma_account/demo/rma_operation.xml @@ -0,0 +1,44 @@ + + + + + no + + + + no + + + + Refund before receive + RFC + ordered + no + no + customer + + + + + Refund Before deliver + RFS + ordered + no + no + supplier + + + + + no + + + + no + + + + no + + + diff --git a/rma_account/models/__init__.py b/rma_account/models/__init__.py new file mode 100644 index 00000000..90fbe336 --- /dev/null +++ b/rma_account/models/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from . import rma_order +from . import rma_order_line +from . import rma_operation +from . import invoice diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py new file mode 100644 index 00000000..9f33a501 --- /dev/null +++ b/rma_account/models/invoice.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from openerp import api, fields, models + + +class AccountInvoice(models.Model): + + _inherit = "account.invoice" + + @api.one + def _compute_rma_count(self): + rma_list = [] + for invl in self.invoice_line_ids: + for rmal in invl.rma_line_ids: + rma_list.append(rmal.rma_id.id) + self.rma_count = len(list(set(rma_list))) + + rma_count = fields.Integer(compute=_compute_rma_count, + string='# of RMA', + copy=False) + + @api.multi + def action_view_rma_supplier(self): + action = self.env.ref('rma.action_rma_supplier') + result = action.read()[0] + rma_list = [] + for invl in self.invoice_line_ids: + for rmal in invl.rma_line_ids: + rma_list.append(rmal.rma_id.id) + self.rma_count = len(list(set(rma_list))) + # choose the view_mode accordingly + if len(rma_list) != 1: + result['domain'] = "[('id', 'in', " + \ + str(rma_list) + ")]" + elif len(rma_list) == 1: + res = self.env.ref('rma.view_rma_supplier_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = rma_list[0] + return result + + @api.multi + def action_view_rma(self): + action = self.env.ref('rma.action_rma_customer') + result = action.read()[0] + rma_list = [] + for invl in self.invoice_line_ids: + for rmal in invl.rma_line_ids: + rma_list.append(rmal.rma_id.id) + self.rma_count = len(list(set(rma_list))) + # choose the view_mode accordingly + if len(rma_list) != 1: + result['domain'] = "[('id', 'in', " + \ + str(rma_list) + ")]" + elif len(rma_list) == 1: + res = self.env.ref('rma.view_rma_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = rma_list[0] + return result + + +class AccountInvoiceLine(models.Model): + + _inherit = "account.invoice.line" + + @api.multi + def _compute_rma_count(self): + rma_list = [] + for invl in self: + for rmal in invl.rma_line_ids: + rma_list.append(rmal.rma_id.id) + invl.rma_count = len(list(set(rma_list))) + + rma_count = fields.Integer(compute=_compute_rma_count, + string='# of RMA', + copy=False) + rma_line_ids = fields.One2many( + comodel_name='rma.order.line', inverse_name='invoice_line_id', + string="RMA", readonly=True, + help="This will contain the RMA lines for the invoice line") + + rma_line_id = fields.Many2one( + comodel_name='rma.order.line', + string="RMA line refund", + ondelete="set null", + help="This will contain the rma line that originated the refund line") diff --git a/rma_account/models/rma_operation.py b/rma_account/models/rma_operation.py new file mode 100644 index 00000000..a42c69c7 --- /dev/null +++ b/rma_account/models/rma_operation.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from openerp import _, api, fields, models + + +class RmaOperation(models.Model): + _inherit = 'rma.operation' + + refund_policy = fields.Selection([ + ('no', 'No refund'), ('ordered', 'Based on Ordered Quantities'), + ('received', 'Based on Received Quantities')], string="Refund Policy", + default='no') diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py new file mode 100644 index 00000000..fdcba820 --- /dev/null +++ b/rma_account/models/rma_order.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from openerp import _, api, fields, models +from openerp.addons import decimal_precision as dp +from openerp.exceptions import UserError +from dateutil.relativedelta import relativedelta +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT +from datetime import datetime + + +class RmaOrder(models.Model): + _inherit = "rma.order" + + @api.multi + def _compute_invoice_refund_count(self): + self.ensure_one() + invoice_list = [] + for line in self.rma_line_ids: + for refund in line.refund_line_ids: + invoice_list.append(refund.invoice_id.id) + self.invoice_refund_count = len(list(set(invoice_list))) + + @api.multi + def _compute_invoice_count(self): + self.ensure_one() + invoice_list = [] + for line in self.rma_line_ids: + if line.invoice_line_id and line.invoice_line_id.id: + invoice_list.append(line.invoice_line_id.invoice_id.id) + self.invoice_count = len(list(set(invoice_list))) + + add_invoice_id = fields.Many2one('account.invoice', string='Add Invoice', + ondelete='set null', readonly=True, + states={'draft': [('readonly', False)]}) + invoice_refund_count = fields.Integer( + compute=_compute_invoice_refund_count, + string='# of Refunds', + copy=False) + invoice_count = fields.Integer(compute=_compute_invoice_count, + string='# of Incoming Shipments', + copy=False) + + def _prepare_rma_line_from_inv_line(self, line): + operation = line.product_id.rma_operation_id and \ + line.product_id.rma_operation_id.id or False + if not operation: + operation = line.product_id.categ_id.rma_operation_id and \ + line.product_id.categ_id.rma_operation_id.id or False + data = { + 'invoice_line_id': line.id, + 'product_id': line.product_id.id, + 'name': line.name, + 'origin': line.invoice_id.number, + 'uom_id': line.uom_id.id, + 'operation_id': operation, + 'product_qty': line.quantity, + 'price_unit': line.invoice_id.currency_id.compute( + line.price_unit, line.currency_id, round=False), + 'rma_id': self._origin.id + } + return data + + @api.onchange('add_invoice_id') + def on_change_invoice(self): + if not self.add_invoice_id: + return {} + if not self.partner_id: + self.partner_id = self.add_invoice_id.partner_id.id + new_lines = self.env['rma.order.line'] + for line in self.add_invoice_id.invoice_line_ids: + # Load a PO line only once + if line in self.rma_line_ids.mapped('invoice_line_id'): + continue + data = self._prepare_rma_line_from_inv_line(line) + new_line = new_lines.new(data) + new_lines += new_line + + self.rma_line_ids += new_lines + self.date_rma = fields.Datetime.now() + self.delivery_address_id = self.add_invoice_id.partner_id.id + self.invoice_address_id = self.add_invoice_id.partner_id.id + self.add_invoice_id = False + return {} + + @api.model + def prepare_rma_line(self, origin_rma, rma_id, line): + line_values = super(RmaOrder, self).prepare_rma_line( + origin_rma, rma_id, line) + line_values['invoice_address_id'] = line.invoice_address_id.id + return line_values + + @api.model + def _prepare_rma_data(self, partner, origin_rma): + res = super(RmaOrder, self)._prepare_rma_data(partner, origin_rma) + res['invoice_address_id'] = partner.id + return res + + @api.multi + def action_view_invoice_refund(self): + """ + This function returns an action that display existing vendor refund + bills of given purchase order id. + When only one found, show the vendor bill immediately. + """ + action = self.env.ref('account.action_invoice_tree2') + result = action.read()[0] + invoice_list = [] + for line in self.rma_line_ids: + for refund in line.refund_line_ids: + invoice_list.append(refund.invoice_id.id) + invoice_ids = list(set(invoice_list)) + # choose the view_mode accordingly + if len(invoice_ids) != 1: + result['domain'] = "[('id', 'in', " + \ + str(invoice_ids) + ")]" + elif len(invoice_ids) == 1: + res = self.env.ref('account.invoice_supplier_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = invoice_ids[0] + return result + + @api.multi + def action_view_invoice(self): + if self.type == "supplier": + action = self.env.ref('account.action_invoice_tree2') + else: + action = self.env.ref('account.action_invoice_tree') + result = action.read()[0] + invoice_list = [] + for line in self.rma_line_ids: + invoice_list.append(line.invoice_id.id) + invoice_ids = list(set(invoice_list)) + # choose the view_mode accordingly + if len(invoice_ids) != 1: + result['domain'] = "[('id', 'in', " + \ + str(invoice_ids) + ")]" + elif len(invoice_ids) == 1: + if self.type == "supplier": + res = self.env.ref('account.invoice_supplier_form', False) + else: + res = self.env.ref('account.invoice_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = invoice_ids[0] + return result diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py new file mode 100644 index 00000000..9f396edd --- /dev/null +++ b/rma_account/models/rma_order_line.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from openerp import _, api, fields, models +from openerp.addons import decimal_precision as dp +from openerp.exceptions import UserError + + +class RmaOrderLine(models.Model): + _inherit = "rma.order.line" + + @api.model + def _default_invoice_address(self): + partner_id = self.env.context.get('partner_id', False) + if partner_id: + return self.env['res.partner'].browse(partner_id) + return False + + @api.multi + @api.depends('refund_line_ids', 'refund_line_ids.invoice_id.state', + 'refund_policy', 'type') + def _compute_qty_refunded(self): + for rec in self: + rec.qty_refunded = sum(rec.refund_line_ids.filtered( + lambda i: i.invoice_id.state in ('open', 'paid')).mapped( + 'quantity')) + + @api.one + @api.depends('refund_line_ids', 'refund_line_ids.invoice_id.state', + 'refund_policy', 'move_ids', 'move_ids.state', 'type') + def _compute_qty_to_refund(self): + qty = 0.0 + if self.refund_policy == 'ordered': + qty = self.product_qty - self.qty_refunded + elif self.refund_policy == 'received': + qty = self.qty_received - self.qty_refunded + self.qty_to_refund = qty + + @api.multi + def _compute_refund_count(self): + for rec in self: + rec.refund_count = len(rec.refund_line_ids.mapped('invoice_id')) + + invoice_address_id = fields.Many2one( + 'res.partner', string='Partner invoice address', + default=_default_invoice_address, + help="Invoice address for current rma order.") + + refund_count = fields.Integer(compute=_compute_refund_count, + string='# of Refunds', copy=False, default=0) + + invoice_line_id = fields.Many2one('account.invoice.line', + string='Invoice Line', + ondelete='restrict', + index=True) + refund_line_ids = fields.One2many(comodel_name='account.invoice.line', + inverse_name='rma_line_id', + string='Refund Lines', + copy=False, index=True, readonly=True) + invoice_id = fields.Many2one('account.invoice', string='Source', + related='invoice_line_id.invoice_id', + index=True, readonly=True) + refund_policy = fields.Selection([ + ('no', 'No refund'), ('ordered', 'Based on Ordered Quantities'), + ('received', 'Based on Received Quantities')], string="Refund Policy", + required=True, default='no') + qty_to_refund = fields.Float( + string='Qty To Refund', copy=False, + digits=dp.get_precision('Product Unit of Measure'), readonly=True, + compute=_compute_qty_to_refund, store=True) + qty_refunded = fields.Float( + string='Qty Refunded', copy=False, + digits=dp.get_precision('Product Unit of Measure'), + readonly=True, compute=_compute_qty_refunded, store=True) + + @api.onchange('operation_id') + def _onchange_operation_id(self): + result = super(RmaOrderLine, self)._onchange_operation_id() + if not self.operation_id: + return result + self.refund_policy = self.operation_id.refund_policy + return result + + @api.onchange('invoice_line_id') + def _onchange_invoice_line_id(self): + result = {} + if not self.invoice_line_id: + return result + self.origin = self.invoice_id.number + return result + + @api.multi + @api.constrains('invoice_line_id') + def _check_duplicated_lines(self): + for line in self: + matching_inv_lines = self.env['account.invoice.line'].search([( + 'id', '=', line.invoice_line_id.id)]) + if len(matching_inv_lines) > 1: + raise UserError( + _("There's an rma for the invoice line %s " + "and invoice %s" % + (line.invoice_line_id, + line.invoice_line_id.invoice_id))) + return {} + + @api.multi + def action_view_invoice(self): + action = self.env.ref('account.action_invoice_tree') + result = action.read()[0] + res = self.env.ref('account.invoice_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['view_id'] = res and res.id or False + result['res_id'] = self.invoice_line_id.invoice_id.id + + return result + + @api.multi + def action_view_refunds(self): + action = self.env.ref('account.action_invoice_tree2') + result = action.read()[0] + invoice_ids = [] + for inv_line in self.refund_line_ids: + invoice_ids.append(inv_line.invoice_id.id) + # choose the view_mode accordingly + if len(invoice_ids) != 1: + result['domain'] = "[('id', 'in', " + \ + str(invoice_ids) + ")]" + elif len(invoice_ids) == 1: + res = self.env.ref('account.invoice_supplier_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = invoice_ids[0] + return result diff --git a/rma_account/views/invoice_view.xml b/rma_account/views/invoice_view.xml new file mode 100644 index 00000000..647c5043 --- /dev/null +++ b/rma_account/views/invoice_view.xml @@ -0,0 +1,73 @@ + + + + + + account.invoice.form + account.invoice + + + +
+ +
+
+
+
+ + + account.invoice.supplier.form + account.invoice + + + +
+ +
+
+
+
+ + + rma.invoice.line.form + account.invoice.line + + + + + + + + + + + + + + + + +
+ + + Invoice Line + account.invoice.line + form + form + + + +
diff --git a/rma_account/views/rma_operation_view.xml b/rma_account/views/rma_operation_view.xml new file mode 100644 index 00000000..671a2a0e --- /dev/null +++ b/rma_account/views/rma_operation_view.xml @@ -0,0 +1,26 @@ + + + + + rma.operation.tree + rma.operation + + + + + + + + + + rma.operation.form + rma.operation + + + + + + + + + diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml new file mode 100644 index 00000000..0e8ba106 --- /dev/null +++ b/rma_account/views/rma_order_line_view.xml @@ -0,0 +1,89 @@ + + + + + rma.order.line.supplier.form + rma.order.line + + + + + + + + + + + + + + + + + + + + + + + + + + + rma.order.line.form + rma.order.line + + + + + + + + + + + + + + + + + + + + + + + + + + + rma.order.line.select + rma.order.line + + + + + + + + + + diff --git a/rma_account/views/rma_order_view.xml b/rma_account/views/rma_order_view.xml new file mode 100644 index 00000000..3e568fb4 --- /dev/null +++ b/rma_account/views/rma_order_view.xml @@ -0,0 +1,68 @@ + + + + + + rma.order.form + rma.order + + + + + + + + + + + rma.order.supplier.form + rma.order + + + + + + + + + + + diff --git a/rma_account/wizards/__init__.py b/rma_account/wizards/__init__.py new file mode 100644 index 00000000..0e1ebd69 --- /dev/null +++ b/rma_account/wizards/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from . import rma_refund +from . import rma_add_invoice +from . import rma_order_line_make_supplier_rma diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py new file mode 100644 index 00000000..45a7e662 --- /dev/null +++ b/rma_account/wizards/rma_add_invoice.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +import time +from openerp import models, fields, exceptions, api, _ +from openerp.exceptions import ValidationError +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DT_FORMAT +import openerp.addons.decimal_precision as dp + + +class RmaAddinvoice(models.TransientModel): + _name = 'rma_add_invoice' + _description = 'Wizard to add rma lines' + + @api.model + def default_get(self, fields): + res = super(RmaAddinvoice, self).default_get(fields) + rma_obj = self.env['rma.order'] + rma_id = self.env.context['active_ids'] or [] + active_model = self.env.context['active_model'] + if not rma_id: + return res + assert active_model == 'rma.order', 'Bad context propagation' + + rma = rma_obj.browse(rma_id) + res['rma_id'] = rma.id + res['partner_id'] = rma.partner_id.id + res['invoice_id'] = False + res['invoice_line_ids'] = False + return res + + rma_id = fields.Many2one('rma.order', string='RMA Order', readonly=True, + ondelete='cascade') + partner_id = fields.Many2one(comodel_name='res.partner', string='Partner', + readonly=True) + invoice_id = fields.Many2one(comodel_name='account.invoice', + string='Invoice') + invoice_line_ids = fields.Many2many('account.invoice.line', + 'rma_add_invoice_add_line_rel', + 'invoice_line_id', + 'rma_add_invoice_id', + string='Invoice Lines') + + def _prepare_rma_line_from_inv_line(self, line): + operation = line.product_id.rma_operation_id or \ + line.product_id.categ_id.rma_operation_id + data = { + 'invoice_line_id': line.id, + 'product_id': line.product_id.id, + 'origin': line.invoice_id.number, + 'uom_id': line.uom_id.id, + 'operation_id': operation.id, + 'product_qty': line.quantity, + 'price_unit': line.invoice_id.currency_id.compute( + line.price_unit, line.currency_id, round=False), + 'delivery_address_id': self.invoice_id.partner_id.id, + 'invoice_address_id': self.invoice_id.partner_id.id, + 'rma_id': self.rma_id.id + } + if not operation: + operation = self.env['rma.operation'].search( + [('type', '=', self.rma_id.type)], limit=1) + if not operation: + raise ValidationError("Please define an operation first") + if not operation.in_route_id or not operation.out_route_id: + route = self.env['stock.location.route'].search( + [('rma_selectable', '=', True)], limit=1) + if not route: + raise ValidationError("Please define an rma route") + data.update( + {'in_route_id': operation.in_route_id.id, + 'out_route_id': operation.out_route_id.id, + 'in_warehouse_id': operation.in_warehouse_id.id, + 'out_warehouse_id': operation.out_warehouse_id.id, + 'receipt_policy': operation.receipt_policy, + 'location_id': operation.location_id.id, + 'operation_id': operation.id, + 'refund_policy': operation.refund_policy, + 'delivery_policy': operation.delivery_policy + }) + return data + + @api.model + def _get_rma_data(self): + data = { + 'date_rma': fields.Datetime.now(), + 'delivery_address_id': self.invoice_id.partner_id.id, + 'invoice_address_id': self.invoice_id.partner_id.id + } + return data + + @api.model + def _get_existing_invoice_lines(self): + existing_invoice_lines = [] + for rma_line in self.rma_id.rma_line_ids: + existing_invoice_lines.append(rma_line.invoice_line_id) + return existing_invoice_lines + + @api.multi + def add_lines(self): + rma_line_obj = self.env['rma.order.line'] + existing_invoice_lines = self._get_existing_invoice_lines() + for line in self.invoice_line_ids: + # Load a PO line only once + if line not in existing_invoice_lines: + data = self._prepare_rma_line_from_inv_line(line) + rma_line_obj.create(data) + rma = self.rma_id + data_rma = self._get_rma_data() + rma.write(data_rma) + return {'type': 'ir.actions.act_window_close'} diff --git a/rma_account/wizards/rma_add_invoice.xml b/rma_account/wizards/rma_add_invoice.xml new file mode 100644 index 00000000..83446712 --- /dev/null +++ b/rma_account/wizards/rma_add_invoice.xml @@ -0,0 +1,90 @@ + + + + + rma.add.invoice + rma_add_invoice + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + Add Invoice + ir.actions.act_window + rma_add_invoice + rma.order + form + form + new + + + + + + + rma.order.line.form + rma.order + + + + + + + + rma.order.line.supplier.form + rma.order + + + + + + + +
diff --git a/rma_account/wizards/rma_order_line_make_supplier_rma.py b/rma_account/wizards/rma_order_line_make_supplier_rma.py new file mode 100644 index 00000000..9315161a --- /dev/null +++ b/rma_account/wizards/rma_order_line_make_supplier_rma.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). + +import openerp.addons.decimal_precision as dp +from openerp import _, api, exceptions, fields, models + + +class RmaLineMakeSupplierRma(models.TransientModel): + _inherit = "rma.order.line.make.supplier.rma" + + @api.model + def _prepare_supplier_rma_line(self, rma, item): + res = super(RmaLineMakeSupplierRma, self)._prepare_supplier_rma_line( + rma, item) + if res['operation_id']: + operation = self.env['rma.operation'].browse(res['operation_id']) + res['refund_policy'] = operation.refund_policy + return res diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py new file mode 100644 index 00000000..1b76ee9e --- /dev/null +++ b/rma_account/wizards/rma_refund.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from openerp import models, fields, exceptions, api, _ +import openerp.addons.decimal_precision as dp + + +class RmaRefund(models.TransientModel): + _name = "rma.refund" + + @api.model + def _get_reason(self): + context = dict(self._context or {}) + active_ids = context.get('active_ids', False) + if active_ids: + rma_lines = self.env['rma.order.line'].browse(active_ids[0]) + return rma_lines.rma_id.name + return '' + + @api.returns('rma.order.line') + def _prepare_item(self, line): + values = {'product_id': line.product_id.id, + 'name': line.name, + 'product_qty': line.product_qty, + 'uom_id': line.uom_id.id, + 'qty_to_refund': line.qty_to_refund, + 'refund_policy': line.refund_policy, + 'invoice_address_id': line.invoice_address_id.id, + 'line_id': line.id, + 'rma_id': line.rma_id.id, + 'wiz_id': self.env.context['active_id']} + return values + + @api.model + def default_get(self, fields): + """Default values for wizard, if there is more than one supplier on + lines the supplier field is empty otherwise is the unique line + supplier. + """ + res = super(RmaRefund, self).default_get( + fields) + rma_line_obj = self.env['rma.order.line'] + rma_line_ids = self.env.context['active_ids'] or [] + active_model = self.env.context['active_model'] + + if not rma_line_ids: + return res + assert active_model == 'rma.order.line', \ + 'Bad context propagation' + + items = [] + lines = rma_line_obj.browse(rma_line_ids) + if len(lines.mapped('partner_id')) > 1: + raise exceptions.Warning( + _('Only RMA lines from the same partner can be processed at ' + 'the same time')) + for line in lines: + items.append([0, 0, self._prepare_item(line)]) + res['item_ids'] = items + return res + + date_invoice = fields.Date(string='Refund Date', + default=fields.Date.context_today, + required=True) + date = fields.Date(string='Accounting Date') + description = fields.Char(string='Reason', required=True, + default=_get_reason) + item_ids = fields.One2many( + 'rma.refund.item', + 'wiz_id', string='Items') + + @api.multi + def compute_refund(self): + for wizard in self: + first = self.item_ids[0] + values = self._prepare_refund(wizard, first.rma_id) + if len(first.line_id.invoice_address_id): + values['partner_id'] = first.line_id.invoice_address_id.id + else: + values['partner_id'] = first.rma_id.partner_id.id + new_refund = self.env['account.invoice'].create(values) + for item in self.item_ids: + refund_line_values = self.prepare_refund_line(item, new_refund) + self.env['account.invoice.line'].create( + refund_line_values) + # Put the reason in the chatter + subject = _("Invoice refund") + body = self.item_ids[0].rma_id.name + new_refund.message_post(body=body, subject=subject) + return new_refund + + @api.multi + def invoice_refund(self): + rma_line_ids = self.env['rma.order.line'].browse( + self.env.context['active_ids']) + for line in rma_line_ids: + if line.refund_policy == 'no': + raise exceptions.Warning( + _('The operation is not refund for at least one line')) + if line.state != 'approved': + raise exceptions.Warning( + _('RMA %s is not approved') % + line.rma_id.name) + new_invoice = self.compute_refund() + action = 'action_invoice_tree1' if ( + new_invoice.type in ['out_refund', 'out_invoice']) \ + else 'action_invoice_tree2' + result = self.env.ref('account.%s' % action).read()[0] + invoice_domain = eval(result['domain']) + invoice_domain.append(('id', '=', new_invoice.id)) + result['domain'] = invoice_domain + return result + + @api.model + def prepare_refund_line(self, item, refund): + accounts = item.product_id.product_tmpl_id._get_product_accounts() + if item.line_id.type == 'customer': + account = accounts['stock_output'] + else: + account = accounts['stock_input'] + if not account: + raise exceptions.ValidationError("Accounts are not configure for " + "this product") + values = { + 'name': item.rma_id.name, + 'origin': item.rma_id.name, + 'account_id': account.id, + 'price_unit': item.line_id.price_unit, + 'uom_id': item.line_id.uom_id.id, + 'product_id': item.product_id.id, + 'rma_line_id': item.line_id.id, + 'quantity': item.qty_to_refund, + 'invoice_id': refund.id + } + return values + + @api.model + def _prepare_refund(self, wizard, order): + # origin_invoices = self._get_invoice(order) + if order.type == 'customer': + journal = self.env['account.journal'].search( + [('type', '=', 'sale')], limit=1) + else: + journal = self.env['account.journal'].search( + [('type', '=', 'purchase')], limit=1) + values = { + 'name': order.name, + 'origin': order.name, + 'reference': False, + # 'account_id': account.id, + 'journal_id': journal.id, + 'partner_id': order.partner_id.id, + 'currency_id': order.partner_id.company_id.currency_id.id, + 'payment_term_id': False, + 'fiscal_position_id': + order.partner_id.property_account_position_id.id, + } + team_ids = self.env['crm.team'].search( + ['|', ('user_id', '=', self.env.uid), + ('member_ids', '=', self.env.uid)], limit=1) + team_id = team_ids[0] if team_ids else False + if team_id: + values['team_id'] = team_id.id + if order.type == 'customer': + values['type'] = 'out_refund' + else: + values['type'] = 'in_refund' + values['state'] = 'draft' + values['number'] = False + values['date'] = wizard.date_invoice + values['date_invoice'] = wizard.date or wizard.date_invoice + return values + + @api.constrains('item_ids') + @api.one + def check_unique_invoice_address_id(self): + addresses = self.item_ids.mapped('invoice_address_id') + if len(addresses) > 1: + raise exceptions.ValidationError('The invoice address must be the ' + 'same for all the lines') + return True + + +class RmaRefundItem(models.TransientModel): + _name = "rma.refund.item" + _description = "RMA Lines to refund" + + wiz_id = fields.Many2one( + 'rma.refund', + string='Wizard', required=True) + line_id = fields.Many2one('rma.order.line', + string='RMA order Line', + required=True, + readonly=True, + ondelete='cascade') + rma_id = fields.Many2one('rma.order', + related='line_id.rma_id', + string='RMA', + readonly=True) + product_id = fields.Many2one('product.product', string='Product', + readonly=True) + name = fields.Char(string='Description', required=True) + product_qty = fields.Float( + string='Quantity Ordered', copy=False, + digits=dp.get_precision('Product Unit of Measure'), + readonly=True) + invoice_address_id = fields.Many2one('res.partner', 'Invoice Address') + qty_to_refund = fields.Float( + string='Quantity To Refund', + digits=dp.get_precision('Product Unit of Measure')) + uom_id = fields.Many2one('product.uom', string='Unit of Measure', + readonly=True) + refund_policy = fields.Selection([ + ('no', 'Not required'), ('ordered', 'Based on Ordered Quantities'), + ('received', 'Based on Received Quantities')], + string="Refund Policy") diff --git a/rma_account/wizards/rma_refund.xml b/rma_account/wizards/rma_refund.xml new file mode 100644 index 00000000..a2363c48 --- /dev/null +++ b/rma_account/wizards/rma_refund.xml @@ -0,0 +1,85 @@ + + + + + + rma.refund.form + rma.refund + +
+ + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + Create Refund + rma.refund + form + tree,form + + + new + + + + rma.order.line.form + rma.order.line + + +
+
+
+
+ + + rma.order.line.supplier.form + rma.order.line + + +
+
+
+
+ + + + Create Refund + client_action_multi + + action + rma.order.line + + +
+
From 73a4369c39f5632c16de1727af19d7ff2d92fc0d Mon Sep 17 00:00:00 2001 From: lreficent Date: Wed, 2 Aug 2017 17:05:58 +0200 Subject: [PATCH 02/93] [9.0][FIX] rma: * fix assignment of moves. * default qty in rma lines. * remove account dependency. * test and flake8 fixes. --- rma_account/models/rma_operation.py | 2 +- rma_account/models/rma_order.py | 7 +------ rma_account/wizards/rma_add_invoice.py | 4 +--- rma_account/wizards/rma_order_line_make_supplier_rma.py | 2 +- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/rma_account/models/rma_operation.py b/rma_account/models/rma_operation.py index a42c69c7..201d1f46 100644 --- a/rma_account/models/rma_operation.py +++ b/rma_account/models/rma_operation.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import _, api, fields, models +from openerp import fields, models class RmaOperation(models.Model): diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index fdcba820..10ca3d08 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -1,12 +1,7 @@ # -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import _, api, fields, models -from openerp.addons import decimal_precision as dp -from openerp.exceptions import UserError -from dateutil.relativedelta import relativedelta -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT -from datetime import datetime +from openerp import api, fields, models class RmaOrder(models.Model): diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index 45a7e662..a81d1098 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -3,10 +3,8 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) import time -from openerp import models, fields, exceptions, api, _ +from openerp import _, api, fields, models from openerp.exceptions import ValidationError -from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DT_FORMAT -import openerp.addons.decimal_precision as dp class RmaAddinvoice(models.TransientModel): diff --git a/rma_account/wizards/rma_order_line_make_supplier_rma.py b/rma_account/wizards/rma_order_line_make_supplier_rma.py index 9315161a..3f798c67 100644 --- a/rma_account/wizards/rma_order_line_make_supplier_rma.py +++ b/rma_account/wizards/rma_order_line_make_supplier_rma.py @@ -3,7 +3,7 @@ # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). import openerp.addons.decimal_precision as dp -from openerp import _, api, exceptions, fields, models +from openerp import api, models class RmaLineMakeSupplierRma(models.TransientModel): From 7e290b9a9a9ac6e16e9d64d955afe80e31a86adb Mon Sep 17 00:00:00 2001 From: aheficent Date: Wed, 16 Aug 2017 12:52:35 +0200 Subject: [PATCH 03/93] [IMP] default operation in product and product_categ for customer and supplier [IMP]Separate menus for customer and supplier operations * Add active field to rma operation * Added tests * Fix travis * Fix create supplier rma from customer rma --- rma_account/models/rma_order.py | 35 +++++------ rma_account/views/rma_order_line_view.xml | 4 +- rma_account/wizards/rma_add_invoice.py | 49 +++++++++------ rma_account/wizards/rma_add_invoice.xml | 61 ++++++++++++++++--- .../rma_order_line_make_supplier_rma.py | 1 - rma_account/wizards/rma_refund.py | 2 +- 6 files changed, 104 insertions(+), 48 deletions(-) diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index 10ca3d08..ff751945 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -9,21 +9,21 @@ class RmaOrder(models.Model): @api.multi def _compute_invoice_refund_count(self): - self.ensure_one() - invoice_list = [] - for line in self.rma_line_ids: - for refund in line.refund_line_ids: - invoice_list.append(refund.invoice_id.id) - self.invoice_refund_count = len(list(set(invoice_list))) + for rec in self: + invoice_list = [] + for line in rec.rma_line_ids: + for refund in line.refund_line_ids: + invoice_list.append(refund.invoice_id.id) + rec.invoice_refund_count = len(list(set(invoice_list))) @api.multi def _compute_invoice_count(self): - self.ensure_one() - invoice_list = [] - for line in self.rma_line_ids: - if line.invoice_line_id and line.invoice_line_id.id: - invoice_list.append(line.invoice_line_id.invoice_id.id) - self.invoice_count = len(list(set(invoice_list))) + for rec in self: + invoice_list = [] + for line in rec.rma_line_ids: + if line.invoice_line_id and line.invoice_line_id.id: + invoice_list.append(line.invoice_line_id.invoice_id.id) + rec.invoice_count = len(list(set(invoice_list))) add_invoice_id = fields.Many2one('account.invoice', string='Add Invoice', ondelete='set null', readonly=True, @@ -37,11 +37,12 @@ class RmaOrder(models.Model): copy=False) def _prepare_rma_line_from_inv_line(self, line): - operation = line.product_id.rma_operation_id and \ - line.product_id.rma_operation_id.id or False - if not operation: - operation = line.product_id.categ_id.rma_operation_id and \ - line.product_id.categ_id.rma_operation_id.id or False + if self.type == 'customer': + operation = self.product_id.rma_customer_operation_id or \ + self.product_id.categ_id.rma_customer_operation_id + else: + operation = self.product_id.rma_supplier_operation_id or \ + self.product_id.categ_id.rma_supplier_operation_id data = { 'invoice_line_id': line.id, 'product_id': line.product_id.id, diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index 0e8ba106..ed32313c 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -28,7 +28,7 @@ - + @@ -64,7 +64,7 @@ - + diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index a81d1098..7efdc21c 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -2,8 +2,7 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -import time -from openerp import _, api, fields, models +from openerp import api, fields, models from openerp.exceptions import ValidationError @@ -20,11 +19,9 @@ class RmaAddinvoice(models.TransientModel): if not rma_id: return res assert active_model == 'rma.order', 'Bad context propagation' - rma = rma_obj.browse(rma_id) res['rma_id'] = rma.id res['partner_id'] = rma.partner_id.id - res['invoice_id'] = False res['invoice_line_ids'] = False return res @@ -32,8 +29,6 @@ class RmaAddinvoice(models.TransientModel): ondelete='cascade') partner_id = fields.Many2one(comodel_name='res.partner', string='Partner', readonly=True) - invoice_id = fields.Many2one(comodel_name='account.invoice', - string='Invoice') invoice_line_ids = fields.Many2many('account.invoice.line', 'rma_add_invoice_add_line_rel', 'invoice_line_id', @@ -41,8 +36,12 @@ class RmaAddinvoice(models.TransientModel): string='Invoice Lines') def _prepare_rma_line_from_inv_line(self, line): - operation = line.product_id.rma_operation_id or \ - line.product_id.categ_id.rma_operation_id + if self.env.context.get('customer'): + operation = line.product_id.rma_customer_operation_id or \ + line.product_id.categ_id.rma_customer_operation_id + else: + operation = line.product_id.rma_supplier_operation_id or \ + line.product_id.categ_id.rma_supplier_operation_id data = { 'invoice_line_id': line.id, 'product_id': line.product_id.id, @@ -52,8 +51,8 @@ class RmaAddinvoice(models.TransientModel): 'product_qty': line.quantity, 'price_unit': line.invoice_id.currency_id.compute( line.price_unit, line.currency_id, round=False), - 'delivery_address_id': self.invoice_id.partner_id.id, - 'invoice_address_id': self.invoice_id.partner_id.id, + 'delivery_address_id': line.invoice_id.partner_id.id, + 'invoice_address_id': line.invoice_id.partner_id.id, 'rma_id': self.rma_id.id } if not operation: @@ -66,16 +65,26 @@ class RmaAddinvoice(models.TransientModel): [('rma_selectable', '=', True)], limit=1) if not route: raise ValidationError("Please define an rma route") + + if not operation.in_warehouse_id or not operation.out_warehouse_id: + warehouse = self.env['stock.warehouse'].search( + [('company_id', '=', self.rma_id.company_id.id), + ('lot_rma_id', '!=', False)], limit=1) + if not warehouse: + raise ValidationError("Please define a warehouse with a" + " default rma location") data.update( - {'in_route_id': operation.in_route_id.id, - 'out_route_id': operation.out_route_id.id, - 'in_warehouse_id': operation.in_warehouse_id.id, - 'out_warehouse_id': operation.out_warehouse_id.id, - 'receipt_policy': operation.receipt_policy, - 'location_id': operation.location_id.id, + {'receipt_policy': operation.receipt_policy, 'operation_id': operation.id, 'refund_policy': operation.refund_policy, - 'delivery_policy': operation.delivery_policy + 'delivery_policy': operation.delivery_policy, + 'in_warehouse_id': operation.in_warehouse_id.id or warehouse.id, + 'out_warehouse_id': operation.out_warehouse_id.id or warehouse.id, + 'in_route_id': operation.in_route_id.id or route.id, + 'out_route_id': operation.out_route_id.id or route.id, + 'location_id': (operation.location_id.id or + operation.in_warehouse_id.lot_rma_id.id or + warehouse.lot_rma_id.id) }) return data @@ -83,8 +92,10 @@ class RmaAddinvoice(models.TransientModel): def _get_rma_data(self): data = { 'date_rma': fields.Datetime.now(), - 'delivery_address_id': self.invoice_id.partner_id.id, - 'invoice_address_id': self.invoice_id.partner_id.id + 'delivery_address_id': + self.invoice_line_ids[0].invoice_id.partner_id.id, + 'invoice_address_id': + self.invoice_line_ids[0].invoice_id.partner_id.id } return data diff --git a/rma_account/wizards/rma_add_invoice.xml b/rma_account/wizards/rma_add_invoice.xml index 83446712..bbe64273 100644 --- a/rma_account/wizards/rma_add_invoice.xml +++ b/rma_account/wizards/rma_add_invoice.xml @@ -11,17 +11,51 @@ domain="[('customer','=',True)]" string="Customer"/> - + + + + + + + + + + + + + + +
+
+ +
+ + + + rma.add.invoice.supplier + rma_add_invoice + +
- + + domain="[('invoice_id.partner_id', '=', partner_id), + ('invoice_id.type', '=', 'in_invoice')]"> + @@ -54,9 +88,20 @@ form new - + + + Add Invoice + ir.actions.act_window + rma_add_invoice + rma.order + form + form + new + + + rma.order.line.form @@ -78,7 +123,7 @@ + + + - @@ -51,9 +55,13 @@ string="Refunds"/> + + + - diff --git a/rma_account/wizards/rma_add_invoice.xml b/rma_account/wizards/rma_add_invoice.xml index 9ecacff3..c0d9e412 100644 --- a/rma_account/wizards/rma_add_invoice.xml +++ b/rma_account/wizards/rma_add_invoice.xml @@ -109,12 +109,11 @@ rma.order - + type="action"/> + @@ -123,12 +122,11 @@ rma.order - + type="action"/> + diff --git a/rma_account/wizards/rma_refund.xml b/rma_account/wizards/rma_refund.xml index a2363c48..65b07fe0 100644 --- a/rma_account/wizards/rma_refund.xml +++ b/rma_account/wizards/rma_refund.xml @@ -50,11 +50,11 @@ rma.order.line -
+
+
@@ -63,11 +63,11 @@ rma.order.line -
+
+
From aeeba9db8d7e046b20d7898274417a3efc90f01d Mon Sep 17 00:00:00 2001 From: lreficent Date: Thu, 19 Oct 2017 10:10:19 +0200 Subject: [PATCH 07/93] [9.0][IMP] rma: add constrains --- rma_account/models/rma_order_line.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 077b101e..e8b9cda8 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -140,6 +140,17 @@ class RmaOrderLine(models.Model): self.update(data) self._remove_other_data_origin('invoice_line_id') + @api.multi + @api.constrains('invoice_line_id', 'partner_id') + def _check_invoice_partner(self): + for rec in self: + if (rec.invoice_line_id and + rec.invoice_line_id.invoice_id.partner_id != + rec.partner_id): + raise ValidationError(_( + "RMA customer and originating invoice line customer " + "doesn't match.")) + @api.multi def _remove_other_data_origin(self, exception): res = super(RmaOrderLine, self)._remove_other_data_origin(exception) From 83e01d640d7bf17e375e47730ddb03b14a0fedca Mon Sep 17 00:00:00 2001 From: lreficent Date: Thu, 19 Oct 2017 11:29:08 +0200 Subject: [PATCH 08/93] [9.0][FIX] wizards need to specify partner. --- rma_account/wizards/rma_add_invoice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index 08af166c..a2904943 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -61,6 +61,7 @@ class RmaAddInvoice(models.TransientModel): raise ValidationError("Please define a warehouse with a" " default rma location") data = { + 'partner_id': self.partner_id.id, 'invoice_line_id': line.id, 'product_id': line.product_id.id, 'origin': line.invoice_id.number, From 2a905209e7c67a902777c41609e1af522a5fda6e Mon Sep 17 00:00:00 2001 From: lreficent Date: Fri, 10 Nov 2017 10:31:45 +0100 Subject: [PATCH 09/93] [9.0][FIX] rma_account: refund wizard --- rma_account/models/rma_order_line.py | 9 ++- rma_account/wizards/rma_refund.py | 111 +++++++++++++-------------- 2 files changed, 57 insertions(+), 63 deletions(-) diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index e8b9cda8..c1209054 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -56,10 +56,11 @@ class RmaOrderLine(models.Model): index=True, readonly=True, states={'draft': [('readonly', False)]}, ) - refund_line_ids = fields.One2many(comodel_name='account.invoice.line', - inverse_name='rma_line_id', - string='Refund Lines', - copy=False, index=True, readonly=True) + refund_line_ids = fields.One2many( + comodel_name='account.invoice.line', + inverse_name='rma_line_id', string='Refund Lines', + copy=False, index=True, readonly=True, + ) invoice_id = fields.Many2one('account.invoice', string='Source', related='invoice_line_id.invoice_id', index=True, readonly=True) diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 04c1b166..6180115e 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import _, api, exceptions, fields, models + +from openerp import _, api, fields, models +from openerp.exceptions import ValidationError import openerp.addons.decimal_precision as dp @@ -10,12 +12,9 @@ class RmaRefund(models.TransientModel): @api.model def _get_reason(self): - context = dict(self._context or {}) - active_ids = context.get('active_ids', False) - if active_ids: - rma_lines = self.env['rma.order.line'].browse(active_ids[0]) - return rma_lines.rma_id.name - return '' + active_ids = self.env.context.get('active_ids', False) + return self.env['rma.order.line'].browse( + active_ids[0]).rma_id.name or '' @api.returns('rma.order.line') def _prepare_item(self, line): @@ -37,55 +36,48 @@ class RmaRefund(models.TransientModel): lines the supplier field is empty otherwise is the unique line supplier. """ - res = super(RmaRefund, self).default_get( - fields) + res = super(RmaRefund, self).default_get(fields) rma_line_obj = self.env['rma.order.line'] rma_line_ids = self.env.context['active_ids'] or [] active_model = self.env.context['active_model'] - if not rma_line_ids: return res - assert active_model == 'rma.order.line', \ - 'Bad context propagation' + assert active_model == 'rma.order.line', 'Bad context propagation' items = [] lines = rma_line_obj.browse(rma_line_ids) if len(lines.mapped('partner_id')) > 1: - raise exceptions.Warning( - _('Only RMA lines from the same partner can be processed at ' - 'the same time')) + raise ValidationError( + _("Only RMAs from the same partner can be processed at " + "the same time.")) for line in lines: items.append([0, 0, self._prepare_item(line)]) res['item_ids'] = items return res - date_invoice = fields.Date(string='Refund Date', - default=fields.Date.context_today, - required=True) + date_invoice = fields.Date( + string='Refund Date', + default=fields.Date.context_today, required=True, + ) date = fields.Date(string='Accounting Date') - description = fields.Char(string='Reason', required=True, - default=_get_reason) + description = fields.Char( + string='Reason', required=True, default=_get_reason, + ) item_ids = fields.One2many( - comodel_name='rma.refund.item', inverse_name='wiz_id', string='Items') + comodel_name='rma.refund.item', + inverse_name='wiz_id', string='Items', + ) @api.multi def compute_refund(self): for wizard in self: first = self.item_ids[0] - values = self._prepare_refund(wizard, first.rma_id) - if len(first.line_id.invoice_address_id): - values['partner_id'] = first.line_id.invoice_address_id.id - else: - values['partner_id'] = first.rma_id.partner_id.id + values = self._prepare_refund(wizard, first.line_id) new_refund = self.env['account.invoice'].create(values) for item in self.item_ids: refund_line_values = self.prepare_refund_line(item, new_refund) self.env['account.invoice.line'].create( refund_line_values) - # Put the reason in the chatter - subject = _("Invoice refund") - body = self.item_ids[0].rma_id.name - new_refund.message_post(body=body, subject=subject) return new_refund @api.multi @@ -94,12 +86,11 @@ class RmaRefund(models.TransientModel): self.env.context['active_ids']) for line in rma_line_ids: if line.refund_policy == 'no': - raise exceptions.Warning( + raise ValidationError( _('The operation is not refund for at least one line')) if line.state != 'approved': - raise exceptions.Warning( - _('RMA %s is not approved') % - line.rma_id.name) + raise ValidationError( + _('RMA %s is not approved') % line.name) new_invoice = self.compute_refund() action = 'action_invoice_tree1' if ( new_invoice.type in ['out_refund', 'out_invoice']) \ @@ -118,11 +109,11 @@ class RmaRefund(models.TransientModel): else: account = accounts['stock_input'] if not account: - raise exceptions.ValidationError("Accounts are not configure for " - "this product") + raise ValidationError(_( + "Accounts are not configure for this product.")) values = { - 'name': item.rma_id.name, - 'origin': item.rma_id.name, + 'name': item.line_id.name or item.rma_id.name, + 'origin': item.line_id.name or item.rma_id.name, 'account_id': account.id, 'price_unit': item.line_id.price_unit, 'uom_id': item.line_id.uom_id.id, @@ -134,40 +125,42 @@ class RmaRefund(models.TransientModel): return values @api.model - def _prepare_refund(self, wizard, order): - # origin_invoices = self._get_invoice(order) - if order.type == 'customer': + def _prepare_refund(self, wizard, rma_line): + # origin_invoices = self._get_invoice(rma_line) + if rma_line.type == 'customer': journal = self.env['account.journal'].search( [('type', '=', 'sale')], limit=1) else: journal = self.env['account.journal'].search( [('type', '=', 'purchase')], limit=1) values = { - 'name': order.name, - 'origin': order.name, + 'name': rma_line.rma_id.name or rma_line.name, + 'origin': rma_line.rma_id.name or rma_line.name, 'reference': False, # 'account_id': account.id, 'journal_id': journal.id, - 'partner_id': order.partner_id.id, - 'currency_id': order.partner_id.company_id.currency_id.id, + 'currency_id': rma_line.partner_id.company_id.currency_id.id, 'payment_term_id': False, 'fiscal_position_id': - order.partner_id.property_account_position_id.id, + rma_line.partner_id.property_account_position_id.id, + 'state': 'draft', + 'number': False, + 'date': wizard.date, + 'date_invoice': wizard.date_invoice, + 'partner_id': rma_line.invoice_address_id.id or + rma_line.partner_id.id, } - team_ids = self.env['crm.team'].search( - ['|', ('user_id', '=', self.env.uid), - ('member_ids', '=', self.env.uid)], limit=1) - team_id = team_ids[0] if team_ids else False - if team_id: - values['team_id'] = team_id.id - if order.type == 'customer': + if self.env.registry.models.get('crm.team', False): + team_ids = self.env['crm.team'].search( + ['|', ('user_id', '=', self.env.uid), + ('member_ids', '=', self.env.uid)], limit=1) + team_id = team_ids[0] if team_ids else False + if team_id: + values['team_id'] = team_id.id + if rma_line.type == 'customer': values['type'] = 'out_refund' else: values['type'] = 'in_refund' - values['state'] = 'draft' - values['number'] = False - values['date'] = wizard.date_invoice - values['date_invoice'] = wizard.date or wizard.date_invoice return values @api.constrains('item_ids') @@ -175,8 +168,8 @@ class RmaRefund(models.TransientModel): def check_unique_invoice_address_id(self): addresses = self.item_ids.mapped('invoice_address_id') if len(addresses) > 1: - raise exceptions.ValidationError('The invoice address must be the ' - 'same for all the lines') + raise ValidationError(_( + "The invoice address must be the same for all the lines.")) return True From 882eb3fcefb0f6ac297bd4c719299871f1bb5921 Mon Sep 17 00:00:00 2001 From: lreficent Date: Mon, 13 Nov 2017 14:05:26 +0100 Subject: [PATCH 10/93] [FIX] allow child partners too --- rma_account/views/rma_order_line_view.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index 58b5b8ba..50b1b344 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -18,7 +18,9 @@ + domain="['|', + ('invoice_id.partner_id', '=', partner_id), + ('invoice_id.partner_id', 'child_of', partner_id)]"/> @@ -58,7 +60,9 @@ + domain="['|', + ('invoice_id.partner_id', '=', partner_id), + ('invoice_id.partner_id', 'child_of', partner_id)]"/> From cfb7183c5915ed403f73592d93458d80e985676b Mon Sep 17 00:00:00 2001 From: aheficent Date: Tue, 19 Dec 2017 18:15:20 +0100 Subject: [PATCH 11/93] [MIG]rma account v10 --- rma_account/{__openerp__.py => __manifest__.py} | 0 rma_account/models/invoice.py | 2 +- rma_account/models/rma_operation.py | 2 +- rma_account/models/rma_order.py | 2 +- rma_account/models/rma_order_line.py | 6 +++--- rma_account/wizards/rma_add_invoice.py | 4 ++-- rma_account/wizards/rma_order_line_make_supplier_rma.py | 2 +- rma_account/wizards/rma_refund.py | 6 +++--- rma_account/wizards/rma_refund.xml | 4 ++-- 9 files changed, 14 insertions(+), 14 deletions(-) rename rma_account/{__openerp__.py => __manifest__.py} (100%) diff --git a/rma_account/__openerp__.py b/rma_account/__manifest__.py similarity index 100% rename from rma_account/__openerp__.py rename to rma_account/__manifest__.py diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index a834d551..d233b7d1 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -2,7 +2,7 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import api, fields, models +from odoo import api, fields, models class AccountInvoice(models.Model): diff --git a/rma_account/models/rma_operation.py b/rma_account/models/rma_operation.py index 201d1f46..55aeea40 100644 --- a/rma_account/models/rma_operation.py +++ b/rma_account/models/rma_operation.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import fields, models +from odoo import fields, models class RmaOperation(models.Model): diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index b925ee93..a92bb76b 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import api, fields, models +from odoo import api, fields, models class RmaOrder(models.Model): diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index c1209054..67dc13d2 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import _, api, fields, models -from openerp.exceptions import ValidationError, UserError -from openerp.addons import decimal_precision as dp +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError, UserError +from odoo.addons import decimal_precision as dp class RmaOrderLine(models.Model): diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index a2904943..44f352be 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -2,8 +2,8 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import api, fields, models -from openerp.exceptions import ValidationError +from odoo import api, fields, models +from odoo.exceptions import ValidationError class RmaAddInvoice(models.TransientModel): diff --git a/rma_account/wizards/rma_order_line_make_supplier_rma.py b/rma_account/wizards/rma_order_line_make_supplier_rma.py index 08e9db96..ead4574d 100644 --- a/rma_account/wizards/rma_order_line_make_supplier_rma.py +++ b/rma_account/wizards/rma_order_line_make_supplier_rma.py @@ -2,7 +2,7 @@ # Copyright 2016 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). -from openerp import api, models +from odoo import api, models class RmaLineMakeSupplierRma(models.TransientModel): diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 6180115e..436e946f 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -2,9 +2,9 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp import _, api, fields, models -from openerp.exceptions import ValidationError -import openerp.addons.decimal_precision as dp +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError +import odoo.addons.decimal_precision as dp class RmaRefund(models.TransientModel): diff --git a/rma_account/wizards/rma_refund.xml b/rma_account/wizards/rma_refund.xml index 65b07fe0..52efcd46 100644 --- a/rma_account/wizards/rma_refund.xml +++ b/rma_account/wizards/rma_refund.xml @@ -1,5 +1,5 @@ - + @@ -82,4 +82,4 @@ - + From c56c1d64c711ec6f787e0897551492720e7452c6 Mon Sep 17 00:00:00 2001 From: Nikul Chaudhary Date: Fri, 10 Nov 2017 12:48:55 +0530 Subject: [PATCH 12/93] [IMP] Improved Unit Test Case and Fixed Travis --- rma_account/__manifest__.py | 2 +- rma_account/models/invoice.py | 2 +- rma_account/models/rma_order.py | 12 +- rma_account/models/rma_order_line.py | 21 +- rma_account/tests/__init__.py | 6 + rma_account/tests/test_rma.py | 395 +++++++++++++++++++++++++ rma_account/tests/test_rma_dropship.py | 96 ++++++ rma_account/tests/test_supplier_rma.py | 156 ++++++++++ rma_account/wizards/rma_refund.py | 1 + 9 files changed, 673 insertions(+), 18 deletions(-) create mode 100644 rma_account/tests/__init__.py create mode 100644 rma_account/tests/test_rma.py create mode 100644 rma_account/tests/test_rma_dropship.py create mode 100644 rma_account/tests/test_supplier_rma.py diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 07696111..93f226c5 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -8,7 +8,7 @@ 'license': 'LGPL-3', 'category': 'RMA', 'summary': 'Integrates RMA with Invoice Processing', - 'author': "Eficent", + 'author': "Eficent, Odoo Community Association (OCA)", 'website': 'http://www.github.com/OCA/rma', 'depends': ['account', 'rma'], 'demo': ['demo/rma_operation.xml'], diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index d233b7d1..233ec0d7 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -8,7 +8,7 @@ from odoo import api, fields, models class AccountInvoice(models.Model): _inherit = "account.invoice" - @api.one + @api.depends('invoice_line_ids.rma_line_ids') def _compute_rma_count(self): for inv in self: rmas = self.mapped('invoice_line_ids.rma_line_ids') diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index a92bb76b..7b710b47 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -31,11 +31,13 @@ class RmaOrder(models.Model): def _prepare_rma_line_from_inv_line(self, line): if self.type == 'customer': - operation = self.product_id.rma_customer_operation_id or \ - self.product_id.categ_id.rma_customer_operation_id + operation =\ + self.rma_line_ids.product_id.rma_customer_operation_id or \ + self.rma_line_ids.product_id.categ_id.rma_customer_operation_id else: - operation = self.product_id.rma_supplier_operation_id or \ - self.product_id.categ_id.rma_supplier_operation_id + operation =\ + self.rma_line_ids.product_id.rma_supplier_operation_id or \ + self.rma_line_ids.product_id.categ_id.rma_supplier_operation_id data = { 'invoice_line_id': line.id, 'product_id': line.product_id.id, @@ -46,7 +48,7 @@ class RmaOrder(models.Model): 'product_qty': line.quantity, 'price_unit': line.invoice_id.currency_id.compute( line.price_unit, line.currency_id, round=False), - 'rma_id': self._origin.id + 'rma_id': self.id } return data diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 67dc13d2..5426bc2a 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -25,16 +25,16 @@ class RmaOrderLine(models.Model): lambda i: i.invoice_id.state in ('open', 'paid')).mapped( 'quantity')) - @api.one @api.depends('refund_line_ids', 'refund_line_ids.invoice_id.state', 'refund_policy', 'move_ids', 'move_ids.state', 'type') def _compute_qty_to_refund(self): qty = 0.0 - if self.refund_policy == 'ordered': - qty = self.product_qty - self.qty_refunded - elif self.refund_policy == 'received': - qty = self.qty_received - self.qty_refunded - self.qty_to_refund = qty + for res in self: + if res.refund_policy == 'ordered': + qty = res.product_qty - res.qty_refunded + elif res.refund_policy == 'received': + qty = res.qty_received - res.qty_refunded + res.qty_to_refund = qty @api.multi def _compute_refund_count(self): @@ -94,21 +94,21 @@ class RmaOrderLine(models.Model): operation = self.env['rma.operation'].search( [('type', '=', self.type)], limit=1) if not operation: - raise ValidationError("Please define an operation first") + raise ValidationError(_("Please define an operation first")) if not operation.in_route_id or not operation.out_route_id: route = self.env['stock.location.route'].search( [('rma_selectable', '=', True)], limit=1) if not route: - raise ValidationError("Please define an rma route") + raise ValidationError(_("Please define an rma route")) if not operation.in_warehouse_id or not operation.out_warehouse_id: warehouse = self.env['stock.warehouse'].search( [('company_id', '=', self.company_id.id), ('lot_rma_id', '!=', False)], limit=1) if not warehouse: - raise ValidationError("Please define a warehouse with a" - " default rma location") + raise ValidationError(_("Please define a warehouse with a" + " default rma location")) data = { 'product_id': line.product_id.id, 'origin': line.invoice_id.number, @@ -189,7 +189,6 @@ class RmaOrderLine(models.Model): result['views'] = [(res and res.id or False, 'form')] result['view_id'] = res and res.id or False result['res_id'] = self.invoice_line_id.invoice_id.id - return result @api.multi diff --git a/rma_account/tests/__init__.py b/rma_account/tests/__init__.py new file mode 100644 index 00000000..dfa77946 --- /dev/null +++ b/rma_account/tests/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) +from . import test_rma +from . import test_supplier_rma +from . import test_rma_dropship diff --git a/rma_account/tests/test_rma.py b/rma_account/tests/test_rma.py new file mode 100644 index 00000000..2a5873f9 --- /dev/null +++ b/rma_account/tests/test_rma.py @@ -0,0 +1,395 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from openerp.tests import common +from openerp import fields + + +class TestRma(common.TransactionCase): + + """ Test the routes and the quantities """ + + def setUp(self): + super(TestRma, self).setUp() + + self.rma_make_picking = self.env['rma_make_picking.wizard'] + self.make_supplier_rma = self.env["rma.order.line.make.supplier.rma"] + self.rma_add_stock_move = self.env['rma_add_stock_move'] + self.stockpicking = self.env['stock.picking'] + self.rma = self.env['rma.order'] + self.rma_line = self.env['rma.order.line'] + self.rma_op = self.env['rma.operation'] + self.rma_cust_replace_op_id = self.env.ref( + 'rma.rma_operation_customer_replace') + self.rma_sup_replace_op_id = self.env.ref( + 'rma.rma_operation_supplier_replace') + self.product_id = self.env.ref('product.product_product_4') + self.product_id.product_tmpl_id.categ_id.\ + property_stock_account_input_categ_id =\ + self.env.ref('account.data_account_type_receivable').id + self.product_id.product_tmpl_id.categ_id.\ + property_stock_account_output_categ_id =\ + self.env.ref('account.data_account_type_expenses').id + self.product_1 = self.env.ref('product.product_product_25') + self.product_2 = self.env.ref('product.product_product_30') + self.product_3 = self.env.ref('product.product_product_33') + self.uom_unit = self.env.ref('product.product_uom_unit') + # assign an operation + self.product_1.write( + {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) + self.product_2.write( + {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) + self.product_3.write( + {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) + self.partner_id = self.env.ref('base.res_partner_12') + self.stock_location = self.env.ref('stock.stock_location_stock') + self.stock_rma_location = self.env.ref('rma.location_rma') + self.customer_location = self.env.ref( + 'stock.stock_location_customers') + self.supplier_location = self.env.ref( + 'stock.stock_location_suppliers') + self.product_uom_id = self.env.ref('product.product_uom_unit') + products2move = [(self.product_1, 3), (self.product_2, 5), + (self.product_3, 2)] + self.rma_customer_id = self._create_rma_from_move( + products2move, 'customer', self.env.ref('base.res_partner_2'), + dropship=False) + + def _create_picking(self, partner): + return self.stockpicking.create({ + 'partner_id': partner.id, + 'picking_type_id': self.env.ref('stock.picking_type_in').id, + 'location_id': self.stock_location.id, + 'location_dest_id': self.supplier_location.id + }) + + def _create_rma_from_move(self, products2move, type, partner, dropship, + supplier_address_id=None): + picking_in = self._create_picking(partner) + + moves = [] + if type == 'customer': + for item in products2move: + move_values = self._prepare_move( + item[0], item[1], self.stock_location, + self.customer_location, picking_in) + moves.append(self.env['stock.move'].create(move_values)) + else: + for item in products2move: + move_values = self._prepare_move( + item[0], item[1], self.supplier_location, + self.stock_rma_location, picking_in) + moves.append(self.env['stock.move'].create(move_values)) + # Create the RMA from the stock_move + rma_id = self.rma.create( + { + 'reference': '0001', + 'type': type, + 'partner_id': partner.id, + 'company_id': self.env.ref('base.main_company').id + }) + rma_id._compute_invoice_refund_count() + rma_id._compute_invoice_count() + + data = {'add_invoice_id': self._create_invoice().id} + new_line = self.rma.new(data) + new_line.on_change_invoice() + + rma_id.action_view_invoice_refund() + rma_id.action_view_invoice() + + for move in moves: + if type == 'customer': + wizard = self.rma_add_stock_move.with_context( + {'stock_move_id': move.id, 'customer': True, + 'active_ids': rma_id.id, + 'active_model': 'rma.order', + } + ).create({}) + data = wizard._prepare_rma_line_from_stock_move(move) + else: + wizard = self.rma_add_stock_move.with_context( + {'stock_move_id': move.id, 'supplier': True, + 'active_ids': rma_id.id, + 'active_model': 'rma.order', + } + ).create({}) + data = wizard._prepare_rma_line_from_stock_move(move) + if dropship: + data.update(customer_to_supplier=dropship, + supplier_address_id=supplier_address_id.id) + self.line = self.rma_line.create(data) + # approve the RMA Line + self.line._compute_refund_count() + self.rma_line.action_rma_to_approve() + + self.line.action_rma_approve() + self.line.action_view_invoice() + self.line.action_view_refunds() + + # approve the RMA +# rma_id.action_rma_to_approve() +# rma_id.action_rma_approve() + return rma_id + + def _prepare_move(self, product, qty, src, dest, picking_in): + res = { + 'partner_id': self.partner_id.id, + 'product_id': product.id, + 'name': product.partner_ref, + 'state': 'confirmed', + 'product_uom': self.product_uom_id.id or product.uom_id.id, + 'product_uom_qty': qty, + 'origin': 'Test RMA', + 'location_id': src.id, + 'location_dest_id': dest.id, + 'picking_id': picking_in.id + } + return res + + def test_rma_refund(self): + + self.rma_refund_item = self.env['rma.refund.item'] + self.rma_refund = self.env['rma.refund'] + + self.product_id.income =\ + self.env.ref('account.data_account_type_receivable').id + self.product_id.expense =\ + self.env.ref('account.data_account_type_expenses').id + + for line in self.rma_customer_id.rma_line_ids: + line.refund_policy = 'ordered' + + refund = self.rma_refund.with_context({ + 'active_ids': self.rma_customer_id.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'active_id': 1 + }).create({'description': 'Test Reason', + 'date_invoice': fields.datetime.now() + }) + self.rma_refund_item.create({ + 'line_id': self.rma_customer_id.rma_line_ids[0].id, + 'rma_id': self.rma_customer_id.id, + 'product_id': self.product_id.id, + 'name': 'Test RMA Refund', + 'product_qty': self.rma_customer_id.rma_line_ids[0].product_qty, + 'wiz_id': refund.id + }) + refund.invoice_refund() + + data = {'invoice_line_id': self._create_invoice().invoice_line_ids.id} + new_line = self.rma_line.new(data) + new_line._onchange_invoice_line_id() + self.rma_customer_id.action_view_invoice_refund() + self.rma_customer_id.action_view_invoice() + + def test_on_change_invoice_rma(self): + + wizard = self.env['rma_add_invoice'].with_context({ + 'active_ids': self.rma_customer_id.ids, + 'active_model': 'rma.order', + 'active_id': self.rma_customer_id.id + }).create({'partner_id': self.partner_id.id, + 'rma_id': self.rma_customer_id.id, + 'invoice_line_ids': + [(6, 0, [self._create_invoice().invoice_line_ids.id])], + }) + wizard.default_get([str(self._create_invoice().id), + str(self._create_invoice().invoice_line_ids.id), + str(self.partner_id.id)]) + wizard.add_lines() + self.rma_customer_id.action_view_invoice_refund() + self.rma_customer_id.action_view_invoice() + self.rma_customer_id.rma_line_ids[0].\ + invoice_id = self._create_invoice().id + self.rma_customer_id.action_view_invoice() + self.rma_customer_id.add_invoice_id = self._create_invoice().id + for line in self.rma_customer_id.rma_line_ids: + line.invoice_id.action_view_rma_supplier() + line.invoice_id.action_view_rma_customer() + + def _create_invoice(self): + self.Account = self.env['account.account'] + self.AccountInvoice = self.env['account.invoice'] + self.AccountInvoiceLine = self.env['account.invoice.line'] + + self.account_receivable =\ + self.env.ref('account.data_account_type_receivable') + self.account_expenses =\ + self.env.ref('account.data_account_type_expenses') + invoice_account = self.Account.\ + search([('user_type_id', '=', self.account_receivable.id)], limit=1 + ).id + invoice_line_account = self.Account.\ + search([('user_type_id', '=', self.account_expenses.id)], limit=1 + ).id + + invoice = self.AccountInvoice.create({ + 'partner_id': self.partner_id.id, + 'account_id': invoice_account, + 'type': 'in_invoice', + }) + + invoice_line = self.AccountInvoiceLine.create({ + 'product_id': self.product_1.id, + 'quantity': 1.0, + 'price_unit': 100.0, + 'invoice_id': invoice.id, + 'uom_id': 1, + 'name': 'product that cost 100', + 'account_id': invoice_line_account, + }) + invoice._compute_rma_count() + invoice_line._compute_rma_count() + invoice.action_view_rma_customer() + invoice.action_view_rma_supplier() + return invoice + + def test_customer_rma(self): + wizard = self.rma_make_picking.with_context({ + 'active_ids': self.rma_customer_id.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'picking_type': 'incoming', + 'active_id': 1 + }).create({}) + procurements = wizard._create_picking() + group_ids = set([proc.group_id.id for proc in procurements if + proc.group_id]) + domain = [('group_id', 'in', list(group_ids))] + picking = self.stockpicking.search(domain) + self.assertEquals(len(picking), 1, + "Incorrect number of pickings created") + moves = picking.move_lines + self.assertEquals(len(moves), 3, + "Incorrect number of moves created") + for line in self.rma_customer_id.rma_line_ids: + # common qtys for all products + self.assertEquals(line.qty_received, 0, + "Wrong qty received") + self.assertEquals(line.qty_to_deliver, 0, + "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 0, + "Wrong qty outgoing") + self.assertEquals(line.qty_delivered, 0, + "Wrong qty delivered") + # product specific + if line.product_id == self.product_1: + self.assertEquals(line.qty_to_receive, 3, + "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 3, + "Wrong qty incoming") + if line.product_id == self.product_2: + self.assertEquals(line.qty_to_receive, 5, + "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 5, + "Wrong qty incoming") + if line.product_id == self.product_3: + self.assertEquals(line.qty_to_receive, 2, + "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 2, + "Wrong qty incoming") + picking.action_assign() + picking.do_transfer() + for line in self.rma_customer_id.rma_line_ids: + self.assertEquals(line.qty_to_receive, 0, + "Wrong qty to_receive") + self.assertEquals(line.qty_incoming, 0, + "Wrong qty incoming") + self.assertEquals(line.qty_outgoing, 0, + "Wrong qty outgoing") + self.assertEquals(line.qty_delivered, 0, + "Wrong qty delivered") + if line.product_id == self.product_1: + self.assertEquals(line.qty_received, 3, + "Wrong qty received") + self.assertEquals(line.qty_to_deliver, 3, + "Wrong qty to_deliver") + if line.product_id == self.product_2: + self.assertEquals(line.qty_received, 5, + "Wrong qty received") + self.assertEquals(line.qty_to_deliver, 5, + "Wrong qty to_deliver") + if line.product_id == self.product_3: + self.assertEquals(line.qty_received, 2, + "Wrong qty received") + self.assertEquals(line.qty_to_deliver, 2, + "Wrong qty to_deliver") + + wizard = self.rma_make_picking.with_context({ + 'active_id': 1, + 'active_ids': self.rma_customer_id.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'picking_type': 'outgoing', + }).create({}) + procurements = wizard._create_picking() + group_ids = set([proc.group_id.id for proc in procurements if + proc.group_id]) + domain = [('group_id', 'in', list(group_ids))] + pickings = self.stockpicking.search(domain) + self.assertEquals(len(pickings), 2, + "Incorrect number of pickings created") + picking_out = pickings[1] + moves = picking_out.move_lines + self.assertEquals(len(moves), 3, + "Incorrect number of moves created") + for line in self.rma_customer_id.rma_line_ids: + self.assertEquals(line.qty_to_receive, 0, + "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 0, + "Wrong qty incoming") + self.assertEquals(line.qty_delivered, 0, + "Wrong qty delivered") + if line.product_id == self.product_1: + self.assertEquals(line.qty_to_deliver, 3, + "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 3, + "Wrong qty outgoing") + self.assertEquals(line.qty_received, 3, + "Wrong qty received") + if line.product_id == self.product_2: + self.assertEquals(line.qty_received, 5, + "Wrong qty received") + self.assertEquals(line.qty_to_deliver, 5, + "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 5, + "Wrong qty outgoing") + if line.product_id == self.product_3: + self.assertEquals(line.qty_received, 2, + "Wrong qty received") + self.assertEquals(line.qty_to_deliver, 2, + "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 2, + "Wrong qty outgoing") + picking_out.action_assign() + picking_out.do_transfer() + for line in self.rma_customer_id.rma_line_ids: + self.assertEquals(line.qty_to_receive, 0, + "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 0, + "Wrong qty incoming") + self.assertEquals(line.qty_to_deliver, 0, + "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 0, + "Wrong qty outgoing") + if line.product_id == self.product_1: + self.assertEquals(line.qty_received, 3, + "Wrong qty received") + self.assertEquals(line.qty_delivered, 3, + "Wrong qty delivered") + if line.product_id == self.product_2: + self.assertEquals(line.qty_received, 5, + "Wrong qty received") + self.assertEquals(line.qty_delivered, 5, + "Wrong qty delivered") + if line.product_id == self.product_3: + self.assertEquals(line.qty_received, 2, + "Wrong qty received") + self.assertEquals(line.qty_delivered, 2, + "Wrong qty delivered") + self.line.action_rma_done() + self.assertEquals(self.line.state, 'done', + "Wrong State") diff --git a/rma_account/tests/test_rma_dropship.py b/rma_account/tests/test_rma_dropship.py new file mode 100644 index 00000000..b19a12b2 --- /dev/null +++ b/rma_account/tests/test_rma_dropship.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from openerp.addons.rma.tests import test_rma + + +class TestRmaDropship(test_rma.TestRma): + + def setUp(self): + super(TestRmaDropship, self).setUp() + products2move = [(self.product_1, 3), (self.product_2, 5), + (self.product_3, 2)] + self.rma_droship_id = self._create_rma_from_move( + products2move, 'customer', self.env.ref('base.res_partner_2'), + dropship=True, + supplier_address_id=self.env.ref('base.res_partner_3')) + + def test_dropship(self): + wizard = self.make_supplier_rma.with_context({ + 'active_ids': self.rma_droship_id.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'active_id': 1 + }).create({}) + res = wizard.make_supplier_rma() + supplier_rma = self.rma.browse(res['res_id']) + for line in supplier_rma.rma_line_ids: + line.action_rma_to_approve() + line.action_rma_approve() + wizard = self.rma_make_picking.with_context({ + 'active_id': 1, + 'active_ids': supplier_rma.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'picking_type': 'incoming', + }).create({}) + procurements = wizard._create_picking() + group_ids = set([proc.group_id.id for proc in procurements if + proc.group_id]) + domain = [('group_id', 'in', list(group_ids))] + picking = self.stockpicking.search(domain) + self.assertEquals(len(picking), 1, + "Incorrect number of pickings created") + moves = picking.move_lines + self.assertEquals(len(moves), 3, + "Incorrect number of moves created") + for line in supplier_rma.rma_line_ids: + # common qtys for all products + self.assertEquals(line.qty_received, 0, + "Wrong qty received") + self.assertEquals(line.qty_outgoing, 0, + "Wrong qty incoming") + self.assertEquals(line.qty_delivered, 0, + "Wrong qty delivered") + # product specific + if line.product_id == self.product_1: + self.assertEquals(line.qty_to_receive, 3, + "Wrong qty to receive") + self.assertEquals(line.qty_to_deliver, 3, + "Wrong qty to deliver") + self.assertEquals(line.qty_incoming, 3, + "Wrong qty outgoing") + if line.product_id == self.product_2: + self.assertEquals(line.qty_to_receive, 5, + "Wrong qty to receive") + self.assertEquals(line.qty_to_deliver, 5, + "Wrong qty to deliver") + self.assertEquals(line.qty_incoming, 5, + "Wrong qty outgoing") + if line.product_id == self.product_3: + self.assertEquals(line.qty_to_receive, 2, + "Wrong qty to receive") + self.assertEquals(line.qty_to_deliver, 2, + "Wrong qty to deliver") + self.assertEquals(line.qty_incoming, 2, + "Wrong qty outgoing") + + for line in self.rma_droship_id.rma_line_ids: + if line.product_id == self.product_1: + self.assertEquals(line.qty_to_supplier_rma, 0, + "Wrong qty to supplier rma") + self.assertEquals(line.qty_in_supplier_rma, 3, + "Wrong qty in supplier rma") + if line.product_id == self.product_2: + self.assertEquals(line.qty_to_supplier_rma, 0, + "Wrong qty to supplier rma") + self.assertEquals(line.qty_in_supplier_rma, 5, + "Wrong qty in supplier rma") + if line.product_id == self.product_3: + self.assertEquals(line.qty_to_supplier_rma, 0, + "Wrong qty to supplier rma") + self.assertEquals(line.qty_in_supplier_rma, 2, + "Wrong qty in supplier rma") + for line in self.rma_droship_id.rma_line_ids: + line.action_rma_done() + self.assertEquals(line.state, 'done', + "Wrong State") diff --git a/rma_account/tests/test_supplier_rma.py b/rma_account/tests/test_supplier_rma.py new file mode 100644 index 00000000..292fc22c --- /dev/null +++ b/rma_account/tests/test_supplier_rma.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from openerp.addons.rma.tests import test_rma + + +class TestSupplierRma(test_rma.TestRma): + + def setUp(self): + super(TestSupplierRma, self).setUp() + products2move = [(self.product_1, 3), (self.product_2, 5), + (self.product_3, 2)] + self.rma_supplier_id = self._create_rma_from_move( + products2move, 'supplier', self.env.ref('base.res_partner_1'), + dropship=False) + + def test_supplier_rma(self): + wizard = self.rma_make_picking.with_context({ + 'active_ids': self.rma_supplier_id.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'picking_type': 'outgoing', + 'active_id': 1 + }).create({}) + procurements = wizard._create_picking() + group_ids = set([proc.group_id.id for proc in procurements if + proc.group_id]) + domain = [('group_id', 'in', list(group_ids))] + picking = self.stockpicking.search(domain) + self.assertEquals(len(picking), 1, + "Incorrect number of pickings created") + moves = picking.move_lines + self.assertEquals(len(moves), 3, + "Incorrect number of moves created") + for line in self.rma_supplier_id.rma_line_ids: + # common qtys for all products + self.assertEquals(line.qty_received, 0, + "Wrong qty received") + self.assertEquals(line.qty_incoming, 0, + "Wrong qty incoming") + self.assertEquals(line.qty_delivered, 0, + "Wrong qty delivered") + # product specific + if line.product_id == self.product_1: + self.assertEquals(line.qty_to_receive, 3, + "Wrong qty to receive") + self.assertEquals(line.qty_to_deliver, 3, + "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 3, + "Wrong qty outgoing") + if line.product_id == self.product_2: + self.assertEquals(line.qty_to_receive, 5, + "Wrong qty to receive") + self.assertEquals(line.qty_to_deliver, 5, + "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 5, + "Wrong qty outgoing") + if line.product_id == self.product_3: + self.assertEquals(line.qty_to_receive, 2, + "Wrong qty to receive") + self.assertEquals(line.qty_to_deliver, 2, + "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 2, + "Wrong qty outgoing") + + picking.action_assign() + picking.do_transfer() + for line in self.rma_supplier_id.rma_line_ids: + self.assertEquals(line.qty_incoming, 0, + "Wrong qty incoming") + self.assertEquals(line.qty_received, 0, + "Wrong qty received") + if line.product_id == self.product_1: + self.assertEquals(line.qty_delivered, 3, + "Wrong qty delivered") + self.assertEquals(line.qty_to_receive, 3, + "Wrong qty to receive") + if line.product_id == self.product_2: + self.assertEquals(line.qty_outgoing, 5, + "Wrong qty delivered") + self.assertEquals(line.qty_to_receive, 5, + "Wrong qty to receive") + if line.product_id == self.product_3: + self.assertEquals(line.qty_outgoing, 2, + "Wrong qty delivered") + self.assertEquals(line.qty_to_receive, 2, + "Wrong qty to receive") + wizard = self.rma_make_picking.with_context({ + 'active_id': 1, + 'active_ids': self.rma_supplier_id.rma_line_ids.ids, + 'active_model': 'rma.order.line', + 'picking_type': 'incoming', + }).create({}) + procurements = wizard._create_picking() + group_ids = set([proc.group_id.id for proc in procurements if + proc.group_id]) + domain = [('group_id', 'in', list(group_ids))] + pickings = self.stockpicking.search(domain) + self.assertEquals(len(pickings), 3, + "Incorrect number of pickings created") + picking_out = pickings[0] + moves = picking_out.move_lines + self.assertEquals(len(moves), 2, + "Incorrect number of moves created") + for line in self.rma_supplier_id.rma_line_ids: + self.assertEquals(line.qty_incoming, 0, + "Wrong qty incoming") + self.assertEquals(line.qty_received, 0, + "Wrong qty received") + if line.product_id == self.product_1: + self.assertEquals(line.qty_to_receive, 3, + "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 0, + "Wrong qty incoming") + self.assertEquals(line.qty_delivered, 3, + "Wrong qty delivered") + if line.product_id == self.product_2: + self.assertEquals(line.qty_to_receive, 5, + "Wrong qty to receive") + self.assertEquals(line.qty_to_deliver, 5, + "Wrong qty to deliver") + if line.product_id == self.product_3: + self.assertEquals(line.qty_to_receive, 2, + "Wrong qty to receive") + self.assertEquals(line.qty_to_deliver, 2, + "Wrong qty to deliver") + picking_out.action_assign() + picking_out.do_transfer() + for line in self.rma_supplier_id.rma_line_ids[0]: + self.assertEquals(line.qty_to_receive, 3, + "Wrong qty to receive") + self.assertEquals(line.qty_incoming, 0, + "Wrong qty incoming") + self.assertEquals(line.qty_to_deliver, 0, + "Wrong qty to deliver") + self.assertEquals(line.qty_outgoing, 3, + "Wrong qty outgoing") + if line.product_id == self.product_1: + self.assertEquals(line.qty_received, 0, + "Wrong qty received") + self.assertEquals(line.qty_delivered, 3, + "Wrong qty delivered") + if line.product_id == self.product_2: + self.assertEquals(line.qty_received, 0, + "Wrong qty received") + self.assertEquals(line.qty_delivered, 5, + "Wrong qty delivered") + if line.product_id == self.product_3: + self.assertEquals(line.qty_received, 2, + "Wrong qty received") + self.assertEquals(line.qty_delivered, 2, + "Wrong qty delivered") + for line in self.rma_supplier_id.rma_line_ids: + line.action_rma_done() + self.assertEquals(line.state, 'done', + "Wrong State") diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 436e946f..2e8df72a 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -4,6 +4,7 @@ from odoo import _, api, fields, models from odoo.exceptions import ValidationError +from odoo.tools.safe_eval import safe_eval as eval import odoo.addons.decimal_precision as dp From fe33db1b89fe4588f77325f188e0788622271cde Mon Sep 17 00:00:00 2001 From: aheficent Date: Tue, 2 Jan 2018 13:05:09 +0100 Subject: [PATCH 13/93] [FIX]various fixes --- rma_account/wizards/rma_add_invoice.py | 10 +++++----- rma_account/wizards/rma_refund.py | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index 44f352be..db087c61 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -2,7 +2,7 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from odoo import api, fields, models +from odoo import _, api, fields, models from odoo.exceptions import ValidationError @@ -46,20 +46,20 @@ class RmaAddInvoice(models.TransientModel): operation = self.env['rma.operation'].search( [('type', '=', self.rma_id.type)], limit=1) if not operation: - raise ValidationError("Please define an operation first") + raise ValidationError(_("Please define an operation first")) if not operation.in_route_id or not operation.out_route_id: route = self.env['stock.location.route'].search( [('rma_selectable', '=', True)], limit=1) if not route: - raise ValidationError("Please define an rma route") + raise ValidationError(_("Please define an rma route")) if not operation.in_warehouse_id or not operation.out_warehouse_id: warehouse = self.env['stock.warehouse'].search( [('company_id', '=', self.rma_id.company_id.id), ('lot_rma_id', '!=', False)], limit=1) if not warehouse: - raise ValidationError("Please define a warehouse with a" - " default rma location") + raise ValidationError(_("Please define a warehouse with a" + " default rma location")) data = { 'partner_id': self.partner_id.id, 'invoice_line_id': line.id, diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 2e8df72a..1efb7b6e 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -165,7 +165,6 @@ class RmaRefund(models.TransientModel): return values @api.constrains('item_ids') - @api.one def check_unique_invoice_address_id(self): addresses = self.item_ids.mapped('invoice_address_id') if len(addresses) > 1: From 12f5ac99d14f1cdef29ce0c9ff6350ae54007f12 Mon Sep 17 00:00:00 2001 From: Nikul Chaudhary Date: Fri, 5 Jan 2018 16:43:54 +0530 Subject: [PATCH 14/93] [MIG] Migrated UT & Fixed Travis --- rma_account/tests/test_rma.py | 33 ++++++++++++++++++++------ rma_account/tests/test_rma_dropship.py | 12 ++++++++++ rma_account/tests/test_supplier_rma.py | 22 ++++++++--------- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/rma_account/tests/test_rma.py b/rma_account/tests/test_rma.py index 2a5873f9..d57c0090 100644 --- a/rma_account/tests/test_rma.py +++ b/rma_account/tests/test_rma.py @@ -32,8 +32,8 @@ class TestRma(common.TransactionCase): property_stock_account_output_categ_id =\ self.env.ref('account.data_account_type_expenses').id self.product_1 = self.env.ref('product.product_product_25') - self.product_2 = self.env.ref('product.product_product_30') - self.product_3 = self.env.ref('product.product_product_33') + self.product_2 = self.env.ref('product.product_product_7') + self.product_3 = self.env.ref('product.product_product_11') self.uom_unit = self.env.ref('product.product_uom_unit') # assign an operation self.product_1.write( @@ -104,24 +104,43 @@ class TestRma(common.TransactionCase): for move in moves: if type == 'customer': - wizard = self.rma_add_stock_move.with_context( + wizard = self.rma_add_stock_move.new( {'stock_move_id': move.id, 'customer': True, 'active_ids': rma_id.id, + 'partner_id': move.partner_id.id, 'active_model': 'rma.order', } - ).create({}) - data = wizard._prepare_rma_line_from_stock_move(move) + ) + wizard.with_context({ + 'stock_move_id': move.id, 'customer': True, + 'active_ids': rma_id.id, + 'partner_id': move.partner_id.id, + 'active_model': 'rma.order', + }) + data = wizard.with_context(customer=1).\ + _prepare_rma_line_from_stock_move(move) + data['partner_id'] = move.partner_id.id else: - wizard = self.rma_add_stock_move.with_context( + wizard = self.rma_add_stock_move.new( {'stock_move_id': move.id, 'supplier': True, 'active_ids': rma_id.id, + 'partner_id': move.partner_id.id, 'active_model': 'rma.order', } - ).create({}) + ) + wizard.with_context( + {'stock_move_id': move.id, 'supplier': True, + 'active_ids': rma_id.id, + 'partner_id': move.partner_id.id, + 'active_model': 'rma.order', + }) data = wizard._prepare_rma_line_from_stock_move(move) + data['partner_id'] = move.partner_id.id if dropship: data.update(customer_to_supplier=dropship, supplier_address_id=supplier_address_id.id) + data['partner_id'] = move.partner_id.id + data['rma_id'] = rma_id.id self.line = self.rma_line.create(data) # approve the RMA Line self.line._compute_refund_count() diff --git a/rma_account/tests/test_rma_dropship.py b/rma_account/tests/test_rma_dropship.py index b19a12b2..abe07221 100644 --- a/rma_account/tests/test_rma_dropship.py +++ b/rma_account/tests/test_rma_dropship.py @@ -9,6 +9,18 @@ class TestRmaDropship(test_rma.TestRma): def setUp(self): super(TestRmaDropship, self).setUp() + self.product_id.write( + {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) + self.product_1.write( + {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) + self.product_2.write( + {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) + self.product_3.write( + {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, + 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) products2move = [(self.product_1, 3), (self.product_2, 5), (self.product_3, 2)] self.rma_droship_id = self._create_rma_from_move( diff --git a/rma_account/tests/test_supplier_rma.py b/rma_account/tests/test_supplier_rma.py index 292fc22c..321b46e1 100644 --- a/rma_account/tests/test_supplier_rma.py +++ b/rma_account/tests/test_supplier_rma.py @@ -76,12 +76,12 @@ class TestSupplierRma(test_rma.TestRma): self.assertEquals(line.qty_to_receive, 3, "Wrong qty to receive") if line.product_id == self.product_2: - self.assertEquals(line.qty_outgoing, 5, + self.assertEquals(line.qty_outgoing, 0, "Wrong qty delivered") self.assertEquals(line.qty_to_receive, 5, "Wrong qty to receive") if line.product_id == self.product_3: - self.assertEquals(line.qty_outgoing, 2, + self.assertEquals(line.qty_outgoing, 0, "Wrong qty delivered") self.assertEquals(line.qty_to_receive, 2, "Wrong qty to receive") @@ -96,11 +96,11 @@ class TestSupplierRma(test_rma.TestRma): proc.group_id]) domain = [('group_id', 'in', list(group_ids))] pickings = self.stockpicking.search(domain) - self.assertEquals(len(pickings), 3, + self.assertEquals(len(pickings), 2, "Incorrect number of pickings created") - picking_out = pickings[0] + picking_out = pickings[1] moves = picking_out.move_lines - self.assertEquals(len(moves), 2, + self.assertEquals(len(moves), 3, "Incorrect number of moves created") for line in self.rma_supplier_id.rma_line_ids: self.assertEquals(line.qty_incoming, 0, @@ -117,12 +117,12 @@ class TestSupplierRma(test_rma.TestRma): if line.product_id == self.product_2: self.assertEquals(line.qty_to_receive, 5, "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, + self.assertEquals(line.qty_to_deliver, 0, "Wrong qty to deliver") if line.product_id == self.product_3: self.assertEquals(line.qty_to_receive, 2, "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, + self.assertEquals(line.qty_to_deliver, 0, "Wrong qty to deliver") picking_out.action_assign() picking_out.do_transfer() @@ -131,14 +131,14 @@ class TestSupplierRma(test_rma.TestRma): "Wrong qty to receive") self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 3, + self.assertEquals(line.qty_delivered, 6, + "Wrong qty deliver") + self.assertEquals(line.qty_outgoing, 0, "Wrong qty outgoing") if line.product_id == self.product_1: self.assertEquals(line.qty_received, 0, "Wrong qty received") - self.assertEquals(line.qty_delivered, 3, + self.assertEquals(line.qty_delivered, 6, "Wrong qty delivered") if line.product_id == self.product_2: self.assertEquals(line.qty_received, 0, From 986eafa7703cc1bf470eb26342ace7bfb13661b9 Mon Sep 17 00:00:00 2001 From: Maxime Chambreuil Date: Fri, 9 Feb 2018 12:35:23 -0600 Subject: [PATCH 15/93] [MIG] Migrate configuration and cleanup --- rma_account/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 93f226c5..df3f6b71 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -20,6 +20,6 @@ 'wizards/rma_add_invoice.xml', 'wizards/rma_refund.xml', ], - 'installable': True, + 'installable': False, 'auto_install': True, } From 23ea7af85e054426ca4c4974a1fb6360c0ba2c82 Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Wed, 23 May 2018 19:13:03 +0200 Subject: [PATCH 16/93] [9.0][IMP] rma_sale and rma_account: consider product when filtering sources on rma lines --- rma_account/models/rma_order_line.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 5426bc2a..3230c1a7 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -79,6 +79,21 @@ class RmaOrderLine(models.Model): digits=dp.get_precision('Product Unit of Measure'), readonly=True, compute=_compute_qty_refunded, store=True) + @api.onchange('product_id') + def _onchange_product_id(self): + res = super(RmaOrderLine, self)._onchange_product_id() + if res.get('domain') and self.product_id: + res['domain']['invoice_line_id'] = [ + ('product_id', '=', self.product_id.id)] + elif res.get('domain') and self.product_id: + res['domain']['invoice_line_id'] = [()] + elif not res.get('domain') and self.product_id: + res['domain'] = { + 'invoice_line_id': [('product_id', '=', self.product_id.id)]} + else: + res['domain'] = {'invoice_line_id': []} + return res + @api.multi def _prepare_rma_line_from_inv_line(self, line): self.ensure_one() From 20291752397d1304b478a0a1ffe26b03065aea75 Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Thu, 17 May 2018 12:40:52 +0200 Subject: [PATCH 17/93] [9.0] rma_account: * fix view * small issue in wizard * modify data file * smaller issues --- rma_account/demo/rma_operation.xml | 2 ++ rma_account/models/rma_order_line.py | 5 ++--- rma_account/views/rma_order_line_view.xml | 19 ++++++++++++------- rma_account/wizards/rma_refund.py | 21 +++++++++++---------- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/rma_account/demo/rma_operation.xml b/rma_account/demo/rma_operation.xml index a312d6db..be6fd118 100644 --- a/rma_account/demo/rma_operation.xml +++ b/rma_account/demo/rma_operation.xml @@ -17,6 +17,7 @@ no customer + @@ -26,6 +27,7 @@ no no supplier + diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 3230c1a7..81789c18 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -177,9 +177,8 @@ class RmaOrderLine(models.Model): @api.onchange('operation_id') def _onchange_operation_id(self): result = super(RmaOrderLine, self)._onchange_operation_id() - if not self.operation_id: - return result - self.refund_policy = self.operation_id.refund_policy + if self.operation_id: + self.refund_policy = self.operation_id.refund_policy or 'no' return result @api.multi diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index 50b1b344..166b9c16 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -49,13 +49,18 @@ + + Date: Thu, 24 May 2018 13:27:13 +0200 Subject: [PATCH 18/93] [ADD] rma_account: add rma menu on the accounting app --- rma_account/__manifest__.py | 1 + rma_account/views/rma_account_menu.xml | 51 +++++++++++++++++++++++ rma_account/views/rma_order_line_view.xml | 11 ++++- 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 rma_account/views/rma_account_menu.xml diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index df3f6b71..07fadf99 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -17,6 +17,7 @@ 'views/rma_operation_view.xml', 'views/rma_order_line_view.xml', 'views/invoice_view.xml', + 'views/rma_account_menu.xml', 'wizards/rma_add_invoice.xml', 'wizards/rma_refund.xml', ], diff --git a/rma_account/views/rma_account_menu.xml b/rma_account/views/rma_account_menu.xml new file mode 100644 index 00000000..a62c6e07 --- /dev/null +++ b/rma_account/views/rma_account_menu.xml @@ -0,0 +1,51 @@ + + + + + + + + + + Customer RMA + rma.order.line + [('type','=', 'customer')] + {"search_default_to_refund":1} + form + tree,form + + + + Supplier RMA + rma.order.line + [('type','=', 'supplier')] + {"search_default_to_refund":1, "supplier":1} + form + tree,form + + + + + + + + diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index 166b9c16..f686e5d5 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -93,12 +93,21 @@ rma.order.line.select rma.order.line - + + + + + + + + + From 2a11e957b1ef4830a01189cc00179012e8f17e6d Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Fri, 25 May 2018 10:13:47 +0200 Subject: [PATCH 19/93] fixup! rma account menus --- rma_account/views/rma_account_menu.xml | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/rma_account/views/rma_account_menu.xml b/rma_account/views/rma_account_menu.xml index a62c6e07..7388a537 100644 --- a/rma_account/views/rma_account_menu.xml +++ b/rma_account/views/rma_account_menu.xml @@ -3,18 +3,6 @@ License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) --> - - - - Customer RMA rma.order.line @@ -35,16 +23,16 @@ From f216de7b8b68c21699e1f051ee5fdba928daf52b Mon Sep 17 00:00:00 2001 From: aaron Date: Fri, 25 May 2018 18:25:54 +0200 Subject: [PATCH 20/93] [IMP]add rma lines to invoices as it is done with PO --- rma_account/models/invoice.py | 51 ++++++++++++++++++++++++++++ rma_account/models/rma_order_line.py | 13 +++++++ rma_account/views/invoice_view.xml | 36 ++++++++++++++++++++ 3 files changed, 100 insertions(+) diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index 233ec0d7..06d74042 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -3,6 +3,7 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import api, fields, models +from odoo.tools.float_utils import float_compare class AccountInvoice(models.Model): @@ -14,9 +15,59 @@ class AccountInvoice(models.Model): rmas = self.mapped('invoice_line_ids.rma_line_ids') inv.rma_count = len(rmas) + def _prepare_invoice_line_from_rma_line(self, line): + qty = line.qty_to_refund + if float_compare( + qty, 0.0, precision_rounding=line.uom_id.rounding) <= 0: + qty = 0.0 + # Todo fill taxes from somewhere + invoice_line = self.env['account.invoice.line'] + data = { + 'purchase_line_id': line.id, + 'name': line.name + ': '+line.name, + 'origin': line.origin, + 'uom_id': line.uom_id.id, + 'product_id': line.product_id.id, + 'account_id': invoice_line.with_context( + {'journal_id': self.journal_id.id, + 'type': 'in_invoice'})._default_account(), + 'price_unit': line.company_id.currency_id.with_context( + date=self.date_invoice).compute( + line.price_unit, self.currency_id, round=False), + 'quantity': qty, + 'discount': 0.0, + 'account_analytic_id': line.analytic_account_id.id, + 'rma_line_ids': [(4, line.id)], + } + return data + + @api.onchange('add_rma_line_id') + def on_change_add_rma_line_id(self): + if not self.add_rma_line_id: + return {} + if not self.partner_id: + self.partner_id = self.add_rma_line_id.partner_id.id + + new_line = self.env['account.invoice.line'] + if self.add_rma_line_id not in ( + self.invoice_line_ids.mapped('rma_line_id')): + data = self._prepare_invoice_line_from_rma_line( + self.add_rma_line_id) + new_line = new_line.new(data) + new_line._set_additional_fields(self) + self.invoice_line_ids += new_line + self.add_rma_line_id = False + return {} + rma_count = fields.Integer( compute=_compute_rma_count, string='# of RMA') + add_rma_line_id = fields.Many2one( + comodel_name='rma.order.line', + string="Add from RMA line", + ondelete="set null", + help="Create a refund in based on an existing rma_line") + @api.multi def action_view_rma_supplier(self): action = self.env.ref('rma.action_rma_supplier_lines') diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 81789c18..2d49f855 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -218,3 +218,16 @@ class RmaOrderLine(models.Model): result['views'] = [(res and res.id or False, 'form')] result['res_id'] = invoice_ids[0] return result + + @api.multi + def name_get(self): + res = [] + if self.env.context.get('rma'): + for rma in self: + res.append((rma.id, "%s %s qty:%s" % ( + rma.name, + rma.product_id.name, + rma.product_qty))) + return res + else: + return super(RmaOrderLine, self).name_get() diff --git a/rma_account/views/invoice_view.xml b/rma_account/views/invoice_view.xml index c1097905..8b24a07d 100644 --- a/rma_account/views/invoice_view.xml +++ b/rma_account/views/invoice_view.xml @@ -62,6 +62,42 @@ + + account.invoice.supplier.rma + account.invoice + + + + + + + + + + account.invoice.customer.rma + account.invoice + + + + + + + + Invoice Line account.invoice.line From 77901e5cc51224f5c514b15a86085e3bfbee2f62 Mon Sep 17 00:00:00 2001 From: aaron Date: Thu, 31 May 2018 10:30:21 +0200 Subject: [PATCH 21/93] [IMP]nicer name_get in the invoice --- rma_account/models/invoice.py | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index 06d74042..b7309659 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -100,6 +100,55 @@ class AccountInvoice(models.Model): class AccountInvoiceLine(models.Model): _inherit = "account.invoice.line" + @api.model + def name_search(self, name, args=None, operator='ilike', limit=100): + """Allows to search by Invoice number. This has to be done this way, + as Odoo adds extra args to name_search on _name_search method that + will make impossible to get the desired result.""" + if not args: + args = [] + lines = self.search( + [('invoice_id.number', operator, name)] + args, limit=limit, + ) + res = lines.name_get() + if limit: + limit_rest = limit - len(lines) + else: + # limit can be 0 or None representing infinite + limit_rest = limit + if limit_rest or not limit: + args += [('id', 'not in', lines.ids)] + res += super(AccountInvoiceLine, self).name_search( + name, args=args, operator=operator, limit=limit_rest, + ) + return res + + @api.multi + def name_get(self): + res = [] + if self.env.context.get('rma'): + for inv in self: + if inv.invoice_id.reference: + res.append( + (inv.id, + "INV:%s | REF:%s | ORIG:%s | PART:%s | QTY:%s" % ( + inv.invoice_id.number or '', + inv.origin or '', + inv.invoice_id.reference or "", + inv.product_id.name, inv.quantity))) + elif inv.invoice_id.number: + res.append( + (inv.id, + "INV:%s | ORIG:%s | PART:%s | QTY:%s" % ( + inv.invoice_id.number or '', + inv.origin or '', + inv.product_id.name, inv.quantity))) + else: + res.append(super(AccountInvoiceLine, inv).name_get()[0]) + return res + else: + return super(AccountInvoiceLine, self).name_get() + @api.multi def _compute_rma_count(self): for invl in self: From 7a6254572bedcbf712ab3081228c24e6c433c79d Mon Sep 17 00:00:00 2001 From: Bhavesh Odedra Date: Fri, 9 Feb 2018 22:47:33 +0530 Subject: [PATCH 22/93] [11.0] MIG: rma_account --- rma_account/README.rst | 1 + rma_account/__init__.py | 2 +- rma_account/__manifest__.py | 5 +- rma_account/demo/rma_operation.xml | 8 +- rma_account/models/__init__.py | 2 +- rma_account/models/invoice.py | 35 ++-- rma_account/models/rma_operation.py | 2 +- rma_account/models/rma_order.py | 20 +-- rma_account/models/rma_order_line.py | 8 +- rma_account/tests/__init__.py | 2 +- rma_account/tests/test_rma.py | 52 +++--- rma_account/tests/test_rma_dropship.py | 13 +- rma_account/tests/test_supplier_rma.py | 75 +++----- rma_account/views/invoice_view.xml | 6 +- rma_account/views/rma_operation_view.xml | 40 ++--- rma_account/views/rma_order_line_view.xml | 167 +++++++++--------- rma_account/views/rma_order_view.xml | 122 +++++++------ rma_account/wizards/__init__.py | 1 - rma_account/wizards/rma_add_invoice.py | 5 - .../rma_order_line_make_supplier_rma.py | 1 - rma_account/wizards/rma_refund.py | 17 +- rma_account/wizards/rma_refund.xml | 141 +++++++-------- 22 files changed, 339 insertions(+), 386 deletions(-) diff --git a/rma_account/README.rst b/rma_account/README.rst index 56f20fd3..c8003352 100644 --- a/rma_account/README.rst +++ b/rma_account/README.rst @@ -43,6 +43,7 @@ Contributors * Jordi Ballester Alomar * Aaron Henriquez * Lois Rilo +* Bhavesh Odedra Maintainer ---------- diff --git a/rma_account/__init__.py b/rma_account/__init__.py index 4105ff51..f3284a96 100644 --- a/rma_account/__init__.py +++ b/rma_account/__init__.py @@ -1,5 +1,5 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + from . import models from . import wizards diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 07fadf99..dfd00108 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -1,10 +1,9 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) { 'name': 'RMA Account', - 'version': '9.0.1.0.0', + 'version': '11.0.1.0.0', 'license': 'LGPL-3', 'category': 'RMA', 'summary': 'Integrates RMA with Invoice Processing', @@ -21,6 +20,6 @@ 'wizards/rma_add_invoice.xml', 'wizards/rma_refund.xml', ], - 'installable': False, + 'installable': True, 'auto_install': True, } diff --git a/rma_account/demo/rma_operation.xml b/rma_account/demo/rma_operation.xml index be6fd118..9a4e5738 100644 --- a/rma_account/demo/rma_operation.xml +++ b/rma_account/demo/rma_operation.xml @@ -1,5 +1,5 @@ - - + + no @@ -35,10 +35,6 @@ no - - no - - no diff --git a/rma_account/models/__init__.py b/rma_account/models/__init__.py index 90fbe336..bdd70de6 100644 --- a/rma_account/models/__init__.py +++ b/rma_account/models/__init__.py @@ -1,6 +1,6 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + from . import rma_order from . import rma_order_line from . import rma_operation diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index b7309659..18eeeda7 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) @@ -72,28 +71,30 @@ class AccountInvoice(models.Model): def action_view_rma_supplier(self): action = self.env.ref('rma.action_rma_supplier_lines') result = action.read()[0] - rma_list = self.mapped('invoice_line_ids.rma_line_ids').ids - # choose the view_mode accordingly - if len(rma_list) != 1: - result['domain'] = [('id', 'in', rma_list)] - elif len(rma_list) == 1: - res = self.env.ref('rma.view_rma_line_supplier_form', False) - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = rma_list[0] + rma_ids = self.mapped('invoice_line_ids.rma_line_ids').ids + if rma_ids: + # choose the view_mode accordingly + if len(rma_ids) > 1: + result['domain'] = [('id', 'in', rma_ids)] + else: + res = self.env.ref('rma.view_rma_line_supplier_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = rma_ids[0] return result @api.multi def action_view_rma_customer(self): action = self.env.ref('rma.action_rma_customer_lines') result = action.read()[0] - rma_list = self.mapped('invoice_line_ids.rma_line_ids').ids - # choose the view_mode accordingly - if len(rma_list) != 1: - result['domain'] = [('id', 'in', rma_list)] - elif len(rma_list) == 1: - res = self.env.ref('rma.view_rma_line_form', False) - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = rma_list[0] + rma_ids = self.mapped('invoice_line_ids.rma_line_ids').ids + if rma_ids: + # choose the view_mode accordingly + if len(rma_ids) > 1: + result['domain'] = [('id', 'in', rma_ids)] + else: + res = self.env.ref('rma.view_rma_line_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = rma_ids[0] return result diff --git a/rma_account/models/rma_operation.py b/rma_account/models/rma_operation.py index 55aeea40..043826c6 100644 --- a/rma_account/models/rma_operation.py +++ b/rma_account/models/rma_operation.py @@ -1,6 +1,6 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + from odoo import fields, models diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index 7b710b47..e16f4ca3 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -1,6 +1,6 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + from odoo import api, fields, models @@ -94,30 +94,28 @@ class RmaOrder(models.Model): invoice_ids = self.mapped( 'rma_line_ids.refund_line_ids.invoice_id').ids # choose the view_mode accordingly - if len(invoice_ids) != 1: + if len(invoice_ids) > 1: result['domain'] = [('id', 'in', invoice_ids)] - elif len(invoice_ids) == 1: + else: res = self.env.ref('account.invoice_supplier_form', False) result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = invoice_ids[0] + result['res_id'] = invoice_ids and invoice_ids[0] return result @api.multi def action_view_invoice(self): if self.type == "supplier": action = self.env.ref('account.action_invoice_tree2') + res = self.env.ref('account.invoice_supplier_form', False) else: action = self.env.ref('account.action_invoice_tree') + res = self.env.ref('account.invoice_form', False) result = action.read()[0] invoice_ids = self.mapped('rma_line_ids.invoice_id').ids # choose the view_mode accordingly - if len(invoice_ids) != 1: + if len(invoice_ids) > 1: result['domain'] = [('id', 'in', invoice_ids)] - elif len(invoice_ids) == 1: - if self.type == "supplier": - res = self.env.ref('account.invoice_supplier_form', False) - else: - res = self.env.ref('account.invoice_form', False) + else: result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = invoice_ids[0] + result['res_id'] = invoice_ids and invoice_ids[0] return result diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 2d49f855..dc1eb29e 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -1,6 +1,6 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + from odoo import _, api, fields, models from odoo.exceptions import ValidationError, UserError from odoo.addons import decimal_precision as dp @@ -211,12 +211,12 @@ class RmaOrderLine(models.Model): result = action.read()[0] invoice_ids = self.mapped('refund_line_ids.invoice_id').ids # choose the view_mode accordingly - if len(invoice_ids) != 1: + if len(invoice_ids) > 1: result['domain'] = [('id', 'in', invoice_ids)] - elif len(invoice_ids) == 1: + else: res = self.env.ref('account.invoice_supplier_form', False) result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = invoice_ids[0] + result['res_id'] = invoice_ids and invoice_ids[0] return result @api.multi diff --git a/rma_account/tests/__init__.py b/rma_account/tests/__init__.py index dfa77946..fd0efa32 100644 --- a/rma_account/tests/__init__.py +++ b/rma_account/tests/__init__.py @@ -1,6 +1,6 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + from . import test_rma from . import test_supplier_rma from . import test_rma_dropship diff --git a/rma_account/tests/test_rma.py b/rma_account/tests/test_rma.py index d57c0090..78b96232 100644 --- a/rma_account/tests/test_rma.py +++ b/rma_account/tests/test_rma.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) @@ -275,13 +274,11 @@ class TestRma(common.TransactionCase): 'picking_type': 'incoming', 'active_id': 1 }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") + wizard._create_picking() + res = self.rma_customer_id.rma_line_ids.action_view_in_shipments() + self.assertTrue('res_id' in res, + "Incorrect number of pickings created") + picking = self.env['stock.picking'].browse(res['res_id']) moves = picking.move_lines self.assertEquals(len(moves), 3, "Incorrect number of moves created") @@ -297,22 +294,31 @@ class TestRma(common.TransactionCase): "Wrong qty delivered") # product specific if line.product_id == self.product_1: + self.assertEquals(line.qty_to_deliver, 0, + "Wrong qty to deliver") self.assertEquals(line.qty_to_receive, 3, "Wrong qty to receive") self.assertEquals(line.qty_incoming, 3, "Wrong qty incoming") if line.product_id == self.product_2: + self.assertEquals(line.qty_to_deliver, 0, + "Wrong qty to deliver") self.assertEquals(line.qty_to_receive, 5, "Wrong qty to receive") self.assertEquals(line.qty_incoming, 5, "Wrong qty incoming") if line.product_id == self.product_3: + self.assertEquals(line.qty_to_deliver, 0, + "Wrong qty to deliver") self.assertEquals(line.qty_to_receive, 2, "Wrong qty to receive") self.assertEquals(line.qty_incoming, 2, "Wrong qty incoming") picking.action_assign() - picking.do_transfer() + picking.action_assign() + for line in picking.move_line_ids: + line.qty_done = line.product_uom_qty + picking.action_done() for line in self.rma_customer_id.rma_line_ids: self.assertEquals(line.qty_to_receive, 0, "Wrong qty to_receive") @@ -344,15 +350,12 @@ class TestRma(common.TransactionCase): 'active_model': 'rma.order.line', 'picking_type': 'outgoing', }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - pickings = self.stockpicking.search(domain) - self.assertEquals(len(pickings), 2, - "Incorrect number of pickings created") - picking_out = pickings[1] - moves = picking_out.move_lines + wizard._create_picking() + res = self.rma_customer_id.rma_line_ids.action_view_out_shipments() + self.assertTrue('res_id' in res, + "Incorrect number of pickings created") + picking = self.env['stock.picking'].browse(res['res_id']) + moves = picking.move_lines self.assertEquals(len(moves), 3, "Incorrect number of moves created") for line in self.rma_customer_id.rma_line_ids: @@ -383,13 +386,12 @@ class TestRma(common.TransactionCase): "Wrong qty to deliver") self.assertEquals(line.qty_outgoing, 2, "Wrong qty outgoing") - picking_out.action_assign() - picking_out.do_transfer() - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_to_receive, 0, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") + picking.action_confirm() + picking.action_assign() + for line in picking.move_line_ids: + line.qty_done = line.product_uom_qty + picking.action_done() + for line in self.rma_customer_id.rma_line_ids[0]: self.assertEquals(line.qty_to_deliver, 0, "Wrong qty to deliver") self.assertEquals(line.qty_outgoing, 0, diff --git a/rma_account/tests/test_rma_dropship.py b/rma_account/tests/test_rma_dropship.py index abe07221..c469252d 100644 --- a/rma_account/tests/test_rma_dropship.py +++ b/rma_account/tests/test_rma_dropship.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) @@ -45,13 +44,11 @@ class TestRmaDropship(test_rma.TestRma): 'active_model': 'rma.order.line', 'picking_type': 'incoming', }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") + wizard._create_picking() + res = supplier_rma.rma_line_ids.action_view_in_shipments() + self.assertTrue('res_id' in res, + "Incorrect number of pickings created") + picking = self.env['stock.picking'].browse(res['res_id']) moves = picking.move_lines self.assertEquals(len(moves), 3, "Incorrect number of moves created") diff --git a/rma_account/tests/test_supplier_rma.py b/rma_account/tests/test_supplier_rma.py index 321b46e1..8da1bd0c 100644 --- a/rma_account/tests/test_supplier_rma.py +++ b/rma_account/tests/test_supplier_rma.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) @@ -22,13 +21,11 @@ class TestSupplierRma(test_rma.TestRma): 'picking_type': 'outgoing', 'active_id': 1 }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, - "Incorrect number of pickings created") + wizard._create_picking() + res = self.rma_supplier_id.rma_line_ids.action_view_out_shipments() + self.assertTrue('res_id' in res, + "Incorrect number of pickings created") + picking = self.env['stock.picking'].browse(res['res_id']) moves = picking.move_lines self.assertEquals(len(moves), 3, "Incorrect number of moves created") @@ -62,9 +59,10 @@ class TestSupplierRma(test_rma.TestRma): "Wrong qty to deliver") self.assertEquals(line.qty_outgoing, 2, "Wrong qty outgoing") - - picking.action_assign() - picking.do_transfer() + picking.force_assign() + for line in picking.move_lines: + line.quantity_done = line.product_uom_qty + picking.button_validate() for line in self.rma_supplier_id.rma_line_ids: self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") @@ -76,12 +74,12 @@ class TestSupplierRma(test_rma.TestRma): self.assertEquals(line.qty_to_receive, 3, "Wrong qty to receive") if line.product_id == self.product_2: - self.assertEquals(line.qty_outgoing, 0, + self.assertEquals(line.qty_delivered, 5, "Wrong qty delivered") self.assertEquals(line.qty_to_receive, 5, "Wrong qty to receive") if line.product_id == self.product_3: - self.assertEquals(line.qty_outgoing, 0, + self.assertEquals(line.qty_delivered, 2, "Wrong qty delivered") self.assertEquals(line.qty_to_receive, 2, "Wrong qty to receive") @@ -91,65 +89,48 @@ class TestSupplierRma(test_rma.TestRma): 'active_model': 'rma.order.line', 'picking_type': 'incoming', }).create({}) - procurements = wizard._create_picking() - group_ids = set([proc.group_id.id for proc in procurements if - proc.group_id]) - domain = [('group_id', 'in', list(group_ids))] - pickings = self.stockpicking.search(domain) - self.assertEquals(len(pickings), 2, - "Incorrect number of pickings created") - picking_out = pickings[1] - moves = picking_out.move_lines + wizard._create_picking() + res = self.rma_supplier_id.rma_line_ids.action_view_in_shipments() + self.assertTrue('res_id' in res, + "Incorrect number of pickings created") + picking = self.env['stock.picking'].browse(res['res_id']) + moves = picking.move_lines self.assertEquals(len(moves), 3, "Incorrect number of moves created") for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") self.assertEquals(line.qty_received, 0, "Wrong qty received") if line.product_id == self.product_1: self.assertEquals(line.qty_to_receive, 3, "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, + self.assertEquals(line.qty_incoming, 3, "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 3, - "Wrong qty delivered") if line.product_id == self.product_2: self.assertEquals(line.qty_to_receive, 5, "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") + self.assertEquals(line.qty_incoming, 5, + "Wrong qty incoming") if line.product_id == self.product_3: self.assertEquals(line.qty_to_receive, 2, "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - picking_out.action_assign() - picking_out.do_transfer() + self.assertEquals(line.qty_incoming, 2, + "Wrong qty incoming") + picking.action_assign() + for line in picking.move_line_ids: + line.qty_done = line.product_uom_qty + picking.action_done() for line in self.rma_supplier_id.rma_line_ids[0]: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") self.assertEquals(line.qty_incoming, 0, "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 6, - "Wrong qty deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 0, + self.assertEquals(line.qty_received, 3, "Wrong qty received") - self.assertEquals(line.qty_delivered, 6, - "Wrong qty delivered") if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 0, + self.assertEquals(line.qty_received, 5, "Wrong qty received") - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") if line.product_id == self.product_3: self.assertEquals(line.qty_received, 2, "Wrong qty received") - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") for line in self.rma_supplier_id.rma_line_ids: line.action_rma_done() self.assertEquals(line.state, 'done', diff --git a/rma_account/views/invoice_view.xml b/rma_account/views/invoice_view.xml index 8b24a07d..e984b90e 100644 --- a/rma_account/views/invoice_view.xml +++ b/rma_account/views/invoice_view.xml @@ -1,7 +1,5 @@ - + - - account.invoice.form account.invoice @@ -60,7 +58,6 @@ - account.invoice.supplier.rma @@ -105,5 +102,4 @@ form - diff --git a/rma_account/views/rma_operation_view.xml b/rma_account/views/rma_operation_view.xml index 671a2a0e..6f9c4062 100644 --- a/rma_account/views/rma_operation_view.xml +++ b/rma_account/views/rma_operation_view.xml @@ -1,26 +1,24 @@ - + - - - rma.operation.tree - rma.operation - - - - - + + rma.operation.tree + rma.operation + + + + - + + - - rma.operation.form - rma.operation - - - - - + + rma.operation.form + rma.operation + + + + - - + + diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index f686e5d5..883559ce 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -1,47 +1,40 @@ - + - - - rma.order.line.supplier.form - rma.order.line - - - - - - - - - - - - - - - - - - - - - - - - + + rma.order.line.supplier.form + rma.order.line + + + + + + + + + - + + + + + + + + + + rma.order.line.form @@ -69,47 +62,61 @@ ('invoice_id.partner_id', '=', partner_id), ('invoice_id.partner_id', 'child_of', partner_id)]"/> - - - - - - - + + + + + + rma.order.line.form + rma.order.line + + + + + + + + + + + + + - - - - - - - - - + + + - - - - rma.order.line.select - rma.order.line - - - - - - - - - + + + + - - + + + + + rma.order.line.select + rma.order.line + + + + - - - - + + diff --git a/rma_account/views/rma_order_view.xml b/rma_account/views/rma_order_view.xml index dbbe0658..270b1058 100644 --- a/rma_account/views/rma_order_view.xml +++ b/rma_account/views/rma_order_view.xml @@ -1,68 +1,64 @@ - + - - - - rma.order.form - rma_account - rma.order - - - - + + rma.order.form - rma_account + rma.order + + + - - - - - - rma.order.supplier.form - rma.order - - - - + - - - + + + + - + + rma.order.supplier.form + rma.order + + + + + + + + diff --git a/rma_account/wizards/__init__.py b/rma_account/wizards/__init__.py index 0e1ebd69..e3832b10 100644 --- a/rma_account/wizards/__init__.py +++ b/rma_account/wizards/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index db087c61..8c44205d 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) @@ -90,10 +89,6 @@ class RmaAddInvoice(models.TransientModel): def _get_rma_data(self): data = { 'date_rma': fields.Datetime.now(), - 'delivery_address_id': - self.invoice_line_ids[0].invoice_id.partner_id.id, - 'invoice_address_id': - self.invoice_line_ids[0].invoice_id.partner_id.id } return data diff --git a/rma_account/wizards/rma_order_line_make_supplier_rma.py b/rma_account/wizards/rma_order_line_make_supplier_rma.py index ead4574d..bbd94cd1 100644 --- a/rma_account/wizards/rma_order_line_make_supplier_rma.py +++ b/rma_account/wizards/rma_order_line_make_supplier_rma.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2016 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index d0b1ad76..57491a76 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -1,10 +1,8 @@ -# -*- coding: utf-8 -*- # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import _, api, fields, models from odoo.exceptions import ValidationError -from odoo.tools.safe_eval import safe_eval as eval import odoo.addons.decimal_precision as dp @@ -38,6 +36,7 @@ class RmaRefund(models.TransientModel): lines the supplier field is empty otherwise is the unique line supplier. """ + context = self._context.copy() res = super(RmaRefund, self).default_get(fields) rma_line_obj = self.env['rma.order.line'] rma_line_ids = self.env.context['active_ids'] or [] @@ -55,6 +54,7 @@ class RmaRefund(models.TransientModel): for line in lines: items.append([0, 0, self._prepare_item(line)]) res['item_ids'] = items + context.update({'items_ids': items}) return res date_invoice = fields.Date( @@ -96,11 +96,11 @@ class RmaRefund(models.TransientModel): new_invoice = self.compute_refund() action = 'action_invoice_tree1' if ( new_invoice.type in ['out_refund', 'out_invoice']) \ - else 'action_invoice_tree2' + else 'action_invoice_in_refund' result = self.env.ref('account.%s' % action).read()[0] - invoice_domain = eval(result['domain']) - invoice_domain.append(('id', '=', new_invoice.id)) - result['domain'] = invoice_domain + form_view = self.env.ref('account.invoice_supplier_form', False) + result['views'] = [(form_view and form_view.id or False, 'form')] + result['res_id'] = new_invoice.id return result @api.model @@ -189,8 +189,9 @@ class RmaRefundItem(models.TransientModel): related='line_id.rma_id', string='RMA', readonly=True) - product_id = fields.Many2one('product.product', string='Product', - readonly=True) + product_id = fields.Many2one('product.product', string='Product') + product = fields.Many2one('product.product', string='Product', + readonly=True) name = fields.Char(string='Description', required=True) product_qty = fields.Float( string='Quantity Ordered', copy=False, diff --git a/rma_account/wizards/rma_refund.xml b/rma_account/wizards/rma_refund.xml index 52efcd46..df4c548a 100644 --- a/rma_account/wizards/rma_refund.xml +++ b/rma_account/wizards/rma_refund.xml @@ -1,85 +1,72 @@ - - - - rma.refund.form - rma.refund - - - - - - - - - - - - - - - - - - - - - -
-
- -
-
- - - Create Refund - rma.refund - form - tree,form - - - new - - - - rma.order.line.form - rma.order.line - - - - - - - - + + + + @@ -108,15 +84,4 @@ - - rma.order.line.select - rma.order.line - - - - - - -
diff --git a/rma_account/wizards/rma_add_invoice.xml b/rma_account/wizards/rma_add_invoice.xml index c0d9e412..0ecb13ab 100644 --- a/rma_account/wizards/rma_add_invoice.xml +++ b/rma_account/wizards/rma_add_invoice.xml @@ -1,4 +1,4 @@ - + diff --git a/rma_account/wizards/rma_refund.xml b/rma_account/wizards/rma_refund.xml index df4c548a..52285b66 100644 --- a/rma_account/wizards/rma_refund.xml +++ b/rma_account/wizards/rma_refund.xml @@ -1,4 +1,4 @@ - + rma.refund.form From 1eed738578f8d5030ed2992d54083bfeadef1364 Mon Sep 17 00:00:00 2001 From: Maxime Chambreuil Date: Tue, 24 Jul 2018 10:16:58 -0500 Subject: [PATCH 24/93] Update __manifest__.py --- rma_account/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 52ef3732..db64990b 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -22,5 +22,5 @@ 'wizards/rma_refund.xml', ], 'installable': True, - 'auto_install': False, + 'auto_install': True, } From 3aaca00725eb63764a9051625a5552e7b9afd3c2 Mon Sep 17 00:00:00 2001 From: Bhavesh Odedra Date: Wed, 25 Jul 2018 10:20:46 +0530 Subject: [PATCH 25/93] [FIX] navigation button issue TypeError: unhashable type: 'list' --- rma_account/models/rma_order.py | 28 +++++++++++++++------------- rma_account/models/rma_order_line.py | 15 ++++++++------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index e16f4ca3..20d4f89b 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -93,13 +93,14 @@ class RmaOrder(models.Model): result = action.read()[0] invoice_ids = self.mapped( 'rma_line_ids.refund_line_ids.invoice_id').ids - # choose the view_mode accordingly - if len(invoice_ids) > 1: - result['domain'] = [('id', 'in', invoice_ids)] - else: - res = self.env.ref('account.invoice_supplier_form', False) - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = invoice_ids and invoice_ids[0] + if invoice_ids: + # choose the view_mode accordingly + if len(invoice_ids) > 1: + result['domain'] = [('id', 'in', invoice_ids)] + else: + res = self.env.ref('account.invoice_supplier_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = invoice_ids[0] return result @api.multi @@ -112,10 +113,11 @@ class RmaOrder(models.Model): res = self.env.ref('account.invoice_form', False) result = action.read()[0] invoice_ids = self.mapped('rma_line_ids.invoice_id').ids - # choose the view_mode accordingly - if len(invoice_ids) > 1: - result['domain'] = [('id', 'in', invoice_ids)] - else: - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = invoice_ids and invoice_ids[0] + if invoice_ids: + # choose the view_mode accordingly + if len(invoice_ids) > 1: + result['domain'] = [('id', 'in', invoice_ids)] + else: + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = invoice_ids[0] return result diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 4cc4ee82..66abd2d9 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -210,13 +210,14 @@ class RmaOrderLine(models.Model): action = self.env.ref('account.action_invoice_tree2') result = action.read()[0] invoice_ids = self.mapped('refund_line_ids.invoice_id').ids - # choose the view_mode accordingly - if len(invoice_ids) > 1: - result['domain'] = [('id', 'in', invoice_ids)] - else: - res = self.env.ref('account.invoice_supplier_form', False) - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = invoice_ids and invoice_ids[0] + if invoice_ids: + # choose the view_mode accordingly + if len(invoice_ids) > 1: + result['domain'] = [('id', 'in', invoice_ids)] + else: + res = self.env.ref('account.invoice_supplier_form', False) + result['views'] = [(res and res.id or False, 'form')] + result['res_id'] = invoice_ids[0] return result @api.multi From ea83bb64b40a461f448509029cc3451e8f47f597 Mon Sep 17 00:00:00 2001 From: Bhavesh Odedra Date: Wed, 25 Jul 2018 17:35:33 +0530 Subject: [PATCH 26/93] [FIX] issue of 'Add from RMA Line' in Customer/Vendor invoice --- rma_account/models/invoice.py | 1 - rma_account/views/invoice_view.xml | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index 18eeeda7..6a88d0cc 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -35,7 +35,6 @@ class AccountInvoice(models.Model): line.price_unit, self.currency_id, round=False), 'quantity': qty, 'discount': 0.0, - 'account_analytic_id': line.analytic_account_id.id, 'rma_line_ids': [(4, line.id)], } return data diff --git a/rma_account/views/invoice_view.xml b/rma_account/views/invoice_view.xml index e984b90e..e1f19fdc 100644 --- a/rma_account/views/invoice_view.xml +++ b/rma_account/views/invoice_view.xml @@ -70,8 +70,8 @@ domain="[('type', '=', 'supplier'), ('partner_id', '=', partner_id)]" attrs="{'readonly': [('state','not in',['draft'])], - 'invisible': ['|', ('state', '=', 'done'), - ('type', '=', 'in_invoice')]}" class="oe_edit_only" + 'invisible': ['|', ('state', '=', 'paid'), + ('type', '=', 'out_invoice')]}" class="oe_edit_only" options="{'no_create': True}"/>
@@ -88,8 +88,8 @@ domain="[('type', '=', 'customer'), ('partner_id', '=', partner_id)]" attrs="{'readonly': [('state','not in',['draft'])], - 'invisible': ['|', ('state', '=', 'done'), - ('type', '=', 'out_invoice')]}" class="oe_edit_only" + 'invisible': ['|', ('state', '=', 'paid'), + ('type', '=', 'in_invoice')]}" class="oe_edit_only" options="{'no_create': True}"/>
From 49726fd4998ecdff50058aaac7ddbb7a46c6fd1c Mon Sep 17 00:00:00 2001 From: Bhavesh Odedra Date: Wed, 25 Jul 2018 17:52:40 +0530 Subject: [PATCH 27/93] [FIX] issue of filters --- rma_account/views/rma_order_line_view.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index 8389265e..a3f50a57 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -84,4 +84,15 @@
+ + rma.order.line.select + rma.order.line + + + + + + + From 9fe1b06ef1c424b93f2efa692f4da668ce2f3f67 Mon Sep 17 00:00:00 2001 From: Bhavesh Odedra Date: Wed, 25 Jul 2018 18:23:31 +0530 Subject: [PATCH 28/93] [FIX] issue of name_get when pull down list from 'Originating Invoice Line' --- rma_account/views/rma_order_line_view.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index a3f50a57..09aaf60f 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -17,6 +17,7 @@ @@ -59,6 +60,7 @@ From 4c38070fc1a48584cc02e8574ee1ecf0f8f8905a Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Thu, 17 May 2018 12:43:06 +0200 Subject: [PATCH 29/93] [9.0][REW] rma_account: complete rework of tests --- rma_account/tests/__init__.py | 6 +- rma_account/tests/test_rma.py | 416 ------------------------- rma_account/tests/test_rma_account.py | 211 +++++++++++++ rma_account/tests/test_rma_dropship.py | 105 ------- rma_account/tests/test_supplier_rma.py | 137 -------- 5 files changed, 213 insertions(+), 662 deletions(-) delete mode 100644 rma_account/tests/test_rma.py create mode 100644 rma_account/tests/test_rma_account.py delete mode 100644 rma_account/tests/test_rma_dropship.py delete mode 100644 rma_account/tests/test_supplier_rma.py diff --git a/rma_account/tests/__init__.py b/rma_account/tests/__init__.py index fd0efa32..77af78d7 100644 --- a/rma_account/tests/__init__.py +++ b/rma_account/tests/__init__.py @@ -1,6 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2018 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from . import test_rma -from . import test_supplier_rma -from . import test_rma_dropship +from . import test_rma_account diff --git a/rma_account/tests/test_rma.py b/rma_account/tests/test_rma.py deleted file mode 100644 index 78b96232..00000000 --- a/rma_account/tests/test_rma.py +++ /dev/null @@ -1,416 +0,0 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.tests import common -from openerp import fields - - -class TestRma(common.TransactionCase): - - """ Test the routes and the quantities """ - - def setUp(self): - super(TestRma, self).setUp() - - self.rma_make_picking = self.env['rma_make_picking.wizard'] - self.make_supplier_rma = self.env["rma.order.line.make.supplier.rma"] - self.rma_add_stock_move = self.env['rma_add_stock_move'] - self.stockpicking = self.env['stock.picking'] - self.rma = self.env['rma.order'] - self.rma_line = self.env['rma.order.line'] - self.rma_op = self.env['rma.operation'] - self.rma_cust_replace_op_id = self.env.ref( - 'rma.rma_operation_customer_replace') - self.rma_sup_replace_op_id = self.env.ref( - 'rma.rma_operation_supplier_replace') - self.product_id = self.env.ref('product.product_product_4') - self.product_id.product_tmpl_id.categ_id.\ - property_stock_account_input_categ_id =\ - self.env.ref('account.data_account_type_receivable').id - self.product_id.product_tmpl_id.categ_id.\ - property_stock_account_output_categ_id =\ - self.env.ref('account.data_account_type_expenses').id - self.product_1 = self.env.ref('product.product_product_25') - self.product_2 = self.env.ref('product.product_product_7') - self.product_3 = self.env.ref('product.product_product_11') - self.uom_unit = self.env.ref('product.product_uom_unit') - # assign an operation - self.product_1.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_2.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_3.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.partner_id = self.env.ref('base.res_partner_12') - self.stock_location = self.env.ref('stock.stock_location_stock') - self.stock_rma_location = self.env.ref('rma.location_rma') - self.customer_location = self.env.ref( - 'stock.stock_location_customers') - self.supplier_location = self.env.ref( - 'stock.stock_location_suppliers') - self.product_uom_id = self.env.ref('product.product_uom_unit') - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_customer_id = self._create_rma_from_move( - products2move, 'customer', self.env.ref('base.res_partner_2'), - dropship=False) - - def _create_picking(self, partner): - return self.stockpicking.create({ - 'partner_id': partner.id, - 'picking_type_id': self.env.ref('stock.picking_type_in').id, - 'location_id': self.stock_location.id, - 'location_dest_id': self.supplier_location.id - }) - - def _create_rma_from_move(self, products2move, type, partner, dropship, - supplier_address_id=None): - picking_in = self._create_picking(partner) - - moves = [] - if type == 'customer': - for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.stock_location, - self.customer_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) - else: - for item in products2move: - move_values = self._prepare_move( - item[0], item[1], self.supplier_location, - self.stock_rma_location, picking_in) - moves.append(self.env['stock.move'].create(move_values)) - # Create the RMA from the stock_move - rma_id = self.rma.create( - { - 'reference': '0001', - 'type': type, - 'partner_id': partner.id, - 'company_id': self.env.ref('base.main_company').id - }) - rma_id._compute_invoice_refund_count() - rma_id._compute_invoice_count() - - data = {'add_invoice_id': self._create_invoice().id} - new_line = self.rma.new(data) - new_line.on_change_invoice() - - rma_id.action_view_invoice_refund() - rma_id.action_view_invoice() - - for move in moves: - if type == 'customer': - wizard = self.rma_add_stock_move.new( - {'stock_move_id': move.id, 'customer': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - } - ) - wizard.with_context({ - 'stock_move_id': move.id, 'customer': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }) - data = wizard.with_context(customer=1).\ - _prepare_rma_line_from_stock_move(move) - data['partner_id'] = move.partner_id.id - else: - wizard = self.rma_add_stock_move.new( - {'stock_move_id': move.id, 'supplier': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - } - ) - wizard.with_context( - {'stock_move_id': move.id, 'supplier': True, - 'active_ids': rma_id.id, - 'partner_id': move.partner_id.id, - 'active_model': 'rma.order', - }) - data = wizard._prepare_rma_line_from_stock_move(move) - data['partner_id'] = move.partner_id.id - if dropship: - data.update(customer_to_supplier=dropship, - supplier_address_id=supplier_address_id.id) - data['partner_id'] = move.partner_id.id - data['rma_id'] = rma_id.id - self.line = self.rma_line.create(data) - # approve the RMA Line - self.line._compute_refund_count() - self.rma_line.action_rma_to_approve() - - self.line.action_rma_approve() - self.line.action_view_invoice() - self.line.action_view_refunds() - - # approve the RMA -# rma_id.action_rma_to_approve() -# rma_id.action_rma_approve() - return rma_id - - def _prepare_move(self, product, qty, src, dest, picking_in): - res = { - 'partner_id': self.partner_id.id, - 'product_id': product.id, - 'name': product.partner_ref, - 'state': 'confirmed', - 'product_uom': self.product_uom_id.id or product.uom_id.id, - 'product_uom_qty': qty, - 'origin': 'Test RMA', - 'location_id': src.id, - 'location_dest_id': dest.id, - 'picking_id': picking_in.id - } - return res - - def test_rma_refund(self): - - self.rma_refund_item = self.env['rma.refund.item'] - self.rma_refund = self.env['rma.refund'] - - self.product_id.income =\ - self.env.ref('account.data_account_type_receivable').id - self.product_id.expense =\ - self.env.ref('account.data_account_type_expenses').id - - for line in self.rma_customer_id.rma_line_ids: - line.refund_policy = 'ordered' - - refund = self.rma_refund.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({'description': 'Test Reason', - 'date_invoice': fields.datetime.now() - }) - self.rma_refund_item.create({ - 'line_id': self.rma_customer_id.rma_line_ids[0].id, - 'rma_id': self.rma_customer_id.id, - 'product_id': self.product_id.id, - 'name': 'Test RMA Refund', - 'product_qty': self.rma_customer_id.rma_line_ids[0].product_qty, - 'wiz_id': refund.id - }) - refund.invoice_refund() - - data = {'invoice_line_id': self._create_invoice().invoice_line_ids.id} - new_line = self.rma_line.new(data) - new_line._onchange_invoice_line_id() - self.rma_customer_id.action_view_invoice_refund() - self.rma_customer_id.action_view_invoice() - - def test_on_change_invoice_rma(self): - - wizard = self.env['rma_add_invoice'].with_context({ - 'active_ids': self.rma_customer_id.ids, - 'active_model': 'rma.order', - 'active_id': self.rma_customer_id.id - }).create({'partner_id': self.partner_id.id, - 'rma_id': self.rma_customer_id.id, - 'invoice_line_ids': - [(6, 0, [self._create_invoice().invoice_line_ids.id])], - }) - wizard.default_get([str(self._create_invoice().id), - str(self._create_invoice().invoice_line_ids.id), - str(self.partner_id.id)]) - wizard.add_lines() - self.rma_customer_id.action_view_invoice_refund() - self.rma_customer_id.action_view_invoice() - self.rma_customer_id.rma_line_ids[0].\ - invoice_id = self._create_invoice().id - self.rma_customer_id.action_view_invoice() - self.rma_customer_id.add_invoice_id = self._create_invoice().id - for line in self.rma_customer_id.rma_line_ids: - line.invoice_id.action_view_rma_supplier() - line.invoice_id.action_view_rma_customer() - - def _create_invoice(self): - self.Account = self.env['account.account'] - self.AccountInvoice = self.env['account.invoice'] - self.AccountInvoiceLine = self.env['account.invoice.line'] - - self.account_receivable =\ - self.env.ref('account.data_account_type_receivable') - self.account_expenses =\ - self.env.ref('account.data_account_type_expenses') - invoice_account = self.Account.\ - search([('user_type_id', '=', self.account_receivable.id)], limit=1 - ).id - invoice_line_account = self.Account.\ - search([('user_type_id', '=', self.account_expenses.id)], limit=1 - ).id - - invoice = self.AccountInvoice.create({ - 'partner_id': self.partner_id.id, - 'account_id': invoice_account, - 'type': 'in_invoice', - }) - - invoice_line = self.AccountInvoiceLine.create({ - 'product_id': self.product_1.id, - 'quantity': 1.0, - 'price_unit': 100.0, - 'invoice_id': invoice.id, - 'uom_id': 1, - 'name': 'product that cost 100', - 'account_id': invoice_line_account, - }) - invoice._compute_rma_count() - invoice_line._compute_rma_count() - invoice.action_view_rma_customer() - invoice.action_view_rma_supplier() - return invoice - - def test_customer_rma(self): - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - 'active_id': 1 - }).create({}) - wizard._create_picking() - res = self.rma_customer_id.rma_line_ids.action_view_in_shipments() - self.assertTrue('res_id' in res, - "Incorrect number of pickings created") - picking = self.env['stock.picking'].browse(res['res_id']) - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_customer_id.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty incoming") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty incoming") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty incoming") - picking.action_assign() - picking.action_assign() - for line in picking.move_line_ids: - line.qty_done = line.product_uom_qty - picking.action_done() - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_to_receive, 0, - "Wrong qty to_receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to_deliver") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to_deliver") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to_deliver") - - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': self.rma_customer_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'outgoing', - }).create({}) - wizard._create_picking() - res = self.rma_customer_id.rma_line_ids.action_view_out_shipments() - self.assertTrue('res_id' in res, - "Incorrect number of pickings created") - picking = self.env['stock.picking'].browse(res['res_id']) - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_customer_id.rma_line_ids: - self.assertEquals(line.qty_to_receive, 0, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 3, - "Wrong qty outgoing") - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 2, - "Wrong qty outgoing") - picking.action_confirm() - picking.action_assign() - for line in picking.move_line_ids: - line.qty_done = line.product_uom_qty - picking.action_done() - for line in self.rma_customer_id.rma_line_ids[0]: - self.assertEquals(line.qty_to_deliver, 0, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty outgoing") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 3, - "Wrong qty delivered") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") - self.line.action_rma_done() - self.assertEquals(self.line.state, 'done', - "Wrong State") diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py new file mode 100644 index 00000000..0d8802bf --- /dev/null +++ b/rma_account/tests/test_rma_account.py @@ -0,0 +1,211 @@ +# -*- coding: utf-8 -*- +# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from openerp.tests import common + + +class TestRmaAccount(common.SingleTransactionCase): + + @classmethod + def setUpClass(cls): + super(TestRmaAccount, cls).setUpClass() + + cls.rma_obj = cls.env['rma.order'] + cls.rma_line_obj = cls.env['rma.order.line'] + cls.rma_op_obj = cls.env['rma.operation'] + cls.rma_add_invoice_wiz = cls.env['rma_add_invoice'] + cls.rma_refund_wiz = cls.env['rma.refund'] + cls.acc_obj = cls.env['account.account'] + cls.inv_obj = cls.env['account.invoice'] + cls.invl_obj = cls.env['account.invoice.line'] + cls.product_obj = cls.env['product.product'] + cls.partner_obj = cls.env['res.partner'] + + cls.rma_route_cust = cls.env.ref('rma.route_rma_customer') + receivable_type = cls.env.ref('account.data_account_type_receivable') + payable_type = cls.env.ref('account.data_account_type_payable') + cls.cust_refund_op = cls.env.ref( + 'rma_account.rma_operation_customer_refund') + + # Create partners + customer1 = cls.partner_obj.create({'name': 'Customer 1'}) + supplier1 = cls.partner_obj.create({'name': 'Supplier 1'}) + + # Create RMA group and operation: + cls.rma_group_customer = cls.rma_obj.create({ + 'partner_id': customer1.id, + 'type': 'customer', + }) + cls.rma_group_supplier = cls.rma_obj.create({ + 'partner_id': supplier1.id, + 'type': 'supplier', + }) + cls.operation_1 = cls.rma_op_obj.create({ + 'code': 'TEST', + 'name': 'Refund and receive', + 'type': 'customer', + 'receipt_policy': 'ordered', + 'refund_policy': 'ordered', + 'in_route_id': cls.rma_route_cust.id, + 'out_route_id': cls.rma_route_cust.id, + }) + + # Create products + cls.product_1 = cls.product_obj.create({ + 'name': 'Test Product 1', + 'type': 'product', + 'list_price': 100.0, + 'rma_customer_operation_id': cls.cust_refund_op.id, + }) + cls.product_2 = cls.product_obj.create({ + 'name': 'Test Product 2', + 'type': 'product', + 'list_price': 150.0, + 'rma_customer_operation_id': cls.operation_1.id, + }) + cls.product_3 = cls.product_obj.create({ + 'name': 'Test Product 3', + 'type': 'product', + }) + cls.product_4 = cls.product_obj.create({ + 'name': 'Test Product 4', + 'type': 'product', + }) + + # Create Invoices: + customer_account = cls.acc_obj. search( + [('user_type_id', '=', receivable_type.id)], limit=1).id + cls.inv_customer = cls.inv_obj.create({ + 'partner_id': customer1.id, + 'account_id': customer_account, + 'type': 'out_invoice', + }) + cls.inv_line_1 = cls.invl_obj.create({ + 'name': cls.product_1.name, + 'product_id': cls.product_1.id, + 'quantity': 12.0, + 'price_unit': 100.0, + 'invoice_id': cls.inv_customer.id, + 'uom_id': cls.product_1.uom_id.id, + 'account_id': customer_account, + }) + cls.inv_line_2 = cls.invl_obj.create({ + 'name': cls.product_2.name, + 'product_id': cls.product_2.id, + 'quantity': 15.0, + 'price_unit': 150.0, + 'invoice_id': cls.inv_customer.id, + 'uom_id': cls.product_2.uom_id.id, + 'account_id': customer_account, + }) + + supplier_account = cls.acc_obj.search( + [('user_type_id', '=', payable_type.id)], limit=1).id + cls.inv_supplier = cls.inv_obj.create({ + 'partner_id': supplier1.id, + 'account_id': supplier_account, + 'type': 'in_invoice', + }) + cls.inv_line_3 = cls.invl_obj.create({ + 'name': cls.product_3.name, + 'product_id': cls.product_3.id, + 'quantity': 17.0, + 'price_unit': 250.0, + 'invoice_id': cls.inv_supplier.id, + 'uom_id': cls.product_3.uom_id.id, + 'account_id': supplier_account, + }) + cls.inv_line_4 = cls.invl_obj.create({ + 'name': cls.product_4.name, + 'product_id': cls.product_4.id, + 'quantity': 9.0, + 'price_unit': 300.0, + 'invoice_id': cls.inv_supplier.id, + 'uom_id': cls.product_4.uom_id.id, + 'account_id': supplier_account, + }) + + def test_01_add_from_invoice_customer(self): + """Test wizard to create RMA from a customer invoice.""" + add_inv = self.rma_add_invoice_wiz.with_context({ + 'customer': True, + 'active_ids': self.rma_group_customer.id, + 'active_model': 'rma.order', + }).create({ + 'invoice_line_ids': + [(6, 0, self.inv_customer.invoice_line_ids.ids)], + }) + add_inv.add_lines() + self.assertEqual(len(self.rma_group_customer.rma_line_ids), 2) + for t in self.rma_group_supplier.rma_line_ids.mapped('type'): + self.assertEqual(t, 'customer') + rma_1 = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_1) + self.assertEqual(rma_1.operation_id, self.cust_refund_op) + rma_2 = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_2) + self.assertEqual(rma_2.operation_id, self.operation_1) + + def test_02_add_from_invoice_supplier(self): + """Test wizard to create RMA from a vendor bill.""" + add_inv = self.rma_add_invoice_wiz.with_context({ + 'supplier': True, + 'active_ids': self.rma_group_supplier.id, + 'active_model': 'rma.order', + }).create({ + 'invoice_line_ids': + [(6, 0, self.inv_supplier.invoice_line_ids.ids)], + }) + add_inv.add_lines() + self.assertEqual(len(self.rma_group_supplier.rma_line_ids), 2) + for t in self.rma_group_supplier.rma_line_ids.mapped('type'): + self.assertEqual(t, 'supplier') + + def test_03_rma_refund_operation(self): + """Test RMA quantities using refund operations.""" + # Received refund_policy: + rma_1 = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_1) + self.assertEqual(rma_1.refund_policy, 'received') + self.assertEqual(rma_1.qty_to_refund, 0.0) + # TODO: receive and check qty_to_refund is 12.0 + # Ordered refund_policy: + rma_2 = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_2) + rma_2._onchange_operation_id() + self.assertEqual(rma_2.refund_policy, 'ordered') + self.assertEqual(rma_2.qty_to_refund, 15.0) + + def test_04_rma_create_refund(self): + """Generate a Refund from a customer RMA.""" + rma = self.rma_group_customer.rma_line_ids.filtered( + lambda r: r.product_id == self.product_2) + rma.action_rma_to_approve() + rma.action_rma_approve() + self.assertEqual(rma.refund_count, 0) + self.assertEqual(rma.qty_to_refund, 15.0) + self.assertEqual(rma.qty_refunded, 0.0) + make_refund = self.rma_refund_wiz.with_context({ + 'customer': True, + 'active_ids': rma.ids, + 'active_model': 'rma.order.line', + }).create({ + 'description': 'Test refund', + }) + make_refund.invoice_refund() + rma.refund_line_ids.invoice_id.invoice_validate() + self.assertEqual(rma.refund_count, 1) + self.assertEqual(rma.qty_to_refund, 0.0) + self.assertEqual(rma.qty_refunded, 15.0) + + def test_05_fill_rma_from_inv_line(self): + """Test filling a RMA (line) from a invoice line.""" + rma = self.rma_line_obj.new({ + 'partner_id': self.inv_customer.partner_id.id, + 'invoice_line_id': self.inv_line_1.id, + }) + self.assertFalse(rma.product_id) + rma._onchange_invoice_line_id() + self.assertEqual(rma.product_id, self.product_1) + self.assertEqual(rma.product_qty, 12.0) diff --git a/rma_account/tests/test_rma_dropship.py b/rma_account/tests/test_rma_dropship.py deleted file mode 100644 index c469252d..00000000 --- a/rma_account/tests/test_rma_dropship.py +++ /dev/null @@ -1,105 +0,0 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.addons.rma.tests import test_rma - - -class TestRmaDropship(test_rma.TestRma): - - def setUp(self): - super(TestRmaDropship, self).setUp() - self.product_id.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_1.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_2.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - self.product_3.write( - {'rma_customer_operation_id': self.rma_cust_replace_op_id.id, - 'rma_supplier_operation_id': self.rma_sup_replace_op_id.id}) - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_droship_id = self._create_rma_from_move( - products2move, 'customer', self.env.ref('base.res_partner_2'), - dropship=True, - supplier_address_id=self.env.ref('base.res_partner_3')) - - def test_dropship(self): - wizard = self.make_supplier_rma.with_context({ - 'active_ids': self.rma_droship_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'active_id': 1 - }).create({}) - res = wizard.make_supplier_rma() - supplier_rma = self.rma.browse(res['res_id']) - for line in supplier_rma.rma_line_ids: - line.action_rma_to_approve() - line.action_rma_approve() - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': supplier_rma.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - wizard._create_picking() - res = supplier_rma.rma_line_ids.action_view_in_shipments() - self.assertTrue('res_id' in res, - "Incorrect number of pickings created") - picking = self.env['stock.picking'].browse(res['res_id']) - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in supplier_rma.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_outgoing, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty outgoing") - - for line in self.rma_droship_id.rma_line_ids: - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 3, - "Wrong qty in supplier rma") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 5, - "Wrong qty in supplier rma") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_supplier_rma, 0, - "Wrong qty to supplier rma") - self.assertEquals(line.qty_in_supplier_rma, 2, - "Wrong qty in supplier rma") - for line in self.rma_droship_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") diff --git a/rma_account/tests/test_supplier_rma.py b/rma_account/tests/test_supplier_rma.py deleted file mode 100644 index 8da1bd0c..00000000 --- a/rma_account/tests/test_supplier_rma.py +++ /dev/null @@ -1,137 +0,0 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) - -from openerp.addons.rma.tests import test_rma - - -class TestSupplierRma(test_rma.TestRma): - - def setUp(self): - super(TestSupplierRma, self).setUp() - products2move = [(self.product_1, 3), (self.product_2, 5), - (self.product_3, 2)] - self.rma_supplier_id = self._create_rma_from_move( - products2move, 'supplier', self.env.ref('base.res_partner_1'), - dropship=False) - - def test_supplier_rma(self): - wizard = self.rma_make_picking.with_context({ - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'outgoing', - 'active_id': 1 - }).create({}) - wizard._create_picking() - res = self.rma_supplier_id.rma_line_ids.action_view_out_shipments() - self.assertTrue('res_id' in res, - "Incorrect number of pickings created") - picking = self.env['stock.picking'].browse(res['res_id']) - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - # common qtys for all products - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_delivered, 0, - "Wrong qty delivered") - # product specific - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 3, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 3, - "Wrong qty outgoing") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 5, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 5, - "Wrong qty outgoing") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_to_deliver, 2, - "Wrong qty to deliver") - self.assertEquals(line.qty_outgoing, 2, - "Wrong qty outgoing") - picking.force_assign() - for line in picking.move_lines: - line.quantity_done = line.product_uom_qty - picking.button_validate() - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_delivered, 3, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - if line.product_id == self.product_2: - self.assertEquals(line.qty_delivered, 5, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - if line.product_id == self.product_3: - self.assertEquals(line.qty_delivered, 2, - "Wrong qty delivered") - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - wizard = self.rma_make_picking.with_context({ - 'active_id': 1, - 'active_ids': self.rma_supplier_id.rma_line_ids.ids, - 'active_model': 'rma.order.line', - 'picking_type': 'incoming', - }).create({}) - wizard._create_picking() - res = self.rma_supplier_id.rma_line_ids.action_view_in_shipments() - self.assertTrue('res_id' in res, - "Incorrect number of pickings created") - picking = self.env['stock.picking'].browse(res['res_id']) - moves = picking.move_lines - self.assertEquals(len(moves), 3, - "Incorrect number of moves created") - for line in self.rma_supplier_id.rma_line_ids: - self.assertEquals(line.qty_received, 0, - "Wrong qty received") - if line.product_id == self.product_1: - self.assertEquals(line.qty_to_receive, 3, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 3, - "Wrong qty incoming") - if line.product_id == self.product_2: - self.assertEquals(line.qty_to_receive, 5, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 5, - "Wrong qty incoming") - if line.product_id == self.product_3: - self.assertEquals(line.qty_to_receive, 2, - "Wrong qty to receive") - self.assertEquals(line.qty_incoming, 2, - "Wrong qty incoming") - picking.action_assign() - for line in picking.move_line_ids: - line.qty_done = line.product_uom_qty - picking.action_done() - for line in self.rma_supplier_id.rma_line_ids[0]: - self.assertEquals(line.qty_incoming, 0, - "Wrong qty incoming") - if line.product_id == self.product_1: - self.assertEquals(line.qty_received, 3, - "Wrong qty received") - if line.product_id == self.product_2: - self.assertEquals(line.qty_received, 5, - "Wrong qty received") - if line.product_id == self.product_3: - self.assertEquals(line.qty_received, 2, - "Wrong qty received") - for line in self.rma_supplier_id.rma_line_ids: - line.action_rma_done() - self.assertEquals(line.state, 'done', - "Wrong State") From 4d786383398249af79c0fd1fd450e90a15b1efe1 Mon Sep 17 00:00:00 2001 From: aheficent Date: Mon, 30 Jul 2018 18:38:48 +0200 Subject: [PATCH 30/93] [FIX]refund policy --- rma_account/demo/rma_operation.xml | 4 ++-- rma_account/models/rma_operation.py | 1 + rma_account/tests/test_rma_account.py | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rma_account/demo/rma_operation.xml b/rma_account/demo/rma_operation.xml index 9a4e5738..bda0529b 100644 --- a/rma_account/demo/rma_operation.xml +++ b/rma_account/demo/rma_operation.xml @@ -12,7 +12,7 @@ Refund before receive RFC - ordered + received no no customer @@ -23,7 +23,7 @@ Refund Before deliver RFS - ordered + delivered no no supplier diff --git a/rma_account/models/rma_operation.py b/rma_account/models/rma_operation.py index 043826c6..88085d85 100644 --- a/rma_account/models/rma_operation.py +++ b/rma_account/models/rma_operation.py @@ -9,5 +9,6 @@ class RmaOperation(models.Model): refund_policy = fields.Selection([ ('no', 'No refund'), ('ordered', 'Based on Ordered Quantities'), + ('delivered', 'Based on Delivered Quantities'), ('received', 'Based on Received Quantities')], string="Refund Policy", default='no') diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py index 0d8802bf..a4f41fdb 100644 --- a/rma_account/tests/test_rma_account.py +++ b/rma_account/tests/test_rma_account.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2017-18 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) From c832b7c70d5c1f535edf1f18f74bf7af34bf92d3 Mon Sep 17 00:00:00 2001 From: aheficent Date: Tue, 21 Aug 2018 17:07:44 +0200 Subject: [PATCH 31/93] [FIX]rma account operations is data --- rma_account/__manifest__.py | 2 +- rma_account/{demo => data}/rma_operation.xml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) rename rma_account/{demo => data}/rma_operation.xml (78%) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index db64990b..8d3dfdac 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -10,7 +10,7 @@ 'author': "Eficent, Odoo Community Association (OCA)", 'website': 'http://www.github.com/OCA/rma', 'depends': ['account', 'rma'], - 'demo': ['demo/rma_operation.xml'], + 'demo': ['data/rma_operation.xml'], 'data': [ 'security/ir.model.access.csv', 'views/rma_order_view.xml', diff --git a/rma_account/demo/rma_operation.xml b/rma_account/data/rma_operation.xml similarity index 78% rename from rma_account/demo/rma_operation.xml rename to rma_account/data/rma_operation.xml index bda0529b..f5a84ca0 100644 --- a/rma_account/demo/rma_operation.xml +++ b/rma_account/data/rma_operation.xml @@ -10,10 +10,10 @@ - Refund before receive - RFC + Refund after receive + RF-C received - no + ordered no customer @@ -21,11 +21,11 @@ - Refund Before deliver - RFS - delivered + Refund after deliver + RF-S + ordered no - no + ordered supplier From 4c6ec141343d04b9289e8c13204fc47a10ad88ac Mon Sep 17 00:00:00 2001 From: aheficent Date: Thu, 4 Oct 2018 16:27:11 +0200 Subject: [PATCH 32/93] [FIX]currency_id was not filled --- rma_account/models/rma_order_line.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 66abd2d9..95904737 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -137,6 +137,7 @@ class RmaOrderLine(models.Model): 'receipt_policy': operation.receipt_policy, 'refund_policy': operation.refund_policy, 'delivery_policy': operation.delivery_policy, + 'currency_id': line.currency_id.id, 'in_warehouse_id': operation.in_warehouse_id.id or warehouse.id, 'out_warehouse_id': operation.out_warehouse_id.id or warehouse.id, 'in_route_id': operation.in_route_id.id or route.id, From 4a740a9645ef3109dfcb59e48ac8c86fed05a11d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Gil=20Sorribes?= Date: Mon, 19 Nov 2018 16:55:31 +0100 Subject: [PATCH 33/93] [12.0][MIG] Migrate rma_account module to v12.0 --- rma_account/__manifest__.py | 4 ++-- rma_account/tests/test_rma_account.py | 3 ++- rma_account/wizards/rma_refund.py | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 8d3dfdac..67ed41f6 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -3,13 +3,13 @@ { 'name': 'RMA Account', - 'version': '11.0.1.0.0', + 'version': '12.0.1.0.0', 'license': 'LGPL-3', 'category': 'RMA', 'summary': 'Integrates RMA with Invoice Processing', 'author': "Eficent, Odoo Community Association (OCA)", 'website': 'http://www.github.com/OCA/rma', - 'depends': ['account', 'rma'], + 'depends': ['stock_account', 'rma'], 'demo': ['data/rma_operation.xml'], 'data': [ 'security/ir.model.access.csv', diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py index a4f41fdb..2f53a503 100644 --- a/rma_account/tests/test_rma_account.py +++ b/rma_account/tests/test_rma_account.py @@ -1,7 +1,7 @@ # Copyright 2017-18 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openerp.tests import common +from odoo.tests import common class TestRmaAccount(common.SingleTransactionCase): @@ -194,6 +194,7 @@ class TestRmaAccount(common.SingleTransactionCase): }) make_refund.invoice_refund() rma.refund_line_ids.invoice_id.invoice_validate() + rma._compute_refund_count() self.assertEqual(rma.refund_count, 1) self.assertEqual(rma.qty_to_refund, 0.0) self.assertEqual(rma.qty_refunded, 15.0) diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 57491a76..48c72eeb 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -112,7 +112,7 @@ class RmaRefund(models.TransientModel): account = accounts['stock_input'] if not account: raise ValidationError(_( - "Accounts are not configure for this product.")) + "Accounts are not configured for this product.")) values = { 'name': item.line_id.name or item.rma_id.name, 'origin': item.line_id.name or item.rma_id.name, @@ -202,7 +202,7 @@ class RmaRefundItem(models.TransientModel): qty_to_refund = fields.Float( string='Quantity To Refund', digits=dp.get_precision('Product Unit of Measure')) - uom_id = fields.Many2one('product.uom', string='Unit of Measure', + uom_id = fields.Many2one('uom.uom', string='Unit of Measure', readonly=True) refund_policy = fields.Selection(selection=[ ('no', 'Not required'), ('ordered', 'Based on Ordered Quantities'), From 4fa1e7b17b10d5dddcd098f05a7f9e5f1f5ae26d Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Tue, 12 Mar 2019 17:27:55 +0100 Subject: [PATCH 34/93] rma_account: Fix uom res.groups --- rma_account/wizards/rma_add_invoice.xml | 4 ++-- rma_account/wizards/rma_refund.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rma_account/wizards/rma_add_invoice.xml b/rma_account/wizards/rma_add_invoice.xml index 0ecb13ab..76023bd8 100644 --- a/rma_account/wizards/rma_add_invoice.xml +++ b/rma_account/wizards/rma_add_invoice.xml @@ -21,7 +21,7 @@ - + @@ -60,7 +60,7 @@ - + diff --git a/rma_account/wizards/rma_refund.xml b/rma_account/wizards/rma_refund.xml index 52285b66..ab9019ef 100644 --- a/rma_account/wizards/rma_refund.xml +++ b/rma_account/wizards/rma_refund.xml @@ -21,7 +21,7 @@ - + From 46c1be4d5f7b7cc3865a3682ac37098b955fed62 Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Tue, 12 Mar 2019 17:28:20 +0100 Subject: [PATCH 35/93] rma_account: Fix res.groups on discount --- rma_account/wizards/rma_add_invoice.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rma_account/wizards/rma_add_invoice.xml b/rma_account/wizards/rma_add_invoice.xml index 76023bd8..29e3fda9 100644 --- a/rma_account/wizards/rma_add_invoice.xml +++ b/rma_account/wizards/rma_add_invoice.xml @@ -23,7 +23,7 @@ - + @@ -62,7 +62,7 @@ - + From 511bca5bb6149a7ebf46bee9daf502b89324e0da Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Tue, 12 Mar 2019 18:31:43 +0100 Subject: [PATCH 36/93] rma_account: Fix test opening invoice before validating --- rma_account/tests/test_rma_account.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py index 2f53a503..75733cf3 100644 --- a/rma_account/tests/test_rma_account.py +++ b/rma_account/tests/test_rma_account.py @@ -193,6 +193,7 @@ class TestRmaAccount(common.SingleTransactionCase): 'description': 'Test refund', }) make_refund.invoice_refund() + rma.refund_line_ids.invoice_id.action_invoice_open() rma.refund_line_ids.invoice_id.invoice_validate() rma._compute_refund_count() self.assertEqual(rma.refund_count, 1) From 618760cacbbb9af91feb36977f779e5ac2d1a31c Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Mon, 18 Mar 2019 17:31:56 +0100 Subject: [PATCH 37/93] Proxy fields defaults with lambda to allow inheritance --- rma_account/README.rst | 1 + rma_account/models/rma_order_line.py | 2 +- rma_account/wizards/rma_refund.py | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rma_account/README.rst b/rma_account/README.rst index c8003352..8dfed892 100644 --- a/rma_account/README.rst +++ b/rma_account/README.rst @@ -44,6 +44,7 @@ Contributors * Aaron Henriquez * Lois Rilo * Bhavesh Odedra +* Akim Juillerat Maintainer ---------- diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 95904737..bfe24b6c 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -43,7 +43,7 @@ class RmaOrderLine(models.Model): invoice_address_id = fields.Many2one( 'res.partner', string='Partner invoice address', - default=_default_invoice_address, + default=lambda self: self._default_invoice_address(), readonly=True, states={'draft': [('readonly', False)]}, help="Invoice address for current rma order.", ) diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 48c72eeb..a77e0e1e 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -63,7 +63,8 @@ class RmaRefund(models.TransientModel): ) date = fields.Date(string='Accounting Date') description = fields.Char( - string='Reason', required=True, default=_get_reason, + string='Reason', required=True, + default=lambda self: self._get_reason(), ) item_ids = fields.One2many( comodel_name='rma.refund.item', From 7bf34184bdb3f72943a45b018beb87afadcd40af Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Mon, 18 Mar 2019 17:38:46 +0100 Subject: [PATCH 38/93] Use strings on fields compute to allow inheritance --- rma_account/models/invoice.py | 4 ++-- rma_account/models/rma_order.py | 4 ++-- rma_account/models/rma_order_line.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index 6a88d0cc..1b8b9fa9 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -58,7 +58,7 @@ class AccountInvoice(models.Model): return {} rma_count = fields.Integer( - compute=_compute_rma_count, string='# of RMA') + compute='_compute_rma_count', string='# of RMA') add_rma_line_id = fields.Many2one( comodel_name='rma.order.line', @@ -156,7 +156,7 @@ class AccountInvoiceLine(models.Model): invl.rma_line_count = len(rma_lines) rma_line_count = fields.Integer( - compute=_compute_rma_count, string='# of RMA') + compute='_compute_rma_count', string='# of RMA') rma_line_ids = fields.One2many( comodel_name='rma.order.line', inverse_name='invoice_line_id', string="RMA", readonly=True, diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index 20d4f89b..82a4591b 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -25,9 +25,9 @@ class RmaOrder(models.Model): ondelete='set null', readonly=True, ) invoice_refund_count = fields.Integer( - compute=_compute_invoice_refund_count, string='# of Refunds') + compute='_compute_invoice_refund_count', string='# of Refunds') invoice_count = fields.Integer( - compute=_compute_invoice_count, string='# of Invoices') + compute='_compute_invoice_count', string='# of Invoices') def _prepare_rma_line_from_inv_line(self, line): if self.type == 'customer': diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index bfe24b6c..5f4d41f5 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -48,7 +48,7 @@ class RmaOrderLine(models.Model): help="Invoice address for current rma order.", ) refund_count = fields.Integer( - compute=_compute_refund_count, string='# of Refunds', default=0) + compute='_compute_refund_count', string='# of Refunds', default=0) invoice_line_id = fields.Many2one( comodel_name='account.invoice.line', string='Originating Invoice Line', @@ -73,11 +73,11 @@ class RmaOrderLine(models.Model): qty_to_refund = fields.Float( string='Qty To Refund', copy=False, digits=dp.get_precision('Product Unit of Measure'), readonly=True, - compute=_compute_qty_to_refund, store=True) + compute='_compute_qty_to_refund', store=True) qty_refunded = fields.Float( string='Qty Refunded', copy=False, digits=dp.get_precision('Product Unit of Measure'), - readonly=True, compute=_compute_qty_refunded, store=True) + readonly=True, compute='_compute_qty_refunded', store=True) @api.onchange('product_id') def _onchange_product_id(self): From a580d9c0aca2df2f0040307a63a1ae0bf02662cc Mon Sep 17 00:00:00 2001 From: Bhavesh Odedra Date: Fri, 24 May 2019 13:28:54 +0530 Subject: [PATCH 39/93] [SET] Correct website URL for RMA modules --- rma_account/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 67ed41f6..c53aa567 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -8,7 +8,7 @@ 'category': 'RMA', 'summary': 'Integrates RMA with Invoice Processing', 'author': "Eficent, Odoo Community Association (OCA)", - 'website': 'http://www.github.com/OCA/rma', + 'website': 'https://github.com/Eficent/stock-rma', 'depends': ['stock_account', 'rma'], 'demo': ['data/rma_operation.xml'], 'data': [ From b8fc80f1835c2affc0dc1ab89c470047c5b54bf1 Mon Sep 17 00:00:00 2001 From: Maxime Chambreuil Date: Thu, 1 Aug 2019 15:00:40 -0500 Subject: [PATCH 40/93] [FIX] rma_account: The model rma.refund has no _description --- rma_account/wizards/rma_refund.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index a77e0e1e..553b5449 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -8,6 +8,7 @@ import odoo.addons.decimal_precision as dp class RmaRefund(models.TransientModel): _name = "rma.refund" + _description = "Wizard for RMA Refund" @api.model def _get_reason(self): From 00af733f395393a1c367756ae654445c826c64fc Mon Sep 17 00:00:00 2001 From: ahenriquez Date: Wed, 24 Jul 2019 15:50:13 +0200 Subject: [PATCH 41/93] [FIX]refund policy consistency rma vs operation --- rma_account/models/rma_order_line.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 5f4d41f5..812a9d3a 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -34,6 +34,8 @@ class RmaOrderLine(models.Model): qty = res.product_qty - res.qty_refunded elif res.refund_policy == 'received': qty = res.qty_received - res.qty_refunded + elif res.refund_policy == 'delivered': + qty = res.qty_delivered - res.qty_refunded res.qty_to_refund = qty @api.multi @@ -66,6 +68,7 @@ class RmaOrderLine(models.Model): index=True, readonly=True) refund_policy = fields.Selection([ ('no', 'No refund'), ('ordered', 'Based on Ordered Quantities'), + ('delivered', 'Based on Delivered Quantities'), ('received', 'Based on Received Quantities')], string="Refund Policy", required=True, default='no', readonly=True, states={'draft': [('readonly', False)]}, From cf4eaf10527bdb93ce87c5a1e84c7eea95e82680 Mon Sep 17 00:00:00 2001 From: ahenriquez Date: Mon, 5 Aug 2019 16:36:41 +0200 Subject: [PATCH 42/93] [MIG]account_move_line_rma_order_line to v12 --- rma_account/tests/test_rma_account.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py index 75733cf3..4da5c8cb 100644 --- a/rma_account/tests/test_rma_account.py +++ b/rma_account/tests/test_rma_account.py @@ -194,7 +194,6 @@ class TestRmaAccount(common.SingleTransactionCase): }) make_refund.invoice_refund() rma.refund_line_ids.invoice_id.action_invoice_open() - rma.refund_line_ids.invoice_id.invoice_validate() rma._compute_refund_count() self.assertEqual(rma.refund_count, 1) self.assertEqual(rma.qty_to_refund, 0.0) From 36ca0f96758e6e968fc269ba6eff2135579d5d16 Mon Sep 17 00:00:00 2001 From: ahenriquez Date: Wed, 18 Sep 2019 10:39:13 +0200 Subject: [PATCH 43/93] [FIX]filter by partner --- rma_account/models/rma_order_line.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 812a9d3a..61e7a5fb 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -82,19 +82,19 @@ class RmaOrderLine(models.Model): digits=dp.get_precision('Product Unit of Measure'), readonly=True, compute='_compute_qty_refunded', store=True) - @api.onchange('product_id') + @api.onchange('product_id', 'partner_id') def _onchange_product_id(self): + """Domain for sale_line_id is computed here to make it dynamic.""" res = super(RmaOrderLine, self)._onchange_product_id() - if res.get('domain') and self.product_id: - res['domain']['invoice_line_id'] = [ - ('product_id', '=', self.product_id.id)] - elif res.get('domain') and self.product_id: - res['domain']['invoice_line_id'] = [()] - elif not res.get('domain') and self.product_id: - res['domain'] = { - 'invoice_line_id': [('product_id', '=', self.product_id.id)]} - else: - res['domain'] = {'invoice_line_id': []} + if not res.get('domain'): + res['domain'] = {} + domain = [ + '|', + ('invoice_id.partner_id', '=', self.partner_id.id), + ('invoice_id.partner_id', 'child_of', self.partner_id.id)] + if self.product_id: + domain.append(('product_id', '=', self.product_id.id)) + res['domain']['invoice_line_id'] = domain return res @api.multi From fc9a907c5e4165992ecb5a6c01e6ba6f44b1dbe0 Mon Sep 17 00:00:00 2001 From: ahenriquez Date: Tue, 29 Oct 2019 16:37:58 +0100 Subject: [PATCH 44/93] [FIX]remove autoinstall for rma_account, rma_sale and rma_purchase modules --- rma_account/__manifest__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index c53aa567..47ddd0b0 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -22,5 +22,4 @@ 'wizards/rma_refund.xml', ], 'installable': True, - 'auto_install': True, } From 47e9d8e84f859adc2d6da94d8dc71a74978b25da Mon Sep 17 00:00:00 2001 From: mreficent Date: Fri, 29 Nov 2019 18:30:43 +0100 Subject: [PATCH 45/93] [FIX] default_gets: avoid using shadowname 'fields' --- rma_account/wizards/rma_add_invoice.py | 4 ++-- rma_account/wizards/rma_refund.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index 8c44205d..f766b6f6 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -10,8 +10,8 @@ class RmaAddInvoice(models.TransientModel): _description = 'Wizard to add rma lines' @api.model - def default_get(self, fields): - res = super(RmaAddInvoice, self).default_get(fields) + def default_get(self, fields_list): + res = super(RmaAddInvoice, self).default_get(fields_list) rma_obj = self.env['rma.order'] rma_id = self.env.context['active_ids'] or [] active_model = self.env.context['active_model'] diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 553b5449..0e06ee16 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -32,13 +32,13 @@ class RmaRefund(models.TransientModel): return values @api.model - def default_get(self, fields): + def default_get(self, fields_list): """Default values for wizard, if there is more than one supplier on lines the supplier field is empty otherwise is the unique line supplier. """ context = self._context.copy() - res = super(RmaRefund, self).default_get(fields) + res = super(RmaRefund, self).default_get(fields_list) rma_line_obj = self.env['rma.order.line'] rma_line_ids = self.env.context['active_ids'] or [] active_model = self.env.context['active_model'] From eb9b50eb9c2373b523c1b5bfa81b312405385a3e Mon Sep 17 00:00:00 2001 From: ahenriquez Date: Wed, 22 Jan 2020 11:18:04 +0100 Subject: [PATCH 46/93] [IMP] : black, isort --- rma_account/__manifest__.py | 38 +-- rma_account/models/invoice.py | 144 +++++---- rma_account/models/rma_operation.py | 17 +- rma_account/models/rma_order.py | 96 +++--- rma_account/models/rma_order_line.py | 298 ++++++++++------- rma_account/tests/test_rma_account.py | 299 +++++++++--------- rma_account/wizards/rma_add_invoice.py | 134 ++++---- .../rma_order_line_make_supplier_rma.py | 9 +- rma_account/wizards/rma_refund.py | 246 +++++++------- 9 files changed, 698 insertions(+), 583 deletions(-) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 47ddd0b0..7ba3aebe 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -2,24 +2,24 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) { - 'name': 'RMA Account', - 'version': '12.0.1.0.0', - 'license': 'LGPL-3', - 'category': 'RMA', - 'summary': 'Integrates RMA with Invoice Processing', - 'author': "Eficent, Odoo Community Association (OCA)", - 'website': 'https://github.com/Eficent/stock-rma', - 'depends': ['stock_account', 'rma'], - 'demo': ['data/rma_operation.xml'], - 'data': [ - 'security/ir.model.access.csv', - 'views/rma_order_view.xml', - 'views/rma_operation_view.xml', - 'views/rma_order_line_view.xml', - 'views/invoice_view.xml', - 'views/rma_account_menu.xml', - 'wizards/rma_add_invoice.xml', - 'wizards/rma_refund.xml', + "name": "RMA Account", + "version": "12.0.1.0.0", + "license": "LGPL-3", + "category": "RMA", + "summary": "Integrates RMA with Invoice Processing", + "author": "Eficent, Odoo Community Association (OCA)", + "website": "https://github.com/Eficent/stock-rma", + "depends": ["stock_account", "rma"], + "demo": ["data/rma_operation.xml"], + "data": [ + "security/ir.model.access.csv", + "views/rma_order_view.xml", + "views/rma_operation_view.xml", + "views/rma_order_line_view.xml", + "views/invoice_view.xml", + "views/rma_account_menu.xml", + "wizards/rma_add_invoice.xml", + "wizards/rma_refund.xml", ], - 'installable': True, + "installable": True, } diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index 1b8b9fa9..3fadd0b4 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -8,92 +8,89 @@ from odoo.tools.float_utils import float_compare class AccountInvoice(models.Model): _inherit = "account.invoice" - @api.depends('invoice_line_ids.rma_line_ids') + @api.depends("invoice_line_ids.rma_line_ids") def _compute_rma_count(self): for inv in self: - rmas = self.mapped('invoice_line_ids.rma_line_ids') + rmas = self.mapped("invoice_line_ids.rma_line_ids") inv.rma_count = len(rmas) def _prepare_invoice_line_from_rma_line(self, line): qty = line.qty_to_refund - if float_compare( - qty, 0.0, precision_rounding=line.uom_id.rounding) <= 0: + if float_compare(qty, 0.0, precision_rounding=line.uom_id.rounding) <= 0: qty = 0.0 # Todo fill taxes from somewhere - invoice_line = self.env['account.invoice.line'] + invoice_line = self.env["account.invoice.line"] data = { - 'purchase_line_id': line.id, - 'name': line.name + ': '+line.name, - 'origin': line.origin, - 'uom_id': line.uom_id.id, - 'product_id': line.product_id.id, - 'account_id': invoice_line.with_context( - {'journal_id': self.journal_id.id, - 'type': 'in_invoice'})._default_account(), - 'price_unit': line.company_id.currency_id.with_context( - date=self.date_invoice).compute( - line.price_unit, self.currency_id, round=False), - 'quantity': qty, - 'discount': 0.0, - 'rma_line_ids': [(4, line.id)], + "purchase_line_id": line.id, + "name": line.name + ": " + line.name, + "origin": line.origin, + "uom_id": line.uom_id.id, + "product_id": line.product_id.id, + "account_id": invoice_line.with_context( + {"journal_id": self.journal_id.id, "type": "in_invoice"} + )._default_account(), + "price_unit": line.company_id.currency_id.with_context( + date=self.date_invoice + ).compute(line.price_unit, self.currency_id, round=False), + "quantity": qty, + "discount": 0.0, + "rma_line_ids": [(4, line.id)], } return data - @api.onchange('add_rma_line_id') + @api.onchange("add_rma_line_id") def on_change_add_rma_line_id(self): if not self.add_rma_line_id: return {} if not self.partner_id: self.partner_id = self.add_rma_line_id.partner_id.id - new_line = self.env['account.invoice.line'] - if self.add_rma_line_id not in ( - self.invoice_line_ids.mapped('rma_line_id')): - data = self._prepare_invoice_line_from_rma_line( - self.add_rma_line_id) + new_line = self.env["account.invoice.line"] + if self.add_rma_line_id not in (self.invoice_line_ids.mapped("rma_line_id")): + data = self._prepare_invoice_line_from_rma_line(self.add_rma_line_id) new_line = new_line.new(data) new_line._set_additional_fields(self) self.invoice_line_ids += new_line self.add_rma_line_id = False return {} - rma_count = fields.Integer( - compute='_compute_rma_count', string='# of RMA') + rma_count = fields.Integer(compute="_compute_rma_count", string="# of RMA") add_rma_line_id = fields.Many2one( - comodel_name='rma.order.line', + comodel_name="rma.order.line", string="Add from RMA line", ondelete="set null", - help="Create a refund in based on an existing rma_line") + help="Create a refund in based on an existing rma_line", + ) @api.multi def action_view_rma_supplier(self): - action = self.env.ref('rma.action_rma_supplier_lines') + action = self.env.ref("rma.action_rma_supplier_lines") result = action.read()[0] - rma_ids = self.mapped('invoice_line_ids.rma_line_ids').ids + rma_ids = self.mapped("invoice_line_ids.rma_line_ids").ids if rma_ids: # choose the view_mode accordingly if len(rma_ids) > 1: - result['domain'] = [('id', 'in', rma_ids)] + result["domain"] = [("id", "in", rma_ids)] else: - res = self.env.ref('rma.view_rma_line_supplier_form', False) - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = rma_ids[0] + res = self.env.ref("rma.view_rma_line_supplier_form", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = rma_ids[0] return result @api.multi def action_view_rma_customer(self): - action = self.env.ref('rma.action_rma_customer_lines') + action = self.env.ref("rma.action_rma_customer_lines") result = action.read()[0] - rma_ids = self.mapped('invoice_line_ids.rma_line_ids').ids + rma_ids = self.mapped("invoice_line_ids.rma_line_ids").ids if rma_ids: # choose the view_mode accordingly if len(rma_ids) > 1: - result['domain'] = [('id', 'in', rma_ids)] + result["domain"] = [("id", "in", rma_ids)] else: - res = self.env.ref('rma.view_rma_line_form', False) - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = rma_ids[0] + res = self.env.ref("rma.view_rma_line_form", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = rma_ids[0] return result @@ -101,15 +98,13 @@ class AccountInvoiceLine(models.Model): _inherit = "account.invoice.line" @api.model - def name_search(self, name, args=None, operator='ilike', limit=100): + def name_search(self, name, args=None, operator="ilike", limit=100): """Allows to search by Invoice number. This has to be done this way, as Odoo adds extra args to name_search on _name_search method that will make impossible to get the desired result.""" if not args: args = [] - lines = self.search( - [('invoice_id.number', operator, name)] + args, limit=limit, - ) + lines = self.search([("invoice_id.number", operator, name)] + args, limit=limit) res = lines.name_get() if limit: limit_rest = limit - len(lines) @@ -117,32 +112,44 @@ class AccountInvoiceLine(models.Model): # limit can be 0 or None representing infinite limit_rest = limit if limit_rest or not limit: - args += [('id', 'not in', lines.ids)] + args += [("id", "not in", lines.ids)] res += super(AccountInvoiceLine, self).name_search( - name, args=args, operator=operator, limit=limit_rest, + name, args=args, operator=operator, limit=limit_rest ) return res @api.multi def name_get(self): res = [] - if self.env.context.get('rma'): + if self.env.context.get("rma"): for inv in self: if inv.invoice_id.reference: res.append( - (inv.id, - "INV:%s | REF:%s | ORIG:%s | PART:%s | QTY:%s" % ( - inv.invoice_id.number or '', - inv.origin or '', - inv.invoice_id.reference or "", - inv.product_id.name, inv.quantity))) + ( + inv.id, + "INV:%s | REF:%s | ORIG:%s | PART:%s | QTY:%s" + % ( + inv.invoice_id.number or "", + inv.origin or "", + inv.invoice_id.reference or "", + inv.product_id.name, + inv.quantity, + ), + ) + ) elif inv.invoice_id.number: res.append( - (inv.id, - "INV:%s | ORIG:%s | PART:%s | QTY:%s" % ( - inv.invoice_id.number or '', - inv.origin or '', - inv.product_id.name, inv.quantity))) + ( + inv.id, + "INV:%s | ORIG:%s | PART:%s | QTY:%s" + % ( + inv.invoice_id.number or "", + inv.origin or "", + inv.product_id.name, + inv.quantity, + ), + ) + ) else: res.append(super(AccountInvoiceLine, inv).name_get()[0]) return res @@ -152,18 +159,21 @@ class AccountInvoiceLine(models.Model): @api.multi def _compute_rma_count(self): for invl in self: - rma_lines = invl.mapped('rma_line_ids') + rma_lines = invl.mapped("rma_line_ids") invl.rma_line_count = len(rma_lines) - rma_line_count = fields.Integer( - compute='_compute_rma_count', string='# of RMA') + rma_line_count = fields.Integer(compute="_compute_rma_count", string="# of RMA") rma_line_ids = fields.One2many( - comodel_name='rma.order.line', inverse_name='invoice_line_id', - string="RMA", readonly=True, - help="This will contain the RMA lines for the invoice line") + comodel_name="rma.order.line", + inverse_name="invoice_line_id", + string="RMA", + readonly=True, + help="This will contain the RMA lines for the invoice line", + ) rma_line_id = fields.Many2one( - comodel_name='rma.order.line', + comodel_name="rma.order.line", string="RMA line refund", ondelete="set null", - help="This will contain the rma line that originated the refund line") + help="This will contain the rma line that originated the refund line", + ) diff --git a/rma_account/models/rma_operation.py b/rma_account/models/rma_operation.py index 88085d85..53ce4ed3 100644 --- a/rma_account/models/rma_operation.py +++ b/rma_account/models/rma_operation.py @@ -5,10 +5,15 @@ from odoo import fields, models class RmaOperation(models.Model): - _inherit = 'rma.operation' + _inherit = "rma.operation" - refund_policy = fields.Selection([ - ('no', 'No refund'), ('ordered', 'Based on Ordered Quantities'), - ('delivered', 'Based on Delivered Quantities'), - ('received', 'Based on Received Quantities')], string="Refund Policy", - default='no') + refund_policy = fields.Selection( + [ + ("no", "No refund"), + ("ordered", "Based on Ordered Quantities"), + ("delivered", "Based on Delivered Quantities"), + ("received", "Based on Received Quantities"), + ], + string="Refund Policy", + default="no", + ) diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index 82a4591b..240ca011 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -10,58 +10,64 @@ class RmaOrder(models.Model): @api.multi def _compute_invoice_refund_count(self): for rec in self: - invoices = rec.mapped( - 'rma_line_ids.refund_line_ids.invoice_id') + invoices = rec.mapped("rma_line_ids.refund_line_ids.invoice_id") rec.invoice_refund_count = len(invoices) @api.multi def _compute_invoice_count(self): for rec in self: - invoices = rec.mapped('rma_line_ids.invoice_id') + invoices = rec.mapped("rma_line_ids.invoice_id") rec.invoice_count = len(invoices) add_invoice_id = fields.Many2one( - comodel_name='account.invoice', string='Add Invoice', - ondelete='set null', readonly=True, + comodel_name="account.invoice", + string="Add Invoice", + ondelete="set null", + readonly=True, ) invoice_refund_count = fields.Integer( - compute='_compute_invoice_refund_count', string='# of Refunds') + compute="_compute_invoice_refund_count", string="# of Refunds" + ) invoice_count = fields.Integer( - compute='_compute_invoice_count', string='# of Invoices') + compute="_compute_invoice_count", string="# of Invoices" + ) def _prepare_rma_line_from_inv_line(self, line): - if self.type == 'customer': - operation =\ - self.rma_line_ids.product_id.rma_customer_operation_id or \ - self.rma_line_ids.product_id.categ_id.rma_customer_operation_id + if self.type == "customer": + operation = ( + self.rma_line_ids.product_id.rma_customer_operation_id + or self.rma_line_ids.product_id.categ_id.rma_customer_operation_id + ) else: - operation =\ - self.rma_line_ids.product_id.rma_supplier_operation_id or \ - self.rma_line_ids.product_id.categ_id.rma_supplier_operation_id + operation = ( + self.rma_line_ids.product_id.rma_supplier_operation_id + or self.rma_line_ids.product_id.categ_id.rma_supplier_operation_id + ) data = { - 'invoice_line_id': line.id, - 'product_id': line.product_id.id, - 'name': line.name, - 'origin': line.invoice_id.number, - 'uom_id': line.uom_id.id, - 'operation_id': operation, - 'product_qty': line.quantity, - 'price_unit': line.invoice_id.currency_id.compute( - line.price_unit, line.currency_id, round=False), - 'rma_id': self.id + "invoice_line_id": line.id, + "product_id": line.product_id.id, + "name": line.name, + "origin": line.invoice_id.number, + "uom_id": line.uom_id.id, + "operation_id": operation, + "product_qty": line.quantity, + "price_unit": line.invoice_id.currency_id.compute( + line.price_unit, line.currency_id, round=False + ), + "rma_id": self.id, } return data - @api.onchange('add_invoice_id') + @api.onchange("add_invoice_id") def on_change_invoice(self): if not self.add_invoice_id: return {} if not self.partner_id: self.partner_id = self.add_invoice_id.partner_id.id - new_lines = self.env['rma.order.line'] + new_lines = self.env["rma.order.line"] for line in self.add_invoice_id.invoice_line_ids: # Load a PO line only once - if line in self.rma_line_ids.mapped('invoice_line_id'): + if line in self.rma_line_ids.mapped("invoice_line_id"): continue data = self._prepare_rma_line_from_inv_line(line) new_line = new_lines.new(data) @@ -76,48 +82,46 @@ class RmaOrder(models.Model): @api.model def prepare_rma_line(self, origin_rma, rma_id, line): - line_values = super(RmaOrder, self).prepare_rma_line( - origin_rma, rma_id, line) - line_values['invoice_address_id'] = line.invoice_address_id.id + line_values = super(RmaOrder, self).prepare_rma_line(origin_rma, rma_id, line) + line_values["invoice_address_id"] = line.invoice_address_id.id return line_values @api.model def _prepare_rma_data(self, partner, origin_rma): res = super(RmaOrder, self)._prepare_rma_data(partner, origin_rma) - res['invoice_address_id'] = partner.id + res["invoice_address_id"] = partner.id return res @api.multi def action_view_invoice_refund(self): - action = self.env.ref('account.action_invoice_tree2') + action = self.env.ref("account.action_invoice_tree2") result = action.read()[0] - invoice_ids = self.mapped( - 'rma_line_ids.refund_line_ids.invoice_id').ids + invoice_ids = self.mapped("rma_line_ids.refund_line_ids.invoice_id").ids if invoice_ids: # choose the view_mode accordingly if len(invoice_ids) > 1: - result['domain'] = [('id', 'in', invoice_ids)] + result["domain"] = [("id", "in", invoice_ids)] else: - res = self.env.ref('account.invoice_supplier_form', False) - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = invoice_ids[0] + res = self.env.ref("account.invoice_supplier_form", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = invoice_ids[0] return result @api.multi def action_view_invoice(self): if self.type == "supplier": - action = self.env.ref('account.action_invoice_tree2') - res = self.env.ref('account.invoice_supplier_form', False) + action = self.env.ref("account.action_invoice_tree2") + res = self.env.ref("account.invoice_supplier_form", False) else: - action = self.env.ref('account.action_invoice_tree') - res = self.env.ref('account.invoice_form', False) + action = self.env.ref("account.action_invoice_tree") + res = self.env.ref("account.invoice_form", False) result = action.read()[0] - invoice_ids = self.mapped('rma_line_ids.invoice_id').ids + invoice_ids = self.mapped("rma_line_ids.invoice_id").ids if invoice_ids: # choose the view_mode accordingly if len(invoice_ids) > 1: - result['domain'] = [('id', 'in', invoice_ids)] + result["domain"] = [("id", "in", invoice_ids)] else: - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = invoice_ids[0] + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = invoice_ids[0] return result diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 61e7a5fb..c6dd50ab 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -1,8 +1,9 @@ # © 2017 Eficent Business and IT Consulting Services S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from odoo import api, fields, models, _ -from odoo.exceptions import ValidationError, UserError +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + from odoo.addons import decimal_precision as dp @@ -11,90 +12,125 @@ class RmaOrderLine(models.Model): @api.model def _default_invoice_address(self): - partner_id = self.env.context.get('partner_id') + partner_id = self.env.context.get("partner_id") if partner_id: - return self.env['res.partner'].browse(partner_id) - return self.env['res.partner'] + return self.env["res.partner"].browse(partner_id) + return self.env["res.partner"] @api.multi - @api.depends('refund_line_ids', 'refund_line_ids.invoice_id.state', - 'refund_policy', 'type') + @api.depends( + "refund_line_ids", "refund_line_ids.invoice_id.state", "refund_policy", "type" + ) def _compute_qty_refunded(self): for rec in self: - rec.qty_refunded = sum(rec.refund_line_ids.filtered( - lambda i: i.invoice_id.state in ('open', 'paid')).mapped( - 'quantity')) + rec.qty_refunded = sum( + rec.refund_line_ids.filtered( + lambda i: i.invoice_id.state in ("open", "paid") + ).mapped("quantity") + ) - @api.depends('refund_line_ids', 'refund_line_ids.invoice_id.state', - 'refund_policy', 'move_ids', 'move_ids.state', 'type') + @api.depends( + "refund_line_ids", + "refund_line_ids.invoice_id.state", + "refund_policy", + "move_ids", + "move_ids.state", + "type", + ) def _compute_qty_to_refund(self): qty = 0.0 for res in self: - if res.refund_policy == 'ordered': + if res.refund_policy == "ordered": qty = res.product_qty - res.qty_refunded - elif res.refund_policy == 'received': + elif res.refund_policy == "received": qty = res.qty_received - res.qty_refunded - elif res.refund_policy == 'delivered': + elif res.refund_policy == "delivered": qty = res.qty_delivered - res.qty_refunded res.qty_to_refund = qty @api.multi def _compute_refund_count(self): for rec in self: - rec.refund_count = len(rec.refund_line_ids.mapped('invoice_id')) + rec.refund_count = len(rec.refund_line_ids.mapped("invoice_id")) invoice_address_id = fields.Many2one( - 'res.partner', string='Partner invoice address', + "res.partner", + string="Partner invoice address", default=lambda self: self._default_invoice_address(), - readonly=True, states={'draft': [('readonly', False)]}, + readonly=True, + states={"draft": [("readonly", False)]}, help="Invoice address for current rma order.", ) refund_count = fields.Integer( - compute='_compute_refund_count', string='# of Refunds', default=0) + compute="_compute_refund_count", string="# of Refunds", default=0 + ) invoice_line_id = fields.Many2one( - comodel_name='account.invoice.line', - string='Originating Invoice Line', - ondelete='restrict', + comodel_name="account.invoice.line", + string="Originating Invoice Line", + ondelete="restrict", index=True, - readonly=True, states={'draft': [('readonly', False)]}, + readonly=True, + states={"draft": [("readonly", False)]}, ) refund_line_ids = fields.One2many( - comodel_name='account.invoice.line', - inverse_name='rma_line_id', string='Refund Lines', - copy=False, index=True, readonly=True, + comodel_name="account.invoice.line", + inverse_name="rma_line_id", + string="Refund Lines", + copy=False, + index=True, + readonly=True, ) - invoice_id = fields.Many2one('account.invoice', string='Source', - related='invoice_line_id.invoice_id', - index=True, readonly=True) - refund_policy = fields.Selection([ - ('no', 'No refund'), ('ordered', 'Based on Ordered Quantities'), - ('delivered', 'Based on Delivered Quantities'), - ('received', 'Based on Received Quantities')], string="Refund Policy", - required=True, default='no', - readonly=True, states={'draft': [('readonly', False)]}, + invoice_id = fields.Many2one( + "account.invoice", + string="Source", + related="invoice_line_id.invoice_id", + index=True, + readonly=True, + ) + refund_policy = fields.Selection( + [ + ("no", "No refund"), + ("ordered", "Based on Ordered Quantities"), + ("delivered", "Based on Delivered Quantities"), + ("received", "Based on Received Quantities"), + ], + string="Refund Policy", + required=True, + default="no", + readonly=True, + states={"draft": [("readonly", False)]}, ) qty_to_refund = fields.Float( - string='Qty To Refund', copy=False, - digits=dp.get_precision('Product Unit of Measure'), readonly=True, - compute='_compute_qty_to_refund', store=True) + string="Qty To Refund", + copy=False, + digits=dp.get_precision("Product Unit of Measure"), + readonly=True, + compute="_compute_qty_to_refund", + store=True, + ) qty_refunded = fields.Float( - string='Qty Refunded', copy=False, - digits=dp.get_precision('Product Unit of Measure'), - readonly=True, compute='_compute_qty_refunded', store=True) + string="Qty Refunded", + copy=False, + digits=dp.get_precision("Product Unit of Measure"), + readonly=True, + compute="_compute_qty_refunded", + store=True, + ) - @api.onchange('product_id', 'partner_id') + @api.onchange("product_id", "partner_id") def _onchange_product_id(self): """Domain for sale_line_id is computed here to make it dynamic.""" res = super(RmaOrderLine, self)._onchange_product_id() - if not res.get('domain'): - res['domain'] = {} + if not res.get("domain"): + res["domain"] = {} domain = [ - '|', - ('invoice_id.partner_id', '=', self.partner_id.id), - ('invoice_id.partner_id', 'child_of', self.partner_id.id)] + "|", + ("invoice_id.partner_id", "=", self.partner_id.id), + ("invoice_id.partner_id", "child_of", self.partner_id.id), + ] if self.product_id: - domain.append(('product_id', '=', self.product_id.id)) - res['domain']['invoice_line_id'] = domain + domain.append(("product_id", "=", self.product_id.id)) + res["domain"]["invoice_line_id"] = domain return res @api.multi @@ -102,137 +138,157 @@ class RmaOrderLine(models.Model): self.ensure_one() if not self.type: self.type = self._get_default_type() - if self.type == 'customer': - operation = line.product_id.rma_customer_operation_id or \ - line.product_id.categ_id.rma_customer_operation_id + if self.type == "customer": + operation = ( + line.product_id.rma_customer_operation_id + or line.product_id.categ_id.rma_customer_operation_id + ) else: - operation = line.product_id.rma_supplier_operation_id or \ - line.product_id.categ_id.rma_supplier_operation_id + operation = ( + line.product_id.rma_supplier_operation_id + or line.product_id.categ_id.rma_supplier_operation_id + ) if not operation: - operation = self.env['rma.operation'].search( - [('type', '=', self.type)], limit=1) + operation = self.env["rma.operation"].search( + [("type", "=", self.type)], limit=1 + ) if not operation: raise ValidationError(_("Please define an operation first")) if not operation.in_route_id or not operation.out_route_id: - route = self.env['stock.location.route'].search( - [('rma_selectable', '=', True)], limit=1) + route = self.env["stock.location.route"].search( + [("rma_selectable", "=", True)], limit=1 + ) if not route: raise ValidationError(_("Please define an rma route")) if not operation.in_warehouse_id or not operation.out_warehouse_id: - warehouse = self.env['stock.warehouse'].search( - [('company_id', '=', self.company_id.id), - ('lot_rma_id', '!=', False)], limit=1) + warehouse = self.env["stock.warehouse"].search( + [("company_id", "=", self.company_id.id), ("lot_rma_id", "!=", False)], + limit=1, + ) if not warehouse: - raise ValidationError(_("Please define a warehouse with a" - " default rma location")) + raise ValidationError( + _("Please define a warehouse with a" " default rma location") + ) data = { - 'product_id': line.product_id.id, - 'origin': line.invoice_id.number, - 'uom_id': line.uom_id.id, - 'operation_id': operation.id, - 'product_qty': line.quantity, - 'price_unit': line.invoice_id.currency_id.compute( - line.price_unit, line.currency_id, round=False), - 'delivery_address_id': line.invoice_id.partner_id.id, - 'invoice_address_id': line.invoice_id.partner_id.id, - 'receipt_policy': operation.receipt_policy, - 'refund_policy': operation.refund_policy, - 'delivery_policy': operation.delivery_policy, - 'currency_id': line.currency_id.id, - 'in_warehouse_id': operation.in_warehouse_id.id or warehouse.id, - 'out_warehouse_id': operation.out_warehouse_id.id or warehouse.id, - 'in_route_id': operation.in_route_id.id or route.id, - 'out_route_id': operation.out_route_id.id or route.id, - 'location_id': (operation.location_id.id or - operation.in_warehouse_id.lot_rma_id.id or - warehouse.lot_rma_id.id), + "product_id": line.product_id.id, + "origin": line.invoice_id.number, + "uom_id": line.uom_id.id, + "operation_id": operation.id, + "product_qty": line.quantity, + "price_unit": line.invoice_id.currency_id.compute( + line.price_unit, line.currency_id, round=False + ), + "delivery_address_id": line.invoice_id.partner_id.id, + "invoice_address_id": line.invoice_id.partner_id.id, + "receipt_policy": operation.receipt_policy, + "refund_policy": operation.refund_policy, + "delivery_policy": operation.delivery_policy, + "currency_id": line.currency_id.id, + "in_warehouse_id": operation.in_warehouse_id.id or warehouse.id, + "out_warehouse_id": operation.out_warehouse_id.id or warehouse.id, + "in_route_id": operation.in_route_id.id or route.id, + "out_route_id": operation.out_route_id.id or route.id, + "location_id": ( + operation.location_id.id + or operation.in_warehouse_id.lot_rma_id.id + or warehouse.lot_rma_id.id + ), } return data - @api.onchange('invoice_line_id') + @api.onchange("invoice_line_id") def _onchange_invoice_line_id(self): if not self.invoice_line_id: return - data = self._prepare_rma_line_from_inv_line( - self.invoice_line_id) + data = self._prepare_rma_line_from_inv_line(self.invoice_line_id) self.update(data) - self._remove_other_data_origin('invoice_line_id') + self._remove_other_data_origin("invoice_line_id") @api.multi - @api.constrains('invoice_line_id', 'partner_id') + @api.constrains("invoice_line_id", "partner_id") def _check_invoice_partner(self): for rec in self: - if (rec.invoice_line_id and - rec.invoice_line_id.invoice_id.partner_id != - rec.partner_id): - raise ValidationError(_( - "RMA customer and originating invoice line customer " - "doesn't match.")) + if ( + rec.invoice_line_id + and rec.invoice_line_id.invoice_id.partner_id != rec.partner_id + ): + raise ValidationError( + _( + "RMA customer and originating invoice line customer " + "doesn't match." + ) + ) @api.multi def _remove_other_data_origin(self, exception): res = super(RmaOrderLine, self)._remove_other_data_origin(exception) - if not exception == 'invoice_line_id': + if not exception == "invoice_line_id": self.invoice_line_id = False return res - @api.onchange('operation_id') + @api.onchange("operation_id") def _onchange_operation_id(self): result = super(RmaOrderLine, self)._onchange_operation_id() if self.operation_id: - self.refund_policy = self.operation_id.refund_policy or 'no' + self.refund_policy = self.operation_id.refund_policy or "no" return result @api.multi - @api.constrains('invoice_line_id') + @api.constrains("invoice_line_id") def _check_duplicated_lines(self): for line in self: - matching_inv_lines = self.env['account.invoice.line'].search([( - 'id', '=', line.invoice_line_id.id)]) + matching_inv_lines = self.env["account.invoice.line"].search( + [("id", "=", line.invoice_line_id.id)] + ) if len(matching_inv_lines) > 1: - raise UserError( - _("There's an rma for the invoice line %s " - "and invoice %s" % - (line.invoice_line_id, - line.invoice_line_id.invoice_id))) + raise UserError( + _( + "There's an rma for the invoice line %s " + "and invoice %s" + % (line.invoice_line_id, line.invoice_line_id.invoice_id) + ) + ) return {} @api.multi def action_view_invoice(self): - action = self.env.ref('account.action_invoice_tree') + action = self.env.ref("account.action_invoice_tree") result = action.read()[0] - res = self.env.ref('account.invoice_form', False) - result['views'] = [(res and res.id or False, 'form')] - result['view_id'] = res and res.id or False - result['res_id'] = self.invoice_line_id.invoice_id.id + res = self.env.ref("account.invoice_form", False) + result["views"] = [(res and res.id or False, "form")] + result["view_id"] = res and res.id or False + result["res_id"] = self.invoice_line_id.invoice_id.id return result @api.multi def action_view_refunds(self): - action = self.env.ref('account.action_invoice_tree2') + action = self.env.ref("account.action_invoice_tree2") result = action.read()[0] - invoice_ids = self.mapped('refund_line_ids.invoice_id').ids + invoice_ids = self.mapped("refund_line_ids.invoice_id").ids if invoice_ids: # choose the view_mode accordingly if len(invoice_ids) > 1: - result['domain'] = [('id', 'in', invoice_ids)] + result["domain"] = [("id", "in", invoice_ids)] else: - res = self.env.ref('account.invoice_supplier_form', False) - result['views'] = [(res and res.id or False, 'form')] - result['res_id'] = invoice_ids[0] + res = self.env.ref("account.invoice_supplier_form", False) + result["views"] = [(res and res.id or False, "form")] + result["res_id"] = invoice_ids[0] return result @api.multi def name_get(self): res = [] - if self.env.context.get('rma'): + if self.env.context.get("rma"): for rma in self: - res.append((rma.id, "%s %s qty:%s" % ( - rma.name, - rma.product_id.name, - rma.product_qty))) + res.append( + ( + rma.id, + "%s %s qty:%s" + % (rma.name, rma.product_id.name, rma.product_qty), + ) + ) return res else: return super(RmaOrderLine, self).name_get() diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py index 4da5c8cb..53c164fd 100644 --- a/rma_account/tests/test_rma_account.py +++ b/rma_account/tests/test_rma_account.py @@ -5,193 +5,206 @@ from odoo.tests import common class TestRmaAccount(common.SingleTransactionCase): - @classmethod def setUpClass(cls): super(TestRmaAccount, cls).setUpClass() - cls.rma_obj = cls.env['rma.order'] - cls.rma_line_obj = cls.env['rma.order.line'] - cls.rma_op_obj = cls.env['rma.operation'] - cls.rma_add_invoice_wiz = cls.env['rma_add_invoice'] - cls.rma_refund_wiz = cls.env['rma.refund'] - cls.acc_obj = cls.env['account.account'] - cls.inv_obj = cls.env['account.invoice'] - cls.invl_obj = cls.env['account.invoice.line'] - cls.product_obj = cls.env['product.product'] - cls.partner_obj = cls.env['res.partner'] + cls.rma_obj = cls.env["rma.order"] + cls.rma_line_obj = cls.env["rma.order.line"] + cls.rma_op_obj = cls.env["rma.operation"] + cls.rma_add_invoice_wiz = cls.env["rma_add_invoice"] + cls.rma_refund_wiz = cls.env["rma.refund"] + cls.acc_obj = cls.env["account.account"] + cls.inv_obj = cls.env["account.invoice"] + cls.invl_obj = cls.env["account.invoice.line"] + cls.product_obj = cls.env["product.product"] + cls.partner_obj = cls.env["res.partner"] - cls.rma_route_cust = cls.env.ref('rma.route_rma_customer') - receivable_type = cls.env.ref('account.data_account_type_receivable') - payable_type = cls.env.ref('account.data_account_type_payable') - cls.cust_refund_op = cls.env.ref( - 'rma_account.rma_operation_customer_refund') + cls.rma_route_cust = cls.env.ref("rma.route_rma_customer") + receivable_type = cls.env.ref("account.data_account_type_receivable") + payable_type = cls.env.ref("account.data_account_type_payable") + cls.cust_refund_op = cls.env.ref("rma_account.rma_operation_customer_refund") # Create partners - customer1 = cls.partner_obj.create({'name': 'Customer 1'}) - supplier1 = cls.partner_obj.create({'name': 'Supplier 1'}) + customer1 = cls.partner_obj.create({"name": "Customer 1"}) + supplier1 = cls.partner_obj.create({"name": "Supplier 1"}) # Create RMA group and operation: - cls.rma_group_customer = cls.rma_obj.create({ - 'partner_id': customer1.id, - 'type': 'customer', - }) - cls.rma_group_supplier = cls.rma_obj.create({ - 'partner_id': supplier1.id, - 'type': 'supplier', - }) - cls.operation_1 = cls.rma_op_obj.create({ - 'code': 'TEST', - 'name': 'Refund and receive', - 'type': 'customer', - 'receipt_policy': 'ordered', - 'refund_policy': 'ordered', - 'in_route_id': cls.rma_route_cust.id, - 'out_route_id': cls.rma_route_cust.id, - }) + cls.rma_group_customer = cls.rma_obj.create( + {"partner_id": customer1.id, "type": "customer"} + ) + cls.rma_group_supplier = cls.rma_obj.create( + {"partner_id": supplier1.id, "type": "supplier"} + ) + cls.operation_1 = cls.rma_op_obj.create( + { + "code": "TEST", + "name": "Refund and receive", + "type": "customer", + "receipt_policy": "ordered", + "refund_policy": "ordered", + "in_route_id": cls.rma_route_cust.id, + "out_route_id": cls.rma_route_cust.id, + } + ) # Create products - cls.product_1 = cls.product_obj.create({ - 'name': 'Test Product 1', - 'type': 'product', - 'list_price': 100.0, - 'rma_customer_operation_id': cls.cust_refund_op.id, - }) - cls.product_2 = cls.product_obj.create({ - 'name': 'Test Product 2', - 'type': 'product', - 'list_price': 150.0, - 'rma_customer_operation_id': cls.operation_1.id, - }) - cls.product_3 = cls.product_obj.create({ - 'name': 'Test Product 3', - 'type': 'product', - }) - cls.product_4 = cls.product_obj.create({ - 'name': 'Test Product 4', - 'type': 'product', - }) + cls.product_1 = cls.product_obj.create( + { + "name": "Test Product 1", + "type": "product", + "list_price": 100.0, + "rma_customer_operation_id": cls.cust_refund_op.id, + } + ) + cls.product_2 = cls.product_obj.create( + { + "name": "Test Product 2", + "type": "product", + "list_price": 150.0, + "rma_customer_operation_id": cls.operation_1.id, + } + ) + cls.product_3 = cls.product_obj.create( + {"name": "Test Product 3", "type": "product"} + ) + cls.product_4 = cls.product_obj.create( + {"name": "Test Product 4", "type": "product"} + ) # Create Invoices: - customer_account = cls.acc_obj. search( - [('user_type_id', '=', receivable_type.id)], limit=1).id - cls.inv_customer = cls.inv_obj.create({ - 'partner_id': customer1.id, - 'account_id': customer_account, - 'type': 'out_invoice', - }) - cls.inv_line_1 = cls.invl_obj.create({ - 'name': cls.product_1.name, - 'product_id': cls.product_1.id, - 'quantity': 12.0, - 'price_unit': 100.0, - 'invoice_id': cls.inv_customer.id, - 'uom_id': cls.product_1.uom_id.id, - 'account_id': customer_account, - }) - cls.inv_line_2 = cls.invl_obj.create({ - 'name': cls.product_2.name, - 'product_id': cls.product_2.id, - 'quantity': 15.0, - 'price_unit': 150.0, - 'invoice_id': cls.inv_customer.id, - 'uom_id': cls.product_2.uom_id.id, - 'account_id': customer_account, - }) + customer_account = cls.acc_obj.search( + [("user_type_id", "=", receivable_type.id)], limit=1 + ).id + cls.inv_customer = cls.inv_obj.create( + { + "partner_id": customer1.id, + "account_id": customer_account, + "type": "out_invoice", + } + ) + cls.inv_line_1 = cls.invl_obj.create( + { + "name": cls.product_1.name, + "product_id": cls.product_1.id, + "quantity": 12.0, + "price_unit": 100.0, + "invoice_id": cls.inv_customer.id, + "uom_id": cls.product_1.uom_id.id, + "account_id": customer_account, + } + ) + cls.inv_line_2 = cls.invl_obj.create( + { + "name": cls.product_2.name, + "product_id": cls.product_2.id, + "quantity": 15.0, + "price_unit": 150.0, + "invoice_id": cls.inv_customer.id, + "uom_id": cls.product_2.uom_id.id, + "account_id": customer_account, + } + ) supplier_account = cls.acc_obj.search( - [('user_type_id', '=', payable_type.id)], limit=1).id - cls.inv_supplier = cls.inv_obj.create({ - 'partner_id': supplier1.id, - 'account_id': supplier_account, - 'type': 'in_invoice', - }) - cls.inv_line_3 = cls.invl_obj.create({ - 'name': cls.product_3.name, - 'product_id': cls.product_3.id, - 'quantity': 17.0, - 'price_unit': 250.0, - 'invoice_id': cls.inv_supplier.id, - 'uom_id': cls.product_3.uom_id.id, - 'account_id': supplier_account, - }) - cls.inv_line_4 = cls.invl_obj.create({ - 'name': cls.product_4.name, - 'product_id': cls.product_4.id, - 'quantity': 9.0, - 'price_unit': 300.0, - 'invoice_id': cls.inv_supplier.id, - 'uom_id': cls.product_4.uom_id.id, - 'account_id': supplier_account, - }) + [("user_type_id", "=", payable_type.id)], limit=1 + ).id + cls.inv_supplier = cls.inv_obj.create( + { + "partner_id": supplier1.id, + "account_id": supplier_account, + "type": "in_invoice", + } + ) + cls.inv_line_3 = cls.invl_obj.create( + { + "name": cls.product_3.name, + "product_id": cls.product_3.id, + "quantity": 17.0, + "price_unit": 250.0, + "invoice_id": cls.inv_supplier.id, + "uom_id": cls.product_3.uom_id.id, + "account_id": supplier_account, + } + ) + cls.inv_line_4 = cls.invl_obj.create( + { + "name": cls.product_4.name, + "product_id": cls.product_4.id, + "quantity": 9.0, + "price_unit": 300.0, + "invoice_id": cls.inv_supplier.id, + "uom_id": cls.product_4.uom_id.id, + "account_id": supplier_account, + } + ) def test_01_add_from_invoice_customer(self): """Test wizard to create RMA from a customer invoice.""" - add_inv = self.rma_add_invoice_wiz.with_context({ - 'customer': True, - 'active_ids': self.rma_group_customer.id, - 'active_model': 'rma.order', - }).create({ - 'invoice_line_ids': - [(6, 0, self.inv_customer.invoice_line_ids.ids)], - }) + add_inv = self.rma_add_invoice_wiz.with_context( + { + "customer": True, + "active_ids": self.rma_group_customer.id, + "active_model": "rma.order", + } + ).create({"invoice_line_ids": [(6, 0, self.inv_customer.invoice_line_ids.ids)]}) add_inv.add_lines() self.assertEqual(len(self.rma_group_customer.rma_line_ids), 2) - for t in self.rma_group_supplier.rma_line_ids.mapped('type'): - self.assertEqual(t, 'customer') + for t in self.rma_group_supplier.rma_line_ids.mapped("type"): + self.assertEqual(t, "customer") rma_1 = self.rma_group_customer.rma_line_ids.filtered( - lambda r: r.product_id == self.product_1) + lambda r: r.product_id == self.product_1 + ) self.assertEqual(rma_1.operation_id, self.cust_refund_op) rma_2 = self.rma_group_customer.rma_line_ids.filtered( - lambda r: r.product_id == self.product_2) + lambda r: r.product_id == self.product_2 + ) self.assertEqual(rma_2.operation_id, self.operation_1) def test_02_add_from_invoice_supplier(self): """Test wizard to create RMA from a vendor bill.""" - add_inv = self.rma_add_invoice_wiz.with_context({ - 'supplier': True, - 'active_ids': self.rma_group_supplier.id, - 'active_model': 'rma.order', - }).create({ - 'invoice_line_ids': - [(6, 0, self.inv_supplier.invoice_line_ids.ids)], - }) + add_inv = self.rma_add_invoice_wiz.with_context( + { + "supplier": True, + "active_ids": self.rma_group_supplier.id, + "active_model": "rma.order", + } + ).create({"invoice_line_ids": [(6, 0, self.inv_supplier.invoice_line_ids.ids)]}) add_inv.add_lines() self.assertEqual(len(self.rma_group_supplier.rma_line_ids), 2) - for t in self.rma_group_supplier.rma_line_ids.mapped('type'): - self.assertEqual(t, 'supplier') + for t in self.rma_group_supplier.rma_line_ids.mapped("type"): + self.assertEqual(t, "supplier") def test_03_rma_refund_operation(self): """Test RMA quantities using refund operations.""" # Received refund_policy: rma_1 = self.rma_group_customer.rma_line_ids.filtered( - lambda r: r.product_id == self.product_1) - self.assertEqual(rma_1.refund_policy, 'received') + lambda r: r.product_id == self.product_1 + ) + self.assertEqual(rma_1.refund_policy, "received") self.assertEqual(rma_1.qty_to_refund, 0.0) # TODO: receive and check qty_to_refund is 12.0 # Ordered refund_policy: rma_2 = self.rma_group_customer.rma_line_ids.filtered( - lambda r: r.product_id == self.product_2) + lambda r: r.product_id == self.product_2 + ) rma_2._onchange_operation_id() - self.assertEqual(rma_2.refund_policy, 'ordered') + self.assertEqual(rma_2.refund_policy, "ordered") self.assertEqual(rma_2.qty_to_refund, 15.0) def test_04_rma_create_refund(self): """Generate a Refund from a customer RMA.""" rma = self.rma_group_customer.rma_line_ids.filtered( - lambda r: r.product_id == self.product_2) + lambda r: r.product_id == self.product_2 + ) rma.action_rma_to_approve() rma.action_rma_approve() self.assertEqual(rma.refund_count, 0) self.assertEqual(rma.qty_to_refund, 15.0) self.assertEqual(rma.qty_refunded, 0.0) - make_refund = self.rma_refund_wiz.with_context({ - 'customer': True, - 'active_ids': rma.ids, - 'active_model': 'rma.order.line', - }).create({ - 'description': 'Test refund', - }) + make_refund = self.rma_refund_wiz.with_context( + {"customer": True, "active_ids": rma.ids, "active_model": "rma.order.line"} + ).create({"description": "Test refund"}) make_refund.invoice_refund() rma.refund_line_ids.invoice_id.action_invoice_open() rma._compute_refund_count() @@ -201,10 +214,12 @@ class TestRmaAccount(common.SingleTransactionCase): def test_05_fill_rma_from_inv_line(self): """Test filling a RMA (line) from a invoice line.""" - rma = self.rma_line_obj.new({ - 'partner_id': self.inv_customer.partner_id.id, - 'invoice_line_id': self.inv_line_1.id, - }) + rma = self.rma_line_obj.new( + { + "partner_id": self.inv_customer.partner_id.id, + "invoice_line_id": self.inv_line_1.id, + } + ) self.assertFalse(rma.product_id) rma._onchange_invoice_line_id() self.assertEqual(rma.product_id, self.product_1) diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index f766b6f6..a97e37f6 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -6,90 +6,106 @@ from odoo.exceptions import ValidationError class RmaAddInvoice(models.TransientModel): - _name = 'rma_add_invoice' - _description = 'Wizard to add rma lines' + _name = "rma_add_invoice" + _description = "Wizard to add rma lines" @api.model def default_get(self, fields_list): res = super(RmaAddInvoice, self).default_get(fields_list) - rma_obj = self.env['rma.order'] - rma_id = self.env.context['active_ids'] or [] - active_model = self.env.context['active_model'] + rma_obj = self.env["rma.order"] + rma_id = self.env.context["active_ids"] or [] + active_model = self.env.context["active_model"] if not rma_id: return res - assert active_model == 'rma.order', 'Bad context propagation' + assert active_model == "rma.order", "Bad context propagation" rma = rma_obj.browse(rma_id) - res['rma_id'] = rma.id - res['partner_id'] = rma.partner_id.id - res['invoice_line_ids'] = False + res["rma_id"] = rma.id + res["partner_id"] = rma.partner_id.id + res["invoice_line_ids"] = False return res - rma_id = fields.Many2one('rma.order', string='RMA Order', readonly=True, - ondelete='cascade') - partner_id = fields.Many2one(comodel_name='res.partner', string='Partner', - readonly=True) - invoice_line_ids = fields.Many2many('account.invoice.line', - 'rma_add_invoice_add_line_rel', - 'invoice_line_id', - 'rma_add_invoice_id', - string='Invoice Lines') + rma_id = fields.Many2one( + "rma.order", string="RMA Order", readonly=True, ondelete="cascade" + ) + partner_id = fields.Many2one( + comodel_name="res.partner", string="Partner", readonly=True + ) + invoice_line_ids = fields.Many2many( + "account.invoice.line", + "rma_add_invoice_add_line_rel", + "invoice_line_id", + "rma_add_invoice_id", + string="Invoice Lines", + ) def _prepare_rma_line_from_inv_line(self, line): - if self.env.context.get('customer'): - operation = line.product_id.rma_customer_operation_id or \ - line.product_id.categ_id.rma_customer_operation_id + if self.env.context.get("customer"): + operation = ( + line.product_id.rma_customer_operation_id + or line.product_id.categ_id.rma_customer_operation_id + ) else: - operation = line.product_id.rma_supplier_operation_id or \ - line.product_id.categ_id.rma_supplier_operation_id + operation = ( + line.product_id.rma_supplier_operation_id + or line.product_id.categ_id.rma_supplier_operation_id + ) if not operation: - operation = self.env['rma.operation'].search( - [('type', '=', self.rma_id.type)], limit=1) + operation = self.env["rma.operation"].search( + [("type", "=", self.rma_id.type)], limit=1 + ) if not operation: raise ValidationError(_("Please define an operation first")) if not operation.in_route_id or not operation.out_route_id: - route = self.env['stock.location.route'].search( - [('rma_selectable', '=', True)], limit=1) + route = self.env["stock.location.route"].search( + [("rma_selectable", "=", True)], limit=1 + ) if not route: raise ValidationError(_("Please define an rma route")) if not operation.in_warehouse_id or not operation.out_warehouse_id: - warehouse = self.env['stock.warehouse'].search( - [('company_id', '=', self.rma_id.company_id.id), - ('lot_rma_id', '!=', False)], limit=1) + warehouse = self.env["stock.warehouse"].search( + [ + ("company_id", "=", self.rma_id.company_id.id), + ("lot_rma_id", "!=", False), + ], + limit=1, + ) if not warehouse: - raise ValidationError(_("Please define a warehouse with a" - " default rma location")) + raise ValidationError( + _("Please define a warehouse with a" " default rma location") + ) data = { - 'partner_id': self.partner_id.id, - 'invoice_line_id': line.id, - 'product_id': line.product_id.id, - 'origin': line.invoice_id.number, - 'uom_id': line.uom_id.id, - 'operation_id': operation.id, - 'product_qty': line.quantity, - 'price_unit': line.invoice_id.currency_id.compute( - line.price_unit, line.currency_id, round=False), - 'delivery_address_id': line.invoice_id.partner_id.id, - 'invoice_address_id': line.invoice_id.partner_id.id, - 'rma_id': self.rma_id.id, - 'receipt_policy': operation.receipt_policy, - 'refund_policy': operation.refund_policy, - 'delivery_policy': operation.delivery_policy, - 'in_warehouse_id': operation.in_warehouse_id.id or warehouse.id, - 'out_warehouse_id': operation.out_warehouse_id.id or warehouse.id, - 'in_route_id': operation.in_route_id.id or route.id, - 'out_route_id': operation.out_route_id.id or route.id, - 'location_id': (operation.location_id.id or - operation.in_warehouse_id.lot_rma_id.id or - warehouse.lot_rma_id.id), + "partner_id": self.partner_id.id, + "invoice_line_id": line.id, + "product_id": line.product_id.id, + "origin": line.invoice_id.number, + "uom_id": line.uom_id.id, + "operation_id": operation.id, + "product_qty": line.quantity, + "price_unit": line.invoice_id.currency_id.compute( + line.price_unit, line.currency_id, round=False + ), + "delivery_address_id": line.invoice_id.partner_id.id, + "invoice_address_id": line.invoice_id.partner_id.id, + "rma_id": self.rma_id.id, + "receipt_policy": operation.receipt_policy, + "refund_policy": operation.refund_policy, + "delivery_policy": operation.delivery_policy, + "in_warehouse_id": operation.in_warehouse_id.id or warehouse.id, + "out_warehouse_id": operation.out_warehouse_id.id or warehouse.id, + "in_route_id": operation.in_route_id.id or route.id, + "out_route_id": operation.out_route_id.id or route.id, + "location_id": ( + operation.location_id.id + or operation.in_warehouse_id.lot_rma_id.id + or warehouse.lot_rma_id.id + ), } return data @api.model def _get_rma_data(self): - data = { - 'date_rma': fields.Datetime.now(), - } + data = {"date_rma": fields.Datetime.now()} return data @api.model @@ -101,7 +117,7 @@ class RmaAddInvoice(models.TransientModel): @api.multi def add_lines(self): - rma_line_obj = self.env['rma.order.line'] + rma_line_obj = self.env["rma.order.line"] existing_invoice_lines = self._get_existing_invoice_lines() for line in self.invoice_line_ids: # Load a PO line only once @@ -111,4 +127,4 @@ class RmaAddInvoice(models.TransientModel): rma = self.rma_id data_rma = self._get_rma_data() rma.write(data_rma) - return {'type': 'ir.actions.act_window_close'} + return {"type": "ir.actions.act_window_close"} diff --git a/rma_account/wizards/rma_order_line_make_supplier_rma.py b/rma_account/wizards/rma_order_line_make_supplier_rma.py index bbd94cd1..e1c3fc78 100644 --- a/rma_account/wizards/rma_order_line_make_supplier_rma.py +++ b/rma_account/wizards/rma_order_line_make_supplier_rma.py @@ -9,9 +9,8 @@ class RmaLineMakeSupplierRma(models.TransientModel): @api.model def _prepare_supplier_rma_line(self, rma, item): - res = super(RmaLineMakeSupplierRma, self)._prepare_supplier_rma_line( - rma, item) - if res['operation_id']: - operation = self.env['rma.operation'].browse(res['operation_id']) - res['refund_policy'] = operation.refund_policy + res = super(RmaLineMakeSupplierRma, self)._prepare_supplier_rma_line(rma, item) + if res["operation_id"]: + operation = self.env["rma.operation"].browse(res["operation_id"]) + res["refund_policy"] = operation.refund_policy return res diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 0e06ee16..d86a754c 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -3,6 +3,7 @@ from odoo import _, api, fields, models from odoo.exceptions import ValidationError + import odoo.addons.decimal_precision as dp @@ -12,22 +13,21 @@ class RmaRefund(models.TransientModel): @api.model def _get_reason(self): - active_ids = self.env.context.get('active_ids', False) - return self.env['rma.order.line'].browse( - active_ids[0]).rma_id.name or '' + active_ids = self.env.context.get("active_ids", False) + return self.env["rma.order.line"].browse(active_ids[0]).rma_id.name or "" - @api.returns('rma.order.line') + @api.returns("rma.order.line") def _prepare_item(self, line): values = { - 'product_id': line.product_id.id, - 'name': line.name, - 'product_qty': line.product_qty, - 'uom_id': line.uom_id.id, - 'qty_to_refund': line.qty_to_refund, - 'refund_policy': line.refund_policy, - 'invoice_address_id': line.invoice_address_id.id, - 'line_id': line.id, - 'rma_id': line.rma_id.id, + "product_id": line.product_id.id, + "name": line.name, + "product_qty": line.product_qty, + "uom_id": line.uom_id.id, + "qty_to_refund": line.qty_to_refund, + "refund_policy": line.refund_policy, + "invoice_address_id": line.invoice_address_id.id, + "line_id": line.id, + "rma_id": line.rma_id.id, } return values @@ -39,37 +39,37 @@ class RmaRefund(models.TransientModel): """ context = self._context.copy() res = super(RmaRefund, self).default_get(fields_list) - rma_line_obj = self.env['rma.order.line'] - rma_line_ids = self.env.context['active_ids'] or [] - active_model = self.env.context['active_model'] + rma_line_obj = self.env["rma.order.line"] + rma_line_ids = self.env.context["active_ids"] or [] + active_model = self.env.context["active_model"] if not rma_line_ids: return res - assert active_model == 'rma.order.line', 'Bad context propagation' + assert active_model == "rma.order.line", "Bad context propagation" items = [] lines = rma_line_obj.browse(rma_line_ids) - if len(lines.mapped('partner_id')) > 1: + if len(lines.mapped("partner_id")) > 1: raise ValidationError( - _("Only RMAs from the same partner can be processed at " - "the same time.")) + _( + "Only RMAs from the same partner can be processed at " + "the same time." + ) + ) for line in lines: items.append([0, 0, self._prepare_item(line)]) - res['item_ids'] = items - context.update({'items_ids': items}) + res["item_ids"] = items + context.update({"items_ids": items}) return res date_invoice = fields.Date( - string='Refund Date', - default=fields.Date.context_today, required=True, + string="Refund Date", default=fields.Date.context_today, required=True ) - date = fields.Date(string='Accounting Date') + date = fields.Date(string="Accounting Date") description = fields.Char( - string='Reason', required=True, - default=lambda self: self._get_reason(), + string="Reason", required=True, default=lambda self: self._get_reason() ) item_ids = fields.One2many( - comodel_name='rma.refund.item', - inverse_name='wiz_id', string='Items', + comodel_name="rma.refund.item", inverse_name="wiz_id", string="Items" ) @api.multi @@ -77,102 +77,107 @@ class RmaRefund(models.TransientModel): for wizard in self: first = self.item_ids[0] values = self._prepare_refund(wizard, first.line_id) - new_refund = self.env['account.invoice'].create(values) + new_refund = self.env["account.invoice"].create(values) for item in self.item_ids: refund_line_values = self.prepare_refund_line(item, new_refund) - self.env['account.invoice.line'].create( - refund_line_values) + self.env["account.invoice.line"].create(refund_line_values) return new_refund @api.multi def invoice_refund(self): - rma_line_ids = self.env['rma.order.line'].browse( - self.env.context['active_ids']) + rma_line_ids = self.env["rma.order.line"].browse(self.env.context["active_ids"]) for line in rma_line_ids: - if line.refund_policy == 'no': + if line.refund_policy == "no": raise ValidationError( - _('The operation is not refund for at least one line')) - if line.state != 'approved': - raise ValidationError( - _('RMA %s is not approved') % line.name) + _("The operation is not refund for at least one line") + ) + if line.state != "approved": + raise ValidationError(_("RMA %s is not approved") % line.name) new_invoice = self.compute_refund() - action = 'action_invoice_tree1' if ( - new_invoice.type in ['out_refund', 'out_invoice']) \ - else 'action_invoice_in_refund' - result = self.env.ref('account.%s' % action).read()[0] - form_view = self.env.ref('account.invoice_supplier_form', False) - result['views'] = [(form_view and form_view.id or False, 'form')] - result['res_id'] = new_invoice.id + action = ( + "action_invoice_tree1" + if (new_invoice.type in ["out_refund", "out_invoice"]) + else "action_invoice_in_refund" + ) + result = self.env.ref("account.%s" % action).read()[0] + form_view = self.env.ref("account.invoice_supplier_form", False) + result["views"] = [(form_view and form_view.id or False, "form")] + result["res_id"] = new_invoice.id return result @api.model def prepare_refund_line(self, item, refund): accounts = item.product_id.product_tmpl_id._get_product_accounts() - if item.line_id.type == 'customer': - account = accounts['stock_output'] + if item.line_id.type == "customer": + account = accounts["stock_output"] else: - account = accounts['stock_input'] + account = accounts["stock_input"] if not account: - raise ValidationError(_( - "Accounts are not configured for this product.")) + raise ValidationError(_("Accounts are not configured for this product.")) values = { - 'name': item.line_id.name or item.rma_id.name, - 'origin': item.line_id.name or item.rma_id.name, - 'account_id': account.id, - 'price_unit': item.line_id.price_unit, - 'uom_id': item.line_id.uom_id.id, - 'product_id': item.product_id.id, - 'rma_line_id': item.line_id.id, - 'quantity': item.qty_to_refund, - 'invoice_id': refund.id + "name": item.line_id.name or item.rma_id.name, + "origin": item.line_id.name or item.rma_id.name, + "account_id": account.id, + "price_unit": item.line_id.price_unit, + "uom_id": item.line_id.uom_id.id, + "product_id": item.product_id.id, + "rma_line_id": item.line_id.id, + "quantity": item.qty_to_refund, + "invoice_id": refund.id, } return values @api.model def _prepare_refund(self, wizard, rma_line): # origin_invoices = self._get_invoice(rma_line) - if rma_line.type == 'customer': - journal = self.env['account.journal'].search( - [('type', '=', 'sale')], limit=1) + if rma_line.type == "customer": + journal = self.env["account.journal"].search( + [("type", "=", "sale")], limit=1 + ) else: - journal = self.env['account.journal'].search( - [('type', '=', 'purchase')], limit=1) + journal = self.env["account.journal"].search( + [("type", "=", "purchase")], limit=1 + ) values = { - 'name': rma_line.rma_id.name or rma_line.name, - 'origin': rma_line.rma_id.name or rma_line.name, - 'reference': False, + "name": rma_line.rma_id.name or rma_line.name, + "origin": rma_line.rma_id.name or rma_line.name, + "reference": False, # 'account_id': account.id, - 'journal_id': journal.id, - 'currency_id': rma_line.partner_id.company_id.currency_id.id, - 'payment_term_id': False, - 'fiscal_position_id': - rma_line.partner_id.property_account_position_id.id, - 'state': 'draft', - 'number': False, - 'date': wizard.date, - 'date_invoice': wizard.date_invoice, - 'partner_id': rma_line.invoice_address_id.id or - rma_line.partner_id.id, + "journal_id": journal.id, + "currency_id": rma_line.partner_id.company_id.currency_id.id, + "payment_term_id": False, + "fiscal_position_id": rma_line.partner_id.property_account_position_id.id, + "state": "draft", + "number": False, + "date": wizard.date, + "date_invoice": wizard.date_invoice, + "partner_id": rma_line.invoice_address_id.id or rma_line.partner_id.id, } - if self.env.registry.models.get('crm.team', False): - team_ids = self.env['crm.team'].search( - ['|', ('user_id', '=', self.env.uid), - ('member_ids', '=', self.env.uid)], limit=1) + if self.env.registry.models.get("crm.team", False): + team_ids = self.env["crm.team"].search( + [ + "|", + ("user_id", "=", self.env.uid), + ("member_ids", "=", self.env.uid), + ], + limit=1, + ) team_id = team_ids[0] if team_ids else False if team_id: - values['team_id'] = team_id.id - if rma_line.type == 'customer': - values['type'] = 'out_refund' + values["team_id"] = team_id.id + if rma_line.type == "customer": + values["type"] = "out_refund" else: - values['type'] = 'in_refund' + values["type"] = "in_refund" return values - @api.constrains('item_ids') + @api.constrains("item_ids") def check_unique_invoice_address_id(self): - addresses = self.item_ids.mapped('invoice_address_id') + addresses = self.item_ids.mapped("invoice_address_id") if len(addresses) > 1: - raise ValidationError(_( - "The invoice address must be the same for all the lines.")) + raise ValidationError( + _("The invoice address must be the same for all the lines.") + ) return True @@ -180,33 +185,38 @@ class RmaRefundItem(models.TransientModel): _name = "rma.refund.item" _description = "RMA Lines to refund" - wiz_id = fields.Many2one( - comodel_name='rma.refund', string='Wizard', required=True) - line_id = fields.Many2one('rma.order.line', - string='RMA order Line', - required=True, - readonly=True, - ondelete='cascade') - rma_id = fields.Many2one('rma.order', - related='line_id.rma_id', - string='RMA', - readonly=True) - product_id = fields.Many2one('product.product', string='Product') - product = fields.Many2one('product.product', string='Product', - readonly=True) - name = fields.Char(string='Description', required=True) + wiz_id = fields.Many2one(comodel_name="rma.refund", string="Wizard", required=True) + line_id = fields.Many2one( + "rma.order.line", + string="RMA order Line", + required=True, + readonly=True, + ondelete="cascade", + ) + rma_id = fields.Many2one( + "rma.order", related="line_id.rma_id", string="RMA", readonly=True + ) + product_id = fields.Many2one("product.product", string="Product") + product = fields.Many2one("product.product", string="Product", readonly=True) + name = fields.Char(string="Description", required=True) product_qty = fields.Float( - string='Quantity Ordered', copy=False, - digits=dp.get_precision('Product Unit of Measure'), - readonly=True) + string="Quantity Ordered", + copy=False, + digits=dp.get_precision("Product Unit of Measure"), + readonly=True, + ) invoice_address_id = fields.Many2one( - comodel_name='res.partner', string='Invoice Address') + comodel_name="res.partner", string="Invoice Address" + ) qty_to_refund = fields.Float( - string='Quantity To Refund', - digits=dp.get_precision('Product Unit of Measure')) - uom_id = fields.Many2one('uom.uom', string='Unit of Measure', - readonly=True) - refund_policy = fields.Selection(selection=[ - ('no', 'Not required'), ('ordered', 'Based on Ordered Quantities'), - ('received', 'Based on Received Quantities')], - string="Refund Policy") + string="Quantity To Refund", digits=dp.get_precision("Product Unit of Measure") + ) + uom_id = fields.Many2one("uom.uom", string="Unit of Measure", readonly=True) + refund_policy = fields.Selection( + selection=[ + ("no", "Not required"), + ("ordered", "Based on Ordered Quantities"), + ("received", "Based on Received Quantities"), + ], + string="Refund Policy", + ) From e42464fe3ace56ca300efdeb36733e53915ea884 Mon Sep 17 00:00:00 2001 From: ahenriquez Date: Wed, 22 Jan 2020 11:23:04 +0100 Subject: [PATCH 47/93] [UPT]rebranding --- rma_account/README.rst | 10 +++++----- rma_account/__init__.py | 2 +- rma_account/__manifest__.py | 6 +++--- rma_account/models/__init__.py | 2 +- rma_account/models/invoice.py | 2 +- rma_account/models/rma_operation.py | 2 +- rma_account/models/rma_order.py | 2 +- rma_account/models/rma_order_line.py | 2 +- rma_account/tests/__init__.py | 2 +- rma_account/tests/test_rma_account.py | 2 +- rma_account/views/rma_account_menu.xml | 2 +- rma_account/wizards/__init__.py | 2 +- rma_account/wizards/rma_add_invoice.py | 2 +- .../wizards/rma_order_line_make_supplier_rma.py | 2 +- rma_account/wizards/rma_refund.py | 2 +- 15 files changed, 21 insertions(+), 21 deletions(-) diff --git a/rma_account/README.rst b/rma_account/README.rst index 8dfed892..c464cd70 100644 --- a/rma_account/README.rst +++ b/rma_account/README.rst @@ -30,7 +30,7 @@ Bug Tracker =========== Bugs are tracked on `GitHub Issues -`_. In case of trouble, please +`_. 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. @@ -40,13 +40,13 @@ Credits Contributors ------------ -* Jordi Ballester Alomar -* Aaron Henriquez -* Lois Rilo +* Jordi Ballester Alomar +* Aaron Henriquez +* Lois Rilo * Bhavesh Odedra * Akim Juillerat Maintainer ---------- -This module is maintained by Eficent. +This module is maintained by ForgeFlow. diff --git a/rma_account/__init__.py b/rma_account/__init__.py index f3284a96..d4a42780 100644 --- a/rma_account/__init__.py +++ b/rma_account/__init__.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from . import models diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 7ba3aebe..12cbab86 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) { @@ -7,8 +7,8 @@ "license": "LGPL-3", "category": "RMA", "summary": "Integrates RMA with Invoice Processing", - "author": "Eficent, Odoo Community Association (OCA)", - "website": "https://github.com/Eficent/stock-rma", + "author": "ForgeFlow, Odoo Community Association (OCA)", + "website": "https://github.com/ForgeFlow/stock-rma", "depends": ["stock_account", "rma"], "demo": ["data/rma_operation.xml"], "data": [ diff --git a/rma_account/models/__init__.py b/rma_account/models/__init__.py index bdd70de6..5f6917c7 100644 --- a/rma_account/models/__init__.py +++ b/rma_account/models/__init__.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from . import rma_order diff --git a/rma_account/models/invoice.py b/rma_account/models/invoice.py index 3fadd0b4..f52efab4 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/invoice.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import api, fields, models diff --git a/rma_account/models/rma_operation.py b/rma_account/models/rma_operation.py index 53ce4ed3..1e984810 100644 --- a/rma_account/models/rma_operation.py +++ b/rma_account/models/rma_operation.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import fields, models diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index 240ca011..5b323c41 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import api, fields, models diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index c6dd50ab..fae7ff27 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import _, api, fields, models diff --git a/rma_account/tests/__init__.py b/rma_account/tests/__init__.py index 77af78d7..4edd8b55 100644 --- a/rma_account/tests/__init__.py +++ b/rma_account/tests/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018 Eficent Business and IT Consulting Services S.L. +# Copyright 2018 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from . import test_rma_account diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py index 53c164fd..62678698 100644 --- a/rma_account/tests/test_rma_account.py +++ b/rma_account/tests/test_rma_account.py @@ -1,4 +1,4 @@ -# Copyright 2017-18 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-18 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo.tests import common diff --git a/rma_account/views/rma_account_menu.xml b/rma_account/views/rma_account_menu.xml index 7388a537..ea117122 100644 --- a/rma_account/views/rma_account_menu.xml +++ b/rma_account/views/rma_account_menu.xml @@ -1,5 +1,5 @@ - diff --git a/rma_account/wizards/__init__.py b/rma_account/wizards/__init__.py index e3832b10..ec155b09 100644 --- a/rma_account/wizards/__init__.py +++ b/rma_account/wizards/__init__.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from . import rma_refund diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_invoice.py index a97e37f6..b38e00b7 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_invoice.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import _, api, fields, models diff --git a/rma_account/wizards/rma_order_line_make_supplier_rma.py b/rma_account/wizards/rma_order_line_make_supplier_rma.py index e1c3fc78..48818da0 100644 --- a/rma_account/wizards/rma_order_line_make_supplier_rma.py +++ b/rma_account/wizards/rma_order_line_make_supplier_rma.py @@ -1,4 +1,4 @@ -# Copyright 2016 Eficent Business and IT Consulting Services S.L. +# Copyright 2016 ForgeFlow S.L. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). from odoo import api, models diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index d86a754c..8faadb92 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -1,4 +1,4 @@ -# © 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import _, api, fields, models From edbc7f4f34b85cb0d6cc748c58e927b2fa087401 Mon Sep 17 00:00:00 2001 From: ahenriquez Date: Wed, 22 Jan 2020 16:03:16 +0100 Subject: [PATCH 48/93] [MIG]rma_account to v13 --- rma_account/__manifest__.py | 8 +- rma_account/data/rma_operation.xml | 2 +- rma_account/models/__init__.py | 2 +- .../models/{invoice.py => account_move.py} | 57 +++++----- rma_account/models/rma_order.py | 62 +++++------ rma_account/models/rma_order_line.py | 89 +++++++-------- rma_account/security/ir.model.access.csv | 6 +- rma_account/tests/test_rma_account.py | 22 ++-- rma_account/views/account_move_view.xml | 69 ++++++++++++ rma_account/views/invoice_view.xml | 105 ------------------ rma_account/views/rma_account_menu.xml | 24 +++- rma_account/views/rma_order_line_view.xml | 24 ++-- rma_account/views/rma_order_view.xml | 4 +- rma_account/wizards/__init__.py | 2 +- ...add_invoice.py => rma_add_account_move.py} | 33 +++--- ...d_invoice.xml => rma_add_account_move.xml} | 55 +++++---- rma_account/wizards/rma_refund.py | 30 ++--- rma_account/wizards/rma_refund.xml | 6 +- 18 files changed, 288 insertions(+), 312 deletions(-) rename rma_account/models/{invoice.py => account_move.py} (77%) create mode 100644 rma_account/views/account_move_view.xml delete mode 100644 rma_account/views/invoice_view.xml rename rma_account/wizards/{rma_add_invoice.py => rma_add_account_move.py} (85%) rename rma_account/wizards/{rma_add_invoice.xml => rma_add_account_move.xml} (71%) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 12cbab86..48291782 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -3,11 +3,11 @@ { "name": "RMA Account", - "version": "12.0.1.0.0", + "version": "13.0.1.0.0", "license": "LGPL-3", "category": "RMA", "summary": "Integrates RMA with Invoice Processing", - "author": "ForgeFlow, Odoo Community Association (OCA)", + "author": "ForgeFlow", "website": "https://github.com/ForgeFlow/stock-rma", "depends": ["stock_account", "rma"], "demo": ["data/rma_operation.xml"], @@ -16,9 +16,9 @@ "views/rma_order_view.xml", "views/rma_operation_view.xml", "views/rma_order_line_view.xml", - "views/invoice_view.xml", + "views/account_move_view.xml", "views/rma_account_menu.xml", - "wizards/rma_add_invoice.xml", + "wizards/rma_add_account_move.xml", "wizards/rma_refund.xml", ], "installable": True, diff --git a/rma_account/data/rma_operation.xml b/rma_account/data/rma_operation.xml index f5a84ca0..139981df 100644 --- a/rma_account/data/rma_operation.xml +++ b/rma_account/data/rma_operation.xml @@ -1,5 +1,5 @@ - + no diff --git a/rma_account/models/__init__.py b/rma_account/models/__init__.py index 5f6917c7..09afbe77 100644 --- a/rma_account/models/__init__.py +++ b/rma_account/models/__init__.py @@ -4,4 +4,4 @@ from . import rma_order from . import rma_order_line from . import rma_operation -from . import invoice +from . import account_move diff --git a/rma_account/models/invoice.py b/rma_account/models/account_move.py similarity index 77% rename from rma_account/models/invoice.py rename to rma_account/models/account_move.py index f52efab4..602b0542 100644 --- a/rma_account/models/invoice.py +++ b/rma_account/models/account_move.py @@ -5,13 +5,13 @@ from odoo import api, fields, models from odoo.tools.float_utils import float_compare -class AccountInvoice(models.Model): - _inherit = "account.invoice" +class AccountMove(models.Model): + _inherit = "account.move" - @api.depends("invoice_line_ids.rma_line_ids") + @api.depends("line_ids.rma_line_ids") def _compute_rma_count(self): for inv in self: - rmas = self.mapped("invoice_line_ids.rma_line_ids") + rmas = self.mapped("line_ids.rma_line_ids") inv.rma_count = len(rmas) def _prepare_invoice_line_from_rma_line(self, line): @@ -19,18 +19,17 @@ class AccountInvoice(models.Model): if float_compare(qty, 0.0, precision_rounding=line.uom_id.rounding) <= 0: qty = 0.0 # Todo fill taxes from somewhere - invoice_line = self.env["account.invoice.line"] + invoice_line = self.env["account.move.line"] data = { "purchase_line_id": line.id, "name": line.name + ": " + line.name, - "origin": line.origin, - "uom_id": line.uom_id.id, + "product_uom_id": line.uom_id.id, "product_id": line.product_id.id, "account_id": invoice_line.with_context( {"journal_id": self.journal_id.id, "type": "in_invoice"} )._default_account(), "price_unit": line.company_id.currency_id.with_context( - date=self.date_invoice + date=self.date ).compute(line.price_unit, self.currency_id, round=False), "quantity": qty, "discount": 0.0, @@ -45,12 +44,12 @@ class AccountInvoice(models.Model): if not self.partner_id: self.partner_id = self.add_rma_line_id.partner_id.id - new_line = self.env["account.invoice.line"] - if self.add_rma_line_id not in (self.invoice_line_ids.mapped("rma_line_id")): + new_line = self.env["account.move.line"] + if self.add_rma_line_id not in (self.line_ids.mapped("rma_line_id")): data = self._prepare_invoice_line_from_rma_line(self.add_rma_line_id) new_line = new_line.new(data) new_line._set_additional_fields(self) - self.invoice_line_ids += new_line + self.line_ids += new_line self.add_rma_line_id = False return {} @@ -63,11 +62,10 @@ class AccountInvoice(models.Model): help="Create a refund in based on an existing rma_line", ) - @api.multi def action_view_rma_supplier(self): action = self.env.ref("rma.action_rma_supplier_lines") result = action.read()[0] - rma_ids = self.mapped("invoice_line_ids.rma_line_ids").ids + rma_ids = self.mapped("line_ids.rma_line_ids").ids if rma_ids: # choose the view_mode accordingly if len(rma_ids) > 1: @@ -78,11 +76,10 @@ class AccountInvoice(models.Model): result["res_id"] = rma_ids[0] return result - @api.multi def action_view_rma_customer(self): action = self.env.ref("rma.action_rma_customer_lines") result = action.read()[0] - rma_ids = self.mapped("invoice_line_ids.rma_line_ids").ids + rma_ids = self.mapped("line_ids.rma_line_ids").ids if rma_ids: # choose the view_mode accordingly if len(rma_ids) > 1: @@ -94,8 +91,8 @@ class AccountInvoice(models.Model): return result -class AccountInvoiceLine(models.Model): - _inherit = "account.invoice.line" +class AccountMoveLine(models.Model): + _inherit = "account.move.line" @api.model def name_search(self, name, args=None, operator="ilike", limit=100): @@ -104,7 +101,7 @@ class AccountInvoiceLine(models.Model): will make impossible to get the desired result.""" if not args: args = [] - lines = self.search([("invoice_id.number", operator, name)] + args, limit=limit) + lines = self.search([("move_id.name", operator, name)] + args, limit=limit) res = lines.name_get() if limit: limit_rest = limit - len(lines) @@ -113,50 +110,48 @@ class AccountInvoiceLine(models.Model): limit_rest = limit if limit_rest or not limit: args += [("id", "not in", lines.ids)] - res += super(AccountInvoiceLine, self).name_search( + res += super(AccountMoveLine, self).name_search( name, args=args, operator=operator, limit=limit_rest ) return res - @api.multi def name_get(self): res = [] if self.env.context.get("rma"): for inv in self: - if inv.invoice_id.reference: + if inv.move_id.ref: res.append( ( inv.id, "INV:%s | REF:%s | ORIG:%s | PART:%s | QTY:%s" % ( - inv.invoice_id.number or "", - inv.origin or "", - inv.invoice_id.reference or "", + inv.move_id.name or "", + inv.move_id.invoice_origin or "", + inv.move_id.ref or "", inv.product_id.name, inv.quantity, ), ) ) - elif inv.invoice_id.number: + elif inv.move_id.name: res.append( ( inv.id, "INV:%s | ORIG:%s | PART:%s | QTY:%s" % ( - inv.invoice_id.number or "", - inv.origin or "", + inv.move_id.name or "", + inv.move_id.invoice_origin or "", inv.product_id.name, inv.quantity, ), ) ) else: - res.append(super(AccountInvoiceLine, inv).name_get()[0]) + res.append(super(AccountMoveLine, inv).name_get()[0]) return res else: - return super(AccountInvoiceLine, self).name_get() + return super(AccountMoveLine, self).name_get() - @api.multi def _compute_rma_count(self): for invl in self: rma_lines = invl.mapped("rma_line_ids") @@ -165,7 +160,7 @@ class AccountInvoiceLine(models.Model): rma_line_count = fields.Integer(compute="_compute_rma_count", string="# of RMA") rma_line_ids = fields.One2many( comodel_name="rma.order.line", - inverse_name="invoice_line_id", + inverse_name="account_move_line_id", string="RMA", readonly=True, help="This will contain the RMA lines for the invoice line", diff --git a/rma_account/models/rma_order.py b/rma_account/models/rma_order.py index 5b323c41..15722a8f 100644 --- a/rma_account/models/rma_order.py +++ b/rma_account/models/rma_order.py @@ -7,20 +7,18 @@ from odoo import api, fields, models class RmaOrder(models.Model): _inherit = "rma.order" - @api.multi def _compute_invoice_refund_count(self): for rec in self: - invoices = rec.mapped("rma_line_ids.refund_line_ids.invoice_id") + invoices = rec.mapped("rma_line_ids.refund_line_ids.move_id") rec.invoice_refund_count = len(invoices) - @api.multi def _compute_invoice_count(self): for rec in self: - invoices = rec.mapped("rma_line_ids.invoice_id") + invoices = rec.mapped("rma_line_ids.move_id") rec.invoice_count = len(invoices) - add_invoice_id = fields.Many2one( - comodel_name="account.invoice", + add_move_id = fields.Many2one( + comodel_name="account.move", string="Add Invoice", ondelete="set null", readonly=True, @@ -44,30 +42,30 @@ class RmaOrder(models.Model): or self.rma_line_ids.product_id.categ_id.rma_supplier_operation_id ) data = { - "invoice_line_id": line.id, + "account_move_line_id": line.id, "product_id": line.product_id.id, "name": line.name, - "origin": line.invoice_id.number, - "uom_id": line.uom_id.id, + "origin": line.move_id.name, + "uom_id": line.product_uom_id.id, "operation_id": operation, "product_qty": line.quantity, - "price_unit": line.invoice_id.currency_id.compute( + "price_unit": line.move_id.currency_id.compute( line.price_unit, line.currency_id, round=False ), "rma_id": self.id, } return data - @api.onchange("add_invoice_id") + @api.onchange("add_move_id") def on_change_invoice(self): - if not self.add_invoice_id: + if not self.add_move_id: return {} if not self.partner_id: - self.partner_id = self.add_invoice_id.partner_id.id + self.partner_id = self.add_move_id.partner_id.id new_lines = self.env["rma.order.line"] - for line in self.add_invoice_id.invoice_line_ids: + for line in self.add_move_id.line_ids: # Load a PO line only once - if line in self.rma_line_ids.mapped("invoice_line_id"): + if line in self.rma_line_ids.mapped("account_move_line_id"): continue data = self._prepare_rma_line_from_inv_line(line) new_line = new_lines.new(data) @@ -75,9 +73,9 @@ class RmaOrder(models.Model): self.rma_line_ids += new_lines self.date_rma = fields.Datetime.now() - self.delivery_address_id = self.add_invoice_id.partner_id.id - self.invoice_address_id = self.add_invoice_id.partner_id.id - self.add_invoice_id = False + self.delivery_address_id = self.add_move_id.partner_id.id + self.invoice_address_id = self.add_move_id.partner_id.id + self.add_move_id = False return {} @api.model @@ -92,36 +90,34 @@ class RmaOrder(models.Model): res["invoice_address_id"] = partner.id return res - @api.multi def action_view_invoice_refund(self): action = self.env.ref("account.action_invoice_tree2") result = action.read()[0] - invoice_ids = self.mapped("rma_line_ids.refund_line_ids.invoice_id").ids - if invoice_ids: + move_ids = self.mapped("rma_line_ids.refund_line_ids.move_id").ids + if move_ids: # choose the view_mode accordingly - if len(invoice_ids) > 1: - result["domain"] = [("id", "in", invoice_ids)] + if len(move_ids) > 1: + result["domain"] = [("id", "in", move_ids)] else: - res = self.env.ref("account.invoice_supplier_form", False) + res = self.env.ref("account.move_supplier_form", False) result["views"] = [(res and res.id or False, "form")] - result["res_id"] = invoice_ids[0] + result["res_id"] = move_ids[0] return result - @api.multi def action_view_invoice(self): if self.type == "supplier": action = self.env.ref("account.action_invoice_tree2") - res = self.env.ref("account.invoice_supplier_form", False) + res = self.env.ref("account.move_supplier_form", False) else: action = self.env.ref("account.action_invoice_tree") - res = self.env.ref("account.invoice_form", False) + res = self.env.ref("account.view_move_form", False) result = action.read()[0] - invoice_ids = self.mapped("rma_line_ids.invoice_id").ids - if invoice_ids: + move_ids = self.mapped("rma_line_ids.move_id").ids + if move_ids: # choose the view_mode accordingly - if len(invoice_ids) > 1: - result["domain"] = [("id", "in", invoice_ids)] + if len(move_ids) > 1: + result["domain"] = [("id", "in", move_ids)] else: result["views"] = [(res and res.id or False, "form")] - result["res_id"] = invoice_ids[0] + result["res_id"] = move_ids[0] return result diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index fae7ff27..d49e879e 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -17,21 +17,20 @@ class RmaOrderLine(models.Model): return self.env["res.partner"].browse(partner_id) return self.env["res.partner"] - @api.multi @api.depends( - "refund_line_ids", "refund_line_ids.invoice_id.state", "refund_policy", "type" + "refund_line_ids", "refund_line_ids.move_id.state", "refund_policy", "type" ) def _compute_qty_refunded(self): for rec in self: rec.qty_refunded = sum( rec.refund_line_ids.filtered( - lambda i: i.invoice_id.state in ("open", "paid") + lambda i: i.move_id.state in ("open", "paid") ).mapped("quantity") ) @api.depends( "refund_line_ids", - "refund_line_ids.invoice_id.state", + "refund_line_ids.move_id.state", "refund_policy", "move_ids", "move_ids.state", @@ -48,10 +47,9 @@ class RmaOrderLine(models.Model): qty = res.qty_delivered - res.qty_refunded res.qty_to_refund = qty - @api.multi def _compute_refund_count(self): for rec in self: - rec.refund_count = len(rec.refund_line_ids.mapped("invoice_id")) + rec.refund_count = len(rec.refund_line_ids.mapped("move_id")) invoice_address_id = fields.Many2one( "res.partner", @@ -64,8 +62,8 @@ class RmaOrderLine(models.Model): refund_count = fields.Integer( compute="_compute_refund_count", string="# of Refunds", default=0 ) - invoice_line_id = fields.Many2one( - comodel_name="account.invoice.line", + account_move_line_id = fields.Many2one( + comodel_name="account.move.line", string="Originating Invoice Line", ondelete="restrict", index=True, @@ -73,17 +71,17 @@ class RmaOrderLine(models.Model): states={"draft": [("readonly", False)]}, ) refund_line_ids = fields.One2many( - comodel_name="account.invoice.line", + comodel_name="account.move.line", inverse_name="rma_line_id", string="Refund Lines", copy=False, index=True, readonly=True, ) - invoice_id = fields.Many2one( - "account.invoice", + move_id = fields.Many2one( + "account.move", string="Source", - related="invoice_line_id.invoice_id", + related="account_move_line_id.move_id", index=True, readonly=True, ) @@ -125,15 +123,14 @@ class RmaOrderLine(models.Model): res["domain"] = {} domain = [ "|", - ("invoice_id.partner_id", "=", self.partner_id.id), - ("invoice_id.partner_id", "child_of", self.partner_id.id), + ("move_id.partner_id", "=", self.partner_id.id), + ("move_id.partner_id", "child_of", self.partner_id.id), ] if self.product_id: domain.append(("product_id", "=", self.product_id.id)) - res["domain"]["invoice_line_id"] = domain + res["domain"]["account_move_line_id"] = domain return res - @api.multi def _prepare_rma_line_from_inv_line(self, line): self.ensure_one() if not self.type: @@ -173,15 +170,15 @@ class RmaOrderLine(models.Model): ) data = { "product_id": line.product_id.id, - "origin": line.invoice_id.number, - "uom_id": line.uom_id.id, + "origin": line.move_id.name, + "uom_id": line.product_uom_id.id, "operation_id": operation.id, "product_qty": line.quantity, - "price_unit": line.invoice_id.currency_id.compute( + "price_unit": line.move_id.currency_id.compute( line.price_unit, line.currency_id, round=False ), - "delivery_address_id": line.invoice_id.partner_id.id, - "invoice_address_id": line.invoice_id.partner_id.id, + "delivery_address_id": line.move_id.partner_id.id, + "invoice_address_id": line.move_id.partner_id.id, "receipt_policy": operation.receipt_policy, "refund_policy": operation.refund_policy, "delivery_policy": operation.delivery_policy, @@ -198,21 +195,20 @@ class RmaOrderLine(models.Model): } return data - @api.onchange("invoice_line_id") - def _onchange_invoice_line_id(self): - if not self.invoice_line_id: + @api.onchange("account_move_line_id") + def _onchange_account_move_line_id(self): + if not self.account_move_line_id: return - data = self._prepare_rma_line_from_inv_line(self.invoice_line_id) + data = self._prepare_rma_line_from_inv_line(self.account_move_line_id) self.update(data) - self._remove_other_data_origin("invoice_line_id") + self._remove_other_data_origin("account_move_line_id") - @api.multi - @api.constrains("invoice_line_id", "partner_id") + @api.constrains("account_move_line_id", "partner_id") def _check_invoice_partner(self): for rec in self: if ( - rec.invoice_line_id - and rec.invoice_line_id.invoice_id.partner_id != rec.partner_id + rec.account_move_line_id + and rec.account_move_line_id.move_id.partner_id != rec.partner_id ): raise ValidationError( _( @@ -221,11 +217,10 @@ class RmaOrderLine(models.Model): ) ) - @api.multi def _remove_other_data_origin(self, exception): res = super(RmaOrderLine, self)._remove_other_data_origin(exception) - if not exception == "invoice_line_id": - self.invoice_line_id = False + if not exception == "account_move_line_id": + self.account_move_line_id = False return res @api.onchange("operation_id") @@ -235,49 +230,45 @@ class RmaOrderLine(models.Model): self.refund_policy = self.operation_id.refund_policy or "no" return result - @api.multi - @api.constrains("invoice_line_id") + @api.constrains("account_move_line_id") def _check_duplicated_lines(self): for line in self: - matching_inv_lines = self.env["account.invoice.line"].search( - [("id", "=", line.invoice_line_id.id)] + matching_inv_lines = self.env["account.move.line"].search( + [("id", "=", line.account_move_line_id.id)] ) if len(matching_inv_lines) > 1: raise UserError( _( "There's an rma for the invoice line %s " "and invoice %s" - % (line.invoice_line_id, line.invoice_line_id.invoice_id) + % (line.account_move_line_id, line.account_move_line_id.move_id) ) ) return {} - @api.multi def action_view_invoice(self): action = self.env.ref("account.action_invoice_tree") result = action.read()[0] - res = self.env.ref("account.invoice_form", False) + res = self.env.ref("account.view_move_form", False) result["views"] = [(res and res.id or False, "form")] result["view_id"] = res and res.id or False - result["res_id"] = self.invoice_line_id.invoice_id.id + result["res_id"] = self.account_move_line_id.move_id.id return result - @api.multi def action_view_refunds(self): action = self.env.ref("account.action_invoice_tree2") result = action.read()[0] - invoice_ids = self.mapped("refund_line_ids.invoice_id").ids - if invoice_ids: + move_ids = self.mapped("refund_line_ids.move_id").ids + if move_ids: # choose the view_mode accordingly - if len(invoice_ids) > 1: - result["domain"] = [("id", "in", invoice_ids)] + if len(move_ids) > 1: + result["domain"] = [("id", "in", move_ids)] else: - res = self.env.ref("account.invoice_supplier_form", False) + res = self.env.ref("account.move_supplier_form", False) result["views"] = [(res and res.id or False, "form")] - result["res_id"] = invoice_ids[0] + result["res_id"] = move_ids[0] return result - @api.multi def name_get(self): res = [] if self.env.context.get("rma"): diff --git a/rma_account/security/ir.model.access.csv b/rma_account/security/ir.model.access.csv index b6fa0d93..74b1c356 100755 --- a/rma_account/security/ir.model.access.csv +++ b/rma_account/security/ir.model.access.csv @@ -1,3 +1,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_account_invoice_customer_user,access_account_invoice,account.model_account_invoice,rma.group_rma_customer_user,1,0,0,0 -access_account_invoice_supplier_user,access_account_invoice,account.model_account_invoice,rma.group_rma_supplier_user,1,0,0,0 +access_account_move_customer_user,access_account_move,account.model_account_move,rma.group_rma_customer_user,1,0,0,0 +access_account_move_supplier_user,access_account_move,account.model_account_move,rma.group_rma_supplier_user,1,0,0,0 +access_account_move_line_customer_user,access_account_move_line,account.model_account_move_line,rma.group_rma_customer_user,1,0,0,0 +access_account_move_line_supplier_user,access_account_move_line,account.model_account_move_line,rma.group_rma_supplier_user,1,0,0,0 diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py index 62678698..32243011 100644 --- a/rma_account/tests/test_rma_account.py +++ b/rma_account/tests/test_rma_account.py @@ -15,8 +15,8 @@ class TestRmaAccount(common.SingleTransactionCase): cls.rma_add_invoice_wiz = cls.env["rma_add_invoice"] cls.rma_refund_wiz = cls.env["rma.refund"] cls.acc_obj = cls.env["account.account"] - cls.inv_obj = cls.env["account.invoice"] - cls.invl_obj = cls.env["account.invoice.line"] + cls.inv_obj = cls.env["account.move"] + cls.invl_obj = cls.env["account.move.line"] cls.product_obj = cls.env["product.product"] cls.partner_obj = cls.env["res.partner"] @@ -89,7 +89,7 @@ class TestRmaAccount(common.SingleTransactionCase): "product_id": cls.product_1.id, "quantity": 12.0, "price_unit": 100.0, - "invoice_id": cls.inv_customer.id, + "move_id": cls.inv_customer.id, "uom_id": cls.product_1.uom_id.id, "account_id": customer_account, } @@ -100,7 +100,7 @@ class TestRmaAccount(common.SingleTransactionCase): "product_id": cls.product_2.id, "quantity": 15.0, "price_unit": 150.0, - "invoice_id": cls.inv_customer.id, + "move_id": cls.inv_customer.id, "uom_id": cls.product_2.uom_id.id, "account_id": customer_account, } @@ -122,7 +122,7 @@ class TestRmaAccount(common.SingleTransactionCase): "product_id": cls.product_3.id, "quantity": 17.0, "price_unit": 250.0, - "invoice_id": cls.inv_supplier.id, + "move_id": cls.inv_supplier.id, "uom_id": cls.product_3.uom_id.id, "account_id": supplier_account, } @@ -133,7 +133,7 @@ class TestRmaAccount(common.SingleTransactionCase): "product_id": cls.product_4.id, "quantity": 9.0, "price_unit": 300.0, - "invoice_id": cls.inv_supplier.id, + "move_id": cls.inv_supplier.id, "uom_id": cls.product_4.uom_id.id, "account_id": supplier_account, } @@ -147,7 +147,7 @@ class TestRmaAccount(common.SingleTransactionCase): "active_ids": self.rma_group_customer.id, "active_model": "rma.order", } - ).create({"invoice_line_ids": [(6, 0, self.inv_customer.invoice_line_ids.ids)]}) + ).create({"line_ids": [(6, 0, self.inv_customer.line_ids.ids)]}) add_inv.add_lines() self.assertEqual(len(self.rma_group_customer.rma_line_ids), 2) for t in self.rma_group_supplier.rma_line_ids.mapped("type"): @@ -169,7 +169,7 @@ class TestRmaAccount(common.SingleTransactionCase): "active_ids": self.rma_group_supplier.id, "active_model": "rma.order", } - ).create({"invoice_line_ids": [(6, 0, self.inv_supplier.invoice_line_ids.ids)]}) + ).create({"line_ids": [(6, 0, self.inv_supplier.line_ids.ids)]}) add_inv.add_lines() self.assertEqual(len(self.rma_group_supplier.rma_line_ids), 2) for t in self.rma_group_supplier.rma_line_ids.mapped("type"): @@ -206,7 +206,7 @@ class TestRmaAccount(common.SingleTransactionCase): {"customer": True, "active_ids": rma.ids, "active_model": "rma.order.line"} ).create({"description": "Test refund"}) make_refund.invoice_refund() - rma.refund_line_ids.invoice_id.action_invoice_open() + rma.refund_line_ids.move_id.action_invoice_open() rma._compute_refund_count() self.assertEqual(rma.refund_count, 1) self.assertEqual(rma.qty_to_refund, 0.0) @@ -217,10 +217,10 @@ class TestRmaAccount(common.SingleTransactionCase): rma = self.rma_line_obj.new( { "partner_id": self.inv_customer.partner_id.id, - "invoice_line_id": self.inv_line_1.id, + "account_move_line_id": self.inv_line_1.id, } ) self.assertFalse(rma.product_id) - rma._onchange_invoice_line_id() + rma._onchange_account_move_line_id() self.assertEqual(rma.product_id, self.product_1) self.assertEqual(rma.product_qty, 12.0) diff --git a/rma_account/views/account_move_view.xml b/rma_account/views/account_move_view.xml new file mode 100644 index 00000000..8c927540 --- /dev/null +++ b/rma_account/views/account_move_view.xml @@ -0,0 +1,69 @@ + + + + account.move.form + account.move + + + +
+ +
+
+
+
+ + + + rma.invoice.line.form + account.move.line + + + + + + + + + + + + + + + + + + + + account.move.customer.rma + account.move + + + + + + + + + + Invoice Line + account.move.line + form + + +
diff --git a/rma_account/views/invoice_view.xml b/rma_account/views/invoice_view.xml deleted file mode 100644 index e1f19fdc..00000000 --- a/rma_account/views/invoice_view.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - account.invoice.form - account.invoice - - - -
- -
-
-
-
- - - account.invoice.supplier.form - account.invoice - - - -
- -
-
-
-
- - - rma.invoice.line.form - account.invoice.line - - - - - - - - - - - - - - - - - - - account.invoice.supplier.rma - account.invoice - - - - - - - - - - account.invoice.customer.rma - account.invoice - - - - - - - - - - Invoice Line - account.invoice.line - form - form - - -
diff --git a/rma_account/views/rma_account_menu.xml b/rma_account/views/rma_account_menu.xml index ea117122..6f552638 100644 --- a/rma_account/views/rma_account_menu.xml +++ b/rma_account/views/rma_account_menu.xml @@ -8,7 +8,6 @@ rma.order.line [('type','=', 'customer')] {"search_default_to_refund":1} - form tree,form
@@ -17,11 +16,32 @@ rma.order.line [('type','=', 'supplier')] {"search_default_to_refund":1, "supplier":1} - form tree,form
+ + + + + + + + + - + ('move_id.partner_id', '=', partner_id), + ('move_id.partner_id', 'child_of', partner_id)]"/> @@ -49,6 +54,11 @@ - + ('move_id.partner_id', '=', partner_id), + ('move_id.partner_id', 'child_of', partner_id)]"/> diff --git a/rma_account/views/rma_order_view.xml b/rma_account/views/rma_order_view.xml index 270b1058..5c6b0e82 100644 --- a/rma_account/views/rma_order_view.xml +++ b/rma_account/views/rma_order_view.xml @@ -25,7 +25,7 @@ @@ -56,7 +56,7 @@ diff --git a/rma_account/wizards/__init__.py b/rma_account/wizards/__init__.py index ec155b09..52d1defb 100644 --- a/rma_account/wizards/__init__.py +++ b/rma_account/wizards/__init__.py @@ -2,5 +2,5 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from . import rma_refund -from . import rma_add_invoice +from . import rma_add_account_move from . import rma_order_line_make_supplier_rma diff --git a/rma_account/wizards/rma_add_invoice.py b/rma_account/wizards/rma_add_account_move.py similarity index 85% rename from rma_account/wizards/rma_add_invoice.py rename to rma_account/wizards/rma_add_account_move.py index b38e00b7..1bd518f5 100644 --- a/rma_account/wizards/rma_add_invoice.py +++ b/rma_account/wizards/rma_add_account_move.py @@ -5,8 +5,8 @@ from odoo import _, api, fields, models from odoo.exceptions import ValidationError -class RmaAddInvoice(models.TransientModel): - _name = "rma_add_invoice" +class RmaAddAccountMove(models.TransientModel): + _name = "rma_add_account_move" _description = "Wizard to add rma lines" @api.model @@ -21,7 +21,7 @@ class RmaAddInvoice(models.TransientModel): rma = rma_obj.browse(rma_id) res["rma_id"] = rma.id res["partner_id"] = rma.partner_id.id - res["invoice_line_ids"] = False + res["line_ids"] = False return res rma_id = fields.Many2one( @@ -30,11 +30,11 @@ class RmaAddInvoice(models.TransientModel): partner_id = fields.Many2one( comodel_name="res.partner", string="Partner", readonly=True ) - invoice_line_ids = fields.Many2many( - "account.invoice.line", - "rma_add_invoice_add_line_rel", - "invoice_line_id", - "rma_add_invoice_id", + line_ids = fields.Many2many( + "account.move.line", + "rma_add_account_move_add_line_rel", + "account_move_line_id", + "rma_add_move_id", string="Invoice Lines", ) @@ -76,17 +76,17 @@ class RmaAddInvoice(models.TransientModel): ) data = { "partner_id": self.partner_id.id, - "invoice_line_id": line.id, + "account_move_line_id": line.id, "product_id": line.product_id.id, - "origin": line.invoice_id.number, - "uom_id": line.uom_id.id, + "origin": line.move_id.name, + "uom_id": line.product_uom_id.id, "operation_id": operation.id, "product_qty": line.quantity, - "price_unit": line.invoice_id.currency_id.compute( + "price_unit": line.move_id.currency_id.compute( line.price_unit, line.currency_id, round=False ), - "delivery_address_id": line.invoice_id.partner_id.id, - "invoice_address_id": line.invoice_id.partner_id.id, + "delivery_address_id": line.move_id.partner_id.id, + "invoice_address_id": line.move_id.partner_id.id, "rma_id": self.rma_id.id, "receipt_policy": operation.receipt_policy, "refund_policy": operation.refund_policy, @@ -112,14 +112,13 @@ class RmaAddInvoice(models.TransientModel): def _get_existing_invoice_lines(self): existing_invoice_lines = [] for rma_line in self.rma_id.rma_line_ids: - existing_invoice_lines.append(rma_line.invoice_line_id) + existing_invoice_lines.append(rma_line.account_move_line_id) return existing_invoice_lines - @api.multi def add_lines(self): rma_line_obj = self.env["rma.order.line"] existing_invoice_lines = self._get_existing_invoice_lines() - for line in self.invoice_line_ids: + for line in self.line_ids: # Load a PO line only once if line not in existing_invoice_lines: data = self._prepare_rma_line_from_inv_line(line) diff --git a/rma_account/wizards/rma_add_invoice.xml b/rma_account/wizards/rma_add_account_move.xml similarity index 71% rename from rma_account/wizards/rma_add_invoice.xml rename to rma_account/wizards/rma_add_account_move.xml index 29e3fda9..4e4efea7 100644 --- a/rma_account/wizards/rma_add_invoice.xml +++ b/rma_account/wizards/rma_add_account_move.xml @@ -2,9 +2,9 @@ - + rma.add.invoice - rma_add_invoice + rma_add_account_move
@@ -13,15 +13,16 @@ string="Customer"/> - + - + - + + @@ -41,9 +42,9 @@ - + rma.add.invoice.supplier - rma_add_invoice + rma_add_account_move @@ -52,15 +53,16 @@ string="Supplier"/> - + - + - + + @@ -80,50 +82,47 @@ - + Add Invoice ir.actions.act_window - rma_add_invoice - rma.order - form + rma_add_account_move form new - + - + Add Invoice ir.actions.act_window - rma_add_invoice - rma.order - form + rma_add_account_move + form new - + - + rma.order.form - invoice wizard rma.order - @@ -23,17 +32,18 @@ rma.invoice.line.form account.move.line - - + + - - - + + + - + @@ -45,17 +55,20 @@ account.move.customer.rma account.move - + - + ('type', '=', 'in_invoice')]}" + class="oe_edit_only" + options="{'no_create': True}" + /> @@ -64,6 +77,6 @@ Invoice Line account.move.line form - + diff --git a/rma_account/views/rma_account_menu.xml b/rma_account/views/rma_account_menu.xml index 6f552638..b5cb1ef3 100644 --- a/rma_account/views/rma_account_menu.xml +++ b/rma_account/views/rma_account_menu.xml @@ -1,9 +1,12 @@ - + - + Customer RMA rma.order.line [('type','=', 'customer')] @@ -15,45 +18,57 @@ Supplier RMA rma.order.line [('type','=', 'supplier')] - {"search_default_to_refund":1, "supplier":1} + {"search_default_to_refund":1, "supplier":1} tree,form - + - + parent="rma.menu_rma_root" + /> - + action="action_rma_account_customer_lines" + /> - + action="action_rma_supplier_lines" + /> - + action="action_rma_account_customer_lines" + /> - + action="action_rma_supplier_lines" + /> diff --git a/rma_account/views/rma_operation_view.xml b/rma_account/views/rma_operation_view.xml index 6f9c4062..58695947 100644 --- a/rma_account/views/rma_operation_view.xml +++ b/rma_account/views/rma_operation_view.xml @@ -1,12 +1,12 @@ - + rma.operation.tree rma.operation - + - + @@ -14,10 +14,10 @@ rma.operation.form rma.operation - + - + diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index 7accc439..47fa18ef 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -1,48 +1,61 @@ - + rma.order.line.supplier.form rma.order.line - + - - + ('move_id.partner_id', 'child_of', partner_id)]" + /> - + - + - + - - + + @@ -51,46 +64,59 @@ rma.order.line.form rma.order.line - + - - + ('move_id.partner_id', 'child_of', partner_id)]" + /> - + - + - + - - + + @@ -99,11 +125,15 @@ rma.order.line.select rma.order.line - + - + diff --git a/rma_account/views/rma_order_view.xml b/rma_account/views/rma_order_view.xml index 5c6b0e82..4378e3eb 100644 --- a/rma_account/views/rma_order_view.xml +++ b/rma_account/views/rma_order_view.xml @@ -1,25 +1,36 @@ - + rma.order.form - rma_account rma.order - + - - - + Customer RMA rma.order.line [('type','=', 'customer')] @@ -18,9 +15,7 @@ Supplier RMA rma.order.line [('type','=', 'supplier')] - {"search_default_to_refund":1, "supplier":1} + {"search_default_to_refund":1, "supplier":1} tree,form diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index 47fa18ef..c6671dcf 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -21,11 +21,7 @@ icon="fa-pencil-square-o" groups="account.group_account_user" > - + @@ -82,11 +78,7 @@ icon="fa-pencil-square-o" groups="account.group_account_user" > - + diff --git a/rma_account/views/rma_order_view.xml b/rma_account/views/rma_order_view.xml index 4378e3eb..bd969d5c 100644 --- a/rma_account/views/rma_order_view.xml +++ b/rma_account/views/rma_order_view.xml @@ -26,11 +26,7 @@ icon="fa-pencil-square-o" groups="account.group_account_user" > - + From dfbcf12ff02c9b91aaaca71946487b9f8a6c5b92 Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Wed, 8 Jun 2022 15:55:52 +0200 Subject: [PATCH 76/93] Hide smart button when empty --- rma_account/views/rma_order_line_view.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index dd74d94f..e701fea0 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -30,6 +30,7 @@ name="action_view_invoice" class="oe_stat_button" icon="fa-pencil-square-o" + attrs="{'invisible': [('account_move_line_id', '=', False)]}" string="Origin Inv" > @@ -38,6 +39,7 @@ name="action_view_refunds" class="oe_stat_button" icon="fa-pencil-square-o" + attrs="{'invisible': [('refund_count', '=', 0)]}" groups="account.group_account_invoice" > From fdab153f1e97bd2d3a2e9e820551c27e9424c650 Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Fri, 1 Jul 2022 13:53:14 +0200 Subject: [PATCH 77/93] [IMP] Make rma order view cleaner for user Hide button and fields depending on the policy chosen on the rma line --- rma_account/views/rma_order_line_view.xml | 11 +++++++++-- rma_account/wizards/rma_refund.xml | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/rma_account/views/rma_order_line_view.xml b/rma_account/views/rma_order_line_view.xml index e701fea0..cb38a14b 100644 --- a/rma_account/views/rma_order_line_view.xml +++ b/rma_account/views/rma_order_line_view.xml @@ -60,7 +60,11 @@ - + @@ -71,7 +75,10 @@ /> - + diff --git a/rma_account/wizards/rma_refund.xml b/rma_account/wizards/rma_refund.xml index 848bddfc..da9cc4d2 100644 --- a/rma_account/wizards/rma_refund.xml +++ b/rma_account/wizards/rma_refund.xml @@ -59,13 +59,13 @@ name="%(action_rma_refund)d" string="Create Refund" class="oe_highlight" - attrs="{'invisible':['|', ('qty_to_refund', '=', 0), ('state', '!=', 'approved')]}" + attrs="{'invisible':['|', '|', ('qty_to_refund', '=', 0), ('state', '!=', 'approved'), ('refund_policy', '=', 'no')]}" type="action" /> - - + + + @@ -55,10 +50,10 @@ From 3448c2f39c93b567d200b3a14c2c635dece7d12e Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Mon, 21 Nov 2022 15:13:06 +0100 Subject: [PATCH 81/93] [FIX] include anglo-saxon price unit calculation in refunds. Otherwise the anglo saxon entries won't be correct. For example, the Interim (Delivered) account should balance after receiving and triggering a refund on a customer rma. --- rma_account/models/__init__.py | 1 + rma_account/models/account_move.py | 45 +++++++ rma_account/models/rma_order_line.py | 26 ++++ rma_account/models/stock_valuation_layer.py | 16 +++ .../test_account_move_line_rma_order_line.py | 4 +- rma_account/tests/test_rma_stock_account.py | 127 ++++++++++++++++-- 6 files changed, 207 insertions(+), 12 deletions(-) create mode 100644 rma_account/models/stock_valuation_layer.py diff --git a/rma_account/models/__init__.py b/rma_account/models/__init__.py index b1fb9d25..0d8b8255 100644 --- a/rma_account/models/__init__.py +++ b/rma_account/models/__init__.py @@ -5,3 +5,4 @@ from . import account_move from . import account_move_line from . import procurement from . import stock_move +from . import stock_valuation_layer diff --git a/rma_account/models/account_move.py b/rma_account/models/account_move.py index 602bba60..e28f89a3 100644 --- a/rma_account/models/account_move.py +++ b/rma_account/models/account_move.py @@ -121,6 +121,19 @@ class AccountMove(models.Model): line.update({"rma_line_id": find_with_label_rma.id}) return res + def _stock_account_get_last_step_stock_moves(self): + rslt = super(AccountMove, self)._stock_account_get_last_step_stock_moves() + for invoice in self.filtered(lambda x: x.move_type == "out_invoice"): + rslt += invoice.mapped("line_ids.rma_line_id.move_ids").filtered( + lambda x: x.state == "done" and x.location_dest_id.usage == "customer" + ) + for invoice in self.filtered(lambda x: x.move_type == "out_refund"): + # Add refunds generated from the RMA + rslt += invoice.mapped("line_ids.rma_line_id.move_ids").filtered( + lambda x: x.state == "done" and x.location_id.usage == "customer" + ) + return rslt + class AccountMoveLine(models.Model): _inherit = "account.move.line" @@ -203,3 +216,35 @@ class AccountMoveLine(models.Model): ondelete="set null", help="This will contain the rma line that originated this line", ) + + def _stock_account_get_anglo_saxon_price_unit(self): + self.ensure_one() + price_unit = super( + AccountMoveLine, self + )._stock_account_get_anglo_saxon_price_unit() + rma_line = self.rma_line_id or self.env["rma.order.line"] + if rma_line: + is_line_reversing = bool(self.move_id.reversed_entry_id) + qty_to_refund = self.product_uom_id._compute_quantity( + self.quantity, self.product_id.uom_id + ) + posted_invoice_lines = rma_line.move_line_ids.filtered( + lambda l: l.move_id.move_type == "out_refund" + and l.move_id.state == "posted" + and bool(l.move_id.reversed_entry_id) == is_line_reversing + ) + qty_refunded = sum( + x.product_uom_id._compute_quantity(x.quantity, x.product_id.uom_id) + for x in posted_invoice_lines + ) + product = self.product_id.with_company(self.company_id).with_context( + is_returned=is_line_reversing + ) + average_price_unit = product._compute_average_price( + qty_refunded, qty_to_refund, rma_line._get_in_moves() + ) + if average_price_unit: + price_unit = self.product_id.uom_id.with_company( + self.company_id + )._compute_price(average_price_unit, self.product_uom_id) + return price_unit diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 09a5e326..ece41b2e 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -307,3 +307,29 @@ class RmaOrderLine(models.Model): return res else: return super(RmaOrderLine, self).name_get() + + def _stock_account_anglo_saxon_reconcile_valuation(self): + for rma in self: + prod = rma.product_id + if rma.product_id.valuation != "real_time": + continue + if not rma.company_id.anglo_saxon_accounting: + continue + product_accounts = prod.product_tmpl_id._get_product_accounts() + if rma.type == "customer": + product_interim_account = product_accounts["stock_output"] + else: + product_interim_account = product_accounts["stock_input"] + if product_interim_account.reconcile: + # Get the in and out moves + amls = rma.move_ids.mapped( + "stock_valuation_layer_ids.account_move_id.line_ids" + ) + # Search for anglo-saxon lines linked to the product in the journal entry. + amls = amls.filtered( + lambda line: line.product_id == prod + and line.account_id == product_interim_account + and not line.reconciled + ) + # Reconcile. + amls.reconcile() diff --git a/rma_account/models/stock_valuation_layer.py b/rma_account/models/stock_valuation_layer.py new file mode 100644 index 00000000..4495744c --- /dev/null +++ b/rma_account/models/stock_valuation_layer.py @@ -0,0 +1,16 @@ +# Copyright 2017-22 ForgeFlow S.L. (www.forgeflow.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class StockValuationLayer(models.Model): + _inherit = "stock.valuation.layer" + + def _validate_accounting_entries(self): + res = super(StockValuationLayer, self)._validate_accounting_entries() + for svl in self: + # Eventually reconcile together the stock interim accounts + if svl.company_id.anglo_saxon_accounting: + svl.stock_move_id.rma_line_id._stock_account_anglo_saxon_reconcile_valuation() + return res diff --git a/rma_account/tests/test_account_move_line_rma_order_line.py b/rma_account/tests/test_account_move_line_rma_order_line.py index 0303727e..4f671931 100644 --- a/rma_account/tests/test_account_move_line_rma_order_line.py +++ b/rma_account/tests/test_account_move_line_rma_order_line.py @@ -42,8 +42,8 @@ class TestAccountMoveLineRmaOrderLine(common.TransactionCase): # Create account for Cost of Goods Sold acc_type = cls._create_account_type("expense", "other", "expense") - name = "Cost of Goods Sold" - code = "cogs" + name = "Goods Delivered Not Invoiced" + code = "gdni" cls.account_cogs = cls._create_account(acc_type, name, code, cls.company) # Create account for Inventory acc_type = cls._create_account_type("asset", "other", "asset") diff --git a/rma_account/tests/test_rma_stock_account.py b/rma_account/tests/test_rma_stock_account.py index ee663988..a0ce458b 100644 --- a/rma_account/tests/test_rma_stock_account.py +++ b/rma_account/tests/test_rma_stock_account.py @@ -14,11 +14,16 @@ class TestRmaStockAccount(TestRma): cls.acc_type_model = cls.env["account.account.type"] cls.account_model = cls.env["account.account"] cls.g_account_user = cls.env.ref("account.group_account_user") + cls.rma_refund_wiz = cls.env["rma.refund"] # we create new products to ensure previous layers do not affect when # running FIFO cls.product_fifo_1 = cls._create_product("product_fifo1") cls.product_fifo_2 = cls._create_product("product_fifo2") cls.product_fifo_3 = cls._create_product("product_fifo3") + # Refs + cls.rma_operation_customer_refund_id = cls.env.ref( + "rma_account.rma_operation_customer_refund" + ) cls.rma_basic_user.write({"groups_id": [(4, cls.g_account_user.id)]}) # The product category created in the base module is not automated valuation # we have to create a new category here @@ -27,11 +32,11 @@ class TestRmaStockAccount(TestRma): name = "Goods Received Not Invoiced" code = "grni" cls.account_grni = cls._create_account(acc_type, name, code, cls.company, True) - # Create account for Cost of Goods Sold - acc_type = cls._create_account_type("expense", "other") - name = "Cost of Goods Sold" - code = "cogs" - cls.account_cogs = cls._create_account(acc_type, name, code, cls.company, False) + # Create account for Goods Delievered + acc_type = cls._create_account_type("asset", "other") + name = "Goods Delivered Not Invoiced" + code = "gdni" + cls.account_gdni = cls._create_account(acc_type, name, code, cls.company, True) # Create account for Inventory acc_type = cls._create_account_type("asset", "other") name = "Inventory" @@ -45,9 +50,9 @@ class TestRmaStockAccount(TestRma): "property_stock_valuation_account_id": cls.account_inventory.id, "property_valuation": "real_time", "property_stock_account_input_categ_id": cls.account_grni.id, - "property_stock_account_output_categ_id": cls.account_cogs.id, + "property_stock_account_output_categ_id": cls.account_gdni.id, "rma_approval_policy": "one_step", - "rma_customer_operation_id": cls.rma_cust_replace_op_id.id, + "rma_customer_operation_id": cls.rma_operation_customer_refund_id.id, "rma_supplier_operation_id": cls.rma_sup_replace_op_id.id, "property_cost_method": "fifo", } @@ -103,7 +108,7 @@ class TestRmaStockAccount(TestRma): self.assertEqual(picking.move_lines.stock_valuation_layer_ids.value, 15.0) account_move = picking.move_lines.stock_valuation_layer_ids.account_move_id self.check_accounts_used( - account_move, debit_account="inventory", credit_account="cogs" + account_move, debit_account="inventory", credit_account="gdni" ) def test_02_cost_from_move(self): @@ -130,8 +135,9 @@ class TestRmaStockAccount(TestRma): dropship=False, ) # Set an incorrect price in the RMA (this should not affect cost) - rma_customer_id.rma_line_ids.price_unit = 999 - rma_customer_id.rma_line_ids.action_rma_to_approve() + rma_lines = rma_customer_id.rma_line_ids + rma_lines.price_unit = 999 + rma_lines.action_rma_to_approve() picking = self._receive_rma(rma_customer_id.rma_line_ids) # Test the value in the layers of the incoming stock move is used for rma_line in rma_customer_id.rma_line_ids: @@ -141,3 +147,104 @@ class TestRmaStockAccount(TestRma): ) value_used = move_product.stock_valuation_layer_ids.value self.assertEqual(value_used, -value_origin) + # Create a refund for the first line + rma = rma_lines[0] + make_refund = self.rma_refund_wiz.with_context( + **{ + "customer": True, + "active_ids": rma.ids, + "active_model": "rma.order.line", + } + ).create({"description": "Test refund"}) + make_refund.item_ids.qty_to_refund = 1 + make_refund.invoice_refund() + rma.refund_line_ids.move_id.action_post() + rma._compute_refund_count() + gdni_amls = rma.refund_line_ids.move_id.line_ids.filtered( + lambda l: l.account_id == self.account_gdni + ) + gdni_amls |= ( + rma.move_ids.stock_valuation_layer_ids.account_move_id.line_ids.filtered( + lambda l: l.account_id == self.account_gdni + ) + ) + gdni_balance = sum(gdni_amls.mapped("balance")) + # When we received we Credited to GDNI 30 + # When we refund we Debit to GDNI 10 + self.assertEqual(gdni_balance, -20.0) + make_refund = self.rma_refund_wizwith_context( + **{ + "customer": True, + "active_ids": rma.ids, + "active_model": "rma.order.line", + } + ).create({"description": "Test refund"}) + make_refund.item_ids.qty_to_refund = 2 + make_refund.invoice_refund() + rma.refund_line_ids.move_id.filtered( + lambda m: m.state != "posted" + ).action_post() + rma._compute_refund_count() + gdni_amls = rma.refund_line_ids.move_id.line_ids.filtered( + lambda l: l.account_id == self.account_gdni + ) + gdni_amls |= ( + rma.move_ids.stock_valuation_layer_ids.account_move_id.line_ids.filtered( + lambda l: l.account_id == self.account_gdni + ) + ) + gdni_balance = sum(gdni_amls.mapped("balance")) + # When we received we Credited to GDNI 30 + # When we refund we Debit to GDNI 30 + self.assertEqual(gdni_balance, 0.0) + # Ensure that the GDNI move lines are all reconciled + self.assertEqual(all(gdni_amls.mapped("reconciled")), True) + + def test_03_cost_from_move(self): + """ + Receive a product and then return it. The Goods Delivered Not Invoiced + should result in 0 + """ + # Set a standard price on the products + self.product_fifo_1.standard_price = 10 + self._create_inventory( + self.product_fifo_1, 20.0, self.env.ref("stock.stock_location_customers") + ) + products2move = [ + (self.product_fifo_1, 3), + ] + self.product_fifo_1.categ_id.rma_customer_operation_id = ( + self.rma_cust_replace_op_id + ) + rma_customer_id = self._create_rma_from_move( + products2move, + "customer", + self.env.ref("base.res_partner_2"), + dropship=False, + ) + # Set an incorrect price in the RMA (this should not affect cost) + rma = rma_customer_id.rma_line_ids + rma.price_unit = 999 + rma.action_rma_to_approve() + self._receive_rma(rma_customer_id.rma_line_ids) + gdni_amls = ( + rma.move_ids.stock_valuation_layer_ids.account_move_id.line_ids.filtered( + lambda l: l.account_id == self.account_gdni + ) + ) + gdni_balance = sum(gdni_amls.mapped("balance")) + self.assertEqual(len(gdni_amls), 1) + # Balance should be -30, as we have only received + self.assertEqual(gdni_balance, -30.0) + self._deliver_rma(rma_customer_id.rma_line_ids) + gdni_amls = ( + rma.move_ids.stock_valuation_layer_ids.account_move_id.line_ids.filtered( + lambda l: l.account_id == self.account_gdni + ) + ) + gdni_balance = sum(gdni_amls.mapped("balance")) + self.assertEqual(len(gdni_amls), 2) + # Balance should be 0, as we have received and shipped + self.assertEqual(gdni_balance, 0.0) + # The GDNI entries should be now reconciled + self.assertEqual(all(gdni_amls.mapped("reconciled")), True) From 11183e48df7ea36c59f92fd55c3bf09787a8e574 Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Thu, 24 Nov 2022 18:59:36 +0100 Subject: [PATCH 82/93] fix pylint --- rma_account/tests/test_rma_stock_account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rma_account/tests/test_rma_stock_account.py b/rma_account/tests/test_rma_stock_account.py index a0ce458b..1e160fee 100644 --- a/rma_account/tests/test_rma_stock_account.py +++ b/rma_account/tests/test_rma_stock_account.py @@ -172,7 +172,7 @@ class TestRmaStockAccount(TestRma): # When we received we Credited to GDNI 30 # When we refund we Debit to GDNI 10 self.assertEqual(gdni_balance, -20.0) - make_refund = self.rma_refund_wizwith_context( + make_refund = self.rma_refund_wiz.with_context( **{ "customer": True, "active_ids": rma.ids, From 5e5a87d2b447f8765b14741b007c3ada55881ee9 Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Mon, 21 Nov 2022 15:13:06 +0100 Subject: [PATCH 83/93] [FIX] include anglo-saxon price unit calculation in refunds. Otherwise the anglo saxon entries won't be correct. For example, the Interim (Delivered) account should balance after receiving and triggering a refund on a customer rma. --- rma_account/models/account_move.py | 7 +++++++ rma_account/models/stock_move.py | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/rma_account/models/account_move.py b/rma_account/models/account_move.py index e28f89a3..361abdd8 100644 --- a/rma_account/models/account_move.py +++ b/rma_account/models/account_move.py @@ -234,8 +234,15 @@ class AccountMoveLine(models.Model): and bool(l.move_id.reversed_entry_id) == is_line_reversing ) qty_refunded = sum( +<<<<<<< HEAD x.product_uom_id._compute_quantity(x.quantity, x.product_id.uom_id) for x in posted_invoice_lines +======= + [ + x.product_uom_id._compute_quantity(x.quantity, x.product_id.uom_id) + for x in posted_invoice_lines + ] +>>>>>>> 614c98c ([FIX] include anglo-saxon price unit calculation in refunds.) ) product = self.product_id.with_company(self.company_id).with_context( is_returned=is_line_reversing diff --git a/rma_account/models/stock_move.py b/rma_account/models/stock_move.py index 610c97e4..1eb1ef02 100644 --- a/rma_account/models/stock_move.py +++ b/rma_account/models/stock_move.py @@ -20,4 +20,11 @@ class StockMove(models.Model): != self.product_id.categ_id.property_stock_valuation_account_id.id ): line[2]["rma_line_id"] = self.rma_line_id.id + + def _account_entry_move(self, qty, description, svl_id, cost): + res = super(StockMove, self)._account_entry_move(qty, description, svl_id, cost) + if self.company_id.anglo_saxon_accounting: + # Eventually reconcile together the invoice and valuation accounting + # entries on the stock interim accounts + self.rma_line_id._stock_account_anglo_saxon_reconcile_valuation() return res From 510f70e438a3e4320ff405841d2984bd9f749dd8 Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Wed, 23 Nov 2022 15:26:03 +0100 Subject: [PATCH 84/93] [IMP] centralize the logic to get the correct cost of the RMA. --- rma_account/__manifest__.py | 2 +- rma_account/models/account_move.py | 7 ------ rma_account/models/procurement.py | 34 ---------------------------- rma_account/models/rma_order_line.py | 16 +++++++++++++ rma_account/models/stock_move.py | 1 + 5 files changed, 18 insertions(+), 42 deletions(-) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index eb22180c..012c6945 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -3,7 +3,7 @@ { "name": "RMA Account", - "version": "15.0.1.1.0", + "version": "15.0.1.1.1", "license": "LGPL-3", "category": "RMA", "summary": "Integrates RMA with Invoice Processing", diff --git a/rma_account/models/account_move.py b/rma_account/models/account_move.py index 361abdd8..e28f89a3 100644 --- a/rma_account/models/account_move.py +++ b/rma_account/models/account_move.py @@ -234,15 +234,8 @@ class AccountMoveLine(models.Model): and bool(l.move_id.reversed_entry_id) == is_line_reversing ) qty_refunded = sum( -<<<<<<< HEAD x.product_uom_id._compute_quantity(x.quantity, x.product_id.uom_id) for x in posted_invoice_lines -======= - [ - x.product_uom_id._compute_quantity(x.quantity, x.product_id.uom_id) - for x in posted_invoice_lines - ] ->>>>>>> 614c98c ([FIX] include anglo-saxon price unit calculation in refunds.) ) product = self.product_id.with_company(self.company_id).with_context( is_returned=is_line_reversing diff --git a/rma_account/models/procurement.py b/rma_account/models/procurement.py index 7a3ae703..e065cfe9 100644 --- a/rma_account/models/procurement.py +++ b/rma_account/models/procurement.py @@ -4,40 +4,6 @@ from odoo import fields, models -class StockRule(models.Model): - _inherit = "stock.rule" - - def _get_stock_move_values( - self, - product_id, - product_qty, - product_uom, - location_id, - name, - origin, - company_id, - values, - ): - res = super(StockRule, self)._get_stock_move_values( - product_id, - product_qty, - product_uom, - location_id, - name, - origin, - company_id, - values, - ) - if "rma_line_id" in values: - line = values.get("rma_line_id") - line = self.env["rma.order.line"].browse([line]) - move = line.reference_move_id - if move and move.stock_valuation_layer_ids: - cost = move.stock_valuation_layer_ids[-1].unit_cost - res["price_unit"] = cost - return res - - class ProcurementGroup(models.Model): _inherit = "procurement.group" diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index ece41b2e..0231446d 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -333,3 +333,19 @@ class RmaOrderLine(models.Model): ) # Reconcile. amls.reconcile() + + def _get_price_unit(self): + self.ensure_one() + price_unit = super(RmaOrderLine, self)._get_price_unit() + if self.reference_move_id: + move = self.reference_move_id + layers = move.sudo().stock_valuation_layer_ids + if layers: + price_unit = sum(layers.mapped("value")) / sum( + layers.mapped("quantity") + ) + price_unit = price_unit + elif self.account_move_line_id and self.type == "supplier": + # We get the cost from the original invoice line + price_unit = self.account_move_line_id.price_unit + return price_unit diff --git a/rma_account/models/stock_move.py b/rma_account/models/stock_move.py index 1eb1ef02..c5872fa4 100644 --- a/rma_account/models/stock_move.py +++ b/rma_account/models/stock_move.py @@ -20,6 +20,7 @@ class StockMove(models.Model): != self.product_id.categ_id.property_stock_valuation_account_id.id ): line[2]["rma_line_id"] = self.rma_line_id.id + return res def _account_entry_move(self, qty, description, svl_id, cost): res = super(StockMove, self)._account_entry_move(qty, description, svl_id, cost) From abae7d2c953dcfdf79adc9730400e4e9a46eb456 Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Sun, 27 Nov 2022 18:49:59 +0100 Subject: [PATCH 85/93] [FIX] rma_account: try to auto-reconcile interim account --- rma_account/models/rma_order_line.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index 0231446d..f27e460e 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -322,7 +322,15 @@ class RmaOrderLine(models.Model): product_interim_account = product_accounts["stock_input"] if product_interim_account.reconcile: # Get the in and out moves - amls = rma.move_ids.mapped( + amls = self.env["account.move.line"].search( + [ + ("rma_line_id", "=", rma.id), + ("account_id", "=", product_interim_account.id), + ("parent_state", "=", "posted"), + ("reconciled", "=", False), + ] + ) + amls |= rma.move_ids.mapped( "stock_valuation_layer_ids.account_move_id.line_ids" ) # Search for anglo-saxon lines linked to the product in the journal entry. From 0e420cd9d5c68d0aebd912f63c94125ec932190b Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Tue, 29 Nov 2022 08:07:01 +0100 Subject: [PATCH 86/93] [IMP] calculate refund unit price --- rma_account/__manifest__.py | 2 +- rma_account/models/account_move.py | 50 ++++++++++++++++++------- rma_account/tests/test_rma_account.py | 46 +++++++++++++---------- rma_account/views/account_move_view.xml | 27 ++++++++++++- rma_account/wizards/rma_refund.py | 17 ++++++++- 5 files changed, 105 insertions(+), 37 deletions(-) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 012c6945..7c81beae 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -3,7 +3,7 @@ { "name": "RMA Account", - "version": "15.0.1.1.1", + "version": "15.0.1.2.0", "license": "LGPL-3", "category": "RMA", "summary": "Integrates RMA with Invoice Processing", diff --git a/rma_account/models/account_move.py b/rma_account/models/account_move.py index e28f89a3..4ce2146d 100644 --- a/rma_account/models/account_move.py +++ b/rma_account/models/account_move.py @@ -9,9 +9,15 @@ class AccountMove(models.Model): _inherit = "account.move" @api.depends("line_ids.rma_line_ids") - def _compute_rma_count(self): + def _compute_used_in_rma_count(self): for inv in self: rmas = self.mapped("line_ids.rma_line_ids") + inv.used_in_rma_count = len(rmas) + + @api.depends("line_ids.rma_line_id") + def _compute_rma_count(self): + for inv in self: + rmas = self.mapped("line_ids.rma_line_id") inv.rma_count = len(rmas) def _prepare_invoice_line_from_rma_line(self, rma_line): @@ -19,22 +25,26 @@ class AccountMove(models.Model): qty = rma_line.qty_to_refund if float_compare(qty, 0.0, precision_rounding=rma_line.uom_id.rounding) <= 0: qty = 0.0 - # Todo fill taxes from somewhere data = { "move_id": self.id, "product_uom_id": rma_line.uom_id.id, "product_id": rma_line.product_id.id, - "price_unit": rma_line.company_id.currency_id.with_context( - date=self.date - ).compute(rma_line.price_unit, self.currency_id, round=False), + "price_unit": rma_line.company_id.currency_id._convert( + rma_line._get_price_unit(), + self.currency_id, + self.company_id, + self.date, + round=False, + ), "quantity": qty, "discount": 0.0, - "rma_line_ids": [(4, rma_line.id)], + "rma_line_id": rma_line.id, "sequence": sequence + 1, } return data def _post_process_invoice_line_from_rma_line(self, new_line, rma_line): + new_line.rma_line_id = rma_line new_line.name = "%s: %s" % ( self.add_rma_line_id.name, new_line._get_computed_name(), @@ -58,17 +68,16 @@ class AccountMove(models.Model): self._post_process_invoice_line_from_rma_line( new_line, self.add_rma_line_id ) - line = new_line._convert_to_write( - {name: new_line[name] for name in new_line._cache} - ) # Compute invoice_origin. origins = set(self.line_ids.mapped("rma_line_id.name")) self.invoice_origin = ",".join(list(origins)) self.add_rma_line_id = False self._onchange_currency() - return line rma_count = fields.Integer(compute="_compute_rma_count", string="# of RMA") + used_in_rma_count = fields.Integer( + compute="_compute_used_in_rma_count", string="# of Used in RMA" + ) add_rma_line_id = fields.Many2one( comodel_name="rma.order.line", @@ -77,7 +86,15 @@ class AccountMove(models.Model): help="Create a refund in based on an existing rma_line", ) + def action_view_used_in_rma(self): + rmas = self.mapped("line_ids.rma_line_ids") + return self._prepare_action_view_rma(rmas) + def action_view_rma(self): + rmas = self.mapped("line_ids.rma_line_id") + return self._prepare_action_view_rma(rmas) + + def _prepare_action_view_rma(self, rmas): if self.move_type in ["in_invoice", "in_refund"]: action = self.env.ref("rma.action_rma_supplier_lines") form_view = self.env.ref("rma.view_rma_line_supplier_form", False) @@ -85,7 +102,7 @@ class AccountMove(models.Model): action = self.env.ref("rma.action_rma_customer_lines") form_view = self.env.ref("rma.view_rma_line_form", False) result = action.sudo().read()[0] - rma_ids = self.mapped("line_ids.rma_line_ids").ids + rma_ids = rmas.ids # choose the view_mode accordingly if not rma_ids: result["domain"] = [("id", "in", [])] @@ -196,11 +213,19 @@ class AccountMoveLine(models.Model): else: return super(AccountMoveLine, self).name_get() - def _compute_rma_count(self): + def _compute_used_in_rma_count(self): for invl in self: rma_lines = invl.mapped("rma_line_ids") + invl.used_in_rma_line_count = len(rma_lines) + + def _compute_rma_count(self): + for invl in self: + rma_lines = invl.mapped("rma_line_id") invl.rma_line_count = len(rma_lines) + used_in_rma_line_count = fields.Integer( + compute="_compute_used_in_rma_line_count", string="# of RMA" + ) rma_line_count = fields.Integer(compute="_compute_rma_count", string="# of RMA") rma_line_ids = fields.One2many( comodel_name="rma.order.line", @@ -209,7 +234,6 @@ class AccountMoveLine(models.Model): readonly=True, help="This will contain the RMA lines for the invoice line", ) - rma_line_id = fields.Many2one( comodel_name="rma.order.line", string="RMA line", diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py index b05ef925..1bfb9370 100644 --- a/rma_account/tests/test_rma_account.py +++ b/rma_account/tests/test_rma_account.py @@ -2,7 +2,9 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from odoo import fields +from odoo.fields import Date from odoo.tests import common +from odoo.tests.common import Form class TestRmaAccount(common.SingleTransactionCase): @@ -230,18 +232,20 @@ class TestRmaAccount(common.SingleTransactionCase): self.assertEqual(rma.qty_to_refund, 0.0) self.assertEqual(rma.qty_refunded, 2.0) - def test_05_fill_rma_from_inv_line(self): - """Test filling a RMA (line) from an invoice line.""" - rma = self.rma_line_obj.new( - { - "partner_id": self.inv_customer.partner_id.id, - "account_move_line_id": self.inv_supplier.line_ids.ids[0], - } - ) - self.assertFalse(rma.product_id) - rma._onchange_account_move_line_id() + def test_05_fill_rma_from_supplier_inv_line(self): + """Test filling a RMA (line) from a invoice line.""" + with Form( + self.rma_line_obj.with_context(default_type="supplier") + ) as rma_line_form: + rma_line_form.partner_id = self.inv_supplier.partner_id + rma_line_form.account_move_line_id = self.inv_supplier.line_ids[0] + rma = rma_line_form.save() self.assertEqual(rma.product_id, self.product_1) self.assertEqual(rma.product_qty, 3.0) + # Remember that the test is SingleTransactionCase. + # This supplier invoice has been referenced in 3 RMA lines. + self.assertEqual(self.inv_supplier.used_in_rma_count, 3) + self.assertEqual(self.inv_supplier.rma_count, 0) def test_06_default_journal(self): self.operation_1.write({"refund_journal_id": self.journal_sale.id}) @@ -285,15 +289,17 @@ class TestRmaAccount(common.SingleTransactionCase): rma_1 = self.rma_group_supplier.rma_line_ids.filtered( lambda r: r.product_id == self.product_1 ) - inv = self.inv_obj.with_context( - **{ - "default_move_type": "in_refund", - "default_partner_id": self.inv_supplier.partner_id, - } - ).create({"add_rma_line_id": rma_1}) - line = inv.on_change_add_rma_line_id() - inv.invoice_line_ids = [(0, 0, line)] - inv_product = inv.invoice_line_ids.filtered( + with Form( + self.env["account.move"].with_context(default_move_type="in_refund") + ) as bill_form: + bill_form.partner_id = rma_1.partner_id + bill_form.invoice_date = Date.today() + bill_form.add_rma_line_id = rma_1 + bill = bill_form.save() + bill.action_post() + bill_product = bill.invoice_line_ids.filtered( lambda x: x.product_id == self.product_1 ).mapped("product_id") - self.assertEqual(rma_1.product_id.id, inv_product.id) + self.assertEqual(rma_1.product_id.id, bill_product.id) + self.assertEqual(bill.rma_count, 1) + self.assertEqual(bill.used_in_rma_count, 0) diff --git a/rma_account/views/account_move_view.xml b/rma_account/views/account_move_view.xml index 2153188a..d6ba3d50 100644 --- a/rma_account/views/account_move_view.xml +++ b/rma_account/views/account_move_view.xml @@ -8,14 +8,38 @@
+
+ + + + + + +
@@ -33,6 +57,7 @@ +
diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 7c2b878b..dfe569fb 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -110,11 +110,24 @@ class RmaRefund(models.TransientModel): result["res_id"] = new_invoice.id return result + def _get_refund_price_unit(self, rma): + price_unit = rma.price_unit + # If this references a previous invoice/bill, use the same unit price + if rma.account_move_line_id: + price_unit = rma.account_move_line_id.price_unit + return price_unit + + def _get_refund_currency(self, rma): + currency = rma.currency_id + if rma.account_move_line_id: + currency = rma.account_move_line_id.currency_id + return currency + @api.model def prepare_refund_line(self, item): values = { "name": item.line_id.name or item.rma_id.name, - "price_unit": item.line_id.price_unit, + "price_unit": self._get_refund_price_unit(item.line_id), "product_uom_id": item.line_id.uom_id.id, "product_id": item.product.id, "rma_line_id": item.line_id.id, @@ -143,7 +156,7 @@ class RmaRefund(models.TransientModel): "journal_id": journal.id, "fiscal_position_id": rma_line.partner_id.property_account_position_id.id, "state": "draft", - "currency_id": rma_line.currency_id.id, + "currency_id": self._get_refund_currency(rma_line), "date": wizard.date, "invoice_date": wizard.date_invoice, "partner_id": rma_line.invoice_address_id.id or rma_line.partner_id.id, From c8c281270e95e8e4b4a8e0ea58fd456f9ef9483a Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Wed, 28 Dec 2022 13:13:34 +0100 Subject: [PATCH 87/93] [FIX] rma_account: Ensure that configuration on the operation is applied Without this, some policies are not being copied from the operation selected when creating new rma line from a rma group. In v16 this patch and the usage of such onchange can be removed in favor of (pre)computed stored editable fields for all policies and configuration in the RMA operation. --- rma_account/wizards/rma_add_account_move.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rma_account/wizards/rma_add_account_move.py b/rma_account/wizards/rma_add_account_move.py index eac2754d..642bda4a 100644 --- a/rma_account/wizards/rma_add_account_move.py +++ b/rma_account/wizards/rma_add_account_move.py @@ -128,7 +128,13 @@ class RmaAddAccountMove(models.TransientModel): # Load a PO line only once if line not in existing_invoice_lines: data = self._prepare_rma_line_from_inv_line(line) - rma_line_obj.create(data) + rec = rma_line_obj.create(data) + # Ensure that configuration on the operation is applied (like + # policies). + # TODO MIG: in v16 the usage of such onchange can be removed in + # favor of (pre)computed stored editable fields for all policies + # and configuration in the RMA operation. + rec._onchange_operation_id() rma = self.rma_id data_rma = self._get_rma_data() rma.write(data_rma) From 06bda844bc987d2d7618408214a15d95c07bde1d Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Mon, 2 Jan 2023 10:25:30 +0100 Subject: [PATCH 88/93] [IMP] rma_account: adapt to changes in supplier rma group form view. --- rma_account/views/rma_order_view.xml | 41 ---------------------------- 1 file changed, 41 deletions(-) diff --git a/rma_account/views/rma_order_view.xml b/rma_account/views/rma_order_view.xml index bed185d5..883ad6c0 100644 --- a/rma_account/views/rma_order_view.xml +++ b/rma_account/views/rma_order_view.xml @@ -35,45 +35,4 @@
- - rma.order.supplier.form - rma.order - - - - - - - -
From ea60657bf7a5fd470651ff1c0d45cf91c1a7cfa7 Mon Sep 17 00:00:00 2001 From: AaronHForgeFlow Date: Wed, 4 Jan 2023 11:57:36 +0100 Subject: [PATCH 89/93] [14.0][FIX] rma_account: reconcile GDNI when receiving but refund is expected --- rma_account/models/rma_operation.py | 16 +++ rma_account/models/rma_order_line.py | 36 +++++++ rma_account/models/stock_move.py | 1 + rma_account/tests/test_rma_stock_account.py | 110 ++++++++++++++++++++ rma_account/views/rma_operation_view.xml | 4 + rma_account/wizards/rma_refund.py | 6 +- 6 files changed, 169 insertions(+), 4 deletions(-) diff --git a/rma_account/models/rma_operation.py b/rma_account/models/rma_operation.py index 727bab40..26702309 100644 --- a/rma_account/models/rma_operation.py +++ b/rma_account/models/rma_operation.py @@ -27,6 +27,16 @@ class RmaOperation(models.Model): comodel_name="account.journal", compute="_compute_domain_valid_journal", ) + automated_refund = fields.Boolean( + help="In the scenario where a company uses anglo-saxon accounting, if " + "you receive products from a customer and don't expect to refund the customer " + "but send a replacement unit, mark this flag to be accounting consistent" + ) + refund_free_of_charge = fields.Boolean( + help="In case of automated refund you should mark this option as long automated" + "refunds mean to compensate Stock Interim accounts only without hitting" + "Accounts receivable" + ) @api.onchange("type") def _compute_domain_valid_journal(self): @@ -39,3 +49,9 @@ class RmaOperation(models.Model): rec.valid_refund_journal_ids = self.env["account.journal"].search( [("type", "=", "purchase")] ) + + @api.onchange("automated_refund") + def _onchange_automated_refund(self): + for rec in self: + if rec.automated_refund: + rec.refund_free_of_charge = True diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index f27e460e..fe30ddda 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -357,3 +357,39 @@ class RmaOrderLine(models.Model): # We get the cost from the original invoice line price_unit = self.account_move_line_id.price_unit return price_unit + + def _refund_at_zero_cost(self): + make_refund = ( + self.env["rma.refund"] + .with_context( + { + "customer": True, + "active_ids": self.ids, + "active_model": "rma.order.line", + } + ) + .create({"description": "RMA Anglosaxon Regularisation"}) + ) + for item in make_refund.item_ids: + item.qty_to_refund = item.line_id.qty_received - item.line_id.qty_refunded + action_refund = make_refund.invoice_refund() + refund_id = action_refund.get("res_id", False) + if refund_id: + refund = self.env["account.move"].browse(refund_id) + refund._post() + + def _check_refund_zero_cost(self): + """ + In the scenario where a company uses anglo-saxon accounting, if you receive + products from a customer and don't expect to refund the customer but send a + replacement unit you still need to create a debit entry on the + Stock Interim (Delivered) account. In order to do this the best approach is + to create a customer refund from the RMA, but set as free of charge + (price unit = 0). The refund will be 0, but the Stock Interim (Delivered) + account will be posted anyways. + """ + # For some reason api.depends on qty_received is not working. Using the + # _account_entry_move method in stock move as trigger then + for rec in self.filtered(lambda l: l.operation_id.automated_refund): + if rec.qty_received > rec.qty_refunded: + rec._refund_at_zero_cost() diff --git a/rma_account/models/stock_move.py b/rma_account/models/stock_move.py index c5872fa4..763c0297 100644 --- a/rma_account/models/stock_move.py +++ b/rma_account/models/stock_move.py @@ -28,4 +28,5 @@ class StockMove(models.Model): # Eventually reconcile together the invoice and valuation accounting # entries on the stock interim accounts self.rma_line_id._stock_account_anglo_saxon_reconcile_valuation() + self.rma_line_id._check_refund_zero_cost() return res diff --git a/rma_account/tests/test_rma_stock_account.py b/rma_account/tests/test_rma_stock_account.py index 1e160fee..8db54d37 100644 --- a/rma_account/tests/test_rma_stock_account.py +++ b/rma_account/tests/test_rma_stock_account.py @@ -25,6 +25,9 @@ class TestRmaStockAccount(TestRma): "rma_account.rma_operation_customer_refund" ) cls.rma_basic_user.write({"groups_id": [(4, cls.g_account_user.id)]}) + cls.customer_route = cls.env.ref("rma.route_rma_customer") + cls.input_location = cls.env.ref("stock.stock_location_company") + cls.output_location = cls.env.ref("stock.stock_location_output") # The product category created in the base module is not automated valuation # we have to create a new category here # Create account for Goods Received Not Invoiced @@ -248,3 +251,110 @@ class TestRmaStockAccount(TestRma): self.assertEqual(gdni_balance, 0.0) # The GDNI entries should be now reconciled self.assertEqual(all(gdni_amls.mapped("reconciled")), True) + + def test_08_cost_from_move_multi_step(self): + """ + Receive a product and then return it using a multi-step route. + The Goods Delivered Not Invoiced should result in 0 + """ + # Alter the customer RMA route to make it multi-step + # Get rid of the duplicated rule + self.env.ref("rma.rule_rma_customer_out_pull").active = False + self.env.ref("rma.rule_rma_customer_in_pull").active = False + cust_in_pull_rule = self.customer_route.rule_ids.filtered( + lambda r: r.location_id == self.stock_rma_location + ) + cust_in_pull_rule.location_id = self.input_location + cust_out_pull_rule = self.customer_route.rule_ids.filtered( + lambda r: r.location_src_id == self.env.ref("rma.location_rma") + ) + cust_out_pull_rule.location_src_id = self.output_location + cust_out_pull_rule.procure_method = "make_to_order" + self.env["stock.rule"].create( + { + "name": "RMA->Output", + "action": "pull", + "warehouse_id": self.wh.id, + "location_src_id": self.env.ref("rma.location_rma").id, + "location_id": self.output_location.id, + "procure_method": "make_to_stock", + "route_id": self.customer_route.id, + "picking_type_id": self.env.ref("stock.picking_type_internal").id, + } + ) + self.env["stock.rule"].create( + { + "name": "Customers->RMA", + "action": "pull", + "warehouse_id": self.wh.id, + "location_src_id": self.customer_location.id, + "location_id": self.env.ref("rma.location_rma").id, + "procure_method": "make_to_order", + "route_id": self.customer_route.id, + "picking_type_id": self.env.ref("stock.picking_type_in").id, + } + ) + # Set a standard price on the products + self.product_fifo_1.standard_price = 10 + self._create_inventory( + self.product_fifo_1, 20.0, self.env.ref("stock.stock_location_customers") + ) + products2move = [ + (self.product_fifo_1, 3), + ] + self.product_fifo_1.categ_id.rma_customer_operation_id = ( + self.rma_cust_replace_op_id + ) + rma_customer_id = self._create_rma_from_move( + products2move, + "customer", + self.env.ref("base.res_partner_2"), + dropship=False, + ) + # Set an incorrect price in the RMA (this should not affect cost) + rma = rma_customer_id.rma_line_ids + rma.price_unit = 999 + rma.action_rma_to_approve() + self._receive_rma(rma) + layers = rma.move_ids.sudo().stock_valuation_layer_ids + gdni_amls = layers.account_move_id.line_ids.filtered( + lambda l: l.account_id == self.account_gdni + ) + gdni_balance = sum(gdni_amls.mapped("balance")) + self.assertEqual(len(gdni_amls), 1) + # Balance should be -30, as we have only received + self.assertEqual(gdni_balance, -30.0) + self._deliver_rma(rma) + layers = rma.move_ids.sudo().stock_valuation_layer_ids + gdni_amls = layers.account_move_id.line_ids.filtered( + lambda l: l.account_id == self.account_gdni + ) + gdni_balance = sum(gdni_amls.mapped("balance")) + self.assertEqual(len(gdni_amls), 2) + # Balance should be 0, as we have received and shipped + self.assertEqual(gdni_balance, 0.0) + # The GDNI entries should be now reconciled + self.assertEqual(all(gdni_amls.mapped("reconciled")), True) + + def test_05_reconcile_grni_when_no_refund(self): + """ + Test that receive and send a replacement order leaves GDNI reconciled + """ + self.product_fifo_1.standard_price = 15 + rma_line = Form(self.rma_line) + rma_line.partner_id = self.partner_id + rma_line.product_id = self.product_fifo_1 + rma_line.operation_id.automated_refund = True + rma_line = rma_line.save() + rma_line.action_rma_to_approve() + # receiving should trigger the refund at zero cost + self._receive_rma(rma_line) + gdni_amls = self.env["account.move.line"].search( + [ + ("rma_line_id", "in", rma_line.ids), + ("account_id", "=", self.account_gdni.id), + ] + ) + rma_line.refund_line_ids.filtered( + lambda l: l.account_id == self.account_gdni + ) + self.assertEqual(all(gdni_amls.mapped("reconciled")), True) diff --git a/rma_account/views/rma_operation_view.xml b/rma_account/views/rma_operation_view.xml index 6d2cdbb0..922f52aa 100644 --- a/rma_account/views/rma_operation_view.xml +++ b/rma_account/views/rma_operation_view.xml @@ -21,6 +21,10 @@ + + + +
diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index dfe569fb..825046a3 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -92,10 +92,6 @@ class RmaRefund(models.TransientModel): def invoice_refund(self): rma_line_ids = self.env["rma.order.line"].browse(self.env.context["active_ids"]) for line in rma_line_ids: - if line.refund_policy == "no": - raise ValidationError( - _("The operation is not refund for at least one line") - ) if line.state != "approved": raise ValidationError(_("RMA %s is not approved") % line.name) new_invoice = self.compute_refund() @@ -111,6 +107,8 @@ class RmaRefund(models.TransientModel): return result def _get_refund_price_unit(self, rma): + if rma.operation_id.refund_free_of_charge: + return 0.0 price_unit = rma.price_unit # If this references a previous invoice/bill, use the same unit price if rma.account_move_line_id: From f1b100ef7861335e7d9b07bac82fadd779992697 Mon Sep 17 00:00:00 2001 From: AaronHForgeFlow Date: Wed, 8 Feb 2023 12:34:11 +0100 Subject: [PATCH 90/93] [IMP] rma_account: pre-commit, context overridden using dict. Better using kwargs --- rma_account/models/rma_order_line.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index fe30ddda..ca3c6037 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -362,7 +362,7 @@ class RmaOrderLine(models.Model): make_refund = ( self.env["rma.refund"] .with_context( - { + **{ "customer": True, "active_ids": self.ids, "active_model": "rma.order.line", From 4cd1255a5da4165b4f1546c869e0a7ea11f760a1 Mon Sep 17 00:00:00 2001 From: DavidJForgeFlow Date: Wed, 22 Feb 2023 11:17:03 +0100 Subject: [PATCH 91/93] [IMP] rma_account: pre-commit stuff --- setup/rma_account/odoo/addons/rma_account | 1 + setup/rma_account/setup.py | 6 ++++++ 2 files changed, 7 insertions(+) create mode 120000 setup/rma_account/odoo/addons/rma_account create mode 100644 setup/rma_account/setup.py diff --git a/setup/rma_account/odoo/addons/rma_account b/setup/rma_account/odoo/addons/rma_account new file mode 120000 index 00000000..85893de8 --- /dev/null +++ b/setup/rma_account/odoo/addons/rma_account @@ -0,0 +1 @@ +../../../../rma_account \ No newline at end of file diff --git a/setup/rma_account/setup.py b/setup/rma_account/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/rma_account/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From f07c5f2e85124858f68ca30e73165095473665de Mon Sep 17 00:00:00 2001 From: DavidJForgeFlow Date: Wed, 22 Feb 2023 15:10:07 +0100 Subject: [PATCH 92/93] [MIG] rma_account: Migration to 16.0 --- rma_account/__manifest__.py | 2 +- rma_account/models/account_move.py | 9 ++-- rma_account/models/rma_order_line.py | 8 ++-- rma_account/models/stock_move.py | 4 +- .../test_account_move_line_rma_order_line.py | 23 +++------- rma_account/tests/test_rma_account.py | 6 +-- rma_account/tests/test_rma_stock_account.py | 45 +++++++++---------- rma_account/wizards/rma_add_account_move.py | 4 +- rma_account/wizards/rma_refund.py | 2 +- 9 files changed, 41 insertions(+), 62 deletions(-) diff --git a/rma_account/__manifest__.py b/rma_account/__manifest__.py index 7c81beae..28f6b2fc 100644 --- a/rma_account/__manifest__.py +++ b/rma_account/__manifest__.py @@ -3,7 +3,7 @@ { "name": "RMA Account", - "version": "15.0.1.2.0", + "version": "16.0.1.0.0", "license": "LGPL-3", "category": "RMA", "summary": "Integrates RMA with Invoice Processing", diff --git a/rma_account/models/account_move.py b/rma_account/models/account_move.py index 4ce2146d..d509aad1 100644 --- a/rma_account/models/account_move.py +++ b/rma_account/models/account_move.py @@ -47,11 +47,9 @@ class AccountMove(models.Model): new_line.rma_line_id = rma_line new_line.name = "%s: %s" % ( self.add_rma_line_id.name, - new_line._get_computed_name(), + new_line.name, ) - new_line.account_id = new_line._get_computed_account() - new_line._onchange_price_subtotal() - new_line._onchange_mark_recompute_taxes() + new_line.account_id = new_line.account_id return True @api.onchange("add_rma_line_id") @@ -72,7 +70,6 @@ class AccountMove(models.Model): origins = set(self.line_ids.mapped("rma_line_id.name")) self.invoice_origin = ",".join(list(origins)) self.add_rma_line_id = False - self._onchange_currency() rma_count = fields.Integer(compute="_compute_rma_count", string="# of RMA") used_in_rma_count = fields.Integer( @@ -224,7 +221,7 @@ class AccountMoveLine(models.Model): invl.rma_line_count = len(rma_lines) used_in_rma_line_count = fields.Integer( - compute="_compute_used_in_rma_line_count", string="# of RMA" + compute="_compute_used_in_rma_count", string="# of RMA" ) rma_line_count = fields.Integer(compute="_compute_rma_count", string="# of RMA") rma_line_ids = fields.One2many( diff --git a/rma_account/models/rma_order_line.py b/rma_account/models/rma_order_line.py index ca3c6037..2b944dcb 100644 --- a/rma_account/models/rma_order_line.py +++ b/rma_account/models/rma_order_line.py @@ -82,7 +82,7 @@ class RmaOrderLine(models.Model): string="Refund Lines", domain=[ ("move_id.move_type", "in", ["in_refund", "out_refund"]), - ("exclude_from_invoice_tab", "=", False), + ("display_type", "=", "product"), ], copy=False, index=True, @@ -129,21 +129,19 @@ class RmaOrderLine(models.Model): res["domain"] = {} if not self.product_id: domain = [ - "&", "|", ("move_id.partner_id", "=", self.partner_id.id), ("move_id.partner_id", "child_of", self.partner_id.id), - ("exclude_from_invoice_tab", "=", False), + ("display_type", "=", "product"), ] res["domain"]["account_move_line_id"] = domain else: domain = [ - "&", "&", "|", ("move_id.partner_id", "=", self.partner_id.id), ("move_id.partner_id", "child_of", self.partner_id.id), - ("exclude_from_invoice_tab", "=", False), + ("display_type", "=", "product"), ("product_id", "=", self.product_id.id), ] res["domain"]["account_move_line_id"] = domain diff --git a/rma_account/models/stock_move.py b/rma_account/models/stock_move.py index 763c0297..78db0347 100644 --- a/rma_account/models/stock_move.py +++ b/rma_account/models/stock_move.py @@ -9,10 +9,10 @@ class StockMove(models.Model): @api.model def _prepare_account_move_line( - self, qty, cost, credit_account_id, debit_account_id, description + self, qty, cost, credit_account_id, debit_account_id, svl_id, description ): res = super(StockMove, self)._prepare_account_move_line( - qty, cost, credit_account_id, debit_account_id, description + qty, cost, credit_account_id, debit_account_id, svl_id, description ) for line in res: if ( diff --git a/rma_account/tests/test_account_move_line_rma_order_line.py b/rma_account/tests/test_account_move_line_rma_order_line.py index 4f671931..a692811e 100644 --- a/rma_account/tests/test_account_move_line_rma_order_line.py +++ b/rma_account/tests/test_account_move_line_rma_order_line.py @@ -18,7 +18,6 @@ class TestAccountMoveLineRmaOrderLine(common.TransactionCase): cls.invoice_line_model = cls.env["account.move.line"] cls.product_model = cls.env["product.product"] cls.product_ctg_model = cls.env["product.category"] - cls.acc_type_model = cls.env["account.account.type"] cls.account_model = cls.env["account.account"] cls.aml_model = cls.env["account.move.line"] cls.res_users_model = cls.env["res.users"] @@ -35,21 +34,20 @@ class TestAccountMoveLineRmaOrderLine(common.TransactionCase): cls.customer_location = cls.env.ref("stock.stock_location_customers") cls.supplier_location = cls.env.ref("stock.stock_location_suppliers") # Create account for Goods Received Not Invoiced - acc_type = cls._create_account_type("equity", "other", "equity") name = "Goods Received Not Invoiced" code = "grni" - cls.account_grni = cls._create_account(acc_type, name, code, cls.company) + cls.account_grni = cls._create_account("equity", name, code, cls.company) # Create account for Cost of Goods Sold - acc_type = cls._create_account_type("expense", "other", "expense") name = "Goods Delivered Not Invoiced" code = "gdni" - cls.account_cogs = cls._create_account(acc_type, name, code, cls.company) + cls.account_cogs = cls._create_account("expense", name, code, cls.company) # Create account for Inventory - acc_type = cls._create_account_type("asset", "other", "asset") name = "Inventory" code = "inventory" - cls.account_inventory = cls._create_account(acc_type, name, code, cls.company) + cls.account_inventory = cls._create_account( + "asset_current", name, code, cls.company + ) # TODO: poner asset de inventario # Create Product cls.product = cls._create_product() cls.product_uom_id = cls.env.ref("uom.product_uom_unit") @@ -81,13 +79,6 @@ class TestAccountMoveLineRmaOrderLine(common.TransactionCase): ) return user.id - @classmethod - def _create_account_type(cls, name, account_type, internal_group): - acc_type = cls.acc_type_model.create( - {"name": name, "type": account_type, "internal_group": internal_group} - ) - return acc_type - @classmethod def _create_account(cls, acc_type, name, code, company, reconcile=False): """Create an account.""" @@ -95,7 +86,7 @@ class TestAccountMoveLineRmaOrderLine(common.TransactionCase): { "name": name, "code": code, - "user_type_id": acc_type.id, + "account_type": acc_type, "company_id": company.id, "reconcile": reconcile, } @@ -254,7 +245,7 @@ class TestAccountMoveLineRmaOrderLine(common.TransactionCase): else: picking_ids = self.env["stock.picking"].search(res["domain"]) picking = self.env["stock.picking"].browse(picking_ids) - picking.move_lines.write({"quantity_done": 1.0}) + picking.move_line_ids.write({"qty_done": 1.0}) picking.button_validate() # decreasing cogs expected_balance = -1.0 diff --git a/rma_account/tests/test_rma_account.py b/rma_account/tests/test_rma_account.py index 1bfb9370..871e976b 100644 --- a/rma_account/tests/test_rma_account.py +++ b/rma_account/tests/test_rma_account.py @@ -24,7 +24,6 @@ class TestRmaAccount(common.SingleTransactionCase): customer1_obj = cls.env["res.partner"] cls.rma_route_cust = cls.env.ref("rma.route_rma_customer") - receivable_type = cls.env.ref("account.data_account_type_receivable") cls.cust_refund_op = cls.env.ref("rma_account.rma_operation_customer_refund") cls.sup_refund_op = cls.env.ref("rma_account.rma_operation_supplier_refund") cls.company_id = cls.env.user.company_id @@ -88,7 +87,7 @@ class TestRmaAccount(common.SingleTransactionCase): # Create Invoices: cls.customer_account = cls.acc_obj.search( - [("user_type_id", "=", receivable_type.id)], limit=1 + [("account_type", "=", "asset_receivable")], limit=1 ).id cls.invoices = cls.env["account.move"].create( @@ -235,7 +234,8 @@ class TestRmaAccount(common.SingleTransactionCase): def test_05_fill_rma_from_supplier_inv_line(self): """Test filling a RMA (line) from a invoice line.""" with Form( - self.rma_line_obj.with_context(default_type="supplier") + self.rma_line_obj.with_context(default_type="supplier"), + view="rma_account.view_rma_line_supplier_form", ) as rma_line_form: rma_line_form.partner_id = self.inv_supplier.partner_id rma_line_form.account_move_line_id = self.inv_supplier.line_ids[0] diff --git a/rma_account/tests/test_rma_stock_account.py b/rma_account/tests/test_rma_stock_account.py index 8db54d37..3de0c7c4 100644 --- a/rma_account/tests/test_rma_stock_account.py +++ b/rma_account/tests/test_rma_stock_account.py @@ -11,7 +11,6 @@ class TestRmaStockAccount(TestRma): @classmethod def setUpClass(cls): super(TestRmaStockAccount, cls).setUpClass() - cls.acc_type_model = cls.env["account.account.type"] cls.account_model = cls.env["account.account"] cls.g_account_user = cls.env.ref("account.group_account_user") cls.rma_refund_wiz = cls.env["rma.refund"] @@ -31,21 +30,20 @@ class TestRmaStockAccount(TestRma): # The product category created in the base module is not automated valuation # we have to create a new category here # Create account for Goods Received Not Invoiced - acc_type = cls._create_account_type("equity", "other") name = "Goods Received Not Invoiced" code = "grni" - cls.account_grni = cls._create_account(acc_type, name, code, cls.company, True) + cls.account_grni = cls._create_account("equity", name, code, cls.company, True) # Create account for Goods Delievered - acc_type = cls._create_account_type("asset", "other") name = "Goods Delivered Not Invoiced" code = "gdni" - cls.account_gdni = cls._create_account(acc_type, name, code, cls.company, True) + cls.account_gdni = cls._create_account( + "asset_current", name, code, cls.company, True + ) # Create account for Inventory - acc_type = cls._create_account_type("asset", "other") name = "Inventory" code = "inventory" cls.account_inventory = cls._create_account( - acc_type, name, code, cls.company, False + "asset_current", name, code, cls.company, False ) product_ctg = cls.product_ctg_model.create( { @@ -65,13 +63,6 @@ class TestRmaStockAccount(TestRma): cls.product_fifo_2.categ_id = product_ctg cls.product_fifo_3.categ_id = product_ctg - @classmethod - def _create_account_type(cls, name, a_type): - acc_type = cls.acc_type_model.create( - {"name": name, "type": a_type, "internal_group": name} - ) - return acc_type - @classmethod def _create_account(cls, acc_type, name, code, company, reconcile): """Create an account.""" @@ -79,7 +70,7 @@ class TestRmaStockAccount(TestRma): { "name": name, "code": code, - "user_type_id": acc_type.id, + "account_type": acc_type, "company_id": company.id, "reconcile": reconcile, } @@ -92,9 +83,9 @@ class TestRmaStockAccount(TestRma): debit_line = account_move.mapped("line_ids").filtered(lambda l: l.debit) credit_line = account_move.mapped("line_ids").filtered(lambda l: l.credit) if debit_account: - self.assertEqual(debit_line.account_id.code, debit_account) + self.assertEqual(debit_line.account_id[0].code, debit_account) if credit_account: - self.assertEqual(credit_line.account_id.code, credit_account) + self.assertEqual(credit_line.account_id[0].code, credit_account) def test_01_cost_from_standard(self): """ @@ -108,8 +99,12 @@ class TestRmaStockAccount(TestRma): rma_line = rma_line.save() rma_line.action_rma_to_approve() picking = self._receive_rma(rma_line) - self.assertEqual(picking.move_lines.stock_valuation_layer_ids.value, 15.0) - account_move = picking.move_lines.stock_valuation_layer_ids.account_move_id + self.assertEqual( + picking.move_line_ids.move_id.stock_valuation_layer_ids.value, 15.0 + ) + account_move = ( + picking.move_line_ids.move_id.stock_valuation_layer_ids.account_move_id + ) self.check_accounts_used( account_move, debit_account="inventory", credit_account="gdni" ) @@ -145,10 +140,10 @@ class TestRmaStockAccount(TestRma): # Test the value in the layers of the incoming stock move is used for rma_line in rma_customer_id.rma_line_ids: value_origin = rma_line.reference_move_id.stock_valuation_layer_ids.value - move_product = picking.move_lines.filtered( + move_product = picking.move_line_ids.filtered( lambda l: l.product_id == rma_line.product_id ) - value_used = move_product.stock_valuation_layer_ids.value + value_used = move_product.move_id.stock_valuation_layer_ids.value self.assertEqual(value_used, -value_origin) # Create a refund for the first line rma = rma_lines[0] @@ -262,9 +257,9 @@ class TestRmaStockAccount(TestRma): self.env.ref("rma.rule_rma_customer_out_pull").active = False self.env.ref("rma.rule_rma_customer_in_pull").active = False cust_in_pull_rule = self.customer_route.rule_ids.filtered( - lambda r: r.location_id == self.stock_rma_location + lambda r: r.location_dest_id == self.stock_rma_location ) - cust_in_pull_rule.location_id = self.input_location + cust_in_pull_rule.location_dest_id = self.input_location cust_out_pull_rule = self.customer_route.rule_ids.filtered( lambda r: r.location_src_id == self.env.ref("rma.location_rma") ) @@ -276,7 +271,7 @@ class TestRmaStockAccount(TestRma): "action": "pull", "warehouse_id": self.wh.id, "location_src_id": self.env.ref("rma.location_rma").id, - "location_id": self.output_location.id, + "location_dest_id": self.output_location.id, "procure_method": "make_to_stock", "route_id": self.customer_route.id, "picking_type_id": self.env.ref("stock.picking_type_internal").id, @@ -288,7 +283,7 @@ class TestRmaStockAccount(TestRma): "action": "pull", "warehouse_id": self.wh.id, "location_src_id": self.customer_location.id, - "location_id": self.env.ref("rma.location_rma").id, + "location_dest_id": self.env.ref("rma.location_rma").id, "procure_method": "make_to_order", "route_id": self.customer_route.id, "picking_type_id": self.env.ref("stock.picking_type_in").id, diff --git a/rma_account/wizards/rma_add_account_move.py b/rma_account/wizards/rma_add_account_move.py index 642bda4a..d4588f11 100644 --- a/rma_account/wizards/rma_add_account_move.py +++ b/rma_account/wizards/rma_add_account_move.py @@ -122,9 +122,7 @@ class RmaAddAccountMove(models.TransientModel): def add_lines(self): rma_line_obj = self.env["rma.order.line"] existing_invoice_lines = self._get_existing_invoice_lines() - for line in self.line_ids.filtered( - lambda aml: aml.exclude_from_invoice_tab is False - ): + for line in self.line_ids.filtered(lambda aml: aml.display_type == "product"): # Load a PO line only once if line not in existing_invoice_lines: data = self._prepare_rma_line_from_inv_line(line) diff --git a/rma_account/wizards/rma_refund.py b/rma_account/wizards/rma_refund.py index 825046a3..e2421c03 100644 --- a/rma_account/wizards/rma_refund.py +++ b/rma_account/wizards/rma_refund.py @@ -154,7 +154,7 @@ class RmaRefund(models.TransientModel): "journal_id": journal.id, "fiscal_position_id": rma_line.partner_id.property_account_position_id.id, "state": "draft", - "currency_id": self._get_refund_currency(rma_line), + "currency_id": self._get_refund_currency(rma_line).id, "date": wizard.date, "invoice_date": wizard.date_invoice, "partner_id": rma_line.invoice_address_id.id or rma_line.partner_id.id, From b1da49147691644f8bc56ed588d7474fc2a18720 Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Mon, 27 Feb 2023 16:08:38 +0100 Subject: [PATCH 93/93] [IMP] rma_account: add index in account.move.line to field 'rma_line_id' --- rma_account/models/account_move.py | 1 + rma_account/wizards/rma_refund.xml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rma_account/models/account_move.py b/rma_account/models/account_move.py index d509aad1..81864c6e 100644 --- a/rma_account/models/account_move.py +++ b/rma_account/models/account_move.py @@ -235,6 +235,7 @@ class AccountMoveLine(models.Model): comodel_name="rma.order.line", string="RMA line", ondelete="set null", + index=True, help="This will contain the rma line that originated this line", ) diff --git a/rma_account/wizards/rma_refund.xml b/rma_account/wizards/rma_refund.xml index da9cc4d2..60b6da75 100644 --- a/rma_account/wizards/rma_refund.xml +++ b/rma_account/wizards/rma_refund.xml @@ -59,13 +59,13 @@ name="%(action_rma_refund)d" string="Create Refund" class="oe_highlight" - attrs="{'invisible':['|', '|', ('qty_to_refund', '=', 0), ('state', '!=', 'approved'), ('refund_policy', '=', 'no')]}" + attrs="{'invisible':['|', '|', '|', ('qty_to_refund', '=', 0), ('qty_to_refund', '<', 0), ('state', '!=', 'approved'), ('refund_policy', '=', 'no')]}" type="action" />