In a few words, it allows to send components to a subcontractor partner and receive a finished product. The production is managed through classical manufacturing orders where the raw and finished location is the subcontracting location. When creating a receipt picking for a subcontractor partner, the location_id of the moves will be set to the subcontracting locations by using the property_stock_customer and property_stock_supplier of the partner. An override of _action_confirm will create the manufacturing order. When a subcontracted bom contains tracking, the produce wizard is available from the picking to record which lots were produced/consumed. New type on the BoM: subcontract New type on res.partner: subcontactor New location per company (we still own the components stored at the subcontractor so they're still valued) New routes created to resupply the subcontracting location on order or not (through a reordering rule). Override of res.partner to set the property_stock_customer/supplier on subcontactor partners. Proper tests were added too. Joint work with: Arnaud Baes <arb@odoo.com> task 1831382
42 lines
1.8 KiB
Python
42 lines
1.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from collections import defaultdict
|
|
|
|
from odoo import models, _
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class StockMove(models.Model):
|
|
_inherit = 'stock.move'
|
|
|
|
def _get_subcontract_bom(self):
|
|
self.ensure_one()
|
|
bom = self.env['mrp.bom']._bom_subcontract_find(
|
|
product=self.product_id,
|
|
picking_type=self.picking_type_id,
|
|
company_id=self.company_id.id,
|
|
bom_type='subcontract',
|
|
subcontractor=self.picking_id.partner_id,
|
|
)
|
|
return bom
|
|
|
|
def _action_confirm(self, merge=True, merge_into=False):
|
|
res = super(StockMove, self)._action_confirm(merge=merge, merge_into=merge_into)
|
|
subcontract_details_per_picking = defaultdict(list)
|
|
for move in res:
|
|
if not move.picking_id:
|
|
continue
|
|
if not move.picking_id._is_subcontract():
|
|
continue
|
|
bom = move._get_subcontract_bom()
|
|
if not bom:
|
|
error_message = _('Please define a BoM of type subcontracting for the product "%s". If you don\'t want to subcontract the product "%s", do not select a partner of type subcontractor.')
|
|
error_message += '\n\n'
|
|
error_message += _('If there is well a BoM of type subcontracting defined, check if you have set the correct subcontractors on it.')
|
|
raise UserError(error_message % (move.product_id.name, move.product_id.name))
|
|
subcontract_details_per_picking[move.picking_id].append((move, bom))
|
|
for picking, subcontract_details in subcontract_details_per_picking.items():
|
|
picking._subcontracted_produce(subcontract_details)
|
|
return res
|