mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
On v12 and with chained moves coming from sales, procurement, etc, move_orig_ids contains that full chain, so we get a singleton error. But as we want the subcontracting production, using mapped, we get that single record, so we apply this solution everywhere where it's needed.
171 lines
7.6 KiB
Python
171 lines
7.6 KiB
Python
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
|
|
# Copyright 2019 Odoo
|
|
# Copyright 2020 Tecnativa - Alexandre Díaz
|
|
# Copyright 2020 Tecnativa - Pedro M. Baeza
|
|
|
|
from datetime import timedelta
|
|
|
|
from odoo import api, fields, models
|
|
|
|
|
|
class StockPicking(models.Model):
|
|
_inherit = 'stock.picking'
|
|
|
|
display_action_record_components = fields.Boolean(
|
|
compute='_compute_display_action_record_components')
|
|
|
|
@api.depends('state')
|
|
def _compute_display_action_record_components(self):
|
|
for picking in self:
|
|
# Hide if not encoding state
|
|
if picking.state in ('draft', 'cancel', 'done'):
|
|
picking.display_action_record_components = False
|
|
continue
|
|
if not picking._is_subcontract():
|
|
picking.display_action_record_components = False
|
|
continue
|
|
# Hide if no components are track
|
|
subcontracted_productions = picking\
|
|
._get_subcontracted_productions()
|
|
subcontracted_moves = subcontracted_productions.mapped(
|
|
'move_raw_ids')
|
|
if all(subcontracted_move.has_tracking == 'none'
|
|
for subcontracted_move in subcontracted_moves):
|
|
picking.display_action_record_components = False
|
|
continue
|
|
# Hide if the production is to close
|
|
if not subcontracted_productions.filtered(lambda mo: (
|
|
not mo.check_to_done and mo.state != 'done'
|
|
)):
|
|
picking.display_action_record_components = False
|
|
continue
|
|
picking.display_action_record_components = True
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Action methods
|
|
# -------------------------------------------------------------------------
|
|
|
|
def action_done(self):
|
|
productions = self.env['mrp.production']
|
|
for picking in self:
|
|
for move in picking.move_lines:
|
|
if not move.is_subcontract:
|
|
continue
|
|
production = move.move_orig_ids.mapped('production_id')
|
|
if move._has_tracked_subcontract_components():
|
|
move.move_orig_ids.filtered(
|
|
lambda m: m.state not in ('done', 'cancel')
|
|
).move_line_ids.unlink()
|
|
move_finished_ids = move.move_orig_ids.filtered(
|
|
lambda m: m.state not in ('done', 'cancel'))
|
|
for ml in move.move_line_ids:
|
|
ml.copy({
|
|
'picking_id': False,
|
|
'production_id':
|
|
move_finished_ids.production_id.id,
|
|
'move_id': move_finished_ids.id,
|
|
'qty_done': ml.qty_done,
|
|
'result_package_id': False,
|
|
'location_id': move_finished_ids.location_id.id,
|
|
'location_dest_id':
|
|
move_finished_ids.location_dest_id.id,
|
|
})
|
|
else:
|
|
for move_line in move.move_line_ids:
|
|
produce = self.env['mrp.product.produce'].with_context(
|
|
default_production_id=production.id).create({
|
|
'production_id': production.id,
|
|
'product_id': production.product_id.id,
|
|
'product_qty': move_line.qty_done,
|
|
'product_uom_id': move_line.product_uom_id.id,
|
|
'lot_id': move_line.lot_id.id,
|
|
})
|
|
produce._onchange_product_qty()
|
|
produce.do_produce()
|
|
productions |= production
|
|
for subcontracted_production in productions:
|
|
if subcontracted_production.check_to_done:
|
|
subcontracted_production.button_mark_done()
|
|
else:
|
|
subcontracted_production.post_inventory()
|
|
res = super(StockPicking, self).action_done()
|
|
for subcontracted_production in productions:
|
|
# For consistency, set the date on production move before the
|
|
# date on picking. (Traceability report + Product Moves menu
|
|
# item)
|
|
minimum_date = min(picking.move_line_ids.mapped('date'))
|
|
production_moves = subcontracted_production.move_raw_ids\
|
|
| subcontracted_production.move_finished_ids
|
|
production_moves.write({
|
|
'date': minimum_date - timedelta(seconds=1),
|
|
})
|
|
production_moves.mapped('move_line_ids').write({
|
|
'date': minimum_date - timedelta(seconds=1),
|
|
})
|
|
return res
|
|
|
|
def action_record_components(self):
|
|
self.ensure_one()
|
|
for move in self.move_lines:
|
|
if not move._has_tracked_subcontract_components():
|
|
continue
|
|
production = move.move_orig_ids.mapped("production_id")
|
|
if not production or production.state in ('done', 'to_close'):
|
|
continue
|
|
return move._action_record_components()
|
|
|
|
# -------------------------------------------------------------------------
|
|
# Subcontract helpers
|
|
# -------------------------------------------------------------------------
|
|
def _is_subcontract(self):
|
|
self.ensure_one()
|
|
return self.picking_type_id.code == 'incoming' and any(
|
|
m.is_subcontract for m in self.move_lines)
|
|
|
|
def _get_subcontracted_productions(self):
|
|
self.ensure_one()
|
|
return self.move_lines.mapped('move_orig_ids.production_id')
|
|
|
|
def _get_warehouse(self, subcontract_move):
|
|
return subcontract_move.warehouse_id\
|
|
or self.picking_type_id.warehouse_id
|
|
|
|
def _prepare_subcontract_mo_vals(self, subcontract_move, bom):
|
|
subcontract_move.ensure_one()
|
|
group = self.env['procurement.group'].create({
|
|
'name': self.name,
|
|
'partner_id': self.partner_id.id,
|
|
})
|
|
product = subcontract_move.product_id
|
|
warehouse = self._get_warehouse(subcontract_move)
|
|
vals = {
|
|
'company_id': subcontract_move.company_id.id,
|
|
'procurement_group_id': group.id,
|
|
'product_id': product.id,
|
|
'product_uom_id': subcontract_move.product_uom.id,
|
|
'bom_id': bom.id,
|
|
'location_src_id':
|
|
subcontract_move.picking_id.partner_id.with_context(
|
|
force_company=subcontract_move.company_id.id)
|
|
.property_stock_subcontractor.id,
|
|
'location_dest_id':
|
|
subcontract_move.picking_id.partner_id.with_context(
|
|
force_company=subcontract_move.company_id.id)
|
|
.property_stock_subcontractor.id,
|
|
'product_qty': subcontract_move.product_uom_qty,
|
|
'picking_type_id': warehouse.subcontracting_type_id.id
|
|
}
|
|
return vals
|
|
|
|
def _subcontracted_produce(self, subcontract_details):
|
|
self.ensure_one()
|
|
for move, bom in subcontract_details:
|
|
mo = self.env['mrp.production'].with_context(
|
|
force_company=move.company_id.id
|
|
).create(self._prepare_subcontract_mo_vals(move, bom))
|
|
# Link the finished to the receipt move.
|
|
finished_move = mo.move_finished_ids.filtered(
|
|
lambda m: m.product_id == move.product_id)
|
|
finished_move.write({'move_dest_ids': [(4, move.id, False)]})
|
|
mo.action_assign()
|