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 @@
-
+