diff --git a/mrp_repair_refurbish/README.rst b/mrp_repair_refurbish/README.rst new file mode 100644 index 000000000..c4e70bd68 --- /dev/null +++ b/mrp_repair_refurbish/README.rst @@ -0,0 +1,78 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +==================== +MRP Repair Refurbish +==================== + +This module adds the ability to obtain refurbished product as a consequence +of the repair of a product that was defective. + + +Configuration +============= + +#. For each product that can potentially be refurbished, define the + refurbished version in the product form. + +#. A default 'Refurbished' virtual location is created during module install, + and proposed by default on each product. + + +Usage +===== + +#. Create an MRP repair. +#. Indicate a product to repair, If the product has a proposed refurbished + version, it will be proposed to be used. The destination location +#. Add operations if needed. +#. Complete the repair. + +The initial product will be moved to the 'Scrap' location, and the +refurbished product will be moved from a 'Refurbish' location to the desired +destination location. + +The components that were added to the repair order will be moved to the +'Refurbish' location. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/129/9.0 + + +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 +* Lois Rilo + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/mrp_repair_refurbish/__init__.py b/mrp_repair_refurbish/__init__.py new file mode 100644 index 000000000..3e4baab2f --- /dev/null +++ b/mrp_repair_refurbish/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2016 Cyril Gaudin (Camptocamp) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/mrp_repair_refurbish/__openerp__.py b/mrp_repair_refurbish/__openerp__.py new file mode 100644 index 000000000..b43669dde --- /dev/null +++ b/mrp_repair_refurbish/__openerp__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# © 2016 Cyril Gaudin (Camptocamp) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "MRP Repair Refurbish", + "summary": "Create refurbished products during repair", + "version": "9.0.1.0.1", + "category": "Manufacturing", + "website": "https://github.com/OCA/manufacture", + "author": "Eficent, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + 'mrp_repair', + ], + "data": [ + "views/mrp_repair_view.xml", + "data/stock_data.xml", + "views/product_template_view.xml", + "views/product_product_view.xml", + ], +} diff --git a/mrp_repair_refurbish/data/stock_data.xml b/mrp_repair_refurbish/data/stock_data.xml new file mode 100644 index 000000000..0bba092e2 --- /dev/null +++ b/mrp_repair_refurbish/data/stock_data.xml @@ -0,0 +1,26 @@ + + + + + + Refurbish + + production + + + + + + + + property_stock_refurbish + + + + + + diff --git a/mrp_repair_refurbish/models/__init__.py b/mrp_repair_refurbish/models/__init__.py new file mode 100644 index 000000000..0a28d40af --- /dev/null +++ b/mrp_repair_refurbish/models/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# © 2016 Cyril Gaudin (Camptocamp) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import product_product +from . import product_template +from . import mrp_repair diff --git a/mrp_repair_refurbish/models/mrp_repair.py b/mrp_repair_refurbish/models/mrp_repair.py new file mode 100644 index 000000000..2a778aeae --- /dev/null +++ b/mrp_repair_refurbish/models/mrp_repair.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# © 2016 Cyril Gaudin (Camptocamp) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp.osv import orm +from openerp import api, fields, models + + +class mrp_repair(orm.Model): + """To inherit using old api is needed here in order to be able to modify + the onchange method for `product_id`. + NOTE: This should be moved to new api in v10, when the standard is also + migrated. + """ + _inherit = 'mrp.repair' + + def onchange_product_id(self, cr, uid, ids, product_id=None): + res = super(mrp_repair, self).onchange_product_id( + cr, uid, ids, product_id=product_id) + product = self.pool['product.product'].browse(cr, uid, product_id) + res['value']['to_refurbish'] = True if \ + product.refurbish_product_id else False + return res + + +class MrpRepair(models.Model): + _inherit = 'mrp.repair' + + to_refurbish = fields.Boolean('To refurbish') + refurbish_location_dest_id = fields.Many2one( + string='Refurbished Delivery Location', comodel_name='stock.location') + refurbish_product_id = fields.Many2one( + string='Refurbished product', comodel_name='product.product') + refurbish_lot_id = fields.Many2one( + string='Refurbished Lot', comodel_name='stock.production.lot') + refurbish_move_id = fields.Many2one( + string='Refurbished Inventory Move', comodel_name='stock.move') + product_id = fields.Many2one(comodel_name='product.product') + + @api.onchange('to_refurbish', 'product_id') + def _onchange_to_refurbish(self): + if self.to_refurbish: + self.refurbish_product_id = self.product_id.refurbish_product_id + self.refurbish_location_dest_id = self.location_dest_id + self.location_dest_id = self.product_id.property_stock_refurbish + else: + self.location_dest_id = self.refurbish_location_dest_id + self.refurbish_product_id = False + self.refurbish_location_dest_id = False + + @api.multi + def action_repair_done(self): + res = super(MrpRepair, self).action_repair_done() + for repair in self: + if repair.to_refurbish: + move = self.env['stock.move'].create({ + 'name': repair.name, + 'product_id': repair.refurbish_product_id.id, + 'product_uom': repair.product_uom.id or + repair.refurbish_product_id.uom_id.id, + 'product_uom_qty': repair.product_qty, + 'partner_id': repair.address_id and + repair.address_id.id or False, + 'location_id': repair.location_dest_id.id, + 'location_dest_id': repair.refurbish_location_dest_id.id, + 'restrict_lot_id': repair.refurbish_lot_id.id, + }) + move.action_done() + repair.refurbish_move_id = move.id + return res + + +class mrp_repair_line(orm.Model): + """To inherit using old api is needed here in order to be able to modify + the onchange method for `type`. + NOTE: This should be moved to new api in v10, when the standard is also + migrated. + """ + _inherit = 'mrp.repair.line' + + def onchange_operation_type(self, cr, uid, ids, type, guarantee_limit, + company_id=False, context=None): + res = super(mrp_repair_line, self).onchange_operation_type( + cr, uid, ids, type, guarantee_limit, company_id=company_id, + context=context) + + if (type == 'add' and 'to_refurbish' in context and + context['to_refurbish']): + res['value']['location_dest_id'] = context[ + 'refurbish_location_dest_id'] + elif (type == 'add' and 'to_refurbish' in context and not + context['to_refurbish']): + scrap_location_ids = self.pool['stock.location'].search(cr, uid, [ + ('usage', '=', 'customer')], context=context) + res['value']['location_dest_id'] = scrap_location_ids[0] + return res diff --git a/mrp_repair_refurbish/models/product_product.py b/mrp_repair_refurbish/models/product_product.py new file mode 100644 index 000000000..de6462618 --- /dev/null +++ b/mrp_repair_refurbish/models/product_product.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# © 2017 Eficent Business and IT Consulting Services S.L. +# © 2016 Cyril Gaudin (Camptocamp) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import fields, models + + +class ProductProduct(models.Model): + _inherit = 'product.product' + + refurbish_product_id = fields.Many2one( + comodel_name='product.product', string='Refurbished Product', + domain="[('type', '=', 'product')]") diff --git a/mrp_repair_refurbish/models/product_template.py b/mrp_repair_refurbish/models/product_template.py new file mode 100644 index 000000000..225b132b5 --- /dev/null +++ b/mrp_repair_refurbish/models/product_template.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# © 2016 Cyril Gaudin (Camptocamp) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = 'product.template' + + refurbish_product_id = fields.Many2one( + comodel_name='product.product', string='Refurbished Product', + compute='_compute_refurbish_product', + inverse='_set_refurbish_product', search='_search_refurbish_product', + domain="[('type', '=', 'product')]") + + property_stock_refurbish = fields.Many2one( + comodel_name='stock.location', string="Refurbish Location", + company_dependent=True, domain=[('usage', 'like', 'production')], + help="This stock location will be used, instead of the " + "default one, as the source location for " + "stock moves generated by repair orders when refurbishing takes " + "place.") + + @api.depends('product_variant_ids', + 'product_variant_ids.refurbish_product_id') + def _compute_refurbish_product(self): + unique_variants = self.filtered(lambda template: + len(template.product_variant_ids) == 1) + for template in unique_variants: + template.refurbish_product_id = \ + template.product_variant_ids.refurbish_product_id + for template in (self - unique_variants): + template.refurbish_product_id = False + + @api.one + def _set_refurbish_product(self): + if len(self.product_variant_ids) == 1: + self.product_variant_ids.refurbish_product_id = \ + self.refurbish_product_id + + def _search_refurbish_product(self, operator, value): + products = self.env['product.product'].search([ + ('refurbish_product_id', operator, value)], limit=None) + return [('id', 'in', products.mapped('product_tmpl_id').ids)] diff --git a/mrp_repair_refurbish/views/mrp_repair_view.xml b/mrp_repair_refurbish/views/mrp_repair_view.xml new file mode 100644 index 000000000..99e209be3 --- /dev/null +++ b/mrp_repair_refurbish/views/mrp_repair_view.xml @@ -0,0 +1,54 @@ + + + + + mrp.repair.tree + mrp.repair + + + + + + + + + + mrp.repair.form + mrp.repair + + + + + + + + + + + + + + {'default_product_uom_qty': product_qty, 'to_refurbish': to_refurbish, 'refurbish_location_dest_id': location_dest_id} + + + + + + mrp.repair.select + mrp.repair + + + + + + + + + + diff --git a/mrp_repair_refurbish/views/product_product_view.xml b/mrp_repair_refurbish/views/product_product_view.xml new file mode 100644 index 000000000..f418118fe --- /dev/null +++ b/mrp_repair_refurbish/views/product_product_view.xml @@ -0,0 +1,17 @@ + + + + + product.product.form + product.product + + + + + + + + + + + diff --git a/mrp_repair_refurbish/views/product_template_view.xml b/mrp_repair_refurbish/views/product_template_view.xml new file mode 100644 index 000000000..cafa2730b --- /dev/null +++ b/mrp_repair_refurbish/views/product_template_view.xml @@ -0,0 +1,31 @@ + + + + + product.template.product.form + product.template + + + + + + + + + + + + product.template.stock.property.form.inherit + product.template + + + + + + + + + +