224 lines
10 KiB
Python
224 lines
10 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||
|
|
||
|
from odoo import api, fields, models, _
|
||
|
|
||
|
|
||
|
class StockWarehouse(models.Model):
|
||
|
_inherit = 'stock.warehouse'
|
||
|
|
||
|
subcontracting_to_resupply = fields.Boolean(
|
||
|
'Resupply Subcontractors', default=True)
|
||
|
subcontracting_mto_pull_id = fields.Many2one(
|
||
|
'stock.rule', 'Subcontracting MTO Rule')
|
||
|
subcontracting_pull_id = fields.Many2one(
|
||
|
'stock.rule', 'Subcontracting MTS Rule'
|
||
|
)
|
||
|
|
||
|
subcontracting_route_id = fields.Many2one('stock.route', 'Resupply Subcontractor', ondelete='restrict')
|
||
|
|
||
|
subcontracting_type_id = fields.Many2one(
|
||
|
'stock.picking.type', 'Subcontracting Operation Type',
|
||
|
domain=[('code', '=', 'mrp_operation')])
|
||
|
subcontracting_resupply_type_id = fields.Many2one(
|
||
|
'stock.picking.type', 'Subcontracting Resupply Operation Type',
|
||
|
domain=[('code', '=', 'outgoing')])
|
||
|
|
||
|
@api.model_create_multi
|
||
|
def create(self, vals_list):
|
||
|
res = super().create(vals_list)
|
||
|
res._update_subcontracting_locations_rules()
|
||
|
# if new warehouse has resupply enabled, enable global route
|
||
|
if any([vals.get('subcontracting_to_resupply', False) for vals in vals_list]):
|
||
|
res._update_global_route_resupply_subcontractor()
|
||
|
return res
|
||
|
|
||
|
def write(self, vals):
|
||
|
res = super().write(vals)
|
||
|
# if all warehouses have resupply disabled, disable global route, until its enabled on a warehouse
|
||
|
if 'subcontracting_to_resupply' in vals or 'active' in vals:
|
||
|
if 'subcontracting_to_resupply' in vals:
|
||
|
# ignore when warehouse archived since it will auto-archive all of its rules
|
||
|
self._update_resupply_rules()
|
||
|
self._update_global_route_resupply_subcontractor()
|
||
|
return res
|
||
|
|
||
|
def get_rules_dict(self):
|
||
|
result = super(StockWarehouse, self).get_rules_dict()
|
||
|
subcontract_location_id = self._get_subcontracting_location()
|
||
|
for warehouse in self:
|
||
|
result[warehouse.id].update({
|
||
|
'subcontract': [
|
||
|
self.Routing(warehouse.lot_stock_id, subcontract_location_id, warehouse.subcontracting_resupply_type_id, 'pull'),
|
||
|
]
|
||
|
})
|
||
|
return result
|
||
|
|
||
|
def _update_global_route_resupply_subcontractor(self):
|
||
|
route_id = self._find_global_route('mrp_subcontracting.route_resupply_subcontractor_mto',
|
||
|
_('Resupply Subcontractor on Order'))
|
||
|
if not route_id.sudo().rule_ids.filtered(lambda r: r.active):
|
||
|
route_id.active = False
|
||
|
else:
|
||
|
route_id.active = True
|
||
|
|
||
|
def _get_routes_values(self):
|
||
|
routes = super(StockWarehouse, self)._get_routes_values()
|
||
|
routes.update({
|
||
|
'subcontracting_route_id': {
|
||
|
'routing_key': 'subcontract',
|
||
|
'depends': ['subcontracting_to_resupply'],
|
||
|
'route_create_values': {
|
||
|
'product_categ_selectable': False,
|
||
|
'warehouse_selectable': True,
|
||
|
'product_selectable': False,
|
||
|
'company_id': self.company_id.id,
|
||
|
'sequence': 10,
|
||
|
'name': self._format_routename(name=_('Resupply Subcontractor'))
|
||
|
},
|
||
|
'route_update_values': {
|
||
|
'active': self.subcontracting_to_resupply,
|
||
|
},
|
||
|
'rules_values': {
|
||
|
'active': self.subcontracting_to_resupply,
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
return routes
|
||
|
|
||
|
def _generate_global_route_rules_values(self):
|
||
|
rules = super()._generate_global_route_rules_values()
|
||
|
subcontract_location_id = self._get_subcontracting_location()
|
||
|
production_location_id = self._get_production_location()
|
||
|
rules.update({
|
||
|
'subcontracting_mto_pull_id': {
|
||
|
'depends': ['subcontracting_to_resupply'],
|
||
|
'create_values': {
|
||
|
'procure_method': 'make_to_order',
|
||
|
'company_id': self.company_id.id,
|
||
|
'action': 'pull',
|
||
|
'auto': 'manual',
|
||
|
'route_id': self._find_global_route('stock.route_warehouse0_mto', _('Replenish on Order (MTO)'), raise_if_not_found=False).id,
|
||
|
'name': self._format_rulename(self.lot_stock_id, subcontract_location_id, 'MTO'),
|
||
|
'location_dest_id': subcontract_location_id.id,
|
||
|
'location_src_id': self.lot_stock_id.id,
|
||
|
'picking_type_id': self.subcontracting_resupply_type_id.id
|
||
|
},
|
||
|
'update_values': {
|
||
|
'active': self.subcontracting_to_resupply
|
||
|
}
|
||
|
},
|
||
|
'subcontracting_pull_id': {
|
||
|
'depends': ['subcontracting_to_resupply'],
|
||
|
'create_values': {
|
||
|
'procure_method': 'make_to_order',
|
||
|
'company_id': self.company_id.id,
|
||
|
'action': 'pull',
|
||
|
'auto': 'manual',
|
||
|
'route_id': self._find_global_route('mrp_subcontracting.route_resupply_subcontractor_mto',
|
||
|
_('Resupply Subcontractor on Order'), raise_if_not_found=False).id,
|
||
|
'name': self._format_rulename(subcontract_location_id, production_location_id, False),
|
||
|
'location_dest_id': production_location_id.id,
|
||
|
'location_src_id': subcontract_location_id.id,
|
||
|
'picking_type_id': self.subcontracting_resupply_type_id.id
|
||
|
},
|
||
|
'update_values': {
|
||
|
'active': self.subcontracting_to_resupply
|
||
|
}
|
||
|
},
|
||
|
})
|
||
|
return rules
|
||
|
|
||
|
def _get_picking_type_create_values(self, max_sequence):
|
||
|
data, next_sequence = super(StockWarehouse, self)._get_picking_type_create_values(max_sequence)
|
||
|
data.update({
|
||
|
'subcontracting_type_id': {
|
||
|
'name': _('Subcontracting'),
|
||
|
'code': 'mrp_operation',
|
||
|
'use_create_components_lots': True,
|
||
|
'sequence': next_sequence + 2,
|
||
|
'sequence_code': 'SBC',
|
||
|
'company_id': self.company_id.id,
|
||
|
},
|
||
|
'subcontracting_resupply_type_id': {
|
||
|
'name': _('Resupply Subcontractor'),
|
||
|
'code': 'outgoing',
|
||
|
'use_create_lots': False,
|
||
|
'use_existing_lots': True,
|
||
|
'default_location_dest_id': self._get_subcontracting_location().id,
|
||
|
'sequence': next_sequence + 3,
|
||
|
'sequence_code': 'RES',
|
||
|
'print_label': True,
|
||
|
'company_id': self.company_id.id,
|
||
|
}
|
||
|
})
|
||
|
return data, max_sequence + 4
|
||
|
|
||
|
def _get_sequence_values(self, name=False, code=False):
|
||
|
values = super(StockWarehouse, self)._get_sequence_values(name=name, code=code)
|
||
|
count = self.env['ir.sequence'].search_count([('prefix', '=like', self.code + '/SBC%/%')])
|
||
|
values.update({
|
||
|
'subcontracting_type_id': {
|
||
|
'name': self.name + ' ' + _('Sequence subcontracting'),
|
||
|
'prefix': self.code + (('/SBC' + str(count) + '/') if count else '/SBC/'),
|
||
|
'padding': 5,
|
||
|
'company_id': self.company_id.id
|
||
|
},
|
||
|
'subcontracting_resupply_type_id': {
|
||
|
'name': self.name + ' ' + _('Sequence Resupply Subcontractor'),
|
||
|
'prefix': self.code + (('/RES' + str(count) + '/') if count else '/RES/'),
|
||
|
'padding': 5,
|
||
|
'company_id': self.company_id.id
|
||
|
},
|
||
|
})
|
||
|
return values
|
||
|
|
||
|
def _get_picking_type_update_values(self):
|
||
|
data = super(StockWarehouse, self)._get_picking_type_update_values()
|
||
|
subcontract_location_id = self._get_subcontracting_location()
|
||
|
production_location_id = self._get_production_location()
|
||
|
data.update({
|
||
|
'subcontracting_type_id': {
|
||
|
'active': False,
|
||
|
'default_location_src_id': subcontract_location_id.id,
|
||
|
'default_location_dest_id': production_location_id.id,
|
||
|
},
|
||
|
'subcontracting_resupply_type_id': {
|
||
|
'default_location_src_id': self.lot_stock_id.id,
|
||
|
'default_location_dest_id': subcontract_location_id.id,
|
||
|
'barcode': self.code.replace(" ", "").upper() + "-RESUPPLY",
|
||
|
'active': self.subcontracting_to_resupply and self.active
|
||
|
},
|
||
|
})
|
||
|
return data
|
||
|
|
||
|
def _get_subcontracting_location(self):
|
||
|
return self.company_id.subcontracting_location_id
|
||
|
|
||
|
def _get_subcontracting_locations(self):
|
||
|
return self.env['stock.location'].search([
|
||
|
('company_id', 'in', self.company_id.ids),
|
||
|
('is_subcontracting_location', '=', 'True'),
|
||
|
])
|
||
|
|
||
|
def _update_subcontracting_locations_rules(self):
|
||
|
subcontracting_locations = self._get_subcontracting_locations()
|
||
|
subcontracting_locations._activate_subcontracting_location_rules()
|
||
|
|
||
|
def _update_resupply_rules(self):
|
||
|
'''update (archive/unarchive) any warehouse subcontracting location resupply rules'''
|
||
|
subcontracting_locations = self._get_subcontracting_locations()
|
||
|
warehouses_to_resupply = self.filtered(lambda w: w.subcontracting_to_resupply and w.active)
|
||
|
if warehouses_to_resupply:
|
||
|
self.env['stock.rule'].with_context(active_test=False).search([
|
||
|
'&', ('picking_type_id', 'in', warehouses_to_resupply.subcontracting_resupply_type_id.ids),
|
||
|
'|', ('location_src_id', 'in', subcontracting_locations.ids),
|
||
|
('location_dest_id', 'in', subcontracting_locations.ids)]).action_unarchive()
|
||
|
|
||
|
warehouses_not_to_resupply = self - warehouses_to_resupply
|
||
|
if warehouses_not_to_resupply:
|
||
|
self.env['stock.rule'].search([
|
||
|
'&', ('picking_type_id', 'in', warehouses_not_to_resupply.subcontracting_resupply_type_id.ids),
|
||
|
'|', ('location_src_id', 'in', subcontracting_locations.ids),
|
||
|
('location_dest_id', 'in', subcontracting_locations.ids)]).action_archive()
|