diff --git a/addons/repair/__manifest__.py b/addons/repair/__manifest__.py index 5a8fd994e57..5c361977c2e 100644 --- a/addons/repair/__manifest__.py +++ b/addons/repair/__manifest__.py @@ -30,6 +30,7 @@ The following topics are covered by this module: 'views/stock_move_views.xml', 'views/repair_views.xml', 'views/stock_lot_views.xml', + 'views/stock_picking_views.xml', 'report/repair_reports.xml', 'report/repair_templates_repair_order.xml', 'data/ir_sequence_data.xml', diff --git a/addons/repair/models/__init__.py b/addons/repair/models/__init__.py index 4bebbca6293..af19f542e98 100644 --- a/addons/repair/models/__init__.py +++ b/addons/repair/models/__init__.py @@ -2,6 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import repair +from . import stock_picking from . import stock_traceability from . import stock_lot from . import account_move diff --git a/addons/repair/models/repair.py b/addons/repair/models/repair.py index 4e53e22fa23..7da6170858c 100644 --- a/addons/repair/models/repair.py +++ b/addons/repair/models/repair.py @@ -110,7 +110,16 @@ class Repair(models.Model): 'res.company', 'Company', readonly=True, required=True, index=True, default=lambda self: self.env.company) - sale_order_id = fields.Many2one('sale.order', 'Sale Order', copy=False, help="Sale Order from which the product to be repaired comes from.") + sale_order_id = fields.Many2one( + 'sale.order', 'Sale Order', check_company=True, + copy=False, help="Sale Order from which the product to be repaired comes from.") + picking_id = fields.Many2one( + 'stock.picking', 'Return', check_company=True, + domain="[('is_repairable', '!=', False), ('company_id', '=', company_id)]", + copy=False, help="Return Order from which the product to be repaired comes from.") + is_returned = fields.Boolean( + "Returned", compute='_compute_is_returned', + help="True if this repair is linked to a Return Order and the order is 'Done'. False otherwise.") tag_ids = fields.Many2many('repair.tags', string="Tags") invoiced = fields.Boolean('Invoiced', copy=False, readonly=True) repaired = fields.Boolean('Repaired', copy=False, readonly=True) @@ -127,6 +136,12 @@ class Repair(models.Model): if order.partner_id: order.default_address_id = order.partner_id.address_get(['contact'])['contact'] + @api.depends('picking_id', 'picking_id.state') + def _compute_is_returned(self): + self.is_returned = False + returned = self.filtered(lambda r: r.picking_id and r.picking_id.state == 'done') + returned.is_returned = True + @api.depends('operations.price_subtotal', 'invoice_method', 'fees_lines.price_subtotal', 'pricelist_id.currency_id') def _amount_untaxed(self): for order in self: diff --git a/addons/repair/models/stock_picking.py b/addons/repair/models/stock_picking.py new file mode 100644 index 00000000000..b5947d57e17 --- /dev/null +++ b/addons/repair/models/stock_picking.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, api, fields, models + + +class PickingType(models.Model): + _inherit = 'stock.picking.type' + + is_repairable = fields.Boolean( + 'Create Repair Orders from Returns', + compute='_compute_is_repairable', store=True, readonly=False, + help="If ticked, you will be able to directly create repair orders from a return.") + return_type_of_ids = fields.One2many('stock.picking.type', 'return_picking_type_id') + + @api.depends('return_type_of_ids', 'code') + def _compute_is_repairable(self): + for picking_type in self: + if not(picking_type.code == 'incoming' and picking_type.return_type_of_ids): + picking_type.is_repairable = False + + +class Picking(models.Model): + _inherit = 'stock.picking' + + is_repairable = fields.Boolean(related='picking_type_id.is_repairable') + repair_ids = fields.One2many('repair.order', 'picking_id') + nbr_repairs = fields.Integer('Number of repairs linked to this picking', compute='_compute_nbr_repairs') + + @api.depends('repair_ids') + def _compute_nbr_repairs(self): + for picking in self: + picking.nbr_repairs = len(picking.repair_ids) + + def action_repair_return(self): + self.ensure_one() + ctx = self.env.context.copy() + ctx.update({ + 'default_location_id': self.location_dest_id.id, + 'default_picking_id': self.id, + 'default_partner_id': self.partner_id and self.partner_id.id or False, + }) + return { + 'name': _('Create Repair'), + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'res_model': 'repair.order', + 'view_id': self.env.ref('repair.view_repair_order_form').id, + 'context': ctx, + } + + def action_view_repairs(self): + if self.repair_ids: + action = { + 'res_model': 'repair.order', + 'type': 'ir.actions.act_window', + } + if len(self.repair_ids) == 1: + action.update({ + 'view_mode': 'form', + 'res_id': self.repair_ids[0].id, + }) + else: + action.update({ + 'name': _('Repair Orders'), + 'view_mode': 'tree,form', + 'domain': [('id', 'in', self.repair_ids.ids)], + }) + return action diff --git a/addons/repair/tests/test_repair.py b/addons/repair/tests/test_repair.py index ec7ef4f59f7..2cc9f6154af 100644 --- a/addons/repair/tests/test_repair.py +++ b/addons/repair/tests/test_repair.py @@ -321,3 +321,25 @@ class TestRepair(AccountTestInvoicingCommon): # tax02 should not be present since it belongs to the second company. self.assertEqual(repair_order.operations.tax_id, tax01) self.assertEqual(repair_order.fees_lines.tax_id, tax01) + + def test_repair_return(self): + """Tests functionality of creating a repair directly from a return picking, + i.e. repair can be made and defaults to appropriate return values. """ + # test return + picking_form = Form(self.env['stock.picking']) + picking_form.picking_type_id = self.stock_warehouse.return_type_id + picking_form.partner_id = self.res_partner_1 + picking_form.location_dest_id = self.stock_location_14 + return_picking = picking_form.save() + + # create repair + res_dict = return_picking.action_repair_return() + repair_form = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])) + repair_form.product_id = self.product_product_3 + repair = repair_form.save() + + # test that the resulting repairs are correctly created + self.assertEqual(len(return_picking.repair_ids), 1, "A repair order should have been created and linked to original return.") + for repair in return_picking.repair_ids: + self.assertEqual(repair.location_id, return_picking.location_dest_id, "Repair location should have defaulted to return destination location") + self.assertEqual(repair.partner_id, return_picking.partner_id, "Repair customer should have defaulted to return customer") diff --git a/addons/repair/views/repair_views.xml b/addons/repair/views/repair_views.xml index 078fb9f3e1f..777566424a0 100644 --- a/addons/repair/views/repair_views.xml +++ b/addons/repair/views/repair_views.xml @@ -6,7 +6,7 @@ repair.tree repair.order - + @@ -18,6 +18,8 @@ + + @@ -84,6 +86,7 @@ + @@ -280,6 +283,7 @@ + diff --git a/addons/repair/views/stock_picking_views.xml b/addons/repair/views/stock_picking_views.xml new file mode 100644 index 00000000000..bb5f5419590 --- /dev/null +++ b/addons/repair/views/stock_picking_views.xml @@ -0,0 +1,36 @@ + + + + stock.picking.type.inherit.repair + stock.picking.type + + + + + + + + + + + + + stock.picking.form.inherit.repair + stock.picking + + + + + + + + + diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml index 8147001f177..18fef14f62c 100644 --- a/addons/stock/views/stock_picking_views.xml +++ b/addons/stock/views/stock_picking_views.xml @@ -71,7 +71,7 @@ - +