diff --git a/addons/mrp/models/mrp_bom.py b/addons/mrp/models/mrp_bom.py
index 91ee51bd9f1..f38cb346007 100644
--- a/addons/mrp/models/mrp_bom.py
+++ b/addons/mrp/models/mrp_bom.py
@@ -111,6 +111,10 @@ class MrpBom(models.Model):
return self.search(domain, order='sequence, product_id', limit=1)
def explode(self, product, quantity, picking_type=False):
+ """
+ Explodes the BoM and creates two lists with all the information you need: bom_done and line_done
+ Quantity should be passed in the UoM of the BoM (don't divide by its quantity)
+ """
boms_done = [(self, {'qty': quantity, 'product': product, 'original_qty': quantity, 'parent_line': False})]
lines_done = []
templates_done = product.product_tmpl_id
diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py
index df3b72a6e91..7ff5bbba781 100644
--- a/addons/mrp/models/mrp_production.py
+++ b/addons/mrp/models/mrp_production.py
@@ -311,8 +311,7 @@ class MrpProduction(models.Model):
source_location = self.bom_id.routing_id.location_id
else:
source_location = self.location_src_id
- original_quantity = self.env['product.uom']._compute_qty(self.product_uom_id.id, self.product_qty, self.bom_id.product_uom_id.id)
-
+ original_quantity = self.product_qty - self.qty_produced
data = {
'name': self.name,
'date': self.date_planned_start,
@@ -354,14 +353,21 @@ class MrpProduction(models.Model):
move.procure_method = 'make_to_order'
@api.multi
- def _update_raw_move(self, bom_line, quantity, **kw):
+ def _update_raw_move(self, bom_line, line_data):
+ quantity = line_data['qty']
self.ensure_one()
move = self.move_raw_ids.filtered(lambda x: x.bom_line_id.id == bom_line.id and x.state not in ('done', 'cancel'))
if move:
- move.write({'product_uom_qty': quantity})
+ if quantity > 0:
+ move[0].write({'product_uom_qty': quantity})
+ else:
+ if move[0].quantity_done > 0:
+ raise UserError(_('Lines need to be deleted, but can not as you still have some quantities to consume in them. '))
+ move[0].action_cancel()
+ move[0].unlink()
return move
else:
- self._generate_raw_move(bom_line, quantity)
+ self._generate_raw_move(bom_line, line_data)
@api.multi
def action_assign(self):
@@ -398,8 +404,7 @@ class MrpProduction(models.Model):
workorders = self.env['mrp.workorder']
qty = bom_data['qty']
- use_serial = any(product.tracking == 'serial' for product in self.mapped('move_finished_ids.product_id'))
- if use_serial:
+ if self.product_id.tracking == 'serial':
quantity = 1.0
else:
quantity = self.product_qty - sum(self.move_finished_ids.mapped('quantity_done'))
diff --git a/addons/mrp/views/mrp_workorder_views.xml b/addons/mrp/views/mrp_workorder_views.xml
index b52fa0b2ff1..f2df2dd66f0 100644
--- a/addons/mrp/views/mrp_workorder_views.xml
+++ b/addons/mrp/views/mrp_workorder_views.xml
@@ -100,7 +100,7 @@
-
+
diff --git a/addons/mrp/wizard/change_production_qty.py b/addons/mrp/wizard/change_production_qty.py
index b093b0c9eb7..0e6382fa398 100644
--- a/addons/mrp/wizard/change_production_qty.py
+++ b/addons/mrp/wizard/change_production_qty.py
@@ -37,32 +37,41 @@ class ChangeProductionQty(models.TransientModel):
@api.multi
def change_prod_qty(self):
- MrpBom = self.env['mrp.bom']
for wizard in self:
production = wizard.mo_id
produced = sum(production.move_finished_ids.mapped('quantity_done'))
if wizard.product_qty < produced:
raise UserError(_("You have already processed %d. Please input a quantity higher than %d ")%(produced, produced))
production.write({'product_qty': wizard.product_qty})
- #production.action_compute()
- #TODO: Do we still need to change the quantity of a production order?
- production_move = production.move_finished_ids.filtered(lambda x : x.state not in ('done', 'cancel') and production.product_id.id == x.product_id.id)
- for move in production.move_raw_ids:
- bom_point = production.bom_id
- # TDE FIXME: this is not the place to do that kind of computation, please
- if not bom_point:
- bom_point = MrpBom._bom_find(product=production.product_id, picking_type=production.picking_type_id)
- if not bom_point:
- raise UserError(_("Cannot find bill of material for this production."))
- production.write({'bom_id': bom_point.id})
- if not bom_point:
- raise UserError(_("Cannot find bill of material for this production."))
- factor = (production.product_qty - production.qty_produced) * production.product_uom_id.factor / bom_point.product_uom_id.factor
- boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
- for line, line_data in lines:
- production._update_raw_move(line, line_data['qty'])
+ bom_point = production.bom_id
+ factor = self.env['product.uom']._compute_qty(production.product_uom_id.id, production.product_qty - production.qty_produced, production.bom_id.product_uom_id.id)
+ boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
+ for line, line_data in lines:
+ production._update_raw_move(line, line_data)
self._update_product_to_produce(production, production.product_qty - production.qty_produced)
moves = production.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
moves.do_unreserve()
moves.action_assign()
+ for wo in production.workorder_ids:
+ if production.product_id.tracking == 'serial':
+ quantity = 1.0
+ else:
+ quantity = wo.qty_production - wo.qty_produced
+ quantity = quantity if (quantity > 0) else 0
+ wo.qty_producing = quantity
+ if wo.qty_produced < wo.qty_production and wo.state == 'done':
+ wo.state = 'progress'
+ # assign moves; last operation receive all unassigned moves (which case ?)
+ operation = wo.operation_id
+
+ # TODO: following could be put in a function as it is similar as code in _workorders_create
+ # TODO: only needed when creating new moves
+ moves_raw = production.move_raw_ids.filtered(lambda move: move.operation_id == operation and move.state not in ('done', 'cancel'))
+ if wo == production.workorder_ids[-1]:
+ moves_raw |= production.move_raw_ids.filtered(lambda move: not move.operation_id)
+ moves_finished = production.move_finished_ids.filtered(lambda move: move.operation_id == operation) #TODO: code does nothing, unless maybe by_products?
+ moves_raw.mapped('move_lot_ids').write({'workorder_id': wo.id})
+ (moves_finished + moves_raw).write({'workorder_id': wo.id})
+ if wo.move_raw_ids.filtered(lambda x: x.product_id.tracking != 'none') and not wo.active_move_lot_ids:
+ wo._generate_lot_ids()
return {}
diff --git a/addons/mrp_byproduct/models/mrp_production.py b/addons/mrp_byproduct/models/mrp_production.py
index 2355b67a60f..a8c34ea4068 100644
--- a/addons/mrp_byproduct/models/mrp_production.py
+++ b/addons/mrp_byproduct/models/mrp_production.py
@@ -4,39 +4,41 @@
from odoo import api, models
-class Production(models.Model):
+class MrpProduction(models.Model):
_description = 'Production'
_inherit = 'mrp.production'
+ def _create_byproduct_move(self, sub_product):
+ UoM = self.env['product.uom']
+ Move = self.env['stock.move']
+ for production in self:
+ source = production.product_id.property_stock_production.id
+ product_uom_factor = UoM._compute_qty_obj(production.product_uom_id, production.product_qty - production.qty_produced, production.bom_id.product_uom_id)
+ qty1 = sub_product.product_qty
+ qty1 *= product_uom_factor / production.bom_id.product_qty
+ data = {
+ 'name': 'PROD:%s' % production.name,
+ 'date': production.date_planned_start,
+ 'product_id': sub_product.product_id.id,
+ 'product_uom_qty': qty1,
+ 'product_uom': sub_product.product_uom_id.id,
+ 'location_id': source,
+ 'location_dest_id': production.location_dest_id.id,
+ 'production_id': production.id,
+ 'origin': production.name,
+ 'unit_factor': qty1 / (production.product_qty - production.qty_produced),
+ 'subproduct_id': sub_product.id
+ }
+ move = Move.create(data)
+ move.action_confirm()
@api.multi
def _generate_moves(self):
""" Generates moves and work orders
@return: Newly generated picking Id.
"""
- # TDE FIXME: was action_confirm ?? -> refactored
- Move = self.env['stock.move']
- res = super(Production, self)._generate_moves()
- UoM = self.env['product.uom']
+ res = super(MrpProduction, self)._generate_moves()
for production in self.filtered(lambda production: production.bom_id):
- source = production.product_id.property_stock_production.id
for sub_product in production.bom_id.sub_products:
- product_uom_factor = UoM._compute_qty_obj(production.product_uom_id, production.product_qty, production.bom_id.product_uom_id)
- qty1 = sub_product.product_qty
- qty1 *= product_uom_factor / production.bom_id.product_qty
- data = {
- 'name': 'PROD:%s' % production.name,
- 'date': production.date_planned_start,
- 'product_id': sub_product.product_id.id,
- 'product_uom_qty': qty1,
- 'product_uom': sub_product.product_uom_id.id,
- 'location_id': source,
- 'location_dest_id': production.location_dest_id.id,
- 'production_id': production.id,
- 'origin': production.name,
- 'unit_factor': qty1 / production.product_qty,
- 'subproduct_id': sub_product.id
- }
- move = Move.create(data)
- move.action_confirm()
+ production._create_byproduct_move(sub_product)
return res
diff --git a/addons/mrp_byproduct/models/stock_move.py b/addons/mrp_byproduct/models/stock_move.py
index e75c2f8351c..119cc8fda94 100644
--- a/addons/mrp_byproduct/models/stock_move.py
+++ b/addons/mrp_byproduct/models/stock_move.py
@@ -4,7 +4,7 @@
from odoo import fields, models
-class Stok_Move(models.Model):
+class StockMove(models.Model):
_inherit = 'stock.move'
subproduct_id = fields.Many2one(
diff --git a/addons/mrp_byproduct/wizard/change_production_qty.py b/addons/mrp_byproduct/wizard/change_production_qty.py
index ac553ced65c..1ac4b74f867 100644
--- a/addons/mrp_byproduct/wizard/change_production_qty.py
+++ b/addons/mrp_byproduct/wizard/change_production_qty.py
@@ -4,19 +4,20 @@
from odoo import api, models
-class change_production_qty(models.TransientModel):
+class ChangeProductionQty(models.TransientModel):
_inherit = 'change.production.qty'
@api.model
def _update_product_to_produce(self, prod, qty):
- # U
+ super(ChangeProductionQty, self)._update_product_to_produce(prod, qty)
Production = self.env['mrp.production']
- for move in prod.move_finished_ids:
- if move.product_id == prod.product_id:
- move.write({'product_uom_qty': qty})
+ UoM = self.env['product.uom']
+ for sub_product_line in prod.bom_id.sub_products:
+ move = prod.move_finished_ids.filtered(lambda x: x.sub_product_id == sub_product_line and x.state not in ('done', 'cancel'))
+ if move:
+ product_uom_factor = UoM._compute_qty_obj(prod.product_uom_id, prod.product_qty - prod.qty_produced, prod.bom_id.product_uom_id)
+ qty1 = sub_product_line.product_qty
+ qty1 *= product_uom_factor / prod.bom_id.product_qty
+ move[0].write({'product_uom_qty': qty1})
else:
- for sub_product_line in prod.bom_id.sub_products:
- if sub_product_line.product_id == move.product_id:
- factor = Production._get_subproduct_factor(move)
- subproduct_qty = qty * factor
- move.write({'product_uom_qty': subproduct_qty})
+ prod._create_byproduct_move(sub_product_line)
\ No newline at end of file
diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py
index c9e497c4477..f824bf1b549 100644
--- a/addons/stock/models/stock_move.py
+++ b/addons/stock/models/stock_move.py
@@ -629,6 +629,7 @@ class StockMove(models.Model):
if move.state != 'assigned' and not self.env.context.get('reserve_only_ops'):
qty_already_assigned = move.reserved_availability
qty = move.product_qty - qty_already_assigned
+
quants = Quant.quants_get_preferred_domain(qty, move, domain=main_domain[move.id], preferred_domain_list=[])
Quant.quants_reserve(quants, move)