diff --git a/rma_purchase/README.rst b/rma_purchase/README.rst new file mode 100644 index 00000000..a2335f81 --- /dev/null +++ b/rma_purchase/README.rst @@ -0,0 +1,47 @@ +.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg + :alt: License LGPL-3 + +============ +RMA Purchase +============ + +This modules extend the RMA functionality allowing to use Purchase Orders as +a RMA source. + +Usage +===== + +To add lines to a RMA from PO act as follows: + +#. Go to a supplier RMA. +#. Fill the *Supplier* field. +#. Click on *Add From Purchase Order*. +#. Select the Purchase Order. +#. Click on *Add an item* and select the lines you would like to add to the + RMA. +#. Hit *Confirm*. + +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 +* Lois Rilo +* Bhavesh Odedra +* Serpent Consulting Services Pvt. Ltd. + +Maintainer +---------- + +This module is maintained by Eficent. diff --git a/rma_purchase/__init__.py b/rma_purchase/__init__.py new file mode 100644 index 00000000..f3284a96 --- /dev/null +++ b/rma_purchase/__init__.py @@ -0,0 +1,5 @@ +# © 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_purchase/__manifest__.py b/rma_purchase/__manifest__.py new file mode 100644 index 00000000..19b6d255 --- /dev/null +++ b/rma_purchase/__manifest__.py @@ -0,0 +1,23 @@ +# © 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +{ + 'name': 'RMA Purchase', + 'version': '12.0.1.0.0', + 'category': 'RMA', + 'summary': 'RMA from PO', + 'license': 'LGPL-3', + 'author': 'Eficent, Odoo Community Association (OCA)', + 'website': 'http://www.github.com/OCA/rma', + 'depends': ['rma_account', 'purchase'], + 'data': [ + 'wizards/rma_order_line_make_purchase_order_view.xml', + 'security/ir.model.access.csv', + 'views/rma_operation_view.xml', + 'views/rma_order_view.xml', + 'views/rma_order_line_view.xml', + 'wizards/rma_add_purchase.xml', + ], + 'installable': True, + 'auto_install': True, +} diff --git a/rma_purchase/models/__init__.py b/rma_purchase/models/__init__.py new file mode 100644 index 00000000..d41e378c --- /dev/null +++ b/rma_purchase/models/__init__.py @@ -0,0 +1,7 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from . import rma_order +from . import rma_order_line +from . import purchase_order +from . import purchase_order_line +from . import rma_operation diff --git a/rma_purchase/models/purchase_order.py b/rma_purchase/models/purchase_order.py new file mode 100644 index 00000000..66ec0277 --- /dev/null +++ b/rma_purchase/models/purchase_order.py @@ -0,0 +1,26 @@ +# 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 odoo import api, models + + +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + @api.model + def new(self, vals): + """Allows to propose a line based on the RMA information.""" + res = super(PurchaseOrder, self).new(vals) + rma_line_id = self.env.context.get('rma_line_id') + if rma_line_id: + rma_line = self.env['rma.order.line'].browse(rma_line_id) + line = self.env['purchase.order.line'].new({ + 'product_id': rma_line.product_id.id, + }) + line.onchange_product_id() + line.update({ + 'product_qty': rma_line.qty_to_purchase, + 'product_uom': rma_line.uom_id.id, + }) + res.order_line = line + return res diff --git a/rma_purchase/models/purchase_order_line.py b/rma_purchase/models/purchase_order_line.py new file mode 100644 index 00000000..fe08f86b --- /dev/null +++ b/rma_purchase/models/purchase_order_line.py @@ -0,0 +1,59 @@ +# Copyright 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 + + +class PurchaseOrderLine(models.Model): + _inherit = "purchase.order.line" + + rma_line_id = fields.Many2one( + comodel_name='rma.order.line', string='RMA', + ) + + @api.model + def name_search(self, name='', args=None, operator='ilike', limit=100): + """Allows to search by PO reference.""" + if not args: + args = [] + args += ['|', + (self._rec_name, operator, name), + ('order_id.name', operator, name)] + return super(PurchaseOrderLine, self).name_search( + name=name, args=args, operator=operator, limit=limit) + + @api.model + def _name_search(self, name='', args=None, operator='ilike', + limit=100, name_get_uid=None): + """Typed text is cleared here for better extensibility.""" + return super(PurchaseOrderLine, self)._name_search( + name='', args=args, operator=operator, limit=limit, + name_get_uid=name_get_uid) + + @api.multi + def name_get(self): + res = [] + if self.env.context.get('rma'): + for purchase in self: + invoices = self.env['account.invoice.line'].search( + [('purchase_line_id', '=', purchase.id)]) + if purchase.order_id.name: + res.append((purchase.id, "%s %s %s qty:%s" % ( + purchase.order_id.name, + " ".join(str(x) for x in [ + inv.number for inv in invoices.mapped( + 'invoice_id')]), + purchase.product_id.name, purchase.product_qty))) + else: + res.append( + super(PurchaseOrderLine, purchase).name_get()[0]) + return res + else: + return super(PurchaseOrderLine, self).name_get() + + @api.model + def create(self, vals): + rma_line_id = self.env.context.get('rma_line_id') + if rma_line_id: + vals['rma_line_id'] = rma_line_id + return super(PurchaseOrderLine, self).create(vals) diff --git a/rma_purchase/models/rma_operation.py b/rma_purchase/models/rma_operation.py new file mode 100644 index 00000000..8665dba6 --- /dev/null +++ b/rma_purchase/models/rma_operation.py @@ -0,0 +1,24 @@ +# Copyright 2018 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 + + +class RmaOperation(models.Model): + _inherit = 'rma.operation' + + purchase_policy = fields.Selection( + selection=[('no', 'Not required'), + ('ordered', 'Based on Ordered Quantities'), + ('delivered', 'Based on Delivered Quantities')], + string="Purchase Policy", default='no', + ) + + @api.multi + @api.constrains('purchase_policy') + def _check_purchase_policy(self): + if self.filtered( + lambda r: r.purchase_policy != 'no' and r.type != 'supplier'): + raise ValidationError(_( + 'Purchase Policy can only apply to supplier operations')) diff --git a/rma_purchase/models/rma_order.py b/rma_purchase/models/rma_order.py new file mode 100644 index 00000000..5fb4943c --- /dev/null +++ b/rma_purchase/models/rma_order.py @@ -0,0 +1,54 @@ +# © 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 + + +class RmaOrder(models.Model): + _inherit = "rma.order" + + @api.multi + def _compute_po_count(self): + for rec in self: + po_count = 0 + rma_line_po = [] + for line in rec.rma_line_ids: + rma_line_po += self.env['purchase.order'].search( + [('origin', '=', line.name)]).ids + if rma_line_po: + po_count = len(list(set(rma_line_po))) + rec.po_count = po_count + + @api.multi + @api.depends('rma_line_ids') + def _compute_origin_po_count(self): + for rma in self: + purchases = rma.mapped( + 'rma_line_ids.purchase_order_line_id.order_id') + rma.origin_po_count = len(purchases) + + po_count = fields.Integer( + compute='_compute_po_count', string='# of PO') + origin_po_count = fields.Integer( + compute='_compute_origin_po_count', string='# of Origin PO') + + @api.multi + def action_view_purchase_order(self): + action = self.env.ref('purchase.purchase_rfq') + result = action.read()[0] + po_ids = self.env['purchase.order'].search( + [('origin', '=', self.name)]).ids + for line in self.rma_line_ids: + po_ids += self.env['purchase.order'].search( + [('origin', '=', line.name)]).ids + result['domain'] = [('id', 'in', po_ids)] + return result + + @api.multi + def action_view_origin_purchase_order(self): + action = self.env.ref('purchase.purchase_rfq') + result = action.read()[0] + po_ids = self.mapped( + 'rma_line_ids.purchase_order_line_id.order_id').ids + result['domain'] = [('id', 'in', po_ids)] + return result diff --git a/rma_purchase/models/rma_order_line.py b/rma_purchase/models/rma_order_line.py new file mode 100644 index 00000000..fd79595d --- /dev/null +++ b/rma_purchase/models/rma_order_line.py @@ -0,0 +1,203 @@ +# © 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.addons import decimal_precision as dp + + +class RmaOrderLine(models.Model): + _inherit = "rma.order.line" + + @api.multi + def _compute_purchase_count(self): + for rec in self: + purchase_line_count = self.env['purchase.order.line'].search( + [('rma_line_id', '=', rec.id)]) + rec.purchase_count = len(purchase_line_count.mapped('order_id')) + + @api.multi + def _compute_purchase_order_lines(self): + for rec in self: + purchase_list = [] + for line in self.env['purchase.order.line'].search( + [('rma_line_id', '=', rec.id)]): + purchase_list.append(line.id) + rec.purchase_order_line_ids = [(6, 0, purchase_list)] + + @api.multi + def _compute_qty_purchase(self): + for rec in self: + rec.qty_purchased = rec._get_rma_purchased_qty() + if rec.purchase_policy == 'ordered': + rec.qty_to_purchase = rec.product_qty - rec.qty_purchased + elif rec.purchase_policy == 'delivered': + rec.qty_to_purchase = rec.qty_delivered - rec.qty_purchased + else: + rec.qty_to_purchase = 0.0 + + purchase_count = fields.Integer( + compute='_compute_purchase_count', string='# of Purchases', + ) + purchase_order_line_id = fields.Many2one( + comodel_name='purchase.order.line', string='Originating Purchase Line', + ondelete='restrict', + readonly=True, states={'draft': [('readonly', False)]}, + ) + purchase_id = fields.Many2one( + string="Source Purchase Order", + related='purchase_order_line_id.order_id', + readonly=True, + ) + purchase_order_line_ids = fields.Many2many( + comodel_name='purchase.order.line', + relation='purchase_line_rma_line_rel', + column1='rma_order_line_id', column2='purchase_order_line_id', + string='Purchase Order Lines', compute='_compute_purchase_order_lines', + ) + purchase_policy = fields.Selection( + selection=[('no', 'Not required'), + ('ordered', 'Based on Ordered Quantities'), + ('delivered', 'Based on Delivered Quantities')], + string="Purchase Policy", default='no', + required=True, + ) + manual_purchase_line_ids = fields.One2many( + comodel_name='purchase.order.line', + inverse_name='rma_line_id', + string='Manual Purchase Order Lines', + readonly=True, copy=False) + qty_to_purchase = fields.Float( + string='Qty To Purchase', copy=False, + digits=dp.get_precision('Product Unit of Measure'), + readonly=True, compute='_compute_qty_purchase' + ) + qty_purchased = fields.Float( + string='Qty Purchased', copy=False, + digits=dp.get_precision('Product Unit of Measure'), + readonly=True, compute='_compute_qty_purchase' + ) + + @api.onchange('product_id', 'partner_id') + def _onchange_product_id(self): + """Domain for purchase_order_line_id is computed here to make + it dynamic.""" + res = super(RmaOrderLine, self)._onchange_product_id() + if not res.get('domain'): + res['domain'] = {} + domain = [ + '|', + ('order_id.partner_id', '=', self.partner_id.id), + ('order_id.partner_id', 'child_of', self.partner_id.id)] + if self.product_id: + domain.append(('product_id', '=', self.product_id.id)) + res['domain']['purchase_order_line_id'] = domain + return res + + @api.onchange('operation_id') + def _onchange_operation_id(self): + res = super(RmaOrderLine, self)._onchange_operation_id() + if self.operation_id: + self.purchase_policy = self.operation_id.purchase_policy or 'no' + return res + + @api.multi + def _prepare_rma_line_from_po_line(self, line): + 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 + else: + 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) + 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 a 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.")) + + data = { + 'product_id': line.product_id.id, + 'origin': line.order_id.name, + 'uom_id': line.product_uom.id, + 'operation_id': operation.id, + 'product_qty': line.product_qty, + 'price_unit': line.currency_id._convert( + line.price_unit, line.currency_id, + self.env.user.company_id, fields.Date.today(), round=False), + 'in_route_id': operation.in_route_id.id or route, + 'out_route_id': operation.out_route_id.id or route, + 'receipt_policy': operation.receipt_policy, + 'currency_id': line.currency_id.id, + 'location_id': (operation.location_id.id or + operation.in_warehouse_id.lot_rma_id.id or + warehouse.lot_rma_id.id), + '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, + } + return data + + @api.onchange('purchase_order_line_id') + def _onchange_purchase_order_line_id(self): + if not self.purchase_order_line_id: + return + data = self._prepare_rma_line_from_po_line( + self.purchase_order_line_id) + self.update(data) + self._remove_other_data_origin('purchase_order_line_id') + + @api.multi + @api.constrains('purchase_order_line_id', 'partner_id') + def _check_purchase_partner(self): + for rec in self: + if (rec.purchase_order_line_id and + rec.purchase_order_line_id.order_id.partner_id != + rec.partner_id): + raise ValidationError(_( + "RMA customer and originating purchase 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 == 'purchase_order_line_id': + self.purchase_order_line_id = False + return res + + @api.multi + def action_view_purchase_order(self): + action = self.env.ref('purchase.purchase_rfq') + result = action.read()[0] + orders = self.mapped('purchase_order_line_ids.order_id') + result['domain'] = [('id', 'in', orders.ids)] + return result + + @api.multi + def _get_rma_purchased_qty(self): + self.ensure_one() + qty = 0.0 + if self.type == 'customer': + return qty + for line in self.purchase_order_line_ids.filtered( + lambda p: p.state not in ('draft', 'sent', 'cancel')): + qty += self.uom_id._compute_quantity( + line.product_qty, line.product_uom) + return qty diff --git a/rma_purchase/security/ir.model.access.csv b/rma_purchase/security/ir.model.access.csv new file mode 100755 index 00000000..e37a8852 --- /dev/null +++ b/rma_purchase/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_purchase_order_supplier_user,access_purchase_order,purchase.model_purchase_order,rma.group_rma_supplier_user,1,0,0,0 +access_purchase_order_line_supplier_user,access_purchase_order_line,purchase.model_purchase_order_line,rma.group_rma_supplier_user,1,0,0,0 diff --git a/rma_purchase/tests/__init__.py b/rma_purchase/tests/__init__.py new file mode 100644 index 00000000..061a9ecc --- /dev/null +++ b/rma_purchase/tests/__init__.py @@ -0,0 +1,4 @@ +# 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_purchase diff --git a/rma_purchase/tests/test_rma_purchase.py b/rma_purchase/tests/test_rma_purchase.py new file mode 100644 index 00000000..f7fdb5cf --- /dev/null +++ b/rma_purchase/tests/test_rma_purchase.py @@ -0,0 +1,93 @@ +# 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 odoo.tests import common +from odoo.fields import Datetime + + +class TestRmaPurchase(common.TransactionCase): + + def setUp(self): + super(TestRmaPurchase, self).setUp() + + self.rma_obj = self.env['rma.order'] + self.rma_line_obj = self.env['rma.order.line'] + self.rma_op_obj = self.env['rma.operation'] + self.rma_add_purchase_wiz = self.env['rma_add_purchase'] + self.po_obj = self.env['purchase.order'] + self.pol_obj = self.env['purchase.order.line'] + self.product_obj = self.env['product.product'] + self.partner_obj = self.env['res.partner'] + + self.rma_route_cust = self.env.ref('rma.route_rma_customer') + + # Create supplier + supplier1 = self.partner_obj.create({'name': 'Supplier 1'}) + + # Create products + self.product_1 = self.product_obj.create({ + 'name': 'Test Product 1', + 'type': 'product', + }) + self.product_2 = self.product_obj.create({ + 'name': 'Test Product 2', + 'type': 'product', + }) + + # Create PO: + self.po = self.po_obj.create({ + 'partner_id': supplier1.id, + }) + self.pol_1 = self.pol_obj.create({ + 'name': self.product_1.name, + 'order_id': self.po.id, + 'product_id': self.product_1.id, + 'product_qty': 20.0, + 'product_uom': self.product_1.uom_id.id, + 'price_unit': 100.0, + 'date_planned': Datetime.now(), + }) + self.pol_2 = self.pol_obj.create({ + 'name': self.product_2.name, + 'order_id': self.po.id, + 'product_id': self.product_2.id, + 'product_qty': 18.0, + 'product_uom': self.product_2.uom_id.id, + 'price_unit': 150.0, + 'date_planned': Datetime.now(), + }) + + # Create RMA group: + self.rma_group = self.rma_obj.create({ + 'partner_id': supplier1.id, + 'type': 'supplier', + }) + + def test_01_add_from_purchase_order(self): + """Test wizard to create supplier RMA from Purchase Orders.""" + self.assertEqual(self.rma_group.origin_po_count, 0) + add_purchase = self.rma_add_purchase_wiz.with_context({ + 'supplier': True, + 'active_ids': self.rma_group.id, + 'active_model': 'rma.order', + }).create({ + 'purchase_id': self.po.id, + 'purchase_line_ids': [(6, 0, self.po.order_line.ids)], + }) + add_purchase.add_lines() + self.assertEqual(len(self.rma_group.rma_line_ids), 2) + for t in self.rma_group.rma_line_ids.mapped('type'): + self.assertEqual(t, 'supplier') + self.assertEqual(self.rma_group.origin_po_count, 1) + + def test_02_fill_rma_from_po_line(self): + """Test filling a RMA (line) from a Purchase Order line.""" + rma = self.rma_line_obj.new({ + 'partner_id': self.po.partner_id.id, + 'purchase_order_line_id': self.pol_1.id, + 'type': 'supplier', + }) + self.assertFalse(rma.product_id) + rma._onchange_purchase_order_line_id() + self.assertEqual(rma.product_id, self.product_1) + self.assertEqual(rma.product_qty, 20.0) diff --git a/rma_purchase/views/rma_operation_view.xml b/rma_purchase/views/rma_operation_view.xml new file mode 100644 index 00000000..1afff91d --- /dev/null +++ b/rma_purchase/views/rma_operation_view.xml @@ -0,0 +1,28 @@ + + + + + + rma.operation.tree - rma_purchase + rma.operation + + + + + + + + + + rma.operation.form - rma_purchase + rma.operation + + + + + + + + + diff --git a/rma_purchase/views/rma_order_line_view.xml b/rma_purchase/views/rma_order_line_view.xml new file mode 100644 index 00000000..2e8a8803 --- /dev/null +++ b/rma_purchase/views/rma_order_line_view.xml @@ -0,0 +1,69 @@ + + + + + Purchase Order + purchase.order + form + current + form,tree + + + + rma.order.line.supplier.form + rma.order.line + + +
+
+
+
+ + + rma.order.line.supplier.form + rma.order.line + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
diff --git a/rma_purchase/views/rma_order_view.xml b/rma_purchase/views/rma_order_view.xml new file mode 100644 index 00000000..f5f61ed2 --- /dev/null +++ b/rma_purchase/views/rma_order_view.xml @@ -0,0 +1,29 @@ + + + + + rma.order.supplier.form + rma.order + + +
+ + +
+
+
+ +
diff --git a/rma_purchase/wizards/__init__.py b/rma_purchase/wizards/__init__.py new file mode 100644 index 00000000..73c6279c --- /dev/null +++ b/rma_purchase/wizards/__init__.py @@ -0,0 +1,6 @@ +# © 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_make_picking +from . import rma_add_purchase +from . import rma_order_line_make_purchase_order diff --git a/rma_purchase/wizards/rma_add_purchase.py b/rma_purchase/wizards/rma_add_purchase.py new file mode 100644 index 00000000..f84a81ef --- /dev/null +++ b/rma_purchase/wizards/rma_add_purchase.py @@ -0,0 +1,116 @@ +# © 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 + + +class RmaAddPurchase(models.TransientModel): + _name = 'rma_add_purchase' + _description = 'Wizard to add rma lines' + + @api.model + def default_get(self, fields): + res = super(RmaAddPurchase, 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['purchase_id'] = False + res['purchase_line_ids'] = False + return res + + rma_id = fields.Many2one( + comodel_name='rma.order', string='RMA Order', readonly=True) + partner_id = fields.Many2one( + comodel_name='res.partner', string='Partner', readonly=True) + purchase_id = fields.Many2one( + comodel_name='purchase.order', string='Order') + purchase_line_ids = fields.Many2many( + comodel_name='purchase.order.line', + relation='rma_add_purchase_add_line_rel', + column1='rma_add_purchase_id', column2='purchase_line_id', + readonly=False, string='Purchase Order Lines') + + def _prepare_rma_line_from_po_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 + else: + 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) + 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 a 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 = { + 'partner_id': self.partner_id.id, + 'purchase_order_line_id': line.id, + 'product_id': line.product_id.id, + 'origin': line.order_id.name, + 'uom_id': line.product_uom.id, + 'operation_id': operation.id, + 'product_qty': line.product_qty, + 'price_unit': line.currency_id._convert( + line.price_unit, line.currency_id, + self.env.user.company_id, fields.Date.today(), round=False), + 'rma_id': self.rma_id.id, + 'in_route_id': operation.in_route_id.id or route, + 'out_route_id': operation.out_route_id.id or route, + 'receipt_policy': operation.receipt_policy, + 'location_id': (operation.location_id.id or + operation.in_warehouse_id.lot_rma_id.id or + warehouse.lot_rma_id.id), + '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, + } + return data + + @api.model + def _get_rma_data(self): + data = { + 'date_rma': fields.Datetime.now(), + } + return data + + @api.model + def _get_existing_purchase_lines(self): + existing_purchase_lines = [] + for rma_line in self.rma_id.rma_line_ids: + existing_purchase_lines.append(rma_line.purchase_order_line_id) + return existing_purchase_lines + + @api.multi + def add_lines(self): + rma_line_obj = self.env['rma.order.line'] + existing_purchase_lines = self._get_existing_purchase_lines() + for line in self.purchase_line_ids: + # Load a PO line only once + if line not in existing_purchase_lines: + data = self._prepare_rma_line_from_po_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_purchase/wizards/rma_add_purchase.xml b/rma_purchase/wizards/rma_add_purchase.xml new file mode 100644 index 00000000..e3337989 --- /dev/null +++ b/rma_purchase/wizards/rma_add_purchase.xml @@ -0,0 +1,74 @@ + + + + + rma.add.purchase + rma_add_purchase + +
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + Add Purchase Order + ir.actions.act_window + rma_add_purchase + rma.order + form + form + new + + + + + + rma.order.line.supplier.form + rma.order + + + +