diff --git a/rma/__openerp__.py b/rma/__openerp__.py index 80bc8f3f..c4e25162 100644 --- a/rma/__openerp__.py +++ b/rma/__openerp__.py @@ -11,10 +11,8 @@ 'in odoo', 'author': "Eficent", 'website': 'http://www.github.com/OCA/rma', - 'depends': ['account', 'stock', 'mail', - 'procurement'], - 'demo': [ - 'demo/stock_demo.xml', + 'depends': ['stock', 'mail', 'procurement'], + 'demo': ['demo/stock_demo.xml', ], 'data': ['security/rma.xml', 'security/ir.model.access.csv', diff --git a/rma/models/procurement.py b/rma/models/procurement.py index 6838c5d1..c8cd39db 100644 --- a/rma/models/procurement.py +++ b/rma/models/procurement.py @@ -18,8 +18,8 @@ class ProcurementOrder(models.Model): res['rma_line_id'] = line.id if line.delivery_address_id: res['partner_id'] = line.delivery_address_id.id - elif line.invoice_line_id.invoice_id.partner_id: - res['partner_id'] = line.invoice_id.partner_id.id + else: + res['partner_id'] = line.rma_id.partner_id.id return res diff --git a/rma/models/rma_operation.py b/rma/models/rma_operation.py index 87d271e0..5d3b230d 100644 --- a/rma/models/rma_operation.py +++ b/rma/models/rma_operation.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 openerp import api, fields, models class RmaOperation(models.Model): @@ -11,9 +11,9 @@ class RmaOperation(models.Model): @api.model def _default_warehouse_id(self): - company = self.env.user.company_id.id + company_id = self.env.user.company_id.id warehouse = self.env['stock.warehouse'].search( - [('company_id', '=', company)], limit=1) + [('company_id', '=', company_id)], limit=1) return warehouse @api.model @@ -44,16 +44,16 @@ class RmaOperation(models.Model): out_route_id = fields.Many2one( 'stock.location.route', string='Outbound Route', domain=[('rma_selectable', '=', True)]) - customer_to_supplier= fields.Boolean( + customer_to_supplier = fields.Boolean( 'The customer will send to the supplier', default=False) supplier_to_customer = fields.Boolean( 'The supplier will send to the customer', default=False) - in_warehouse_id = fields.Many2one('stock.warehouse', - string='Inbound Warehouse', - default=_default_warehouse_id) - out_warehouse_id = fields.Many2one('stock.warehouse', - string='Outbound Warehouse', - default=_default_warehouse_id) + in_warehouse_id = fields.Many2one( + comodel_name='stock.warehouse', string='Inbound Warehouse', + default=_default_warehouse_id) + out_warehouse_id = fields.Many2one( + comodel_name='stock.warehouse', string='Outbound Warehouse', + default=_default_warehouse_id) location_id = fields.Many2one( 'stock.location', 'Send To This Company Location') type = fields.Selection([ diff --git a/rma/models/rma_order.py b/rma/models/rma_order.py index e307b35c..28a9ff8d 100644 --- a/rma/models/rma_order.py +++ b/rma/models/rma_order.py @@ -2,12 +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 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): @@ -18,8 +13,7 @@ class RmaOrder(models.Model): def _get_default_type(self): if 'supplier' in self.env.context: return "supplier" - else: - return "customer" + return "customer" @api.multi def _compute_in_shipment_count(self): @@ -47,23 +41,21 @@ class RmaOrder(models.Model): self.ensure_one() self.line_count = len(self._get_valid_lines()) - name = fields.Char(string='Order Number', index=True, - readonly=True, - states={'progress': [('readonly', False)]}, - copy=False) + name = fields.Char( + string='Order Number', index=True, readonly=True, + states={'progress': [('readonly', False)]}, copy=False) type = fields.Selection( [('customer', 'Customer'), ('supplier', 'Supplier')], string="Type", required=True, default=_get_default_type, readonly=True) - reference = fields.Char(string='Reference', + reference = fields.Char(string='Partner Reference', help="The partner reference of this RMA order.") - comment = fields.Text('Additional Information', readonly=True, states={ 'draft': [('readonly', False)]}) state = fields.Selection([('draft', 'Draft'), ('to_approve', 'To Approve'), ('approved', 'Approved'), ('done', 'Done')], string='State', index=True, - default='draft') + default='draft') date_rma = fields.Datetime(string='Order Date', index=True, copy=False) partner_id = fields.Many2one('res.partner', string='Partner', required=True, readonly=True, @@ -165,8 +157,7 @@ class RmaOrder(models.Model): @api.multi def action_rma_draft(self): - for rec in self: - rec.state = 'draft' + self.write({'state': 'draft'}) return True @api.multi @@ -177,12 +168,13 @@ class RmaOrder(models.Model): @api.multi def action_rma_done(self): - for rec in self: - rec.state = 'done' - return True + self.write({'state': 'done'}) + return True @api.multi def _get_valid_lines(self): + """:return: A recordset of rma lines. + """ self.ensure_one() return self.rma_line_ids diff --git a/rma/models/rma_order_line.py b/rma/models/rma_order_line.py index a2847bb7..8eb1f917 100644 --- a/rma/models/rma_order_line.py +++ b/rma/models/rma_order_line.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 openerp import api, fields, models from openerp.addons import decimal_precision as dp import operator ops = {'=': operator.eq, @@ -90,8 +90,8 @@ class RmaOrderLine(models.Model): rec.qty_to_deliver = 0.0 if rec.delivery_policy == 'ordered': rec.qty_to_deliver = rec.product_qty - rec.qty_delivered - elif self.delivery_policy == 'received': - self.qty_to_deliver = rec.qty_received - rec.qty_delivered + elif rec.delivery_policy == 'received': + rec.qty_to_deliver = rec.qty_received - rec.qty_delivered @api.multi @api.depends('move_ids', 'move_ids.state', 'type') @@ -180,7 +180,7 @@ class RmaOrderLine(models.Model): readonly=True, states={"new": [("readonly", False)]}, ) product_qty = fields.Float( - string='Ordered Qty', copy=False, + string='Ordered Qty', copy=False, default=1.0, digits=dp.get_precision('Product Unit of Measure')) uom_id = fields.Many2one('product.uom', string='Unit of Measure', required=True) @@ -197,8 +197,8 @@ class RmaOrderLine(models.Model): out_shipment_count = fields.Integer(compute=_compute_out_shipment_count, string='# of Deliveries', default=0) move_ids = fields.One2many('stock.move', 'rma_line_id', - string='Stock Moves', readonly=True - , copy=False) + string='Stock Moves', readonly=True, + copy=False) reference_move_id = fields.Many2one(comodel_name='stock.move', string='Originating stock move', readonly=True, copy=False) @@ -243,7 +243,8 @@ class RmaOrderLine(models.Model): default=_default_location_id) customer_rma_id = fields.Many2one( 'rma.order.line', string='Customer RMA line', ondelete='cascade') - supplier_rma_line_ids = fields.One2many('rma.order.line', 'customer_rma_id') + supplier_rma_line_ids = fields.One2many( + 'rma.order.line', 'customer_rma_id') supplier_address_id = fields.Many2one( 'res.partner', readonly=True, states={'draft': [('readonly', False)]}, @@ -408,10 +409,11 @@ class RmaOrderLine(models.Model): @api.multi def action_view_procurements(self): - action = self.env.ref('procurement.procurement_order_action_exceptions') + action = self.env.ref( + 'procurement.procurement_order_action_exceptions') result = action.read()[0] procurements = self.procurement_ids.filtered( - lambda p: p.state == 'exception').ids + lambda p: p.state == 'exception').ids # choose the view_mode accordingly if len(procurements) != 1: result['domain'] = "[('id', 'in', " + \ diff --git a/rma/models/stock.py b/rma/models/stock.py index cc70c174..c8fdaf88 100644 --- a/rma/models/stock.py +++ b/rma/models/stock.py @@ -10,28 +10,29 @@ class StockPicking(models.Model): @api.multi def action_assign(self): + """When you try to bring back a product from a customer location, + it may happen that there is no quants available to perform the + picking.""" + res = super(StockPicking, self).action_assign() for picking in self: for move in picking.move_lines: - if len(move.rma_line_id): - if move.state in ('confirmed', 'waiting', 'assigned') \ - and move.location_id.usage in ( - 'supplier', 'customer'): - move.force_assign() - return super(StockPicking, self).action_assign() + if (move.rma_line_id and move.state == 'confirmed' and + move.location_id.usage == 'customer'): + move.force_assign() + return res class StockMove(models.Model): - _inherit = "stock.move" - rma_line_id = fields.Many2one('rma.order.line', string='RMA', + rma_line_id = fields.Many2one('rma.order.line', string='RMA line', ondelete='restrict') @api.model def create(self, vals): - if vals.get('procurement_id', False): + if vals.get('procurement_id'): procurement = self.env['procurement.order'].browse( vals['procurement_id']) - if procurement.rma_line_id and procurement.rma_line_id.id: + if procurement.rma_line_id: vals['rma_line_id'] = procurement.rma_line_id.id return super(StockMove, self).create(vals) diff --git a/rma/models/stock_warehouse.py b/rma/models/stock_warehouse.py index 3d465a60..26ff4b08 100644 --- a/rma/models/stock_warehouse.py +++ b/rma/models/stock_warehouse.py @@ -2,11 +2,10 @@ # © 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 StockWarehouse(models.Model): - _inherit = "stock.warehouse" lot_rma_id = fields.Many2one('stock.location', 'RMA Location') diff --git a/rma/tests/test_rma.py b/rma/tests/test_rma.py index 6ae75d89..95bbe572 100644 --- a/rma/tests/test_rma.py +++ b/rma/tests/test_rma.py @@ -13,7 +13,7 @@ class TestRma(common.TransactionCase): super(TestRma, self).setUp() self.rma_make_picking = self.env['rma_make_picking.wizard'] - self.rma_add_invoice = self.env['rma_add_invoice'] + 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'] @@ -29,59 +29,56 @@ class TestRma(common.TransactionCase): self.product_2.write({'rma_operation_id': self.rma_op_id.id}) self.product_3.write({'rma_operation_id': self.rma_op_id.id}) self.partner_id = self.env.ref('base.res_partner_12') - - self.customer_location_id = self.env.ref( - 'stock.stock_location_customers' - ) - uom_unit = self.env.ref('product.product_uom_unit') - sale_values = self._prepare_sale() - self.sale_order = self.env['sale.order'].create(sale_values) - invoice_id = self.sale_order.action_invoice_create()[0] - self.invoice = self.env['account.invoice'].browse(invoice_id) - # Create the RMA from the invoice + 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.product_uom_id = self.env.ref('product.product_uom_unit') + self.product_uom_id = self.env.ref('product.product_uom_unit') + moves = [] + products2move = [(self.product_1, 3), (self.product_2, 5), + (self.product_3, 2)] + for item in products2move: + move_values = self._prepare_move(item[0], item[1]) + moves.append(self.env['stock.move'].create(move_values)) + # Create the RMA from the stock_move self.rma_id = self.rma.create( { 'reference': '0001', 'type': 'customer', 'partner_id': self.env.ref('base.res_partner_2').id }) - - for line in self.invoice.invoice_line_ids: - data = self.rma_add_invoice.with_context( - {'invoice_id': self.invoice.id} - )._prepare_rma_line_from_inv_line(line) - data.update(rma_id=self.rma_id.id) + for move in moves: + data = self.rma_add_stock_move.with_context( + {'stock_move_id': move.id} + )._prepare_rma_line_from_stock_move(move) + operation = self.rma_op.browse(data['operation_id']) + data.update( + rma_id=self.rma_id.id, + receipt_policy=operation.receipt_policy, + delivery_policy=operation.delivery_policy, + in_warehouse_id=operation.in_warehouse_id.id, + out_warehouse_id=operation.out_warehouse_id.id, + location_id=self.stock_rma_location.id, + in_route_id=operation.in_route_id.id, + out_route_id=operation.out_route_id.id) self.rma_line.create(data) - #approve the RMA + # approve the RMA self.rma_id.action_rma_to_approve() self.rma_id.action_rma_approve() - def _prepare_sale(self): - values = { - 'state': 'done', - 'partner_id': self.env.ref('base.res_partner_2').id, - 'pricelist_id': self.env.ref('product.list0').id, - 'warehouse_id': self.env.ref('stock.warehouse0').id, - 'partner_invoice_id': self.env.ref('base.res_partner_2').id, - 'partner_shipping_id': self.env.ref('base.res_partner_2').id, - 'picking_policy': 'direct', - 'order_line': [ - (0, False, { - 'name': product.name, - 'product_id': product.id, - 'product_uom_qty': qty, - 'qty_delivered': qty, - 'product_uom': self.uom_unit.id, - 'price_unit': product.list_price - - }) for product, qty in [ - (self.product_1, 3), - (self.product_2, 5), - (self.product_3, 2), - ] - ] + def _prepare_move(self, product, qty): + res = { + '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': self.stock_location.id, + 'location_dest_id': self.customer_location.id, } - return values + return res def test_00_receive_items(self): wizard = self.rma_make_picking.with_context({ @@ -93,8 +90,7 @@ class TestRma(common.TransactionCase): procurements = wizard._create_picking() group_ids = set([proc.group_id.id for proc in procurements if proc.group_id]) - domain = "[('group_id','in',[" + ','.join( - map(str, list(group_ids))) + "])]" + domain = [('group_id', 'in', list(group_ids))] picking = self.stockpicking.search(domain) self.assertEquals(len(picking), 1, "Incorrect number of pickings created") @@ -102,6 +98,7 @@ class TestRma(common.TransactionCase): self.assertEquals(len(moves), 3, "Incorrect number of moves created") for line in self.rma_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, @@ -110,10 +107,7 @@ class TestRma(common.TransactionCase): "Wrong qty outgoing") self.assertEquals(line.qty_delivered, 0, "Wrong qty delivered") - self.assertEquals(line.qty_to_refund, 0, - "Wrong qty to refund") - self.assertEquals(line.qty_to_refunded, 0, - "Wrong qty refunded") + # product specific if line.product_id == self.product_1: self.assertEquals(line.qty_to_receive, 3, "Wrong qty to receive") @@ -129,8 +123,8 @@ class TestRma(common.TransactionCase): "Wrong qty to receive") self.assertEquals(line.qty_incoming, 2, "Wrong qty incoming") - pickings.action_assign() - pickings.do_transfer() + picking.action_assign() + picking.do_transfer() for line in self.rma_id.rma_line_ids: self.assertEquals(line.qty_to_receive, 0, "Wrong qty to_receive") @@ -140,10 +134,6 @@ class TestRma(common.TransactionCase): "Wrong qty outgoing") self.assertEquals(line.qty_delivered, 0, "Wrong qty delivered") - self.assertEquals(line.qty_to_refund, 0, - "Wrong qty to refund") - self.assertEquals(line.qty_to_refunded, 0, - "Wrong qty refunded") if line.product_id == self.product_1: self.assertEquals(line.qty_received, 3, "Wrong qty received") @@ -169,12 +159,12 @@ class TestRma(common.TransactionCase): procurements = wizard._create_picking() group_ids = set([proc.group_id.id for proc in procurements if proc.group_id]) - domain = "[('group_id','in',[" + ','.join( - map(str, list(group_ids))) + "])]" - picking = self.stockpicking.search(domain) - self.assertEquals(len(picking), 1, + domain = [('group_id', 'in', list(group_ids))] + pickings = self.stockpicking.search(domain) + self.assertEquals(len(pickings), 2, "Incorrect number of pickings created") - moves = picking.move_lines + picking_out = pickings[1] + moves = picking_out.move_lines self.assertEquals(len(moves), 3, "Incorrect number of moves created") for line in self.rma_id.rma_line_ids: @@ -184,10 +174,6 @@ class TestRma(common.TransactionCase): "Wrong qty incoming") self.assertEquals(line.qty_delivered, 0, "Wrong qty delivered") - self.assertEquals(line.qty_to_refund, 0, - "Wrong qty to refund") - self.assertEquals(line.qty_to_refunded, 0, - "Wrong qty refunded") if line.product_id == self.product_1: self.assertEquals(line.qty_to_deliver, 3, "Wrong qty to deliver") @@ -209,8 +195,8 @@ class TestRma(common.TransactionCase): "Wrong qty to deliver") self.assertEquals(line.qty_outgoing, 2, "Wrong qty outgoing") - pickings.action_assign() - pickings.do_transfer() + picking_out.action_assign() + picking_out.do_transfer() for line in self.rma_id.rma_line_ids: self.assertEquals(line.qty_to_receive, 0, "Wrong qty to receive") @@ -218,10 +204,6 @@ class TestRma(common.TransactionCase): "Wrong qty incoming") self.assertEquals(line.qty_to_deliver, 0, "Wrong qty to deliver") - self.assertEquals(line.qty_to_refund, 0, - "Wrong qty to refund") - self.assertEquals(line.qty_to_refunded, 0, - "Wrong qty refunded") self.assertEquals(line.qty_outgoing, 0, "Wrong qty outgoing") if line.product_id == self.product_1: diff --git a/rma/views/rma_order_line_view.xml b/rma/views/rma_order_line_view.xml index 649552f4..29d8797d 100644 --- a/rma/views/rma_order_line_view.xml +++ b/rma/views/rma_order_line_view.xml @@ -5,7 +5,7 @@ rma.order.line.tree rma.order.line - @@ -27,7 +27,7 @@ rma.order.line.supplier.tree rma.order.line - @@ -48,7 +48,7 @@ rma.order.line.supplier.form rma.order.line -
+
@@ -171,7 +171,7 @@ rma.order.line.form rma.order.line - +
diff --git a/rma/wizards/rma_add_stock_move.py b/rma/wizards/rma_add_stock_move.py index e5007085..64ce435f 100644 --- a/rma/wizards/rma_add_stock_move.py +++ b/rma/wizards/rma_add_stock_move.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 models, fields, exceptions, api, _ +from openerp import models, fields, api, _ from openerp.exceptions import ValidationError @@ -100,7 +100,8 @@ class RmaAddStockMove(models.TransientModel): rma_line_obj.with_context( default_rma_id=self.rma_id.id).create(data) else: - data = self._prepare_rma_line_from_stock_move(sm, lot=False) + data = self._prepare_rma_line_from_stock_move( + sm, lot=False) rma_line_obj.with_context( default_rma_id=self.rma_id.id).create(data) return {'type': 'ir.actions.act_window_close'} diff --git a/rma/wizards/rma_make_picking.py b/rma/wizards/rma_make_picking.py index 80f2f5ba..c81aa6a5 100644 --- a/rma/wizards/rma_make_picking.py +++ b/rma/wizards/rma_make_picking.py @@ -3,7 +3,7 @@ # 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 models, fields, api, _ from openerp.exceptions import ValidationError from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DT_FORMAT import openerp.addons.decimal_precision as dp @@ -45,7 +45,7 @@ class RmaMakePicking(models.TransientModel): items = [] lines = rma_line_obj.browse(rma_line_ids) if len(lines.mapped('partner_id')) > 1: - raise exceptions.Warning( + raise ValidationError( _('Only RMA lines from the same partner can be processed at ' 'the same time')) for line in lines: @@ -71,12 +71,13 @@ class RmaMakePicking(models.TransientModel): @api.model def _get_address(self, item): if item.line_id.delivery_address_id: - delivery_address = item.line_id.delivery_address_id or \ - item.line_id.partner_id + delivery_address = item.line_id.delivery_address_id elif item.line_id.customer_to_supplier: delivery_address = item.line_id.supplier_address_id + elif item.line_id.partner_id: + delivery_address = item.line_id.partner_id else: - raise exceptions.Warning('Unknown delivery address') + raise ValidationError('Unknown delivery address') return delivery_address def _get_address_location(self, delivery_address_id, type): @@ -103,9 +104,9 @@ class RmaMakePicking(models.TransientModel): warehouse = line.out_warehouse_id route = line.out_route_id if not route: - raise exceptions.Warning("No route specified") + raise ValidationError("No route specified") if not warehouse: - raise exceptions.Warning("No warehouse specified") + raise ValidationError("No warehouse specified") procurement_data = { 'name': line.rma_id.name, 'group_id': group.id, @@ -147,16 +148,16 @@ class RmaMakePicking(models.TransientModel): for item in self.item_ids: line = item.line_id if line.state != 'approved': - raise exceptions.Warning( + raise ValidationError( _('RMA %s is not approved') % line.rma_id.name) if line.receipt_policy == 'no' and picking_type == \ 'incoming': - raise exceptions.Warning( + raise ValidationError( _('No shipments needed for this operation')) if line.delivery_policy == 'no' and picking_type == \ 'outgoing': - raise exceptions.Warning( + raise ValidationError( _('No deliveries needed for this operation')) procurement = self._create_procurement(item, picking_type) procurement_list.append(procurement) @@ -191,7 +192,7 @@ class RmaMakePicking(models.TransientModel): if proc.group_id: groups.append(proc.group_id.id) if len(groups): - pickings =self.env['stock.picking'].search( + pickings = self.env['stock.picking'].search( [('group_id', 'in', groups)]) action = self._get_action(pickings, procurements) diff --git a/rma/wizards/rma_order_line_make_supplier_rma.py b/rma/wizards/rma_order_line_make_supplier_rma.py index 79137bd5..2f258c68 100644 --- a/rma/wizards/rma_order_line_make_supplier_rma.py +++ b/rma/wizards/rma_order_line_make_supplier_rma.py @@ -72,7 +72,7 @@ class RmaLineMakeSupplierRma(models.TransientModel): @api.model def _prepare_supplier_rma_line(self, rma, item): operation = self.env['rma.operation'].search( - [('type', '=', 'supplier')], limit=1) + [('type', '=', 'supplier')], limit=1) return { 'origin': item.line_id.rma_id.name, 'delivery_address_id':