|
|
-
+
|
-
+
-
+
diff --git a/addons/l10n_it_stock_ddt/tests/test_ddt.py b/addons/l10n_it_stock_ddt/tests/test_ddt.py
index 71395904dad..1ed0a66430e 100644
--- a/addons/l10n_it_stock_ddt/tests/test_ddt.py
+++ b/addons/l10n_it_stock_ddt/tests/test_ddt.py
@@ -72,7 +72,7 @@ class TestDDT(TestSaleCommon):
# deliver partially
pick = self.so.picking_ids
- pick.move_ids.write({'quantity_done': 1})
+ pick.move_ids.write({'quantity': 1, 'picked': True})
wiz_act = pick.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
wiz.process()
@@ -84,14 +84,14 @@ class TestDDT(TestSaleCommon):
# deliver partially
pickx1 = self.so.picking_ids.filtered(lambda p: p.state != 'done')
- pickx1.move_ids.write({'quantity_done': 1})
+ pickx1.move_ids.write({'quantity': 1, 'picked': True})
wiz_act = pickx1.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
wiz.process()
# and again
pickx2 = self.so.picking_ids.filtered(lambda p: p.state != 'done')
- pickx2.move_ids.write({'quantity_done': 2})
+ pickx2.move_ids.write({'quantity': 2, 'picked': True})
wiz_act = pickx2.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
wiz.process()
@@ -129,7 +129,7 @@ class TestDDT(TestSaleCommon):
# deliver partially
picking_1 = so.picking_ids
- picking_1.move_ids.write({'quantity_done': 1})
+ picking_1.move_ids.write({'quantity': 1, 'picked': True})
wiz_act = picking_1.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
wiz.process()
@@ -139,7 +139,7 @@ class TestDDT(TestSaleCommon):
invoice_1.action_post()
picking_2 = so.picking_ids.filtered(lambda p: p.state != 'done')
- picking_2.move_ids.write({'quantity_done': 2})
+ picking_2.move_ids.write({'quantity': 2, 'picked': True})
picking_2.button_validate()
invoice_2 = so._create_invoices()
diff --git a/addons/l10n_it_stock_ddt/tests/test_edi.py b/addons/l10n_it_stock_ddt/tests/test_edi.py
index 49b378c5ffa..a85ae725d1f 100644
--- a/addons/l10n_it_stock_ddt/tests/test_edi.py
+++ b/addons/l10n_it_stock_ddt/tests/test_edi.py
@@ -143,7 +143,7 @@ class TestItEdiDDT(TestItEdi):
def _create_delivery(self, sale_order, qty=1):
""" Create a picking of a limited quantity and create a backorder """
pickings = sale_order.picking_ids.filtered(lambda picking: picking.state != 'done')
- pickings.move_ids.write({'quantity_done': qty})
+ pickings.move_ids.write({'quantity': qty})
wizard_action = pickings.button_validate()
context = wizard_action['context']
wizard = Form(self.env['stock.backorder.confirmation'].with_context(context))
diff --git a/addons/mrp/data/mrp_demo.xml b/addons/mrp/data/mrp_demo.xml
index 6112555c3a9..e64b1fc29d8 100644
--- a/addons/mrp/data/mrp_demo.xml
+++ b/addons/mrp/data/mrp_demo.xml
@@ -718,7 +718,7 @@
-
+
diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py
index f616ccf03cf..8e8308b4f4b 100644
--- a/addons/mrp/models/mrp_production.py
+++ b/addons/mrp/models/mrp_production.py
@@ -533,8 +533,8 @@ class MrpProduction(models.Model):
production.finished_move_line_ids = production.move_finished_ids.mapped('move_line_ids')
@api.depends(
- 'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
- 'workorder_ids.state', 'product_qty', 'qty_producing')
+ 'move_raw_ids.state', 'move_raw_ids.quantity', 'move_finished_ids.state',
+ 'workorder_ids.state', 'product_qty', 'qty_producing', 'move_raw_ids.picked')
def _compute_state(self):
""" Compute the production state. This uses a similar process to stock
picking, but has been adapted to support having no moves. This adaption
@@ -564,7 +564,7 @@ class MrpProduction(models.Model):
production.state = 'progress'
elif production.product_uom_id and not float_is_zero(production.qty_producing, precision_rounding=production.product_uom_id.rounding):
production.state = 'progress'
- elif any(not float_is_zero(move.quantity_done, precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding) for move in production.move_raw_ids if move.product_id):
+ elif any(production.move_raw_ids.mapped('picked')):
production.state = 'progress'
@api.depends('bom_id', 'product_id', 'product_qty', 'product_uom_id')
@@ -633,16 +633,16 @@ class MrpProduction(models.Model):
def _compute_unreserve_visible(self):
for order in self:
already_reserved = order.state not in ('done', 'cancel') and order.mapped('move_raw_ids.move_line_ids')
- any_quantity_done = any(m.quantity_done > 0 for m in order.move_raw_ids)
+ any_quantity_done = any(order.move_raw_ids.mapped('picked'))
order.unreserve_visible = not any_quantity_done and already_reserved
order.reserve_visible = order.state in ('confirmed', 'progress', 'to_close') and any(move.product_uom_qty and move.state in ['confirmed', 'partially_available'] for move in order.move_raw_ids)
- @api.depends('workorder_ids.state', 'move_finished_ids', 'move_finished_ids.quantity_done')
+ @api.depends('workorder_ids.state', 'move_finished_ids', 'move_finished_ids.quantity')
def _get_produced_qty(self):
for production in self:
done_moves = production.move_finished_ids.filtered(lambda x: x.state != 'cancel' and x.product_id.id == production.product_id.id)
- qty_produced = sum(done_moves.mapped('quantity_done'))
+ qty_produced = sum(done_moves.filtered(lambda m: m.picked).mapped('quantity'))
production.qty_produced = qty_produced
return True
@@ -890,7 +890,7 @@ class MrpProduction(models.Model):
if 'lot_producing_id' in vals:
finished_move_lines.write({'lot_id': vals.get('lot_producing_id')})
if 'qty_producing' in vals:
- finished_move_lines.write({'qty_done': vals.get('qty_producing')})
+ finished_move_lines.write({'quantity': vals.get('qty_producing')})
if self._has_workorders() and not production.workorder_ids.operation_id and vals.get('date_start') and not vals.get('date_finished'):
new_date_start = fields.Datetime.to_datetime(vals.get('date_start'))
if not production.date_finished or new_date_start >= production.date_finished:
@@ -1030,7 +1030,7 @@ class MrpProduction(models.Model):
target_uom = (move.bom_line_id or move.byproduct_id).product_uom_id or move.product_uom
# In order to be able to multiply the move quantity by the ratio, we
# have to be sure they both express in the same UoM.
- qty = move.quantity_done or move.product_uom_qty
+ qty = move.quantity or move.product_uom_qty
qty = move.product_uom._compute_quantity(qty * ratio, target_uom)
return (target_uom, qty)
@@ -1195,20 +1195,18 @@ class MrpProduction(models.Model):
qty_producing_uom = self.product_uom_id._compute_quantity(self.qty_producing, self.product_id.uom_id, rounding_method='HALF-UP')
if qty_producing_uom != 1:
self.qty_producing = self.product_id.uom_id._compute_quantity(1, self.product_uom_id, rounding_method='HALF-UP')
-
for move in (self.move_raw_ids | self.move_finished_ids.filtered(lambda m: m.product_id != self.product_id)):
- if move._should_bypass_set_qty_producing() or not move.product_uom:
+ # picked + manual means the user set the quantity manually
+ if move.manual_consumption and move.picked:
+ continue
+
+ if move._should_bypass_set_qty_producing():
continue
new_qty = float_round((self.qty_producing - self.qty_produced) * move.unit_factor, precision_rounding=move.product_uom.rounding)
- if self.use_auto_consume_components_lots and move.has_tracking in ('lot', 'serial'):
- if float_compare(move.reserved_availability, 0, precision_rounding=move.product_uom.rounding) <= 0:
- continue
- else:
- new_qty = min(new_qty, move.reserved_availability)
-
- move.move_line_ids.filtered(lambda ml: ml.state not in ('done', 'cancel')).qty_done = 0
move._set_quantity_done(new_qty)
+ if (not move.manual_consumption and not move._origin.manual_consumption):
+ move.picked = True
def _update_raw_moves(self, factor):
self.ensure_one()
@@ -1518,17 +1516,17 @@ class MrpProduction(models.Model):
done_qty_by_product = defaultdict(float)
for move in order.move_raw_ids:
- qty_done = move.product_uom._compute_quantity(move.quantity_done, move.product_id.uom_id)
+ quantity = move.product_uom._compute_quantity(move.quantity, move.product_id.uom_id)
rounding = move.product_id.uom_id.rounding
- if not (move.product_id in expected_qty_by_product or float_is_zero(qty_done, precision_rounding=rounding)):
- issues.append((order, move.product_id, qty_done, 0.0))
+ if not (move.product_id in expected_qty_by_product or float_is_zero(quantity, precision_rounding=rounding)) or not move.picked:
+ issues.append((order, move.product_id, quantity, 0.0))
continue
- done_qty_by_product[move.product_id] += qty_done
+ done_qty_by_product[move.product_id] += quantity
for product, qty_to_consume in expected_qty_by_product.items():
- qty_done = done_qty_by_product.get(product, 0.0)
- if float_compare(qty_to_consume, qty_done, precision_rounding=product.uom_id.rounding) != 0:
- issues.append((order, product, qty_done, qty_to_consume))
+ quantity = done_qty_by_product.get(product, 0.0)
+ if float_compare(qty_to_consume, quantity, precision_rounding=product.uom_id.rounding) != 0:
+ issues.append((order, product, quantity, qty_to_consume))
return issues
@@ -1632,15 +1630,17 @@ class MrpProduction(models.Model):
return True
def _post_inventory(self, cancel_backorder=False):
- moves_to_do, moves_not_to_do = set(), set()
+ moves_to_do, moves_not_to_do, moves_to_cancel = set(), set(), set()
for move in self.move_raw_ids:
if move.state == 'done':
moves_not_to_do.add(move.id)
+ elif not move.picked:
+ moves_to_cancel.add(move.id)
elif move.state != 'cancel':
moves_to_do.add(move.id)
- if move.product_qty == 0.0 and move.quantity_done > 0:
- move.product_uom_qty = move.quantity_done
+
self.with_context(skip_mo_check=True).env['stock.move'].browse(moves_to_do)._action_done(cancel_backorder=cancel_backorder)
+ self.with_context(skip_mo_check=True).env['stock.move'].browse(moves_to_cancel)._action_cancel()
moves_to_do = self.move_raw_ids.filtered(lambda x: x.state == 'done') - self.env['stock.move'].browse(moves_not_to_do)
# Create a dict to avoid calling filtered inside for loops.
moves_to_do_by_order = defaultdict(lambda: self.env['stock.move'], [
@@ -1651,8 +1651,7 @@ class MrpProduction(models.Model):
finish_moves = order.move_finished_ids.filtered(lambda m: m.product_id == order.product_id and m.state not in ('done', 'cancel'))
# the finish move can already be completed by the workorder.
for move in finish_moves:
- if not move.quantity_done:
- move._set_quantity_done(float_round(order.qty_producing - order.qty_produced, precision_rounding=order.product_uom_id.rounding, rounding_method='HALF-UP'))
+ move.quantity = float_round(order.qty_producing - order.qty_produced, precision_rounding=order.product_uom_id.rounding, rounding_method='HALF-UP')
if move.has_tracking != 'none' and order.lot_producing_id:
move.move_line_ids.lot_id = order.lot_producing_id
# workorder duration need to be set to calculate the price of the product
@@ -1660,12 +1659,12 @@ class MrpProduction(models.Model):
if workorder.state not in ('done', 'cancel'):
workorder.duration_expected = workorder._get_duration_expected()
if workorder.duration == 0.0:
- workorder.duration = workorder.duration_expected * order.qty_produced/order.product_qty
+ workorder.duration = workorder.duration_expected * order.qty_producing / order.product_qty
workorder.duration_unit = round(workorder.duration / max(workorder.qty_produced, 1), 2)
order._cal_price(moves_to_do_by_order[order.id])
moves_to_finish = self.move_finished_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
+ moves_to_finish.picked = True
moves_to_finish = moves_to_finish._action_done(cancel_backorder=cancel_backorder)
- self.action_assign()
for order in self:
consume_move_lines = moves_to_do_by_order[order.id].mapped('move_line_ids')
order.move_finished_ids.move_line_ids.consume_line_ids = [(6, 0, consume_move_lines.ids)]
@@ -1707,7 +1706,7 @@ class MrpProduction(models.Model):
and a new backorder with product_qty=2.
:param bool cancel_remaining_qty: whether to cancel remaining quantities or generate
an additional backorder, e.g. having product_qty=5 if mrp.production(1,) product_qty was 10.
- :param bool set_consumed_qty: whether to set qty_done on move lines to the reserved quantity
+ :param bool set_consumed_qty: whether to set quantity on move lines to the reserved quantity
or the initial demand if no reservation, except for the remaining backorder.
:return: mrp.production records in order of [orig_prod_1, backorder_prod_1,
backorder_prod_2, orig_prod_2, backorder_prod_2, etc.]
@@ -1796,6 +1795,7 @@ class MrpProduction(models.Model):
moves.append(move)
backorder_moves = self.env['stock.move'].create(new_moves_vals)
+ move_to_assign = backorder_moves
# Split `stock.move.line`s. 2 options for this:
# - do_unreserve -> action_assign
# - Split the reserved amounts manually
@@ -1810,7 +1810,6 @@ class MrpProduction(models.Model):
assigned_moves = set()
partially_assigned_moves = set()
move_lines_to_unlink = set()
-
for initial_move, backorder_moves in move_to_backorder_moves.items():
# Create `stock.move.line` for consumed but non-reserved components
if initial_move.raw_material_production_id and not initial_move.move_line_ids and set_consumed_qty:
@@ -1819,7 +1818,7 @@ class MrpProduction(models.Model):
for move in list(initial_move + backorder_moves - backorder_move_to_ignore):
new_ml_vals = dict(
ml_vals,
- qty_done=move.product_uom_qty,
+ quantity=move.product_uom_qty,
move_id=move.id
)
move_lines_vals.append(new_ml_vals)
@@ -1828,23 +1827,27 @@ class MrpProduction(models.Model):
ml_by_move = []
product_uom = initial_move.product_id.uom_id
for move_line in initial_move.move_line_ids:
- available_qty = move_line.product_uom_id._compute_quantity(move_line.reserved_uom_qty, product_uom)
+ if initial_move.picked:
+ continue
+ available_qty = move_line.product_uom_id._compute_quantity(move_line.quantity, product_uom)
if float_compare(available_qty, 0, precision_rounding=move_line.product_uom_id.rounding) <= 0:
continue
ml_by_move.append((available_qty, move_line, move_line.copy_data()[0]))
- initial_move.move_line_ids.with_context(bypass_reservation_update=True).write({'reserved_uom_qty': 0})
moves = list(initial_move | backorder_moves)
move = moves and moves.pop(0)
move_qty_to_reserve = move.product_qty
for index, (quantity, move_line, ml_vals) in enumerate(ml_by_move):
- taken_qty = min(quantity, move_qty_to_reserve, move_line.product_uom_id._compute_quantity(move_line.qty_done, product_uom))
+ taken_qty = min(quantity, move_qty_to_reserve)
taken_qty_uom = product_uom._compute_quantity(taken_qty, move_line.product_uom_id)
if float_is_zero(taken_qty_uom, precision_rounding=move_line.product_uom_id.rounding):
continue
- move_line.with_context(bypass_reservation_update=True).reserved_uom_qty = taken_qty_uom
+ move_line.write({
+ 'quantity': taken_qty_uom,
+ 'move_id': move.id,
+ })
move_qty_to_reserve -= taken_qty
ml_by_move[index] = (quantity - taken_qty, move_line, ml_vals)
@@ -1859,17 +1862,13 @@ class MrpProduction(models.Model):
taken_qty = min(move_qty_to_reserve, quantity)
taken_qty_uom = product_uom._compute_quantity(taken_qty, move_line.product_uom_id)
if move == initial_move:
- move_line.with_context(bypass_reservation_update=True).reserved_uom_qty += taken_qty_uom
- if set_consumed_qty:
- move_line.qty_done += taken_qty_uom
+ move_line.quantity += taken_qty_uom
elif not float_is_zero(taken_qty_uom, precision_rounding=move_line.product_uom_id.rounding):
new_ml_vals = dict(
ml_vals,
- reserved_uom_qty=taken_qty_uom,
+ quantity=taken_qty_uom,
move_id=move.id
)
- if set_consumed_qty:
- new_ml_vals['qty_done'] = taken_qty_uom
move_lines_vals.append(new_ml_vals)
quantity -= taken_qty
move_qty_to_reserve -= taken_qty
@@ -1891,15 +1890,22 @@ class MrpProduction(models.Model):
if move and move_qty_to_reserve != move.product_qty:
partially_assigned_moves.add(move.id)
- move_lines_to_unlink.update(initial_move.move_line_ids.filtered(
- lambda ml: not ml.reserved_uom_qty and not ml.qty_done).ids)
+ move_lines_to_unlink.update(initial_move.move_line_ids.filtered(lambda ml: not ml.quantity).ids)
+ # reserve new backorder moves depending on the picking type
self.env['stock.move'].browse(assigned_moves).write({'state': 'assigned'})
self.env['stock.move'].browse(partially_assigned_moves).write({'state': 'partially_available'})
+ move_to_assign = move_to_assign.filtered(
+ lambda move: move.state in ('confirmed', 'partially_available')
+ and (move._should_bypass_reservation()
+ or move.picking_type_id.reservation_method == 'at_confirm'
+ or (move.reservation_date and move.reservation_date <= fields.Date.today())))
+ move_to_assign._action_assign()
+
# Avoid triggering a useless _recompute_state
self.env['stock.move.line'].browse(move_lines_to_unlink).write({'move_id': False})
self.env['stock.move.line'].browse(move_lines_to_unlink).unlink()
- self.env['stock.move.line'].with_context(bypass_reservation_update=True).create(move_lines_vals)
+ self.env['stock.move.line'].create(move_lines_vals)
workorders_to_cancel = self.env['mrp.workorder']
for production in self:
@@ -1993,7 +1999,7 @@ class MrpProduction(models.Model):
}
elif self.user_has_groups('mrp.group_mrp_reception_report'):
mos_to_show = self.filtered(lambda mo: mo.picking_type_id.auto_show_reception_report)
- lines = mos_to_show.move_finished_ids.filtered(lambda m: m.product_id.type == 'product' and m.state != 'cancel' and m.quantity_done and not m.move_dest_ids)
+ lines = mos_to_show.move_finished_ids.filtered(lambda m: m.product_id.type == 'product' and m.state != 'cancel' and m.picked and not m.move_dest_ids)
if lines:
if any(mo.show_allocation for mo in mos_to_show):
another_action = mos_to_show.action_view_reception_report()
@@ -2187,7 +2193,7 @@ class MrpProduction(models.Model):
if self.product_id.tracking != 'serial':
return
if self.state == 'confirmed' and self.reservation_state != 'assigned':
- missing_components = {move.product_id for move in self.move_raw_ids if float_compare(move.reserved_availability, move.product_uom_qty, precision_rounding=move.product_uom.rounding) < 0}
+ missing_components = {move.product_id for move in self.move_raw_ids if float_compare(move.quantity, move.product_uom_qty, precision_rounding=move.product_uom.rounding) < 0}
message = _("Make sure enough quantities of these components are reserved to do the production:\n")
message += "\n".join(component.name for component in missing_components)
raise UserError(message)
@@ -2474,17 +2480,17 @@ class MrpProduction(models.Model):
if move.has_tracking != 'serial' or move.product_id == self.product_id:
continue
for move_line in move.move_line_ids:
- if float_is_zero(move_line.qty_done, precision_rounding=move_line.product_uom_id.rounding):
+ if float_is_zero(move_line.quantity, precision_rounding=move_line.product_uom_id.rounding):
continue
if self._is_finished_sn_already_produced(move_line.lot_id, excluded_sml=move_line):
raise UserError(_('The serial number %(number)s used for byproduct %(product_name)s has already been produced',
number=move_line.lot_id.name, product_name=move_line.product_id.name))
for move in self.move_raw_ids:
- if move.has_tracking != 'serial':
+ if move.has_tracking != 'serial' or not move.picked:
continue
for move_line in move.move_line_ids:
- if float_is_zero(move_line.qty_done, precision_rounding=move_line.product_uom_id.rounding):
+ if float_is_zero(move_line.quantity, precision_rounding=move_line.product_uom_id.rounding):
continue
message = _('The serial number %(number)s used for component %(component)s has already been consumed',
number=move_line.lot_id.name,
@@ -2494,7 +2500,7 @@ class MrpProduction(models.Model):
# Check presence of same sn in previous productions
duplicates = self.env['stock.move.line'].search_count([
('lot_id', '=', move_line.lot_id.id),
- ('qty_done', '=', 1),
+ ('quantity', '=', 1),
('state', '=', 'done'),
('location_dest_id.usage', '=', 'production'),
('production_id', '!=', False),
@@ -2517,7 +2523,7 @@ class MrpProduction(models.Model):
if not ((duplicates_returned or removed) and duplicates - duplicates_returned - removed + unremoved == 0):
raise UserError(message)
# Check presence of same sn in current production
- duplicates = co_prod_move_lines.filtered(lambda ml: ml.qty_done and ml.lot_id == move_line.lot_id) - move_line
+ duplicates = co_prod_move_lines.filtered(lambda ml: ml.quantity and ml.lot_id == move_line.lot_id) - move_line
if duplicates:
raise UserError(message)
@@ -2527,7 +2533,7 @@ class MrpProduction(models.Model):
excluded_sml = excluded_sml or self.env['stock.move.line']
domain = [
('lot_id', '=', lot.id),
- ('qty_done', '=', 1),
+ ('quantity', '=', 1),
('state', '=', 'done')
]
co_prod_move_lines = self.move_finished_ids.move_line_ids - excluded_sml
@@ -2554,7 +2560,7 @@ class MrpProduction(models.Model):
if not ((duplicates_unbuild or removed) and duplicates - duplicates_unbuild - removed == 0):
return True
# Check presence of same sn in current production
- duplicates = co_prod_move_lines.filtered(lambda ml: ml.qty_done and ml.lot_id == lot)
+ duplicates = co_prod_move_lines.filtered(lambda ml: ml.quantity and ml.lot_id == lot)
return bool(duplicates)
def _pre_action_split_merge_hook(self, merge=False, split=False):
@@ -2612,10 +2618,10 @@ class MrpProduction(models.Model):
continue
rounding = move.product_uom.rounding
if move.manual_consumption:
- if move.has_tracking in ('serial', 'lot') and float_is_zero(move.quantity_done, precision_rounding=rounding):
+ if move.has_tracking in ('serial', 'lot') and (any(not line.lot_id for line in move.move_line_ids if line.quantity) or not move.picked):
missing_lot_id_products += "\n - %s" % move.product_id.display_name
if missing_lot_id_products:
- error_msg = _('You need to supply Lot/Serial Number for products:') + missing_lot_id_products
+ error_msg = _("You need to supply Lot/Serial Number for products and 'picked' them:") + missing_lot_id_products
raise UserError(error_msg)
def _get_autoprint_done_report_actions(self):
diff --git a/addons/mrp/models/mrp_unbuild.py b/addons/mrp/models/mrp_unbuild.py
index 8f816f351a7..e795176be51 100644
--- a/addons/mrp/models/mrp_unbuild.py
+++ b/addons/mrp/models/mrp_unbuild.py
@@ -1,12 +1,12 @@
-# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import api, fields, models, _
+from collections import defaultdict
+
+from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools import float_compare, float_round
-from odoo.osv import expression
+from odoo.tools.misc import clean_context
-from collections import defaultdict
class MrpUnbuild(models.Model):
_name = "mrp.unbuild"
@@ -131,17 +131,19 @@ class MrpUnbuild(models.Model):
def action_unbuild(self):
self.ensure_one()
self._check_company()
+ # remove the default_* keys that was only needed in the unbuild wizard
+ self.env.context = dict(clean_context(self.env.context))
if self.product_id.tracking != 'none' and not self.lot_id.id:
raise UserError(_('You should provide a lot number for the final product.'))
- if self.mo_id:
- if self.mo_id.state != 'done':
- raise UserError(_('You cannot unbuild a undone manufacturing order.'))
+ if self.mo_id and self.mo_id.state != 'done':
+ raise UserError(_('You cannot unbuild a undone manufacturing order.'))
consume_moves = self._generate_consume_moves()
consume_moves._action_confirm()
produce_moves = self._generate_produce_moves()
- produce_moves.with_context(default_lot_id=False)._action_confirm()
+ produce_moves._action_confirm()
+ produce_moves.quantity = 0
finished_moves = consume_moves.filtered(lambda m: m.product_id == self.product_id)
consume_moves -= finished_moves
@@ -153,18 +155,15 @@ class MrpUnbuild(models.Model):
raise UserError(_('Some of your byproducts are tracked, you have to specify a manufacturing order in order to retrieve the correct byproducts.'))
for finished_move in finished_moves:
- if finished_move.has_tracking != 'none':
- self.env['stock.move.line'].create({
- 'move_id': finished_move.id,
- 'lot_id': self.lot_id.id,
- 'qty_done': finished_move.product_uom_qty,
- 'product_id': finished_move.product_id.id,
- 'product_uom_id': finished_move.product_uom.id,
- 'location_id': finished_move.location_id.id,
- 'location_dest_id': finished_move.location_dest_id.id,
- })
- else:
- finished_move.quantity_done = finished_move.product_uom_qty
+ self.env['stock.move.line'].create({
+ 'move_id': finished_move.id,
+ 'lot_id': self.lot_id.id,
+ 'quantity': finished_move.product_uom_qty,
+ 'product_id': finished_move.product_id.id,
+ 'product_uom_id': finished_move.product_uom.id,
+ 'location_id': finished_move.location_id.id,
+ 'location_dest_id': finished_move.location_dest_id.id,
+ })
# TODO: Will fail if user do more than one unbuild with lot on the same MO. Need to check what other unbuild has aready took
qty_already_used = defaultdict(float)
@@ -178,12 +177,12 @@ class MrpUnbuild(models.Model):
moves_lines = moves_lines.filtered(lambda ml: self.lot_id in ml.produce_line_ids.lot_id) # FIXME sle: double check with arm
for move_line in moves_lines:
# Iterate over all move_lines until we unbuilded the correct quantity.
- taken_quantity = min(needed_quantity, move_line.qty_done - qty_already_used[move_line])
+ taken_quantity = min(needed_quantity, move_line.quantity - qty_already_used[move_line])
if taken_quantity:
self.env['stock.move.line'].create({
'move_id': move.id,
'lot_id': move_line.lot_id.id,
- 'qty_done': taken_quantity,
+ 'quantity': taken_quantity,
'product_id': move.product_id.id,
'product_uom_id': move_line.product_uom_id.id,
'location_id': move.location_id.id,
@@ -192,12 +191,13 @@ class MrpUnbuild(models.Model):
needed_quantity -= taken_quantity
qty_already_used[move_line] += taken_quantity
else:
- move.quantity_done = float_round(move.product_uom_qty, precision_rounding=move.product_uom.rounding)
+ move.quantity = float_round(move.product_uom_qty, precision_rounding=move.product_uom.rounding)
+ (finished_moves | consume_moves | produce_moves).picked = True
finished_moves._action_done()
consume_moves._action_done()
produce_moves._action_done()
- produced_move_line_ids = produce_moves.mapped('move_line_ids').filtered(lambda ml: ml.qty_done > 0)
+ produced_move_line_ids = produce_moves.mapped('move_line_ids').filtered(lambda ml: ml.quantity > 0)
consume_moves.mapped('move_line_ids').write({'produce_line_ids': [(6, 0, produced_move_line_ids.ids)]})
if self.mo_id:
unbuild_msg = _("%(qty)s %(measure)s unbuilt in %(order)s",
@@ -300,7 +300,7 @@ class MrpUnbuild(models.Model):
'default_location_id': self.location_id.id,
'default_unbuild_id': self.id,
'default_quantity': unbuild_qty,
- 'default_product_uom_name': self.product_id.uom_name
+ 'default_product_uom_name': self.product_id.uom_name,
},
- 'target': 'new'
+ 'target': 'new',
}
diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py
index 34d9137bcdc..f159d6879af 100644
--- a/addons/mrp/models/mrp_workorder.py
+++ b/addons/mrp/models/mrp_workorder.py
@@ -830,8 +830,8 @@ class MrpWorkorder(models.Model):
if move_line:
if self.product_id.tracking == 'serial':
raise UserError(_('You cannot produce the same serial number twice.'))
- move_line.reserved_uom_qty += self.qty_producing
- move_line.qty_done += self.qty_producing
+ move_line.picked = True
+ move_line.quantity += self.qty_producing
else:
quantity = self.product_uom_id._compute_quantity(self.qty_producing, self.product_id.uom_id, rounding_method='HALF-UP')
putaway_location = production_move.location_dest_id._get_putaway_strategy(self.product_id, quantity)
@@ -839,17 +839,14 @@ class MrpWorkorder(models.Model):
'move_id': production_move.id,
'product_id': production_move.product_id.id,
'lot_id': self.finished_lot_id.id,
- 'reserved_uom_qty': self.qty_producing,
'product_uom_id': self.product_uom_id.id,
- 'qty_done': self.qty_producing,
+ 'quantity': self.qty_producing,
'location_id': production_move.location_id.id,
'location_dest_id': putaway_location.id,
})
else:
rounding = production_move.product_uom.rounding
- production_move._set_quantity_done(
- float_round(self.qty_producing, precision_rounding=rounding)
- )
+ production_move.quantity = float_round(self.qty_producing, precision_rounding=rounding)
def _should_start_timer(self):
return True
diff --git a/addons/mrp/models/product.py b/addons/mrp/models/product.py
index ea7c96d19e2..682d83b7fdb 100644
--- a/addons/mrp/models/product.py
+++ b/addons/mrp/models/product.py
@@ -314,7 +314,7 @@ class ProductProduct(models.Model):
def _count_returned_sn_products(self, sn_lot):
res = self.env['stock.move.line'].search_count([
('lot_id', '=', sn_lot.id),
- ('qty_done', '=', 1),
+ ('quantity', '=', 1),
('state', '=', 'done'),
('production_id', '=', False),
('location_id.usage', '=', 'production'),
diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py
index 9ce77a986dc..c327ffa03ff 100644
--- a/addons/mrp/models/stock_move.py
+++ b/addons/mrp/models/stock_move.py
@@ -69,19 +69,10 @@ class StockMoveLine(models.Model):
lines |= raw_moves_lines.filtered(lambda ml: ml.product_id == self.product_id and (ml.lot_id or ml.lot_name))
return lines
- def _reservation_is_updatable(self, quantity, reserved_quant):
- self.ensure_one()
- if self.produce_line_ids.lot_id:
- ml_remaining_qty = self.qty_done - self.reserved_uom_qty
- ml_remaining_qty = self.product_uom_id._compute_quantity(ml_remaining_qty, self.product_id.uom_id, rounding_method="HALF-UP")
- if float_compare(ml_remaining_qty, quantity, precision_rounding=self.product_id.uom_id.rounding) < 0:
- return False
- return super(StockMoveLine, self)._reservation_is_updatable(quantity, reserved_quant)
-
def write(self, vals):
for move_line in self:
production = move_line.move_id.production_id or move_line.move_id.raw_material_production_id
- if production and move_line.state == 'done' and any(field in vals for field in ('lot_id', 'location_id', 'qty_done')):
+ if production and move_line.state == 'done' and any(field in vals for field in ('lot_id', 'location_id', 'quantity')):
move_line._log_message(production, move_line, 'mrp.track_production_move_template', vals)
return super(StockMoveLine, self).write(vals)
@@ -229,7 +220,8 @@ class StockMove(models.Model):
def _onchange_product_uom_qty(self):
if self.raw_material_production_id and self.has_tracking == 'none':
mo = self.raw_material_production_id
- self._update_quantity_done(mo)
+ new_qty = float_round((mo.qty_producing - mo.qty_produced) * self.unit_factor, precision_rounding=self.product_uom.rounding)
+ self.quantity = new_qty
@api.model
def default_get(self, fields_list):
@@ -362,12 +354,12 @@ class StockMove(models.Model):
moves_ids_to_return.add(move.id)
continue
if float_is_zero(move.product_uom_qty, precision_rounding=move.product_uom.rounding):
- factor = move.product_uom._compute_quantity(move.quantity_done, bom.product_uom_id) / bom.product_qty
+ factor = move.product_uom._compute_quantity(move.quantity, bom.product_uom_id) / bom.product_qty
else:
factor = move.product_uom._compute_quantity(move.product_uom_qty, bom.product_uom_id) / bom.product_qty
boms, lines = bom.sudo().explode(move.product_id, factor, picking_type=bom.picking_type_id)
for bom_line, line_data in lines:
- if move.picking_id.immediate_transfer or float_is_zero(move.product_uom_qty, precision_rounding=move.product_uom.rounding) or self.env.context.get('is_scrap'):
+ if float_is_zero(move.product_uom_qty, precision_rounding=move.product_uom.rounding) or self.env.context.get('is_scrap'):
phantom_moves_vals_list += move._generate_move_phantom(bom_line, 0, line_data['qty'])
else:
phantom_moves_vals_list += move._generate_move_phantom(bom_line, line_data['qty'], 0)
@@ -375,7 +367,7 @@ class StockMove(models.Model):
moves_ids_to_unlink.add(move.id)
move_to_unlink = self.env['stock.move'].browse(moves_ids_to_unlink).sudo()
- move_to_unlink.quantity_done = 0
+ move_to_unlink.quantity = 0
move_to_unlink._action_cancel()
move_to_unlink.unlink()
if phantom_moves_vals_list:
@@ -423,9 +415,9 @@ class StockMove(models.Model):
'product_id': bom_line.product_id.id,
'product_uom': bom_line.product_uom_id.id,
'product_uom_qty': product_qty,
- 'quantity_done': quantity_done,
- 'state': 'draft', # will be confirmed below
+ 'quantity': quantity_done,
'name': self.name,
+ 'picked': self.picked,
'bom_line_id': bom_line.id,
}
@@ -478,8 +470,6 @@ class StockMove(models.Model):
# Do not update extra product quantities
if float_is_zero(self.product_uom_qty, precision_rounding=self.product_uom.rounding):
return True
- if (not self.raw_material_production_id.use_auto_consume_components_lots and self.has_tracking != 'none') or self.manual_consumption or self._origin.manual_consumption:
- return True
return False
def _key_assign_picking(self):
@@ -542,15 +532,6 @@ class StockMove(models.Model):
else:
return 0.0
- def _update_quantity_done(self, mo):
- self.ensure_one()
- new_qty = float_round((mo.qty_producing - mo.qty_produced) * self.unit_factor, precision_rounding=self.product_uom.rounding)
- if not self.is_quantity_done_editable:
- self.move_line_ids.filtered(lambda ml: ml.state not in ('done', 'cancel')).qty_done = 0
- self.move_line_ids = self._set_quantity_done_prepare_vals(new_qty)
- else:
- self.quantity_done = new_qty
-
def _update_candidate_moves_list(self, candidate_moves_set):
super()._update_candidate_moves_list(candidate_moves_set)
for production in self.mapped('raw_material_production_id'):
@@ -586,3 +567,11 @@ class StockMove(models.Model):
def _determine_is_manual_consumption(self, product, production, bom_line):
return (product.product_tmpl_id.tracking != 'none' and not production.use_auto_consume_components_lots) or \
(product.product_tmpl_id.tracking == 'none' and bom_line and bom_line.manual_consumption)
+
+ def _get_relevant_state_among_moves(self):
+ res = super()._get_relevant_state_among_moves()
+ if res == 'partially_available'\
+ and self.raw_material_production_id\
+ and all(float_compare(move.quantity, move.should_consume_qty, precision_rounding=move.product_uom.rounding) == 0 for move in self):
+ res = 'assigned'
+ return res
diff --git a/addons/mrp/models/stock_scrap.py b/addons/mrp/models/stock_scrap.py
index 5484e9a2ca0..ec5da7bcbbe 100644
--- a/addons/mrp/models/stock_scrap.py
+++ b/addons/mrp/models/stock_scrap.py
@@ -3,6 +3,7 @@
from odoo import _, api, fields, models
+
class StockScrap(models.Model):
_inherit = 'stock.scrap'
@@ -55,7 +56,7 @@ class StockScrap(models.Model):
else:
return super()._onchange_serial_number()
- @api.depends('move_ids', 'move_ids.move_line_ids.qty_done', 'product_id')
+ @api.depends('move_ids', 'move_ids.move_line_ids.quantity', 'product_id')
def _compute_scrap_qty(self):
self.scrap_qty = 1
for scrap in self:
diff --git a/addons/mrp/report/mrp_production_templates.xml b/addons/mrp/report/mrp_production_templates.xml
index 669afe0e958..656a247ff1c 100644
--- a/addons/mrp/report/mrp_production_templates.xml
+++ b/addons/mrp/report/mrp_production_templates.xml
@@ -115,7 +115,7 @@
|
-
+
|
@@ -137,12 +137,12 @@
-
+
-
+
@@ -173,7 +173,7 @@
Quantity:
1.0
-
+
diff --git a/addons/mrp/report/mrp_report_mo_overview.py b/addons/mrp/report/mrp_report_mo_overview.py
index db09b65cb1a..36495820ebd 100644
--- a/addons/mrp/report/mrp_report_mo_overview.py
+++ b/addons/mrp/report/mrp_report_mo_overview.py
@@ -199,8 +199,8 @@ class ReportMoOverview(models.AbstractModel):
for move in record.move_raw_ids:
if move.product_id.detailed_type != 'product':
continue
- components_qty_to_produce[move.product_id] += move.product_uom._compute_quantity(move.product_uom_qty, move.product_id.uom_id)
- components_qty_reserved[move.product_id] += move.product_uom._compute_quantity(move.reserved_availability, move.product_id.uom_id)
+ components_qty_to_produce[move.product_id] += move.product_qty
+ components_qty_reserved[move.product_id] += move.product_uom._compute_quantity(move.quantity, move.product_id.uom_id)
producible_qty = record.product_qty
for product_id, comp_qty_to_produce in components_qty_to_produce.items():
if float_is_zero(comp_qty_to_produce, precision_rounding=product_id.uom_id.rounding):
@@ -419,7 +419,7 @@ class ReportMoOverview(models.AbstractModel):
def _format_component_move(self, production, move_raw, replenishments, replenish_data, level, index):
currency = (production.company_id or self.env.company).currency_id
product = move_raw.product_id
- quantity = move_raw.product_uom_qty if move_raw.state != 'done' else move_raw.quantity_done
+ quantity = move_raw.product_uom_qty if move_raw.state != 'done' else move_raw.quantity
replenish_mo_cost, dummy_real_cost = self._compute_cost_sums(replenishments)
replenish_quantity = sum(rep.get('summary', {}).get('quantity', 0.0) for rep in replenishments)
missing_quantity = quantity - replenish_quantity
@@ -495,7 +495,7 @@ class ReportMoOverview(models.AbstractModel):
def _get_replenishment_lines(self, production, move_raw, replenish_data, level, current_index):
product = move_raw.product_id
- quantity = move_raw.product_uom_qty if move_raw.state != 'done' else move_raw.quantity_done
+ quantity = move_raw.product_uom_qty if move_raw.state != 'done' else move_raw.quantity
currency = (production.company_id or self.env.company).currency_id
forecast = replenish_data['products'][product.id].get('forecast', [])
current_lines = filter(lambda line: line.get('document_in', False) and line.get('document_out', False)
@@ -848,7 +848,7 @@ class ReportMoOverview(models.AbstractModel):
if move.state not in ('partially_available', 'assigned'):
continue
# count reserved stock in move_raw's uom
- reserved = move.product_uom._compute_quantity(move.reserved_availability, move_raw.product_uom)
+ reserved = move.product_uom._compute_quantity(move.quantity, move_raw.product_uom)
# check if the move reserved qty was counted before (happens if multiple outs share pick/pack)
reserved = min(reserved - move.product_uom._compute_quantity(replenish_data['qty_already_reserved'][move], move_raw.product_uom), move_raw.product_uom_qty)
total_reserved += reserved
diff --git a/addons/mrp/report/mrp_zebra_production_templates.xml b/addons/mrp/report/mrp_zebra_production_templates.xml
index 0190a8be527..fb6fb2e6e40 100644
--- a/addons/mrp/report/mrp_zebra_production_templates.xml
+++ b/addons/mrp/report/mrp_zebra_production_templates.xml
@@ -7,7 +7,7 @@
-
+
diff --git a/addons/mrp/static/src/widgets/mrp_production_components_x2many.js b/addons/mrp/static/src/widgets/mrp_production_components_x2many.js
index d82200e8b07..bd60946c5eb 100644
--- a/addons/mrp/static/src/widgets/mrp_production_components_x2many.js
+++ b/addons/mrp/static/src/widgets/mrp_production_components_x2many.js
@@ -7,7 +7,7 @@ import { StockMoveX2ManyField, MovesListRenderer } from "@stock/views/picking_fo
export class MrpProductionComponentsListRenderer extends MovesListRenderer {
getCellClass(column, record) {
let classNames = super.getCellClass(...arguments);
- if (column.name == "quantity_done" && !record.data.manual_consumption) {
+ if (column.name == "quantity" && !record.data.manual_consumption) {
classNames += ' o_non_manual_consumption';
}
return classNames;
diff --git a/addons/mrp/static/tests/tours/mrp_manual_consumption.js b/addons/mrp/static/tests/tours/mrp_manual_consumption.js
index 635cd1065ea..6021040c20e 100644
--- a/addons/mrp/static/tests/tours/mrp_manual_consumption.js
+++ b/addons/mrp/static/tests/tours/mrp_manual_consumption.js
@@ -7,15 +7,15 @@ registry.category("web_tour.tours").add('test_mrp_manual_consumption', {
test: true,
steps: () => [
{
- trigger: 'div[name=move_raw_ids] td[name="quantity_done"]:last:contains("5.00")',
+ trigger: 'div[name=move_raw_ids] td[name="quantity"]:last:contains("5.00")',
run: () => {},
},
{
- trigger: 'div[name=move_raw_ids] td[name="quantity_done"]:last',
+ trigger: 'div[name=move_raw_ids] td[name="quantity"]:last',
run: 'click',
},
{
- trigger: 'div[name="quantity_done"] input',
+ trigger: 'div[name="quantity"] input',
run: 'text 6.0'
},
{
@@ -31,7 +31,7 @@ registry.category("web_tour.tours").add('test_mrp_manual_consumption', {
trigger: ".o_pager_value:first()",
},
{
- trigger: 'div[name=move_raw_ids] td[name="quantity_done"]:last:contains("6.00")',
+ trigger: 'div[name=move_raw_ids] td[name="quantity"]:last:contains("6.00")',
run: () => {},
},
{
@@ -56,7 +56,7 @@ registry.category("web_tour.tours").add('test_mrp_manual_consumption', {
trigger: ".o_pager_value:first()",
},
{
- trigger: 'div[name=move_raw_ids] td[name="quantity_done"]:last:contains("2.00")',
+ trigger: 'div[name=move_raw_ids] td[name="quantity"]:last:contains("2.00")',
run: () => {},
},
{
diff --git a/addons/mrp/tests/test_backorder.py b/addons/mrp/tests/test_backorder.py
index 80813c7a5ed..c5e06be0813 100644
--- a/addons/mrp/tests/test_backorder.py
+++ b/addons/mrp/tests/test_backorder.py
@@ -74,7 +74,7 @@ class TestMrpProductionBackorder(TestMrpCommon):
self.assertEqual(mo_backorder.product_id.id, production.product_id.id)
self.assertEqual(mo_backorder.product_qty, 3)
self.assertEqual(sum(mo_backorder.move_raw_ids.filtered(lambda m: m.product_id.id == product_to_use_1.id).mapped("product_uom_qty")), 9)
- self.assertEqual(mo_backorder.reserve_visible, False) # the reservation of the first MO should've been moved here
+ self.assertEqual(mo_backorder.reserve_visible, False) # the reservation is retrigger depending on the picking type
def test_no_tracking_pbm_1(self):
"""Create a MO for 4 product. Produce 1. The backorder button should
@@ -195,18 +195,18 @@ class TestMrpProductionBackorder(TestMrpCommon):
self.env['stock.quant']._update_available_quantity(p1, self.stock_location, nb_product_todo*4, lot_id=lot_1)
self.env['stock.quant']._update_available_quantity(p2, self.stock_location, nb_product_todo, lot_id=lot_2)
- production.action_assign()
active_production = production
for i in range(nb_product_todo):
+ active_production.action_assign()
details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p1), view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 4
+ ml.quantity = 4
ml.lot_id = lot_1
details_operation_form.save()
details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p2), view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
+ ml.quantity = 1
ml.lot_id = lot_2
details_operation_form.save()
@@ -215,6 +215,7 @@ class TestMrpProductionBackorder(TestMrpCommon):
production_form.lot_producing_id = lot_final
active_production = production_form.save()
+ active_production.move_raw_ids.picked = True
active_production.button_mark_done()
if i + 1 != nb_product_todo: # If last MO, don't make a backorder
action = active_production.button_mark_done()
@@ -249,7 +250,7 @@ class TestMrpProductionBackorder(TestMrpCommon):
details_operation_form = Form(production.move_raw_ids.filtered(lambda m: m.product_id == p1), view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 4 * 3
+ ml.quantity = 4 * 3
details_operation_form.save()
# Consume 1 Product from lot1 and 2 from lot 2
@@ -257,10 +258,10 @@ class TestMrpProductionBackorder(TestMrpCommon):
self.assertEqual(len(p2_smls), 2, 'One for each lot')
details_operation_form = Form(production.move_raw_ids.filtered(lambda m: m.product_id == p2), view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
+ ml.quantity = 1
ml.lot_id = lot1
with details_operation_form.move_line_ids.edit(1) as ml:
- ml.qty_done = 2
+ ml.quantity = 2
ml.lot_id = lot2
details_operation_form.save()
@@ -272,7 +273,7 @@ class TestMrpProductionBackorder(TestMrpCommon):
p2_bo_mls = production.procurement_group_id.mrp_production_ids[-1].move_raw_ids.filtered(lambda m: m.product_id == p2).move_line_ids
self.assertEqual(len(p2_bo_mls), 1)
self.assertEqual(p2_bo_mls.lot_id, lot1)
- self.assertEqual(p2_bo_mls.reserved_qty, 2)
+ self.assertEqual(p2_bo_mls.quantity, 2)
def test_uom_backorder(self):
"""
@@ -352,22 +353,20 @@ class TestMrpProductionBackorder(TestMrpCommon):
production.action_assign()
active_production = production
for i in range(nb_product_todo):
-
- details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p1), view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
- ml.lot_id = serials_p1[i]
- details_operation_form.save()
- details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p2), view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
- ml.lot_id = serials_p2[i]
- details_operation_form.save()
-
production_form = Form(active_production)
production_form.qty_producing = 1
production_form.lot_producing_id = serials_final[i]
active_production = production_form.save()
+ details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p1), view=self.env.ref('stock.view_stock_move_operations'))
+ with details_operation_form.move_line_ids.edit(0) as ml:
+ ml.quantity = 1
+ ml.lot_id = serials_p1[i]
+ details_operation_form.save()
+ details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p2), view=self.env.ref('stock.view_stock_move_operations'))
+ with details_operation_form.move_line_ids.edit(0) as ml:
+ ml.quantity = 1
+ ml.lot_id = serials_p2[i]
+ details_operation_form.save()
active_production.button_mark_done()
if i + 1 != nb_product_todo: # If last MO, don't make a backorder
action = active_production.button_mark_done()
@@ -556,6 +555,7 @@ class TestMrpProductionBackorder(TestMrpCommon):
self.assertEqual(production.reserve_visible, False)
backorder = produce_one(production)
self.assertEqual(backorder.state, 'confirmed')
+ # The backorder is re reserved depending on the picking type
self.assertEqual(backorder.reserve_visible, False)
diff --git a/addons/mrp/tests/test_bom.py b/addons/mrp/tests/test_bom.py
index e452279bc7b..db7032f4741 100644
--- a/addons/mrp/tests/test_bom.py
+++ b/addons/mrp/tests/test_bom.py
@@ -1264,7 +1264,7 @@ class TestBoM(TestMrpCommon):
operation.duration_expected = 480
with mo_form.move_byproduct_ids.new() as by_product_line:
by_product_line.product_id = by_product
- by_product_line.quantity_done = 6
+ by_product_line.quantity = 6
mo_3 = mo_form.save()
bom_from_mo_3 = generate_bom_from_mo(mo_3)
# Checks the MO's data.
diff --git a/addons/mrp/tests/test_byproduct.py b/addons/mrp/tests/test_byproduct.py
index 38856ca0ac1..69e23e2e433 100644
--- a/addons/mrp/tests/test_byproduct.py
+++ b/addons/mrp/tests/test_byproduct.py
@@ -105,7 +105,7 @@ class TestMrpByProduct(common.TransactionCase):
mnf_product_a.action_confirm()
self.assertEqual(mnf_product_a.state, "confirmed")
mnf_product_a.move_raw_ids._action_assign()
- mnf_product_a.move_raw_ids.quantity_done = mnf_product_a.move_raw_ids.product_uom_qty
+ mnf_product_a.move_raw_ids.picked = True
mnf_product_a.move_raw_ids._action_done()
self.assertEqual(mnf_product_a.state, "progress")
mnf_product_a.qty_producing = 2
@@ -357,8 +357,6 @@ class TestMrpByProduct(common.TransactionCase):
'production_id': mo.id,
'location_id': self.ref('stock.stock_location_stock'),
'location_dest_id': self.ref('stock.stock_location_output'),
- 'product_uom_qty': 0,
- 'quantity_done': 0
})
byproduct_2 = self.env['stock.move'].create({
'name': 'By Product 2',
@@ -367,8 +365,6 @@ class TestMrpByProduct(common.TransactionCase):
'production_id': mo.id,
'location_id': self.ref('stock.stock_location_stock'),
'location_dest_id': self.ref('stock.stock_location_output'),
- 'product_uom_qty': 0,
- 'quantity_done': 0
})
# Update byproduct has cost share > 100%
@@ -404,6 +400,5 @@ class TestMrpByProduct(common.TransactionCase):
mo_form.qty_producing = 1
mo = mo_form.save()
self.assertEqual(mo.state, 'to_close')
- mo.move_byproduct_ids[0].quantity_done = 1
mo.button_mark_done()
self.assertEqual(mo.state, 'done')
diff --git a/addons/mrp/tests/test_consume_component.py b/addons/mrp/tests/test_consume_component.py
index 31c901f7e11..74f968a92cd 100644
--- a/addons/mrp/tests/test_consume_component.py
+++ b/addons/mrp/tests/test_consume_component.py
@@ -1,7 +1,7 @@
import copy
from odoo.exceptions import UserError
-from odoo.tests import common, tagged
+from odoo.tests import common, tagged, Form
class TestConsumeComponentCommon(common.TransactionCase):
@@ -261,7 +261,7 @@ class TestConsumeComponent(TestConsumeComponentCommon):
# Quantities are fully reserved (stock.move state is available)
mo_all.action_assign()
for mov in mo_all.move_raw_ids:
- self.assertEqual(mov.product_qty, mov.reserved_availability, "Reserved quantity shall be equal to To Consume quantity.")
+ self.assertEqual(mov.product_qty, mov.quantity, "Reserved quantity shall be equal to To Consume quantity.")
# Test for Serial Product
self.executeConsumptionTriggers(mo_serial)
@@ -269,9 +269,9 @@ class TestConsumeComponent(TestConsumeComponentCommon):
self.executeConsumptionTriggers(mo_lot)
for mov in mo_all.move_raw_ids:
if mov.has_tracking == 'none' or mov.raw_material_production_id.state == 'done':
- self.assertEqual(mov.product_qty, mov.quantity_done, "Done quantity shall be equal to To Consume quantity.")
+ self.assertTrue(mov.picked, "non tracked components should be picked")
else:
- self.assertEqual(0, mov.quantity_done, "Done quantity shall be equal to 0.")
+ self.assertFalse(mov.picked, "tracked components should be picked")
def test_option_enabled_and_qty_available(self):
"""Option enabled, qty available
@@ -296,13 +296,13 @@ class TestConsumeComponent(TestConsumeComponentCommon):
# Quantities are fully reserved (stock.move state is available)
mo_all.action_assign()
for mov in mo_all.move_raw_ids:
- self.assertEqual(mov.product_qty, mov.reserved_availability, "Reserved quantity shall be equal to To Consume quantity.")
+ self.assertEqual(mov.product_qty, mov.quantity, "Reserved quantity shall be equal to To Consume quantity.")
self.executeConsumptionTriggers(mo_serial)
self.executeConsumptionTriggers(mo_none)
self.executeConsumptionTriggers(mo_lot)
for mov in mo_all.move_raw_ids:
- self.assertEqual(mov.product_qty, mov.quantity_done, "Done quantity shall be equal to To Consume quantity.")
+ self.assertTrue(mov.picked, "All components should be picked")
def test_option_enabled_and_qty_not_available(self):
"""Option enabled, qty not available
@@ -320,7 +320,7 @@ class TestConsumeComponent(TestConsumeComponentCommon):
# Quantities are not reserved at all (stock.move state is confirmed)
mo_all.action_assign()
for mov in mo_all.move_raw_ids:
- self.assertEqual(0, mov.reserved_availability, "Reserved quantity shall be equal to 0.")
+ self.assertEqual(0, mov.quantity, "Reserved quantity shall be equal to 0.")
self.executeConsumptionTriggers(mo_serial)
self.executeConsumptionTriggers(mo_none)
@@ -328,9 +328,9 @@ class TestConsumeComponent(TestConsumeComponentCommon):
for mov in mo_all.move_raw_ids:
if mov.has_tracking == 'none':
- self.assertEqual(mov.product_qty, mov.quantity_done, "Done quantity shall be equal to To Consume quantity.")
+ self.assertTrue(mov.picked, "components should be picked even without no quantity reserved")
else:
- self.assertEqual(0, mov.quantity_done, "Done quantity shall be equal to To Consume quantity.")
+ self.assertEqual(mov.product_qty, mov.quantity, "Done quantity shall be equal to To Consume quantity.")
def test_option_enabled_and_qty_partially_available(self):
"""Option enabled, qty partially available
@@ -360,23 +360,24 @@ class TestConsumeComponent(TestConsumeComponentCommon):
mo.action_assign()
for mov in mo.move_raw_ids:
if mov.has_tracking == "none":
- self.assertEqual(raw_none_qty, mov.reserved_availability, "Reserved quantity shall be equal to " + str(raw_none_qty)+ ".")
+ self.assertEqual(raw_none_qty, mov.quantity, "Reserved quantity shall be equal to " + str(raw_none_qty) + ".")
else:
- self.assertEqual(raw_tracked_qty, mov.reserved_availability, "Reserved quantity shall be equal to " + str(raw_tracked_qty)+ ".")
+ self.assertEqual(raw_tracked_qty, mov.quantity, "Reserved quantity shall be equal to " + str(raw_tracked_qty) + ".")
if serialTrigger is None:
self.executeConsumptionTriggers(mo)
elif serialTrigger == 1:
- mo.qty_producing = mo.product_qty
- mo._onchange_producing()
+ mo_form = Form(mo)
+ mo_form.qty_producing = mo_form.product_qty
+ mo = mo_form.save()
elif serialTrigger == 2:
mo.action_generate_serial()
for mov in mo.move_raw_ids:
if mov.has_tracking == "none":
- self.assertEqual(mov.product_qty, mov.quantity_done, "Done quantity shall be equal to To Consume quantity.")
+ self.assertTrue(mov.picked, "non tracked components should be picked")
else:
- self.assertEqual(raw_tracked_qty, mov.quantity_done, "Done quantity shall be equal to " + str(raw_tracked_qty)+ ".")
+ self.assertEqual(mov.product_qty, mov.quantity, "Done quantity shall be equal to To Consume quantity.")
mo.action_cancel()
testUnit(self.mo_none_tmpl)
diff --git a/addons/mrp/tests/test_manual_consumption.py b/addons/mrp/tests/test_manual_consumption.py
index 3a8496e6e13..5d5188b00d4 100644
--- a/addons/mrp/tests/test_manual_consumption.py
+++ b/addons/mrp/tests/test_manual_consumption.py
@@ -9,9 +9,9 @@ from odoo.tests import tagged, Form, HttpCase
class TestTourManualConsumption(HttpCase):
def test_mrp_manual_consumption(self):
"""Test manual consumption mechanism. Test when manual consumption is
- True, quantity_done won't be updated automatically. Bom line with tracked
+ True, quantity won't be updated automatically. Bom line with tracked
products or operations should be set to manual consumption automatically.
- Also test that when manually change quantity_done, manual consumption
+ Also test that when manually change quantity, manual consumption
will be set to True. Also test when create backorder, the manual consumption
should be set according to the bom.
"""
@@ -58,22 +58,25 @@ class TestTourManualConsumption(HttpCase):
mo = mo_form.save()
move_nt, move_sn, move_lot = mo.move_raw_ids
self.assertEqual(move_nt.manual_consumption, False)
- self.assertEqual(move_nt.quantity_done, 5)
+ self.assertEqual(move_nt.quantity, 5)
+ self.assertTrue(move_nt.picked)
self.assertEqual(move_sn.manual_consumption, True)
- self.assertEqual(move_sn.quantity_done, 0)
+ self.assertEqual(move_sn.quantity, 5)
+ self.assertFalse(move_sn.picked)
self.assertEqual(move_lot.manual_consumption, True)
- self.assertEqual(move_lot.quantity_done, 0)
+ self.assertEqual(move_lot.quantity, 5)
+ self.assertFalse(move_lot.picked)
action_id = self.env.ref('mrp.menu_mrp_production_action').action
url = "/web#model=mrp.production&view_type=form&action=%s&id=%s" % (str(action_id.id), str(mo.id))
- self.start_tour(url, "test_mrp_manual_consumption", login="admin", timeout=200)
+ self.start_tour(url, "test_mrp_manual_consumption", login="admin", timeout=100)
self.assertEqual(move_nt.manual_consumption, True)
- self.assertEqual(move_nt.quantity_done, 6.0)
+ self.assertEqual(move_nt.quantity, 6.0)
self.assertEqual(move_sn.manual_consumption, True)
- self.assertEqual(move_sn.quantity_done, 0)
+ self.assertEqual(move_sn.quantity, 0)
self.assertEqual(move_lot.manual_consumption, True)
- self.assertEqual(move_lot.quantity_done, 0)
+ self.assertEqual(move_lot.quantity, 0)
backorder = mo.procurement_group_id.mrp_production_ids - mo
move_nt = backorder.move_raw_ids.filtered(lambda m: m.product_id == product_nt)
@@ -111,12 +114,13 @@ class TestManualConsumption(TestMrpCommon):
mo_form = Form(mo)
mo_form.qty_producing = 1
mo_form.save()
- self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c1.id).mapped("quantity_done")), 0)
- self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c2.id).mapped("quantity_done")), 1)
+ self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c1.id).mapped("quantity")), 4)
+ self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c2.id).mapped("quantity")), 1)
+ self.assertEqual(sorted(mo.move_raw_ids.mapped('picked')), sorted([False, True]))
details_operation_form = Form(mo.move_raw_ids.filtered(lambda m: m.product_id == c1), view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 4
+ ml.quantity = 4
ml.lot_id = lot
details_operation_form.save()
@@ -152,8 +156,8 @@ class TestManualConsumption(TestMrpCommon):
mo_form = Form(mo)
mo_form.qty_producing = 1
mo_form.save()
- self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c1.id).mapped("quantity_done")), 4)
- self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c2.id).mapped("quantity_done")), 1)
+ self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c1.id).mapped("quantity")), 4)
+ self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c2.id).mapped("quantity")), 1)
action = mo.button_mark_done()
backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
diff --git a/addons/mrp/tests/test_multicompany.py b/addons/mrp/tests/test_multicompany.py
index fda22d07180..0a6fdf165ec 100644
--- a/addons/mrp/tests/test_multicompany.py
+++ b/addons/mrp/tests/test_multicompany.py
@@ -175,8 +175,9 @@ class TestMrpMulticompany(common.TransactionCase):
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = lot_b
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
+ mo.move_raw_ids.picked = True
with self.assertRaises(UserError):
mo.button_mark_done()
diff --git a/addons/mrp/tests/test_order.py b/addons/mrp/tests/test_order.py
index 6e1a6f16d3c..681b297eabe 100644
--- a/addons/mrp/tests/test_order.py
+++ b/addons/mrp/tests/test_order.py
@@ -182,24 +182,24 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 2
+ ml.quantity = 2
details_operation_form.save()
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 11
+ ml.quantity = 11
details_operation_form.save()
self.assertEqual(len(mo.move_raw_ids), 2)
self.assertEqual(len(mo.move_raw_ids.mapped('move_line_ids')), 2)
- self.assertEqual(mo.move_raw_ids[0].move_line_ids.mapped('qty_done'), [2])
- self.assertEqual(mo.move_raw_ids[1].move_line_ids.mapped('qty_done'), [11])
- self.assertEqual(mo.move_raw_ids[0].quantity_done, 2)
- self.assertEqual(mo.move_raw_ids[1].quantity_done, 11)
+ self.assertEqual(mo.move_raw_ids[0].move_line_ids.mapped('quantity'), [2])
+ self.assertEqual(mo.move_raw_ids[1].move_line_ids.mapped('quantity'), [11])
+ self.assertEqual(mo.move_raw_ids[0].quantity, 2)
+ self.assertEqual(mo.move_raw_ids[1].quantity, 11)
mo.button_mark_done()
self.assertEqual(len(mo.move_raw_ids), 2)
self.assertEqual(len(mo.move_raw_ids.mapped('move_line_ids')), 2)
- self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [2, 11])
- self.assertEqual(mo.move_raw_ids.mapped('move_line_ids.qty_done'), [2, 11])
+ self.assertEqual(mo.move_raw_ids.mapped('quantity'), [2, 11])
+ self.assertEqual(mo.move_raw_ids.mapped('move_line_ids.quantity'), [2, 11])
def test_under_consumption(self):
""" Consume less component quantity than the initial demand.
@@ -218,26 +218,26 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 0
+ ml.quantity = 0
details_operation_form.save()
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 5
+ ml.quantity = 5
details_operation_form.save()
self.assertEqual(len(mo.move_raw_ids), 2)
self.assertEqual(len(mo.move_raw_ids.mapped('move_line_ids')), 2)
- self.assertEqual(mo.move_raw_ids[0].move_line_ids.mapped('qty_done'), [0])
- self.assertEqual(mo.move_raw_ids[1].move_line_ids.mapped('qty_done'), [5])
- self.assertEqual(mo.move_raw_ids[0].quantity_done, 0)
- self.assertEqual(mo.move_raw_ids[1].quantity_done, 5)
+ self.assertEqual(mo.move_raw_ids[0].move_line_ids.mapped('quantity'), [0])
+ self.assertEqual(mo.move_raw_ids[1].move_line_ids.mapped('quantity'), [5])
+ self.assertEqual(mo.move_raw_ids[0].quantity, 0)
+ self.assertEqual(mo.move_raw_ids[1].quantity, 5)
mo.button_mark_done()
self.assertEqual(len(mo.move_raw_ids), 2)
self.assertEqual(len(mo.move_raw_ids.mapped('move_line_ids')), 1)
- self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [0, 5])
+ self.assertEqual(mo.move_raw_ids.mapped('quantity'), [0, 5])
self.assertEqual(mo.move_raw_ids.mapped('product_uom_qty'), [1, 10])
self.assertEqual(mo.move_raw_ids.mapped('state'), ['cancel', 'done'])
- self.assertEqual(mo.move_raw_ids.mapped('move_line_ids.qty_done'), [5])
+ self.assertEqual(mo.move_raw_ids.mapped('move_line_ids.quantity'), [5])
def test_update_quantity_1(self):
""" Build 5 final products with different consumed lots,
@@ -271,17 +271,18 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = lot_1
- ml.qty_done = 20
+ ml.quantity = 20
details_operation_form.save()
+ mo.move_raw_ids[1].picked = True
update_quantity_wizard = self.env['change.production.qty'].create({
'mo_id': mo.id,
'product_qty': 4,
})
update_quantity_wizard.change_prod_qty()
- self.assertEqual(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).quantity_done, 20, 'Update the produce quantity should not impact already produced quantity.')
+ self.assertEqual(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).quantity, 20, 'Update the produce quantity should not impact already produced quantity.')
self.assertEqual(mo.move_finished_ids.product_uom_qty, 4)
mo.button_mark_done()
@@ -303,8 +304,6 @@ class TestMrpOrder(TestMrpCommon):
mo_form.qty_producing = 2
mo = mo_form.save()
- mo._post_inventory()
-
update_quantity_wizard = self.env['change.production.qty'].create({
'mo_id': mo.id,
'product_qty': 5,
@@ -315,8 +314,8 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
mo.button_mark_done()
- self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).mapped('quantity_done')), 20)
- self.assertEqual(sum(mo.move_finished_ids.mapped('quantity_done')), 5)
+ self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).mapped('quantity')), 20)
+ self.assertEqual(sum(mo.move_finished_ids.mapped('quantity')), 5)
def test_update_quantity_3(self):
bom = self.env['mrp.bom'].create({
@@ -536,8 +535,8 @@ class TestMrpOrder(TestMrpCommon):
mo_form = Form(production)
mo_form.qty_producing = 8
production = mo_form.save()
- self.assertEqual(production.move_raw_ids[0].quantity_done, 16, 'Should use half-up rounding when producing')
- self.assertEqual(production.move_raw_ids[1].quantity_done, 34, 'Should use half-up rounding when producing')
+ self.assertEqual(production.move_raw_ids[0].quantity, 16, 'Should use half-up rounding when producing')
+ self.assertEqual(production.move_raw_ids[1].quantity, 34, 'Should use half-up rounding when producing')
def test_product_produce_1(self):
""" Checks the production wizard contains lines even for untracked products. """
@@ -553,7 +552,7 @@ class TestMrpOrder(TestMrpCommon):
# change the quantity done in one line
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
# change the quantity producing
@@ -562,9 +561,9 @@ class TestMrpOrder(TestMrpCommon):
# check than all quantities are update correctly
self.assertEqual(mo_form.move_raw_ids._records[0]['product_uom_qty'], 5, "Wrong quantity to consume")
- self.assertEqual(mo_form.move_raw_ids._records[0]['quantity_done'], 3, "Wrong quantity done")
+ self.assertEqual(mo_form.move_raw_ids._records[0]['quantity'], 3, "Wrong quantity done")
self.assertEqual(mo_form.move_raw_ids._records[1]['product_uom_qty'], 20, "Wrong quantity to consume")
- self.assertEqual(mo_form.move_raw_ids._records[1]['quantity_done'], 12, "Wrong quantity done")
+ self.assertEqual(mo_form.move_raw_ids._records[1]['quantity'], 12, "Wrong quantity done")
def test_product_produce_2(self):
""" Checks that, for a BOM where one of the components is tracked by serial number and the
@@ -599,10 +598,10 @@ class TestMrpOrder(TestMrpCommon):
# get the proposed lot
details_operation_form = Form(mo.move_raw_ids.filtered(lambda move: move.product_id == p1), view=self.env.ref('stock.view_stock_move_operations'))
- self.assertEqual(len(details_operation_form.move_line_ids), 2)
+ self.assertEqual(len(details_operation_form.move_line_ids), 1)
with details_operation_form.move_line_ids.edit(0) as ml:
consumed_lots = ml.lot_id
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
remaining_lot = (lot_p1_1 | lot_p1_2) - consumed_lots
@@ -668,28 +667,22 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
# p2
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.edit(0) as line:
- line.qty_done = line.reserved_uom_qty
with details_operation_form.move_line_ids.new() as line:
- line.qty_done = 1
+ line.quantity = 1
details_operation_form.save()
# p1
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
- for i in range(len(details_operation_form.move_line_ids)):
- # reservation in shelf1: 3 lot1, shelf2: 3 lot1, stock: 4 lot2
- with details_operation_form.move_line_ids.edit(i) as line:
- line.qty_done = line.reserved_uom_qty
with details_operation_form.move_line_ids.new() as line:
- line.qty_done = 2
+ line.quantity = 2
line.lot_id = first_lot_for_p1
with details_operation_form.move_line_ids.new() as line:
- line.qty_done = 1
+ line.quantity = 1
line.lot_id = second_lot_for_p1
details_operation_form.save()
move_1 = mo.move_raw_ids.filtered(lambda m: m.product_id == p1)
- # qty_done/reserved_uom_qty lot
+ # quantity/reserved_uom_qty lot
# 3/3 lot 1 shelf 1
# 1/1 lot 1 shelf 2
# 2/2 lot 1 shelf 2
@@ -698,9 +691,9 @@ class TestMrpOrder(TestMrpCommon):
ml_to_shelf_1 = move_1.move_line_ids.filtered(lambda ml: ml.lot_id == first_lot_for_p1 and ml.location_id == self.stock_shelf_1)
ml_to_shelf_2 = move_1.move_line_ids.filtered(lambda ml: ml.lot_id == first_lot_for_p1 and ml.location_id == self.stock_shelf_2)
- self.assertEqual(sum(ml_to_shelf_1.mapped('qty_done')), 3.0, '3 units should be took from shelf1 as reserved.')
- self.assertEqual(sum(ml_to_shelf_2.mapped('qty_done')), 3.0, '3 units should be took from shelf2 as reserved.')
- self.assertEqual(move_1.quantity_done, 13, 'You should have used the tem units.')
+ self.assertEqual(sum(ml_to_shelf_1.mapped('quantity')), 3.0, '3 units should be took from shelf1 as reserved.')
+ self.assertEqual(sum(ml_to_shelf_2.mapped('quantity')), 3.0, '3 units should be took from shelf2 as reserved.')
+ self.assertEqual(move_1.quantity, 13, 'You should have used the tem units.')
mo.button_mark_done()
self.assertEqual(mo.state, 'done', "Production order should be in done state.")
@@ -723,9 +716,6 @@ class TestMrpOrder(TestMrpCommon):
self.assertEqual(len(ml_p1), 2)
self.assertEqual(len(ml_p2), 1)
- # Add some quantity already done to force an extra move line to be created
- ml_p1[0].qty_done = 1.0
-
# Produce baby!
mo_form = Form(mo)
mo_form.qty_producing = 1
@@ -734,9 +724,8 @@ class TestMrpOrder(TestMrpCommon):
m_p1 = mo.move_raw_ids.filtered(lambda x: x.product_id == p1)
ml_p1 = m_p1.mapped('move_line_ids')
self.assertEqual(len(ml_p1), 2)
- self.assertEqual(sorted(ml_p1.mapped('qty_done')), [2.0, 3.0], 'Quantity done should be 1.0, 2.0 or 3.0')
- self.assertEqual(m_p1.quantity_done, 5.0, 'Total qty done should be 6.0')
- self.assertEqual(sum(ml_p1.mapped('reserved_uom_qty')), 5.0, 'Total qty reserved should be 5.0')
+ self.assertEqual(sorted(ml_p1.mapped('quantity')), [2.0, 3.0], 'Quantity should be 2.0 and 3.0')
+ self.assertEqual(m_p1.quantity, 5.0, 'Total qty done should be 5.0')
mo.button_mark_done()
self.assertEqual(mo.state, 'done', "Production order should be in done state.")
@@ -763,21 +752,21 @@ class TestMrpOrder(TestMrpCommon):
mo._post_inventory()
self.assertEqual(len(mo.move_raw_ids), 4)
- mo.move_raw_ids.filtered(lambda m: m.state != 'done')[0].quantity_done = 3
+ mo.move_raw_ids.filtered(lambda m: m.state != 'done')[0].quantity = 3
update_quantity_wizard = self.env['change.production.qty'].create({
'mo_id': mo.id,
'product_qty': 3,
})
- mo.move_raw_ids.filtered(lambda m: m.state != 'done')[0].quantity_done = 0
+ mo.move_raw_ids.filtered(lambda m: m.state != 'done')[0].quantity = 0
update_quantity_wizard.change_prod_qty()
self.assertEqual(len(mo.move_raw_ids), 4)
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
self.assertTrue(all(s in ['done', 'cancel'] for s in mo.move_raw_ids.mapped('state')))
- self.assertEqual(sum(mo.move_raw_ids.mapped('move_line_ids.reserved_uom_qty')), 0)
def test_consumption_strict_1(self):
""" Checks the constraints of a strict BOM without tracking when playing around
@@ -800,7 +789,7 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[-1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
# Won't accept to be done, instead return a wizard
mo.button_mark_done()
@@ -838,7 +827,7 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[-1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
# Won't accept to be done, instead return a wizard
@@ -878,7 +867,7 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[-1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
# Won't accept to be done, instead return a wizard
@@ -910,7 +899,7 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[-1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
# Won't accept to be done, instead return a wizard
@@ -937,7 +926,7 @@ class TestMrpOrder(TestMrpCommon):
with self.assertRaises(AssertionError):
with mo_form.move_raw_ids.new() as move:
move.product_id = serial
- move.quantity_done = 2
+ move.quantity = 2
mo_form.save()
def test_product_produce_10(self):
@@ -1011,18 +1000,18 @@ class TestMrpOrder(TestMrpCommon):
move_byproduct_1 = mo.move_finished_ids.filtered(lambda l: l.product_id == self.byproduct1)
self.assertEqual(len(move_byproduct_1), 1)
self.assertEqual(move_byproduct_1.product_uom_qty, 2.0)
- self.assertEqual(move_byproduct_1.quantity_done, 0)
+ self.assertEqual(move_byproduct_1.quantity, 2)
self.assertEqual(len(move_byproduct_1.move_line_ids), 2)
move_byproduct_2 = mo.move_finished_ids.filtered(lambda l: l.product_id == self.byproduct2)
self.assertEqual(len(move_byproduct_2), 1)
self.assertEqual(move_byproduct_2.product_uom_qty, 4.0)
- self.assertEqual(move_byproduct_2.quantity_done, 0)
+ self.assertEqual(move_byproduct_2.quantity, 4)
self.assertEqual(len(move_byproduct_2.move_line_ids), 1)
move_byproduct_3 = mo.move_finished_ids.filtered(lambda l: l.product_id == self.byproduct3)
self.assertEqual(move_byproduct_3.product_uom_qty, 4.0)
- self.assertEqual(move_byproduct_3.quantity_done, 0)
+ self.assertEqual(move_byproduct_3.quantity, 4)
self.assertEqual(move_byproduct_3.product_uom, dozen)
self.assertEqual(len(move_byproduct_3.move_line_ids), 1)
@@ -1032,27 +1021,28 @@ class TestMrpOrder(TestMrpCommon):
move_byproduct_1 = mo.move_finished_ids.filtered(lambda l: l.product_id == self.byproduct1)
self.assertEqual(len(move_byproduct_1), 1)
self.assertEqual(move_byproduct_1.product_uom_qty, 2.0)
- self.assertEqual(move_byproduct_1.quantity_done, 0)
+ self.assertEqual(move_byproduct_1.quantity, 1)
+ self.assertFalse(move_byproduct_1.picked)
move_byproduct_2 = mo.move_finished_ids.filtered(lambda l: l.product_id == self.byproduct2)
self.assertEqual(len(move_byproduct_2), 1)
self.assertEqual(move_byproduct_2.product_uom_qty, 4.0)
- self.assertEqual(move_byproduct_2.quantity_done, 0)
+ self.assertEqual(move_byproduct_2.quantity, 2)
+ self.assertFalse(move_byproduct_2.picked)
move_byproduct_3 = mo.move_finished_ids.filtered(lambda l: l.product_id == self.byproduct3)
self.assertEqual(move_byproduct_3.product_uom_qty, 4.0)
- self.assertEqual(move_byproduct_3.quantity_done, 2.0)
+ self.assertEqual(move_byproduct_3.quantity, 2.0)
+ self.assertTrue(move_byproduct_3.picked)
self.assertEqual(move_byproduct_3.product_uom, dozen)
details_operation_form = Form(move_byproduct_1, view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.serial_1
- ml.qty_done = 1
details_operation_form.save()
details_operation_form = Form(move_byproduct_2, view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.lot_1
- ml.qty_done = 2
details_operation_form.save()
action = mo.button_mark_done()
backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
@@ -1066,42 +1056,44 @@ class TestMrpOrder(TestMrpCommon):
move_byproduct_1 = mo2.move_finished_ids.filtered(lambda l: l.product_id == self.byproduct1)
self.assertEqual(len(move_byproduct_1), 1)
self.assertEqual(move_byproduct_1.product_uom_qty, 1.0)
- self.assertEqual(move_byproduct_1.quantity_done, 0)
+ self.assertEqual(move_byproduct_1.quantity, 1)
+ self.assertFalse(move_byproduct_1.picked)
move_byproduct_2 = mo2.move_finished_ids.filtered(lambda l: l.product_id == self.byproduct2)
self.assertEqual(len(move_byproduct_2), 1)
self.assertEqual(move_byproduct_2.product_uom_qty, 2.0)
- self.assertEqual(move_byproduct_2.quantity_done, 0)
+ self.assertEqual(move_byproduct_2.quantity, 2)
+ self.assertFalse(move_byproduct_2.picked)
move_byproduct_3 = mo2.move_finished_ids.filtered(lambda l: l.product_id == self.byproduct3)
self.assertEqual(move_byproduct_3.product_uom_qty, 2.0)
- self.assertEqual(move_byproduct_3.quantity_done, 2.0)
+ self.assertEqual(move_byproduct_3.quantity, 2.0)
+ self.assertTrue(move_byproduct_3.picked)
self.assertEqual(move_byproduct_3.product_uom, dozen)
details_operation_form = Form(move_byproduct_1, view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.serial_2
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
details_operation_form = Form(move_byproduct_2, view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.lot_2
- ml.qty_done = 2
details_operation_form.save()
details_operation_form = Form(move_byproduct_3, view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 3
+ ml.quantity = 3
details_operation_form.save()
mo2.button_mark_done()
move_lines_byproduct_1 = (mo | mo2).move_finished_ids.filtered(lambda l: l.product_id == self.byproduct1).mapped('move_line_ids')
move_lines_byproduct_2 = (mo | mo2).move_finished_ids.filtered(lambda l: l.product_id == self.byproduct2).mapped('move_line_ids')
move_lines_byproduct_3 = (mo | mo2).move_finished_ids.filtered(lambda l: l.product_id == self.byproduct3).mapped('move_line_ids')
- self.assertEqual(move_lines_byproduct_1.filtered(lambda ml: ml.lot_id == self.serial_1).qty_done, 1.0)
- self.assertEqual(move_lines_byproduct_1.filtered(lambda ml: ml.lot_id == self.serial_2).qty_done, 1.0)
- self.assertEqual(move_lines_byproduct_2.filtered(lambda ml: ml.lot_id == self.lot_1).qty_done, 2.0)
- self.assertEqual(move_lines_byproduct_2.filtered(lambda ml: ml.lot_id == self.lot_2).qty_done, 2.0)
- self.assertEqual(sum(move_lines_byproduct_3.mapped('qty_done')), 5.0)
+ self.assertEqual(move_lines_byproduct_1.filtered(lambda ml: ml.lot_id == self.serial_1).quantity, 1.0)
+ self.assertEqual(move_lines_byproduct_1.filtered(lambda ml: ml.lot_id == self.serial_2).quantity, 1.0)
+ self.assertEqual(move_lines_byproduct_2.filtered(lambda ml: ml.lot_id == self.lot_1).quantity, 2.0)
+ self.assertEqual(move_lines_byproduct_2.filtered(lambda ml: ml.lot_id == self.lot_2).quantity, 2.0)
+ self.assertEqual(sum(move_lines_byproduct_3.mapped('quantity')), 5.0)
self.assertEqual(move_lines_byproduct_3.mapped('product_uom_id'), dozen)
def test_product_produce_11(self):
@@ -1122,33 +1114,30 @@ class TestMrpOrder(TestMrpCommon):
mo_form = Form(mo)
mo_form.qty_producing = 3
- self.assertEqual(sum([x['quantity_done'] for x in mo_form.move_raw_ids._records]), 15, 'Update the produce quantity should change the components quantity.')
+ self.assertEqual(sum([x['quantity'] for x in mo_form.move_raw_ids._records]), 15, 'Update the produce quantity should change the components quantity.')
mo = mo_form.save()
- self.assertEqual(sum(mo.move_raw_ids.mapped('reserved_availability')), 5, 'Update the produce quantity should not change the components reserved quantity.')
mo_form = Form(mo)
mo_form.qty_producing = 4
- self.assertEqual(sum([x['quantity_done'] for x in mo_form.move_raw_ids._records]), 20, 'Update the produce quantity should change the components quantity.')
+ self.assertEqual(sum([x['quantity'] for x in mo_form.move_raw_ids._records]), 20, 'Update the produce quantity should change the components quantity.')
mo = mo_form.save()
- self.assertEqual(sum(mo.move_raw_ids.mapped('reserved_availability')), 5, 'Update the produce quantity should not change the components reserved quantity.')
mo_form = Form(mo)
mo_form.qty_producing = 1
- self.assertEqual(sum([x['quantity_done'] for x in mo_form.move_raw_ids._records]), 5, 'Update the produce quantity should change the components quantity.')
+ self.assertEqual(sum([x['quantity'] for x in mo_form.move_raw_ids._records]), 5, 'Update the produce quantity should change the components quantity.')
mo = mo_form.save()
- self.assertEqual(sum(mo.move_raw_ids.mapped('reserved_availability')), 5, 'Update the produce quantity should not change the components reserved quantity.')
# try adding another product that doesn't belong to the BoM
with mo_form.move_raw_ids.new() as move:
move.product_id = self.product_4
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[-1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 10
+ ml.quantity = 10
details_operation_form.save()
# Check that this new product is not updated by qty_producing
mo_form = Form(mo)
mo_form.qty_producing = 2
for move in mo_form.move_raw_ids._records:
if move['product_id'] == self.product_4.id:
- self.assertEqual(move['quantity_done'], 10)
+ self.assertEqual(move['quantity'], 10)
break
mo = mo_form.save()
mo.button_mark_done()
@@ -1192,9 +1181,10 @@ class TestMrpOrder(TestMrpCommon):
mo_form.qty_producing = 1
mo1 = mo_form.save()
details_operation_form = Form(mo1.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = sn
details_operation_form.save()
+ mo1.move_raw_ids.picked = True
mo1.button_mark_done()
mo_form = Form(self.env['mrp.production'])
@@ -1208,9 +1198,10 @@ class TestMrpOrder(TestMrpCommon):
mo_form.qty_producing = 1
mo2 = mo_form.save()
details_operation_form = Form(mo2.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = sn
details_operation_form.save()
+ mo2.move_raw_ids.picked = True
with self.assertRaises(UserError):
mo2.button_mark_done()
@@ -1250,7 +1241,7 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
move_byproduct = mo.move_finished_ids.filtered(lambda m: m.product_id != mo.product_id)
details_operation_form = Form(move_byproduct, view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = sn
details_operation_form.save()
mo.button_mark_done()
@@ -1286,9 +1277,10 @@ class TestMrpOrder(TestMrpCommon):
mo_form.qty_producing = 1
mo1 = mo_form.save()
details_operation_form = Form(mo1.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = sn
details_operation_form.save()
+ mo1.move_raw_ids.picked = True
mo1.button_mark_done()
unbuild_form = Form(self.env['mrp.unbuild'])
@@ -1310,9 +1302,10 @@ class TestMrpOrder(TestMrpCommon):
mo_form.qty_producing = 1
mo2 = mo_form.save()
details_operation_form = Form(mo2.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = sn
details_operation_form.save()
+ mo2.move_raw_ids.picked = True
mo2.button_mark_done()
def test_product_produce_duplicate_5(self):
@@ -1373,9 +1366,10 @@ class TestMrpOrder(TestMrpCommon):
view=self.env.ref("stock.view_stock_move_operations"),
)
with finished_good_detailed_operations_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
+ ml.quantity = 1
ml.lot_id = subassembly_sn
finished_good_detailed_operations_form.save()
+ finished_good_mo.move_raw_ids.picked = True
finished_good_mo.button_mark_done()
finished_good_ub_form = Form(self.env["mrp.unbuild"])
@@ -1425,8 +1419,6 @@ class TestMrpOrder(TestMrpCommon):
'product_uom': self.ref('uom.product_uom_unit'),
'production_id': mo.id,
'location_dest_id': self.ref('stock.stock_location_output'),
- 'product_uom_qty': 0,
- 'quantity_done': 0,
})
self.assertEqual(move.name, mo.name)
@@ -1464,8 +1456,6 @@ class TestMrpOrder(TestMrpCommon):
'production_id': mo.id,
'location_id': self.ref('stock.stock_location_stock'),
'location_dest_id': self.ref('stock.stock_location_output'),
- 'product_uom_qty': 0,
- 'quantity_done': 0,
})
mo.move_raw_ids |= move
mo.action_confirm()
@@ -1525,13 +1515,13 @@ class TestMrpOrder(TestMrpCommon):
mo_form.lot_producing_id = final_product_lot
mo = mo_form.save()
- move_line_raw = mo.move_raw_ids.mapped('move_line_ids').filtered(lambda m: m.qty_done)
- self.assertEqual(move_line_raw.qty_done, 1)
+ move_line_raw = mo.move_raw_ids.mapped('move_line_ids').filtered(lambda m: m.quantity)
+ self.assertEqual(move_line_raw.quantity, 1)
self.assertEqual(move_line_raw.product_uom_id, unit, 'Should be 1 unit since the tracking is serial.')
mo._post_inventory()
- move_line_finished = mo.move_finished_ids.mapped('move_line_ids').filtered(lambda m: m.qty_done)
- self.assertEqual(move_line_finished.qty_done, 1)
+ move_line_finished = mo.move_finished_ids.move_line_ids.filtered(lambda m: m.state == 'done' and m.quantity)
+ self.assertEqual(move_line_finished.quantity, 1)
self.assertEqual(move_line_finished.product_uom_id, unit, 'Should be 1 unit since the tracking is serial.')
def test_product_type_service_1(self):
@@ -1577,27 +1567,9 @@ class TestMrpOrder(TestMrpCommon):
mo.action_assign()
res_dict = mo.button_mark_done()
self.assertEqual(mo.move_raw_ids.mapped('state'), ['done', 'done'])
- self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [1, 1])
+ self.assertEqual(mo.move_raw_ids.mapped('quantity'), [1, 1])
self.assertEqual(mo.move_finished_ids.state, 'done')
- self.assertEqual(mo.move_finished_ids.quantity_done, 1)
-
- def test_immediate_validate_2(self):
- """ In a production non-tracked components, clicking on mark as done after filling quantity for a move be
- processed as immediate production. The manual filling quantity will be kept."""
- mo, bom, p_final, p1, p2 = self.generate_mo(qty_final=1, qty_base_1=1, qty_base_2=1)
- self.env['stock.quant']._update_available_quantity(p1, self.stock_location_components, 5.0)
- self.env['stock.quant']._update_available_quantity(p2, self.stock_location_components, 5.0)
- mo.action_assign()
- details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 2
- details_operation_form.save()
- mo.move_raw_ids.filtered('quantity_done').manual_consumption = True # this should be set automatically in front end
- mo.button_mark_done()
- self.assertEqual(mo.move_raw_ids.mapped('state'), ['done', 'done'])
- self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [2, 1])
- self.assertEqual(mo.move_finished_ids.state, 'done')
- self.assertEqual(mo.move_finished_ids.quantity_done, 1)
+ self.assertEqual(mo.move_finished_ids.quantity, 1)
def test_immediate_validate_3(self):
""" In a production with a serial number tracked product. Check that the immediate production only creates
@@ -1611,7 +1583,7 @@ class TestMrpOrder(TestMrpCommon):
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
action = wizard.action_backorder()
self.assertEqual(mo.qty_producing, 1)
- self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [1, 1])
+ self.assertEqual(mo.move_raw_ids.mapped('quantity'), [1, 1])
self.assertEqual(len(mo.procurement_group_id.mrp_production_ids), 2)
mo_backorder = mo.procurement_group_id.mrp_production_ids[-1]
self.assertEqual(mo_backorder.product_qty, 1)
@@ -1628,7 +1600,7 @@ class TestMrpOrder(TestMrpCommon):
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
action = wizard.action_backorder()
self.assertEqual(mo.qty_producing, 1)
- self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [1, 1])
+ self.assertEqual(mo.move_raw_ids.mapped('quantity'), [1, 1])
self.assertEqual(len(mo.procurement_group_id.mrp_production_ids), 2)
mo_backorder = mo.procurement_group_id.mrp_production_ids[-1]
self.assertEqual(mo_backorder.product_qty, 1)
@@ -1657,9 +1629,9 @@ class TestMrpOrder(TestMrpCommon):
mos = mo1 | mo2 | mo3
mos.button_mark_done()
self.assertEqual(mos.move_raw_ids.mapped('state'), ['done'] * 6)
- self.assertEqual(mos.move_raw_ids.mapped('quantity_done'), [1] * 6)
+ self.assertEqual(mos.move_raw_ids.mapped('quantity'), [1] * 6)
self.assertEqual(mos.move_finished_ids.mapped('state'), ['done'] * 3)
- self.assertEqual(mos.move_finished_ids.mapped('quantity_done'), [1] * 3)
+ self.assertEqual(mos.move_finished_ids.mapped('quantity'), [1] * 3)
def test_components_availability(self):
self.bom_2.unlink() # remove the kit bom of product_5
@@ -1698,7 +1670,7 @@ class TestMrpOrder(TestMrpCommon):
self.assertEqual(mo.components_availability, f'Exp {format_date(self.env, tommorrow)}')
self.assertEqual(mo.components_availability_state, 'expected')
- (move1 | move2 | move3)._set_quantities_to_reservation()
+ (move1 | move2 | move3).picked = True
(move1 | move2 | move3)._action_done()
mo.invalidate_recordset(['components_availability', 'components_availability_state'])
@@ -1721,9 +1693,9 @@ class TestMrpOrder(TestMrpCommon):
mo.action_assign()
mo.button_mark_done()
self.assertEqual(mo.move_raw_ids.mapped('state'), ['done'] * 2)
- self.assertEqual(mo.move_raw_ids.mapped('quantity_done'), [1] * 2)
+ self.assertEqual(mo.move_raw_ids.mapped('quantity'), [1] * 2)
self.assertEqual(mo.move_finished_ids.state, 'done')
- self.assertEqual(mo.move_finished_ids.quantity_done, 1)
+ self.assertEqual(mo.move_finished_ids.quantity, 1)
self.assertTrue(mo.move_finished_ids.move_line_ids.lot_id != False)
def test_immediate_validate_uom(self):
@@ -1756,9 +1728,9 @@ class TestMrpOrder(TestMrpCommon):
mo.action_assign()
mo.button_mark_done()
self.assertEqual(mo.move_raw_ids.state, 'done')
- self.assertEqual(mo.move_raw_ids.quantity_done, 12)
+ self.assertEqual(mo.move_raw_ids.quantity, 12)
self.assertEqual(mo.move_finished_ids.state, 'done')
- self.assertEqual(mo.move_finished_ids.quantity_done, 1)
+ self.assertEqual(mo.move_finished_ids.quantity, 1)
self.assertEqual(component.qty_available, 13)
def test_immediate_validate_uom_2(self):
@@ -1815,7 +1787,7 @@ class TestMrpOrder(TestMrpCommon):
mo.button_mark_done()
self.assertEqual(mo.move_raw_ids.product_uom_qty, 0.2)
- self.assertEqual(mo.move_raw_ids.quantity_done, 0.2)
+ self.assertEqual(mo.move_raw_ids.quantity, 0.2)
def test_copy(self):
""" Check that copying a done production, create all the stock moves"""
@@ -2072,9 +2044,11 @@ class TestMrpOrder(TestMrpCommon):
"""
mo, _, _, _, _ = self.generate_mo(qty_final=30, qty_base_1=2, qty_base_2=3)
mo.action_confirm()
- mo.qty_producing = 10
- mo.move_raw_ids[0].quantity_done = 90
- mo.move_raw_ids[1].quantity_done = 70
+ mo_form = Form(mo)
+ mo_form.qty_producing = 10
+ mo = mo_form.save()
+ mo.move_raw_ids[0].quantity = 90
+ mo.move_raw_ids[1].quantity = 70
action = mo.button_mark_done()
backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
backorder.save().action_backorder()
@@ -2089,9 +2063,9 @@ class TestMrpOrder(TestMrpCommon):
move_prod_2 = self.env['stock.move'].search([
('product_id', '=', mo.bom_id.bom_line_ids[1].product_id.id),
('raw_material_production_id', '=', mo.id)])
- self.assertEqual(sum(move_prod_1.mapped('quantity_done')), 90.0)
+ self.assertEqual(sum(move_prod_1.mapped('quantity')), 90.0)
self.assertEqual(sum(move_prod_1.mapped('product_uom_qty')), 30.0)
- self.assertEqual(sum(move_prod_2.mapped('quantity_done')), 70.0)
+ self.assertEqual(sum(move_prod_2.mapped('quantity')), 70.0)
self.assertEqual(sum(move_prod_2.mapped('product_uom_qty')), 20.0)
# Check quantities of the backorder MO
@@ -2111,9 +2085,11 @@ class TestMrpOrder(TestMrpCommon):
"""
mo, _, _, p1, p2 = self.generate_mo(qty_final=20, qty_base_1=1, qty_base_2=1)
mo.action_confirm()
- mo.qty_producing = 10
- mo.move_raw_ids.filtered(lambda m: m.product_id == p1).quantity_done = 5
- mo.move_raw_ids.filtered(lambda m: m.product_id == p2).quantity_done = 10
+ mo_form = Form(mo)
+ mo_form.qty_producing = 10
+ mo = mo_form.save()
+ mo.move_raw_ids.filtered(lambda m: m.product_id == p1).quantity = 5
+ mo.move_raw_ids.filtered(lambda m: m.product_id == p2).quantity = 10
action = mo.button_mark_done()
backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
backorder.save().action_backorder()
@@ -2123,10 +2099,10 @@ class TestMrpOrder(TestMrpCommon):
self.assertEqual(mo.product_uom_qty, 10.0)
self.assertEqual(mo.qty_produced, 10.0)
move_prod_1_done = mo.move_raw_ids.filtered(lambda m: m.product_id == p1)
- self.assertEqual(sum(move_prod_1_done.mapped('quantity_done')), 5)
+ self.assertEqual(sum(move_prod_1_done.mapped('quantity')), 5)
self.assertEqual(sum(move_prod_1_done.mapped('product_uom_qty')), 10)
move_prod_2 = mo.move_raw_ids.filtered(lambda m: m.product_id == p2)
- self.assertEqual(sum(move_prod_2.mapped('quantity_done')), 10)
+ self.assertEqual(sum(move_prod_2.mapped('quantity')), 10)
self.assertEqual(sum(move_prod_2.mapped('product_uom_qty')), 10)
# Check quantities of the backorder MO
@@ -3193,7 +3169,7 @@ class TestMrpOrder(TestMrpCommon):
mo.action_confirm()
self.assertEqual(mo.move_raw_ids.product_uom_qty, 1)
- self.assertEqual(mo.move_raw_ids.move_line_ids.reserved_uom_qty, mo.move_raw_ids.product_uom_qty)
+ self.assertEqual(mo.move_raw_ids.move_line_ids.quantity, mo.move_raw_ids.product_uom_qty)
self.assertEqual(mo.move_raw_ids.availability, 250)
update_quantity_wizard = self.env['change.production.qty'].create({
'mo_id': mo.id,
@@ -3202,7 +3178,7 @@ class TestMrpOrder(TestMrpCommon):
update_quantity_wizard.change_prod_qty()
self.assertEqual(mo.move_raw_ids.product_uom_qty, 2)
- self.assertEqual(mo.move_raw_ids.move_line_ids.reserved_uom_qty, mo.move_raw_ids.product_uom_qty)
+ self.assertEqual(mo.move_raw_ids.move_line_ids.quantity, mo.move_raw_ids.product_uom_qty)
self.assertEqual(mo.move_raw_ids.availability, 0)
def test_update_qty_to_consume_of_component(self):
@@ -3228,7 +3204,7 @@ class TestMrpOrder(TestMrpCommon):
with mo_form.move_raw_ids.edit(0) as raw:
raw.product_uom_qty = 1.25
- self.assertEqual(mo.move_raw_ids.quantity_done, 1.25)
+ self.assertEqual(mo.move_raw_ids.quantity, 1.25)
def test_clear_finished_move(self):
""" Test that the finished moves created by the compute are correctly
@@ -3395,7 +3371,7 @@ class TestMrpOrder(TestMrpCommon):
- a component's UoM is changed after MO is created => action_set_qty = match BoM qty, but leave UoM unchanged (i.e. correctly convert)
scenario 3:
- a component has 2 moves in a MO => action_set_qty = set the 1st move to the correct qty, set 2nd move to 0
- (i.e. no way to know how to distribute qty_done across these moves since warning aggregates qty by product)
+ (i.e. no way to know how to distribute quantity across these moves since warning aggregates qty by product)
"""
mo, bom, p_final, p1, p2 = self.generate_mo(consumption='warning', qty_final=10, qty_base_1=12, qty_base_2=20)
@@ -3405,13 +3381,13 @@ class TestMrpOrder(TestMrpCommon):
mo = mo_form.save()
# mo.move_raw_ids[0] = p2 => 20 qty_base, mo.move_raw_ids[1] = p1 => 12 qty_base
self.assertEqual(mo.move_raw_ids[0].product_uom_qty, 200, "current MO To Consume qty should match expected qty to produce")
- self.assertEqual(mo.move_raw_ids[0].quantity_done, 80, "current MO Consumed qty should match expected qty to produce")
+ self.assertEqual(mo.move_raw_ids[0].quantity, 80, "current MO Consumed qty should match expected qty to produce")
self.assertEqual(mo.move_raw_ids[1].product_uom_qty, 120, "current MO To Consume qty should match expected qty produced")
- self.assertEqual(mo.move_raw_ids[1].quantity_done, 48, "current MO Consumed qty should match expected qty produced")
+ self.assertEqual(mo.move_raw_ids[1].quantity, 48, "current MO Consumed qty should match expected qty produced")
# bom changes won't auto-update MO, it will only show diff in consumption warning
bom.bom_line_ids[0].product_qty = 10
self.assertEqual(mo.move_raw_ids[0].product_uom_qty, 200)
- self.assertEqual(mo.move_raw_ids[0].quantity_done, 80)
+ self.assertEqual(mo.move_raw_ids[0].quantity, 80)
action = mo.button_mark_done()
warning = Form(self.env['mrp.consumption.warning'].with_context(**action['context']))
consumption = warning.save()
@@ -3421,9 +3397,9 @@ class TestMrpOrder(TestMrpCommon):
backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
backorder.save().action_backorder()
self.assertEqual(mo.move_raw_ids[0].product_uom_qty, 80, "current bom expected qty should remain unchanged")
- self.assertEqual(mo.move_raw_ids[0].quantity_done, 40, "current bom expected qty was not applied as qty to be done")
+ self.assertEqual(mo.move_raw_ids[0].quantity, 40, "current bom expected qty was not applied as qty to be done")
self.assertEqual(mo.move_raw_ids[1].product_uom_qty, 48, "line without consumption issue was incorrectly changed")
- self.assertEqual(mo.move_raw_ids[1].quantity_done, 48, "line without consumption issue was incorrectly changed")
+ self.assertEqual(mo.move_raw_ids[1].quantity, 48, "line without consumption issue was incorrectly changed")
self.assertEqual(mo.state, 'done')
# double check that backorder qtys are also correct
mo_backorder = mo.procurement_group_id.mrp_production_ids[-1]
@@ -3448,7 +3424,7 @@ class TestMrpOrder(TestMrpCommon):
mo2 = mo2_form.save()
self.assertEqual(len(mo2.move_raw_ids), 1, "current MO should still have 1 component from its BoM deleted")
self.assertEqual(mo2.move_raw_ids[0].product_uom_qty, 60, "current MO To Consume qty should match manually set expected qty produced")
- self.assertEqual(mo2.move_raw_ids[0].quantity_done, 48, "current MO Consumed qty should match expected qty to produce based on manually set value")
+ self.assertEqual(mo2.move_raw_ids[0].quantity, 48, "current MO Consumed qty should match expected qty to produce based on manually set value")
action = mo2.button_mark_done()
warning = Form(self.env['mrp.consumption.warning'].with_context(**action['context']))
@@ -3468,10 +3444,10 @@ class TestMrpOrder(TestMrpCommon):
for move in mo2.move_raw_ids:
if move.product_id == p2:
self.assertEqual(move.product_uom_qty, 40, "missing line values were not correctly added")
- self.assertEqual(move.quantity_done, 40, "missing line values were not correctly added")
+ self.assertEqual(move.quantity, 40, "missing line values were not correctly added")
else:
self.assertEqual(move.product_uom_qty, 48, "expected qty should be unchanged")
- self.assertEqual(move.quantity_done, 4, "expected qty was not applied as qty to be done (UoM was possibly not correctly converted)")
+ self.assertEqual(move.quantity, 4, "expected qty was not applied as qty to be done (UoM was possibly not correctly converted)")
self.assertEqual(mo2.state, 'done')
# double check that backorder qtys are also correct
mo2_backorder = mo2.procurement_group_id.mrp_production_ids[-1]
@@ -3499,9 +3475,9 @@ class TestMrpOrder(TestMrpCommon):
mo3_form.qty_producing = 1
mo3 = mo3_form.save()
self.assertEqual(mo3.move_raw_ids[0].product_uom_qty, 12, "BoM created comp move does not match expected To Consume qty")
- self.assertEqual(mo3.move_raw_ids[0].quantity_done, 12, "BoM created comp move does not match expected Consumed qty")
+ self.assertEqual(mo3.move_raw_ids[0].quantity, 12, "BoM created comp move does not match expected Consumed qty")
self.assertEqual(mo3.move_raw_ids[1].product_uom_qty, 5, "Manually added comp move does not match original To Consume qty")
- self.assertEqual(mo3.move_raw_ids[1].quantity_done, 5, "Manually added comp move was not Consumed")
+ self.assertEqual(mo3.move_raw_ids[1].quantity, 5, "Manually added comp move was not Consumed")
action = mo3.button_mark_done()
warning = Form(self.env['mrp.consumption.warning'].with_context(**action['context']))
consumption = warning.save()
@@ -3510,9 +3486,9 @@ class TestMrpOrder(TestMrpCommon):
self.assertEqual(consumption.mrp_consumption_warning_line_ids[0].product_consumed_qty_uom, 17, "total Consumed qty not correctly passed to wizard")
action = consumption.action_set_qty()
self.assertEqual(mo3.move_raw_ids[0].product_uom_qty, 12, "BoM created comp move does not match expected To Consume qty")
- self.assertEqual(mo3.move_raw_ids[0].quantity_done, 12, "BoM created comp move does not match expected Consumed qty")
+ self.assertEqual(mo3.move_raw_ids[0].quantity, 12, "BoM created comp move does not match expected Consumed qty")
self.assertEqual(mo3.move_raw_ids[1].product_uom_qty, 5, "Manually added comp move To Consume qty should be unchanged")
- self.assertEqual(mo3.move_raw_ids[1].quantity_done, 0, "Extra line Consumed qty not correctly zero-ed")
+ self.assertEqual(mo3.move_raw_ids[1].quantity, 0, "Extra line Consumed qty not correctly zero-ed")
self.assertEqual(mo3.state, 'done')
def test_exceeded_consumed_qty_and_duplicated_lines(self):
@@ -3549,15 +3525,15 @@ class TestMrpOrder(TestMrpCommon):
mo_form.qty_producing = 1.0
mo = mo_form.save()
- mo.move_raw_ids[0].move_line_ids.qty_done = 1.5
+ mo.move_raw_ids[0].move_line_ids.quantity = 1.5
mo.button_mark_done()
self.assertEqual(mo.state, 'done')
p02_raws = mo.move_raw_ids.filtered(lambda m: m.product_id == product02)
p03_raws = mo.move_raw_ids.filtered(lambda m: m.product_id == product03)
- self.assertEqual(sum(p02_raws.mapped('quantity_done')), 1.5)
- self.assertEqual(sum(p03_raws.mapped('quantity_done')), 2)
+ self.assertEqual(sum(p02_raws.mapped('quantity')), 1.5)
+ self.assertEqual(sum(p03_raws.mapped('quantity')), 2)
def test_validation_mo_with_tracked_component(self):
"""
@@ -3584,18 +3560,15 @@ class TestMrpOrder(TestMrpCommon):
mo.action_confirm()
self.assertEqual(mo.state, 'confirmed')
# set the qty to consume of the tracked product to 0
- mo.move_raw_ids[0].write({
- 'product_uom_qty': 0,
- 'quantity_done': 0,
- })
- mo.action_assign()
+ mo.move_raw_ids[0].product_uom_qty = 0
+ mo.move_raw_ids[0].quantity = 0
# Set MO Done and create backorder
action = mo.button_mark_done()
consumption_warning = Form(self.env['mrp.consumption.warning'].with_context(**action['context'])).save()
- self.assertEqual(len(consumption_warning.mrp_consumption_warning_line_ids), 1)
+ self.assertEqual(len(consumption_warning.mrp_consumption_warning_line_ids), 2)
self.assertEqual(consumption_warning.mrp_consumption_warning_line_ids[0].product_consumed_qty_uom, 0)
- self.assertEqual(consumption_warning.mrp_consumption_warning_line_ids[0].product_expected_qty_uom, 1)
+ self.assertEqual(consumption_warning.mrp_consumption_warning_line_ids[0].product_expected_qty_uom, 0)
# Force the warning
consumption_warning.action_confirm()
self.assertEqual(mo.state, 'done')
diff --git a/addons/mrp/tests/test_procurement.py b/addons/mrp/tests/test_procurement.py
index 9a511ff4bed..b2aecbad51f 100644
--- a/addons/mrp/tests/test_procurement.py
+++ b/addons/mrp/tests/test_procurement.py
@@ -174,22 +174,21 @@ class TestProcurement(TestMrpCommon):
self.assertTrue(picking_qc_to_stock)
picking_input_to_qc.action_assign()
self.assertEqual(picking_input_to_qc.state, 'assigned')
- picking_input_to_qc.move_line_ids.write({'qty_done': 5.0})
+ picking_input_to_qc.move_ids.write({'quantity': 5.0, 'picked': True})
picking_input_to_qc._action_done()
picking_qc_to_stock.action_assign()
self.assertEqual(picking_qc_to_stock.state, 'assigned')
- picking_qc_to_stock.move_line_ids.write({'qty_done': 3.0})
+ picking_qc_to_stock.move_ids.write({'quantity': 3.0, 'picked': True})
picking_qc_to_stock.with_context(skip_backorder=True, picking_ids_not_to_backorder=picking_qc_to_stock.ids).button_validate()
self.assertEqual(picking_qc_to_stock.state, 'done')
mo.action_assign()
- self.assertEqual(mo.move_raw_ids.reserved_availability, 3.0)
+ self.assertEqual(mo.move_raw_ids.quantity, 3.0)
produce_form = Form(mo)
produce_form.qty_producing = 3.0
mo = produce_form.save()
- self.assertEqual(mo.move_raw_ids.quantity_done, 3.0)
- picking_qc_to_stock.move_line_ids.qty_done = 5.0
- self.assertEqual(mo.move_raw_ids.reserved_availability, 5.0)
- self.assertEqual(mo.move_raw_ids.quantity_done, 3.0)
+ self.assertEqual(mo.move_raw_ids.quantity, 3.0)
+ picking_qc_to_stock.move_line_ids.quantity = 5.0
+ self.assertEqual(mo.move_raw_ids.quantity, 3.0)
def test_link_date_mo_moves(self):
""" Check link of shedule date for manufaturing with date stock move."""
@@ -343,7 +342,7 @@ class TestProcurement(TestMrpCommon):
production.button_mark_done()
move_dest._action_assign()
- self.assertEqual(move_dest.reserved_availability, 10.0)
+ self.assertEqual(move_dest.quantity, 10.0)
def test_auto_assign(self):
""" When auto reordering rule exists, check for when:
@@ -455,7 +454,6 @@ class TestProcurement(TestMrpCommon):
'location_dest_id': self.ref('stock.stock_location_customers'),
})],
})
- pick_output.action_reset_draft()
pick_output.action_confirm() # should trigger orderpoint to create and confirm 1st MO
pick_output.action_assign()
@@ -467,7 +465,7 @@ class TestProcurement(TestMrpCommon):
self.assertEqual(len(mo), 1, "Manufacture order was not automatically created")
mo.action_assign()
mo.is_locked = False
- self.assertEqual(mo.move_raw_ids.reserved_availability, 0, "No components should be reserved yet")
+ self.assertEqual(mo.move_raw_ids.quantity, 0, "No components should be reserved yet")
self.assertEqual(mo.product_qty, 15, "Quantity to produce should be picking demand + reordering rule max qty")
# 2nd MO for product_2 should have been created and confirmed when 1st MO for product_1 was confirmed
@@ -483,7 +481,7 @@ class TestProcurement(TestMrpCommon):
mo2 = mo2_form.save()
mo2.button_mark_done()
- self.assertEqual(mo.move_raw_ids.reserved_availability, 15, "Components should have been auto-reserved")
+ self.assertEqual(mo.move_raw_ids.quantity, 15, "Components should have been auto-reserved")
# add new component to 1st MO
mo_form = Form(mo)
@@ -501,12 +499,12 @@ class TestProcurement(TestMrpCommon):
self.assertEqual(mo3.product_qty, 6, "Quantity to produce should be 1 + reordering rule max qty")
mo_form = Form(mo)
- mo.move_raw_ids.quantity_done = 15
+ mo.move_raw_ids.quantity = 15
mo_form.qty_producing = 15
mo = mo_form.save()
mo.button_mark_done()
- self.assertEqual(pick_output.move_ids_without_package.reserved_availability, 10, "Completed products should have been auto-reserved in picking")
+ self.assertEqual(pick_output.move_ids_without_package.quantity, 10, "Completed products should have been auto-reserved in picking")
# make sure next MO auto-reserves components now that they are in stock since
# default reservation_method = 'at_confirm'
@@ -518,7 +516,7 @@ class TestProcurement(TestMrpCommon):
mo_assign_at_confirm = mo_form.save()
mo_assign_at_confirm.action_confirm()
- self.assertEqual(mo_assign_at_confirm.move_raw_ids.reserved_availability, 5, "Components should have been auto-reserved")
+ self.assertEqual(mo_assign_at_confirm.move_raw_ids.quantity, 5, "Components should have been auto-reserved")
def test_check_update_qty_mto_chain(self):
""" Simulate a mto chain with a manufacturing order. Updating the
diff --git a/addons/mrp/tests/test_smp.py b/addons/mrp/tests/test_smp.py
index c5e98838b4d..3daeb966938 100644
--- a/addons/mrp/tests/test_smp.py
+++ b/addons/mrp/tests/test_smp.py
@@ -117,11 +117,11 @@ class TestMrpSerialMassProduce(TestMrpCommon):
# Reload the wizard to apply generated serial numbers
wizard = Form(self.env['stock.assign.serial'].browse(action['res_id']))
wizard.save().apply()
- # 1st & 3rd MO in sequence should have only 1 move lines (1 lot) for product_to_use_1 (2nd in bom)
+ # 1st & 2nd MO in sequence should have only 1 move lines (1 lot) for product_to_use_1 (2nd in bom)
self.assertEqual(mo.procurement_group_id.mrp_production_ids[0].move_raw_ids[1].move_lines_count, 1)
- self.assertEqual(mo.procurement_group_id.mrp_production_ids[2].move_raw_ids[1].move_lines_count, 1)
- # 2nd MO should have 2 move lines (2 different lots) for product_to_use_1
- self.assertEqual(mo.procurement_group_id.mrp_production_ids[1].move_raw_ids[1].move_lines_count, 2)
+ self.assertEqual(mo.procurement_group_id.mrp_production_ids[1].move_raw_ids[1].move_lines_count, 1)
+ # 3rd MO should have 2 move lines (2 different lots) for product_to_use_1
+ self.assertEqual(mo.procurement_group_id.mrp_production_ids[2].move_raw_ids[1].move_lines_count, 2)
# Verify if lot IDs were correctly assigned to move lines
mo.procurement_group_id.mrp_production_ids.button_mark_done()
diff --git a/addons/mrp/tests/test_stock.py b/addons/mrp/tests/test_stock.py
index c4d6ae97ed0..546fb223ec5 100644
--- a/addons/mrp/tests/test_stock.py
+++ b/addons/mrp/tests/test_stock.py
@@ -296,7 +296,7 @@ class TestKitPicking(common.TestMrpCommon):
}
def test_kit_immediate_transfer(self):
- """ Make sure a kit is split in the corrects quantity_done by components in case of an
+ """ Make sure a kit is split in the corrects quantity by components in case of an
immediate transfer.
"""
picking = self.env['stock.picking'].create({
@@ -308,7 +308,8 @@ class TestKitPicking(common.TestMrpCommon):
self.env['stock.move'].create({
'name': self.kit_parent.name,
'product_id': self.kit_parent.id,
- 'product_uom_qty': 3,
+ 'quantity': 3,
+ 'picked': True,
'product_uom': self.kit_parent.uom_id.id,
'picking_id': picking.id,
'picking_type_id': self.env.ref('stock.picking_type_in').id,
@@ -316,14 +317,12 @@ class TestKitPicking(common.TestMrpCommon):
'location_dest_id': self.warehouse_1.wh_input_stock_loc_id.id,
})
picking.button_validate()
- backorder_wizard_dict = picking.button_validate()
- backorder_wizard_form = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context']))
- backorder_wizard_form.save().process()
# We check that the picking has the correct quantities after its move were splitted.
self.assertEqual(len(picking.move_ids), 7)
- for move_line in picking.move_ids:
- self.assertEqual(move_line.quantity_done, self.expected_quantities[move_line.product_id])
+ for move in picking.move_ids:
+ self.assertEqual(move.quantity, self.expected_quantities[move.product_id])
+ self.assertEqual(move.state, 'done')
def test_kit_planned_transfer(self):
""" Make sure a kit is split in the corrects product_qty by components in case of a
@@ -334,7 +333,6 @@ class TestKitPicking(common.TestMrpCommon):
'location_dest_id': self.warehouse_1.wh_input_stock_loc_id.id,
'partner_id': self.test_partner.id,
'picking_type_id': self.env.ref('stock.picking_type_in').id,
- 'immediate_transfer': False,
})
move_receipt_1 = self.env['stock.move'].create({
'name': self.kit_parent.name,
@@ -368,8 +366,6 @@ class TestKitPicking(common.TestMrpCommon):
'picking_type_id': in_type.id,
'location_id': customer_location.id,
'location_dest_id': stock_location.id,
- 'state': 'draft',
- 'immediate_transfer': False,
'move_ids': [(0, 0, {
'name': product.name,
'product_id': product.id,
@@ -381,19 +377,20 @@ class TestKitPicking(common.TestMrpCommon):
})
receipt.action_confirm()
- receipt.move_line_ids.qty_done = 1
+ receipt.move_line_ids.quantity = 1
receipt.move_line_ids = [(0, 0, {
'product_id': kit.id,
- 'qty_done': 1,
+ 'quantity': 1,
'product_uom_id': kit.uom_id.id,
'location_id': customer_location.id,
'location_dest_id': stock_location.id,
})]
+ receipt.move_ids.picked = True
receipt.button_validate()
self.assertEqual(receipt.state, 'done')
self.assertRecordValues(receipt.move_ids, [
- {'product_id': product.id, 'quantity_done': 1, 'state': 'done'},
- {'product_id': compo.id, 'quantity_done': 1, 'state': 'done'},
+ {'product_id': product.id, 'quantity': 1, 'state': 'done'},
+ {'product_id': compo.id, 'quantity': 1, 'state': 'done'},
])
diff --git a/addons/mrp/tests/test_stock_report.py b/addons/mrp/tests/test_stock_report.py
index ee691676a6b..0850d82eab2 100644
--- a/addons/mrp/tests/test_stock_report.py
+++ b/addons/mrp/tests/test_stock_report.py
@@ -123,7 +123,7 @@ class TestMrpStockReports(TestReportsCommon):
pick = mo_1.move_raw_ids.move_orig_ids.picking_id
pick_form = Form(pick)
with pick_form.move_line_ids_without_package.edit(0) as move_line:
- move_line.qty_done = 20
+ move_line.quantity = 20
pick = pick_form.save()
pick.button_validate()
# Produces 3 products then creates a backorder for the remaining product.
@@ -236,7 +236,7 @@ class TestMrpStockReports(TestReportsCommon):
picking = picking_form.save()
picking.action_confirm()
- picking.move_ids.quantity_done = 1
+ picking.move_ids.write({'quantity': 1, 'picked': True})
move = picking.move_ids.filtered(lambda m: m.name == "Super Kit" and m.product_id == compo03)
move.move_line_ids.result_package_id = self.env['stock.quant.package'].create({'name': 'Package0001'})
picking.button_validate()
@@ -254,4 +254,6 @@ class TestMrpStockReports(TestReportsCommon):
break
if keys[0] in line:
keys = keys[1:]
+
+
self.assertFalse(keys, "All keys should be in the report with the defined order")
diff --git a/addons/mrp/tests/test_traceability.py b/addons/mrp/tests/test_traceability.py
index 8c4526df261..7c14f948fea 100644
--- a/addons/mrp/tests/test_traceability.py
+++ b/addons/mrp/tests/test_traceability.py
@@ -95,12 +95,13 @@ class TestTraceability(TestMrpCommon):
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
details_operation_form = Form(mo.move_raw_ids[2], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
self.assertEqual(mo.state, 'done', "Production order should be in done state.")
@@ -192,48 +193,45 @@ class TestTraceability(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.env['stock.lot'].create({
'product_id': product_1.id,
'name': 'Raw_1_lot_1',
'company_id': self.env.company.id,
})
- ml.qty_done = 1
details_operation_form.save()
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.env['stock.lot'].create({
'product_id': product_2.id,
'name': 'Raw_2_lot_1',
'company_id': self.env.company.id,
})
- ml.qty_done = 1
details_operation_form.save()
details_operation_form = Form(
mo.move_finished_ids.filtered(lambda m: m.product_id == byproduct_1),
view=self.env.ref('stock.view_stock_move_operations')
)
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.env['stock.lot'].create({
'product_id': byproduct_1.id,
'name': 'Byproduct_1_lot_1',
'company_id': self.env.company.id,
})
- ml.qty_done = 1
details_operation_form.save()
details_operation_form = Form(
mo.move_finished_ids.filtered(lambda m: m.product_id == byproduct_2),
view=self.env.ref('stock.view_stock_move_operations')
)
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.env['stock.lot'].create({
'product_id': byproduct_2.id,
'name': 'Byproduct_2_lot_1',
'company_id': self.env.company.id,
})
- ml.qty_done = 1
details_operation_form.save()
+ mo.move_raw_ids.picked = True
action = mo.button_mark_done()
backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context']))
backorder.save().action_backorder()
@@ -251,56 +249,50 @@ class TestTraceability(TestMrpCommon):
mo_backorder.move_raw_ids.filtered(lambda m: m.product_id == product_1),
view=self.env.ref('stock.view_stock_move_operations')
)
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.env['stock.lot'].create({
'product_id': product_1.id,
'name': 'Raw_1_lot_2',
'company_id': self.env.company.id,
})
- ml.qty_done = 1
details_operation_form.save()
details_operation_form = Form(
mo_backorder.move_raw_ids.filtered(lambda m: m.product_id == product_2),
view=self.env.ref('stock.view_stock_move_operations')
)
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.env['stock.lot'].create({
'product_id': product_2.id,
'name': 'Raw_2_lot_2',
'company_id': self.env.company.id,
})
- ml.qty_done = 1
details_operation_form.save()
details_operation_form = Form(
mo_backorder.move_finished_ids.filtered(lambda m: m.product_id == byproduct_1),
view=self.env.ref('stock.view_stock_move_operations')
)
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.env['stock.lot'].create({
'product_id': byproduct_1.id,
'name': 'Byproduct_1_lot_2',
'company_id': self.env.company.id,
})
- ml.qty_done = 1
details_operation_form.save()
details_operation_form = Form(
mo_backorder.move_finished_ids.filtered(lambda m: m.product_id == byproduct_2),
view=self.env.ref('stock.view_stock_move_operations')
)
- with details_operation_form.move_line_ids.new() as ml:
+ with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = self.env['stock.lot'].create({
'product_id': byproduct_2.id,
'name': 'Byproduct_2_lot_2',
'company_id': self.env.company.id,
})
- ml.qty_done = 1
details_operation_form.save()
+ mo_backorder.move_raw_ids.picked = True
mo_backorder.button_mark_done()
- # self.assertEqual(len(mo.move_raw_ids.mapped('move_line_ids')), 4)
- # self.assertEqual(len(mo.move_finished_ids.mapped('move_line_ids')), 6)
-
mo = mo | mo_backorder
raw_move_lines = mo.move_raw_ids.mapped('move_line_ids')
raw_line_raw_1_lot_1 = raw_move_lines.filtered(lambda ml: ml.lot_id.name == 'Raw_1_lot_1')
@@ -310,19 +302,19 @@ class TestTraceability(TestMrpCommon):
finished_move_lines = mo.move_finished_ids.mapped('move_line_ids')
finished_move_line_lot_1 = finished_move_lines.filtered(lambda ml: ml.lot_id.name == 'Final_lot_1')
- self.assertEqual(finished_move_line_lot_1.consume_line_ids.filtered(lambda l: l.qty_done), raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1)
+ self.assertEqual(finished_move_line_lot_1.consume_line_ids.filtered(lambda l: l.quantity), raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1)
finished_move_line_lot_2 = finished_move_lines.filtered(lambda ml: ml.lot_id.name == 'Final_lot_2')
raw_line_raw_1_lot_2 = raw_move_lines.filtered(lambda ml: ml.lot_id.name == 'Raw_1_lot_2')
raw_line_raw_2_lot_2 = raw_move_lines.filtered(lambda ml: ml.lot_id.name == 'Raw_2_lot_2')
self.assertEqual(finished_move_line_lot_2.consume_line_ids, raw_line_raw_1_lot_2 | raw_line_raw_2_lot_2)
byproduct_move_line_1_lot_1 = finished_move_lines.filtered(lambda ml: ml.lot_id.name == 'Byproduct_1_lot_1')
- self.assertEqual(byproduct_move_line_1_lot_1.consume_line_ids.filtered(lambda l: l.qty_done), raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1)
+ self.assertEqual(byproduct_move_line_1_lot_1.consume_line_ids.filtered(lambda l: l.quantity), raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1)
byproduct_move_line_1_lot_2 = finished_move_lines.filtered(lambda ml: ml.lot_id.name == 'Byproduct_1_lot_2')
self.assertEqual(byproduct_move_line_1_lot_2.consume_line_ids, raw_line_raw_1_lot_2 | raw_line_raw_2_lot_2)
byproduct_move_line_2_lot_1 = finished_move_lines.filtered(lambda ml: ml.lot_id.name == 'Byproduct_2_lot_1')
- self.assertEqual(byproduct_move_line_2_lot_1.consume_line_ids.filtered(lambda l: l.qty_done), raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1)
+ self.assertEqual(byproduct_move_line_2_lot_1.consume_line_ids.filtered(lambda l: l.quantity), raw_line_raw_1_lot_1 | raw_line_raw_2_lot_1)
byproduct_move_line_2_lot_2 = finished_move_lines.filtered(lambda ml: ml.lot_id.name == 'Byproduct_2_lot_2')
self.assertEqual(byproduct_move_line_2_lot_2.consume_line_ids, raw_line_raw_1_lot_2 | raw_line_raw_2_lot_2)
@@ -348,6 +340,7 @@ class TestTraceability(TestMrpCommon):
mo_form.qty_producing = 1.0
mo_form.lot_producing_id = lot
mo = mo_form.save()
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
unbuild_form = Form(self.env['mrp.unbuild'])
@@ -367,6 +360,7 @@ class TestTraceability(TestMrpCommon):
_logger.warning('Dummy')
self.assertEqual(len(log_catcher.output), 1, "Useless warnings: \n%s" % "\n".join(log_catcher.output[:-1]))
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
self.assertEqual(mo.state, 'done')
@@ -483,7 +477,7 @@ class TestTraceability(TestMrpCommon):
mo_form.qty_producing = 1
mo_form.lot_producing_id = lot_componentA
mo = mo_form.save()
- mo.move_raw_ids[0].quantity_done = 1.0
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
# Produce 1 endProduct A
@@ -496,7 +490,7 @@ class TestTraceability(TestMrpCommon):
mo_form.qty_producing = 1
mo_form.lot_producing_id = lot_endProductA
mo = mo_form.save()
- mo.move_raw_ids[0].quantity_done = 1.0
+ mo.move_raw_ids[0].write({'quantity': 1.0, 'picked': True})
mo.button_mark_done()
# Create out picking for EndProduct A
@@ -508,7 +502,7 @@ class TestTraceability(TestMrpCommon):
moveA = self.env['stock.move'].create({
'name': 'Picking A move',
'product_id': endproductA.id,
- 'quantity_done': 1,
+ 'quantity': 1,
'product_uom': endproductA.uom_id.id,
'picking_id': pickingA_out.id,
'location_id': stock_location.id,
@@ -516,10 +510,11 @@ class TestTraceability(TestMrpCommon):
# Set move_line lot_id to the mrp.production lot_producing_id
moveA.move_line_ids[0].write({
- 'qty_done': 1.0,
+ 'quantity': 1.0,
'lot_id': lot_endProductA.id,
})
# Transfer picking
+ moveA.picked = True
pickingA_out._action_done()
# Use concat so that delivery_ids is computed in batch.
@@ -557,7 +552,7 @@ class TestTraceability(TestMrpCommon):
with Form(mo) as mo_form:
mo_form.qty_producing = 1
- mo.move_raw_ids.move_line_ids.qty_done = 1
+ mo.move_raw_ids.move_line_ids.quantity = 1
mo.button_mark_done()
# unbuild
@@ -583,12 +578,13 @@ class TestTraceability(TestMrpCommon):
'product_id': component.id,
'product_uom': component.uom_id.id,
'product_uom_qty': 1.0,
+ 'picked': True,
'move_line_ids': [(0, 0, {
'product_id': component.id,
'location_id': scrap_location.id,
'location_dest_id': stock_location.id,
'product_uom_id': component.uom_id.id,
- 'qty_done': 1.0,
+ 'quantity': 1.0,
'lot_id': serial_number.id,
})],
})
@@ -605,12 +601,13 @@ class TestTraceability(TestMrpCommon):
with Form(mo) as mo_form:
mo_form.qty_producing = 1
- mo.move_raw_ids.move_line_ids.qty_done = 1
+ mo.move_raw_ids.move_line_ids.quantity = 1
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
self.assertRecordValues((mo.move_finished_ids + mo.move_raw_ids).move_line_ids, [
- {'product_id': self.bom_4.product_id.id, 'lot_id': False, 'qty_done': 1},
- {'product_id': component.id, 'lot_id': serial_number.id, 'qty_done': 1},
+ {'product_id': self.bom_4.product_id.id, 'lot_id': False, 'quantity': 1},
+ {'product_id': component.id, 'lot_id': serial_number.id, 'quantity': 1},
])
def test_generate_serial_button(self):
diff --git a/addons/mrp/tests/test_unbuild.py b/addons/mrp/tests/test_unbuild.py
index 1bb80accba4..de35232a608 100644
--- a/addons/mrp/tests/test_unbuild.py
+++ b/addons/mrp/tests/test_unbuild.py
@@ -181,9 +181,10 @@ class TestUnbuild(TestMrpCommon):
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
ml.lot_id = lot
- ml.qty_done = 20
+ ml.quantity = 20
details_operation_form.save()
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
self.assertEqual(mo.state, 'done', "Production order should be in done state.")
# Check quantity in stock before unbuild.
@@ -272,13 +273,14 @@ class TestUnbuild(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 5
+ ml.quantity = 5
details_operation_form.save()
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 20
+ ml.quantity = 20
details_operation_form.save()
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
self.assertEqual(mo.state, 'done', "Production order should be in done state.")
# Check quantity in stock before unbuild.
@@ -371,15 +373,8 @@ class TestUnbuild(TestMrpCommon):
mo_form = Form(mo)
mo_form.qty_producing = 5.0
mo = mo_form.save()
- details_operation_form = Form(mo.move_raw_ids.filtered(lambda ml: ml.product_id == p2), view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = ml.reserved_uom_qty
- with details_operation_form.move_line_ids.edit(1) as ml:
- ml.qty_done = ml.reserved_uom_qty
- with details_operation_form.move_line_ids.edit(2) as ml:
- ml.qty_done = ml.reserved_uom_qty
- details_operation_form.save()
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
self.assertEqual(mo.state, 'done', "Production order should be in done state.")
# Check quantity in stock before unbuild.
@@ -427,12 +422,13 @@ class TestUnbuild(TestMrpCommon):
mo_form.qty_producing = 3.0
mo_form.lot_producing_id = lot_finished_1
mo = mo_form.save()
- self.assertEqual(mo.move_raw_ids[1].quantity_done, 12)
+ self.assertEqual(mo.move_raw_ids[1].quantity, 12)
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
- with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 3
+ with details_operation_form.move_line_ids.edit(0) as ml:
+ ml.quantity = 3
ml.lot_id = lot_1
details_operation_form.save()
+ mo.move_raw_ids.picked = True
action = mo.button_mark_done()
backorder = Form(self.env[action['res_model']].with_context(**action['context']))
backorder.save().action_backorder()
@@ -460,16 +456,16 @@ class TestUnbuild(TestMrpCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 2
+ ml.quantity = 2
ml.lot_id = lot_2
details_operation_form.save()
action = mo.button_mark_done()
mo1 = mo.procurement_group_id.mrp_production_ids[0]
ml = mo1.finished_move_line_ids[0].consume_line_ids.filtered(lambda m: m.product_id == p1 and lot_finished_1 in m.produce_line_ids.lot_id)
- self.assertEqual(sum(ml.mapped('qty_done')), 12.0, 'Should have consumed 12 for the first lot')
+ self.assertEqual(sum(ml.mapped('quantity')), 12.0, 'Should have consumed 12 for the first lot')
ml = mo.finished_move_line_ids[0].consume_line_ids.filtered(lambda m: m.product_id == p1 and lot_finished_2 in m.produce_line_ids.lot_id)
- self.assertEqual(sum(ml.mapped('qty_done')), 8.0, 'Should have consumed 8 for the second lot')
+ self.assertEqual(sum(ml.mapped('quantity')), 8.0, 'Should have consumed 8 for the second lot')
def test_unbuild_with_routes(self):
""" This test creates a MO of a stockable product (Table). A new route for rule QC/Unbuild -> Stock
@@ -581,7 +577,7 @@ class TestUnbuild(TestMrpCommon):
# Transfer it
for ml in picking.move_ids_without_package:
- ml.quantity_done = 1
+ ml.write({'quantity': 1, 'picked': True})
picking._action_done()
# Check the available quantity of components and final product in stock
@@ -662,12 +658,13 @@ class TestUnbuild(TestMrpCommon):
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
details_operation_form = Form(mo.move_raw_ids[1], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.edit(0) as ml:
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
uo_form = Form(self.env['mrp.unbuild'])
@@ -708,7 +705,8 @@ class TestUnbuild(TestMrpCommon):
internal_form.location_dest_id = subloc01
with internal_form.move_ids_without_package.new() as move:
move.product_id = p_final
- move.quantity_done = 1.0
+ move.quantity = 1.0
+ move.picked = True
internal_transfer = internal_form.save()
internal_transfer.button_validate()
@@ -811,11 +809,12 @@ class TestUnbuild(TestMrpCommon):
details_operation_form = Form(mo2.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.new() as ml:
ml.lot_id = product_1_sn
- ml.qty_done = 1
+ ml.quantity = 1
details_operation_form.save()
mo_form = Form(mo2)
mo_form.qty_producing = 1
mo2 = mo_form.save()
+ mo2.move_raw_ids.picked = True
mo2.button_mark_done()
self.assertEqual(mo2.state, 'done', "Production order should be in done state.")
@@ -857,7 +856,7 @@ class TestUnbuild(TestMrpCommon):
mo.action_confirm()
mo.qty_producing = 1.0
mo.lot_producing_id = finished_product_sn
- mo.move_raw_ids.quantity_done = 1
+ mo.move_raw_ids.write({'quantity': 1, 'picked': True})
mo.button_mark_done()
self.assertEqual(mo.state, 'done', "Production order should be in done state.")
# unbuild order mo_1
@@ -886,7 +885,7 @@ class TestUnbuild(TestMrpCommon):
mo_2.action_confirm()
mo_2.qty_producing = 1.0
mo_2.lot_producing_id = finished_product_sn
- mo_2.move_raw_ids.quantity_done = 1
+ mo_2.move_raw_ids.write({'quantity': 1, 'picked': True})
mo_2.button_mark_done()
self.assertEqual(mo_2.state, 'done', "Production order should be in done state.")
# unbuild mo_2
diff --git a/addons/mrp/tests/test_warehouse_multistep_manufacturing.py b/addons/mrp/tests/test_warehouse_multistep_manufacturing.py
index 300ec39ba16..78dc3381cfb 100644
--- a/addons/mrp/tests/test_warehouse_multistep_manufacturing.py
+++ b/addons/mrp/tests/test_warehouse_multistep_manufacturing.py
@@ -147,7 +147,6 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
'partner_id': self.env['ir.model.data']._xmlid_to_res_id('base.res_partner_4'),
'picking_type_id': self.warehouse.out_type_id.id,
'state': 'draft',
- 'immediate_transfer': False,
})
self.env['stock.move'].create({
@@ -189,7 +188,7 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
self.assertEqual(picking_stock_postprod.origin, 'SOURCEDOCUMENT', 'The post-prod origin should be the SO name')
picking_stock_preprod.action_assign()
- picking_stock_preprod.move_line_ids.qty_done = 4
+ picking_stock_preprod.move_ids.write({'quantity': 4, 'picked': True})
picking_stock_preprod._action_done()
self.assertFalse(sum(self.env['stock.quant']._gather(self.raw_product, self.warehouse.lot_stock_id).mapped('quantity')))
@@ -230,7 +229,6 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
'partner_id': self.env['ir.model.data']._xmlid_to_res_id('base.res_partner_4'),
'picking_type_id': self.warehouse.out_type_id.id,
'state': 'draft',
- 'immediate_transfer': False,
})
self.env['stock.move'].create({
'name': self.finished_product.name,
diff --git a/addons/mrp/views/mrp_production_views.xml b/addons/mrp/views/mrp_production_views.xml
index 9367bef5bf9..8bb83f0c1c6 100644
--- a/addons/mrp/views/mrp_production_views.xml
+++ b/addons/mrp/views/mrp_production_views.xml
@@ -349,7 +349,8 @@
That being said, the best would be to have the byproducts feature working without relying on anything in the view,
e.g. so the byproducts feature works with xmlrpc calls.
-->
-
+
+
@@ -391,22 +392,23 @@
-
-
-
-
+
+
+
+
-
+
diff --git a/addons/mrp/views/mrp_workorder_views.xml b/addons/mrp/views/mrp_workorder_views.xml
index 3f8fb51c41d..6b4060cb3b8 100644
--- a/addons/mrp/views/mrp_workorder_views.xml
+++ b/addons/mrp/views/mrp_workorder_views.xml
@@ -226,8 +226,8 @@
-
-
+
+
diff --git a/addons/mrp/views/stock_move_views.xml b/addons/mrp/views/stock_move_views.xml
index 6da8e295686..65b432800af 100644
--- a/addons/mrp/views/stock_move_views.xml
+++ b/addons/mrp/views/stock_move_views.xml
@@ -15,10 +15,7 @@
- Total To Consume
-
-
- Consumed
+ Total To Consume
@@ -31,10 +28,7 @@
- To Produce
-
-
- Produced
+ To Produce
diff --git a/addons/mrp/wizard/change_production_qty.py b/addons/mrp/wizard/change_production_qty.py
index 73da124d9cb..018193347f8 100644
--- a/addons/mrp/wizard/change_production_qty.py
+++ b/addons/mrp/wizard/change_production_qty.py
@@ -58,20 +58,16 @@ class ChangeProductionQty(models.TransientModel):
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
for wizard in self:
production = wizard.mo_id
- produced = sum(production.move_finished_ids.filtered(lambda m: m.product_id == production.product_id).mapped('quantity_done'))
- if wizard.product_qty < produced:
+ if wizard.product_qty < production.qty_produced:
format_qty = '%.{precision}f'.format(precision=precision)
raise UserError(_(
- "You have already processed %(quantity)s. Please input a quantity higher than %(minimum)s ",
- quantity=format_qty % produced,
- minimum=format_qty % produced
+ "You have already processed %(quantity)s. Please input a quantity higher than %(quantity)s ",
+ quantity=format_qty % production.qty_produced,
))
old_production_qty = production.product_qty
new_production_qty = wizard.product_qty
- done_moves = production.move_finished_ids.filtered(lambda x: x.state == 'done' and x.product_id == production.product_id)
- qty_produced = production.product_id.uom_id._compute_quantity(sum(done_moves.mapped('product_qty')), production.product_uom_id)
- factor = (new_production_qty - qty_produced) / (old_production_qty - qty_produced)
+ factor = (new_production_qty - production.qty_produced) / (old_production_qty - production.qty_produced)
update_info = production._update_raw_moves(factor)
documents = {}
for move, old_qty, new_qty in update_info:
@@ -84,7 +80,7 @@ class ChangeProductionQty(models.TransientModel):
else:
documents[key] = [value]
production._log_manufacture_exception(documents)
- self._update_finished_moves(production, new_production_qty - qty_produced, old_production_qty - qty_produced)
+ self._update_finished_moves(production, new_production_qty - production.qty_produced, old_production_qty - production.qty_produced)
production.write({'product_qty': new_production_qty})
for wo in production.workorder_ids:
diff --git a/addons/mrp/wizard/mrp_consumption_warning.py b/addons/mrp/wizard/mrp_consumption_warning.py
index a7dfbf650d0..f0ee5106266 100644
--- a/addons/mrp/wizard/mrp_consumption_warning.py
+++ b/addons/mrp/wizard/mrp_consumption_warning.py
@@ -46,14 +46,14 @@ class MrpConsumptionWarning(models.TransientModel):
if line.product_id != move.product_id:
continue
qty_expected = line.product_uom_id._compute_quantity(line.product_expected_qty_uom, move.product_uom)
- qty_compare_result = float_compare(qty_expected, move.quantity_done, precision_rounding=move.product_uom.rounding)
+ qty_compare_result = float_compare(qty_expected, move.quantity, precision_rounding=move.product_uom.rounding)
if qty_compare_result != 0:
if (move.has_tracking in ('lot', 'serial')
and not production.use_auto_consume_components_lots
and qty_compare_result > 0):
problem_tracked_products |= line.product_id
break
- move.quantity_done = qty_expected
+ move.quantity = qty_expected
# in case multiple lines with same product => set others to 0 since we have no way to know how to distribute the qty done
line.product_expected_qty_uom = 0
# move was deleted before confirming MO or force deleted somehow
@@ -65,9 +65,10 @@ class MrpConsumptionWarning(models.TransientModel):
'product_id': line.product_id.id,
'product_uom': line.product_uom_id.id,
'product_uom_qty': line.product_expected_qty_uom,
- 'quantity_done': line.product_expected_qty_uom,
+ 'quantity': line.product_expected_qty_uom,
'raw_material_production_id': line.mrp_production_id.id,
'additional': True,
+ 'picked': True,
})
if problem_tracked_products:
raise UserError(
diff --git a/addons/mrp/wizard/stock_assign_serial_numbers.py b/addons/mrp/wizard/stock_assign_serial_numbers.py
index 2c778e3c25a..c72fdf94d35 100644
--- a/addons/mrp/wizard/stock_assign_serial_numbers.py
+++ b/addons/mrp/wizard/stock_assign_serial_numbers.py
@@ -78,10 +78,6 @@ class StockAssignSerialNumbers(models.TransientModel):
for workorder in production.workorder_ids:
workorder.qty_produced = workorder.qty_producing
- if productions and len(production_lots) < len(productions):
- productions[-1].move_raw_ids.move_line_ids.write({'qty_done': 0})
- productions[-1].state = "confirmed"
-
if self.mark_as_done:
productions.button_mark_done()
diff --git a/addons/mrp_account/data/mrp_account_demo.xml b/addons/mrp_account/data/mrp_account_demo.xml
index 539da456ea7..946a2a8132a 100644
--- a/addons/mrp_account/data/mrp_account_demo.xml
+++ b/addons/mrp_account/data/mrp_account_demo.xml
@@ -44,11 +44,11 @@
-
+
-
+
diff --git a/addons/mrp_account/models/mrp_production.py b/addons/mrp_account/models/mrp_production.py
index 3ebb7d484e4..aac8515ff8e 100644
--- a/addons/mrp_account/models/mrp_production.py
+++ b/addons/mrp_account/models/mrp_production.py
@@ -83,25 +83,25 @@ class MrpProduction(models.Model):
super(MrpProduction, self)._cal_price(consumed_moves)
work_center_cost = 0
finished_move = self.move_finished_ids.filtered(
- lambda x: x.product_id == self.product_id and x.state not in ('done', 'cancel') and x.quantity_done > 0)
+ lambda x: x.product_id == self.product_id and x.state not in ('done', 'cancel') and x.quantity > 0)
if finished_move:
finished_move.ensure_one()
for work_order in self.workorder_ids:
work_center_cost += work_order._cal_cost()
- qty_done = finished_move.product_uom._compute_quantity(
- finished_move.quantity_done, finished_move.product_id.uom_id)
- extra_cost = self.extra_cost * qty_done
+ quantity = finished_move.product_uom._compute_quantity(
+ finished_move.quantity, finished_move.product_id.uom_id)
+ extra_cost = self.extra_cost * quantity
total_cost = - sum(consumed_moves.sudo().stock_valuation_layer_ids.mapped('value')) + work_center_cost + extra_cost
- byproduct_moves = self.move_byproduct_ids.filtered(lambda m: m.state not in ('done', 'cancel') and m.quantity_done > 0)
+ byproduct_moves = self.move_byproduct_ids.filtered(lambda m: m.state not in ('done', 'cancel') and m.quantity > 0)
byproduct_cost_share = 0
for byproduct in byproduct_moves:
if byproduct.cost_share == 0:
continue
byproduct_cost_share += byproduct.cost_share
if byproduct.product_id.cost_method in ('fifo', 'average'):
- byproduct.price_unit = total_cost * byproduct.cost_share / 100 / byproduct.product_uom._compute_quantity(byproduct.quantity_done, byproduct.product_id.uom_id)
+ byproduct.price_unit = total_cost * byproduct.cost_share / 100 / byproduct.product_uom._compute_quantity(byproduct.quantity, byproduct.product_id.uom_id)
if finished_move.product_id.cost_method in ('fifo', 'average'):
- finished_move.price_unit = total_cost * float_round(1 - byproduct_cost_share / 100, precision_rounding=0.0001) / qty_done
+ finished_move.price_unit = total_cost * float_round(1 - byproduct_cost_share / 100, precision_rounding=0.0001) / quantity
return True
def _get_backorder_mo_vals(self):
diff --git a/addons/mrp_account/models/stock_move.py b/addons/mrp_account/models/stock_move.py
index 1cc4c64a16c..2414c2dd608 100644
--- a/addons/mrp_account/models/stock_move.py
+++ b/addons/mrp_account/models/stock_move.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import _, models
+from odoo import models
class StockMove(models.Model):
@@ -12,14 +12,6 @@ class StockMove(models.Model):
res += self.filtered(lambda m: m.bom_line_id.bom_id.product_tmpl_id.id == product.product_tmpl_id.id)
return res
- def _generate_analytic_lines_data(self, unit_amount, amount, distribution, account, distribution_on_each_plan):
- vals = super()._generate_analytic_lines_data(unit_amount, amount, distribution, account, distribution_on_each_plan)
- if self._get_analytic_distribution():
- vals['name'] = _('[Raw] %s', self.product_id.display_name)
- vals['ref'] = self.raw_material_production_id.display_name
- vals['category'] = 'manufacturing_order'
- return vals
-
def _get_analytic_distribution(self):
distribution = self.raw_material_production_id.analytic_distribution
if distribution:
diff --git a/addons/mrp_account/tests/test_analytic_account.py b/addons/mrp_account/tests/test_analytic_account.py
index 2af76f710e4..3a538851d4a 100644
--- a/addons/mrp_account/tests/test_analytic_account.py
+++ b/addons/mrp_account/tests/test_analytic_account.py
@@ -296,6 +296,6 @@ class TestAnalyticAccount(TestMrpAnalyticAccount):
mo.button_mark_done()
self.assertEqual(mo.state, 'done')
self.assertEqual(analytic_account.debit, 100)
- mo.move_raw_ids[0].quantity_done = 0
+ mo.move_raw_ids[0].quantity = 0
self.assertEqual(analytic_account.debit, 0)
self.assertFalse(analytic_account.line_ids)
diff --git a/addons/mrp_account/tests/test_valuation_layers.py b/addons/mrp_account/tests/test_valuation_layers.py
index 1389916d6d6..f7e218199cf 100644
--- a/addons/mrp_account/tests/test_valuation_layers.py
+++ b/addons/mrp_account/tests/test_valuation_layers.py
@@ -370,20 +370,20 @@ class TestMrpValuationStandard(TestMrpValuationCommon):
'location_dest_id': self.stock_location.id,
'picking_type_id': self.picking_type_in.id,
'state': 'draft',
- 'immediate_transfer': False,
'move_line_ids': [(0, 0, {
'product_id': self.product1.id,
- 'qty_done': 1,
+ 'quantity': 1,
'product_uom_id': self.product1.uom_id.id,
'location_id': self.customer_location.id,
'location_dest_id': self.stock_location.id,
})]
})
+ receipt.move_ids.picked = True
receipt.button_validate()
self.assertEqual(receipt.state, 'done')
self.assertRecordValues(receipt.move_ids, [
- {'product_id': self.component.id, 'quantity_done': 1, 'state': 'done'},
+ {'product_id': self.component.id, 'quantity': 1, 'state': 'done'},
])
self.assertEqual(self.component.qty_available, 1)
self.assertEqual(self.component.value_svl, 1424)
@@ -434,7 +434,8 @@ class TestMrpStockValuation(TestStockValuation):
'product_uom_qty': 10.0,
})
production_in.action_confirm()
- move.quantity_done = 10
+ move.quantity = 10
+ move.picked = True
production_in.button_validate()
in_aml = self._get_production_cost_move_lines()
@@ -457,7 +458,8 @@ class TestMrpStockValuation(TestStockValuation):
'product_uom_qty': 10.0,
})
production_out.action_confirm()
- move.quantity_done = 10
+ move.quantity = 10
+ move.picked = True
production_out.button_validate()
out_aml = self._get_production_cost_move_lines() - in_aml
@@ -509,7 +511,8 @@ class TestMrpStockValuation(TestStockValuation):
'product_uom_qty': 10.0,
})
production_in.action_confirm()
- move.quantity_done = 10
+ move.quantity = 10
+ move.picked = True
production_in.button_validate()
in_aml = self.env['account.move.line'].search([
@@ -534,7 +537,8 @@ class TestMrpStockValuation(TestStockValuation):
'product_uom_qty': 10.0,
})
production_out.action_confirm()
- move.quantity_done = 10
+ move.quantity = 10
+ move.picked = True
production_out.button_validate()
out_aml = self.env['account.move.line'].search([
diff --git a/addons/mrp_product_expiry/tests/test_mrp_product_expiry.py b/addons/mrp_product_expiry/tests/test_mrp_product_expiry.py
index eb34b635330..0ac46ba185f 100644
--- a/addons/mrp_product_expiry/tests/test_mrp_product_expiry.py
+++ b/addons/mrp_product_expiry/tests/test_mrp_product_expiry.py
@@ -82,7 +82,7 @@ class TestStockLot(TestStockCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 3
+ ml.quantity = 3
ml.lot_id = self.lot_good_apple
details_operation_form.save()
res = mo.button_mark_done()
@@ -105,7 +105,7 @@ class TestStockLot(TestStockCommon):
mo = mo_form.save()
details_operation_form = Form(mo.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations'))
with details_operation_form.move_line_ids.new() as ml:
- ml.qty_done = 3
+ ml.quantity = 3
ml.lot_id = self.lot_expired_apple
details_operation_form.save()
res = mo.button_mark_done()
diff --git a/addons/mrp_repair/tests/test_tracability.py b/addons/mrp_repair/tests/test_tracability.py
index 272d325de4d..074e6fff75a 100644
--- a/addons/mrp_repair/tests/test_tracability.py
+++ b/addons/mrp_repair/tests/test_tracability.py
@@ -44,6 +44,7 @@ class TestRepairTraceability(TestMrpCommon):
mo.lot_producing_id = ptrepair_lot
# Set component serial to B2
mo.move_raw_ids.move_line_ids.lot_id = ptremove_lot
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
with Form(self.env['repair.order']) as ro_form:
@@ -56,6 +57,7 @@ class TestRepairTraceability(TestMrpCommon):
ro.action_validate()
ro.move_ids[0].lot_ids = ptremove_lot # Remove product Serial B2 from the product.
ro.action_repair_start()
+ ro.move_ids.picked = True
ro.action_repair_end()
# Create a manufacturing order with product (with SN A2)
@@ -74,6 +76,7 @@ class TestRepairTraceability(TestMrpCommon):
})
# Set component serial to B2 again, it is possible
mo2.move_raw_ids.move_line_ids.lot_id = ptremove_lot
+ mo2.move_raw_ids.picked = True
# We are not forbidden to use that serial number, so nothing raised here
mo2.button_mark_done()
@@ -92,6 +95,7 @@ class TestRepairTraceability(TestMrpCommon):
mo = mo_form.save()
mo.action_confirm()
mo.action_assign()
+ mo.move_raw_ids.picked = True
mo.button_mark_done()
return mo
@@ -128,8 +132,8 @@ class TestRepairTraceability(TestMrpCommon):
ro.action_validate()
ro.move_ids[0].lot_ids = sn_lot
ro.action_repair_start()
+ ro.move_ids.picked = True
ro.action_repair_end()
-
mo = produce_one(finished, component)
self.assertEqual(mo.state, 'done')
self.assertEqual(mo.move_raw_ids.lot_ids, sn_lot)
diff --git a/addons/mrp_subcontracting/models/mrp_production.py b/addons/mrp_subcontracting/models/mrp_production.py
index d0c847f7327..9555f12aebe 100644
--- a/addons/mrp_subcontracting/models/mrp_production.py
+++ b/addons/mrp_subcontracting/models/mrp_production.py
@@ -38,7 +38,7 @@ class MrpProduction(models.Model):
for move in production.move_raw_ids:
move.move_line_ids = line_by_product.pop(move.product_id, self.env['stock.move.line'])
for product_id, lines in line_by_product.items():
- qty = sum(line.product_uom_id._compute_quantity(line.qty_done, product_id.uom_id) for line in lines)
+ qty = sum(line.product_uom_id._compute_quantity(line.quantity, product_id.uom_id) for line in lines)
move = production._get_move_raw_values(product_id, qty, product_id.uom_id)
move['additional'] = True
production.move_raw_ids = [(0, 0, move)]
@@ -58,6 +58,7 @@ class MrpProduction(models.Model):
def subcontracting_record_component(self):
self.ensure_one()
+ self.move_raw_ids.picked = True
if not self._get_subcontract_move():
raise UserError(_("This MO isn't related to a subcontracted move"))
if float_is_zero(self.qty_producing, precision_rounding=self.product_uom_id.rounding):
@@ -67,13 +68,12 @@ class MrpProduction(models.Model):
for sml in self.move_raw_ids.move_line_ids:
if sml.tracking != 'none' and not sml.lot_id:
raise UserError(_('You must enter a serial number for each line of %s', sml.product_id.display_name))
- if self.move_raw_ids and not any(self.move_raw_ids.mapped('quantity_done')):
+ if self.move_raw_ids and not any(self.move_raw_ids.mapped('quantity')):
raise UserError(_("You must indicate a non-zero amount consumed for at least one of your components"))
consumption_issues = self._get_consumption_issues()
if consumption_issues:
return self._action_generate_consumption_wizard(consumption_issues)
-
- self.sudo()._update_finished_move() # Portal user may need sudo rights to update pickings
+ self.sudo()._update_finished_move() # Portal user may need sudo rights to update pickings
self.subcontracting_has_been_recorded = True
quantity_issues = self._get_quantity_produced_issues()
@@ -104,37 +104,30 @@ class MrpProduction(models.Model):
if subcontract_move_id:
quantity = self.qty_producing
if self.lot_producing_id:
- move_lines = subcontract_move_id.move_line_ids.filtered(lambda ml: ml.lot_id == self.lot_producing_id or not ml.lot_id)
+ move_lines = subcontract_move_id.move_line_ids.filtered(lambda ml: not ml.picked and ml.lot_id == self.lot_producing_id or not ml.lot_id)
else:
- move_lines = subcontract_move_id.move_line_ids.filtered(lambda ml: not ml.lot_id)
+ move_lines = subcontract_move_id.move_line_ids.filtered(lambda ml: not ml.picked and not ml.lot_id)
# Update reservation and quantity done
for ml in move_lines:
rounding = ml.product_uom_id.rounding
if float_compare(quantity, 0, precision_rounding=rounding) <= 0:
break
- quantity_to_process = min(quantity, ml.reserved_uom_qty - ml.qty_done)
+ quantity_to_process = min(quantity, ml.quantity)
quantity -= quantity_to_process
- new_quantity_done = (ml.qty_done + quantity_to_process)
-
# on which lot of finished product
- if float_compare(new_quantity_done, ml.reserved_uom_qty, precision_rounding=rounding) >= 0:
+ if float_compare(quantity_to_process, ml.quantity, precision_rounding=rounding) >= 0:
ml.write({
- 'qty_done': new_quantity_done,
+ 'quantity': quantity_to_process,
+ 'picked': True,
'lot_id': self.lot_producing_id and self.lot_producing_id.id,
})
else:
- new_qty_reserved = ml.reserved_uom_qty - new_quantity_done
- default = {
- 'reserved_uom_qty': new_quantity_done,
- 'qty_done': new_quantity_done,
- 'lot_id': self.lot_producing_id and self.lot_producing_id.id,
- }
ml.write({
- 'reserved_uom_qty': new_qty_reserved,
- 'qty_done': 0
+ 'quantity': quantity_to_process,
+ 'picked': True,
+ 'lot_id': self.lot_producing_id and self.lot_producing_id.id,
})
- ml.copy(default=default)
if float_compare(quantity, 0, precision_rounding=self.product_uom_id.rounding) > 0:
self.env['stock.move.line'].create({
@@ -143,18 +136,13 @@ class MrpProduction(models.Model):
'product_id': self.product_id.id,
'location_id': subcontract_move_id.location_id.id,
'location_dest_id': subcontract_move_id.location_dest_id.id,
- 'reserved_uom_qty': 0,
'product_uom_id': self.product_uom_id.id,
- 'qty_done': quantity,
+ 'quantity': quantity,
+ 'picked': True,
'lot_id': self.lot_producing_id and self.lot_producing_id.id,
})
if not self._get_quantity_to_backorder():
- ml_reserved = subcontract_move_id.move_line_ids.filtered(lambda ml:
- float_is_zero(ml.qty_done, precision_rounding=ml.product_uom_id.rounding) and
- not float_is_zero(ml.reserved_uom_qty, precision_rounding=ml.product_uom_id.rounding))
- ml_reserved.unlink()
- for ml in subcontract_move_id.move_line_ids:
- ml.reserved_uom_qty = ml.qty_done
+ subcontract_move_id.move_line_ids.filtered(lambda ml: not ml.picked).unlink()
subcontract_move_id._recompute_state()
def _subcontracting_filter_to_done(self):
diff --git a/addons/mrp_subcontracting/models/stock_move.py b/addons/mrp_subcontracting/models/stock_move.py
index ad723e07b46..9413649aba2 100644
--- a/addons/mrp_subcontracting/models/stock_move.py
+++ b/addons/mrp_subcontracting/models/stock_move.py
@@ -38,7 +38,7 @@ class StockMove(models.Model):
for move in self:
if not move.is_subcontract:
continue
- if float_is_zero(move.quantity_done, precision_rounding=move.product_uom.rounding):
+ if float_is_zero(move.quantity, precision_rounding=move.product_uom.rounding):
continue
productions = move._get_subcontract_production()
if not productions or (productions[:1].consumption == 'strict' and not productions[:1]._has_tracked_component()):
@@ -110,10 +110,7 @@ class StockMove(models.Model):
'show_lots_text': False,
})
elif self.env.user.has_group('base.group_portal'):
- if self.show_reserved:
- action['views'] = [(self.env.ref('mrp_subcontracting.mrp_subcontracting_view_stock_move_operations').id, 'form')]
- else:
- action['views'] = [(self.env.ref('mrp_subcontracting.mrp_subcontracting_view_stock_move_nosuggest_operations').id, 'form')]
+ action['views'] = [(self.env.ref('mrp_subcontracting.mrp_subcontracting_view_stock_move_operations').id, 'form')]
return action
def action_show_subcontract_details(self):
@@ -135,10 +132,6 @@ class StockMove(models.Model):
'context': ctx
}
- def _set_quantities_to_reservation(self):
- move_untouchable = self.filtered(lambda m: m.is_subcontract and m._get_subcontract_production()._has_tracked_component())
- return super(StockMove, self - move_untouchable)._set_quantities_to_reservation()
-
def _action_cancel(self):
for move in self:
if move.is_subcontract:
@@ -225,11 +218,6 @@ class StockMove(models.Model):
vals['location_id'] = self.location_id.id
return vals
- def _should_bypass_set_qty_producing(self):
- if (self.production_id | self.raw_material_production_id)._get_subcontract_move():
- return False
- return super()._should_bypass_set_qty_producing()
-
def _should_bypass_reservation(self, forced_location=False):
""" If the move is subcontracted then ignore the reservation. """
should_bypass_reservation = super()._should_bypass_reservation(forced_location=forced_location)
@@ -239,7 +227,7 @@ class StockMove(models.Model):
def _update_subcontract_order_qty(self, new_quantity):
for move in self:
- move_quantity = move.quantity_done if move.from_immediate_transfer else move.product_uom_qty
+ move_quantity = move.product_uom_qty
quantity_to_remove = move_quantity - new_quantity
if float_is_zero(quantity_to_remove, precision_rounding=move.product_uom.rounding):
continue
diff --git a/addons/mrp_subcontracting/models/stock_picking.py b/addons/mrp_subcontracting/models/stock_picking.py
index 0c7258beb77..98525dd1ecf 100644
--- a/addons/mrp_subcontracting/models/stock_picking.py
+++ b/addons/mrp_subcontracting/models/stock_picking.py
@@ -13,10 +13,6 @@ class StockPicking(models.Model):
_name = 'stock.picking'
_inherit = 'stock.picking'
- # override existing field domains to prevent suboncontracting production lines from showing in Detailed Operations tab
- move_line_nosuggest_ids = fields.One2many(
- domain=['&', '|', ('location_dest_id.usage', '!=', 'production'), ('move_id.picking_code', '!=', 'outgoing'),
- '|', ('reserved_qty', '=', 0.0), '&', ('reserved_qty', '!=', 0.0), ('qty_done', '!=', 0.0)])
move_line_ids_without_package = fields.One2many(
domain=['&', '|', ('location_dest_id.usage', '!=', 'production'), ('move_id.picking_code', '!=', 'outgoing'),
'|', ('package_level_id', '=', False), ('picking_type_entire_packs', '=', False)])
@@ -49,7 +45,7 @@ class StockPicking(models.Model):
productions = move._get_subcontract_production()
recorded_productions = productions.filtered(lambda p: p._has_been_recorded())
recorded_qty = sum(recorded_productions.mapped('qty_producing'))
- sm_done_qty = sum(productions._get_subcontract_move().mapped('quantity_done'))
+ sm_done_qty = sum(productions._get_subcontract_move().filtered(lambda m: m.picked).mapped('quantity'))
rounding = self.env['decimal.precision'].precision_get('Product Unit of Measure')
if float_compare(recorded_qty, sm_done_qty, precision_digits=rounding) >= 0:
continue
@@ -59,7 +55,7 @@ class StockPicking(models.Model):
if len(production) > 1:
raise UserError(_("There shouldn't be multiple productions to record for the same subcontracted move."))
# Manage additional quantities
- quantity_done_move = move.product_uom._compute_quantity(move.quantity_done, production.product_uom_id)
+ quantity_done_move = move.product_uom._compute_quantity(move.quantity, production.product_uom_id)
if float_compare(production.product_qty, quantity_done_move, precision_rounding=production.product_uom_id.rounding) == -1:
change_qty = self.env['change.production.qty'].create({
'mo_id': production.id,
@@ -67,14 +63,15 @@ class StockPicking(models.Model):
})
change_qty.with_context(skip_activity=True).change_prod_qty()
# Create backorder MO for each move lines
- amounts = [move_line.qty_done for move_line in move.move_line_ids]
+ amounts = [move_line.quantity for move_line in move.move_line_ids]
len_amounts = len(amounts)
productions = production._split_productions({production: amounts}, set_consumed_qty=True)
- productions.move_finished_ids.move_line_ids.write({'qty_done': 0})
+ productions.move_finished_ids.move_line_ids.write({'quantity': 0})
for production, move_line in zip(productions, move.move_line_ids):
if move_line.lot_id:
production.lot_producing_id = move_line.lot_id
production.qty_producing = production.product_qty
+ production._set_qty_producing()
productions[:len_amounts].subcontracting_has_been_recorded = True
for picking in self:
@@ -138,7 +135,7 @@ class StockPicking(models.Model):
'bom_id': bom.id,
'location_src_id': subcontract_move.picking_id.partner_id.with_company(subcontract_move.company_id).property_stock_subcontractor.id,
'location_dest_id': subcontract_move.picking_id.partner_id.with_company(subcontract_move.company_id).property_stock_subcontractor.id,
- 'product_qty': subcontract_move.from_immediate_transfer and subcontract_move.quantity_done or subcontract_move.product_qty,
+ 'product_qty': subcontract_move.product_qty or subcontract_move.quantity,
'picking_type_id': warehouse.subcontracting_type_id.id,
'date_start': subcontract_move.date - relativedelta(days=bom.produce_delay)
}
@@ -150,13 +147,11 @@ class StockPicking(models.Model):
# do not create extra production for move that have their quantity updated
if move.move_orig_ids.production_id:
continue
- quantity = move.from_immediate_transfer and move.quantity_done or move.product_qty
+ quantity = move.product_qty or move.quantity
if float_compare(quantity, 0, precision_rounding=move.product_uom.rounding) <= 0:
# If a subcontracted amount is decreased, don't create a MO that would be for a negative value.
continue
mo = self.env['mrp.production'].with_company(move.company_id).create(self._prepare_subcontract_mo_vals(move, bom))
- self.env['stock.move'].create(mo._get_moves_raw_values())
- self.env['stock.move'].create(mo._get_moves_finished_values())
mo.date_finished = move.date # Avoid to have the picking late depending of the MO
mo.action_confirm()
diff --git a/addons/mrp_subcontracting/tests/test_subcontracting.py b/addons/mrp_subcontracting/tests/test_subcontracting.py
index 9cd6a291428..b73ed92bf29 100644
--- a/addons/mrp_subcontracting/tests/test_subcontracting.py
+++ b/addons/mrp_subcontracting/tests/test_subcontracting.py
@@ -40,11 +40,10 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
move.product_id = self.finished
move.product_uom_qty = 1
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
# Nothing should be tracked
- self.assertTrue(all(m.product_uom_qty == m.reserved_availability for m in picking_receipt.move_ids))
+ self.assertTrue(all(m.product_uom_qty == m.quantity for m in picking_receipt.move_ids))
self.assertEqual(picking_receipt.state, 'assigned')
self.assertEqual(picking_receipt.display_action_record_components, 'hide')
@@ -72,7 +71,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
picking = self.env['stock.picking'].search([('group_id', '=', pg1.id)])
self.assertEqual(len(picking), 1)
self.assertEqual(picking.picking_type_id, wh.subcontracting_resupply_type_id)
- picking_receipt.move_ids.quantity_done = 1
+ picking_receipt.move_ids.quantity = 1
+ picking_receipt.move_ids.picked = True
picking_receipt.button_validate()
self.assertEqual(mo.state, 'done')
@@ -122,7 +122,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished
- move.quantity_done = 1
+ move.quantity = 1
+ move.picked = True
picking_receipt = picking_form.save()
# Nothing should be tracked
@@ -149,7 +150,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
comp2mo = self.env['mrp.production'].search([('bom_id', '=', self.comp2_bom.id)])
self.assertEqual(len(comp2mo), 0)
- picking_receipt.move_ids.quantity_done = 1
+ picking_receipt.move_ids.quantity = 1
+ picking_receipt.move_ids.picked = True
picking_receipt.button_validate()
self.assertEqual(mo.state, 'done')
@@ -189,7 +191,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished
- move.quantity_done = 1
+ move.quantity = 1
+ move.picked = True
picking_receipt = picking_form.save()
# Nothing should be tracked
@@ -215,7 +218,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
# As well as a manufacturing order for `self.comp2`
comp2mo = self.env['mrp.production'].search([('bom_id', '=', self.comp2_bom.id)])
self.assertEqual(len(comp2mo), 1)
- picking_receipt.move_ids.quantity_done = 1
+ picking_receipt.move_ids.quantity = 1
+ picking_receipt.move_ids.picked = True
picking_receipt.button_validate()
self.assertEqual(mo.state, 'done')
@@ -254,7 +258,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished
- move.quantity_done = 1
+ move.quantity = 1
+ move.picked = True
picking_receipt = picking_form.save()
warehouse = picking_receipt.picking_type_id.warehouse_id
@@ -322,7 +327,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished
- move.quantity_done = 1
+ move.quantity = 1
+ move.picked = True
picking_receipt1 = picking_form.save()
# Create a receipt picking from the subcontractor2
@@ -331,7 +337,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
picking_form.partner_id = subcontractor_partner2
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished
- move.quantity_done = 1
+ move.quantity = 1
+ move.picked = True
picking_receipt2 = picking_form.save()
mo_pick1 = picking_receipt1.move_ids.mapped('move_orig_ids.production_id')
@@ -383,21 +390,21 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
move.product_id = self.finished
move.product_uom_qty = 1
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
- picking_receipt.move_ids.quantity_done = 3.0
+ picking_receipt.move_ids.quantity = 3.0
+ picking_receipt.move_ids.picked = True
picking_receipt._action_done()
mo = picking_receipt._get_subcontract_production()
move_comp1 = mo.move_raw_ids.filtered(lambda m: m.product_id == self.comp1)
move_comp3 = mo.move_raw_ids.filtered(lambda m: m.product_id == comp3)
self.assertEqual(sum(move_comp1.mapped('product_uom_qty')), 3.0)
self.assertEqual(sum(move_comp3.mapped('product_uom_qty')), 6.0)
- self.assertEqual(sum(move_comp1.mapped('quantity_done')), 3.0)
- self.assertEqual(sum(move_comp3.mapped('quantity_done')), 6.0)
+ self.assertEqual(sum(move_comp1.mapped('quantity')), 3.0)
+ self.assertEqual(sum(move_comp3.mapped('quantity')), 6.0)
move_finished = mo.move_finished_ids
self.assertEqual(sum(move_finished.mapped('product_uom_qty')), 3.0)
- self.assertEqual(sum(move_finished.mapped('quantity_done')), 3.0)
+ self.assertEqual(sum(move_finished.mapped('quantity')), 3.0)
def test_flow_8(self):
resupply_sub_on_order_route = self.env['stock.route'].search([('name', '=', 'Resupply Subcontractor on Order')])
@@ -411,10 +418,10 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
move.product_id = self.finished
move.product_uom_qty = 5
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
- picking_receipt.move_ids.quantity_done = 3
+ picking_receipt.move_ids.quantity = 3
+ picking_receipt.move_ids.picked = True
backorder_wiz = picking_receipt.button_validate()
backorder_wiz = Form(self.env[backorder_wiz['res_model']].with_context(backorder_wiz['context'])).save()
backorder_wiz.process()
@@ -430,7 +437,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
self.assertTrue(backorder_mo)
self.assertEqual(backorder_mo.product_uom_qty, 2)
self.assertEqual(backorder_mo.qty_produced, 0)
- backorder.move_ids.quantity_done = 2
+ backorder.move_ids.quantity = 2
+ backorder.move_ids.picked = True
backorder._action_done()
self.assertTrue(picking_receipt.move_ids.move_orig_ids[0].production_id.state == 'done')
@@ -450,7 +458,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished
- move.quantity_done = 5
+ move.quantity = 5
+ move.picked = True
picking_receipt = picking_form.save()
picking_delivery = self.env['stock.move'].search([
@@ -484,7 +493,6 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
move.product_id = self.finished
move.product_uom_qty = 1
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
# Check that a manufacturing order is created
@@ -502,7 +510,6 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
move.product_id = self.finished
move.product_uom_qty = 1
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
self.assertEqual(picking_receipt.display_action_record_components, 'facultative')
action = picking_receipt.action_record_components()
@@ -511,11 +518,11 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
mo_form.qty_producing = 1
with mo_form.move_line_raw_ids.edit(0) as ml:
self.assertEqual(ml.product_id, self.comp1)
- self.assertEqual(ml.qty_done, 1)
- ml.qty_done = 2
+ self.assertEqual(ml.quantity, 1)
+ ml.quantity = 2
mo = mo_form.save()
mo.subcontracting_record_component()
- self.assertEqual(mo.move_raw_ids[0].move_line_ids.qty_done, 2)
+ self.assertEqual(mo.move_raw_ids[0].move_line_ids.quantity, 2)
# We should not be able to call the 'record_components' button
self.assertEqual(picking_receipt.display_action_record_components, 'hide')
@@ -536,7 +543,6 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
move.product_id = self.finished
move.product_uom_qty = 1
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
self.assertEqual(picking_receipt.display_action_record_components, 'facultative')
@@ -546,8 +552,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
mo_form.qty_producing = 1
with mo_form.move_line_raw_ids.edit(0) as ml:
self.assertEqual(ml.product_id, self.comp1)
- self.assertEqual(ml.qty_done, 1)
- ml.qty_done = 2
+ self.assertEqual(ml.quantity, 1)
+ ml.quantity = 2
mo = mo_form.save()
action_warning = mo.subcontracting_record_component()
warning = Form(self.env['mrp.consumption.warning'].with_context(**action_warning['context']))
@@ -559,7 +565,7 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
warning = warning.save()
warning.action_confirm()
- self.assertEqual(mo.move_raw_ids[0].move_line_ids.qty_done, 2)
+ self.assertEqual(mo.move_raw_ids[0].move_line_ids.quantity, 2)
# We should not be able to call the 'record_components' button
self.assertEqual(picking_receipt.display_action_record_components, 'hide')
@@ -614,7 +620,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
def test_several_backorders(self):
def process_picking(picking, qty):
- picking.move_ids.quantity_done = qty
+ picking.move_ids.quantity = qty
+ picking.move_ids.picked = True
action = picking.button_validate()
if isinstance(action, dict):
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
@@ -645,7 +652,6 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
move.product_id = finished
move.product_uom_qty = 5
picking = picking_form.save()
- picking.action_reset_draft()
picking.action_confirm()
supply_picking = self.env['mrp.production'].search([('bom_id', '=', bom.id)]).picking_ids
@@ -657,8 +663,7 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
process_picking(backorder01, 1)
backorder02 = backorder01.backorder_ids
- process_picking(backorder02, 0)
- self.assertEqual(backorder02.move_ids.quantity_done, 2.75)
+ self.assertEqual(backorder02.move_ids.quantity, 2.75)
self.assertEqual(self.env['mrp.production'].search_count([('bom_id', '=', bom.id)]), 3)
@@ -698,7 +703,8 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
with self.assertRaises(AssertionError):
with Form(picking) as picking_form:
with picking_form.move_ids_without_package.edit(0) as line:
- line.quantity_done = done_qty
+ line.quantity = done_qty
+ line.picked = True
action = picking.action_record_components()
mo = self.env['mrp.production'].browse(action['res_id'])
@@ -715,7 +721,7 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon):
productions = self.env['mrp.production'].search([('product_id', '=', finished.id)], order='id')
self.assertEqual(productions.mapped('state'), ['done', 'done'])
- self.assertEqual(productions.move_raw_ids.mapped('quantity_done'), [2.0, 3.0])
+ self.assertEqual(productions.move_raw_ids.mapped('quantity'), [2.0, 3.0])
def test_subcontracting_rules_replication(self):
""" Test activate/archive subcontracting location rules."""
@@ -802,9 +808,9 @@ class TestSubcontractingTracking(TransactionCase):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished_product
- move.quantity_done = 1
+ move.quantity = 1
+ move.picked = True
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
# We should be able to call the 'record_components' button
@@ -881,10 +887,10 @@ class TestSubcontractingTracking(TransactionCase):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished_product
- move.quantity_done = nb_finished_product
+ move.quantity = nb_finished_product
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
+ picking_receipt.action_clear_quantities_to_zero()
# We shouldn't be able to call the 'record_components' button
self.assertEqual(picking_receipt.display_action_record_components, 'hide')
@@ -892,13 +898,13 @@ class TestSubcontractingTracking(TransactionCase):
wh = picking_receipt.picking_type_id.warehouse_id
lot_names_finished = [f"subtracked_{i}" for i in range(nb_finished_product)]
- move_details = Form(picking_receipt.move_ids, view='stock.view_stock_move_nosuggest_operations')
+ move_details = Form(picking_receipt.move_ids, view='stock.view_stock_move_operations')
for lot_name in lot_names_finished:
- with move_details.move_line_nosuggest_ids.new() as ml:
- ml.qty_done = 1
+ with move_details.move_line_ids.new() as ml:
+ ml.quantity = 1
ml.lot_name = lot_name
move_details.save()
-
+ picking_receipt.move_ids.picked = True
picking_receipt.button_validate()
# Check the created manufacturing order
# Should have one mo by serial number
@@ -929,9 +935,8 @@ class TestSubcontractingTracking(TransactionCase):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished_product
- move.quantity_done = todo_nb
+ move.quantity = todo_nb
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
# We should be able to call the 'record_components' button
@@ -981,6 +986,7 @@ class TestSubcontractingTracking(TransactionCase):
# We should not be able to call the 'record_components' button
self.assertEqual(picking_receipt.display_action_record_components, 'hide')
+ picking_receipt.move_ids.picked = True
picking_receipt.button_validate()
self.assertEqual(mo.state, 'done')
self.assertEqual(mo.procurement_group_id.mrp_production_ids.mapped("state"), ['done'] * todo_nb)
@@ -1035,7 +1041,6 @@ class TestSubcontractingTracking(TransactionCase):
move.product_id = finished_product
move.product_uom_qty = todo_nb
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
mo = self.env['mrp.production'].search([('bom_id', '=', bom.id)])
@@ -1043,9 +1048,7 @@ class TestSubcontractingTracking(TransactionCase):
# Process the delivery of the components
compo_picking = mo.picking_ids
compo_picking.action_assign()
- wizard_data = compo_picking.button_validate()
- wizard = Form(self.env[wizard_data['res_model']].with_context(wizard_data['context'])).save()
- wizard.process()
+ compo_picking.button_validate()
for qty in [3, 1]:
# Record the receiption of finished products
@@ -1108,9 +1111,9 @@ class TestSubcontractingTracking(TransactionCase):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = finished_product
- move.quantity_done = todo_nb
+ move.quantity = todo_nb
+ move.picked = True
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
mo = self.env['mrp.production'].search([('bom_id', '=', bom.id)])
@@ -1118,16 +1121,13 @@ class TestSubcontractingTracking(TransactionCase):
# Process the delivery of the components
compo_picking = mo.picking_ids
compo_picking.action_assign()
- wizard_data = compo_picking.button_validate()
- wizard = Form(self.env[wizard_data['res_model']].with_context(wizard_data['context'])).save()
- wizard.process()
+ compo_picking.button_validate()
picking_receipt = self.env['stock.picking'].search([('partner_id', '=', self.subcontractor_partner1.id), ('state', '!=', 'done')])
for sn in finished_serials:
# Record the production of each serial number separately
action = picking_receipt.action_record_components()
mo = self.env['mrp.production'].browse(action['res_id'])
- self.assertEqual(mo.move_raw_ids.state, 'assigned')
mo_form = Form(mo.with_context(**action['context']), view=action['view_id'])
mo_form.qty_producing = 1
mo_form.lot_producing_id = sn
@@ -1210,7 +1210,6 @@ class TestSubcontractingPortal(TransactionCase):
move.product_id = self.finished_product
move.product_uom_qty = 2
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
# Using the subcontractor (portal user)
@@ -1259,7 +1258,7 @@ class TestSubcontractingPortal(TransactionCase):
ml.product_id = self.comp1_sn
ml.lot_id = serial3
with mo_form.move_line_raw_ids.edit(1) as ml:
- ml.qty_done = 2
+ ml.quantity = 2
# The portal user should not be able to add a product not in the BoM
with self.assertRaises(AccessError):
with mo_form.move_line_raw_ids.new() as ml:
@@ -1277,11 +1276,11 @@ class TestSubcontractingPortal(TransactionCase):
# Validation from the backend user
picking_receipt.button_validate()
self.assertEqual(mo.state, 'done')
- self.assertEqual(mo.move_line_raw_ids[0].qty_done, 1)
+ self.assertEqual(mo.move_line_raw_ids[0].quantity, 1)
self.assertEqual(mo.move_line_raw_ids[0].lot_id, serial2)
- self.assertEqual(mo.move_line_raw_ids[1].qty_done, 1)
+ self.assertEqual(mo.move_line_raw_ids[1].quantity, 1)
self.assertEqual(mo.move_line_raw_ids[1].lot_id, serial3)
- self.assertEqual(mo.move_line_raw_ids[2].qty_done, 2)
+ self.assertEqual(mo.move_line_raw_ids[2].quantity, 2)
class TestSubcontractingSerialMassReceipt(TransactionCase):
def setUp(self):
@@ -1324,23 +1323,21 @@ class TestSubcontractingSerialMassReceipt(TransactionCase):
move.product_id = self.finished
move.product_uom_qty = sum(quantities)
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
# Process the delivery of the components
picking_deliver = self.env['mrp.production'].search([('bom_id', '=', self.bom.id)]).picking_ids
picking_deliver.action_assign()
picking_deliver.button_validate()
- wizard_data = picking_deliver.button_validate()
- wizard = Form(self.env[wizard_data['res_model']].with_context(wizard_data['context'])).save()
- wizard.process()
# Receive
for quantity in quantities:
# Receive finished products
+ picking_receipt.action_clear_quantities_to_zero()
Form(self.env['stock.assign.serial'].with_context(
default_move_id=picking_receipt.move_ids[0].id,
default_next_serial_number=self.env['stock.lot']._get_next_serial(picking_receipt.company_id, picking_receipt.move_ids[0].product_id) or 'sn#1',
default_next_serial_count=quantity,
)).save().generate_serial_numbers()
+ picking_receipt.move_ids.picked = True
wizard_data = picking_receipt.button_validate()
if wizard_data is not True:
# Create backorder
@@ -1361,14 +1358,17 @@ class TestSubcontractingSerialMassReceipt(TransactionCase):
picking_form.partner_id = self.subcontractor
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished
- move.quantity_done = quantity
+ move.product_uom_qty = quantity
picking_receipt = picking_form.save()
+ picking_receipt.action_confirm()
+ picking_receipt.action_clear_quantities_to_zero()
# Receive finished products
Form(self.env['stock.assign.serial'].with_context(
default_move_id=picking_receipt.move_ids[0].id,
default_next_serial_number=self.env['stock.lot']._get_next_serial(picking_receipt.company_id, picking_receipt.move_ids[0].product_id) or 'sn#1',
default_next_serial_count=quantity,
)).save().generate_serial_numbers()
+ picking_receipt.move_ids.picked = True
picking_receipt.button_validate()
self.assertEqual(picking_receipt.state, 'done')
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.raw_material, self.env.ref('stock.stock_location_stock')), 0)
diff --git a/addons/mrp_subcontracting/tests/test_subcontracting_portal_ui.py b/addons/mrp_subcontracting/tests/test_subcontracting_portal_ui.py
index e6a58915d41..27fa0f53996 100644
--- a/addons/mrp_subcontracting/tests/test_subcontracting_portal_ui.py
+++ b/addons/mrp_subcontracting/tests/test_subcontracting_portal_ui.py
@@ -54,9 +54,9 @@ class TestSubcontractingPortalUi(HttpCase):
picking_form.partner_id = self.partner_portal
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished_product
- move.quantity_done = 2
+ move.quantity = 2
+ move.picked = True
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
picking_receipt.action_confirm()
self.start_tour("/my/productions", 'subcontracting_portal_tour', login="georges1")
diff --git a/addons/mrp_subcontracting/views/stock_move_views.xml b/addons/mrp_subcontracting/views/stock_move_views.xml
index 7dde602230f..4c6838bb6f9 100644
--- a/addons/mrp_subcontracting/views/stock_move_views.xml
+++ b/addons/mrp_subcontracting/views/stock_move_views.xml
@@ -23,10 +23,7 @@
invisible="tracking not in ('serial', 'lot')"
required="tracking in ('serial', 'lot')"
context="{'default_product_id': product_id, 'default_company_id': company_id}"/>
-
-
+
@@ -70,18 +67,7 @@
-
- mrp.subcontracting.stock.move.operations.nosuggest.form
- stock.move
- primary
- 1000
-
-
-
- {'tree_view_ref': 'mrp_subcontracting.mrp_subcontracting_view_stock_move_line_operation_tree','default_picking_id': picking_id, 'default_move_id': id, 'default_product_id': product_id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id, 'default_company_id': company_id}
-
-
-
+
mrp.subcontracting.move.form.view
stock.move
@@ -105,7 +91,7 @@
-
+
-
+
@@ -152,7 +138,7 @@
stock.move
1000
-
+
@@ -172,8 +158,7 @@
-
-
+
diff --git a/addons/mrp_subcontracting/views/subcontracting_portal_views.xml b/addons/mrp_subcontracting/views/subcontracting_portal_views.xml
index accfdf7839a..c1169ed6afd 100644
--- a/addons/mrp_subcontracting/views/subcontracting_portal_views.xml
+++ b/addons/mrp_subcontracting/views/subcontracting_portal_views.xml
@@ -32,7 +32,7 @@
-
+
diff --git a/addons/mrp_subcontracting_account/models/mrp_production.py b/addons/mrp_subcontracting_account/models/mrp_production.py
index 6b10e4e45a3..d76be99bfa2 100644
--- a/addons/mrp_subcontracting_account/models/mrp_production.py
+++ b/addons/mrp_subcontracting_account/models/mrp_production.py
@@ -8,7 +8,7 @@ class MrpProduction(models.Model):
_inherit = 'mrp.production'
def _cal_price(self, consumed_moves):
- finished_move = self.move_finished_ids.filtered(lambda x: x.product_id == self.product_id and x.state not in ('done', 'cancel') and x.quantity_done > 0)
+ finished_move = self.move_finished_ids.filtered(lambda x: x.product_id == self.product_id and x.state not in ('done', 'cancel') and x.quantity > 0)
# Take the price unit of the reception move
last_done_receipt = finished_move.move_dest_ids.filtered(lambda m: m.state == 'done')[-1:]
if last_done_receipt.is_subcontract:
diff --git a/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py b/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py
index 4ad87454dd5..a0ac489befb 100644
--- a/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py
+++ b/addons/mrp_subcontracting_account/tests/test_subcontracting_account.py
@@ -36,7 +36,8 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
})
move1._action_confirm()
move1._action_assign()
- move1.move_line_ids.qty_done = 10.0
+ move1.move_line_ids.quantity = 10.0
+ move1.picked = True
move1._action_done()
move2 = self.env['stock.move'].create({
'name': 'IN 10 units @ 20.00 per unit',
@@ -49,7 +50,8 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
})
move2._action_confirm()
move2._action_assign()
- move2.move_line_ids.qty_done = 10.0
+ move2.move_line_ids.quantity = 10.0
+ move2.picked = True
move2._action_done()
all_amls_ids = self.env['account.move.line'].search([]).ids
@@ -66,7 +68,8 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
picking_receipt.action_confirm()
# Suppose the additional cost changes:
picking_receipt.move_ids.price_unit = 30.0
- picking_receipt.move_ids.quantity_done = 1.0
+ picking_receipt.move_ids.quantity = 1.0
+ picking_receipt.move_ids.picked = True
picking_receipt._action_done()
mo = picking_receipt._get_subcontract_production()
@@ -106,7 +109,8 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
picking_receipt.move_ids.price_unit = 0
picking_receipt.action_confirm()
- picking_receipt.move_ids.quantity_done = 1.0
+ picking_receipt.move_ids.quantity = 1.0
+ picking_receipt.move_ids.picked = True
picking_receipt._action_done()
mo = picking_receipt._get_subcontract_production()
@@ -168,7 +172,8 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
})
move1._action_confirm()
move1._action_assign()
- move1.move_line_ids.qty_done = 10.0
+ move1.move_line_ids.quantity = 10.0
+ move1.picked = True
move1._action_done()
move2 = self.env['stock.move'].create({
'name': 'IN 10 units @ 20.00 per unit',
@@ -181,7 +186,8 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
})
move2._action_confirm()
move2._action_assign()
- move2.move_line_ids.qty_done = 10.0
+ move2.move_line_ids.quantity = 10.0
+ move2.picked = True
move2._action_done()
all_amls_ids = self.env['account.move.line'].search([]).ids
@@ -195,7 +201,8 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
picking_receipt = picking_form.save()
picking_receipt.move_ids.price_unit = 30.0
picking_receipt.action_confirm()
- picking_receipt.move_ids.quantity_done = 1.0
+ picking_receipt.move_ids.quantity = 1.0
+ picking_receipt.move_ids.picked = True
picking_receipt._action_done()
amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)])
@@ -231,12 +238,12 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished
- move.quantity_done = todo_nb
+ move.quantity = todo_nb
picking_receipt = picking_form.save()
- picking_receipt.action_reset_draft()
# Mimic the extra cost on the po line
picking_receipt.move_ids.price_unit = 50
picking_receipt.action_confirm()
+ picking_receipt.action_clear_quantities_to_zero()
# We should be able to call the 'record_components' button
self.assertTrue(picking_receipt.display_action_record_components)
@@ -275,7 +282,7 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
mo.subcontracting_record_component()
# We should not be able to call the 'record_components' button
-
+ picking_receipt.move_ids.picked = True
picking_receipt.button_validate()
f_layers = self.finished.stock_valuation_layer_ids
@@ -307,7 +314,6 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
move.product_id = self.finished
move.product_uom_qty = 10
receipt = receipt_form.save()
- receipt.action_reset_draft()
# add an extra cost
receipt.move_ids.price_unit = 50
receipt.action_confirm()
@@ -371,7 +377,8 @@ class TestAccountSubcontractingFlows(TestMrpSubcontractingCommon):
picking_receipt.move_ids.price_unit = 15.0
picking_receipt.action_confirm()
- picking_receipt.move_ids.quantity_done = 1.0
+ picking_receipt.move_ids.quantity = 1.0
+ picking_receipt.move_ids.picked = True
picking_receipt._action_done()
amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)])
diff --git a/addons/mrp_subcontracting_dropshipping/tests/test_anglo_saxon_valuation.py b/addons/mrp_subcontracting_dropshipping/tests/test_anglo_saxon_valuation.py
index 969438c5434..045eb9e9d63 100644
--- a/addons/mrp_subcontracting_dropshipping/tests/test_anglo_saxon_valuation.py
+++ b/addons/mrp_subcontracting_dropshipping/tests/test_anglo_saxon_valuation.py
@@ -69,8 +69,7 @@ class TestSubcontractingDropshippingValuation(ValuationReconciliationTestCommon)
po.button_confirm()
delivery = po.picking_ids
- res = delivery.button_validate()
- Form(self.env['stock.immediate.transfer'].with_context(res['context'])).save().process()
+ delivery.button_validate()
stock_in_acc_id = self.categ_fifo_auto.property_stock_account_input_categ_id.id
stock_out_acc_id = self.categ_fifo_auto.property_stock_account_output_categ_id.id
@@ -104,7 +103,8 @@ class TestSubcontractingDropshippingValuation(ValuationReconciliationTestCommon)
return_wizard = return_form.save()
return_id, _ = return_wizard._create_returns()
return_picking = self.env['stock.picking'].browse(return_id)
- return_picking.move_ids.quantity_done = 1
+ return_picking.move_ids.quantity = 1
+ return_picking.move_ids.picked = True
return_picking.button_validate()
amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)])
@@ -125,7 +125,8 @@ class TestSubcontractingDropshippingValuation(ValuationReconciliationTestCommon)
return_wizard = return_form.save()
return_id, _ = return_wizard._create_returns()
return_picking = self.env['stock.picking'].browse(return_id)
- return_picking.move_ids.quantity_done = 1
+ return_picking.move_ids.quantity = 1
+ return_picking.move_ids.picked = True
return_picking.button_validate()
amls = self.env['account.move.line'].search([('id', 'not in', all_amls_ids)])
diff --git a/addons/mrp_subcontracting_dropshipping/tests/test_purchase_subcontracting.py b/addons/mrp_subcontracting_dropshipping/tests/test_purchase_subcontracting.py
index 8ae8122824c..f884281fe2a 100644
--- a/addons/mrp_subcontracting_dropshipping/tests/test_purchase_subcontracting.py
+++ b/addons/mrp_subcontracting_dropshipping/tests/test_purchase_subcontracting.py
@@ -241,7 +241,8 @@ class TestSubcontractingDropshippingFlows(TestMrpSubcontractingCommon):
self.assertEqual(mo.picking_type_id, self.warehouse.subcontracting_type_id)
delivery = po.picking_ids
- delivery.move_line_ids.qty_done = 2.0
+ delivery.move_line_ids.quantity = 2.0
+ delivery.move_ids.picked = True
delivery.button_validate()
self.assertEqual(delivery.state, 'done')
@@ -259,7 +260,8 @@ class TestSubcontractingDropshippingFlows(TestMrpSubcontractingCommon):
return_picking_id, _pick_type_id = return_wizard._create_returns()
delivery_return01 = self.env['stock.picking'].browse(return_picking_id)
- delivery_return01.move_line_ids.qty_done = 1.0
+ delivery_return01.move_line_ids.quantity = 1.0
+ delivery_return01.move_ids.picked = True
delivery_return01.button_validate()
self.assertEqual(delivery_return01.state, 'done')
@@ -276,7 +278,8 @@ class TestSubcontractingDropshippingFlows(TestMrpSubcontractingCommon):
return_picking_id, _pick_type_id = return_wizard._create_returns()
delivery_return02 = self.env['stock.picking'].browse(return_picking_id)
- delivery_return02.move_line_ids.qty_done = 1.0
+ delivery_return02.move_line_ids.quantity = 1.0
+ delivery_return02.move_ids.picked = True
delivery_return02.button_validate()
self.assertEqual(delivery_return02.state, 'done')
@@ -343,7 +346,8 @@ class TestSubcontractingDropshippingFlows(TestMrpSubcontractingCommon):
self.assertEqual(delivery.location_dest_id, super_subcontractor.property_stock_subcontractor)
self.assertTrue(delivery.is_dropship)
- delivery.move_line_ids.qty_done = 1.0
+ delivery.move_line_ids.quantity = 1.0
+ delivery.move_ids.picked = True
delivery.button_validate()
self.assertEqual(po.order_line.qty_received, 1.0)
diff --git a/addons/mrp_subcontracting_dropshipping/tests/test_sale_dropshipping.py b/addons/mrp_subcontracting_dropshipping/tests/test_sale_dropshipping.py
index dcdf1e7b1c3..fe03e37a31d 100644
--- a/addons/mrp_subcontracting_dropshipping/tests/test_sale_dropshipping.py
+++ b/addons/mrp_subcontracting_dropshipping/tests/test_sale_dropshipping.py
@@ -57,16 +57,12 @@ class TestSaleDropshippingFlows(TestMrpSubcontractingCommon):
# Deliver the first one
picking = sale_order.picking_ids.filtered(lambda p: p.partner_id == partners[0])
- action = picking.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
+ picking.button_validate()
self.assertEqual(sale_order.order_line.qty_delivered, 0)
# Deliver the third one
picking = sale_order.picking_ids.filtered(lambda p: p.partner_id == partners[2])
- action = picking.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
+ picking.button_validate()
self.assertEqual(sale_order.order_line.qty_delivered, 0)
# Cancel the second one
@@ -106,9 +102,7 @@ class TestSaleDropshippingFlows(TestMrpSubcontractingCommon):
self.assertEqual(sale_order.order_line.qty_delivered, 0.0)
picking = sale_order.picking_ids
- action = picking.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
+ picking.button_validate()
self.assertEqual(sale_order.order_line.qty_delivered, 1.0)
for case in ['return', 'deliver again']:
@@ -120,9 +114,7 @@ class TestSaleDropshippingFlows(TestMrpSubcontractingCommon):
picking = self.env['stock.picking'].browse(action['res_id'])
self.assertEqual(sale_order.order_line.qty_delivered, delivered_before_case, "Incorrect delivered qty for case '%s'" % case)
- action = picking.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
+ picking.button_validate()
self.assertEqual(sale_order.order_line.qty_delivered, delivered_after_case, "Incorrect delivered qty for case '%s'" % case)
def test_partial_return_kit_and_delivered_qty(self):
@@ -166,7 +158,8 @@ class TestSaleDropshippingFlows(TestMrpSubcontractingCommon):
self.assertEqual(sale_order.order_line.qty_delivered, 0.0, "Delivered components: 0/4")
picking01 = sale_order.picking_ids
- picking01.move_ids.quantity_done = 2
+ picking01.move_ids.quantity = 2
+ picking01.move_ids.picked = True
action = picking01.button_validate()
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
wizard.process()
@@ -179,19 +172,22 @@ class TestSaleDropshippingFlows(TestMrpSubcontractingCommon):
res = wizard.create_returns()
return01 = self.env['stock.picking'].browse(res['res_id'])
- return01.move_ids.quantity_done = 2
+ return01.move_ids.quantity = 2
+ return01.move_ids.picked = True
return01.button_validate()
self.assertEqual(sale_order.order_line.qty_delivered, 0.0, "Delivered components: 0/4")
picking02 = picking01.backorder_ids
- picking02.move_ids.quantity_done = 1
+ picking02.move_ids.quantity = 1
+ picking02.move_ids.picked = True
action = picking02.button_validate()
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
wizard.process()
self.assertEqual(sale_order.order_line.qty_delivered, 0.0, "Delivered components: 1/4")
picking03 = picking02.backorder_ids
- picking03.move_ids.quantity_done = 1
+ picking03.move_ids.quantity = 1
+ picking03.move_ids.picked = True
picking03.button_validate()
self.assertEqual(sale_order.order_line.qty_delivered, 0.0, "Delivered components: 2/4")
@@ -202,7 +198,8 @@ class TestSaleDropshippingFlows(TestMrpSubcontractingCommon):
res = wizard.create_returns()
picking04 = self.env['stock.picking'].browse(res['res_id'])
- picking04.move_ids.quantity_done = 1
+ picking04.move_ids.quantity = 1
+ picking04.move_ids.picked = True
picking04.button_validate()
self.assertEqual(sale_order.order_line.qty_delivered, 0.0, "Delivered components: 3/4")
@@ -213,7 +210,8 @@ class TestSaleDropshippingFlows(TestMrpSubcontractingCommon):
res = wizard.create_returns()
picking04 = self.env['stock.picking'].browse(res['res_id'])
- picking04.move_ids.quantity_done = 1
+ picking04.move_ids.quantity = 1
+ picking04.move_ids.picked = True
picking04.button_validate()
self.assertEqual(sale_order.order_line.qty_delivered, 1, "Delivered components: 4/4")
@@ -286,7 +284,8 @@ class TestSaleDropshippingFlows(TestMrpSubcontractingCommon):
sale_order.action_confirm()
self.env['purchase.order'].search([], order='id desc', limit=1).button_confirm()
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.quantity = 1
+ sale_order.picking_ids.move_ids.picked = True
sale_order.picking_ids[0].button_validate()
sale_order.picking_ids[1].button_validate()
diff --git a/addons/mrp_subcontracting_purchase/tests/test_mrp_subcontracting_purchase.py b/addons/mrp_subcontracting_purchase/tests/test_mrp_subcontracting_purchase.py
index e42fb5d8989..08065697cb6 100644
--- a/addons/mrp_subcontracting_purchase/tests/test_mrp_subcontracting_purchase.py
+++ b/addons/mrp_subcontracting_purchase/tests/test_mrp_subcontracting_purchase.py
@@ -98,7 +98,8 @@ class MrpSubcontractingPurchaseTest(TestMrpSubcontractingCommon):
# check that a neg qty can't proprogate once receipt is done
for move in receipt.move_ids:
- move.move_line_ids.qty_done = move.product_qty
+ move.move_line_ids.quantity = move.product_qty
+ receipt.move_ids.picked = True
receipt.button_validate()
self.assertEqual(receipt.state, 'done')
self.assertEqual(sub_mos.state, 'done')
@@ -127,7 +128,8 @@ class MrpSubcontractingPurchaseTest(TestMrpSubcontractingCommon):
self.assertTrue(mo)
receipt = po.picking_ids
- receipt.move_ids.quantity_done = 10
+ receipt.move_ids.quantity = 10
+ receipt.move_ids.picked = True
receipt.button_validate()
return_form = Form(self.env['stock.return.picking'].with_context(active_id=receipt.id, active_model='stock.picking'))
@@ -137,7 +139,8 @@ class MrpSubcontractingPurchaseTest(TestMrpSubcontractingCommon):
return_id, _ = return_wizard._create_returns()
return_picking = self.env['stock.picking'].browse(return_id)
- return_picking.move_ids.quantity_done = 3
+ return_picking.move_ids.quantity = 3
+ return_picking.move_ids.picked = True
return_picking.button_validate()
self.assertEqual(self.finished2.qty_available, 7.0)
@@ -169,7 +172,8 @@ class MrpSubcontractingPurchaseTest(TestMrpSubcontractingCommon):
self.assertTrue(mo)
receipt = po.picking_ids
- receipt.move_ids.quantity_done = 10
+ receipt.move_ids.quantity = 10
+ receipt.move_ids.picked = True
receipt.button_validate()
return_form = Form(self.env['stock.return.picking'].with_context(active_id=receipt.id, active_model='stock.picking'))
@@ -180,7 +184,8 @@ class MrpSubcontractingPurchaseTest(TestMrpSubcontractingCommon):
return_id, _ = return_wizard._create_returns()
return_picking = self.env['stock.picking'].browse(return_id)
- return_picking.move_ids.quantity_done = 3
+ return_picking.move_ids.quantity = 3
+ return_picking.move_ids.picked = True
return_picking.button_validate()
self.assertEqual(self.finished2.qty_available, 7.0)
@@ -276,12 +281,14 @@ class MrpSubcontractingPurchaseTest(TestMrpSubcontractingCommon):
action = po.action_view_subcontracting_resupply()
resupply_picking = self.env[action['res_model']].browse(action['res_id'])
- resupply_picking.move_ids.quantity_done = 1
+ resupply_picking.move_ids.quantity = 1
+ resupply_picking.move_ids.picked = True
resupply_picking.button_validate()
action = po.action_view_picking()
final_picking = self.env[action['res_model']].browse(action['res_id'])
- final_picking.move_ids.quantity_done = 1
+ final_picking.move_ids.quantity = 1
+ final_picking.move_ids.picked = True
final_picking.button_validate()
action = po.action_create_invoice()
@@ -308,16 +315,15 @@ class MrpSubcontractingPurchaseTest(TestMrpSubcontractingCommon):
'order_line': [Command.create({
'name': self.finished.name,
'product_id': self.finished.id,
- 'product_uom_qty': 10,
+ 'product_qty': 10,
'product_uom': self.finished.uom_id.id,
'price_unit': 1,
})],
})
-
purchase.button_confirm()
# receive product
receipt = purchase.picking_ids
- receipt.move_ids.quantity_done = 10
+ receipt.move_ids.picked = True
receipt.button_validate()
# create bill
purchase.action_create_invoice()
diff --git a/addons/point_of_sale/models/pos_session.py b/addons/point_of_sale/models/pos_session.py
index 4abfd4fa3d3..e6e760cc440 100644
--- a/addons/point_of_sale/models/pos_session.py
+++ b/addons/point_of_sale/models/pos_session.py
@@ -804,7 +804,7 @@ class PosSession(models.Model):
signed_product_qty = move.product_qty
if move._is_in():
signed_product_qty *= -1
- amount = signed_product_qty * move.product_id._compute_average_price(0, move.quantity_done, move)
+ amount = signed_product_qty * move.product_id._compute_average_price(0, move.quantity, move)
stock_expense[exp_key] = self._update_amounts(stock_expense[exp_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
if move._is_in():
stock_return[out_key] = self._update_amounts(stock_return[out_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
@@ -833,7 +833,7 @@ class PosSession(models.Model):
signed_product_qty = move.product_qty
if move._is_in():
signed_product_qty *= -1
- amount = signed_product_qty * move.product_id._compute_average_price(0, move.quantity_done, move)
+ amount = signed_product_qty * move.product_id._compute_average_price(0, move.quantity, move)
stock_expense[exp_key] = self._update_amounts(stock_expense[exp_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
if move._is_in():
stock_return[out_key] = self._update_amounts(stock_return[out_key], {'amount': amount}, move.picking_id.date, force_company_currency=True)
diff --git a/addons/point_of_sale/models/stock_picking.py b/addons/point_of_sale/models/stock_picking.py
index 28c5e3c7486..a675abef0fd 100644
--- a/addons/point_of_sale/models/stock_picking.py
+++ b/addons/point_of_sale/models/stock_picking.py
@@ -81,7 +81,6 @@ class StockPicking(models.Model):
'picking_type_id': self.picking_type_id.id,
'product_id': first_line.product_id.id,
'product_uom_qty': abs(sum(order_lines.mapped('qty'))),
- 'state': 'draft',
'location_id': self.location_id.id,
'location_dest_id': self.location_dest_id.id,
'company_id': self.company_id.id,
@@ -97,6 +96,7 @@ class StockPicking(models.Model):
moves = self.env['stock.move'].create(move_vals)
confirmed_moves = moves._action_confirm()
confirmed_moves._add_mls_related_to_order(lines, are_qties_done=True)
+ confirmed_moves.picked = True
self._link_owner_on_return_picking(lines)
def _link_owner_on_return_picking(self, lines):
@@ -105,12 +105,12 @@ class StockPicking(models.Model):
returned_lines_picking = lines[0].order_id.refunded_order_ids.picking_ids
returnable_qty_by_product = {}
for move_line in returned_lines_picking.move_line_ids:
- returnable_qty_by_product[(move_line.product_id.id, move_line.owner_id.id or 0)] = move_line.qty_done
+ returnable_qty_by_product[(move_line.product_id.id, move_line.owner_id.id or 0)] = move_line.quantity
for move in self.move_line_ids:
for keys in returnable_qty_by_product:
if move.product_id.id == keys[0] and keys[1] and returnable_qty_by_product[keys] > 0:
move.write({'owner_id': keys[1]})
- returnable_qty_by_product[keys] -= move.qty_done
+ returnable_qty_by_product[keys] -= move.quantity
def _send_confirmation_email(self):
@@ -198,22 +198,6 @@ class StockMove(models.Model):
lines_data[product_id].update({'order_lines': self.env['pos.order.line'].concat(*olines)})
return lines_data
- def _complete_done_qties(self, set_quantity_done_on_move=False):
- self._action_assign()
- for move_line in self.move_line_ids:
- move_line.qty_done = move_line.reserved_uom_qty
- mls_vals = []
- moves_to_set = set()
- for move in self:
- if float_compare(move.product_uom_qty, move.quantity_done, precision_rounding=move.product_uom.rounding) > 0:
- remaining_qty = move.product_uom_qty - move.quantity_done
- mls_vals.append(dict(move._prepare_move_line_vals(), qty_done=remaining_qty))
- moves_to_set.add(move.id)
- self.env['stock.move.line'].create(mls_vals)
- if set_quantity_done_on_move:
- for move in self.env['stock.move'].browse(moves_to_set):
- move.quantity_done = move.product_uom_qty
-
def _create_production_lots_for_pos_order(self, lines):
''' Search for existing lots and create missing ones.
@@ -251,56 +235,16 @@ class StockMove(models.Model):
def _add_mls_related_to_order(self, related_order_lines, are_qties_done=True):
lines_data = self._prepare_lines_data_dict(related_order_lines)
- qty_fname = 'qty_done' if are_qties_done else 'reserved_uom_qty'
# Moves with product_id not in related_order_lines. This can happend e.g. when product_id has a phantom-type bom.
moves_to_assign = self.filtered(lambda m: m.product_id.id not in lines_data or m.product_id.tracking == 'none'
or (not m.picking_type_id.use_existing_lots and not m.picking_type_id.use_create_lots))
- moves_to_assign._complete_done_qties(set_quantity_done_on_move=True)
+ for move in moves_to_assign:
+ move.quantity = move.product_uom_qty
moves_remaining = self - moves_to_assign
existing_lots = moves_remaining._create_production_lots_for_pos_order(related_order_lines)
- move_lines_to_create = []
- mls_qties = []
if are_qties_done:
for move in moves_remaining:
- for line in lines_data[move.product_id.id]['order_lines']:
- sum_of_lots = 0
- for lot in line.pack_lot_ids.filtered(lambda l: l.lot_name):
- if line.product_id.tracking == 'serial':
- qty = 1
- else:
- qty = abs(line.qty)
- ml_vals = dict(move._prepare_move_line_vals())
- if existing_lots:
- existing_lot = existing_lots.filtered_domain([('product_id', '=', line.product_id.id), ('name', '=', lot.lot_name)])
- quant = self.env['stock.quant']
- if existing_lot:
- quant = self.env['stock.quant'].search(
- [('lot_id', '=', existing_lot.id), ('quantity', '>', '0.0'), ('location_id', 'child_of', move.location_id.id)],
- order='id desc',
- limit=1
- )
- ml_vals.update({
- 'lot_id': existing_lot.id,
- 'location_id': quant.location_id.id or move.location_id.id,
- 'owner_id': quant.owner_id.id or False,
- })
- else:
- ml_vals.update({'lot_name': lot.lot_name})
- move_lines_to_create.append(ml_vals)
- mls_qties.append(qty)
- sum_of_lots += qty
- if abs(line.qty) != sum_of_lots:
- difference_qty = abs(line.qty) - sum_of_lots
- ml_vals = move._prepare_move_line_vals()
- if line.product_id.tracking == 'serial':
- move_lines_to_create.extend([ml_vals for i in range(int(difference_qty))])
- mls_qties.extend([1]*int(difference_qty))
- else:
- move_lines_to_create.append(ml_vals)
- mls_qties.append(difference_qty)
- move_lines = self.env['stock.move.line'].create(move_lines_to_create)
- for move_line, qty in zip(move_lines, mls_qties):
- move_line.write({qty_fname: qty})
+ move.quantity = move.product_uom_qty
else:
for move in moves_remaining:
for line in lines_data[move.product_id.id]['order_lines']:
diff --git a/addons/point_of_sale/tests/test_anglo_saxon.py b/addons/point_of_sale/tests/test_anglo_saxon.py
index 22d5ca18038..05693684d28 100644
--- a/addons/point_of_sale/tests/test_anglo_saxon.py
+++ b/addons/point_of_sale/tests/test_anglo_saxon.py
@@ -277,7 +277,7 @@ class TestAngloSaxonFlow(TestAngloSaxonCommon):
self.assertEqual(current_session_id.state, 'closed', 'Check that session is closed')
self.assertEqual(len(current_session.picking_ids), 2, "There should be 2 pickings")
- current_session.picking_ids.move_ids_without_package.quantity_done = 1
+ current_session.picking_ids.move_ids_without_package.write({'quantity': 1, 'picked': True})
current_session.picking_ids.button_validate()
# I test that the generated journal entries are correct.
diff --git a/addons/point_of_sale/tests/test_pos_margin.py b/addons/point_of_sale/tests/test_pos_margin.py
index bb5ec0eb344..fdb2bca3a4d 100644
--- a/addons/point_of_sale/tests/test_pos_margin.py
+++ b/addons/point_of_sale/tests/test_pos_margin.py
@@ -289,7 +289,8 @@ class TestPosMargin(TestPoSCommon):
}).sudo()
move1._action_confirm()
move1._action_assign()
- move1.move_line_ids.qty_done = 2
+ move1.move_line_ids.quantity = 2
+ move1.picked = True
move1._action_done()
move2 = self.env['stock.move'].create({
@@ -303,7 +304,8 @@ class TestPosMargin(TestPoSCommon):
}).sudo()
move2._action_confirm()
move2._action_assign()
- move2.move_line_ids.qty_done = 1
+ move2.move_line_ids.quantity = 1
+ move2.picked = True
move2._action_done()
# open a session
@@ -349,7 +351,8 @@ class TestPosMargin(TestPoSCommon):
}).sudo()
move1._action_confirm()
move1._action_assign()
- move1.move_line_ids.qty_done = 2
+ move1.move_line_ids.quantity = 2
+ move1.picked = True
move1._action_done()
move2 = self.env['stock.move'].create({
@@ -363,7 +366,8 @@ class TestPosMargin(TestPoSCommon):
}).sudo()
move2._action_confirm()
move2._action_assign()
- move2.move_line_ids.qty_done = 1
+ move2.move_line_ids.quantity = 1
+ move2.picked = True
move2._action_done()
# open a session
diff --git a/addons/pos_sale/tests/test_pos_sale_flow.py b/addons/pos_sale/tests/test_pos_sale_flow.py
index 684f5bd8959..435ae7c55e8 100644
--- a/addons/pos_sale/tests/test_pos_sale_flow.py
+++ b/addons/pos_sale/tests/test_pos_sale_flow.py
@@ -56,7 +56,8 @@ class TestPoSSale(TestPointOfSaleHttpCommon):
})
sale_order.action_confirm()
picking = sale_order.picking_ids
- picking.move_ids.quantity_done = 300
+ picking.move_ids.quantity = 300
+ picking.move_ids.picked = True
action = picking.button_validate()
wizard = Form(self.env[action['res_model']].with_context(action['context']))
wizard.save().process()
@@ -75,9 +76,9 @@ class TestPoSSale(TestPointOfSaleHttpCommon):
#assert that sales order qty are correctly updated
self.assertEqual(sale_order.order_line.qty_delivered, 3)
self.assertEqual(sale_order.picking_ids[0].move_ids.product_qty, 2100) # 7 left to deliver => 300 * 7 = 2100
- self.assertEqual(sale_order.picking_ids[0].move_ids.quantity_done, 0)
+ self.assertEqual(sale_order.picking_ids[0].move_ids.quantity, 0)
self.assertEqual(sale_order.picking_ids[1].move_ids.product_qty, 300)
- self.assertEqual(sale_order.picking_ids[1].move_ids.quantity_done, 300) # 1 delivered => 300 * 2 = 600
+ self.assertEqual(sale_order.picking_ids[1].move_ids.quantity, 300) # 1 delivered => 300 * 2 = 600
def test_settle_order_with_incompatible_partner(self):
""" If the partner of the sale order is not compatible with the current pos order,
@@ -242,9 +243,9 @@ class TestPoSSale(TestPointOfSaleHttpCommon):
})
sale_order.action_confirm()
- self.assertEqual(sale_order.order_line.move_ids.move_line_ids[0].reserved_qty, 2)
+ self.assertEqual(sale_order.order_line.move_ids.move_line_ids[0].quantity, 2)
self.assertEqual(sale_order.order_line.move_ids.move_line_ids[0].location_id.id, self.shelf_1.id)
- self.assertEqual(sale_order.order_line.move_ids.move_line_ids[1].reserved_qty, 2)
+ self.assertEqual(sale_order.order_line.move_ids.move_line_ids[1].quantity, 2)
self.assertEqual(sale_order.order_line.move_ids.move_line_ids[1].location_id.id, self.shelf_2.id)
self.main_pos_config.company_id.write({'point_of_sale_update_stock_quantities': 'real'})
@@ -252,9 +253,9 @@ class TestPoSSale(TestPointOfSaleHttpCommon):
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'PosSettleOrderRealTime', login="accountman")
self.main_pos_config.current_session_id.close_session_from_ui()
pos_order = self.env['pos.order'].search([], order='id desc', limit=1)
- self.assertEqual(pos_order.picking_ids.move_line_ids[0].qty_done, 2)
+ self.assertEqual(pos_order.picking_ids.move_line_ids[0].quantity, 2)
self.assertEqual(pos_order.picking_ids.move_line_ids[0].location_id.id, self.shelf_1.id)
- self.assertEqual(pos_order.picking_ids.move_line_ids[1].qty_done, 2)
+ self.assertEqual(pos_order.picking_ids.move_line_ids[1].quantity, 2)
self.assertEqual(pos_order.picking_ids.move_line_ids[1].location_id.id, self.shelf_2.id)
self.assertEqual(sale_order.order_line.move_ids.move_lines_count, 0)
diff --git a/addons/product_expiry/tests/test_generate_serial_numbers.py b/addons/product_expiry/tests/test_generate_serial_numbers.py
index f775f888a66..a881ea4b76e 100644
--- a/addons/product_expiry/tests/test_generate_serial_numbers.py
+++ b/addons/product_expiry/tests/test_generate_serial_numbers.py
@@ -43,7 +43,7 @@ class TestStockLot(StockGenerateCommon):
self.assertEqual(len(move.move_line_ids), len(list_lot_and_qty))
for i, move_line in enumerate(move.move_line_ids):
self.assertEqual(move_line.lot_name, list_lot_and_qty[i]['lot_name'])
- self.assertEqual(move_line.qty_done, 1)
+ self.assertEqual(move_line.quantity, 1)
self.assertEqual(move_line.expiration_date, list_lot_and_qty[i]["datetime"])
# Same test but with with the "month/day/year" date format this time.
@@ -61,7 +61,7 @@ class TestStockLot(StockGenerateCommon):
self.assertEqual(len(move.move_line_ids), len(list_lot_and_qty))
for i, move_line in enumerate(move.move_line_ids):
self.assertEqual(move_line.lot_name, list_lot_and_qty[i]['lot_name'])
- self.assertEqual(move_line.qty_done, 1)
+ self.assertEqual(move_line.quantity, 1)
self.assertEqual(move_line.expiration_date, list_lot_and_qty[i]["datetime"])
def test_set_multiple_lot_name_with_expiration_date_02_product_dont_use_expiration_date(self):
@@ -90,7 +90,7 @@ class TestStockLot(StockGenerateCommon):
self.assertEqual(len(move.move_line_ids), len(list_lot_and_qty))
for i, move_line in enumerate(move.move_line_ids):
self.assertEqual(move_line.lot_name, list_lot_and_qty[i]['lot_name'])
- self.assertEqual(move_line.qty_done, 1)
+ self.assertEqual(move_line.quantity, 1)
self.assertEqual(move_line.expiration_date, False)
def test_set_multiple_lot_name_with_expiration_date_03_adaptive_date_format(self):
@@ -119,7 +119,7 @@ class TestStockLot(StockGenerateCommon):
self.assertEqual(len(move.move_line_ids), len(list_lot_and_qty))
for i, move_line in enumerate(move.move_line_ids):
self.assertEqual(move_line.lot_name, list_lot_and_qty[i]['lot_name'])
- self.assertEqual(move_line.qty_done, 1)
+ self.assertEqual(move_line.quantity, 1)
self.assertEqual(move_line.expiration_date, list_lot_and_qty[i]["datetime"])
# Now, tries with day first but the year is at the first place in the given dates.
@@ -137,7 +137,7 @@ class TestStockLot(StockGenerateCommon):
self.assertEqual(len(move.move_line_ids), len(list_lot_and_qty))
for i, move_line in enumerate(move.move_line_ids):
self.assertEqual(move_line.lot_name, list_lot_and_qty[i]['lot_name'])
- self.assertEqual(move_line.qty_done, 1)
+ self.assertEqual(move_line.quantity, 1)
self.assertEqual(move_line.expiration_date, list_lot_and_qty[i]["datetime"])
def test_set_multiple_lot_name_with_expiration_date_04_written_months(self):
@@ -160,7 +160,7 @@ class TestStockLot(StockGenerateCommon):
self.assertEqual(len(move.move_line_ids), len(list_lot_and_qty))
for i, move_line in enumerate(move.move_line_ids):
self.assertEqual(move_line.lot_name, list_lot_and_qty[i]['lot_name'])
- self.assertEqual(move_line.qty_done, 1)
+ self.assertEqual(move_line.quantity, 1)
self.assertEqual(move_line.expiration_date, list_lot_and_qty[i]["datetime"])
@freeze_time('2023-04-17')
@@ -191,35 +191,35 @@ class TestStockLot(StockGenerateCommon):
self.assertEqual(len(move.move_line_ids), len(list_lot_and_qty))
self.assertEqual(move.move_line_ids[0].lot_name, "ln01")
- self.assertEqual(move.move_line_ids[0].qty_done, 1)
+ self.assertEqual(move.move_line_ids[0].quantity, 1)
self.assertEqual(move.move_line_ids[0].expiration_date, datetime(day=31, month=12, year=2023))
self.assertEqual(move.move_line_ids[1].lot_name, "ln02")
- self.assertEqual(move.move_line_ids[1].qty_done, 1)
+ self.assertEqual(move.move_line_ids[1].quantity, 1)
self.assertEqual(move.move_line_ids[1].expiration_date, datetime(day=17, month=4, year=1989))
self.assertEqual(move.move_line_ids[2].lot_name, "ln03")
- self.assertEqual(move.move_line_ids[2].qty_done, 1)
+ self.assertEqual(move.move_line_ids[2].quantity, 1)
self.assertEqual(move.move_line_ids[2].expiration_date, today)
self.assertEqual(move.move_line_ids[3].lot_name, "ln04")
- self.assertEqual(move.move_line_ids[3].qty_done, 1989)
+ self.assertEqual(move.move_line_ids[3].quantity, 1989)
self.assertEqual(move.move_line_ids[3].expiration_date, today)
self.assertEqual(move.move_line_ids[4].lot_name, "ln05")
- self.assertEqual(move.move_line_ids[4].qty_done, 1989.04)
+ self.assertEqual(move.move_line_ids[4].quantity, 1989.04)
self.assertEqual(move.move_line_ids[4].expiration_date, today)
self.assertEqual(move.move_line_ids[5].lot_name, "ln06\t1989+04")
- self.assertEqual(move.move_line_ids[5].qty_done, 1)
+ self.assertEqual(move.move_line_ids[5].quantity, 1)
self.assertEqual(move.move_line_ids[5].expiration_date, today)
self.assertEqual(move.move_line_ids[6].lot_name, "ln07\tdacember")
- self.assertEqual(move.move_line_ids[6].qty_done, 1)
+ self.assertEqual(move.move_line_ids[6].quantity, 1)
self.assertEqual(move.move_line_ids[6].expiration_date, today)
self.assertEqual(move.move_line_ids[7].lot_name, "ln08")
- self.assertEqual(move.move_line_ids[7].qty_done, 1)
+ self.assertEqual(move.move_line_ids[7].quantity, 1)
self.assertEqual(move.move_line_ids[7].expiration_date, datetime(day=17, month=12, year=2023))
def test_set_multiple_lot_name_with_expiration_date_06_one_line(self):
@@ -237,5 +237,5 @@ class TestStockLot(StockGenerateCommon):
move = self.get_new_move(product=product_lot)
self._import_lots(lot_name, move)
self.assertEqual(move.move_line_ids.lot_name, "lot-001")
- self.assertEqual(move.move_line_ids.qty_done, 20)
+ self.assertEqual(move.move_line_ids.quantity, 20)
self.assertEqual(move.move_line_ids.expiration_date, datetime(day=4, month=8, year=2048))
diff --git a/addons/product_expiry/tests/test_stock_lot.py b/addons/product_expiry/tests/test_stock_lot.py
index 0b4c9ceab56..6a7c3ed42fe 100644
--- a/addons/product_expiry/tests/test_stock_lot.py
+++ b/addons/product_expiry/tests/test_stock_lot.py
@@ -51,7 +51,6 @@ class TestStockLot(TestStockCommon):
'location_id': self.supplier_location,
'location_dest_id': self.stock_location,
'state': 'draft',
- 'immediate_transfer': False,
})
move_a = self.MoveObj.create({
@@ -70,10 +69,11 @@ class TestStockLot(TestStockCommon):
# Replace pack operation of incoming shipments.
picking_in.action_assign()
- move_a.move_line_ids.qty_done = 33
+ move_a.move_line_ids.quantity = 33
move_a.move_line_ids.lot_id = self.lot1_productAAA.id
# Transfer Incoming Shipment.
+ move_a.picked = True
picking_in._action_done()
# run scheduled tasks
@@ -148,7 +148,6 @@ class TestStockLot(TestStockCommon):
'picking_type_id': self.picking_type_in,
'location_id': self.supplier_location,
'state': 'draft',
- 'immediate_transfer': False,
'location_dest_id': self.stock_location})
move_b = self.MoveObj.create({
@@ -166,7 +165,7 @@ class TestStockLot(TestStockCommon):
# Replace pack operation of incoming shipments.
picking_in.action_assign()
- move_b.move_line_ids.qty_done = 44
+ move_b.move_line_ids.quantity = 44
move_b.move_line_ids.lot_id = self.lot1_productBBB.id
# Transfer Incoming Shipment.
@@ -197,7 +196,6 @@ class TestStockLot(TestStockCommon):
'picking_type_id': self.picking_type_in,
'location_id': self.supplier_location,
'state': 'draft',
- 'immediate_transfer': False,
'location_dest_id': self.stock_location})
move_c = self.MoveObj.create({
@@ -215,7 +213,7 @@ class TestStockLot(TestStockCommon):
# Replace pack operation of incoming shipments.
picking_in.action_assign()
- move_c.move_line_ids.qty_done = 55
+ move_c.move_line_ids.quantity = 55
move_c.move_line_ids.lot_id = self.lot1_productCCC.id
# Transfer Incoming Shipment.
@@ -313,12 +311,12 @@ class TestStockLot(TestStockCommon):
# Defines a date during the receipt.
move_form = Form(receipt.move_ids_without_package, view="stock.view_stock_move_operations")
- with move_form.move_line_nosuggest_ids.new() as line:
+ with move_form.move_line_ids.edit(0) as line:
line.lot_name = 'Apple Box #2'
line.expiration_date = expiration_date
- line.qty_done = 4
move = move_form.save()
+ move.picked = True
receipt._action_done()
# Get back the lot created when the picking was done...
apple_lot = self.env['stock.lot'].search(
@@ -355,7 +353,8 @@ class TestStockLot(TestStockCommon):
picking_form.picking_type_id = self.env.ref('stock.picking_type_in')
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.apple_product
- move.quantity_done = 4
+ move.quantity = 4
+ move.picked = True
receipt = picking_form.save()
# Defines a date during the receipt.
@@ -424,8 +423,9 @@ class TestStockLot(TestStockCommon):
'lot_id': good_lot.id,
'product_id': self.apple_product.id,
'product_uom_id': self.apple_product.uom_id.id,
- 'qty_done': 4,
+ 'quantity': 4,
})]
+ delivery_1.move_ids.picked = True
res = delivery_1.button_validate()
# Validate a delivery for good products must not raise anything.
self.assertEqual(res, True)
@@ -449,7 +449,7 @@ class TestStockLot(TestStockCommon):
'lot_id': good_lot.id,
'product_id': self.apple_product.id,
'product_uom_id': self.apple_product.uom_id.id,
- 'qty_done': 4,
+ 'quantity': 4,
}), (0, 0, {
'company_id': self.env.company.id,
'location_id': delivery_2.move_ids.location_id.id,
@@ -457,8 +457,9 @@ class TestStockLot(TestStockCommon):
'lot_id': expired_lot_1.id,
'product_id': self.apple_product.id,
'product_uom_id': self.apple_product.uom_id.id,
- 'qty_done': 4,
+ 'quantity': 4,
})]
+ delivery_2.move_ids.picked = True
res = delivery_2.button_validate()
# Validate a delivery containing expired products must raise a confirmation wizard.
self.assertNotEqual(res, True)
@@ -482,8 +483,9 @@ class TestStockLot(TestStockCommon):
'lot_id': expired_lot_1.id,
'product_id': self.apple_product.id,
'product_uom_id': self.apple_product.uom_id.id,
- 'qty_done': 4,
+ 'quantity': 4,
})]
+ delivery_3.move_ids.picked = True
res = delivery_3.button_validate()
# Validate a delivery containing expired products must raise a confirmation wizard.
self.assertNotEqual(res, True)
@@ -535,7 +537,7 @@ class TestStockLot(TestStockCommon):
'location_id': self.supplier_location,
'location_dest_id': self.stock_location,
'product_id': self.apple_product.id,
- 'qty_done': 3,
+ 'quantity': 3,
'product_uom_id': self.apple_product.uom_id.id,
'lot_id': lot.id,
'company_id': self.env.company.id,
diff --git a/addons/product_expiry/views/stock_move_views.xml b/addons/product_expiry/views/stock_move_views.xml
index 01515443426..66360220f85 100644
--- a/addons/product_expiry/views/stock_move_views.xml
+++ b/addons/product_expiry/views/stock_move_views.xml
@@ -11,17 +11,6 @@
-
- stock.move.operations.inherit.form
- stock.move
-
-
-
-
-
-
-
-
stock.move.line.inherit.tree
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index 8e5a4787eca..96408db0b51 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -1275,7 +1275,7 @@ class PurchaseOrderLine(models.Model):
line.product_packaging_id = False
# suggest biggest suitable packaging
if line.product_id and line.product_qty and line.product_uom:
- line.product_packaging_id = line.product_id.packaging_ids.filtered('purchase')._find_suitable_product_packaging(line.product_qty, line.product_uom) or line.product_packaging_id
+ line.product_packaging_id = line.product_id.packaging_ids.filtered('purchase').with_context(myCompany=line.company_id)._find_suitable_product_packaging(line.product_qty, line.product_uom) or line.product_packaging_id
@api.onchange('product_packaging_id')
def _onchange_product_packaging_id(self):
diff --git a/addons/purchase_mrp/tests/test_anglo_saxon_valuation.py b/addons/purchase_mrp/tests/test_anglo_saxon_valuation.py
index 238adc3577c..27a9601a6c8 100644
--- a/addons/purchase_mrp/tests/test_anglo_saxon_valuation.py
+++ b/addons/purchase_mrp/tests/test_anglo_saxon_valuation.py
@@ -60,9 +60,7 @@ class TestAngloSaxonValuationPurchaseMRP(TransactionCase):
po = po_form.save()
po.button_confirm()
- action = po.picking_ids.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
+ po.picking_ids.button_validate()
action = po.action_create_invoice()
invoice = self.env['account.move'].browse(action['res_id'])
@@ -133,7 +131,7 @@ class TestAngloSaxonValuationPurchaseMRP(TransactionCase):
po.button_confirm()
receipt = po.picking_ids
- receipt.move_line_ids.qty_done = 1
+ receipt.move_line_ids.quantity = 1
receipt.button_validate()
self.assertEqual(receipt.state, 'done')
@@ -156,7 +154,7 @@ class TestAngloSaxonValuationPurchaseMRP(TransactionCase):
})],
})
delivery.action_confirm()
- delivery.move_ids.move_line_ids.qty_done = 1
+ delivery.move_ids.move_line_ids.quantity = 1
delivery.button_validate()
self.assertEqual(component01.stock_valuation_layer_ids.mapped('value'), [25, -25])
@@ -173,7 +171,7 @@ class TestAngloSaxonValuationPurchaseMRP(TransactionCase):
wizard = wizard_form.save()
action = wizard.create_returns()
return_picking = self.env["stock.picking"].browse(action["res_id"])
- return_picking.move_ids.move_line_ids.qty_done = 1
+ return_picking.move_ids.move_line_ids.quantity = 1
return_picking.button_validate()
self.assertEqual(component01.stock_valuation_layer_ids.mapped('value'), [25, -25, 25])
diff --git a/addons/purchase_mrp/tests/test_purchase_mrp_flow.py b/addons/purchase_mrp/tests/test_purchase_mrp_flow.py
index 03b80862c9a..ddb89fa0133 100644
--- a/addons/purchase_mrp/tests/test_purchase_mrp_flow.py
+++ b/addons/purchase_mrp/tests/test_purchase_mrp_flow.py
@@ -179,7 +179,8 @@ class TestPurchaseMrpFlow(TransactionCase):
"""
moves_to_process = moves.filtered(lambda m: m.product_id in quantities_to_process.keys())
for move in moves_to_process:
- move.write({'quantity_done': quantities_to_process[move.product_id]})
+ move.quantity = quantities_to_process[move.product_id]
+ move.picked = True
def _assert_quantities(self, moves, quantities_to_process):
""" Helper to check expected quantities based on a dict following this structure :
@@ -214,7 +215,7 @@ class TestPurchaseMrpFlow(TransactionCase):
move._action_confirm()
move._action_assign()
move_line = move.move_line_ids[0]
- move_line.qty_done = qty_to_process[comp][0]
+ move_line.quantity = qty_to_process[comp][0]
move._action_done()
def test_kit_component_cost(self):
@@ -232,7 +233,6 @@ class TestPurchaseMrpFlow(TransactionCase):
line.price_unit = 1260
po = po.save()
po.button_confirm()
- po.picking_ids.action_set_quantities_to_reservation()
po.picking_ids.button_validate()
# Unit price equaly dived among bom lines (cost share not set)
@@ -285,7 +285,6 @@ class TestPurchaseMrpFlow(TransactionCase):
po = po.save()
po.button_confirm()
- po.picking_ids.action_set_quantities_to_reservation()
po.picking_ids.button_validate()
layer = po.picking_ids.move_ids.stock_valuation_layer_ids
@@ -349,7 +348,7 @@ class TestPurchaseMrpFlow(TransactionCase):
# Process only 7 units of each component
qty_to_process = 7
- move_ids.write({'quantity_done': qty_to_process})
+ move_ids.write({'quantity': qty_to_process, 'picked': True})
# Create a backorder for the missing componenents
pick = po.picking_ids[0]
@@ -456,9 +455,7 @@ class TestPurchaseMrpFlow(TransactionCase):
return_pick = self.env['stock.picking'].browse(res['res_id'])
# Process all components and validate the picking
- wiz_act = return_pick.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ return_pick.button_validate()
# Now quantity received should be 3 again
self.assertEqual(order_line.qty_received, 3)
@@ -475,7 +472,7 @@ class TestPurchaseMrpFlow(TransactionCase):
# Process all components except one of each
for move in return_of_return_pick.move_ids:
move.write({
- 'quantity_done': expected_quantities[move.product_id] - 1,
+ 'quantity': expected_quantities[move.product_id] - 1,
'to_refund': True
})
diff --git a/addons/purchase_requisition_stock/tests/test_purchase_requisition_stock.py b/addons/purchase_requisition_stock/tests/test_purchase_requisition_stock.py
index 57d360ad465..8e08c5cc4ad 100644
--- a/addons/purchase_requisition_stock/tests/test_purchase_requisition_stock.py
+++ b/addons/purchase_requisition_stock/tests/test_purchase_requisition_stock.py
@@ -283,7 +283,7 @@ class TestPurchaseRequisitionStock(TestPurchaseRequisitionCommon):
self.env['procurement.group'].run_scheduler()
# Find the internal move (Input -> Stock) that has been generated
int_move = self.env['stock.move'].search([('product_id', '=', product.id)])
- self.assertEqual(int_move.reserved_availability, 0, "No product should be available, as no products were received at this point.")
+ self.assertEqual(int_move.quantity, 0, "No product should be available, as no products were received at this point.")
# Find the Purchase Order generated by the orderpoint
orig_po = self.env['purchase.order'].search([('partner_id', '=', vendor_1.id)])
self.assertEqual(len(orig_po.ids), 1, "Only one PO should have been generated.")
@@ -308,8 +308,9 @@ class TestPurchaseRequisitionStock(TestPurchaseRequisitionCommon):
# Set all qty as done and validate the alternative PO's picking
in_picking = alt_po.picking_ids
self.assertEqual(in_picking.picking_type_id.code, 'incoming', "Must be the reception picking.")
- in_picking.move_ids.quantity_done = 10
+ in_picking.move_ids.quantity = 10
+ in_picking.move_ids.picked = True
in_picking.button_validate()
# Quantity should be reserved in the internal transfer's move
- self.assertEqual(int_move.reserved_availability, 10, "Quantity should be reserved in the original internal move.")
+ self.assertEqual(int_move.quantity, 10, "Quantity should be reserved in the original internal move.")
self.assertEqual(int_move.move_orig_ids.id, in_picking.move_ids.id, "Both moves should be correctly chained together.")
diff --git a/addons/purchase_stock/models/purchase.py b/addons/purchase_stock/models/purchase.py
index c49d0e1eb75..8f425d09516 100644
--- a/addons/purchase_stock/models/purchase.py
+++ b/addons/purchase_stock/models/purchase.py
@@ -223,8 +223,6 @@ class PurchaseOrder(models.Model):
'location_dest_id': self._get_destination_location(),
'location_id': self.partner_id.property_stock_supplier.id,
'company_id': self.company_id.id,
- 'state': 'draft',
- 'immediate_transfer': False,
}
def _create_picking(self):
@@ -339,7 +337,7 @@ class PurchaseOrderLine(models.Model):
if move.state == 'done':
if move._is_purchase_return():
if move.to_refund:
- total -= move.product_uom._compute_quantity(move.quantity_done, line.product_uom, rounding_method='HALF-UP')
+ total -= move.product_uom._compute_quantity(move.quantity, line.product_uom, rounding_method='HALF-UP')
elif move.origin_returned_move_id and move.origin_returned_move_id._is_dropshipped() and not move._is_dropshipped_returned():
# Edge case: the dropship is returned to the stock, no to the supplier.
# In this case, the received quantity on the PO is set although we didn't
@@ -349,7 +347,7 @@ class PurchaseOrderLine(models.Model):
elif move.origin_returned_move_id and move.origin_returned_move_id._is_purchase_return() and not move.to_refund:
pass
else:
- total += move.product_uom._compute_quantity(move.quantity_done, line.product_uom, rounding_method='HALF-UP')
+ total += move.product_uom._compute_quantity(move.quantity, line.product_uom, rounding_method='HALF-UP')
line._track_qty_received(total)
line.qty_received = total
@@ -523,10 +521,10 @@ class PurchaseOrderLine(models.Model):
qty = 0.0
outgoing_moves, incoming_moves = self._get_outgoing_incoming_moves()
for move in outgoing_moves:
- qty_to_compute = move.quantity_done if move.state == 'done' else move.product_uom_qty
+ qty_to_compute = move.quantity if move.state == 'done' else move.product_uom_qty
qty -= move.product_uom._compute_quantity(qty_to_compute, self.product_uom, rounding_method='HALF-UP')
for move in incoming_moves:
- qty_to_compute = move.quantity_done if move.state == 'done' else move.product_uom_qty
+ qty_to_compute = move.quantity if move.state == 'done' else move.product_uom_qty
qty += move.product_uom._compute_quantity(qty_to_compute, self.product_uom, rounding_method='HALF-UP')
return qty
diff --git a/addons/purchase_stock/models/res_partner.py b/addons/purchase_stock/models/res_partner.py
index dacce687f4a..80f4bec4fd0 100644
--- a/addons/purchase_stock/models/res_partner.py
+++ b/addons/purchase_stock/models/res_partner.py
@@ -26,7 +26,7 @@ class ResPartner(models.Model):
('order_id.state', 'in', ['done', 'purchase']),
('product_id', 'in', self.env['product.product'].sudo()._search([('type', '!=', 'service')]))
])
- lines_qty_done = defaultdict(lambda: 0)
+ lines_quantity = defaultdict(lambda: 0)
moves = self.env['stock.move'].search([
('purchase_line_id', 'in', order_lines.ids),
('state', '=', 'done')])
@@ -34,13 +34,13 @@ class ResPartner(models.Model):
order_lines.read(['date_planned', 'partner_id', 'product_uom_qty'], load='')
moves.read(['purchase_line_id', 'date'], load='')
moves = moves.filtered(lambda m: m.date.date() <= m.purchase_line_id.date_planned.date())
- for move, qty_done in zip(moves, moves.mapped('quantity_done')):
- lines_qty_done[move.purchase_line_id.id] += qty_done
+ for move, quantity in zip(moves, moves.mapped('quantity')):
+ lines_quantity[move.purchase_line_id.id] += quantity
partner_dict = {}
for line in order_lines:
on_time, ordered = partner_dict.get(line.partner_id, (0, 0))
ordered += line.product_uom_qty
- on_time += lines_qty_done[line.id]
+ on_time += lines_quantity[line.id]
partner_dict[line.partner_id] = (on_time, ordered)
seen_partner = self.env['res.partner']
for partner, numbers in partner_dict.items():
diff --git a/addons/purchase_stock/models/stock_move.py b/addons/purchase_stock/models/stock_move.py
index 46b0d9a22af..8293f04642f 100644
--- a/addons/purchase_stock/models/stock_move.py
+++ b/addons/purchase_stock/models/stock_move.py
@@ -46,7 +46,7 @@ class StockMove(models.Model):
order = line.order_id
received_qty = line.qty_received
if self.state == 'done':
- received_qty -= self.product_uom._compute_quantity(self.quantity_done, line.product_uom, rounding_method='HALF-UP')
+ received_qty -= self.product_uom._compute_quantity(self.quantity, line.product_uom, rounding_method='HALF-UP')
if float_compare(line.qty_invoiced, received_qty, precision_rounding=line.product_uom.rounding) > 0:
move_layer = line.move_ids.sudo().stock_valuation_layer_ids
invoiced_layer = line.sudo().invoice_lines.stock_valuation_layer_ids
diff --git a/addons/purchase_stock/report/vendor_delay_report.py b/addons/purchase_stock/report/vendor_delay_report.py
index ea43727cecd..2121f833421 100644
--- a/addons/purchase_stock/report/vendor_delay_report.py
+++ b/addons/purchase_stock/report/vendor_delay_report.py
@@ -30,7 +30,7 @@ SELECT m.id AS id,
Min(po.partner_id) AS partner_id,
Min(m.product_qty) AS qty_total,
Sum(CASE
- WHEN (m.state = 'done' and pol.date_planned::date >= m.date::date) THEN (ml.qty_done / ml_uom.factor * pt_uom.factor)
+ WHEN (m.state = 'done' and pol.date_planned::date >= m.date::date) THEN (ml.quantity / ml_uom.factor * pt_uom.factor)
ELSE 0
END) AS qty_on_time
FROM stock_move m
diff --git a/addons/purchase_stock/tests/test_anglo_saxon_valuation_reconciliation.py b/addons/purchase_stock/tests/test_anglo_saxon_valuation_reconciliation.py
index 0e24f3544ee..be3b2e513e2 100644
--- a/addons/purchase_stock/tests/test_anglo_saxon_valuation_reconciliation.py
+++ b/addons/purchase_stock/tests/test_anglo_saxon_valuation_reconciliation.py
@@ -100,7 +100,8 @@ class TestValuationReconciliation(ValuationReconciliationTestCommon):
stock_return_picking_action = stock_return_picking.create_returns()
return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
return_pick.action_assign()
- return_pick.move_ids.quantity_done = 1
+ return_pick.move_ids.quantity = 1
+ return_pick.move_ids.picked = True
return_pick._action_done()
# Refund the invoice
diff --git a/addons/purchase_stock/tests/test_average_price.py b/addons/purchase_stock/tests/test_average_price.py
index 27f1301b36e..35a02ae374c 100644
--- a/addons/purchase_stock/tests/test_average_price.py
+++ b/addons/purchase_stock/tests/test_average_price.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.stock_account.tests.test_anglo_saxon_valuation_reconciliation_common import ValuationReconciliationTestCommon
-from odoo.tests import tagged, Form
+from odoo.tests import tagged
import time
@@ -52,8 +52,7 @@ class TestAveragePrice(ValuationReconciliationTestCommon):
# Process the reception of purchase order 1
picking = purchase_order_1.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
# Check the average_price of the product (average icecream).
self.assertEqual(product_cable_management_box.qty_available, 10.0, 'Wrong quantity in stock after first reception')
@@ -76,8 +75,7 @@ class TestAveragePrice(ValuationReconciliationTestCommon):
purchase_order_2.button_confirm()
# Process the reception of purchase order 2
picking = purchase_order_2.picking_ids[0]
- res = picking.button_validate()
- Form(self.env['stock.immediate.transfer'].with_context(res['context'])).save().process()
+ picking.button_validate()
# Check the standard price
self.assertEqual(product_cable_management_box.standard_price, 75.0, 'After second reception, we should have an average price of 75.0 on the product')
@@ -97,10 +95,8 @@ class TestAveragePrice(ValuationReconciliationTestCommon):
})
# Assign this outgoing shipment and process the delivery
- outgoing_shipment.action_reset_draft()
outgoing_shipment.action_assign()
- res = outgoing_shipment.button_validate()
- Form(self.env['stock.immediate.transfer'].with_context(res['context'])).save().process()
+ outgoing_shipment.button_validate()
# Check the average price (60 * 10 + 30 * 80) / 40 = 75.0€ did not change
self.assertEqual(product_cable_management_box.standard_price, 75.0, 'Average price should not have changed with outgoing picking!')
@@ -124,8 +120,7 @@ class TestAveragePrice(ValuationReconciliationTestCommon):
# Process the reception of purchase order 3 in grams
picking = purchase_order_3.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
# Check price is (75.0 * 20 + 200*0.5) / 20.5 = 78.04878€
self.assertEqual(product_cable_management_box.qty_available, 20.5, 'Reception of purchase order in grams leads to wrong quantity in stock')
@@ -163,7 +158,7 @@ class TestAveragePrice(ValuationReconciliationTestCommon):
self.assertEqual(purchase_order.order_line[0].qty_invoiced, 1.0, 'QTY invoiced should have been set to 1 on the purchase order line')
picking = purchase_order.picking_ids[0]
- picking.action_set_quantities_to_reservation()
+ picking.move_ids.picked = True
# clear cash to ensure access rights verification
self.env.invalidate_all()
picking.with_user(self.res_users_stock_user).button_validate()
diff --git a/addons/purchase_stock/tests/test_create_picking.py b/addons/purchase_stock/tests/test_create_picking.py
index 725ec7651a4..8be2042b021 100644
--- a/addons/purchase_stock/tests/test_create_picking.py
+++ b/addons/purchase_stock/tests/test_create_picking.py
@@ -55,8 +55,7 @@ class TestCreatePicking(common.TestProductCommon):
# Validate first shipment
self.picking = self.po.picking_ids[0]
- for ml in self.picking.move_line_ids:
- ml.qty_done = ml.reserved_uom_qty
+ self.picking.move_ids.picked = True
self.picking._action_done()
self.assertEqual(self.po.order_line.mapped('qty_received'), [7.0], 'Purchase: all products should be received')
@@ -169,7 +168,8 @@ class TestCreatePicking(common.TestProductCommon):
# Process pickings
picking.action_confirm()
- picking.move_ids.quantity_done = 100.0
+ picking.move_ids.quantity = 100.0
+ picking.move_ids.picked = True
picking.button_validate()
# mts move will be automatically assigned
@@ -219,8 +219,11 @@ class TestCreatePicking(common.TestProductCommon):
self.assertEqual(move2.product_qty, 12)
# deliver everything
- move1.quantity_done = 24
- move2.quantity_done = 1
+ move1.quantity = 24
+ move1.picked = True
+ move2.quantity = 1
+ move2.picked = True
+
po.picking_ids.button_validate()
# check the delivered quantity
@@ -273,7 +276,6 @@ class TestCreatePicking(common.TestProductCommon):
'procure_method': 'make_to_order',
'picking_id': customer_picking.id,
})
- customer_picking.action_reset_draft()
customer_picking.action_confirm()
purchase_order = self.env['purchase.order'].search([('partner_id', '=', partner.id)])
@@ -308,13 +310,15 @@ class TestCreatePicking(common.TestProductCommon):
purchase_order_2.button_confirm()
- purchase_order.picking_ids.move_ids.quantity_done = 80.0
+ purchase_order.picking_ids.move_ids.quantity = 80.0
+ purchase_order.picking_ids.move_ids.picked = True
purchase_order.picking_ids.button_validate()
- purchase_order_2.picking_ids.move_ids.quantity_done = 20.0
+ purchase_order_2.picking_ids.move_ids.quantity = 20.0
+ purchase_order_2.picking_ids.move_ids.picked = True
purchase_order_2.picking_ids.button_validate()
- self.assertEqual(sum(customer_picking.move_ids.mapped('reserved_availability')), 100.0, 'The total quantity for the customer move should be available and reserved.')
+ self.assertEqual(sum(customer_picking.move_ids.mapped('quantity')), 100.0, 'The total quantity for the customer move should be available and reserved.')
def test_04_rounding(self):
""" We set the Unit(s) rounding to 1.0 and ensure buying 1.2 units in a PO is rounded to 1.0
@@ -342,7 +346,8 @@ class TestCreatePicking(common.TestProductCommon):
self.assertEqual(move1.product_qty, 2.0)
# deliver everything
- move1.quantity_done = 2.0
+ move1.quantity = 2.0
+ move1.picked = True
po.picking_ids.button_validate()
# check the delivered quantity
@@ -420,7 +425,6 @@ class TestCreatePicking(common.TestProductCommon):
'picking_id': delivery_order.id,
})
- delivery_order.action_reset_draft()
delivery_order.action_confirm()
# find created po the product
purchase_order = self.env['purchase.order'].search([('partner_id', '=', partner.id)])
@@ -471,7 +475,8 @@ class TestCreatePicking(common.TestProductCommon):
po.button_approve()
po.picking_ids.move_line_ids.write({
- 'qty_done': 1.0
+ 'quantity': 1.0,
+ 'picked': True
})
po.picking_ids.button_validate()
@@ -486,7 +491,8 @@ class TestCreatePicking(common.TestProductCommon):
po.button_confirm()
first_picking = po.picking_ids
- first_picking.move_ids.quantity_done = 5
+ first_picking.move_ids.quantity = 5
+ first_picking.move_ids.picked = True
# create the backorder
backorder_wizard_dict = first_picking.button_validate()
backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
@@ -507,7 +513,8 @@ class TestCreatePicking(common.TestProductCommon):
stock_return_picking_action = stock_return_picking.create_returns()
return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
return_pick.action_assign()
- return_pick.move_ids.quantity_done = 2
+ return_pick.move_ids.quantity = 2
+ return_pick.move_ids.picked = True
return_pick._action_done()
self.assertEqual(po.order_line.qty_received, 3)
@@ -672,12 +679,13 @@ class TestCreatePicking(common.TestProductCommon):
line.product_qty = 10
po = po_form.save()
po.button_approve()
-
first_picking = po.picking_ids
- first_picking.move_ids.quantity_done = 10
+ first_picking.move_ids.quantity = 10
+ first_picking.move_ids.picked = True
first_picking.button_validate()
second_picking = first_picking.move_ids.move_dest_ids.picking_id
- second_picking.move_ids.quantity_done = 10
+ second_picking.move_ids.quantity = 10
+ second_picking.move_ids.picked = True
second_picking.button_validate()
self.assertEqual(po.order_line.qty_received, 10)
@@ -695,11 +703,13 @@ class TestCreatePicking(common.TestProductCommon):
stock_return_picking_action = stock_return_picking.create_returns()
return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
return_pick.action_assign()
- return_pick.move_ids.quantity_done = 2
+ return_pick.move_ids.quantity = 2
+ return_pick.move_ids.picked = True
return_pick._action_done()
push_pick = return_pick.move_ids.move_dest_ids.picking_id
push_pick.action_assign()
- push_pick.move_ids.quantity_done = 2
+ push_pick.move_ids.quantity = 2
+ push_pick.move_ids.picked = True
push_pick._action_done()
self.assertEqual(po.order_line.qty_received, 8)
diff --git a/addons/purchase_stock/tests/test_fifo_price.py b/addons/purchase_stock/tests/test_fifo_price.py
index 58a918ad08e..abe63cc4e96 100644
--- a/addons/purchase_stock/tests/test_fifo_price.py
+++ b/addons/purchase_stock/tests/test_fifo_price.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.stock_account.tests.test_anglo_saxon_valuation_reconciliation_common import ValuationReconciliationTestCommon
-from odoo.tests import tagged, Form
+from odoo.tests import tagged
import time
@@ -50,8 +50,7 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
# Process the reception of purchase order 1 and set date
picking = purchase_order_1.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
# Check the standard price of the product (fifo icecream), that should have changed
# because the unit cost of the purchase order is 50
@@ -75,8 +74,7 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
# Process the reception of purchase order 2
picking = purchase_order_2.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
# Check the standard price of the product, that should have not changed because we
# still have icecream in stock
@@ -99,12 +97,10 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
})
# I assign this outgoing shipment
- outgoing_shipment.action_reset_draft()
outgoing_shipment.action_assign()
# Process the delivery of the outgoing shipment
- res = outgoing_shipment.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ outgoing_shipment.button_validate()
# Check stock value became 1600 .
self.assertEqual(product_cable_management_box.value_svl, 1600.0, 'Stock valuation should be 1600')
@@ -125,12 +121,10 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
})
# I assign this outgoing shipment
- outgoing_shipment_uom.action_reset_draft()
outgoing_shipment_uom.action_assign()
# Process the delivery of the outgoing shipment
- res = outgoing_shipment_uom.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ outgoing_shipment_uom.button_validate()
# Check stock valuation and qty in stock
self.assertEqual(product_cable_management_box.value_svl, 1560.0, 'Stock valuation should be 1560')
@@ -167,8 +161,7 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
purchase_order_usd.button_confirm()
# Process the reception of purchase order with USD
picking = purchase_order_usd.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
# Create delivery order of 49.5 kg
outgoing_shipment_cur = self.env['stock.picking'].create({
@@ -186,12 +179,10 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
})
# I assign this outgoing shipment
- outgoing_shipment_cur.action_reset_draft()
outgoing_shipment_cur.action_assign()
# Process the delivery of the outgoing shipment
- res = outgoing_shipment_cur.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ outgoing_shipment_cur.button_validate()
# Do a delivery of an extra 10 kg
outgoing_shipment_ret = self.env['stock.picking'].create({
@@ -209,10 +200,8 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
})
# I assign this outgoing shipment
- outgoing_shipment_ret.action_reset_draft()
outgoing_shipment_ret.action_assign()
- res = outgoing_shipment_ret.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ outgoing_shipment_ret.button_validate()
# Check rounded price is 150.0 / 1.2834
self.assertEqual(round(product_cable_management_box.qty_available), 0.0, 'Wrong quantity in stock after first reception.')
@@ -248,7 +237,8 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
# Process the delivery of the first outgoing shipment
outgoing_shipment_neg.action_confirm()
- outgoing_shipment_neg.move_ids[0].quantity_done = 100.0
+ outgoing_shipment_neg.move_ids[0].quantity = 100.0
+ outgoing_shipment_neg.move_ids[0].picked = True
outgoing_shipment_neg._action_done()
# Check qty available = -100
@@ -274,7 +264,8 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
# Process the delivery of the outgoing shipments
outgoing_shipment_neg2.action_confirm()
- outgoing_shipment_neg2.move_ids[0].quantity_done = 400.0
+ outgoing_shipment_neg2.move_ids[0].quantity = 400.0
+ outgoing_shipment_neg2.move_ids[0].picked = True
outgoing_shipment_neg2._action_done()
# Check qty available = -500
@@ -297,8 +288,7 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
# Process the reception of purchase order neg
picking = purchase_order_neg.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
# Receive purchase order with 600 kg FIFO Ice Cream at 80 euro/kg
purchase_order_neg2 = self.env['purchase.order'].create({
@@ -317,8 +307,7 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
# Process the reception of purchase order neg2
picking = purchase_order_neg2.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
original_out_move = outgoing_shipment_neg.move_ids[0]
self.assertEqual(original_out_move.product_id.value_svl, 12000.0, 'Value of the move should be 12000')
@@ -362,8 +351,7 @@ class TestFifoPrice(ValuationReconciliationTestCommon):
self.assertEqual(purchase_order.state, 'purchase')
picking = purchase_order.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
self.assertEqual(super_product.standard_price, 0.035)
self.assertEqual(super_product.value_svl, 35.0)
diff --git a/addons/purchase_stock/tests/test_fifo_returns.py b/addons/purchase_stock/tests/test_fifo_returns.py
index dd2ca8c8ce5..13005c139cc 100644
--- a/addons/purchase_stock/tests/test_fifo_returns.py
+++ b/addons/purchase_stock/tests/test_fifo_returns.py
@@ -58,8 +58,7 @@ class TestFifoReturns(ValuationReconciliationTestCommon):
# Process the reception of purchase order 1
picking = purchase_order_1.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
# Check the standard price of the product (fifo icecream)
self.assertAlmostEqual(product_fiforet_icecream.standard_price, 50)
@@ -67,8 +66,7 @@ class TestFifoReturns(ValuationReconciliationTestCommon):
# Confirm the second purchase order
purchase_order_2.button_confirm()
picking = purchase_order_2.picking_ids[0]
- res = picking.button_validate()
- Form(self.env[res['res_model']].with_context(res['context'])).save().process()
+ picking.button_validate()
# Return the goods of purchase order 2
picking = purchase_order_2.picking_ids[0]
@@ -81,7 +79,8 @@ class TestFifoReturns(ValuationReconciliationTestCommon):
# Important to pass through confirmation and assignation
return_picking = self.env['stock.picking'].browse(return_picking_id)
return_picking.action_confirm()
- return_picking.move_ids[0].quantity_done = return_picking.move_ids[0].product_uom_qty
+ return_picking.move_ids[0].quantity = return_picking.move_ids[0].product_uom_qty
+ return_picking.move_ids[0].picked = True
return_picking._action_done()
# After the return only 10 of the second purchase order should still be in stock as it applies fifo on the return too
diff --git a/addons/purchase_stock/tests/test_move_cancel_propagation.py b/addons/purchase_stock/tests/test_move_cancel_propagation.py
index 8ef2964f873..8fb48eda7c3 100644
--- a/addons/purchase_stock/tests/test_move_cancel_propagation.py
+++ b/addons/purchase_stock/tests/test_move_cancel_propagation.py
@@ -52,7 +52,6 @@ class TestMoveCancelPropagation(PurchaseTestCommon):
self.warehouse.write({'delivery_steps': 'ship_only', 'reception_steps': 'one_step'})
self.picking_out.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
self.move.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
- self.picking_out.action_reset_draft()
self.picking_out.action_confirm()
# Find PO related to picking.
@@ -82,7 +81,6 @@ class TestMoveCancelPropagation(PurchaseTestCommon):
self.warehouse.write({'delivery_steps': 'ship_only', 'reception_steps': 'one_step'})
self.picking_out.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
self.move.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
- self.picking_out.action_reset_draft()
self.picking_out.action_confirm()
# Find PO related to picking.
@@ -113,7 +111,6 @@ class TestMoveCancelPropagation(PurchaseTestCommon):
self.warehouse.write({'delivery_steps': 'pick_ship', 'reception_steps': 'two_steps'})
self.picking_out.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
self.move.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
- self.picking_out.action_reset_draft()
self.picking_out.action_confirm()
# Find purchase order related to picking.
@@ -148,7 +145,6 @@ class TestMoveCancelPropagation(PurchaseTestCommon):
self.warehouse.write({'delivery_steps': 'pick_ship', 'reception_steps': 'two_steps'})
self.picking_out.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
self.move.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
- self.picking_out.action_reset_draft()
self.picking_out.action_confirm()
# Find PO related to picking.
@@ -187,7 +183,6 @@ class TestMoveCancelPropagation(PurchaseTestCommon):
self.warehouse.write({'delivery_steps': 'pick_pack_ship', 'reception_steps': 'three_steps'})
self.picking_out.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
self.move.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
- self.picking_out.action_reset_draft()
self.picking_out.action_confirm()
# Find PO related to picking.
@@ -224,7 +219,6 @@ class TestMoveCancelPropagation(PurchaseTestCommon):
self.warehouse.write({'delivery_steps': 'pick_pack_ship', 'reception_steps': 'three_steps'})
self.picking_out.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
self.move.write({'location_id': self.warehouse.out_type_id.default_location_src_id.id})
- self.picking_out.action_reset_draft()
self.picking_out.action_confirm()
# Find PO related to picking.
diff --git a/addons/purchase_stock/tests/test_purchase_order.py b/addons/purchase_stock/tests/test_purchase_order.py
index b5f59727dff..9e261968bcf 100644
--- a/addons/purchase_stock/tests/test_purchase_order.py
+++ b/addons/purchase_stock/tests/test_purchase_order.py
@@ -71,7 +71,8 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
self.assertEqual(self.po.incoming_picking_count, 1, 'Purchase: one picking should be created"')
self.picking = self.po.picking_ids[0]
- self.picking.move_line_ids.write({'qty_done': 5.0})
+ self.picking.move_line_ids.write({'quantity': 5.0})
+ self.picking.move_ids.picked = True
self.picking.button_validate()
self.assertEqual(self.po.order_line.mapped('qty_received'), [5.0, 5.0], 'Purchase: all products should be received"')
@@ -102,7 +103,8 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
self.assertEqual(self.po.state, 'purchase', 'Purchase: PO state should be "Purchase')
self.assertEqual(self.po.incoming_picking_count, 1, 'Purchase: one picking should be created"')
self.picking = self.po.picking_ids[0]
- self.picking.move_line_ids.write({'qty_done': 5.0})
+ self.picking.move_line_ids.write({'quantity': 5.0})
+ self.picking.move_ids.picked = True
self.picking.button_validate()
self.assertEqual(self.po.order_line.mapped('qty_received'), [5.0, 5.0], 'Purchase: all products should be received"')
@@ -131,8 +133,8 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
return_pick = self.env['stock.picking'].browse(res['res_id'])
# Validate picking
- return_pick.move_line_ids.write({'qty_done': 2})
-
+ return_pick.move_line_ids.write({'quantity': 2})
+ return_pick.move_ids.picked = True
return_pick.button_validate()
# Check Received quantity
@@ -188,9 +190,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
po1.button_confirm()
picking = po1.picking_ids
- wiz_act = picking.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ picking.button_validate()
# Return 5 units
stock_return_picking_form = Form(self.env['stock.return.picking'].with_context(
@@ -206,9 +206,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
})
res = return_wiz.create_returns()
return_pick = self.env['stock.picking'].browse(res['res_id'])
- wiz_act = return_pick.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ return_pick.button_validate()
self.assertEqual(po1.order_line.qty_received, 5)
@@ -246,9 +244,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
)
# receive products
- wiz_act = po.picking_ids.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ po.picking_ids.button_validate()
# update second line
old_date = po.order_line[1].date_planned
@@ -300,12 +296,13 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
po.button_confirm()
picking = po.picking_ids[0]
# Process 9.0 out of the 10.0 ordered qty
- picking.move_line_ids.write({'qty_done': 9.0})
+ picking.move_line_ids.write({'quantity': 9.0})
+ picking.move_ids.picked = True
res_dict = picking.button_validate()
# No backorder
self.env['stock.backorder.confirmation'].with_context(res_dict['context']).process_cancel_backorder()
# `on_time_rate` should be equals to the ratio of quantity received against quantity ordered
- expected_rate = sum(picking.move_line_ids.mapped("qty_done")) / sum(po.order_line.mapped("product_qty")) * 100
+ expected_rate = sum(picking.move_line_ids.mapped("quantity")) / sum(po.order_line.mapped("product_qty")) * 100
self.assertEqual(expected_rate, po.on_time_rate)
# Create a purchase order with 80% qty received for company B
@@ -319,12 +316,13 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
po.button_confirm()
picking = po.picking_ids[0]
# Process 8.0 out of the 10.0 ordered qty
- picking.move_line_ids.write({'qty_done': 8.0})
+ picking.move_line_ids.write({'quantity': 8.0})
+ picking.move_ids.picked = True
res_dict = picking.button_validate()
# No backorder
self.env['stock.backorder.confirmation'].with_context(res_dict['context']).process_cancel_backorder()
# `on_time_rate` should be equal to the ratio of quantity received against quantity ordered
- expected_rate = sum(picking.move_line_ids.mapped("qty_done")) / sum(po.order_line.mapped("product_qty")) * 100
+ expected_rate = sum(picking.move_line_ids.mapped("quantity")) / sum(po.order_line.mapped("product_qty")) * 100
self.assertEqual(expected_rate, po.on_time_rate)
# Tricky corner case
@@ -372,7 +370,8 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
})
po.button_confirm()
picking = po.picking_ids[0]
- picking.move_line_ids.write({'qty_done': 3.66})
+ picking.move_line_ids.write({'quantity': 3.66})
+ picking.move_ids.picked = True
picking.button_validate()
self.assertEqual(po.order_line.mapped('qty_received'), [4.0], 'Purchase: no conversion error on receipt in different uom"')
@@ -413,7 +412,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
self.assertEqual(purchase_order.state, 'purchase')
self.assertEqual(len(purchase_order.picking_ids), 1)
self.assertEqual(len(purchase_order.picking_ids.move_line_ids), 1)
- self.assertEqual(purchase_order.picking_ids.move_line_ids.reserved_qty, 7)
+ self.assertEqual(purchase_order.picking_ids.move_line_ids.quantity, 7)
purchase_order.order_line.product_qty = 4
@@ -422,7 +421,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
purchase_order.button_confirm()
self.assertEqual(len(purchase_order.picking_ids), 1)
self.assertEqual(len(purchase_order.picking_ids.move_line_ids), 1)
- self.assertEqual(purchase_order.picking_ids.move_line_ids.reserved_qty, 4)
+ self.assertEqual(purchase_order.picking_ids.move_line_ids.quantity, 4)
def test_message_qty_already_received(self):
self.env.user.write({'company_id': self.company_data['company'].id})
@@ -441,19 +440,19 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
_purchase_order.button_confirm()
first_picking = _purchase_order.picking_ids[0]
- first_picking.move_ids.quantity_done = 5
+ first_picking.move_ids.quantity = 5
backorder_wizard_dict = first_picking.button_validate()
backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
backorder_wizard.process()
second_picking = _purchase_order.picking_ids[1]
- second_picking.move_ids.quantity_done = 5
+ second_picking.move_ids.quantity = 5
backorder_wizard_dict = second_picking.button_validate()
backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
backorder_wizard.process()
third_picking = _purchase_order.picking_ids[2]
- third_picking.move_ids.quantity_done = 5
+ third_picking.move_ids.quantity = 5
backorder_wizard_dict = third_picking.button_validate()
backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
backorder_wizard.process()
@@ -604,7 +603,8 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
picking = po.picking_ids
self.assertEqual(po.state, "purchase")
self.assertEqual(picking.move_line_ids_without_package.location_dest_id.id, sub_loc_01.id)
- picking.move_line_ids_without_package.write({'qty_done': 1})
+ picking.move_line_ids_without_package.write({'quantity': 1})
+ picking.move_ids.write({'picked': True})
res_dict = picking.button_validate()
self.env[res_dict['res_model']].with_context(res_dict['context']).process()
backorder = picking.backorder_ids
@@ -623,7 +623,8 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
line.product_qty = 5
po = po_form.save()
po.button_confirm()
- po.picking_ids.move_ids.quantity_done = 5
+ po.picking_ids.move_ids.quantity = 5
+ po.picking_ids.move_ids.picked = True
po.picking_ids.button_validate()
self.assertEqual(po.picking_ids.state, 'done')
quant = self.env['stock.quant'].search([('product_id', '=', product.id), ('location_id.usage', '=', 'internal')])
@@ -632,34 +633,14 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
self.assertEqual(quant.quantity, 5)
def test_po_edit_after_receive(self):
- po_1 = self.env['purchase.order'].create(self.po_vals)
- po_1.button_confirm()
- po_1.picking_ids.move_ids.quantity_done = 5
- po_1.picking_ids.button_validate()
- self.assertEqual(po_1.picking_ids.move_ids.mapped('product_uom_qty'), [5.0, 5.0])
- po_1.with_context(import_file=True).order_line[0].product_qty = 10
- self.assertEqual(po_1.picking_ids.move_ids.mapped('product_uom_qty'), [5.0, 5.0, 5.0])
-
- ### Without backorder ###
- po_2 = self.env['purchase.order'].create(self.po_vals)
- po_2.button_confirm()
- self.assertEqual(len(po_2.picking_ids), 1)
-
- receipt_picking = po_2.picking_ids
- receipt_picking.move_ids.quantity_done = 2
- backorder_wizard_dict = receipt_picking.button_validate()
- backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
- backorder_wizard.process_cancel_backorder()
- self.assertEqual(po_2.order_line.mapped('product_uom_qty'), [5.0, 5.0])
- self.assertEqual(po_2.order_line.mapped('qty_received'), [2.0, 2.0])
-
- po_2.write({
- 'order_line': [
- (1, po_2.order_line[0].id, {'product_qty': 2}),
- (1, po_2.order_line[1].id, {'product_qty': 2})
- ]
- })
- self.assertEqual(len(po_2.picking_ids), 1)
+ self.po = self.env['purchase.order'].create(self.po_vals)
+ self.po.button_confirm()
+ self.po.picking_ids.move_ids.quantity = 5
+ self.po.picking_ids.move_ids.picked = True
+ self.po.picking_ids.button_validate()
+ self.assertEqual(self.po.picking_ids.move_ids.mapped('product_uom_qty'), [5.0, 5.0])
+ self.po.with_context(import_file=True).order_line[0].product_qty = 10
+ self.assertEqual(self.po.picking_ids.move_ids.mapped('product_uom_qty'), [5.0, 5.0, 5.0])
def test_receive_returned_product_without_po_update(self):
"""
@@ -670,7 +651,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
po.button_confirm()
receipt01 = po.picking_ids
- receipt01.move_ids.quantity_done = 5
+ receipt01.move_ids.quantity = 5
receipt01.button_validate()
wizard = Form(self.env['stock.return.picking'].with_context(active_ids=receipt01.ids, active_id=receipt01.id, active_model='stock.picking')).save()
@@ -678,7 +659,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
res = wizard.create_returns()
return_pick = self.env['stock.picking'].browse(res['res_id'])
- return_pick.move_ids.quantity_done = 5
+ return_pick.move_ids.quantity = 5
return_pick.button_validate()
wizard = Form(self.env['stock.return.picking'].with_context(active_ids=return_pick.ids, active_id=return_pick.id, active_model='stock.picking')).save()
@@ -686,7 +667,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
res = wizard.create_returns()
receipt02 = self.env['stock.picking'].browse(res['res_id'])
- receipt02.move_ids.quantity_done = 5
+ receipt02.move_ids.quantity = 5
receipt02.button_validate()
self.assertEqual(po.order_line[0].qty_received, 5)
diff --git a/addons/purchase_stock/tests/test_purchase_stock_accrued_entries.py b/addons/purchase_stock/tests/test_purchase_stock_accrued_entries.py
index 1f184ea4e9a..82e89ad83c4 100644
--- a/addons/purchase_stock/tests/test_purchase_stock_accrued_entries.py
+++ b/addons/purchase_stock/tests/test_purchase_stock_accrued_entries.py
@@ -41,7 +41,10 @@ class TestAccruedPurchaseStock(AccountTestInvoicingCommon):
def test_purchase_stock_accruals(self):
# receive 2 on 2020-01-02
pick = self.purchase_order.picking_ids
- pick.move_ids.write({'quantity_done': 2})
+ pick.move_ids.write({
+ 'quantity': 2,
+ 'picked': True,
+ })
pick.button_validate()
wiz_act = pick.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
@@ -50,7 +53,7 @@ class TestAccruedPurchaseStock(AccountTestInvoicingCommon):
# receive 3 on 2020-01-06
pick = pick.copy()
- pick.move_ids.write({'quantity_done': 3})
+ pick.move_ids.write({'quantity': 3, 'picked': True})
wiz_act = pick.button_validate()
pick.move_ids.write({'date': fields.Date.to_date('2020-01-06')})
@@ -90,7 +93,7 @@ class TestAccruedPurchaseStock(AccountTestInvoicingCommon):
def test_purchase_stock_invoiced_accrued_entries(self):
# deliver 2 on 2020-01-02
pick = self.purchase_order.picking_ids
- pick.move_ids.write({'quantity_done': 2})
+ pick.move_ids.write({'quantity': 2, 'picked': True})
pick.button_validate()
wiz_act = pick.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
@@ -104,7 +107,7 @@ class TestAccruedPurchaseStock(AccountTestInvoicingCommon):
# deliver 3 on 2020-01-06
pick = pick.copy()
- pick.move_ids.write({'quantity_done': 3})
+ pick.move_ids.write({'quantity': 3, 'picked': True})
wiz_act = pick.button_validate()
pick.move_ids.write({'date': fields.Date.to_date('2020-01-06')})
diff --git a/addons/purchase_stock/tests/test_purchase_stock_report.py b/addons/purchase_stock/tests/test_purchase_stock_report.py
index 32948dea71e..f48187de770 100644
--- a/addons/purchase_stock/tests/test_purchase_stock_report.py
+++ b/addons/purchase_stock/tests/test_purchase_stock_report.py
@@ -43,9 +43,7 @@ class TestPurchaseStockReports(TestReportsCommon):
# Receives 5 products.
receipt = po.picking_ids
- res_dict = receipt.button_validate()
- wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save()
- wizard.process()
+ receipt.button_validate()
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
draft_picking_qty_in = docs['draft_picking_qty']['in']
draft_purchase_qty = docs['draft_purchase_qty']
@@ -118,9 +116,7 @@ class TestPurchaseStockReports(TestReportsCommon):
receipt = po.picking_ids
# Receives 4 products.
- res_dict = receipt.button_validate()
- wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save()
- wizard.process()
+ receipt.button_validate()
report_values, docs, lines = self.get_report_forecast(product_template_ids=self.product_template.ids)
draft_picking_qty_in = docs['draft_picking_qty']['in']
draft_purchase_qty = docs['draft_purchase_qty']
@@ -227,9 +223,10 @@ class TestPurchaseStockReports(TestReportsCommon):
'location_dest_id': receipt_move.location_dest_id.id,
'product_id': self.product.id,
'product_uom_id': uom_12.id,
- 'qty_done': 1,
+ 'quantity': 1,
'picking_id': receipt.id,
})]
+ receipt.move_ids.picked = True
receipt.button_validate()
data = self.env['vendor.delay.report'].read_group(
@@ -267,16 +264,17 @@ class TestPurchaseStockReports(TestReportsCommon):
'location_dest_id': child_loc_01.id,
'product_id': self.product.id,
'product_uom_id': self.product.uom_id.id,
- 'qty_done': 6,
+ 'quantity': 6,
'picking_id': receipt.id,
}), (0, 0, {
'location_id': receipt_move.location_id.id,
'location_dest_id': child_loc_02.id,
'product_id': self.product.id,
'product_uom_id': self.product.uom_id.id,
- 'qty_done': 4,
+ 'quantity': 4,
'picking_id': receipt.id,
})]
+ receipt.move_ids.picked = True
receipt.button_validate()
data = self.env['vendor.delay.report'].read_group(
@@ -306,7 +304,7 @@ class TestPurchaseStockReports(TestReportsCommon):
receipt01 = po.picking_ids
receipt01_move = receipt01.move_ids
- receipt01_move.quantity_done = 6
+ receipt01_move.quantity = 6
action = receipt01.button_validate()
Form(self.env[action['res_model']].with_context(action['context'])).save().process()
@@ -320,7 +318,8 @@ class TestPurchaseStockReports(TestReportsCommon):
self.assertEqual(data['on_time_rate'], 60)
receipt02 = receipt01.backorder_ids
- receipt02.move_ids.quantity_done = 4
+ receipt02.move_ids.quantity = 4
+ receipt02.move_ids.picked = True
receipt02.button_validate()
(receipt01 | receipt02).move_ids.invalidate_recordset()
@@ -349,7 +348,8 @@ class TestPurchaseStockReports(TestReportsCommon):
receipt01 = po.picking_ids
receipt01_move = receipt01.move_ids
- receipt01_move.quantity_done = 6
+ receipt01_move.quantity = 6
+ receipt01_move.picked = True
action = receipt01.button_validate()
Form(self.env[action['res_model']].with_context(action['context'])).save().process_cancel_backorder()
diff --git a/addons/purchase_stock/tests/test_reordering_rule.py b/addons/purchase_stock/tests/test_reordering_rule.py
index a6e7562419a..b901b775aaf 100644
--- a/addons/purchase_stock/tests/test_reordering_rule.py
+++ b/addons/purchase_stock/tests/test_reordering_rule.py
@@ -68,6 +68,7 @@ class TestReorderingRule(TransactionCase):
move.product_id = self.product_01
move.product_uom_qty = 10.0
customer_picking = picking_form.save()
+ customer_picking.action_confirm()
# Run scheduler
self.env['procurement.group'].run_scheduler()
@@ -150,6 +151,7 @@ class TestReorderingRule(TransactionCase):
customer_picking.move_ids[1].location_id = subloc_2.id
# picking confirm
+ customer_picking.action_confirm()
self.assertEqual(self.product_01.with_context(location=subloc_1.id).virtual_available, -10)
self.assertEqual(self.product_01.with_context(location=subloc_2.id).virtual_available, -10)
@@ -360,7 +362,6 @@ class TestReorderingRule(TransactionCase):
move.product_uom_qty = 10.0
customer_picking = picking_form.save()
customer_picking.move_ids.filtered(lambda m: m.product_id == product_buy_mto).procure_method = 'make_to_order'
- customer_picking.action_reset_draft()
customer_picking.action_confirm()
self.env['stock.warehouse.orderpoint']._get_orderpoint_action()
self.env['stock.warehouse.orderpoint']._get_orderpoint_action()
@@ -404,7 +405,6 @@ class TestReorderingRule(TransactionCase):
move.product_uom_qty = 10.0
customer_picking = picking_form.save()
customer_picking.move_ids.filtered(lambda m: m.product_id == product_buy_mto).procure_method = 'make_to_order'
- customer_picking.action_reset_draft()
customer_picking.action_confirm()
self.env['stock.warehouse.orderpoint'].flush_model()
@@ -460,7 +460,6 @@ class TestReorderingRule(TransactionCase):
move.product_uom_qty = 10.0
customer_picking = picking_form.save()
customer_picking.move_ids.filtered(lambda m: m.product_id == product_buy_mto).procure_method = 'make_to_order'
- customer_picking.action_reset_draft()
customer_picking.action_confirm()
self.env['stock.warehouse.orderpoint']._get_orderpoint_action()
orderpoint_product = self.env['stock.warehouse.orderpoint'].search(
@@ -503,7 +502,6 @@ class TestReorderingRule(TransactionCase):
move.product_uom_qty = 10.0
customer_picking = picking_form.save()
customer_picking.move_ids.filtered(lambda m: m.product_id == product_buy_mto).procure_method = 'make_to_order'
- customer_picking.action_reset_draft()
customer_picking.action_confirm()
self.env['stock.warehouse.orderpoint'].flush_model()
@@ -722,13 +720,11 @@ class TestReorderingRule(TransactionCase):
po.button_confirm()
picking = po.picking_ids
- action = picking.button_validate()
- wizard = Form(self.env[(action.get('res_model'))].with_context(action['context'])).save()
- wizard.process()
+ picking.button_validate()
self.assertRecordValues(picking.move_line_ids, [
- {'product_id': self.product_01.id, 'qty_done': 1.0, 'state': 'done', 'location_dest_id': stock_location.id},
- {'product_id': self.product_01.id, 'qty_done': 2.0, 'state': 'done', 'location_dest_id': sub_location.id},
+ {'product_id': self.product_01.id, 'quantity': 1.0, 'state': 'done', 'location_dest_id': stock_location.id},
+ {'product_id': self.product_01.id, 'quantity': 2.0, 'state': 'done', 'location_dest_id': sub_location.id},
])
def test_2steps_and_partner_on_orderpoint(self):
@@ -1020,9 +1016,7 @@ class TestReorderingRule(TransactionCase):
'location_dest_id': self.env.ref('stock.stock_location_customers').id,
})],
'state': 'draft',
- 'immediate_transfer': False,
})
- picking.with_user(user).action_reset_draft()
picking.with_user(user).action_assign()
# check that the PO line quantity has been updated
self.assertEqual(po_line.product_qty, 6, 'The PO line quantity should be 6')
diff --git a/addons/purchase_stock/tests/test_stockvaluation.py b/addons/purchase_stock/tests/test_stockvaluation.py
index a07bbbf534b..3cd859bfaad 100644
--- a/addons/purchase_stock/tests/test_stockvaluation.py
+++ b/addons/purchase_stock/tests/test_stockvaluation.py
@@ -127,7 +127,8 @@ class TestStockValuation(TransactionCase):
last_po_id.button_confirm()
picking = last_po_id.picking_ids[0]
move = picking.move_ids[0]
- move.quantity_done = move.product_uom_qty
+ move.quantity = move.product_uom_qty
+ move.picked = True
picking.button_validate()
self.assertEqual(move.stock_valuation_layer_ids.unit_cost,
@@ -166,9 +167,7 @@ class TestStockValuation(TransactionCase):
# validate the receipt
- res_dict = picking1.button_validate()
- wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
- wizard.process()
+ picking1.button_validate()
# the unit price of the valuationlayer used the latest value
self.assertEqual(move1.stock_valuation_layer_ids.unit_cost, 200)
@@ -214,9 +213,7 @@ class TestStockValuation(TransactionCase):
self.assertEqual(move1.price_unit, 11)
# validate the receipt
- res_dict = picking1.button_validate()
- wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
- wizard.process()
+ picking1.button_validate()
# the unit price of the valuation layer used the latest value
self.assertEqual(move1.stock_valuation_layer_ids.unit_cost, 12)
@@ -245,14 +242,16 @@ class TestStockValuation(TransactionCase):
picking1 = po1.picking_ids[0]
move1 = picking1.move_ids[0]
- move1.quantity_done = 15
+ move1.quantity = 15
+ move1.picked = True
picking1.button_validate()
# there should be only one move
self.assertEqual(len(picking1.move_ids), 1)
self.assertEqual(move1.price_unit, 100)
self.assertEqual(move1.stock_valuation_layer_ids.unit_cost, 100)
- self.assertEqual(move1.product_qty, 15)
+ self.assertEqual(move1.product_qty, 10)
+ self.assertEqual(move1.quantity, 15)
self.assertEqual(self.product1.value_svl, 1500)
def test_backorder_fifo_1(self):
@@ -277,7 +276,8 @@ class TestStockValuation(TransactionCase):
picking1 = po1.picking_ids[0]
move1 = picking1.move_ids[0]
- move1.quantity_done = 5
+ move1.quantity = 5
+ move1.picked = True
res_dict = picking1.button_validate()
self.assertEqual(res_dict['res_model'], 'stock.backorder.confirmation')
wizard = self.env[(res_dict.get('res_model'))].browse(res_dict.get('res_id')).with_context(res_dict['context'])
@@ -411,7 +411,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
wizard.product_return_moves.quantity = qty
action = wizard.create_returns()
return_picking = self.env["stock.picking"].browse(action["res_id"])
- return_picking.move_ids.move_line_ids.qty_done = qty
+ return_picking.move_ids.move_line_ids.quantity = qty
+ return_picking.move_ids.picked = True
return_picking.button_validate()
return return_picking
@@ -476,9 +477,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
self.assertAlmostEqual(move1.price_unit, price_unit_usd, places=2)
# validate the receipt
- res_dict = picking1.button_validate()
- wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
- wizard.process()
+ picking1.button_validate()
# the unit price of the valuation layer used the latest value
self.assertAlmostEqual(move1.stock_valuation_layer_ids.unit_cost, price_unit_usd_new_rate)
@@ -506,7 +505,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
})
po1.button_confirm()
receipt_po1 = po1.picking_ids[0]
- receipt_po1.move_ids.quantity_done = 10
+ receipt_po1.move_ids.quantity = 10
+ receipt_po1.move_ids.picked = True
receipt_po1.button_validate()
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
@@ -532,7 +532,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
})
po2.button_confirm()
receipt_po2 = po2.picking_ids[0]
- receipt_po2.move_ids.quantity_done = 10
+ receipt_po2.move_ids.quantity = 10
+ receipt_po2.move_ids.picked = True
receipt_po2.button_validate()
move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
@@ -552,7 +553,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
stock_return_picking.product_return_moves.quantity = 10
stock_return_picking_action = stock_return_picking.create_returns()
return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
- return_pick.move_ids[0].move_line_ids[0].qty_done = 10
+ return_pick.move_ids[0].move_line_ids[0].quantity = 10
+ return_pick.move_ids[0].picked = True
return_pick.button_validate()
# valuation of product1 should be 200 as the first items will be sent out
@@ -598,7 +600,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
# Receive the goods
receipt = order.picking_ids[0]
- receipt.move_ids.quantity_done = 1
+ receipt.move_ids.quantity = 1
+ receipt.move_ids.picked = True
receipt.button_validate()
stock_valuation_aml = self.env['account.move.line'].search([('account_id', '=', self.stock_valuation_account.id)])
@@ -665,7 +668,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
})
po1.button_confirm()
receipt_po1 = po1.picking_ids[0]
- receipt_po1.move_ids.quantity_done = 10
+ receipt_po1.move_ids.quantity = 10
+ receipt_po1.move_ids.picked = True
receipt_po1.button_validate()
# valuation of product1 should be 15 as the tax with no account set
@@ -719,7 +723,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
# Receive the goods
receipt = po.picking_ids[0]
- receipt.move_line_ids.qty_done = 1
+ receipt.move_line_ids.quantity = 1
+ receipt.move_ids.picked = True
receipt.button_validate()
# Create a vendor bill
@@ -818,7 +823,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
# Receive the goods
receipt = po.picking_ids[0]
- receipt.move_line_ids.qty_done = 1
+ receipt.move_line_ids.quantity = 1
+ receipt.move_ids.picked = True
receipt.button_validate()
# Create a vendor bill
@@ -1195,7 +1201,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
picking = po.picking_ids
(picking.move_ids
.filtered(lambda l: l.purchase_line_id == line_product_avg)
- .write({'quantity_done': 1.0}))
+ .write({'quantity': 1.0, 'picked': True}))
picking.button_validate()
# 5 Units received at rate 0.7 = 42.86
@@ -1294,7 +1300,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
picking = po.picking_ids
(picking.move_ids
.filtered(lambda l: l.purchase_line_id == line_product_avg)
- .write({'quantity_done': 1.0}))
+ .write({'quantity': 1.0, 'picked': True}))
picking.button_validate()
# 5 Units received at rate 2 = 42.86
@@ -1422,7 +1428,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
picking = po.picking_ids
(picking.move_ids
.filtered(lambda l: l.purchase_line_id == line_product_avg)
- .write({'quantity_done': 5.0}))
+ .write({'quantity': 5.0, 'picked': True}))
picking.button_validate()
picking._action_done() # Create Backorder
@@ -1456,7 +1462,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
backorder_picking = self.env['stock.picking'].search([('backorder_id', '=', picking.id)])
(backorder_picking.move_ids
.filtered(lambda l: l.purchase_line_id == line_product_avg)
- .write({'quantity_done': 5.0}))
+ .write({'quantity': 5.0, 'picked': True}))
backorder_picking.button_validate()
# 5 Units invoiced at rate 2 (10) + 5 Units received at rate 0.8 (37.50) = 23.75
self.assertAlmostEqual(product_avg.standard_price, 23.75)
@@ -1545,7 +1551,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
# Receive the goods
receipt = order.picking_ids[0]
- receipt.move_ids.quantity_done = 1
+ receipt.move_ids.quantity = 1
+ receipt.move_ids.picked = True
receipt.button_validate()
# Create an invoice with a different price and a discount
@@ -1594,7 +1601,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
# Receive the goods
receipt = order.picking_ids[0]
- receipt.move_ids.quantity_done = 1
+ receipt.move_ids.quantity = 1
+ receipt.move_ids.picked = True
receipt.button_validate()
# Create an invoice with a different price and a discount
@@ -1641,7 +1649,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
# Receive the goods
receipt = order.picking_ids[0]
- receipt.move_ids.quantity_done = 1
+ receipt.move_ids.quantity = 1
+ receipt.move_ids.picked = True
receipt.button_validate()
# Create an invoice with a different price and a discount
@@ -1754,7 +1763,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
# Receive 7 Hundred
receipt01 = po.picking_ids[0]
- receipt01.move_ids.move_line_ids.qty_done = 700
+ receipt01.move_ids.move_line_ids.quantity = 700
+ receipt01.move_ids.picked = True
action = receipt01.button_validate()
backorder_wizard = Form(self.env['stock.backorder.confirmation'].with_context(action['context'])).save()
backorder_wizard.process()
@@ -1764,7 +1774,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
# Receive 3 Hundred
receipt02 = receipt01.backorder_ids
- receipt02.move_ids._set_quantities_to_reservation()
+ receipt02.move_ids.picked = True
receipt02.button_validate()
expected_svl_values += [3 * 50]
@@ -1784,11 +1794,9 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
'location_dest_id': customer_location.id,
})],
'state': 'draft',
- 'immediate_transfer': False,
})
- delivery01.action_reset_draft()
delivery01.action_confirm()
- delivery01.move_ids._set_quantities_to_reservation()
+ delivery01.move_ids.picked = True
delivery01.button_validate()
expected_svl_values += [-5 * 50]
@@ -1858,11 +1866,9 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
'location_dest_id': customer_location.id,
})],
'state': 'draft',
- 'immediate_transfer': False,
})
- delivery02.action_reset_draft()
delivery02.action_confirm()
- delivery02.move_ids._set_quantities_to_reservation()
+ delivery02.move_ids.picked = True
delivery02.button_validate()
expected_svl_values += [-2 * 50 + -2 * 10]
@@ -1899,7 +1905,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
po.button_confirm()
receipt = po.picking_ids[0]
- receipt.move_ids._set_quantities_to_reservation()
+ receipt.move_ids.picked = True
receipt.button_validate()
delivery = self.env['stock.picking'].create({
@@ -1914,11 +1920,9 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
'location_dest_id': customer_location.id,
})],
'state': 'draft',
- 'immediate_transfer': False,
})
- delivery.action_reset_draft()
delivery.action_confirm()
- delivery.move_ids._set_quantities_to_reservation()
+ delivery.move_ids.picked = True
delivery.button_validate()
bill01_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice'))
@@ -1973,19 +1977,22 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
po.button_confirm()
receipt01 = po.picking_ids
- receipt01.move_ids.move_line_ids.qty_done = 4
+ receipt01.move_ids.move_line_ids.quantity = 4
+ receipt01.move_ids.picked = True
action = receipt01.button_validate()
backorder_wizard = Form(self.env['stock.backorder.confirmation'].with_context(action['context'])).save()
backorder_wizard.process()
receipt02 = receipt01.backorder_ids
- receipt02.move_ids.move_line_ids.qty_done = 3
+ receipt02.move_ids.move_line_ids.quantity = 3
+ receipt02.move_ids.picked = True
action = receipt02.button_validate()
backorder_wizard = Form(self.env['stock.backorder.confirmation'].with_context(action['context'])).save()
backorder_wizard.process()
receipt03 = receipt02.backorder_ids
- receipt03.move_ids.move_line_ids.qty_done = 5
+ receipt03.move_ids.move_line_ids.quantity = 5
+ receipt03.move_ids.picked = True
receipt03.button_validate()
expected_svl_values = [40, 30, 50]
@@ -2121,7 +2128,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
po.button_confirm()
receipt = po.picking_ids
- receipt.move_ids.move_line_ids.qty_done = 10
+ receipt.move_ids.move_line_ids.quantity = 10
+ receipt.move_ids.picked = True
receipt.button_validate()
expected_svl_values += [100.0]
expected_svl_remaining_values += [100.0]
@@ -2149,7 +2157,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
})],
})
delivery.action_confirm()
- delivery.move_ids.quantity_done = 3.0
+ delivery.move_ids.quantity = 3.0
+ delivery.move_ids.picked = True
delivery.button_validate()
expected_svl_values += [-36.0]
expected_svl_remaining_values += [0.0]
@@ -2185,7 +2194,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
})],
})
delivery.action_confirm()
- delivery.move_ids.quantity_done = 1.0
+ delivery.move_ids.quantity = 1.0
+ delivery.move_ids.picked = True
delivery.button_validate()
expected_svl_values += [-9.0]
expected_svl_remaining_values += [0.0]
@@ -2274,7 +2284,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
po.button_confirm()
receipt = po.picking_ids
- receipt.move_ids.move_line_ids.qty_done = 10
+ receipt.move_ids.move_line_ids.quantity = 10
+ receipt.move_ids.picked = True
receipt.button_validate()
expected_svl_values += [100.0]
expected_svl_remaining_values += [100.0]
@@ -2367,13 +2378,15 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
po.button_confirm()
receipt01 = po.picking_ids
- receipt01.move_ids.move_line_ids.qty_done = 1
+ receipt01.move_ids.move_line_ids.quantity = 1
+ receipt01.move_ids.picked = True
action = receipt01.button_validate()
backorder_wizard = Form(self.env['stock.backorder.confirmation'].with_context(action['context'])).save()
backorder_wizard.process()
receipt02 = receipt01.backorder_ids
- receipt02.move_ids.move_line_ids.qty_done = 1
+ receipt02.move_ids.move_line_ids.quantity = 1
+ receipt02.move_ids.picked = True
receipt02.button_validate()
bill01 = self._bill(po, 1.0, 11)
@@ -2471,7 +2484,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
po.button_confirm()
picking = po.picking_ids[0]
move = picking.move_ids[0]
- move.quantity_done = 10
+ move.quantity = 10
+ move.picked = True
res_dict = picking.button_validate()
self.assertEqual(res_dict['res_model'], 'stock.backorder.confirmation')
wizard = self.env[(res_dict.get('res_model'))].browse(res_dict.get('res_id')).with_context(res_dict['context'])
@@ -2482,7 +2496,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
picking2 = po.picking_ids.filtered(lambda p: p.backorder_id)
move2 = picking2.move_ids[0]
- move2.quantity_done = 2
+ move2.quantity = 2
+ move2.picked = True
picking2.button_validate()
self.assertAlmostEqual(move2.stock_valuation_layer_ids.unit_cost, price_unit_USD)
@@ -2515,7 +2530,8 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
po.button_confirm()
picking = po.picking_ids[0]
move = picking.move_ids[0]
- move.quantity_done = 10
+ move.quantity = 10
+ move.picked = True
res_dict = picking.button_validate()
self.assertEqual(res_dict['res_model'], 'stock.backorder.confirmation')
wizard = self.env[(res_dict.get('res_model'))].browse(res_dict.get('res_id')).with_context(res_dict['context'])
@@ -2526,6 +2542,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
picking2 = po.picking_ids.filtered(lambda p: p.backorder_id)
move2 = picking2.move_ids[0]
- move2.quantity_done = 2
+ move2.quantity = 2
+ move2.picked = True
picking2.button_validate()
self.assertAlmostEqual(move2.stock_valuation_layer_ids.unit_cost, price_unit_USD)
diff --git a/addons/purchase_stock/tests/test_uninstall.py b/addons/purchase_stock/tests/test_uninstall.py
index 742057645a8..d7da6808c0a 100644
--- a/addons/purchase_stock/tests/test_uninstall.py
+++ b/addons/purchase_stock/tests/test_uninstall.py
@@ -26,7 +26,8 @@ class TestUninstallPurchaseStock(PurchaseTestCommon):
self.assertEqual(order_line.product_id.detailed_type, 'product')
- stock_move.quantity_done = 1
+ stock_move.quantity = 1
+ stock_move.picked = True
stock_move.picking_id.button_validate()
self.assertEqual(purchase_order.order_line.qty_received, 1)
diff --git a/addons/repair/models/product.py b/addons/repair/models/product.py
index 9582bbba255..f25a2ab597f 100644
--- a/addons/repair/models/product.py
+++ b/addons/repair/models/product.py
@@ -9,9 +9,9 @@ class Product(models.Model):
def _count_returned_sn_products(self, sn_lot):
res = self.env['stock.move'].search_count([
- ('repair_line_type', '=', 'remove'),
+ ('repair_line_type', 'in', ['remove', 'recycle']),
('product_uom_qty', '=', 1),
- ('move_line_ids.lot_id', 'in', sn_lot.id),
+ ('move_line_ids.lot_id', '=', sn_lot.id),
('state', '=', 'done'),
('location_dest_usage', '=', 'internal'),
])
diff --git a/addons/repair/models/repair.py b/addons/repair/models/repair.py
index 1421b0b561e..8d6542a10cb 100644
--- a/addons/repair/models/repair.py
+++ b/addons/repair/models/repair.py
@@ -251,22 +251,20 @@ class Repair(models.Model):
returned = self.filtered(lambda r: r.picking_id and r.picking_id.state == 'done')
returned.is_returned = True
- @api.depends('state',
- 'move_ids.reserved_availability',
- 'move_ids.quantity_done')
+ @api.depends('state', 'move_ids.quantity', 'move_ids.product_uom_qty')
def _compute_show_qty_button(self):
self.show_set_qty_button = False
self.show_clear_qty_button = False
for repair in self.filtered(lambda r: r.state not in ['cancel', 'done']):
- if any(float_is_zero(m.quantity_done, precision_rounding=m.product_uom.rounding) and not float_is_zero(m.reserved_availability, precision_rounding=m.product_uom.rounding) for m in repair.move_ids):
+ if any(float_is_zero(m.quantity, precision_rounding=m.product_uom.rounding) and not float_is_zero(m.product_uom_qty, precision_rounding=m.product_uom.rounding) for m in repair.move_ids):
repair.show_set_qty_button = True
- elif any(not float_is_zero(m.quantity_done, precision_rounding=m.product_uom.rounding) and float_compare(m.quantity_done, m.reserved_availability, precision_rounding=m.product_uom.rounding) == 0 for m in repair.move_ids):
+ elif any(not float_is_zero(m.quantity, precision_rounding=m.product_uom.rounding) for m in repair.move_ids):
repair.show_clear_qty_button = True
@api.depends('move_ids', 'state', 'move_ids.product_uom_qty')
def _compute_unreserve_visible(self):
for repair in self:
- already_reserved = repair.state not in ('done', 'cancel') and any(repair.mapped('move_ids.move_line_ids.reserved_qty'))
+ already_reserved = repair.state not in ('done', 'cancel') and any(repair.mapped('move_ids.move_line_ids.quantity'))
repair.unreserve_visible = already_reserved
repair.reserve_visible = repair.state in ('confirmed', 'under_repair') and any(move.product_uom_qty and move.state in ['confirmed', 'partially_available'] for move in repair.move_ids)
@@ -326,7 +324,7 @@ class Repair(models.Model):
return self.move_ids._action_assign()
def action_clear_quantities_to_zero(self):
- return self.move_ids.filtered(lambda m: float_compare(m.quantity_done, m.reserved_availability, precision_rounding=m.product_uom.rounding) == 0)._clear_quantities_to_zero()
+ return self.move_ids.filtered(lambda m: float_compare(m.quantity, m.reserved_availability, precision_rounding=m.product_uom.rounding) == 0)._clear_quantities_to_zero()
def action_create_sale_order(self):
if any(repair.sale_order_id for repair in self):
@@ -377,16 +375,15 @@ class Repair(models.Model):
# Clean the context to get rid of residual default_* keys that could cause issues
# during the creation of stock.move.
self = self.with_context(clean_context(self._context))
- self._check_product_tracking()
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
product_move_vals = []
- # Cancel moves with 0 quantity_done
- self.move_ids.filtered(lambda m: float_is_zero(m.quantity_done, precision_rounding=m.product_uom.rounding))._action_cancel()
+ # Cancel moves with 0 quantity
+ self.move_ids.filtered(lambda m: float_is_zero(m.quantity, precision_rounding=m.product_uom.rounding))._action_cancel()
no_service_policy = 'service_policy' not in self.env['product.template']
- #SOL qty delivered = repair.move_ids.quantity_done
+ #SOL qty delivered = repair.move_ids.quantity
for repair in self:
if repair.sale_order_line_id:
ro_origin_product = repair.sale_order_line_id.product_template_id
@@ -418,9 +415,8 @@ class Repair(models.Model):
'move_line_ids': [(0, 0, {
'product_id': repair.product_id.id,
'lot_id': repair.lot_id.id,
- 'reserved_uom_qty': 0, # bypass reservation here
'product_uom_id': repair.product_uom.id or repair.product_id.uom_id.id,
- 'qty_done': repair.product_qty,
+ 'quantity': repair.product_qty,
'package_id': False,
'result_package_id': False,
'owner_id': owner_id,
@@ -436,7 +432,6 @@ class Repair(models.Model):
product_moves = self.env['stock.move'].create(product_move_vals)
self.move_id = product_moves.id
- self.sale_order_line_id.move_ids._set_quantities_to_reservation()
all_moves = self.move_ids + product_moves
all_moves._action_done()
@@ -454,7 +449,7 @@ class Repair(models.Model):
"""
if self.filtered(lambda repair: repair.state != 'under_repair'):
raise UserError(_("Repair must be under repair in order to end reparation."))
- if any(float_compare(move.quantity_done, move.product_uom_qty, precision_rounding=move.product_uom.rounding) < 0 for move in self.move_ids):
+ if any(float_compare(move.quantity, move.product_uom_qty, precision_rounding=move.product_uom.rounding) < 0 for move in self.move_ids):
ctx = dict(self.env.context or {})
ctx['default_repair_ids'] = self.ids
return {
@@ -476,9 +471,6 @@ class Repair(models.Model):
self._action_repair_confirm()
return self.write({'state': 'under_repair'})
- def action_set_quantities_to_reservation(self):
- return self.move_ids.filtered(lambda m: float_is_zero(m.quantity_done, precision_rounding=m.product_uom.rounding))._set_quantities_to_reservation()
-
def action_unreserve(self):
return self.move_ids.filtered(lambda m: m.state in ('assigned', 'partially_available'))._do_unreserve()
@@ -537,15 +529,6 @@ class Repair(models.Model):
repairs_to_confirm.write({'state': 'confirmed'})
return True
- def _check_product_tracking(self):
- invalid_lines = self.move_ids.filtered(lambda x: x.has_tracking != 'none' and not x.lot_ids)
- if invalid_lines:
- products = invalid_lines.product_id
- raise ValidationError(_(
- "Serial number is required for operation lines with products: %s",
- ", ".join(products.mapped('display_name')),
- ))
-
def _get_location(self, field):
return self.picking_type_id[MAP_REPAIR_TO_PICKING_LOCATIONS[field]]
diff --git a/addons/repair/models/sale_order.py b/addons/repair/models/sale_order.py
index 89324bbfa45..ebcb06bea7f 100644
--- a/addons/repair/models/sale_order.py
+++ b/addons/repair/models/sale_order.py
@@ -57,7 +57,7 @@ class SaleOrderLine(models.Model):
if len(move) != 1:
continue
remaining_so_lines -= so_line
- so_line.qty_delivered = move.quantity_done
+ so_line.qty_delivered = move.quantity
return super(SaleOrderLine, remaining_so_lines)._compute_qty_delivered()
@api.model_create_multi
diff --git a/addons/repair/models/stock_move.py b/addons/repair/models/stock_move.py
index daa6a181aeb..3fc20a83069 100644
--- a/addons/repair/models/stock_move.py
+++ b/addons/repair/models/stock_move.py
@@ -113,7 +113,7 @@ class StockMove(models.Model):
for move in self:
if move.sale_line_id or move.repair_line_type != 'add' or not move.repair_id.sale_order_id:
continue
- product_qty = move.product_uom_qty if move.repair_id.state != 'done' else move.quantity_done
+ product_qty = move.product_uom_qty if move.repair_id.state != 'done' else move.quantity
so_line_vals.append({
'order_id': move.repair_id.sale_order_id.id,
'product_id': move.product_id.id,
diff --git a/addons/repair/tests/test_repair.py b/addons/repair/tests/test_repair.py
index e905ed04efa..fc888ea3d4e 100644
--- a/addons/repair/tests/test_repair.py
+++ b/addons/repair/tests/test_repair.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo.exceptions import UserError, ValidationError
+from odoo.exceptions import UserError
from odoo.tests import tagged, common, Form
from odoo.tools import float_compare, float_is_zero
@@ -215,7 +215,7 @@ class TestRepair(common.TransactionCase):
# No partner warning -> working case -> already linked warning
# Ensure SO doesn't exist
- self.assertEqual(repair.sale_order_id.__len__(), 0)
+ self.assertEqual(len(repair.sale_order_id), 0)
repair.partner_id = None
with self.assertRaises(UserError) as err:
repair.action_create_sale_order()
@@ -223,11 +223,10 @@ class TestRepair(common.TransactionCase):
repair.partner_id = self.res_partner_12.id
repair.action_create_sale_order()
# Ensure SO and SOL were created
- self.assertNotEqual(repair.sale_order_id.__len__(), 0)
- self.assertEqual(repair.sale_order_id.order_line.__len__(), 3)
+ self.assertNotEqual(len(repair.sale_order_id), 0)
+ self.assertEqual(len(repair.sale_order_id.order_line), 3)
with self.assertRaises(UserError) as err:
repair.action_create_sale_order()
- self.assertIn("You cannot create a quotation for a repair order that is already linked", err.exception.args[0])
# (*) -> cancel (action_repair_cancel)
# PRE
@@ -271,15 +270,16 @@ class TestRepair(common.TransactionCase):
# under_repair -> done (action_repair_end -> action_repair_done)
# PRE
# state == under_repair !-> UserError
- # lines' qty_done >= lines' product_uom_qty !-> Warning
+ # lines' quantity >= lines' product_uom_qty !-> Warning
# line tracked => line has lot_ids !-> ValidationError
# POST
- # lines with qty_done == 0 are cancelled (related sol product_uom_qty is consequently set to 0)
+ # lines with quantity == 0 are cancelled (related sol product_uom_qty is consequently set to 0)
# repair.product_id => repair.move_id
# move_ids.state == (done || cancel)
# state == done
- # move_ids with qty_done (LOWER or HIGHER than) product_uom_qty MUST NOT be splitted
- # Any line with qty_done < product_uom_qty => Warning
+ # move_ids with quantity (LOWER or HIGHER than) product_uom_qty MUST NOT be splitted
+ # Any line with quantity < product_uom_qty => Warning
+ repair.move_ids.picked = True
end_action = repair.action_repair_end()
self.assertEqual(end_action.get("res_model"), "repair.warn.uncomplete.move")
warn_uncomplete_wizard = Form(
@@ -287,22 +287,22 @@ class TestRepair(common.TransactionCase):
.with_context(**end_action['context'])
).save()
# LineB : no serial => ValidationError
- with self.assertRaises(ValidationError) as err:
+ lot = lineB.move_line_ids.lot_id
+ with self.assertRaises(UserError) as err:
+ lineB.move_line_ids.lot_id = False
warn_uncomplete_wizard.action_validate()
- self.assertIn("Serial number is required for operation lines", err.exception.args[0])
# LineB with lots
- move_line = lineB.move_line_ids[0]
- move_line.qty_done = move_line.reserved_uom_qty
+ lineB.move_line_ids.lot_id = lot
- lineA.quantity_done = 2 # qty_done = product_uom_qty
- lineC.quantity_done = 2 # qty_done > product_uom_qty (No warning)
+ lineA.quantity = 2 # quantity = product_uom_qty
+ lineC.quantity = 2 # quantity > product_uom_qty (No warning)
lineD = self._create_simple_part_move(repair.id, 0.0)
repair.move_ids |= lineD # product_uom_qty = 0 : state is cancelled
self.assertEqual(lineD.state, 'assigned')
- num_of_lines = repair.move_ids.__len__()
- self.assertEqual(repair.move_id.__len__(), 0)
+ num_of_lines = len(repair.move_ids)
+ self.assertFalse(repair.move_id)
repair.action_repair_end()
self.assertEqual(repair.state, "done")
@@ -310,15 +310,14 @@ class TestRepair(common.TransactionCase):
#line a,b,c are 'done', line d is 'cancel'
self.assertTrue(all(m.state == 'done' for m in done_moves))
self.assertEqual(lineD.state, 'cancel')
- self.assertEqual(repair.move_id.__len__(), 1)
- self.assertEqual(repair.move_ids.__len__(), num_of_lines) # No split
+ self.assertEqual(len(repair.move_id), 1)
+ self.assertEqual(len(repair.move_ids), num_of_lines) # No split
# (*) -> cancel (action_repair_cancel)
# PRE
# state != done !-> UserError
with self.assertRaises(UserError) as err:
repair.action_repair_cancel()
- self.assertEqual(err.exception.args[0], "You cannot cancel a Repair Order that's already been completed")
def test_02_repair_sale_order_binding(self):
# Binding from SO to RO(s)
@@ -411,13 +410,14 @@ class TestRepair(common.TransactionCase):
# repair_order.action_repair_end()
# -> order_line.qty_delivered == order_line.product_uom_qty
- # -> "RO Lines"'s SOL.qty_delivered == move.quantity_done
- for line in repair_order.move_ids:
- line.quantity_done = line.product_uom_qty
+ # -> "RO Lines"'s SOL.qty_delivered == move.quantity
repair_order.action_repair_start()
+ for line in repair_order.move_ids:
+ line.quantity = line.product_uom_qty
+ repair_order.move_ids.picked = True
repair_order.action_repair_end()
self.assertTrue(float_is_zero(order_line.qty_delivered, 2))
- self.assertEqual(float_compare(sol_part_0.product_uom_qty, ro_line_0.quantity_done, 2), 0)
+ self.assertEqual(float_compare(sol_part_0.product_uom_qty, ro_line_0.quantity, 2), 0)
self.assertTrue(float_is_zero(sol_part_1.qty_delivered, 2))
def test_03_sale_order_delivered_qty(self):
@@ -546,9 +546,8 @@ class TestRepair(common.TransactionCase):
picking = picking_form.save()
picking.action_confirm()
picking.action_assign()
- res_dict = picking.button_validate()
- wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save()
- wizard.process()
+ picking.button_validate()
+
self.assertEqual(picking.state, 'done')
# Create a return
stock_return_picking_form = Form(self.env['stock.return.picking']
@@ -558,7 +557,7 @@ class TestRepair(common.TransactionCase):
stock_return_picking.product_return_moves.quantity = 1.0
stock_return_picking_action = stock_return_picking.create_returns()
return_picking = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
- return_picking.action_set_quantities_to_reservation()
+ return_picking.move_ids.picked = True
return_picking.button_validate()
self.assertEqual(return_picking.state, 'done')
diff --git a/addons/repair/views/repair_views.xml b/addons/repair/views/repair_views.xml
index 137502f8398..53641d66d52 100644
--- a/addons/repair/views/repair_views.xml
+++ b/addons/repair/views/repair_views.xml
@@ -67,7 +67,6 @@
-
@@ -147,7 +146,6 @@
-
@@ -159,18 +157,16 @@
-
-
-
-
+
+
0)
for m in moves) or not moves:
order_line.qty_delivered = 0
diff --git a/addons/sale_mrp/models/stock_move.py b/addons/sale_mrp/models/stock_move.py
index bc0a1f1bce0..4d31d27e3fd 100644
--- a/addons/sale_mrp/models/stock_move.py
+++ b/addons/sale_mrp/models/stock_move.py
@@ -20,6 +20,6 @@ class StockMoveLine(models.Model):
kit_lines = self.filtered(lambda move_line: move_line.move_id.bom_line_id.bom_id.type == 'phantom')
for move_line in kit_lines:
unit_price = move_line.product_id.list_price
- qty = move_line.product_uom_id._compute_quantity(move_line.qty_done, move_line.product_id.uom_id)
+ qty = move_line.product_uom_id._compute_quantity(move_line.quantity, move_line.product_id.uom_id)
move_line.sale_price = unit_price * qty
super(StockMoveLine, self - kit_lines)._compute_sale_price()
diff --git a/addons/sale_mrp/tests/test_sale_mrp_anglo_saxon_valuation.py b/addons/sale_mrp/tests/test_sale_mrp_anglo_saxon_valuation.py
index 2cbd8d735d9..ff7fcfc1252 100644
--- a/addons/sale_mrp/tests/test_sale_mrp_anglo_saxon_valuation.py
+++ b/addons/sale_mrp/tests/test_sale_mrp_anglo_saxon_valuation.py
@@ -96,7 +96,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
})],
})
so.action_confirm()
- so.picking_ids.move_ids.quantity_done = 1
+ so.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
so.picking_ids.button_validate()
invoice = so.with_context(default_journal_id=self.company_data['default_journal_sale'].id)._create_invoices()
@@ -190,9 +190,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
# Deliver the three finished products
pick = so.picking_ids
# To check the products on the picking
- wiz_act = pick.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ pick.button_validate()
# Create the invoice
so._create_invoices()
invoice = so.invoice_ids
@@ -244,7 +242,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': p,
} for p in [10, 20, 60]])
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
# Sell 3 kits
@@ -267,7 +265,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
picking = so.picking_ids
while picking:
pickings.append(picking)
- picking.move_ids.quantity_done = 1
+ picking.move_ids.write({'quantity': 1, 'picked': True})
action = picking.button_validate()
if isinstance(action, dict):
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
@@ -288,7 +286,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 100,
})
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
# Return the second picking (i.e. one component @20)
@@ -296,7 +294,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
return_wizard = Form(self.env['stock.return.picking'].with_context(ctx)).save()
return_picking_id, dummy = return_wizard._create_returns()
return_picking = self.env['stock.picking'].browse(return_picking_id)
- return_picking.move_ids.quantity_done = 1
+ return_picking.move_ids.write({'quantity': 1, 'picked': True})
return_picking.button_validate()
# Add a credit note for the returned kit
@@ -349,7 +347,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': p,
} for p in [10, 20, 60]])
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
# Sell 3 kits
@@ -372,7 +370,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
picking = so.picking_ids
while picking:
pickings.append(picking)
- picking.move_ids.quantity_done = 1
+ picking.move_ids.write({'quantity': 1, 'picked': True})
action = picking.button_validate()
if isinstance(action, dict):
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
@@ -393,7 +391,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 100,
})
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
# Return the second picking (i.e. one component @20)
@@ -401,7 +399,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
return_wizard = Form(self.env['stock.return.picking'].with_context(ctx)).save()
return_picking_id, dummy = return_wizard._create_returns()
return_picking = self.env['stock.picking'].browse(return_picking_id)
- return_picking.move_ids.quantity_done = 1
+ return_picking.move_ids.write({'quantity': 1, 'picked': True})
return_picking.button_validate()
# Create a new invoice for the returned kit
@@ -460,7 +458,7 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
})],
})
so.action_confirm()
- so.picking_ids.move_ids.quantity_done = 1
+ so.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
so.picking_ids.button_validate()
invoice = so._create_invoices()
@@ -513,7 +511,8 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon):
})],
})
so.action_confirm()
- so.picking_ids.move_line_ids.qty_done = 1
+ so.picking_ids.move_line_ids.quantity = 1
+ so.picking_ids.move_ids.picked = True
so.picking_ids.button_validate()
invoice = so._create_invoices()
diff --git a/addons/sale_mrp/tests/test_sale_mrp_flow.py b/addons/sale_mrp/tests/test_sale_mrp_flow.py
index 85b50ee72c5..d6b5f1d6414 100644
--- a/addons/sale_mrp/tests/test_sale_mrp_flow.py
+++ b/addons/sale_mrp/tests/test_sale_mrp_flow.py
@@ -196,7 +196,10 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
"""
moves_to_process = moves.filtered(lambda m: m.product_id in quantities_to_process.keys())
for move in moves_to_process:
- move.write({'quantity_done': quantities_to_process[move.product_id]})
+ move.write({
+ 'quantity': quantities_to_process[move.product_id],
+ 'picked': True
+ })
def _assert_quantities(self, moves, quantities_to_process):
""" Helper to check expected quantities based on a dict following this structure :
@@ -231,7 +234,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
move._action_confirm()
move._action_assign()
move_line = move.move_line_ids[0]
- move_line.qty_done = qty_to_process[comp][0]
+ move_line.quantity = qty_to_process[comp][0]
move._action_done()
def test_00_sale_mrp_flow(self):
@@ -549,7 +552,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
# deliver partially (1 of each instead of 5), check the so's invoice_status and delivered quantities
pick = so.picking_ids
- pick.move_ids.write({'quantity_done': 1})
+ pick.move_ids.write({'quantity': 1, 'picked': True})
wiz_act = pick.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
wiz.process()
@@ -561,9 +564,9 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
pick_2 = so.picking_ids.filtered('backorder_id')
for move in pick_2.move_ids:
if move.product_id.id == product_desk_bolt.id:
- move.write({'quantity_done': 19})
+ move.write({'quantity': 19, 'picked': True})
else:
- move.write({'quantity_done': 4})
+ move.write({'quantity': 4, 'picked': True})
pick_2.button_validate()
del_qty = sum(sol.qty_delivered for sol in so.order_line)
@@ -670,9 +673,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
pick = self.so.picking_ids
# To check the products on the picking
self.assertEqual(pick.move_ids.mapped('product_id'), self.component1 | self.component2)
- wiz_act = pick.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ pick.button_validate()
# Create the invoice
self.so._create_invoices()
self.invoice = self.so.invoice_ids
@@ -749,7 +750,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
self._assert_quantities(move_ids, expected_quantities)
# Process only x1 of the first component then create a backorder for the missing components
- picking_original.move_ids.sorted()[0].write({'quantity_done': 1})
+ picking_original.move_ids.sorted()[0].write({'quantity': 1, 'picked': True})
wiz_act = so.picking_ids[0].button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save().process()
@@ -762,7 +763,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
# Process only x6 each componenent in the picking
# Then create a backorder for the missing components
- backorder_1.move_ids.write({'quantity_done': 6})
+ backorder_1.move_ids.write({'quantity': 6, 'picked': True})
wiz_act = backorder_1.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save().process()
@@ -778,7 +779,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
# Process x3 more unit of each components :
# - Now only 3 kits should be delivered
# - A backorder will be created, the SO should have 3 picking_ids linked to it.
- backorder_2.move_ids.write({'quantity_done': 3})
+ backorder_2.move_ids.write({'quantity': 3, 'picked': True})
wiz_act = backorder_2.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save().process()
@@ -870,7 +871,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
# Process only 7 units of each component
qty_to_process = 7
- move_ids.write({'quantity_done': qty_to_process})
+ move_ids.write({'quantity': qty_to_process, 'picked': True})
# Create a backorder for the missing componenents
wiz_act = picking_original.button_validate()
@@ -976,9 +977,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
return_pick = self.env['stock.picking'].browse(res['res_id'])
# Process all components and validate the picking
- wiz_act = return_pick.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ return_pick.button_validate()
# Now quantity delivered should be 3 again
self.assertEqual(order_line.qty_delivered, 3)
@@ -995,7 +994,8 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
# Process all components except one of each
for move in return_of_return_pick.move_ids:
move.write({
- 'quantity_done': expected_quantities[move.product_id] - 1,
+ 'quantity': expected_quantities[move.product_id] - 1,
+ 'picked': True,
'to_refund': True
})
@@ -1702,7 +1702,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
# Validate delivery
pick = order.picking_ids
- pick.move_ids.write({'quantity_done': 1})
+ pick.move_ids.write({'quantity': 1, 'picked': True})
pick.button_validate()
qty_del_validated = sum(sol.qty_delivered for sol in order.order_line)
self.assertEqual(qty_del_validated, 1.0, 'The order went from warehouse to client, so it has been delivered')
@@ -1718,7 +1718,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
})
res = return_wiz.create_returns()
return_pick = self.env['stock.picking'].browse(res['res_id'])
- return_pick.move_line_ids.qty_done = 1
+ return_pick.move_line_ids.quantity = 1
return_pick.button_validate() # validate return
# Delivered quantities to the client should be 0
@@ -1766,9 +1766,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
so = so_form.save()
so.action_confirm()
- wiz_act = so.picking_ids.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ so.picking_ids.button_validate()
p2_bom.type = "normal"
@@ -1902,8 +1900,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
so.action_confirm()
# Deliver the products
pick = so.picking_ids
- wiz_act = pick.button_validate()
- Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save().process()
+ pick.button_validate()
# Create the invoice
so._create_invoices()
# Validate the invoice
@@ -1946,9 +1943,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
# Check picking creation
self.assertEqual(len(so.picking_ids), 1, "A picking should be created after the SO validation")
- wiz_act = so.picking_ids.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ so.picking_ids.button_validate()
so._action_cancel()
so.action_draft()
@@ -1989,9 +1984,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
self.assertEqual(price, 10)
picking = so.picking_ids
- action = picking.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
+ picking.button_validate()
ctx = {'active_ids':picking.ids, 'active_id': picking.ids[0], 'active_model': 'stock.picking'}
return_picking_wizard_form = Form(self.env['stock.return.picking'].with_context(ctx))
@@ -2049,8 +2042,6 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
{'product_id': self.component_f.id, 'product_uom_qty': 100},
{'product_id': self.component_g.id, 'product_uom_qty': 200},
])
-
- delivery.action_set_quantities_to_reservation()
delivery.button_validate()
# Return 2 [uom_ten] x kit_3
@@ -2060,7 +2051,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
return_wizard.product_return_moves[1].quantity = 40
action = return_wizard.create_returns()
return_picking = self.env['stock.picking'].browse(action['res_id'])
- return_picking.action_set_quantities_to_reservation()
+ return_picking.move_ids.picked = True
return_picking.button_validate()
# Adapt the SOL qty according to the delivered one
@@ -2069,10 +2060,10 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
line.product_uom_qty = 8
self.assertRecordValues(so.picking_ids.sorted('id').move_ids, [
- {'product_id': self.component_f.id, 'location_dest_id': custo_location.id, 'quantity_done': 100, 'state': 'done'},
- {'product_id': self.component_g.id, 'location_dest_id': custo_location.id, 'quantity_done': 200, 'state': 'done'},
- {'product_id': self.component_f.id, 'location_dest_id': stock_location.id, 'quantity_done': 20, 'state': 'done'},
- {'product_id': self.component_g.id, 'location_dest_id': stock_location.id, 'quantity_done': 40, 'state': 'done'},
+ {'product_id': self.component_f.id, 'location_dest_id': custo_location.id, 'quantity': 100, 'state': 'done'},
+ {'product_id': self.component_g.id, 'location_dest_id': custo_location.id, 'quantity': 200, 'state': 'done'},
+ {'product_id': self.component_f.id, 'location_dest_id': stock_location.id, 'quantity': 20, 'state': 'done'},
+ {'product_id': self.component_g.id, 'location_dest_id': stock_location.id, 'quantity': 40, 'state': 'done'},
])
def test_kit_decrease_sol_qty_to_zero(self):
@@ -2139,7 +2130,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
delivery = so.picking_ids
for m in delivery.move_ids:
- m.quantity_done = m.product_uom_qty
+ m.write({'quantity': m.product_uom_qty, 'picked': True})
delivery.button_validate()
self.assertEqual(delivery.state, 'done')
@@ -2150,7 +2141,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
return_picking_id, dummy = return_wizard._create_returns()
return_picking = self.env['stock.picking'].browse(return_picking_id)
for m in return_picking.move_ids:
- m.quantity_done = m.product_uom_qty
+ m.write({'quantity': m.product_uom_qty, 'picked': True})
return_picking.button_validate()
self.assertEqual(return_picking.state, 'done')
@@ -2197,7 +2188,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
'price_unit': p,
} for p in [10, 50]])
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
so = self.env['sale.order'].create({
@@ -2215,7 +2206,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
so.action_confirm()
picking = so.picking_ids
- picking.move_ids.quantity_done = 1.0
+ picking.move_ids.write({'quantity': 1.0, 'picked': True})
picking.button_validate()
invoice01 = so._create_invoices()
@@ -2279,7 +2270,8 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
})],
})
so.action_confirm()
- so.picking_ids.move_line_ids.qty_done = 1
+ so.picking_ids.move_line_ids.quantity = 1
+ so.picking_ids.move_ids.picked = True
so.picking_ids.button_validate()
invoice = so._create_invoices()
@@ -2310,7 +2302,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
self.bom_kit_1.unlink()
for move in so.order_line.move_ids:
- move.quantity_done = move.product_uom_qty
+ move.write({'quantity': move.product_uom_qty, 'picked': True})
so.picking_ids.button_validate()
self.assertEqual(so.picking_ids.state, 'done')
diff --git a/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py b/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py
index 9cb28747a55..849110bbb99 100644
--- a/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py
+++ b/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py
@@ -184,7 +184,7 @@ class TestSaleMrpKitBom(TransactionCase):
self.assertEqual(so.order_line.qty_delivered, 0)
picking = so.picking_ids
- picking.move_ids.quantity_done = 0.86000
+ picking.move_ids.write({'quantity': 0.86000, 'picked': True})
picking.button_validate()
# Checks the delivery amount (must be 10).
@@ -249,9 +249,7 @@ class TestSaleMrpKitBom(TransactionCase):
self.assertEqual(so.order_line.qty_delivered, 0)
picking = so.picking_ids
- action = picking.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
+ picking.button_validate()
# Checks the delivery amount (must be 1).
self.assertEqual(so.order_line.qty_delivered, 1)
@@ -386,7 +384,7 @@ class TestSaleMrpKitBom(TransactionCase):
ship = so.picking_ids[1]
for move in pick.move_ids:
- move.quantity_done = 1
+ move.write({'quantity': 1, 'picked': True})
pick.action_put_in_pack()
pick.button_validate()
@@ -395,7 +393,7 @@ class TestSaleMrpKitBom(TransactionCase):
ship.package_level_ids._set_is_done()
for move_line in ship.move_line_ids:
- self.assertEqual(move_line.move_id.product_uom_qty, move_line.qty_done, "Quantity done should be equal to the quantity reserved in the move line")
+ self.assertEqual(move_line.move_id.product_uom_qty, move_line.quantity, "Quantity done should be equal to the quantity reserved in the move line")
def test_kit_in_delivery_slip(self):
"""
@@ -511,7 +509,7 @@ class TestSaleMrpKitBom(TransactionCase):
so.action_confirm()
picking = so.picking_ids
self.assertEqual(len(so.picking_ids.move_ids_without_package), 7)
- picking.move_ids.quantity_done = 1
+ picking.move_ids.write({'quantity': 1, 'picked': True})
picking.button_validate()
self.assertEqual(picking.state, 'done')
diff --git a/addons/sale_mrp/tests/test_sale_mrp_report.py b/addons/sale_mrp/tests/test_sale_mrp_report.py
index 3013d92f481..2fbffbaf055 100644
--- a/addons/sale_mrp/tests/test_sale_mrp_report.py
+++ b/addons/sale_mrp/tests/test_sale_mrp_report.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo.tests import common, Form
+from odoo.tests import common
from odoo.tools import html2plaintext
@@ -57,9 +57,7 @@ class TestSaleMrpInvoices(common.TransactionCase):
})
so.action_confirm()
- action = so.picking_ids.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
+ so.picking_ids.button_validate()
invoice = so._create_invoices()
invoice.action_post()
diff --git a/addons/sale_purchase_stock/tests/test_sale_purchase_stock_flow.py b/addons/sale_purchase_stock/tests/test_sale_purchase_stock_flow.py
index 1629fa177dd..ea2a928f526 100644
--- a/addons/sale_purchase_stock/tests/test_sale_purchase_stock_flow.py
+++ b/addons/sale_purchase_stock/tests/test_sale_purchase_stock_flow.py
@@ -71,7 +71,7 @@ class TestSalePurchaseStockFlow(TransactionCase):
'location_id': sm.location_id.id,
'location_dest_id': sm.location_dest_id.id,
'product_id': sm.product_id.id,
- 'qty_done': 12,
+ 'quantity': 12,
'company_id': sm.company_id.id,
'product_uom_id': sm.product_uom.id,
'picking_id': delivery.id,
@@ -79,8 +79,8 @@ class TestSalePurchaseStockFlow(TransactionCase):
delivery.button_validate()
self.assertEqual(delivery.state, 'done')
- self.assertEqual(delivery.move_ids.move_line_ids.qty_done, 12)
+ self.assertEqual(delivery.move_ids.move_line_ids.quantity, 12)
self.assertEqual(so.order_line.qty_delivered, 12)
- sm.move_line_ids.qty_done = 10
+ sm.move_line_ids.quantity = 10
self.assertEqual(so.order_line.qty_delivered, 10)
diff --git a/addons/sale_stock/models/account_move.py b/addons/sale_stock/models/account_move.py
index ce8f8ed6974..b9c12d93f20 100644
--- a/addons/sale_stock/models/account_move.py
+++ b/addons/sale_stock/models/account_move.py
@@ -61,7 +61,7 @@ class AccountMove(models.Model):
continue
product = sml.product_id
product_uom = product.uom_id
- qty_done = sml.product_uom_id._compute_quantity(sml.qty_done, product_uom)
+ quantity = sml.product_uom_id._compute_quantity(sml.quantity, product_uom)
# is it a stock return considering the document type (should it be it thought of as positively or negatively?)
is_stock_return = (
@@ -70,22 +70,22 @@ class AccountMove(models.Model):
self.move_type == 'out_refund' and (sml.location_id.usage, sml.location_dest_id.usage) == ('internal', 'customer')
)
if is_stock_return:
- returned_qty = min(qties_per_lot[sml.lot_id], qty_done)
+ returned_qty = min(qties_per_lot[sml.lot_id], quantity)
qties_per_lot[sml.lot_id] -= returned_qty
- qty_done = returned_qty - qty_done
+ quantity = returned_qty - quantity
previous_qty_invoiced = previous_qties_invoiced[product]
previous_qty_delivered = previous_qties_delivered[product]
- # If we return more than currently delivered (i.e., qty_done < 0), we remove the surplus
- # from the previously delivered (and qty_done becomes zero). If it's a delivery, we first
+ # If we return more than currently delivered (i.e., quantity < 0), we remove the surplus
+ # from the previously delivered (and quantity becomes zero). If it's a delivery, we first
# try to reach the previous_qty_invoiced
- if float_compare(qty_done, 0, precision_rounding=product_uom.rounding) < 0 or \
+ if float_compare(quantity, 0, precision_rounding=product_uom.rounding) < 0 or \
float_compare(previous_qty_delivered, previous_qty_invoiced, precision_rounding=product_uom.rounding) < 0:
- previously_done = qty_done if is_stock_return else min(previous_qty_invoiced - previous_qty_delivered, qty_done)
+ previously_done = quantity if is_stock_return else min(previous_qty_invoiced - previous_qty_delivered, quantity)
previous_qties_delivered[product] += previously_done
- qty_done -= previously_done
+ quantity -= previously_done
- qties_per_lot[sml.lot_id] += qty_done
+ qties_per_lot[sml.lot_id] += quantity
for lot, qty in qties_per_lot.items():
# access the lot as a superuser in order to avoid an error
diff --git a/addons/sale_stock/models/sale_order_line.py b/addons/sale_stock/models/sale_order_line.py
index 0f453bb4075..3be909b1837 100644
--- a/addons/sale_stock/models/sale_order_line.py
+++ b/addons/sale_stock/models/sale_order_line.py
@@ -62,7 +62,7 @@ class SaleOrderLine(models.Model):
line.qty_available_today = 0
line.free_qty_today = 0
for move in moves:
- line.qty_available_today += move.product_uom._compute_quantity(move.reserved_availability, line.product_uom)
+ line.qty_available_today += move.product_uom._compute_quantity(move.quantity, line.product_uom)
line.free_qty_today += move.product_id.uom_id._compute_quantity(move.forecast_availability, line.product_uom)
line.scheduled_date = line.order_id.commitment_date or line._expected_date()
line.virtual_available_at_date = False
@@ -148,7 +148,7 @@ class SaleOrderLine(models.Model):
if not line.is_expense and line.product_id.type in ['consu', 'product']:
line.qty_delivered_method = 'stock_move'
- @api.depends('move_ids.state', 'move_ids.scrapped', 'move_ids.quantity_done', 'move_ids.product_uom')
+ @api.depends('move_ids.state', 'move_ids.scrapped', 'move_ids.quantity', 'move_ids.product_uom')
def _compute_qty_delivered(self):
super(SaleOrderLine, self)._compute_qty_delivered()
@@ -159,11 +159,11 @@ class SaleOrderLine(models.Model):
for move in outgoing_moves:
if move.state != 'done':
continue
- qty += move.product_uom._compute_quantity(move.quantity_done, line.product_uom, rounding_method='HALF-UP')
+ qty += move.product_uom._compute_quantity(move.quantity, line.product_uom, rounding_method='HALF-UP')
for move in incoming_moves:
if move.state != 'done':
continue
- qty -= move.product_uom._compute_quantity(move.quantity_done, line.product_uom, rounding_method='HALF-UP')
+ qty -= move.product_uom._compute_quantity(move.quantity, line.product_uom, rounding_method='HALF-UP')
line.qty_delivered = qty
@api.model_create_multi
@@ -237,10 +237,10 @@ class SaleOrderLine(models.Model):
qty = 0.0
outgoing_moves, incoming_moves = self._get_outgoing_incoming_moves()
for move in outgoing_moves:
- qty_to_compute = move.quantity_done if move.state == 'done' else move.product_uom_qty
+ qty_to_compute = move.quantity if move.state == 'done' else move.product_uom_qty
qty += move.product_uom._compute_quantity(qty_to_compute, self.product_uom, rounding_method='HALF-UP')
for move in incoming_moves:
- qty_to_compute = move.quantity_done if move.state == 'done' else move.product_uom_qty
+ qty_to_compute = move.quantity if move.state == 'done' else move.product_uom_qty
qty -= move.product_uom._compute_quantity(qty_to_compute, self.product_uom, rounding_method='HALF-UP')
return qty
diff --git a/addons/sale_stock/models/stock.py b/addons/sale_stock/models/stock.py
index a1b1deeba01..46666242b14 100644
--- a/addons/sale_stock/models/stock.py
+++ b/addons/sale_stock/models/stock.py
@@ -106,7 +106,7 @@ class StockPicking(models.Model):
sale_order = move.picking_id.sale_id
# Creates new SO line only when pickings linked to a sale order and
# for moves with qty. done and not already linked to a SO line.
- if not sale_order or move.location_dest_id.usage != 'customer' or move.sale_line_id or not move.quantity_done:
+ if not sale_order or move.location_dest_id.usage != 'customer' or move.sale_line_id or not move.picked:
continue
product = move.product_id
so_line_vals = {
@@ -115,7 +115,7 @@ class StockPicking(models.Model):
'order_id': sale_order.id,
'product_id': product.id,
'product_uom_qty': 0,
- 'qty_delivered': move.quantity_done,
+ 'qty_delivered': move.quantity,
'product_uom': move.product_uom.id,
}
if product.invoice_policy == 'delivery':
diff --git a/addons/sale_stock/tests/test_anglo_saxon_valuation.py b/addons/sale_stock/tests/test_anglo_saxon_valuation.py
index 6edd7b75c4b..7e34b85954e 100644
--- a/addons/sale_stock/tests/test_anglo_saxon_valuation.py
+++ b/addons/sale_stock/tests/test_anglo_saxon_valuation.py
@@ -57,7 +57,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 8,
})
in_move_1._action_confirm()
- in_move_1.quantity_done = 1
+ in_move_1.write({'quantity': 1, 'picked': True})
in_move_1._action_done()
in_move_2 = self.env['stock.move'].create({
'name': 'a',
@@ -69,7 +69,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 10,
})
in_move_2._action_confirm()
- in_move_2.quantity_done = 1
+ in_move_2.write({'quantity': 1, 'picked': True})
in_move_2._action_done()
# -------------------------------------------------------------------------
@@ -127,7 +127,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
wiz = sale_order.picking_ids.button_validate()
wiz = Form(self.env[wiz['res_model']].with_context(wiz['context'])).save()
wiz.process()
@@ -160,7 +160,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
self.product.standard_price = 14.0
# deliver the backorder
- sale_order.picking_ids[0].move_ids.quantity_done = 1
+ sale_order.picking_ids[0].move_ids.write({'quantity': 1, 'picked': True})
sale_order.picking_ids[0].button_validate()
# change the standard price to 16
@@ -199,7 +199,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
wiz = sale_order.picking_ids.button_validate()
wiz = Form(self.env[wiz['res_model']].with_context(wiz['context'])).save()
wiz.process()
@@ -208,7 +208,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
self.product.standard_price = 14.0
# deliver the backorder
- sale_order.picking_ids.filtered('backorder_id').move_ids.quantity_done = 1
+ sale_order.picking_ids.filtered('backorder_id').move_ids.write({'quantity': 1, 'picked': True})
sale_order.picking_ids.filtered('backorder_id').button_validate()
# Invoice the sale order.
@@ -266,7 +266,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
wiz = sale_order.picking_ids.button_validate()
wiz = Form(self.env[wiz['res_model']].with_context(wiz['context'])).save()
wiz.process()
@@ -299,7 +299,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
self.product.standard_price = 14.0
# deliver the backorder
- sale_order.picking_ids[0].move_ids.quantity_done = 1
+ sale_order.picking_ids[0].move_ids.write({'quantity': 1, 'picked': True})
sale_order.picking_ids[0].button_validate()
# change the standard price to 16
@@ -338,7 +338,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
wiz = sale_order.picking_ids.button_validate()
wiz = Form(self.env[wiz['res_model']].with_context(wiz['context'])).save()
wiz.process()
@@ -347,7 +347,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
self.product.standard_price = 14.0
# deliver the backorder
- sale_order.picking_ids.filtered('backorder_id').move_ids.quantity_done = 1
+ sale_order.picking_ids.filtered('backorder_id').move_ids.write({'quantity': 1, 'picked': True})
sale_order.picking_ids.filtered('backorder_id').button_validate()
# Invoice the sale order.
@@ -418,7 +418,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
wiz = sale_order.picking_ids.button_validate()
wiz = Form(self.env[wiz['res_model']].with_context(wiz['context'])).save()
wiz.process()
@@ -456,7 +456,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 2
+ sale_order.picking_ids.move_ids.write({'quantity': 2, 'picked': True})
sale_order.picking_ids.button_validate()
# Invoice the sale order.
@@ -503,7 +503,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
so.action_confirm()
pick = so.picking_ids
- pick.move_ids.write({'quantity_done': 5})
+ pick.move_ids.write({'quantity': 5, 'picked': True})
pick.button_validate()
product.standard_price = 40
@@ -516,7 +516,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
res = return_wiz.create_returns()
return_pick = self.env['stock.picking'].browse(res['res_id'])
- return_pick.move_ids.write({'quantity_done': 1})
+ return_pick.move_ids.write({'quantity': 1, 'picked': True})
return_pick.button_validate()
picking = self.env['stock.picking'].create({
@@ -532,7 +532,8 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'picking_id': picking.id,
'product_id': product.id,
'product_uom': product.uom_id.id,
- 'quantity_done': 1,
+ 'quantity': 1,
+ 'picked': True,
})
picking.button_validate()
@@ -573,7 +574,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
wiz = sale_order.picking_ids.button_validate()
wiz = Form(self.env[wiz['res_model']].with_context(wiz['context'])).save()
wiz.process()
@@ -610,7 +611,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
# Create and confirm a sale order for 2@12
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 2
+ sale_order.picking_ids.move_ids.write({'quantity': 2, 'picked': True})
sale_order.picking_ids.button_validate()
# Invoice the sale order.
@@ -648,7 +649,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
# Create and confirm a sale order for 2@12
sale_order = self._so_and_confirm_two_units()
# Deliver both products (there should be two SML)
- sale_order.picking_ids.move_line_ids.qty_done = 1
+ sale_order.picking_ids.move_line_ids.write({'quantity': 1, 'picked': True})
sale_order.picking_ids.button_validate()
# Invoice one by one
@@ -687,7 +688,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
self.env['stock.quant']._update_available_quantity(self.product, self.company_data['default_warehouse'].lot_stock_id, 2, owner_id=self.partner_b)
sale_order = self._so_and_confirm_two_units()
- sale_order.picking_ids.move_line_ids.qty_done = 2
+ sale_order.picking_ids.move_line_ids.write({'quantity': 2, 'picked': True})
sale_order.picking_ids.button_validate()
invoice = sale_order._create_invoices()
@@ -747,7 +748,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
wiz = sale_order.picking_ids.button_validate()
wiz = Form(self.env[wiz['res_model']].with_context(wiz['context'])).save()
wiz.process()
@@ -790,7 +791,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 2
+ sale_order.picking_ids.move_ids.write({'quantity': 2, 'picked': True})
sale_order.picking_ids.button_validate()
# Invoice the sale order.
@@ -843,7 +844,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
wiz = sale_order.picking_ids.button_validate()
wiz = Form(self.env[wiz['res_model']].with_context(wiz['context'])).save()
wiz.process()
@@ -887,7 +888,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order = self._so_and_confirm_two_units()
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 2
+ sale_order.picking_ids.move_ids.write({'quantity': 2, 'picked': True})
sale_order.picking_ids.button_validate()
# Invoice the sale order.
@@ -927,7 +928,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 10,
})
in_move_1._action_confirm()
- in_move_1.quantity_done = 8
+ in_move_1.write({'quantity': 8, 'picked': True})
in_move_1._action_done()
# Create and confirm a sale order for 2@12
@@ -946,7 +947,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order.action_confirm()
# Deliver 10
- sale_order.picking_ids.move_ids.quantity_done = 10
+ sale_order.picking_ids.move_ids.write({'quantity': 10, 'picked': True})
sale_order.picking_ids.button_validate()
# Make the second receipt
@@ -960,7 +961,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 12,
})
in_move_2._action_confirm()
- in_move_2.quantity_done = 2
+ in_move_2.write({'quantity': 2, 'picked': True})
in_move_2._action_done()
self.assertEqual(self.product.stock_valuation_layer_ids[-1].value, -4) # we sent two at 10 but they should have been sent at 12
self.assertEqual(self.product.stock_valuation_layer_ids[-1].quantity, 0)
@@ -1003,7 +1004,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 8,
})
in_move_1._action_confirm()
- in_move_1.quantity_done = 5
+ in_move_1.write({'quantity': 5, 'picked': True})
in_move_1._action_done()
# +8@12
@@ -1017,7 +1018,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 12,
})
in_move_2._action_confirm()
- in_move_2.quantity_done = 8
+ in_move_2.write({'quantity': 8, 'picked': True})
in_move_2._action_done()
# sale 1@20, deliver, invoice
@@ -1034,7 +1035,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
})],
})
sale_order.action_confirm()
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
sale_order.picking_ids.button_validate()
invoice = sale_order._create_invoices()
invoice.action_post()
@@ -1053,7 +1054,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
})],
})
sale_order.action_confirm()
- sale_order.picking_ids.move_ids.quantity_done = 6
+ sale_order.picking_ids.move_ids.write({'quantity': 6, 'picked': True})
sale_order.picking_ids.button_validate()
invoice = sale_order._create_invoices()
invoice.action_post()
@@ -1081,7 +1082,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 10,
})
in_move_1._action_confirm()
- in_move_1.quantity_done = 8
+ in_move_1.write({'quantity': 8, 'picked': True})
in_move_1._action_done()
# Create and confirm a sale order for 10@12
@@ -1100,7 +1101,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
sale_order.action_confirm()
# Deliver 10
- sale_order.picking_ids.move_ids.quantity_done = 10
+ sale_order.picking_ids.move_ids.write({'quantity': 10, 'picked': True})
sale_order.picking_ids.button_validate()
# Invoice the sale order.
@@ -1118,7 +1119,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 12,
})
in_move_2._action_confirm()
- in_move_2.quantity_done = 2
+ in_move_2.write({'quantity': 2, 'picked': True})
in_move_2._action_done()
# check the last anglo saxon move line
@@ -1143,12 +1144,12 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 10,
})
in_move_1._action_confirm()
- in_move_1.quantity_done = 2
+ in_move_1.write({'quantity': 2, 'picked': True})
in_move_1._action_done()
# Create, confirm and deliver a sale order for 2@12 (SO1)
so_1 = self._so_and_confirm_two_units()
- so_1.picking_ids.move_ids.quantity_done = 2
+ so_1.picking_ids.move_ids.write({'quantity': 2, 'picked': True})
so_1.picking_ids.button_validate()
# Return 1 from SO1
@@ -1161,7 +1162,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
stock_return_picking_action = stock_return_picking.create_returns()
return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
return_pick.action_assign()
- return_pick.move_ids.quantity_done = 1
+ return_pick.move_ids.write({'quantity': 1, 'picked': True})
return_pick._action_done()
# Create, confirm and deliver a sale order for 1@12 (SO2)
@@ -1178,7 +1179,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
})],
})
so_2.action_confirm()
- so_2.picking_ids.move_ids.quantity_done = 1
+ so_2.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
so_2.picking_ids.button_validate()
# Receive 1@20
@@ -1192,7 +1193,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 20,
})
in_move_2._action_confirm()
- in_move_2.quantity_done = 1
+ in_move_2.write({'quantity': 1, 'picked': True})
in_move_2._action_done()
# Re-deliver returned 1 from SO1
@@ -1205,7 +1206,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
stock_redeliver_picking_action = stock_redeliver_picking.create_returns()
redeliver_pick = self.env['stock.picking'].browse(stock_redeliver_picking_action['res_id'])
redeliver_pick.action_assign()
- redeliver_pick.move_ids.quantity_done = 1
+ redeliver_pick.move_ids.write({'quantity': 1, 'picked': True})
redeliver_pick._action_done()
# Invoice the sale orders
@@ -1274,7 +1275,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
})],
})
so_1.action_confirm()
- so_1.picking_ids.move_ids.quantity_done = 12
+ so_1.picking_ids.move_ids.write({'quantity': 12, 'picked': True})
so_1.picking_ids.button_validate()
# Invoice the sale order.
@@ -1317,7 +1318,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 1.0,
})
in_move_1._action_confirm()
- in_move_1.quantity_done = quantity
+ in_move_1.write({'quantity': quantity, 'picked': True})
in_move_1._action_done()
# Create, confirm and deliver a sale order for 12@1.5 with reception (50 * 1.0, 50 * 0.0)(SO2)
@@ -1334,7 +1335,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
})],
})
so_2.action_confirm()
- so_2.picking_ids.move_ids.quantity_done = 12
+ so_2.picking_ids.move_ids.write({'quantity': 12, 'picked': True})
so_2.picking_ids.button_validate()
# Invoice the sale order.
@@ -1384,7 +1385,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': p,
} for p in [10, 20, 60]])
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
# Sell 3 units
@@ -1407,7 +1408,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
picking = so.picking_ids
while picking:
pickings.append(picking)
- picking.move_ids.quantity_done = 1
+ picking.move_ids.write({'quantity': 1, 'picked': True})
action = picking.button_validate()
if isinstance(action, dict):
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
@@ -1428,7 +1429,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 100,
})
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
# Return the second picking (i.e. 1@20)
@@ -1436,7 +1437,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
return_wizard = Form(self.env['stock.return.picking'].with_context(ctx)).save()
return_picking_id, dummy = return_wizard._create_returns()
return_picking = self.env['stock.picking'].browse(return_picking_id)
- return_picking.move_ids.quantity_done = 1
+ return_picking.move_ids.write({'quantity': 1, 'picked': True})
return_picking.button_validate()
# Add a credit note for the returned product
@@ -1478,7 +1479,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': p,
} for p in [10, 20, 60]])
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
# Sell 3 units
@@ -1501,7 +1502,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
picking = so.picking_ids
while picking:
pickings.append(picking)
- picking.move_ids.quantity_done = 1
+ picking.move_ids.write({'quantity': 1, 'picked': True})
action = picking.button_validate()
if isinstance(action, dict):
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
@@ -1522,7 +1523,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': 100,
})
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
# Return the second picking (i.e. 1@20)
@@ -1530,7 +1531,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
return_wizard = Form(self.env['stock.return.picking'].with_context(ctx)).save()
return_picking_id, dummy = return_wizard._create_returns()
return_picking = self.env['stock.picking'].browse(return_picking_id)
- return_picking.move_ids.quantity_done = 1
+ return_picking.move_ids.write({'quantity': 1, 'picked': True})
return_picking.button_validate()
# Create a new invoice for the returned product
@@ -1567,7 +1568,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': p,
} for p in svl_values])
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
so = self.env['sale.order'].create({
@@ -1589,7 +1590,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
invoices = self.env['account.move']
picking = so.picking_ids
while picking:
- picking.move_ids.quantity_done = 1
+ picking.move_ids.write({'quantity': 1, 'picked': True})
action = picking.button_validate()
if isinstance(action, dict):
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
@@ -1657,7 +1658,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
'price_unit': p,
} for p in [10, 50]])
in_moves._action_confirm()
- in_moves.quantity_done = 1
+ in_moves.write({'quantity': 1, 'picked': True})
in_moves._action_done()
so = self.env['sale.order'].create({
@@ -1675,7 +1676,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
so.action_confirm()
picking = so.picking_ids
- picking.move_ids.quantity_done = 1.0
+ picking.move_ids.write({'quantity': 1.0, 'picked': True})
picking.button_validate()
invoice01 = so._create_invoices()
@@ -1714,7 +1715,7 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon):
self.assertEqual(sale_order.order_line.product_uom_qty, 2.0)
# Deliver one.
- sale_order.picking_ids.move_ids.quantity_done = 2
+ sale_order.picking_ids.move_ids.write({'quantity': 2, 'picked': True})
sale_order.picking_ids.button_validate()
svl_am = sale_order.order_line.move_ids.stock_valuation_layer_ids.account_move_id
svl_am.button_draft()
diff --git a/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py b/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py
index 13eb570d8be..ae96b17bd93 100644
--- a/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py
+++ b/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py
@@ -63,7 +63,7 @@ class TestValuationReconciliationCommon(ValuationReconciliationTestCommon):
})
move1._action_confirm()
move1._action_assign()
- move1.move_line_ids.qty_done = 11
+ move1.move_line_ids.write({'quantity': 11, 'picked': True})
move1._action_done()
@@ -112,7 +112,7 @@ class TestValuationReconciliation(TestValuationReconciliationCommon):
stock_return_picking_action = stock_return_picking.create_returns()
return_pick = self.env['stock.picking'].browse(stock_return_picking_action['res_id'])
return_pick.action_assign()
- return_pick.move_ids.quantity_done = 1
+ return_pick.move_ids.write({'quantity': 1, 'picked': True})
return_pick._action_done()
refund_invoice_wiz = self.env['account.move.reversal'].with_context(active_model='account.move', active_ids=[invoice.id]).create({
'reason': 'test_invoice_shipment_refund',
diff --git a/addons/sale_stock/tests/test_sale_order_dates.py b/addons/sale_stock/tests/test_sale_order_dates.py
index 4a2ceb7bd54..e3f5b2c94bf 100644
--- a/addons/sale_stock/tests/test_sale_order_dates.py
+++ b/addons/sale_stock/tests/test_sale_order_dates.py
@@ -82,8 +82,7 @@ class TestSaleExpectedDate(ValuationReconciliationTestCommon):
# Check effective date, it should be date on which the first shipment successfully delivered to customer
picking = sale_order.picking_ids[0]
- for ml in picking.move_line_ids:
- ml.qty_done = ml.reserved_uom_qty
+ picking.move_ids.picked = True
picking._action_done()
self.assertEqual(picking.state, 'done', "Picking not processed correctly!")
self.assertEqual(fields.Date.today(), sale_order.effective_date.date(), "Wrong effective date on sale order!")
diff --git a/addons/sale_stock/tests/test_sale_stock.py b/addons/sale_stock/tests/test_sale_stock.py
index 3dc6dc0acb7..e098d3d8135 100644
--- a/addons/sale_stock/tests/test_sale_stock.py
+++ b/addons/sale_stock/tests/test_sale_stock.py
@@ -67,7 +67,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# deliver partially, check the so's invoice_status and delivered quantities
self.assertEqual(self.so.invoice_status, 'no', 'Sale Stock: so invoice_status should be "nothing to invoice" after invoicing')
pick = self.so.picking_ids
- pick.move_ids.write({'quantity_done': 1})
+ pick.move_ids.write({'quantity': 1, 'picked': True})
wiz_act = pick.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
wiz.process()
@@ -85,7 +85,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
'Sale Stock: so invoice_status should be "nothing to invoice" after partial delivery and invoicing')
self.assertEqual(len(self.so.picking_ids), 2, 'Sale Stock: number of pickings should be 2')
pick_2 = self.so.picking_ids.filtered('backorder_id')
- pick_2.move_ids.write({'quantity_done': 1})
+ pick_2.move_ids.write({'quantity': 1, 'picked': True})
self.assertTrue(pick_2.button_validate(), 'Sale Stock: second picking should be final without need for a backorder')
self.assertEqual(self.so.invoice_status, 'to invoice', 'Sale Stock: so invoice_status should be "to invoice" after complete delivery')
del_qties = [sol.qty_delivered for sol in self.so.order_line]
@@ -164,7 +164,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# deliver, check the delivered quantities
pick = self.so.picking_ids
- pick.move_ids.write({'quantity_done': 2})
+ pick.move_ids.write({'quantity': 2, 'picked': True})
self.assertTrue(pick.button_validate(), 'Sale Stock: complete delivery should not need a backorder')
del_qties = [sol.qty_delivered for sol in self.so.order_line]
del_qties_truth = [2.0 if sol.product_id.type in ['product', 'consu'] else 0.0 for sol in self.so.order_line]
@@ -203,7 +203,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# deliver completely
pick = self.so.picking_ids
- pick.move_ids.write({'quantity_done': 5})
+ pick.move_ids.write({'quantity': 5, 'picked': True})
pick.button_validate()
# Check quantity delivered
@@ -229,7 +229,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
return_pick = self.env['stock.picking'].browse(res['res_id'])
# Validate picking
- return_pick.move_ids.write({'quantity_done': 2})
+ return_pick.move_ids.write({'quantity': 2, 'picked': True})
return_pick.button_validate()
# Check invoice
@@ -272,9 +272,6 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
self.assertEqual(len(self.so.picking_ids), 1)
res_dict = self.so.picking_ids.sorted()[0].button_validate()
wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
- self.assertEqual(wizard._name, 'stock.immediate.transfer')
- res_dict = wizard.process()
- wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
self.assertEqual(wizard._name, 'stock.backorder.confirmation')
wizard.process()
@@ -336,9 +333,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# deliver them
self.assertEqual(len(self.so.picking_ids), 1)
- res_dict = self.so.picking_ids.sorted()[0].button_validate()
- wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
- wizard.process()
+ self.so.picking_ids.sorted()[0].button_validate()
self.assertEqual(self.so.picking_ids.sorted()[0].state, "done")
# update the two original sale order lines
@@ -454,8 +449,8 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
self.assertEqual(move2.product_qty, 12)
# deliver everything
- move1.quantity_done = 24
- move2.quantity_done = 1
+ move1.write({'quantity': 24, 'picked': True})
+ move2.write({'quantity': 1, 'picked': True})
so1.picking_ids.button_validate()
# check the delivered quantity
@@ -502,34 +497,8 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
so1.action_confirm()
self.assertEqual(len(so1.picking_ids.move_ids), 3)
- so1.picking_ids.write({
- 'move_line_ids': [
- (0, 0, {
- 'product_id': item1.id,
- 'reserved_uom_qty': 0,
- 'qty_done': 1,
- 'product_uom_id': uom_dozen.id,
- 'location_id': so1.picking_ids.location_id.id,
- 'location_dest_id': so1.picking_ids.location_dest_id.id,
- }),
- (0, 0, {
- 'product_id': item1.id,
- 'reserved_uom_qty': 0,
- 'qty_done': 1,
- 'product_uom_id': uom_dozen.id,
- 'location_id': so1.picking_ids.location_id.id,
- 'location_dest_id': so1.picking_ids.location_dest_id.id,
- }),
- (0, 0, {
- 'product_id': item1.id,
- 'reserved_uom_qty': 0,
- 'qty_done': 1,
- 'product_uom_id': uom_dozen.id,
- 'location_id': so1.picking_ids.location_id.id,
- 'location_dest_id': so1.picking_ids.location_dest_id.id,
- }),
- ],
- })
+ self.assertEqual(len(so1.picking_ids.move_line_ids), 3)
+ so1.picking_ids.move_ids.picked = True
so1.picking_ids.button_validate()
self.assertEqual(so1.picking_ids.state, 'done')
self.assertEqual(so1.order_line.mapped('qty_delivered'), [1, 1, 1])
@@ -562,9 +531,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
so1.action_confirm()
picking = so1.picking_ids
- wiz_act = picking.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ picking.button_validate()
# Return 5 units
stock_return_picking_form = Form(self.env['stock.return.picking'].with_context(
@@ -580,9 +547,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
})
res = return_wiz.create_returns()
return_pick = self.env['stock.picking'].browse(res['res_id'])
- wiz_act = return_pick.button_validate()
- wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
- wiz.process()
+ return_pick.button_validate()
self.assertEqual(so1.order_line.qty_delivered, 5)
@@ -665,7 +630,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
self.assertTrue(sale_order.picking_ids)
self.assertEqual(sale_order.order_line.qty_delivered, 0)
picking = sale_order.picking_ids
- picking.move_ids.write({'quantity_done': 10})
+ picking.move_ids.write({'quantity': 10, 'picked': True})
picking.button_validate()
# Checks the delivery amount (must be 10).
@@ -682,7 +647,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# Valids the return picking.
res = return_wizard.create_returns()
return_picking = self.env['stock.picking'].browse(res['res_id'])
- return_picking.move_ids.write({'quantity_done': 10})
+ return_picking.move_ids.write({'quantity': 10, 'picked': True})
return_picking.button_validate()
# Checks the delivery amount (must be 0).
self.assertEqual(sale_order.order_line.qty_delivered, 0)
@@ -699,7 +664,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
self.assertTrue(sale_order.picking_ids)
self.assertEqual(sale_order.order_line.qty_delivered, 0)
picking = sale_order.picking_ids
- picking.move_ids.write({'quantity_done': 10})
+ picking.move_ids.write({'quantity': 10, 'picked': True})
picking.button_validate()
# Checks the delivery amount (must be 10).
@@ -716,7 +681,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# Valids the return picking.
res = return_wizard.create_returns()
return_picking = self.env['stock.picking'].browse(res['res_id'])
- return_picking.move_ids.write({'quantity_done': 10})
+ return_picking.move_ids.write({'quantity': 10, 'picked': True})
return_picking.button_validate()
# Checks the delivery amount (must still be 10).
self.assertEqual(sale_order.order_line.qty_delivered, 10)
@@ -748,11 +713,12 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
picking_form = Form(picking)
with picking_form.move_line_ids_without_package.edit(0) as move:
- move.qty_done = 5
+ move.quantity = 5
with picking_form.move_line_ids_without_package.new() as new_move:
new_move.product_id = product_inv_on_order
- new_move.qty_done = 5
+ new_move.quantity = 5
picking = picking_form.save()
+ picking.move_ids.picked = True
picking.button_validate()
# Check a new sale order line was correctly created.
@@ -772,8 +738,8 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# Check the picking didn't change
self.assertRecordValues(sale_order.picking_ids.move_ids, [
- {'product_id': initial_product.id, 'quantity_done': 5},
- {'product_id': product_inv_on_order.id, 'quantity_done': 5},
+ {'product_id': initial_product.id, 'quantity': 5},
+ {'product_id': product_inv_on_order.id, 'quantity': 5},
])
# Creates a second sale order for 3 product invoiced on qty. ordered.
@@ -788,11 +754,12 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
picking_form = Form(picking)
with picking_form.move_line_ids_without_package.edit(0) as move:
- move.qty_done = 5
+ move.quantity = 5
with picking_form.move_line_ids_without_package.new() as new_move:
new_move.product_id = product_inv_on_delivered
- new_move.qty_done = 5
+ new_move.quantity = 5
picking = picking_form.save()
+ picking.move_ids.picked = True
picking.button_validate()
# Check a new sale order line was correctly created.
@@ -837,14 +804,16 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
picking_form = Form(pick)
with picking_form.move_line_ids_without_package.edit(0) as move:
- move.qty_done = 10
+ move.quantity = 10
pick = picking_form.save()
+ pick.move_ids.picked = True
pick.button_validate()
picking_form = Form(delivery)
with picking_form.move_line_ids_without_package.edit(0) as move:
- move.qty_done = 10
+ move.quantity = 10
delivery = picking_form.save()
+ delivery.move_ids.picked = True
delivery.button_validate()
# Check no new sale order line was created.
@@ -865,20 +834,22 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
picking_form = Form(pick)
with picking_form.move_line_ids_without_package.edit(0) as move:
- move.qty_done = 10
+ move.quantity = 10
with picking_form.move_line_ids_without_package.new() as new_move:
new_move.product_id = product_inv_on_order
- new_move.qty_done = 10
+ new_move.quantity = 10
pick = picking_form.save()
+ pick.move_ids.picked = True
pick.button_validate()
picking_form = Form(delivery)
with picking_form.move_line_ids_without_package.edit(0) as move:
- move.qty_done = 10
+ move.quantity = 10
with picking_form.move_line_ids_without_package.new() as new_move:
new_move.product_id = product_inv_on_order
- new_move.qty_done = 10
+ new_move.quantity = 10
delivery = picking_form.save()
+ delivery.move_ids.picked = True
delivery.button_validate()
# Check a new sale order line was correctly created.
@@ -921,7 +892,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# deliver partially
pick = so.picking_ids
- pick.move_ids.write({'quantity_done': 3})
+ pick.move_ids.write({'quantity': 3, 'picked': True})
wiz_act = pick.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
@@ -933,7 +904,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
self.assertEqual(inv_1.state, 'posted', 'invoice should be in posted state')
pick_2 = so.picking_ids.filtered('backorder_id')
- pick_2.move_ids.write({'quantity_done': 2})
+ pick_2.move_ids.write({'quantity': 2, 'picked': True})
pick_2.button_validate()
# create invoice for remaining 2 quantity
@@ -1101,7 +1072,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
})
so.action_confirm()
picking = so.picking_ids[0]
- picking.move_ids.write({'quantity_done': 3.66})
+ picking.move_ids.write({'quantity': 3.66, 'picked': True})
picking.button_validate()
self.assertEqual(so.order_line.mapped('qty_delivered'), [4.0], 'Sale: no conversion error on delivery in different uom"')
@@ -1176,10 +1147,9 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
'product_id': self.product_b.id,
'product_uom_qty': 1,
'product_uom': uom_km_id,
+ 'quantity': 1,
})
- action = picking.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
+ picking.button_validate()
self.assertEqual(so.order_line[1].product_id, self.product_b)
self.assertEqual(so.order_line[1].qty_delivered, 1)
@@ -1201,7 +1171,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# Validate delivery
picking = sale_order.picking_ids
- picking.move_ids.write({'quantity_done': 10})
+ picking.move_ids.write({'quantity': 10, 'picked': True})
picking.button_validate()
# Update the line and check a new delivery is created
@@ -1217,7 +1187,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# Valids the sale order, then valids the delivery.
sale_order.action_confirm()
picking = sale_order.picking_ids
- picking.move_ids.write({'quantity_done': 10})
+ picking.move_ids.write({'quantity': 10, 'picked': True})
picking.button_validate()
# Creates a return from the delivery picking.
@@ -1231,7 +1201,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
# Valids the return picking.
res = return_wizard.create_returns()
return_picking = self.env['stock.picking'].browse(res['res_id'])
- return_picking.move_ids.write({'quantity_done': 2})
+ return_picking.move_ids.write({'quantity': 2, 'picked': True})
return_picking.button_validate()
# Creates a second return from the delivery picking.
@@ -1273,7 +1243,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
so.action_confirm()
_, pack_picking, pick_picking = so.picking_ids
- (pick_picking + pack_picking).move_ids.quantity_done = 5
+ (pick_picking + pack_picking).move_ids.write({'quantity': 5, 'picked': True})
(pick_picking + pack_picking).button_validate()
with Form(so) as so_form:
with so_form.order_line.edit(0) as line:
@@ -1291,7 +1261,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
ret_pack_sm.picking_id.action_assign()
self.assertEqual(ret_pack_sm.state, 'assigned')
- self.assertEqual(ret_pack_sm.move_line_ids.reserved_uom_qty, 2)
+ self.assertEqual(ret_pack_sm.move_line_ids.quantity, 2)
def test_mtso_and_qty_decreasing(self):
"""
@@ -1369,21 +1339,22 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
so.action_confirm()
pick01, ship01 = so.picking_ids
- pick01.move_line_ids.qty_done = 6
+ pick01.move_line_ids.write({'quantity': 6})
+ pick01.move_ids.picked = True
pick01._action_done()
pick02 = pick01.backorder_ids
- ship01.move_line_ids[0].qty_done = 6
+ ship01.move_ids.write({'quantity': 6, 'picked': True})
ship01._action_done()
ship02 = ship01.backorder_ids
so.order_line.product_uom_qty = 7
self.assertRecordValues(so.picking_ids.move_ids.sorted('id'), [
- {'location_id': out_location.id, 'location_dest_id': customer_location.id, 'product_uom_qty': 6.0, 'quantity_done': 6.0, 'state': 'done'},
- {'location_id': stock_location.id, 'location_dest_id': out_location.id, 'product_uom_qty': 6.0, 'quantity_done': 6.0, 'state': 'done'},
- {'location_id': stock_location.id, 'location_dest_id': out_location.id, 'product_uom_qty': 1.0, 'quantity_done': 0.0, 'state': 'assigned'},
- {'location_id': out_location.id, 'location_dest_id': customer_location.id, 'product_uom_qty': 1.0, 'quantity_done': 0.0, 'state': 'waiting'},
+ {'location_id': out_location.id, 'location_dest_id': customer_location.id, 'product_uom_qty': 6.0, 'quantity': 6.0, 'state': 'done'},
+ {'location_id': stock_location.id, 'location_dest_id': out_location.id, 'product_uom_qty': 6.0, 'quantity': 6.0, 'state': 'done'},
+ {'location_id': stock_location.id, 'location_dest_id': out_location.id, 'product_uom_qty': 1.0, 'quantity': 1.0, 'state': 'assigned'},
+ {'location_id': out_location.id, 'location_dest_id': customer_location.id, 'product_uom_qty': 1.0, 'quantity': 0.0, 'state': 'waiting'},
])
self.assertEqual(ship01.move_ids.move_orig_ids, (pick01 | pick02).move_ids)
self.assertEqual(ship02.move_ids.move_orig_ids, (pick01 | pick02).move_ids)
@@ -1435,12 +1406,12 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
so_1 = self._get_new_sale_order()
so_1.action_confirm()
picking_1 = so_1.picking_ids
- picking_1.move_ids.write({'quantity_done': 1})
+ picking_1.move_ids.write({'quantity': 1, 'picked': True})
so_2 = self._get_new_sale_order()
so_2.action_confirm()
picking_2 = so_2.picking_ids
- picking_2.move_ids.write({'quantity_done': 2})
+ picking_2.move_ids.write({'quantity': 2, 'picked': True})
#multi-picking validation
pick = picking_1 | picking_2
@@ -1482,14 +1453,14 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
pack_picking = so_1.picking_ids.filtered(lambda p: p.picking_type_id == warehouse.pack_type_id)
out_picking = so_1.picking_ids.filtered(lambda p: p.picking_type_id == warehouse.out_type_id)
- pick_picking.move_ids.quantity_done = 2
+ pick_picking.move_ids.write({'quantity': 2, 'picked': True})
pick_picking.action_put_in_pack()
backorder_wizard_dict = pick_picking.button_validate()
backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
backorder_wizard.process()
pack_picking.move_line_ids.result_package_id = False
- pack_picking.move_ids.quantity_done = 2
+ pack_picking.move_ids.write({'quantity': 2, 'picked': True})
pack_picking.button_validate()
backorder_wizard_dict = pack_picking.button_validate()
backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
@@ -1500,7 +1471,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
pick_picking_2 = so_1.picking_ids.filtered(lambda x: x.picking_type_id == warehouse.pick_type_id and x.state != 'done')
- pick_picking_2.move_ids.quantity_done = 2
+ pick_picking_2.move_ids.write({'quantity': 2, 'picked': True})
package_2 = pick_picking_2.action_put_in_pack()
backorder_wizard_dict = pick_picking_2.button_validate()
backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
@@ -1511,7 +1482,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
pack_picking_2 = so_1.picking_ids.filtered(lambda p: p.picking_type_id == warehouse.pack_type_id and p.state != 'done')
- pack_picking_2.move_ids.quantity_done = 2
+ pack_picking_2.move_ids.write({'quantity': 2, 'picked': True})
pack_picking_2.button_validate()
backorder_wizard_dict = pack_picking_2.button_validate()
backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
@@ -1533,7 +1504,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
self.ref('sales_team.group_sale_salesman')])]
})
pick.with_user(inventory_admin_user).move_ids.write(
- {'quantity_done': 1})
+ {'quantity': 1, 'picked': True})
res_dict = pick.button_validate()
wizard = Form(self.env[(res_dict.get('res_model'))].with_user(inventory_admin_user).with_context(
res_dict['context'])).save()
@@ -1551,7 +1522,7 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
self.assertEqual(len(so_1.picking_ids), 1)
delivery_picking = so_1.picking_ids
- delivery_picking.move_ids.quantity_done = 2
+ delivery_picking.move_ids.quantity = 2
backorder_wizard_dict = delivery_picking.button_validate()
backorder_wizard = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context'])).save()
backorder_wizard.process_cancel_backorder()
@@ -1590,15 +1561,15 @@ class TestSaleStock(TestSaleCommon, ValuationReconciliationTestCommon):
so.action_confirm()
pick_picking, ship_picking = so.picking_ids
- pick_picking.move_ids.quantity_done = 1.0
+ pick_picking.move_ids.picked = True
so.order_line[0].product_uom_qty = 0
self.assertRecordValues(pick_picking.move_ids, [
- {'product_id': self.product_a.id, 'product_uom_qty': 0, 'quantity_done': 1, 'state': 'assigned'},
- {'product_id': self.product_b.id, 'product_uom_qty': 1, 'quantity_done': 1, 'state': 'assigned'},
+ {'product_id': self.product_a.id, 'product_uom_qty': 0, 'quantity': 1, 'state': 'assigned'},
+ {'product_id': self.product_b.id, 'product_uom_qty': 1, 'quantity': 1, 'state': 'assigned'},
])
self.assertRecordValues(ship_picking.move_ids, [
- {'product_id': self.product_a.id, 'product_uom_qty': 0, 'quantity_done': 0, 'state': 'cancel'},
- {'product_id': self.product_b.id, 'product_uom_qty': 1, 'quantity_done': 0, 'state': 'waiting'},
+ {'product_id': self.product_a.id, 'product_uom_qty': 0, 'quantity': 0, 'state': 'cancel'},
+ {'product_id': self.product_b.id, 'product_uom_qty': 1, 'quantity': 0, 'state': 'waiting'},
])
diff --git a/addons/sale_stock/tests/test_sale_stock_accrued_entries.py b/addons/sale_stock/tests/test_sale_stock_accrued_entries.py
index 166ea97cf6c..9484f3f0d39 100644
--- a/addons/sale_stock/tests/test_sale_stock_accrued_entries.py
+++ b/addons/sale_stock/tests/test_sale_stock_accrued_entries.py
@@ -40,7 +40,7 @@ class TestAccruedStockSaleOrders(AccountTestInvoicingCommon):
def test_sale_stock_accruals(self):
# deliver 2 on 2020-01-02
pick = self.sale_order.picking_ids
- pick.move_ids.write({'quantity_done': 2})
+ pick.move_ids.write({'quantity': 2, 'picked': True})
pick.button_validate()
wiz_act = pick.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
@@ -49,7 +49,7 @@ class TestAccruedStockSaleOrders(AccountTestInvoicingCommon):
# deliver 3 on 2020-01-06
pick = pick.copy()
- pick.move_ids.write({'quantity_done': 3})
+ pick.move_ids.write({'quantity': 3, 'picked': True})
wiz_act = pick.button_validate()
pick.move_ids.write({'date': fields.Date.to_date('2020-01-06')})
@@ -89,7 +89,7 @@ class TestAccruedStockSaleOrders(AccountTestInvoicingCommon):
def test_sale_stock_invoiced_accrued_entries(self):
# deliver 2 on 2020-01-02
pick = self.sale_order.picking_ids
- pick.move_ids.write({'quantity_done': 2})
+ pick.move_ids.write({'quantity': 2, 'picked': True})
pick.button_validate()
wiz_act = pick.button_validate()
wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save()
@@ -103,7 +103,7 @@ class TestAccruedStockSaleOrders(AccountTestInvoicingCommon):
# deliver 3 on 2020-01-06
pick = pick.copy()
- pick.move_ids.write({'quantity_done': 3})
+ pick.move_ids.write({'quantity': 3, 'picked': True})
wiz_act = pick.button_validate()
pick.move_ids.write({'date': fields.Date.to_date('2020-01-06')})
diff --git a/addons/sale_stock/tests/test_sale_stock_report.py b/addons/sale_stock/tests/test_sale_stock_report.py
index d4c8c4d18f0..2b013f30d0a 100644
--- a/addons/sale_stock/tests/test_sale_stock_report.py
+++ b/addons/sale_stock/tests/test_sale_stock_report.py
@@ -142,7 +142,7 @@ class TestSaleStockInvoices(TestSaleCommon):
so.action_confirm()
picking = so.picking_ids
- picking.move_ids.quantity_done = 5
+ picking.move_ids.write({'quantity': 5, 'picked': True})
picking.button_validate()
invoice = so._create_invoices()
@@ -181,7 +181,7 @@ class TestSaleStockInvoices(TestSaleCommon):
invoice.action_post()
picking = so.picking_ids
- picking.move_ids.quantity_done = 4
+ picking.move_ids.write({'quantity': 4, 'picked': True})
picking.button_validate()
html = self.env['ir.actions.report']._render_qweb_html(
@@ -209,11 +209,8 @@ class TestSaleStockInvoices(TestSaleCommon):
so.action_confirm()
picking = so.picking_ids
- picking.move_ids.move_line_ids[0].qty_done = 1
+ picking.move_ids.move_line_ids[0].quantity = 1
picking.button_validate()
- action = picking.button_validate()
- wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
- wizard.process()
invoice01 = so._create_invoices()
with Form(invoice01) as form:
@@ -222,7 +219,7 @@ class TestSaleStockInvoices(TestSaleCommon):
invoice01.action_post()
backorder = picking.backorder_ids
- backorder.move_ids.move_line_ids.qty_done = 1
+ backorder.move_ids.move_line_ids.quantity = 1
backorder.button_validate()
IrActionsReport = self.env['ir.actions.report']
@@ -291,7 +288,7 @@ class TestSaleStockInvoices(TestSaleCommon):
# Deliver 10 x LOT0001
delivery01 = so.picking_ids
- delivery01.move_ids.quantity_done = 10
+ delivery01.move_ids.write({'quantity': 10, 'picked': True})
delivery01.button_validate()
self.assertEqual(delivery01.move_line_ids.lot_id.name, 'LOT0001')
@@ -301,11 +298,12 @@ class TestSaleStockInvoices(TestSaleCommon):
action = return_wizard.create_returns()
pick_return = self.env['stock.picking'].browse(action['res_id'])
- move_form = Form(pick_return.move_ids, view='stock.view_stock_move_nosuggest_operations')
- with move_form.move_line_nosuggest_ids.new() as line:
+ move_form = Form(pick_return.move_ids, view='stock.view_stock_move_operations')
+ with move_form.move_line_ids.edit(0) as line:
line.lot_id = lot01
- line.qty_done = 10
+ line.quantity = 10
move_form.save()
+ pick_return.move_ids.picked = True
pick_return.button_validate()
# Return pick_return
@@ -316,11 +314,12 @@ class TestSaleStockInvoices(TestSaleCommon):
# Deliver 3 x LOT0002
delivery02.do_unreserve()
- move_form = Form(delivery02.move_ids, view='stock.view_stock_move_nosuggest_operations')
- with move_form.move_line_nosuggest_ids.new() as line:
+ move_form = Form(delivery02.move_ids, view='stock.view_stock_move_operations')
+ with move_form.move_line_ids.new() as line:
line.lot_id = lot02
- line.qty_done = 3
+ line.quantity = 3
move_form.save()
+ delivery02.move_ids.picked = True
action = delivery02.button_validate()
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
wizard.process()
@@ -341,14 +340,15 @@ class TestSaleStockInvoices(TestSaleCommon):
# Deliver 5 x LOT0002 + 2 x LOT0003
delivery03 = delivery02.backorder_ids
delivery03.do_unreserve()
- move_form = Form(delivery03.move_ids, view='stock.view_stock_move_nosuggest_operations')
- with move_form.move_line_nosuggest_ids.new() as line:
+ move_form = Form(delivery03.move_ids, view='stock.view_stock_move_operations')
+ with move_form.move_line_ids.new() as line:
line.lot_id = lot02
- line.qty_done = 5
- with move_form.move_line_nosuggest_ids.new() as line:
+ line.quantity = 5
+ with move_form.move_line_ids.new() as line:
line.lot_id = lot03
- line.qty_done = 2
+ line.quantity = 2
move_form.save()
+ delivery03.move_ids.picked = True
delivery03.button_validate()
# Invoice 8 x P
@@ -382,8 +382,9 @@ class TestSaleStockInvoices(TestSaleCommon):
so.action_confirm()
picking = so.picking_ids
- picking.move_ids.move_line_ids[0].qty_done = 1
- picking.move_ids.move_line_ids[1].qty_done = 1
+ picking.move_ids.move_line_ids[0].quantity = 1
+ picking.move_ids.move_line_ids[1].quantity = 1
+ picking.move_ids.picked = True
picking.button_validate()
invoice01 = so._create_invoices()
@@ -408,14 +409,15 @@ class TestSaleStockInvoices(TestSaleCommon):
res = return_wiz.create_returns()
pick_return = self.env['stock.picking'].browse(res['res_id'])
- move_form = Form(pick_return.move_ids, view='stock.view_stock_move_nosuggest_operations')
- with move_form.move_line_nosuggest_ids.new() as line:
+ move_form = Form(pick_return.move_ids, view='stock.view_stock_move_operations')
+ with move_form.move_line_ids.edit(0) as line:
line.lot_id = self.usn01
- line.qty_done = 1
- with move_form.move_line_nosuggest_ids.new() as line:
+ line.quantity = 1
+ with move_form.move_line_ids.edit(1) as line:
line.lot_id = self.usn02
- line.qty_done = 1
+ line.quantity = 1
move_form.save()
+ pick_return.move_ids.picked = True
pick_return.button_validate()
# reversed invoice
@@ -444,7 +446,8 @@ class TestSaleStockInvoices(TestSaleCommon):
so.action_confirm()
picking = so.picking_ids
- picking.move_ids.move_line_ids[0].qty_done = 1
+ picking.move_ids.move_line_ids[0].quantity = 1
+ picking.move_ids.picked = True
picking.button_validate()
invoice01 = so._create_invoices()
diff --git a/addons/sale_stock_margin/tests/test_sale_stock_margin.py b/addons/sale_stock_margin/tests/test_sale_stock_margin.py
index 8720ef2b95c..6787951cbc3 100644
--- a/addons/sale_stock_margin/tests/test_sale_stock_margin.py
+++ b/addons/sale_stock_margin/tests/test_sale_stock_margin.py
@@ -63,7 +63,7 @@ class TestSaleStockMargin(TestStockValuationCommon):
self.assertEqual(order_line.purchase_price, 35)
self.assertEqual(sale_order.margin, 15)
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
sale_order.picking_ids.button_validate()
self.assertEqual(order_line.purchase_price, 35)
@@ -84,7 +84,7 @@ class TestSaleStockMargin(TestStockValuationCommon):
self.assertEqual(order_line.purchase_price, 19.5)
self.assertAlmostEqual(sale_order.margin, 61)
- sale_order.picking_ids.move_ids.quantity_done = 2
+ sale_order.picking_ids.move_ids.write({'quantity': 2, 'picked': True})
sale_order.picking_ids.button_validate()
self.assertAlmostEqual(order_line.purchase_price, 24.5)
@@ -104,7 +104,7 @@ class TestSaleStockMargin(TestStockValuationCommon):
self.assertEqual(order_line.purchase_price, 10)
self.assertAlmostEqual(sale_order.margin, 20)
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
sale_order.picking_ids.button_validate()
self.assertAlmostEqual(order_line.purchase_price, 10)
@@ -125,7 +125,7 @@ class TestSaleStockMargin(TestStockValuationCommon):
self.assertEqual(order_line.purchase_price, 15)
self.assertAlmostEqual(sale_order.margin, 10)
- sale_order.picking_ids.move_ids.quantity_done = 1
+ sale_order.picking_ids.move_ids.write({'quantity': 1, 'picked': True})
res = sale_order.picking_ids.button_validate()
Form(self.env[res['res_model']].with_context(res['context'])).save().process()
@@ -156,8 +156,8 @@ class TestSaleStockMargin(TestStockValuationCommon):
self.assertAlmostEqual(order_line_2.margin, 6 * 4)
self.assertAlmostEqual(sale_order.margin, 58)
- sale_order.picking_ids.move_ids[0].quantity_done = 2
- sale_order.picking_ids.move_ids[1].quantity_done = 3
+ sale_order.picking_ids.move_ids[0].write({'quantity': 2, 'picked': True})
+ sale_order.picking_ids.move_ids[1].write({'quantity': 3, 'picked': True})
res = sale_order.picking_ids.button_validate()
Form(self.env[res['res_model']].with_context(res['context'])).save().process()
@@ -276,11 +276,8 @@ class TestSaleStockMargin(TestStockValuationCommon):
'picking_type_id': incoming_picking_type.id,
'picking_id': picking.id,
})
- picking.action_reset_draft()
picking.action_confirm()
- res_dict = picking.button_validate()
- wizard = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context'])).save()
- wizard.process()
+ picking.button_validate()
self.pricelist.currency_id = new_company_currency.id
partner = self.env['res.partner'].create({'name': 'Super Partner'})
diff --git a/addons/stock/__manifest__.py b/addons/stock/__manifest__.py
index df73ecc532d..d3dbec37697 100644
--- a/addons/stock/__manifest__.py
+++ b/addons/stock/__manifest__.py
@@ -49,7 +49,6 @@
'wizard/stock_change_product_qty_views.xml',
'wizard/stock_picking_return_views.xml',
'wizard/stock_scheduler_compute_views.xml',
- 'wizard/stock_immediate_transfer_views.xml',
'wizard/stock_inventory_conflict.xml',
'wizard/stock_backorder_confirmation_views.xml',
'wizard/stock_quantity_history.xml',
diff --git a/addons/stock/data/stock_demo2.xml b/addons/stock/data/stock_demo2.xml
index e644230b529..2d74b84e454 100644
--- a/addons/stock/data/stock_demo2.xml
+++ b/addons/stock/data/stock_demo2.xml
@@ -87,7 +87,6 @@
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
draft
- False
-
+
-
+
-
+
-
+
-
+
diff --git a/addons/stock/i18n/stock.pot b/addons/stock/i18n/stock.pot
index 1b57be5c2c4..95f17e46229 100644
--- a/addons/stock/i18n/stock.pot
+++ b/addons/stock/i18n/stock.pot
@@ -2566,7 +2566,7 @@ msgid "Do you confirm you want to scrap"
msgstr ""
#. module: stock
-#: model:ir.model.fields,field_description:stock.field_stock_move_line__qty_done
+#: model:ir.model.fields,field_description:stock.field_stock_move_line__quantity
#: model:ir.model.fields,field_description:stock.field_stock_package_level__is_done
#: model:ir.model.fields.selection,name:stock.selection__stock_move__state__done
#: model:ir.model.fields.selection,name:stock.selection__stock_package_level__state__done
diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py
index 4d82f507594..53078cddbd0 100644
--- a/addons/stock/models/product.py
+++ b/addons/stock/models/product.py
@@ -117,7 +117,7 @@ class Product(models.Model):
if product.barcode:
product.valid_ean = check_barcode_encoding(product.barcode.rjust(14, '0'), 'gtin14')
- @api.depends('stock_move_ids.product_qty', 'stock_move_ids.state')
+ @api.depends('stock_move_ids.product_qty', 'stock_move_ids.state', 'stock_move_ids.quantity')
@api.depends_context(
'lot_id', 'owner_id', 'package_id', 'from_date', 'to_date',
'location', 'warehouse',
diff --git a/addons/stock/models/stock_location.py b/addons/stock/models/stock_location.py
index f5d1d2fc2ad..1a8e6b8ea53 100644
--- a/addons/stock/models/stock_location.py
+++ b/addons/stock/models/stock_location.py
@@ -100,7 +100,7 @@ class Location(models.Model):
_sql_constraints = [('barcode_company_uniq', 'unique (barcode,company_id)', 'The barcode for a location must be unique per company!'),
('inventory_freq_nonneg', 'check(cyclic_inventory_frequency >= 0)', 'The inventory frequency (days) for a location must be non-negative')]
- @api.depends('outgoing_move_line_ids.reserved_qty', 'incoming_move_line_ids.reserved_qty',
+ @api.depends('outgoing_move_line_ids.quantity_product_uom', 'incoming_move_line_ids.quantity_product_uom',
'outgoing_move_line_ids.state', 'incoming_move_line_ids.state',
'outgoing_move_line_ids.product_id.weight', 'outgoing_move_line_ids.product_id.weight',
'quant_ids.quantity', 'quant_ids.product_id.weight')
@@ -116,9 +116,9 @@ class Location(models.Model):
location.net_weight += quant.product_id.weight * quant.quantity
location.forecast_weight = location.net_weight
for line in incoming_move_lines:
- location.forecast_weight += line.product_id.weight * line.reserved_qty
+ location.forecast_weight += line.product_id.weight * line.quantity_product_uom
for line in outgoing_move_lines:
- location.forecast_weight -= line.product_id.weight * line.reserved_qty
+ location.forecast_weight -= line.product_id.weight * line.quantity_product_uom
@api.depends('name', 'location_id.complete_name', 'usage')
def _compute_complete_name(self):
@@ -207,7 +207,7 @@ class Location(models.Model):
for f in {'usage', 'scrap_location'}))
reserved_quantities = self.env['stock.move.line'].search_count([
('location_id', 'in', modified_locations.ids),
- ('reserved_qty', '>', 0),
+ ('quantity', '>', 0),
])
if reserved_quantities:
raise UserError(_(
@@ -312,17 +312,16 @@ class Location(models.Model):
('product_id', '=', product.id),
('location_dest_id', 'in', locations.ids),
('state', 'not in', ['draft', 'done', 'cancel'])
- ], ['location_dest_id'], ['reserved_qty:array_agg', 'qty_done:array_agg', 'product_uom_id:recordset'])
+ ], ['location_dest_id'], ['quantity:array_agg', 'product_uom_id:recordset'])
quant_data = self.env['stock.quant']._read_group([
('product_id', '=', product.id),
('location_id', 'in', locations.ids),
], ['location_id'], ['quantity:sum'])
qty_by_location.update({location.id: quantity_sum for location, quantity_sum in quant_data})
- for location_dest, reserved_qty_list, qty_done_list, uoms in move_line_data:
- qty_done = sum(max(ml_uom._compute_quantity(float(qty), product.uom_id), float(qty_reserved))
- for qty_reserved, qty, ml_uom in zip(reserved_qty_list, qty_done_list, uoms))
- qty_by_location[location_dest.id] += qty_done
+ for location_dest, quantity_list, uoms in move_line_data:
+ quantity = sum(ml_uom._compute_quantity(float(qty), product.uom_id) for qty, ml_uom in zip(quantity_list, uoms))
+ qty_by_location[location_dest.id] += quantity
if additional_qty:
for location_id, qty in additional_qty.items():
@@ -379,8 +378,8 @@ class Location(models.Model):
# check if enough space
if package and package.package_type_id:
# check weight
- package_smls = self.env['stock.move.line'].search([('result_package_id', '=', package.id)])
- if self.storage_category_id.max_weight < self.forecast_weight + sum(package_smls.mapped(lambda sml: sml.reserved_qty * sml.product_id.weight)):
+ package_smls = self.env['stock.move.line'].search([('result_package_id', '=', package.id), ('state', 'not in', ['done', 'cancel'])])
+ if self.storage_category_id.max_weight < self.forecast_weight + sum(package_smls.mapped(lambda sml: sml.quantity_product_uom * sml.product_id.weight)):
return False
# check if enough space
package_capacity = self.storage_category_id.package_capacity_ids.filtered(lambda pc: pc.package_type_id == package.package_type_id)
diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py
index 8d0d837be52..6f96e6cedaa 100644
--- a/addons/stock/models/stock_move.py
+++ b/addons/stock/models/stock_move.py
@@ -106,6 +106,9 @@ class StockMove(models.Model):
"* Waiting Availability: The stock move is confirmed but the product can't be reserved.\n"
"* Available: The product of the stock move is reserved.\n"
"* Done: The product has been transferred and the transfer has been confirmed.")
+ picked = fields.Boolean(
+ 'Picked', compute='_compute_picked', inverse='_inverse_picked',
+ store=True, readonly=False, copy=False, default=False)
# used to record the product cost set by the user during a picking confirmation (when costing
# method used is 'average price' or 'real'). Value given in company currency and in product uom.
@@ -134,15 +137,10 @@ class StockMove(models.Model):
picking_type_id = fields.Many2one('stock.picking.type', 'Operation Type', compute='_compute_picking_type_id', store=True, readonly=False, check_company=True)
is_inventory = fields.Boolean('Inventory')
move_line_ids = fields.One2many('stock.move.line', 'move_id')
- move_line_nosuggest_ids = fields.One2many('stock.move.line', 'move_id', domain=['|', ('reserved_qty', '=', 0.0), ('qty_done', '!=', 0.0)])
origin_returned_move_id = fields.Many2one(
'stock.move', 'Origin return move', copy=False, index=True,
help='Move that created the return move', check_company=True)
returned_move_ids = fields.One2many('stock.move', 'origin_returned_move_id', 'All returned moves', help='Optional: all returned moves created from this move')
- reserved_availability = fields.Float(
- 'Quantity Reserved', compute='_compute_reserved_availability',
- digits='Product Unit of Measure',
- readonly=True, help='Quantity that has already been reserved for this move')
availability = fields.Float(
'Forecasted Quantity', compute='_compute_product_availability',
readonly=True, help='Quantity in stock that can still be reserved for this move')
@@ -154,13 +152,11 @@ class StockMove(models.Model):
check_company=True)
warehouse_id = fields.Many2one('stock.warehouse', 'Warehouse', help="the warehouse to consider for the route selection on the next procurement (if any).")
has_tracking = fields.Selection(related='product_id.tracking', string='Product with Tracking')
- quantity_done = fields.Float(
- 'Quantity Done', compute='_quantity_done_compute', digits='Product Unit of Measure',
- inverse='_quantity_done_set', store=True)
+ quantity = fields.Float(
+ 'Quantity', compute='_compute_quantity', digits='Product Unit of Measure', inverse='_set_quantity', store=True)
show_operations = fields.Boolean(related='picking_id.picking_type_id.show_operations')
picking_code = fields.Selection(related='picking_id.picking_type_id.code', readonly=True)
show_details_visible = fields.Boolean('Details Visible', compute='_compute_show_details_visible')
- show_reserved_availability = fields.Boolean('From Supplier', compute='_compute_show_reserved_availability')
product_type = fields.Selection(related='product_id.detailed_type', readonly=True)
additional = fields.Boolean("Whether the move was added after the picking's confirmation", default=False)
is_locked = fields.Boolean(compute='_compute_is_locked', readonly=True)
@@ -178,16 +174,11 @@ class StockMove(models.Model):
forecast_availability = fields.Float('Forecast Availability', compute='_compute_forecast_information', digits='Product Unit of Measure', compute_sudo=True)
forecast_expected_date = fields.Datetime('Forecasted Expected date', compute='_compute_forecast_information', compute_sudo=True)
lot_ids = fields.Many2many('stock.lot', compute='_compute_lot_ids', inverse='_set_lot_ids', string='Serial Numbers', readonly=False)
- reservation_date = fields.Date('Date to Reserve', compute='_compute_reservation_date', store=True,
- help="Computes when a move should be reserved")
+ reservation_date = fields.Date('Date to Reserve', compute='_compute_reservation_date', store=True, help="Computes when a move should be reserved")
product_packaging_id = fields.Many2one('product.packaging', 'Packaging', domain="[('product_id', '=', product_id)]", check_company=True)
- product_packaging_qty = fields.Float(
- string="Reserved Packaging Quantity",
- compute='_compute_product_packaging_qty')
- product_packaging_qty_done = fields.Float(
- string="Done Packaging Quantity",
- compute='_compute_product_packaging_qty_done')
- from_immediate_transfer = fields.Boolean(related="picking_id.immediate_transfer")
+ product_packaging_qty = fields.Float(string="Reserved Packaging Quantity", compute='_compute_product_packaging_qty')
+ product_packaging_quantity = fields.Float(
+ string="Done Packaging Quantity", compute='_compute_product_packaging_quantity')
show_reserved = fields.Boolean(compute='_compute_show_reserved')
show_quant = fields.Boolean("Show Quant", compute="_compute_show_info")
show_lots_m2o = fields.Boolean("Show lot_id", compute="_compute_show_info")
@@ -209,6 +200,16 @@ class StockMove(models.Model):
)
move.display_assign_serial = move.has_tracking == 'serial' and move.display_import_lot
+ @api.depends('move_line_ids.picked', 'state')
+ def _compute_picked(self):
+ for move in self:
+ if move.state == 'done' or any(ml.picked for ml in move.move_line_ids):
+ move.picked = True
+
+ def _inverse_picked(self):
+ for move in self:
+ move.move_line_ids.picked = move.picked
+
@api.depends('picking_id.priority')
def _compute_priority(self):
for move in self:
@@ -242,36 +243,20 @@ class StockMove(models.Model):
for move in self:
if not move.product_id:
move.show_details_visible = False
- elif len(move._get_move_lines()) > 1:
+ elif len(move.move_line_ids) > 1:
move.show_details_visible = True
else:
move.show_details_visible = show_details_visible or move.has_tracking != 'none'
- def _compute_show_reserved_availability(self):
- """ This field is only of use in an attrs in the picking view, in order to hide the
- "available" column if the move is coming from a supplier.
- """
- for move in self:
- move.show_reserved_availability = not move.location_id.usage == 'supplier'
-
- @api.depends('state', 'picking_id.is_locked', 'picking_id.immediate_transfer')
+ @api.depends('state', 'picking_id.is_locked')
def _compute_is_initial_demand_editable(self):
- self.is_initial_demand_editable = False
for move in self:
- if move.state == 'done' and move.picking_id.is_locked:
- move.is_initial_demand_editable = True
- elif move.state not in ('done', 'cancel') and move.picking_id.immediate_transfer:
- move.is_initial_demand_editable = True
- elif move.state == 'draft':
- move.is_initial_demand_editable = True
+ move.is_initial_demand_editable = not move.picking_id.is_locked or move.state == 'draft'
- @api.depends('state', 'picking_id', 'product_id')
+ @api.depends('product_id')
def _compute_is_quantity_done_editable(self):
for move in self:
- if not move.product_id:
- move.is_quantity_done_editable = False
- else:
- move.is_quantity_done_editable = True
+ move.is_quantity_done_editable = move.product_id
@api.depends('picking_id', 'name')
def _compute_reference(self):
@@ -283,15 +268,11 @@ class StockMove(models.Model):
for move in self:
move.move_lines_count = len(move.move_line_ids)
- @api.depends('product_id', 'product_uom', 'product_uom_qty', 'quantity_done', 'state')
+ @api.depends('product_id', 'product_uom', 'product_uom_qty', 'state')
def _compute_product_qty(self):
for move in self:
- if move.state != 'done':
- move.product_qty = move.product_uom._compute_quantity(
- move.product_uom_qty, move.product_id.uom_id, rounding_method='HALF-UP')
- else:
- move.product_qty = move.product_uom._compute_quantity(
- move.quantity_done, move.product_id.uom_id, rounding_method='HALF-UP')
+ move.product_qty = move.product_uom._compute_quantity(
+ move.product_uom_qty, move.product_id.uom_id, rounding_method='HALF-UP')
@api.depends('picking_id.partner_id')
def _compute_partner_id(self):
@@ -306,21 +287,13 @@ class StockMove(models.Model):
continue
move.product_packaging_qty = move.product_packaging_id._compute_qty(move.product_qty)
- @api.depends('product_packaging_id', 'product_uom', 'quantity_done')
- def _compute_product_packaging_qty_done(self):
- self.product_packaging_qty_done = False
+ @api.depends('product_packaging_id', 'product_uom', 'quantity')
+ def _compute_product_packaging_quantity(self):
+ self.product_packaging_quantity = False
for move in self:
if not move.product_packaging_id:
continue
- move.product_packaging_qty_done = move.product_packaging_id._compute_qty(move.quantity_done, move.product_uom)
-
- def _get_move_lines(self):
- """ This will return the move lines to consider when applying _quantity_done_compute on a stock.move.
- In some context, such as MRP, it is necessary to compute quantity_done on filtered sock.move.line."""
- self.ensure_one()
- if not self.show_reserved:
- return self.move_line_nosuggest_ids
- return self.move_line_ids
+ move.product_packaging_quantity = move.product_packaging_id._compute_qty(move.quantity, move.product_uom)
@api.depends('move_orig_ids.date', 'move_orig_ids.state', 'state', 'date')
def _compute_delay_alert_date(self):
@@ -340,16 +313,16 @@ class StockMove(models.Model):
for move in self:
move.show_reserved = move.picking_type_id.show_reserved or move.origin_returned_move_id
- def _quantity_done_sml(self):
+ def _quantity_sml(self):
self.ensure_one()
quantity = 0
- for move_line in self._get_move_lines():
- quantity += move_line.product_uom_id._compute_quantity(move_line.qty_done, self.product_uom, round=False)
+ for move_line in self.move_line_ids:
+ quantity += move_line.product_uom_id._compute_quantity(move_line.quantity, self.product_uom, round=False)
return quantity
- @api.depends('move_line_ids.qty_done', 'move_line_ids.product_uom_id', 'move_line_nosuggest_ids.qty_done')
- def _quantity_done_compute(self):
- """ This field represents the sum of the move lines `qty_done`. It allows the user to know
+ @api.depends('move_line_ids.quantity', 'move_line_ids.product_uom_id')
+ def _compute_quantity(self):
+ """ This field represents the sum of the move lines `quantity`. It allows the user to know
if there is still work to do.
We take care of rounding this value at the general decimal precision and not the rounding
@@ -360,73 +333,55 @@ class StockMove(models.Model):
if not any(self._ids):
# onchange
for move in self:
- move.quantity_done = move._quantity_done_sml()
+ move.quantity = move._quantity_sml()
else:
# compute
move_lines_ids = set()
for move in self:
- move_lines_ids |= set(move._get_move_lines().ids)
+ move_lines_ids |= set(move.move_line_ids.ids)
data = self.env['stock.move.line']._read_group(
[('id', 'in', list(move_lines_ids))],
- ['move_id', 'product_uom_id'], ['qty_done:sum']
+ ['move_id', 'product_uom_id'], ['quantity:sum']
)
- sum_qty_done = defaultdict(float)
- for move, product_uom, qty_done_sum in data:
+ sum_qty = defaultdict(float)
+ for move, product_uom, qty_sum in data:
uom = move.product_uom
- sum_qty_done[move.id] += product_uom._compute_quantity(qty_done_sum, uom, round=False)
+ sum_qty[move.id] += product_uom._compute_quantity(qty_sum, uom, round=False)
for move in self:
- move.quantity_done = sum_qty_done[move.id]
+ move.quantity = sum_qty[move.id]
- def _quantity_done_set(self):
+ def _set_quantity(self):
def _process_decrease(move, quantity):
- """Prioritize decrease the ml without reserved qty"""
- res_mls = move._get_move_lines().sorted(lambda ml: float_is_zero(ml.reserved_uom_qty, precision_rounding=ml.product_uom_id.rounding), reverse=True)
- qty_to_unreserve = move.reserved_availability - move.product_uom_qty
- for ml in res_mls:
+ for ml in move.move_line_ids:
if float_is_zero(quantity, precision_rounding=move.product_uom.rounding):
break
- qty_ml_dec = min(ml.qty_done, ml.product_uom_id._compute_quantity(quantity, ml.product_uom_id, round=False))
+ qty_ml_dec = min(ml.quantity, ml.product_uom_id._compute_quantity(quantity, ml.product_uom_id, round=False))
if float_is_zero(qty_ml_dec, precision_rounding=ml.product_uom_id.rounding):
continue
- ml.qty_done -= qty_ml_dec
+ if float_compare(ml.quantity, qty_ml_dec, precision_rounding=ml.product_uom_id.rounding) == 0 and ml.state not in ['done', 'cancel']:
+ ml.unlink()
+ else:
+ ml.quantity -= qty_ml_dec
quantity -= move.product_uom._compute_quantity(qty_ml_dec, move.product_uom, round=False)
- # Unreserve
- if (not move.picking_id.immediate_transfer and move.reserved_availability < move.product_uom_qty):
- continue
- if float_compare(ml.reserved_uom_qty, ml.qty_done, precision_rounding=ml.product_uom_id.rounding) <= 0:
- continue
- if move.picking_id.immediate_transfer:
- ml.reserved_uom_qty = ml.qty_done
- elif float_compare(qty_to_unreserve, 0, precision_rounding=move.product_uom.rounding) > 0:
- qty_unreserved = min(qty_to_unreserve, ml.reserved_qty - ml.qty_done)
- ml.reserved_uom_qty = ml.reserved_qty - qty_unreserved
- qty_to_unreserve -= qty_unreserved
def _process_increase(move, quantity):
- moves = move
- if move.picking_id and move.picking_id.immediate_transfer:
- moves = move._action_confirm(merge=False)
- # Kits, already handle in action_explode, should be clean in master
- if len(moves) > 1:
- return
- if move.reserved_availability < move.quantity_done and move.state not in ['done', 'cancel']:
- move._action_assign(force_qty=move.quantity_done)
- move._set_quantity_done(quantity)
+ # move._action_assign(quantity)
+ move._set_quantity_done(move.quantity)
err = []
for move in self:
- uom_qty = float_round(move.quantity_done, precision_rounding=move.product_uom.rounding, rounding_method='HALF-UP')
+ uom_qty = float_round(move.quantity, precision_rounding=move.product_uom.rounding, rounding_method='HALF-UP')
precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
- qty = float_round(move.quantity_done, precision_digits=precision_digits, rounding_method='HALF-UP')
+ qty = float_round(move.quantity, precision_digits=precision_digits, rounding_method='HALF-UP')
if float_compare(uom_qty, qty, precision_digits=precision_digits) != 0:
err.append(_("""
The quantity done for the product %s doesn't respect the rounding precision defined on the unit of measure %s.
Please change the quantity done or the rounding precision of your unit of measure.""",
move.product_id.display_name, move.product_uom.display_name))
continue
- delta_qty = move.quantity_done - move._quantity_done_sml()
+ delta_qty = move.quantity - move._quantity_sml()
if float_compare(delta_qty, 0, precision_rounding=move.product_uom.rounding) > 0:
_process_increase(move, delta_qty)
elif float_compare(delta_qty, 0, precision_rounding=move.product_uom.rounding) < 0:
@@ -441,26 +396,6 @@ Please change the quantity done or the rounding precision of your unit of measur
detect errors. """
raise UserError(_('The requested operation cannot be processed because of a programming error setting the `product_qty` field instead of the `product_uom_qty`.'))
- @api.depends('move_line_ids.reserved_qty')
- def _compute_reserved_availability(self):
- """ Fill the `availability` field on a stock move, which is the actual reserved quantity
- and is represented by the aggregated `product_qty` on the linked move lines. If the move
- is force assigned, the value will be 0.
- """
- if not any(self._ids):
- # onchange
- for move in self:
- reserved_availability = sum(move.move_line_ids.mapped('reserved_qty'))
- move.reserved_availability = move.product_id.uom_id._compute_quantity(
- reserved_availability, move.product_uom, rounding_method='HALF-UP')
- else:
- # compute
- result = {move.id: reserved_qty for move, reserved_qty in
- self.env['stock.move.line']._read_group([('move_id', 'in', self.ids)], ['move_id'], ['reserved_qty:sum'])}
- for move in self:
- move.reserved_availability = move.product_id.uom_id._compute_quantity(
- result.get(move.id, 0.0), move.product_uom, rounding_method='HALF-UP')
-
@api.depends('state', 'product_id', 'product_qty', 'location_id')
def _compute_product_availability(self):
""" Fill the `availability` field on a stock move, which is the quantity to potentially
@@ -474,7 +409,7 @@ Please change the quantity done or the rounding precision of your unit of measur
total_availability = self.env['stock.quant']._get_available_quantity(move.product_id, move.location_id) if move.product_id else 0.0
move.availability = min(move.product_qty, total_availability)
- @api.depends('product_id', 'product_qty', 'picking_type_id', 'reserved_availability', 'priority', 'state', 'product_uom_qty', 'location_id')
+ @api.depends('product_id', 'product_qty', 'picking_type_id', 'quantity', 'priority', 'state', 'product_uom_qty', 'location_id')
def _compute_forecast_information(self):
""" Compute forecasted information of the related product by warehouse."""
self.forecast_availability = False
@@ -512,7 +447,7 @@ Please change the quantity done or the rounding precision of your unit of measur
if move._is_consuming():
if move.state == 'assigned':
move.forecast_availability = move.product_uom._compute_quantity(
- move.reserved_availability, move.product_id.uom_id, rounding_method='HALF-UP')
+ move.quantity, move.product_id.uom_id, rounding_method='HALF-UP')
elif move.state == 'draft':
# for move _is_consuming and in draft -> the forecast_availability > 0 if in stock
move.forecast_availability = virtual_available_dict[key_virtual_available(move)][move.product_id.id] - move.product_qty
@@ -552,33 +487,27 @@ Please change the quantity done or the rounding precision of your unit of measur
else:
move_update.date_deadline = new_deadline
- @api.depends('move_line_ids.lot_id', 'move_line_ids.qty_done')
+ @api.depends('move_line_ids.lot_id', 'move_line_ids.quantity')
def _compute_lot_ids(self):
- domain_nosuggest = [('move_id', 'in', self.ids), ('lot_id', '!=', False), '|', ('qty_done', '!=', 0.0), ('reserved_qty', '=', 0.0)]
- domain_suggest = [('move_id', 'in', self.ids), ('lot_id', '!=', False), ('qty_done', '!=', 0.0)]
- lots_by_move_id_list = []
- for domain in [domain_nosuggest, domain_suggest]:
- lots_by_move_id = self.env['stock.move.line']._read_group(
- domain,
- ['move_id'], ['lot_id:array_agg'],
- )
- lots_by_move_id_list.append({move.id: lot_ids for move, lot_ids in lots_by_move_id})
+ domain = [('move_id', 'in', self.ids), ('lot_id', '!=', False), ('quantity', '!=', 0.0)]
+ lots_by_move_id = self.env['stock.move.line']._read_group(
+ domain,
+ ['move_id'], ['lot_id:array_agg'],
+ )
+ lots_by_move_id = {move.id: lot_ids for move, lot_ids in lots_by_move_id}
for move in self:
- move.lot_ids = lots_by_move_id_list[0 if move.show_reserved else 1].get(move._origin.id, [])
+ move.lot_ids = lots_by_move_id.get(move._origin.id, [])
def _set_lot_ids(self):
for move in self:
if move.product_id.tracking != 'serial':
continue
move_lines_commands = []
- if not move.show_reserved:
- mls = move.move_line_nosuggest_ids
- else:
- mls = move.move_line_ids
+ mls = move.move_line_ids
mls_with_lots = mls.filtered(lambda ml: ml.lot_id)
mls_without_lots = (mls - mls_with_lots)
for ml in mls_with_lots:
- if ml.qty_done and ml.lot_id not in move.lot_ids:
+ if ml.quantity and ml.lot_id not in move.lot_ids:
move_lines_commands.append((2, ml.id))
ls = move.move_line_ids.lot_id
for lot in move.lot_ids:
@@ -589,7 +518,7 @@ Please change the quantity done or the rounding precision of your unit of measur
'lot_name': lot.name,
'lot_id': lot.id,
'product_uom_id': move.product_id.uom_id.id,
- 'qty_done': 1,
+ 'quantity': 1,
}))
mls_without_lots -= move_line
else: # No line without serial number, creates a new one.
@@ -597,11 +526,11 @@ Please change the quantity done or the rounding precision of your unit of measur
move_line_vals['lot_id'] = lot.id
move_line_vals['lot_name'] = lot.name
move_line_vals['product_uom_id'] = move.product_id.uom_id.id
- move_line_vals['qty_done'] = 1
+ move_line_vals['quantity'] = 1
move_lines_commands.append((0, 0, move_line_vals))
else:
move_line = move.move_line_ids.filtered(lambda line: line.lot_id.id == lot.id)
- move_line.qty_done = 1
+ move_line.quantity = 1
move.write({'move_line_ids': move_lines_commands})
@api.depends('picking_type_id', 'date', 'priority', 'state')
@@ -657,12 +586,8 @@ Please change the quantity done or the rounding precision of your unit of measur
picking_id = self.env['stock.picking'].browse(self.env.context['default_picking_id'])
if picking_id.state == 'done':
defaults['state'] = 'done'
- defaults['product_uom_qty'] = 0.0
defaults['additional'] = True
elif picking_id.state not in ['cancel', 'draft', 'done']:
- if picking_id.immediate_transfer:
- defaults['state'] = 'assigned'
- defaults['product_uom_qty'] = 0.0
defaults['additional'] = True # to trigger `_autoconfirm_picking`
return defaults
@@ -677,11 +602,8 @@ Please change the quantity done or the rounding precision of your unit of measur
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
- if (vals.get('quantity_done') or vals.get('move_line_ids')) and 'lot_ids' in vals:
+ if (vals.get('quantity') or vals.get('move_line_ids')) and 'lot_ids' in vals:
vals.pop('lot_ids')
- picking_id = self.env['stock.picking'].browse(vals.get('picking_id'))
- if picking_id and picking_id.immediate_transfer and not vals.get('qty_done'):
- vals['state'] = 'assigned'
return super().create(vals_list)
def write(self, vals):
@@ -689,8 +611,10 @@ Please change the quantity done or the rounding precision of your unit of measur
# messages according to the state of the stock.move records.
receipt_moves_to_reassign = self.env['stock.move']
move_to_recompute_state = self.env['stock.move']
- if 'quantity_done' in vals and any(move.state == 'cancel' for move in self):
- raise UserError(_('You cannot change a cancelled stock move, create a new line instead.'))
+ move_to_confirm = self.env['stock.move']
+ if 'quantity' in vals:
+ if any(move.state == 'cancel' for move in self):
+ raise UserError(_('You cannot change a cancelled stock move, create a new line instead.'))
if 'product_uom' in vals and any(move.state == 'done' for move in self):
raise UserError(_('You cannot change the UoM for a stock move that has been set to \'Done\'.'))
if 'product_uom_qty' in vals:
@@ -700,16 +624,17 @@ Please change the quantity done or the rounding precision of your unit of measur
self.env['stock.move.line']._log_message(move.picking_id, move, 'stock.track_move_template', vals)
if self.env.context.get('do_not_unreserve') is None:
move_to_unreserve = self.filtered(
- lambda m: m.state not in ['draft', 'done', 'cancel'] and float_compare(m.reserved_availability, vals.get('product_uom_qty'), precision_rounding=m.product_uom.rounding) == 1
+ lambda m: m.state not in ['draft', 'done', 'cancel'] and float_compare(m.quantity, vals.get('product_uom_qty'), precision_rounding=m.product_uom.rounding) == 1
)
move_to_unreserve._do_unreserve()
(self - move_to_unreserve).filtered(lambda m: m.state == 'assigned').write({'state': 'partially_available'})
# When editing the initial demand, directly run again action assign on receipt moves.
receipt_moves_to_reassign |= move_to_unreserve.filtered(lambda m: m.location_id.usage == 'supplier')
- receipt_moves_to_reassign |= (self - move_to_unreserve).filtered(lambda m:
- m.location_id.usage == 'supplier'
- and m.state in ('partially_available', 'assigned')
- and not m.picking_id.immediate_transfer)
+ receipt_moves_to_reassign |= (self - move_to_unreserve).filtered(
+ lambda m:
+ m.location_id.usage == 'supplier' and
+ m.state in ('partially_available', 'assigned')
+ )
move_to_recompute_state |= self - move_to_unreserve - receipt_moves_to_reassign
# propagate product_packaging_id changes in the stock move chain
if 'product_packaging_id' in vals:
@@ -717,10 +642,13 @@ Please change the quantity done or the rounding precision of your unit of measur
if 'date_deadline' in vals:
self._set_date_deadline(vals.get('date_deadline'))
if 'move_orig_ids' in vals:
- move_to_recompute_state |= self
+ move_to_recompute_state |= self.filtered(lambda m: m.state not in ['draft', 'cance', 'done'])
+
res = super(StockMove, self).write(vals)
if move_to_recompute_state:
move_to_recompute_state._recompute_state()
+ if move_to_confirm:
+ move_to_confirm._action_assign()
if receipt_moves_to_reassign:
receipt_moves_to_reassign._action_assign()
return res
@@ -784,14 +712,7 @@ Please change the quantity done or the rounding precision of your unit of measur
checked on the picking type.
"""
self.ensure_one()
- # If "show suggestions" is not checked on the picking type, we have to filter out the
- # reserved move lines. We do this by displaying `move_line_nosuggest_ids`. We use
- # different views to display one field or another so that the webclient doesn't have to
- # fetch both.
- if self.from_immediate_transfer:
- view = self.env.ref('stock.view_stock_move_operations_immediate')
- else:
- view = self.env.ref('stock.view_stock_move_operations')
+ view = self.env.ref('stock.view_stock_move_operations')
return {
'name': _('Detailed Operations'),
@@ -823,11 +744,7 @@ Please change the quantity done or the rounding precision of your unit of measur
since there's no way to undo the action.
"""
self.ensure_one()
- if self.show_reserved:
- move_lines = self.move_line_ids
- else:
- move_lines = self.move_line_nosuggest_ids
- move_lines.unlink()
+ self.move_line_ids.unlink()
return self.action_show_details()
def action_assign_serial(self):
@@ -870,18 +787,16 @@ Please change the quantity done or the rounding precision of your unit of measur
moves_to_unreserve.add(move.id)
moves_to_unreserve = self.env['stock.move'].browse(moves_to_unreserve)
- ml_to_update, ml_to_unlink = OrderedSet(), OrderedSet()
+ ml_to_unlink = OrderedSet()
moves_not_to_recompute = OrderedSet()
for ml in moves_to_unreserve.move_line_ids:
- if ml.qty_done:
- ml_to_update.add(ml.id)
- else:
- ml_to_unlink.add(ml.id)
+ if ml.picked:
moves_not_to_recompute.add(ml.move_id.id)
- ml_to_update, ml_to_unlink = self.env['stock.move.line'].browse(ml_to_update), self.env['stock.move.line'].browse(ml_to_unlink)
+ continue
+ ml_to_unlink.add(ml.id)
+ ml_to_unlink = self.env['stock.move.line'].browse(ml_to_unlink)
moves_not_to_recompute = self.env['stock.move'].browse(moves_not_to_recompute)
- ml_to_update.write({'reserved_uom_qty': 0})
ml_to_unlink.unlink()
# `write` on `stock.move.line` doesn't call `_recompute_state` (unlike to `unlink`),
# so it must be called for each move where no move line has been deleted.
@@ -895,14 +810,10 @@ Please change the quantity done or the rounding precision of your unit of measur
self.ensure_one()
if not location_id:
location_id = self.location_dest_id
-
lot_names = self.env['stock.lot'].generate_lot_names(next_serial, next_serial_count or self.next_serial_count)
- field_data = [{'lot_name': lot_name['lot_name'], 'qty_done': lot_name.get('qty_done', 1)} for lot_name in lot_names]
+ field_data = [{'lot_name': lot_name['lot_name'], 'quantity': 1} for lot_name in lot_names]
move_lines_commands = self._generate_serial_move_line_commands(field_data)
- if self.show_reserved:
- self.move_line_ids = move_lines_commands
- else:
- self.move_line_nosuggest_ids = move_lines_commands
+ self.move_line_ids = move_lines_commands
return True
@api.model
@@ -921,7 +832,7 @@ Please change the quantity done or the rounding precision of your unit of measur
for lot_text in split_lines:
move_line_vals = {
'lot_name': lot_text,
- 'qty_done': 1,
+ 'quantity': 1,
}
# Semicolons are also used for separation but for convenience we
# replace them to work only with tabs.
@@ -961,11 +872,11 @@ Please change the quantity done or the rounding precision of your unit of measur
elif mode == 'import':
lot_names = self.split_lots(lot_text)
for lot in lot_names:
- if not lot.get('qty_done'):
- lot['qty_done'] = 1
+ if not lot.get('quantity'):
+ lot['quantity'] = 1
loc_dest = self.env['stock.location'].browse(default_vals['location_dest_id'])
product = self.env['product.product'].browse(default_vals['product_id'])
- loc_dest = loc_dest._get_putaway_strategy(product, lot['qty_done'])
+ loc_dest = loc_dest._get_putaway_strategy(product, lot['quantity'])
vals_list.append({**default_vals,
**lot,
'location_dest_id': loc_dest.id,
@@ -1122,7 +1033,7 @@ Please change the quantity done or the rounding precision of your unit of measur
moves_to_unlink.sudo().unlink()
if moves_to_cancel:
- moves_to_cancel.filtered(lambda m: float_is_zero(m.quantity_done, precision_rounding=m.product_uom.rounding))._action_cancel()
+ moves_to_cancel.filtered(lambda m: not m.picked)._action_cancel()
return (self | merged_moves) - moves_to_unlink
@@ -1184,9 +1095,9 @@ Please change the quantity done or the rounding precision of your unit of measur
@api.onchange('lot_ids')
def _onchange_lot_ids(self):
- quantity_done = sum(ml.product_uom_id._compute_quantity(ml.qty_done, self.product_uom) for ml in self.move_line_ids.filtered(lambda ml: not ml.lot_id and ml.lot_name))
- quantity_done += self.product_id.uom_id._compute_quantity(len(self.lot_ids), self.product_uom)
- self.update({'quantity_done': quantity_done})
+ quantity = sum(ml.quantity_product_uom for ml in self.move_line_ids.filtered(lambda ml: not ml.lot_id and ml.lot_name))
+ quantity += self.product_id.uom_id._compute_quantity(len(self.lot_ids), self.product_uom)
+ self.update({'quantity': quantity})
quants = self.env['stock.quant'].search([('product_id', '=', self.product_id.id),
('lot_id', 'in', self.lot_ids.ids),
@@ -1286,7 +1197,7 @@ Please change the quantity done or the rounding precision of your unit of measur
Called when user want to create and assign multiple serial numbers in
one time (using the button/wizard or copy-paste a list in the field).
- :param field_data: A list containing dict with at least `lot_name` and `qty_done`
+ :param field_data: A list containing dict with at least `lot_name` and `quantity`
:type field_data: list
:param origin_move_line: A move line to duplicate the value from, empty record by default
:type origin_move_line: record of :class:`stock.move.line`
@@ -1303,8 +1214,7 @@ Please change the quantity done or the rounding precision of your unit of measur
'product_uom_id': self.product_id.uom_id.id,
}
# Select the right move lines depending of the picking type's configuration.
- move_lines = self['move_line_ids' if self.show_reserved else 'move_line_nosuggest_ids']
- move_lines = move_lines.filtered(lambda ml: not ml.lot_id and not ml.lot_name)
+ move_lines = self.move_line_ids.filtered(lambda ml: not ml.lot_id and not ml.lot_name)
if origin_move_line:
# Copies `owner_id` and `package_id` if new move lines are created from an existing one.
@@ -1316,22 +1226,22 @@ Please change the quantity done or the rounding precision of your unit of measur
move_lines_commands = []
qty_by_location = defaultdict(float)
for command_vals in field_data:
- qty_done = command_vals['qty_done']
+ quantity = command_vals['quantity']
# We write the lot name on an existing move line (if we have still one)...
if move_lines:
move_lines_commands.append(Command.update(move_lines[0].id, command_vals))
- qty_by_location[move_lines[0].location_dest_id.id] += qty_done
+ qty_by_location[move_lines[0].location_dest_id.id] += quantity
move_lines = move_lines[1:]
# ... or create a new move line with the serial name.
else:
- loc = loc_dest or self.location_dest_id._get_putaway_strategy(self.product_id, quantity=qty_done, packaging=self.product_packaging_id, additional_qty=qty_by_location)
+ loc = loc_dest or self.location_dest_id._get_putaway_strategy(self.product_id, quantity=quantity, packaging=self.product_packaging_id, additional_qty=qty_by_location)
new_move_line_vals = {
**move_line_vals,
**command_vals,
'location_dest_id': loc.id
}
move_lines_commands.append(Command.create(new_move_line_vals))
- qty_by_location[loc.id] += qty_done
+ qty_by_location[loc.id] += quantity
return move_lines_commands
def _get_formating_options(self, strings):
@@ -1362,8 +1272,6 @@ Please change the quantity done or the rounding precision of your unit of measur
'picking_type_id': self.mapped('picking_type_id').id,
'location_id': self.mapped('location_id').id,
'location_dest_id': self.mapped('location_dest_id').id,
- 'state': 'draft',
- 'immediate_transfer': False,
}
def _should_be_assigned(self):
@@ -1415,7 +1323,7 @@ Please change the quantity done or the rounding precision of your unit of measur
# assign picking in batch for all confirmed move that share the same details
for moves_ids in to_assign.values():
self.browse(moves_ids).with_context(clean_context(self.env.context))._assign_picking()
- new_push_moves = self.filtered(lambda m: not m.picking_id.immediate_transfer)._push_apply()
+ new_push_moves = self._push_apply()
self._check_company()
moves = self
if merge:
@@ -1511,9 +1419,9 @@ Please change the quantity done or the rounding precision of your unit of measur
uom_quantity = float_round(uom_quantity, precision_digits=rounding)
uom_quantity_back_to_product_uom = self.product_uom._compute_quantity(uom_quantity, self.product_id.uom_id, rounding_method='HALF-UP')
if float_compare(quantity, uom_quantity_back_to_product_uom, precision_digits=rounding) == 0:
- vals = dict(vals, reserved_uom_qty=uom_quantity)
+ vals = dict(vals, quantity=uom_quantity)
else:
- vals = dict(vals, reserved_uom_qty=quantity, product_uom_id=self.product_id.uom_id.id)
+ vals = dict(vals, quantity=quantity, product_uom_id=self.product_id.uom_id.id)
package = None
if reserved_quant:
package = reserved_quant.package_id
@@ -1557,7 +1465,7 @@ Please change the quantity done or the rounding precision of your unit of measur
uom_quantity = float_round(uom_quantity, precision_digits=rounding)
uom_quantity_back_to_product_uom = to_update.product_uom_id._compute_quantity(uom_quantity, self.product_id.uom_id, rounding_method='HALF-UP')
if to_update and float_compare(quantity, uom_quantity_back_to_product_uom, precision_digits=rounding) == 0:
- to_update.with_context(reserved_quant=reserved_quant).reserved_uom_qty += uom_quantity
+ to_update.with_context(reserved_quant=reserved_quant).quantity += uom_quantity
else:
if self.product_id.tracking == 'serial':
vals_list = self._add_serial_move_line_to_vals_list(reserved_quant, quantity)
@@ -1590,10 +1498,10 @@ Please change the quantity done or the rounding precision of your unit of measur
grouped_move_lines_in = {}
for k, g in groupby(move_lines_in, key=_keys_in_groupby):
- qty_done = 0
+ quantity = 0
for ml in g:
- qty_done += ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id)
- grouped_move_lines_in[k] = qty_done
+ quantity += ml.product_uom_id._compute_quantity(ml.quantity, ml.product_id.uom_id)
+ grouped_move_lines_in[k] = quantity
return grouped_move_lines_in
@@ -1614,12 +1522,12 @@ Please change the quantity done or the rounding precision of your unit of measur
grouped_move_lines_out = {}
for k, g in groupby(move_lines_out_done, key=_keys_out_groupby):
- qty_done = 0
+ quantity = 0
for ml in g:
- qty_done += ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id)
- grouped_move_lines_out[k] = qty_done
+ quantity += ml.product_uom_id._compute_quantity(ml.quantity, ml.product_id.uom_id)
+ grouped_move_lines_out[k] = quantity
for k, g in groupby(move_lines_out_reserved, key=_keys_out_groupby):
- grouped_move_lines_out[k] = sum(self.env['stock.move.line'].concat(*list(g)).mapped('reserved_qty'))
+ grouped_move_lines_out[k] = sum(self.env['stock.move.line'].concat(*list(g)).mapped('quantity'))
return grouped_move_lines_out
@@ -1642,7 +1550,8 @@ Please change the quantity done or the rounding precision of your unit of measur
partially_available_moves_ids = OrderedSet()
# Read the `reserved_availability` field of the moves out of the loop to prevent unwanted
# cache invalidation when actually reserving the move.
- reserved_availability = {move: move.reserved_availability for move in self}
+ reserved_availability = {move: move.quantity for move in self}
+
roundings = {move: move.product_id.uom_id.rounding for move in self}
move_line_vals_list = []
# Once the quantities are assigned, we want to find a better destination location thanks
@@ -1650,17 +1559,21 @@ Please change the quantity done or the rounding precision of your unit of measur
moves_to_redirect = OrderedSet()
moves_to_assign = self
if not force_qty:
- moves_to_assign = self.filtered(lambda m: m.state in ['confirmed', 'waiting', 'partially_available'])
+ moves_to_assign = moves_to_assign.filtered(
+ lambda m: not m.picked and m.state in ['confirmed', 'waiting', 'partially_available']
+ )
moves_to_reserve = moves_to_assign.filtered(lambda m: not m._should_bypass_reservation())
quants_by_product = self.env['stock.quant']._get_quants_by_products_locations(moves_to_reserve.product_id, moves_to_reserve.location_id)
for move in moves_to_assign:
rounding = roundings[move]
if not force_qty:
- missing_reserved_uom_quantity = move.product_uom_qty
+ missing_reserved_uom_quantity = move.product_uom_qty - reserved_availability[move]
else:
missing_reserved_uom_quantity = force_qty
- missing_reserved_uom_quantity -= reserved_availability[move]
+ if float_compare(missing_reserved_uom_quantity, 0, precision_rounding=rounding) <= 0:
+ assigned_moves_ids.add(move.id)
+ continue
missing_reserved_quantity = move.product_uom._compute_quantity(missing_reserved_uom_quantity, move.product_id.uom_id, rounding_method='HALF-UP')
quants = quants_by_product[move.product_id.id]
if move._should_bypass_reservation():
@@ -1690,11 +1603,13 @@ Please change the quantity done or the rounding precision of your unit of measur
ml.location_id == move.location_id and
ml.location_dest_id == move.location_dest_id and
ml.picking_id == move.picking_id and
+ not ml.picked and
not ml.lot_id and
+ not ml.result_package_id and
not ml.package_id and
not ml.owner_id)
if to_update:
- to_update[0].reserved_uom_qty += move.product_id.uom_id._compute_quantity(
+ to_update[0].quantity += move.product_id.uom_id._compute_quantity(
missing_reserved_quantity, move.product_uom, rounding_method='HALF-UP')
else:
move_line_vals_list.append(move._prepare_move_line_vals(quantity=missing_reserved_quantity))
@@ -1724,17 +1639,17 @@ Please change the quantity done or the rounding precision of your unit of measur
else:
# Check what our parents brought and what our siblings took in order to
# determine what we can distribute.
- # `qty_done` is in `ml.product_uom_id` and, as we will later increase
+ # `quantity` is in `ml.product_uom_id` and, as we will later increase
# the reserved quantity on the quants, convert it here in
# `product_id.uom_id` (the UOM of the quants is the UOM of the product).
available_move_lines = move._get_available_move_lines(assigned_moves_ids, partially_available_moves_ids)
if not available_move_lines:
continue
- for move_line in move.move_line_ids.filtered(lambda m: m.reserved_qty):
+ for move_line in move.move_line_ids.filtered(lambda m: m.quantity):
if available_move_lines.get((move_line.location_id, move_line.lot_id, move_line.result_package_id, move_line.owner_id)):
- available_move_lines[(move_line.location_id, move_line.lot_id, move_line.result_package_id, move_line.owner_id)] -= move_line.reserved_qty
+ available_move_lines[(move_line.location_id, move_line.lot_id, move_line.result_package_id, move_line.owner_id)] -= move_line.quantity
for (location_id, lot_id, package_id, owner_id), quantity in available_move_lines.items():
- need = move.product_qty - sum(move.move_line_ids.mapped('reserved_qty'))
+ need = move.product_qty - sum(move.move_line_ids.mapped('quantity'))
# `quantity` is what is brought by chained done move lines. We double check
# here this quantity is available on the quants themselves. If not, this
# could be the result of an inventory adjustment that removed totally of
@@ -1764,6 +1679,7 @@ Please change the quantity done or the rounding precision of your unit of measur
if any(move.state == 'done' and not move.scrapped for move in self):
raise UserError(_('You cannot cancel a stock move that has been set to \'Done\'. Create a return in order to reverse the moves which took place.'))
moves_to_cancel = self.filtered(lambda m: m.state != 'cancel' and not (m.state == 'done' and m.scrapped))
+ moves_to_cancel.picked = False
# self cannot contain moves that are either cancelled or done, therefore we can safely
# unlink all associated move_line_ids
moves_to_cancel._do_unreserve()
@@ -1809,16 +1725,18 @@ Please change the quantity done or the rounding precision of your unit of measur
"""
extra_move = self
rounding = self.product_uom.rounding
+ if float_is_zero(self.product_uom_qty, precision_rounding=rounding):
+ return self
# moves created after the picking is assigned do not have `product_uom_qty`, but we shouldn't create extra moves for them
- if float_compare(self.quantity_done, self.product_uom_qty, precision_rounding=rounding) > 0:
+ if float_compare(self.quantity, self.product_uom_qty, precision_rounding=rounding) > 0:
# create the extra moves
extra_move_quantity = float_round(
- self.quantity_done - self.product_uom_qty,
+ self.quantity - self.product_uom_qty,
precision_rounding=rounding,
rounding_method='HALF-UP')
extra_move_vals = self._prepare_extra_move_vals(extra_move_quantity)
extra_move = self.copy(default=extra_move_vals).with_context(avoid_putaway_rules=True)
- return extra_move.with_context(merge_extra=True)._action_confirm(merge_into=self)
+ return extra_move.with_context(merge_extra=True, do_not_unreserve=True)._action_confirm(merge_into=self)
return self
def _check_unlink_move_dest(self):
@@ -1843,22 +1761,26 @@ Please change the quantity done or the rounding precision of your unit of measur
new_push_moves._action_confirm()
def _action_done(self, cancel_backorder=False):
- moves = self.filtered(lambda move: move.state == 'draft' or move.state == 'assigned' and move.from_immediate_transfer)._action_confirm() # MRP allows scrapping draft moves
+ moves = self.filtered(
+ lambda move: move.state == 'draft'
+ or float_is_zero(move.product_uom_qty, precision_digits=move.product_uom.rounding)
+ )._action_confirm(merge=False) # MRP allows scrapping draft moves
moves = (self | moves).exists().filtered(lambda x: x.state not in ('done', 'cancel'))
moves_ids_todo = OrderedSet()
# Cancel moves where necessary ; we should do it before creating the extra moves because
# this operation could trigger a merge of moves.
for move in moves:
- if move.quantity_done <= 0 and not move.is_inventory:
+ if (move.quantity <= 0 or not move.picked) and not move.is_inventory:
if float_compare(move.product_uom_qty, 0.0, precision_rounding=move.product_uom.rounding) == 0 or cancel_backorder:
move._action_cancel()
# Create extra moves where necessary
for move in moves:
- if move.state == 'cancel' or (move.quantity_done <= 0 and not move.is_inventory):
+ if move.state == 'cancel' or (move.quantity <= 0 and not move.is_inventory):
+ continue
+ if not move.picked:
continue
-
moves_ids_todo |= move._create_extra_move().ids
moves_todo = self.browse(moves_ids_todo)
@@ -1870,9 +1792,9 @@ Please change the quantity done or the rounding precision of your unit of measur
# To know whether we need to create a backorder or not, round to the general product's
# decimal precision and not the product's UOM.
rounding = self.env['decimal.precision'].precision_get('Product Unit of Measure')
- if float_compare(move.quantity_done, move.product_uom_qty, precision_digits=rounding) < 0:
+ if float_compare(move.quantity, move.product_uom_qty, precision_digits=rounding) < 0:
# Need to do some kind of conversion here
- qty_split = move.product_uom._compute_quantity(move.product_uom_qty - move.quantity_done, move.product_id.uom_id, rounding_method='HALF-UP')
+ qty_split = move.product_uom._compute_quantity(move.product_uom_qty - move.quantity, move.product_id.uom_id, rounding_method='HALF-UP')
new_move_vals = move._split(qty_split)
backorder_moves_vals += new_move_vals
backorder_moves = self.env['stock.move'].create(backorder_moves_vals)
@@ -1883,7 +1805,7 @@ Please change the quantity done or the rounding precision of your unit of measur
# Check the consistency of the result packages; there should be an unique location across
# the contained quants.
for result_package in moves_todo\
- .mapped('move_line_ids.result_package_id')\
+ .move_line_ids.filtered(lambda ml: ml.picked).mapped('result_package_id')\
.filtered(lambda p: p.quant_ids and len(p.quant_ids) > 1):
if len(result_package.quant_ids.filtered(lambda q: not float_is_zero(abs(q.quantity) + abs(q.reserved_quantity), precision_rounding=q.product_uom_id.rounding)).mapped('location_id')) > 1:
raise UserError(_('You cannot move the same package content more than once in the same transfer or split the same package into two location.'))
@@ -1892,9 +1814,6 @@ Please change the quantity done or the rounding precision of your unit of measur
picking = moves_todo.mapped('picking_id')
moves_todo.write({'state': 'done', 'date': fields.Datetime.now()})
- new_push_moves = moves_todo.filtered(lambda m: m.picking_id.immediate_transfer)._push_apply()
- if new_push_moves:
- new_push_moves._action_confirm()
move_dests_per_company = defaultdict(lambda: self.env['stock.move'])
# Break move dest link if move dest and move_dest source are not the same,
@@ -1914,7 +1833,7 @@ Please change the quantity done or the rounding precision of your unit of measur
if picking and not cancel_backorder:
backorder = picking._create_backorder()
if any([m.state == 'assigned' for m in backorder.move_ids]):
- backorder._check_entire_pack()
+ backorder._check_entire_pack()
return moves_todo
@api.ondelete(at_uninstall=False)
@@ -1954,8 +1873,8 @@ Please change the quantity done or the rounding precision of your unit of measur
# we restrict the split of a draft move because if not confirmed yet, it may be replaced by several other moves in
# case of phantom bom (with mrp module). And we don't want to deal with this complexity by copying the product that will explode.
raise UserError(_('You cannot split a draft move. It needs to be confirmed first.'))
- # exclude immediate transfer in case we want to add a move line in a wave picking
- if float_is_zero(qty, precision_rounding=self.product_id.uom_id.rounding) or self.product_qty <= qty and not self.from_immediate_transfer:
+
+ if float_is_zero(qty, precision_rounding=self.product_id.uom_id.rounding):
return []
decimal_precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
@@ -1990,11 +1909,11 @@ Please change the quantity done or the rounding precision of your unit of measur
moves_state_to_write = defaultdict(set)
for move in self:
rounding = move.product_uom.rounding
- if move.state in ('cancel', 'done', 'draft'):
+ if move.state in ('cancel', 'done'):
continue
- elif float_compare(move.reserved_availability, move.product_uom_qty, precision_rounding=rounding) >= 0:
+ elif float_compare(move.quantity, move.product_uom_qty, precision_rounding=rounding) >= 0:
moves_state_to_write['assigned'].add(move.id)
- elif move.reserved_availability and float_compare(move.reserved_availability, move.product_uom_qty, precision_rounding=rounding) <= 0:
+ elif move.quantity and float_compare(move.quantity, move.product_uom_qty, precision_rounding=rounding) <= 0:
moves_state_to_write['partially_available'].add(move.id)
elif move.procure_method == 'make_to_order' and not move.move_orig_ids:
moves_state_to_write['waiting'].add(move.id)
@@ -2037,7 +1956,10 @@ Please change the quantity done or the rounding precision of your unit of measur
def _set_quantity_done_prepare_vals(self, qty):
res = []
for ml in self.move_line_ids:
- ml_qty = ml.reserved_uom_qty - ml.qty_done
+ ml_qty = ml.quantity
+ if float_is_zero(qty, precision_rounding=self.product_uom.rounding):
+ res.append((2, ml.id))
+ continue
if float_compare(ml_qty, 0, precision_rounding=ml.product_uom_id.rounding) <= 0:
continue
# Convert move line qty into move uom
@@ -2052,28 +1974,21 @@ Please change the quantity done or the rounding precision of your unit of measur
# Assign qty_done and explicitly round to make sure there is no inconsistency between
# ml.qty_done and qty.
taken_qty = float_round(taken_qty, precision_rounding=ml.product_uom_id.rounding)
- res.append((1, ml.id, {'qty_done': ml.qty_done + taken_qty}))
+ res.append((1, ml.id, {'quantity': taken_qty}))
if ml.product_uom_id != self.product_uom:
taken_qty = ml.product_uom_id._compute_quantity(ml_qty, self.product_uom, round=False)
qty -= taken_qty
- if float_compare(qty, 0.0, precision_rounding=self.product_uom.rounding) <= 0:
- break
-
- for ml in self.move_line_ids:
- if float_is_zero(ml.reserved_uom_qty, precision_rounding=ml.product_uom_id.rounding) and float_is_zero(ml.qty_done, precision_rounding=ml.product_uom_id.rounding):
- res.append((2, ml.id))
-
if float_compare(qty, 0.0, precision_rounding=self.product_uom.rounding) > 0:
if self.product_id.tracking != 'serial':
vals = self._prepare_move_line_vals(quantity=0)
- vals['qty_done'] = qty
+ vals['quantity'] = qty
res.append((0, 0, vals))
else:
uom_qty = self.product_uom._compute_quantity(qty, self.product_id.uom_id)
for i in range(0, int(uom_qty)):
vals = self._prepare_move_line_vals(quantity=0)
- vals['qty_done'] = 1
+ vals['quantity'] = 1
vals['product_uom_id'] = self.product_id.uom_id.id
res.append((0, 0, vals))
return res
@@ -2091,20 +2006,6 @@ Please change the quantity done or the rounding precision of your unit of measur
# These new SMLs need to be redirected thanks to putaway rules
(self.move_line_ids - existing_smls)._apply_putaway_strategy()
- def _set_quantities_to_reservation(self):
- for move in self:
- if move.state not in ('partially_available', 'assigned'):
- continue
- for move_line in move.move_line_ids:
- if move.has_tracking == 'none' or\
- (move.picking_type_id.use_existing_lots and move_line.lot_id) or\
- (move.picking_type_id.use_create_lots and move_line.lot_name) or\
- (not move.picking_type_id.use_existing_lots and not move.picking_type_id.use_create_lots):
- move_line.qty_done = move_line.reserved_uom_qty
-
- def _clear_quantities_to_zero(self):
- self.filtered(lambda m: m.state in ('partially_available', 'assigned')).move_line_ids.qty_done = 0
-
def _adjust_procure_method(self):
""" This method will try to apply the procure method MTO on some moves if
a compatible MTO route is found. Else the procure method will be set to MTS
@@ -2290,7 +2191,7 @@ Please change the quantity done or the rounding precision of your unit of measur
product_rounding = product.uom_id.rounding
for out in reserved_outs_per_product.get(product, []):
# Reconcile with reserved stock.
- reserved = out.product_uom._compute_quantity(out.reserved_availability, product.uom_id)
+ reserved = out.product_uom._compute_quantity(out.quantity, product.uom_id)
currents[product.id] -= reserved
if out.id in ids_in_self:
result[out] = (result[out][0] + reserved, False)
@@ -2300,7 +2201,7 @@ Please change the quantity done or the rounding precision of your unit of measur
# Reconcile with the current stock.
reserved = 0.0
if out.state in ('partially_available', 'assigned'):
- reserved = out.product_uom._compute_quantity(out.reserved_availability, product.uom_id)
+ reserved = out.product_uom._compute_quantity(out.quantity, product.uom_id)
demand = out.product_qty - reserved
if float_is_zero(demand, precision_rounding=product_rounding):
@@ -2349,5 +2250,5 @@ Please change the quantity done or the rounding precision of your unit of measur
def _convert_string_into_field_data(self, string, options):
string = string.replace(',', '.') # Parsing string as float works only with dot, not comma.
if regex_findall(r'^([0-9]+\.?[0-9]*|\.[0-9]+)$', string): # Number => Quantity.
- return {'qty_done': float(string)}
+ return {'quantity': float(string)}
return False
diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py
index 27eaf75027a..bf3b542b082 100644
--- a/addons/stock/models/stock_move_line.py
+++ b/addons/stock/models/stock_move_line.py
@@ -32,14 +32,13 @@ class StockMoveLine(models.Model):
)
product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id')
product_category_name = fields.Char(related="product_id.categ_id.complete_name", store=True, string="Product Category")
- reserved_qty = fields.Float(
- 'Real Reserved Quantity', digits=0, copy=False,
- compute='_compute_reserved_qty', inverse='_set_reserved_qty', store=True)
- reserved_uom_qty = fields.Float(
- 'Reserved', default=0.0, digits='Product Unit of Measure',
- required=True, copy=False, compute='_compute_qty_reserved', store=True, readonly=False)
- qty_done = fields.Float('Done', digits='Product Unit of Measure', copy=False,
- compute='_compute_qty_done', store=True, readonly=False)
+ quantity = fields.Float(
+ 'Quantity', digits='Product Unit of Measure', copy=False, store=True,
+ compute='_compute_quantity', readonly=False)
+ quantity_product_uom = fields.Float(
+ 'Quantity in Product UoM', digits='Product Unit of Measure',
+ copy=False, compute='_compute_quantity_product_uom', store=True)
+ picked = fields.Boolean('Picked', compute='_compute_picked', store=True, readonly=False, copy=False)
package_id = fields.Many2one(
'stock.quant.package', 'Source Package', ondelete='restrict',
check_company=True,
@@ -75,7 +74,6 @@ class StockMoveLine(models.Model):
picking_type_use_existing_lots = fields.Boolean(related='picking_type_id.use_existing_lots', readonly=True)
picking_type_entire_packs = fields.Boolean(related='picking_id.picking_type_id.show_entire_packs', readonly=True)
state = fields.Selection(related='move_id.state', store=True, related_sudo=False)
- is_initial_demand_editable = fields.Boolean(related='move_id.is_initial_demand_editable')
is_inventory = fields.Boolean(related='move_id.is_inventory')
is_locked = fields.Boolean(related='move_id.is_locked', readonly=True)
consume_line_ids = fields.Many2many('stock.move.line', 'stock_move_line_consume_rel', 'consume_line_id', 'produce_line_id')
@@ -85,12 +83,7 @@ class StockMoveLine(models.Model):
origin = fields.Char(related='move_id.origin', string='Source')
description_picking = fields.Text(string="Description picking")
quant_id = fields.Many2one('stock.quant', "Pick From", store=False) # Dummy field for the detailed operation view
- product_packaging_qty = fields.Float(
- string="Reserved Packaging Quantity",
- compute='_compute_product_packaging_qty')
- product_packaging_qty_done = fields.Float(
- string="Done Packaging Quantity",
- compute='_compute_product_packaging_qty_done')
+ product_packaging_qty = fields.Float(string="Reserved Packaging Quantity", compute='_compute_product_packaging_qty')
@api.depends('product_uom_id.category_id', 'product_id.uom_id.category_id', 'move_id.product_uom', 'product_id.uom_id')
def _compute_product_uom_id(self):
@@ -110,6 +103,12 @@ class StockMoveLine(models.Model):
else:
line.lots_visible = line.product_id.tracking != 'none'
+ @api.depends('state')
+ def _compute_picked(self):
+ for line in self:
+ if line.move_id.state == 'done':
+ line.picked = True
+
@api.depends('picking_id')
def _compute_picking_type_id(self):
self.picking_type_id = False
@@ -125,55 +124,31 @@ class StockMoveLine(models.Model):
if not line.location_dest_id:
line.location_dest_id = line.move_id.location_dest_id or line.picking_id.location_dest_id
- @api.depends('move_id.product_packaging_id', 'product_uom_id', 'reserved_qty')
+ @api.depends('move_id.product_packaging_id', 'product_uom_id', 'quantity')
def _compute_product_packaging_qty(self):
self.product_packaging_qty = 0
for line in self:
if not line.move_id.product_packaging_id:
continue
- line.product_packaging_qty = line.move_id.product_packaging_id._compute_qty(line.reserved_qty)
-
- @api.depends('move_id.product_packaging_id', 'product_uom_id', 'qty_done')
- def _compute_product_packaging_qty_done(self):
- self.product_packaging_qty_done = 0
- for line in self:
- if not line.move_id.product_packaging_id:
- continue
- line.product_packaging_qty_done = line.move_id.product_packaging_id._compute_qty(line.qty_done, line.product_uom_id)
+ line.product_packaging_qty = line.move_id.product_packaging_id._compute_qty(line.quantity, line.product_uom_id)
def _search_picking_type_id(self, operator, value):
return [('picking_id.picking_type_id', operator, value)]
- @api.depends('product_id', 'product_uom_id', 'reserved_uom_qty')
- def _compute_reserved_qty(self):
+ @api.depends('quant_id')
+ def _compute_quantity(self):
+ for record in self:
+ if not record.quant_id or record.quantity:
+ continue
+ if float_compare(record.move_id.product_qty, record.move_id.quantity, record.move_id.product_uom.rounding) > 0:
+ record.quantity = max(0, min(record.quant_id.available_quantity, record.move_id.product_qty - record.move_id.quantity))
+ else:
+ record.quantity = max(0, record.quant_id.available_quantity)
+
+ @api.depends('quantity', 'product_uom_id')
+ def _compute_quantity_product_uom(self):
for line in self:
- line.reserved_qty = line.product_uom_id._compute_quantity(line.reserved_uom_qty, line.product_id.uom_id, rounding_method='HALF-UP')
-
- def _set_reserved_qty(self):
- """ The meaning of reserved_qty field changed lately and is now a functional field computing the quantity
- in the default product UoM. This code has been added to raise an error if a write is made given a value
- for `reserved_qty`, where the same write should set the `reserved_uom_qty` field instead, in order to
- detect errors. """
- raise UserError(_('The requested operation cannot be processed because of a programming error setting the `reserved_qty` field instead of the `reserved_uom_qty`.'))
-
- @api.depends('quant_id')
- def _compute_qty_done(self):
- for record in self:
- if not record.qty_done:
- if (record.move_id.product_qty - record.move_id.quantity_done):
- record.qty_done = max(0, min(record.quant_id.available_quantity, record.move_id.product_qty - record.move_id.quantity_done))
- else:
- record.qty_done = max(0, record.quant_id.available_quantity)
-
- @api.depends('quant_id')
- def _compute_qty_reserved(self):
- for record in self:
- if not record.reserved_uom_qty:
- if (record.move_id.product_qty - record.move_id.quantity_done):
- record.reserved_uom_qty = max(0, min(record.quant_id.available_quantity, record.move_id.product_qty - record.move_id.quantity_done))
- else:
- record.reserved_uom_qty = max(0, record.quant_id.available_quantity)
-
+ line.quantity_product_uom = line.product_uom_id._compute_quantity(line.quantity, line.product_id.uom_id, rounding_method='HALF-UP')
@api.constrains('lot_id', 'product_id')
def _check_lot_product(self):
@@ -185,15 +160,9 @@ class StockMoveLine(models.Model):
product_name=line.product_id.display_name
))
- @api.constrains('reserved_uom_qty')
- def _check_reserved_done_quantity(self):
- for move_line in self:
- if move_line.state == 'done' and not float_is_zero(move_line.reserved_uom_qty, precision_digits=self.env['decimal.precision'].precision_get('Product Unit of Measure')):
- raise ValidationError(_('A done move line should never have a reserved quantity.'))
-
- @api.constrains('qty_done')
- def _check_positive_qty_done(self):
- if any(ml.qty_done < 0 for ml in self):
+ @api.constrains('quantity')
+ def _check_positive_quantity(self):
+ if any(ml.quantity < 0 for ml in self):
raise ValidationError(_('You can not enter negative quantities.'))
@api.onchange('product_id', 'product_uom_id')
@@ -208,14 +177,14 @@ class StockMoveLine(models.Model):
def _onchange_serial_number(self):
""" When the user is encoding a move line for a tracked product, we apply some logic to
help him. This includes:
- - automatically switch `qty_done` to 1.0
+ - automatically switch `quantity` to 1.0
- warn if he has already encoded `lot_name` in another move line
- warn (and update if appropriate) if the SN is in a different source location than selected
"""
res = {}
if self.product_id.tracking == 'serial':
- if not self.qty_done:
- self.qty_done = 1
+ if not self.quantity:
+ self.quantity = 1
message = None
if self.lot_name or self.lot_id:
@@ -226,8 +195,8 @@ class StockMoveLine(models.Model):
message = _('You cannot use the same serial number twice. Please correct the serial numbers encoded.')
elif not self.lot_id:
lots = self.env['stock.lot'].search([('product_id', '=', self.product_id.id),
- ('name', '=', self.lot_name),
- ('company_id', '=', self.company_id.id)])
+ ('name', '=', self.lot_name),
+ ('company_id', '=', self.company_id.id)])
quants = lots.quant_ids.filtered(lambda q: q.quantity != 0 and q.location_id.usage in ['customer', 'internal', 'transit'])
if quants:
message = _('Serial number (%s) already exists in location(s): %s. Please correct the serial number encoded.', self.lot_name, ', '.join(quants.location_id.mapped('display_name')))
@@ -237,37 +206,33 @@ class StockMoveLine(models.Model):
message = _('You cannot use the same serial number twice. Please correct the serial numbers encoded.')
else:
# check if in correct source location
- message, recommended_location = self.env['stock.quant'].sudo()._check_serial_number(self.product_id,
- self.lot_id,
- self.company_id,
- self.location_id,
- self.picking_id.location_id)
+ message, recommended_location = self.env['stock.quant'].sudo()._check_serial_number(
+ self.product_id, self.lot_id, self.company_id, self.location_id, self.picking_id.location_id)
if recommended_location:
self.location_id = recommended_location
if message:
res['warning'] = {'title': _('Warning'), 'message': message}
return res
- @api.onchange('qty_done', 'product_uom_id')
- def _onchange_qty_done(self):
+ @api.onchange('quantity', 'product_uom_id')
+ def _onchange_quantity(self):
""" When the user is encoding a move line for a tracked product, we apply some logic to
- help him. This onchange will warn him if he set `qty_done` to a non-supported value.
+ help him. This onchange will warn him if he set `quantity` to a non-supported value.
"""
res = {}
- if self.qty_done and self.product_id.tracking == 'serial':
- qty_done = self.product_uom_id._compute_quantity(self.qty_done, self.product_id.uom_id)
- if float_compare(qty_done, 1.0, precision_rounding=self.product_id.uom_id.rounding) != 0:
+ if self.quantity and self.product_id.tracking == 'serial':
+ if float_compare(self.quantity_product_uom, 1.0, precision_rounding=self.product_id.uom_id.rounding) != 0:
message = _('You can only process 1.0 %s of products with unique serial number.', self.product_id.uom_id.name)
res['warning'] = {'title': _('Warning'), 'message': message}
return res
- @api.onchange('result_package_id', 'product_id', 'product_uom_id', 'qty_done')
+ @api.onchange('result_package_id', 'product_id', 'product_uom_id', 'quantity')
def _onchange_putaway_location(self):
- if not self.id and self.user_has_groups('stock.group_stock_multi_locations') and self.product_id and self.qty_done:
- qty_done = self.product_uom_id._compute_quantity(self.qty_done, self.product_id.uom_id)
+ if not self.id and self.user_has_groups('stock.group_stock_multi_locations') and self.product_id and self.quantity_product_uom:
default_dest_location = self._get_default_dest_location()
+ quantity = self.quantity_product_uom
self.location_dest_id = default_dest_location.with_context(exclude_sml_ids=self.ids)._get_putaway_strategy(
- self.product_id, quantity=qty_done, package=self.result_package_id,
+ self.product_id, quantity=quantity, package=self.result_package_id,
packaging=self.move_id.product_packaging_id)
def _apply_putaway_strategy(self):
@@ -285,7 +250,7 @@ class StockMoveLine(models.Model):
for sml in smls:
if len(used_locations) > 1:
break
- sml.location_dest_id = sml.move_id.location_dest_id.with_context(exclude_sml_ids=excluded_smls.ids)._get_putaway_strategy(sml.product_id, quantity=sml.reserved_uom_qty)
+ sml.location_dest_id = sml.move_id.location_dest_id.with_context(exclude_sml_ids=excluded_smls.ids)._get_putaway_strategy(sml.product_id, quantity=sml.quantity)
excluded_smls -= sml
used_locations.add(sml.location_dest_id)
if len(used_locations) > 1:
@@ -294,9 +259,8 @@ class StockMoveLine(models.Model):
smls.package_level_id.location_dest_id = smls.location_dest_id
else:
for sml in smls:
- qty = max(sml.reserved_uom_qty, sml.qty_done)
putaway_loc_id = sml.move_id.location_dest_id.with_context(exclude_sml_ids=excluded_smls.ids)._get_putaway_strategy(
- sml.product_id, quantity=qty, packaging=sml.move_id.product_packaging_id,
+ sml.product_id, quantity=sml.quantity, packaging=sml.move_id.product_packaging_id,
)
if putaway_loc_id != sml.location_dest_id:
sml.location_dest_id = putaway_loc_id
@@ -312,7 +276,7 @@ class StockMoveLine(models.Model):
def _get_putaway_additional_qty(self):
addtional_qty = {}
for ml in self._origin:
- qty = max(ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id), ml.reserved_uom_qty)
+ qty = ml.product_uom_id._compute_quantity(ml.quantity, ml.product_id.uom_id)
addtional_qty[ml.location_dest_id.id] = addtional_qty.get(ml.location_dest_id.id, 0) - qty
return addtional_qty
@@ -323,7 +287,7 @@ class StockMoveLine(models.Model):
ON
stock_move_line (id, company_id, product_id, lot_id, location_id, owner_id, package_id)
WHERE
- (state IS NULL OR state NOT IN ('cancel', 'done')) AND reserved_qty > 0""")
+ (state IS NULL OR state NOT IN ('cancel', 'done')) AND quantity > 0 AND not picked""")
@api.model_create_multi
def create(self, vals_list):
@@ -332,6 +296,8 @@ class StockMoveLine(models.Model):
vals['company_id'] = self.env['stock.move'].browse(vals['move_id']).company_id.id
elif vals.get('picking_id'):
vals['company_id'] = self.env['stock.picking'].browse(vals['picking_id']).company_id.id
+ if vals.get('move_id') and 'picked' not in vals:
+ vals['picked'] = self.env['stock.move'].browse(vals['move_id']).picked
if vals.get('quant_id'):
vals.update(self._copy_quant_info(vals))
@@ -349,7 +315,7 @@ class StockMoveLine(models.Model):
continue
if move_line.picking_id.state != 'done':
moves = move_line.picking_id.move_ids.filtered(lambda x: x.product_id == move_line.product_id)
- moves = sorted(moves, key=lambda m: m.quantity_done < m.product_qty, reverse=True)
+ moves = sorted(moves, key=lambda m: m.quantity < m.product_qty, reverse=True)
if moves:
move_line.write({
'move_id': moves[0].id,
@@ -362,42 +328,26 @@ class StockMoveLine(models.Model):
move_to_recompute_state = self.env['stock.move']
for move_line in mls:
- reserved_uom_qty = move_line.reserved_uom_qty
location = move_line.location_id
product = move_line.product_id
move = move_line.move_id
if move:
- bypass_reservation = not move._should_bypass_reservation()
+ reservation = not move._should_bypass_reservation()
else:
- bypass_reservation = product.type == 'product' and not location.should_bypass_reservation()
- if reserved_uom_qty and not self.env.context.get('bypass_reservation_update') and bypass_reservation:
- ml_uom = move_line.product_uom_id
+ reservation = product.type == 'product' and not location.should_bypass_reservation()
+ if move_line.quantity and reservation:
+ self.env.context.get('reserved_quant', self.env['stock.quant'])._update_reserved_quantity(
+ product, location, move_line.quantity_product_uom, lot_id=move_line.lot_id, package_id=move_line.package_id, owner_id=move_line.owner_id)
- reserved_qty = ml_uom._compute_quantity(reserved_uom_qty, product.uom_id, rounding_method='HALF-UP')
- reserved_quants = self.env.context.get('reserved_quant', self.env['stock.quant'])._update_reserved_quantity(
- product, location, reserved_qty, lot_id=move_line.lot_id, package_id=move_line.package_id, owner_id=move_line.owner_id, strict=True)
-
- if not reserved_quants or float_compare(reserved_qty, sum(map(lambda q: q[1], reserved_quants)), product.uom_id.rounding) != 0:
- reserved_uom_qty = product.uom_id._compute_quantity(reserved_qty, ml_uom, rounding_method='HALF-UP')
- move_line.with_context(bypass_reservation=True).reserved_uom_qty = reserved_uom_qty
if move:
move_to_recompute_state |= move
move_to_recompute_state._recompute_state()
- moves_to_update = mls.filtered(
- lambda ml:
- ml.move_id and
- ml.qty_done and
- ml.move_id.state == 'done'
- ).move_id
- for move in moves_to_update:
- move.with_context(avoid_putaway_rules=True).product_uom_qty = move.quantity_done
-
for ml, vals in zip(mls, vals_list):
if ml.state == 'done':
- if ml.product_id.type == 'product' and not self.env.context.get('bypass_reservation_update'):
+ if ml.product_id.type == 'product':
Quant = self.env['stock.quant']
- quantity = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id,rounding_method='HALF-UP')
+ quantity = ml.product_uom_id._compute_quantity(ml.quantity, ml.move_id.product_id.uom_id, rounding_method='HALF-UP')
in_date = None
available_qty, in_date = Quant._update_available_quantity(ml.product_id, ml.location_id, -quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
if available_qty < 0 and ml.lot_id:
@@ -414,16 +364,10 @@ class StockMoveLine(models.Model):
return mls
def write(self, vals):
- # Very dangerous key. It could create some desynchronization between `stock.move.line` and `stock.quant`.
- # It exists for performances purposes. Only use it if you handle `stock.quant` reservation manualy.
- if self.env.context.get('bypass_reservation_update'):
- return super().write(vals)
if 'product_id' in vals and any(vals.get('state', ml.state) != 'draft' and vals['product_id'] != ml.product_id.id for ml in self):
raise UserError(_("Changing the product is only allowed in 'Draft' state."))
moves_to_recompute_state = self.env['stock.move']
- Quant = self.env['stock.quant']
- precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
triggers = [
('location_id', 'stock.location'),
('location_dest_id', 'stock.location'),
@@ -451,84 +395,50 @@ class StockMoveLine(models.Model):
# Only need to unlink the package level if it's empty. Otherwise will unlink it to still valid move lines.
if not package_level.move_line_ids:
package_level.unlink()
-
# When we try to write on a reserved move line any fields from `triggers` or directly
# `reserved_uom_qty` (the actual reserved quantity), we need to make sure the associated
# quants are correctly updated in order to not make them out of sync (i.e. the sum of the
# move lines `reserved_uom_qty` should always be equal to the sum of `reserved_quantity` on
# the quants). If the new charateristics are not available on the quants, we chose to
# reserve the maximum possible.
- if updates or 'reserved_uom_qty' in vals:
+ if updates or 'quantity' in vals:
for ml in self:
- if ml.product_id.type != 'product':
+ if ml.product_id.type != 'product' or ml.state == 'done':
continue
- if 'reserved_uom_qty' in vals:
+ if 'quantity' in vals:
new_reserved_qty = ml.product_uom_id._compute_quantity(
- vals['reserved_uom_qty'], ml.product_id.uom_id, rounding_method='HALF-UP')
+ vals['quantity'], ml.product_id.uom_id, rounding_method='HALF-UP')
# Make sure `reserved_uom_qty` is not negative.
if float_compare(new_reserved_qty, 0, precision_rounding=ml.product_id.uom_id.rounding) < 0:
raise UserError(_('Reserving a negative quantity is not allowed.'))
else:
- new_reserved_qty = ml.reserved_qty
+ new_reserved_qty = ml.quantity_product_uom
# Unreserve the old charateristics of the move line.
- if not float_is_zero(ml.reserved_qty, precision_rounding=ml.product_uom_id.rounding):
- if not ml.move_id._should_bypass_reservation(ml.location_id):
- Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.reserved_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
+ if not float_is_zero(ml.quantity_product_uom, precision_rounding=ml.product_uom_id.rounding):
+ ml._synchronize_quant(-ml.quantity_product_uom, ml.location_id, action="reserved")
# Reserve the maximum available of the new charateristics of the move line.
- reserved_qty = new_reserved_qty
if not ml.move_id._should_bypass_reservation(updates.get('location_id', ml.location_id)):
- q = Quant._update_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), new_reserved_qty, lot_id=updates.get('lot_id', ml.lot_id),
- package_id=updates.get('package_id', ml.package_id), owner_id=updates.get('owner_id', ml.owner_id), strict=True)
- reserved_qty = sum([x[1] for x in q])
+ ml._synchronize_quant(
+ new_reserved_qty, updates.get('location_id', ml.location_id), action="reserved",
+ lot=updates.get('lot_id', ml.lot_id), package=updates.get('package_id', ml.package_id),
+ owner=updates.get('owner_id', ml.owner_id))
- if reserved_qty != new_reserved_qty:
- reserved_uom_qty = ml.product_id.uom_id._compute_quantity(reserved_qty, ml.product_uom_id, rounding_method='HALF-UP')
- vals['reserved_uom_qty'] = reserved_uom_qty
-
- if 'reserved_uom_qty' in vals and vals['reserved_uom_qty'] != ml.reserved_uom_qty:
+ if 'quantity' in vals and vals['quantity'] != ml.quantity:
moves_to_recompute_state |= ml.move_id
# When editing a done move line, the reserved availability of a potential chained move is impacted. Take care of running again `_action_assign` on the concerned moves.
- if updates or 'qty_done' in vals:
+ mls = self.env['stock.move.line']
+ if updates or 'quantity' in vals:
next_moves = self.env['stock.move']
mls = self.filtered(lambda ml: ml.move_id.state == 'done' and ml.product_id.type == 'product')
- if not updates: # we can skip those where qty_done is already good up to UoM rounding
- mls = mls.filtered(lambda ml: not float_is_zero(ml.qty_done - vals['qty_done'], precision_rounding=ml.product_uom_id.rounding))
+ if not updates: # we can skip those where quantity is already good up to UoM rounding
+ mls = mls.filtered(lambda ml: not float_is_zero(ml.quantity - vals['quantity'], precision_rounding=ml.product_uom_id.rounding))
for ml in mls:
# undo the original move line
- qty_done_orig = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP')
- in_date = Quant._update_available_quantity(ml.product_id, ml.location_dest_id, -qty_done_orig, lot_id=ml.lot_id,
- package_id=ml.result_package_id, owner_id=ml.owner_id)[1]
- Quant._update_available_quantity(ml.product_id, ml.location_id, qty_done_orig, lot_id=ml.lot_id,
- package_id=ml.package_id, owner_id=ml.owner_id, in_date=in_date)
-
- # move what's been actually done
- product_id = ml.product_id
- location_id = updates.get('location_id', ml.location_id)
- location_dest_id = updates.get('location_dest_id', ml.location_dest_id)
- qty_done = vals.get('qty_done', ml.qty_done)
- lot_id = updates.get('lot_id', ml.lot_id)
- package_id = updates.get('package_id', ml.package_id)
- result_package_id = updates.get('result_package_id', ml.result_package_id)
- owner_id = updates.get('owner_id', ml.owner_id)
- product_uom_id = updates.get('product_uom_id', ml.product_uom_id)
- quantity = product_uom_id._compute_quantity(qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP')
- if not ml.move_id._should_bypass_reservation(location_id):
- ml._free_reservation(product_id, location_id, quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id)
- if not float_is_zero(quantity, precision_digits=precision):
- available_qty, in_date = Quant._update_available_quantity(product_id, location_id, -quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id)
- if available_qty < 0 and lot_id:
- # see if we can compensate the negative quants with some untracked quants
- untracked_qty = Quant._get_available_quantity(product_id, location_id, lot_id=False, package_id=package_id, owner_id=owner_id, strict=True)
- if untracked_qty:
- taken_from_untracked_qty = min(untracked_qty, abs(available_qty))
- Quant._update_available_quantity(product_id, location_id, -taken_from_untracked_qty, lot_id=False, package_id=package_id, owner_id=owner_id)
- Quant._update_available_quantity(product_id, location_id, taken_from_untracked_qty, lot_id=lot_id, package_id=package_id, owner_id=owner_id)
- if not ml.move_id._should_bypass_reservation(location_id):
- ml._free_reservation(ml.product_id, location_id, untracked_qty, lot_id=False, package_id=package_id, owner_id=owner_id)
- Quant._update_available_quantity(product_id, location_dest_id, quantity, lot_id=lot_id, package_id=result_package_id, owner_id=owner_id, in_date=in_date)
+ in_date = ml._synchronize_quant(-ml.quantity_product_uom, ml.location_dest_id, package=ml.result_package_id)[1]
+ ml._synchronize_quant(ml.quantity_product_uom, ml.location_id, in_date=in_date)
# Unreserve and reserve following move in order to have the real reserved quantity on move_line.
next_moves |= ml.move_id.move_dest_ids.filtered(lambda move: move.state not in ('done', 'cancel'))
@@ -539,13 +449,19 @@ class StockMoveLine(models.Model):
res = super(StockMoveLine, self).write(vals)
+ for ml in mls:
+ available_qty, dummy = ml._synchronize_quant(-ml.quantity_product_uom, ml.location_id)
+ ml._synchronize_quant(ml.quantity_product_uom, ml.location_dest_id, package=ml.result_package_id)
+ if available_qty < 0:
+ ml._free_reservation(
+ ml.product_id, ml.location_id,
+ abs(available_qty), lot_id=ml.lot_id, package_id=ml.package_id,
+ owner_id=ml.owner_id)
+
# As stock_account values according to a move's `product_uom_qty`, we consider that any
# done stock move should have its `quantity_done` equals to its `product_uom_qty`, and
# this is what move's `action_done` will do. So, we replicate the behavior here.
- if updates or 'qty_done' in vals:
- moves = self.filtered(lambda ml: ml.move_id.state == 'done').mapped('move_id')
- for move in moves:
- move.product_uom_qty = move.quantity_done
+ if updates or 'quantity' in vals:
next_moves._do_unreserve()
next_moves._action_assign()
@@ -565,11 +481,11 @@ class StockMoveLine(models.Model):
quants_by_product = self.env['stock.quant']._get_quants_by_products_locations(self.product_id, self.location_id)
for ml in self:
# Unlinking a move line should unreserve.
- if not float_is_zero(ml.reserved_qty, precision_digits=precision) and ml.move_id and not ml.move_id._should_bypass_reservation(ml.location_id):
+ if not float_is_zero(ml.quantity, precision_digits=precision) and ml.move_id and not ml.move_id._should_bypass_reservation(ml.location_id):
quants = quants_by_product[ml.product_id.id]
- quants._update_reserved_quantity(ml.product_id, ml.location_id, -ml.reserved_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
+ quants._update_reserved_quantity(ml.product_id, ml.location_id, -ml.quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
moves = self.mapped('move_id')
- res = super(StockMoveLine, self).unlink()
+ res = super().unlink()
if moves:
# Add with_prefetch() to set the _prefecht_ids = _ids
# because _prefecht_ids generator look lazily on the cache of move_id
@@ -586,29 +502,28 @@ class StockMoveLine(models.Model):
intended to be called when editing a `done` move (that's what the override of `write` here
is done.
"""
- Quant = self.env['stock.quant']
- # First, we loop over all the move lines to do a preliminary check: `qty_done` should not
+ # First, we loop over all the move lines to do a preliminary check: `quantity` should not
# be negative and, according to the presence of a picking type or a linked inventory
- # adjustment, enforce some rules on the `lot_id` field. If `qty_done` is null, we unlink
+ # adjustment, enforce some rules on the `lot_id` field. If `quantity` is null, we unlink
# the line. It is mandatory in order to free the reservation and correctly apply
# `action_done` on the next move lines.
ml_ids_tracked_without_lot = OrderedSet()
ml_ids_to_delete = OrderedSet()
ml_ids_to_create_lot = OrderedSet()
for ml in self:
- # Check here if `ml.qty_done` respects the rounding of `ml.product_uom_id`.
- uom_qty = float_round(ml.qty_done, precision_rounding=ml.product_uom_id.rounding, rounding_method='HALF-UP')
+ # Check here if `ml.quantity` respects the rounding of `ml.product_uom_id`.
+ uom_qty = float_round(ml.quantity, precision_rounding=ml.product_uom_id.rounding, rounding_method='HALF-UP')
precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
- qty_done = float_round(ml.qty_done, precision_digits=precision_digits, rounding_method='HALF-UP')
- if float_compare(uom_qty, qty_done, precision_digits=precision_digits) != 0:
+ quantity = float_round(ml.quantity, precision_digits=precision_digits, rounding_method='HALF-UP')
+ if float_compare(uom_qty, quantity, precision_digits=precision_digits) != 0:
raise UserError(_('The quantity done for the product "%s" doesn\'t respect the rounding precision '
'defined on the unit of measure "%s". Please change the quantity done or the '
'rounding precision of your unit of measure.',
ml.product_id.display_name, ml.product_uom_id.name))
- qty_done_float_compared = float_compare(ml.qty_done, 0, precision_rounding=ml.product_uom_id.rounding)
- if qty_done_float_compared > 0:
+ quantity_float_compared = float_compare(ml.quantity, 0, precision_rounding=ml.product_uom_id.rounding)
+ if quantity_float_compared > 0:
if ml.product_id.tracking != 'none':
picking_type_id = ml.move_id.picking_type_id
if picking_type_id:
@@ -638,7 +553,7 @@ class StockMoveLine(models.Model):
if not ml.lot_id and ml.id not in ml_ids_to_create_lot:
ml_ids_tracked_without_lot.add(ml.id)
- elif qty_done_float_compared < 0:
+ elif quantity_float_compared < 0:
raise UserError(_('No negative quantities allowed'))
elif not ml.is_inventory:
ml_ids_to_delete.add(ml.id)
@@ -648,7 +563,7 @@ class StockMoveLine(models.Model):
raise UserError(_('You need to supply a Lot/Serial Number for product: \n - ') +
'\n - '.join(mls_tracked_without_lot.mapped('product_id.display_name')))
ml_to_create_lot = self.env['stock.move.line'].browse(ml_ids_to_create_lot)
- ml_to_create_lot.with_context(bypass_reservation_update=True)._create_and_assign_production_lot()
+ ml_to_create_lot._create_and_assign_production_lot()
mls_to_delete = self.env['stock.move.line'].browse(ml_ids_to_delete)
mls_to_delete.unlink()
@@ -658,34 +573,45 @@ class StockMoveLine(models.Model):
# Now, we can actually move the quant.
ml_ids_to_ignore = OrderedSet()
+
for ml in mls_todo:
- if ml.product_id.type == 'product':
- rounding = ml.product_uom_id.rounding
-
- # if this move line is force assigned, unreserve elsewhere if needed
- if not ml.move_id._should_bypass_reservation(ml.location_id) and float_compare(ml.qty_done, ml.reserved_uom_qty, precision_rounding=rounding) > 0:
- qty_done_product_uom = ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id, rounding_method='HALF-UP')
- extra_qty = qty_done_product_uom - ml.reserved_qty
- ml._free_reservation(ml.product_id, ml.location_id, extra_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, ml_ids_to_ignore=ml_ids_to_ignore)
-
- # move what's been actually done
- quantity = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP')
- available_qty, in_date = Quant._update_available_quantity(ml.product_id, ml.location_id, -quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
- if available_qty < 0 and ml.lot_id:
- # see if we can compensate the negative quants with some untracked quants
- untracked_qty = Quant._get_available_quantity(ml.product_id, ml.location_id, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True)
- if untracked_qty:
- taken_from_untracked_qty = min(untracked_qty, abs(quantity))
- Quant._update_available_quantity(ml.product_id, ml.location_id, -taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id)
- Quant._update_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
- Quant._update_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id, in_date=in_date)
+ # if this move line is force assigned, unreserve elsewhere if needed
+ ml._synchronize_quant(-ml.quantity_product_uom, ml.location_id, action="reserved")
+ available_qty, in_date = ml._synchronize_quant(-ml.quantity_product_uom, ml.location_id)
+ ml._synchronize_quant(ml.quantity_product_uom, ml.location_dest_id, package=ml.result_package_id, in_date=in_date)
+ if available_qty < 0:
+ ml._free_reservation(
+ ml.product_id, ml.location_id,
+ abs(available_qty), lot_id=ml.lot_id, package_id=ml.package_id,
+ owner_id=ml.owner_id, ml_ids_to_ignore=ml_ids_to_ignore)
ml_ids_to_ignore.add(ml.id)
# Reset the reserved quantity as we just moved it to the destination location.
mls_todo.write({
- 'reserved_uom_qty': 0.00,
'date': fields.Datetime.now(),
})
+ def _synchronize_quant(self, quantity, location, action="available", in_date=False, **quants_value):
+ """ quantity should be express in product's UoM"""
+ lot = quants_value.get('lot', self.lot_id)
+ package = quants_value.get('package', self.package_id)
+ owner = quants_value.get('owner', self.owner_id)
+ available_qty = 0
+ if self.product_id.type != 'product' or float_is_zero(quantity, precision_rounding=self.product_uom_id.rounding):
+ return 0, False
+ if action == "available":
+ available_qty, in_date = self.env['stock.quant']._update_available_quantity(self.product_id, location, quantity, lot_id=lot, package_id=package, owner_id=owner, in_date=in_date)
+ elif action == "reserved" and not self.move_id._should_bypass_reservation():
+ self.env['stock.quant']._update_reserved_quantity(self.product_id, location, quantity, lot_id=lot, package_id=package, owner_id=owner)
+ if available_qty < 0 and lot:
+ # see if we can compensate the negative quants with some untracked quants
+ untracked_qty = self.env['stock.quant']._get_available_quantity(self.product_id, location, lot_id=False, package_id=package, owner_id=owner, strict=True)
+ if not untracked_qty:
+ return available_qty, in_date
+ taken_from_untracked_qty = min(untracked_qty, abs(quantity))
+ self.env['stock.quant']._update_available_quantity(self.product_id, location, -taken_from_untracked_qty, lot_id=False, package_id=package, owner_id=owner, in_date=in_date)
+ self.env['stock.quant']._update_available_quantity(self.product_id, location, taken_from_untracked_qty, lot_id=lot, package_id=package, owner_id=owner, in_date=in_date)
+ return available_qty, in_date
+
def _get_similar_move_lines(self):
self.ensure_one()
lines = self.env['stock.move.line']
@@ -727,7 +653,8 @@ class StockMoveLine(models.Model):
self.location_id.id == reserved_quant.location_id.id and
self.lot_id.id == reserved_quant.lot_id.id and
self.package_id.id == reserved_quant.package_id.id and
- self.owner_id.id == reserved_quant.owner_id.id):
+ self.owner_id.id == reserved_quant.owner_id.id and
+ not self.result_package_id):
return True
return False
@@ -759,67 +686,56 @@ class StockMoveLine(models.Model):
:param ml_ids_to_ignore: OrderedSet of `stock.move.line` ids that should NOT be unreserved
"""
self.ensure_one()
-
if ml_ids_to_ignore is None:
ml_ids_to_ignore = OrderedSet()
ml_ids_to_ignore |= self.ids
- # Check the available quantity, with the `strict` kw set to `True`. If the available
- # quantity is greater than the quantity now unavailable, there is nothing to do.
- available_quantity = self.env['stock.quant']._get_available_quantity(
- product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=True
- )
- if quantity > available_quantity:
- quantity = quantity - available_quantity
- # We now have to find the move lines that reserved our now unavailable quantity. We
- # take care to exclude ourselves and the move lines were work had already been done.
- outdated_move_lines_domain = [
- ('state', 'not in', ['done', 'cancel']),
- ('product_id', '=', product_id.id),
- ('lot_id', '=', lot_id.id if lot_id else False),
- ('location_id', '=', location_id.id),
- ('owner_id', '=', owner_id.id if owner_id else False),
- ('package_id', '=', package_id.id if package_id else False),
- ('reserved_qty', '>', 0.0),
- ('id', 'not in', tuple(ml_ids_to_ignore)),
- ]
+ if self.move_id._should_bypass_reservation(location_id):
+ return
- # We take the current picking first, then the pickings with the latest scheduled date
- current_picking_first = lambda cand: (
+ # We now have to find the move lines that reserved our now unavailable quantity. We
+ # take care to exclude ourselves and the move lines were work had already been done.
+ outdated_move_lines_domain = [
+ ('state', 'not in', ['done', 'cancel']),
+ ('product_id', '=', product_id.id),
+ ('lot_id', '=', lot_id.id if lot_id else False),
+ ('location_id', '=', location_id.id),
+ ('owner_id', '=', owner_id.id if owner_id else False),
+ ('package_id', '=', package_id.id if package_id else False),
+ ('quantity', '>', 0.0),
+ ('picked', '=', False),
+ ('id', 'not in', tuple(ml_ids_to_ignore)),
+ ]
+
+ # We take the current picking first, then the pickings with the latest scheduled date
+ def current_picking_first(cand):
+ return (
cand.picking_id != self.move_id.picking_id,
-(cand.picking_id.scheduled_date or cand.move_id.date).timestamp()
if cand.picking_id or cand.move_id
- else -cand.id,
- )
- outdated_candidates = self.env['stock.move.line'].search(outdated_move_lines_domain).sorted(current_picking_first)
+ else -cand.id)
- # As the move's state is not computed over the move lines, we'll have to manually
- # recompute the moves which we adapted their lines.
- move_to_recompute_state = self.env['stock.move']
- to_unlink_candidate_ids = set()
+ outdated_candidates = self.env['stock.move.line'].search(outdated_move_lines_domain).sorted(current_picking_first)
- rounding = self.product_uom_id.rounding
- for candidate in outdated_candidates:
- if float_compare(candidate.reserved_qty, quantity, precision_rounding=rounding) <= 0:
- quantity -= candidate.reserved_qty
- if candidate.qty_done:
- move_to_recompute_state |= candidate.move_id
- candidate.reserved_uom_qty = 0.0
- else:
- to_unlink_candidate_ids.add(candidate.id)
- if float_is_zero(quantity, precision_rounding=rounding):
- break
- else:
- # split this move line and assign the new part to our extra move
- quantity_split = float_round(
- candidate.reserved_qty - quantity,
- precision_rounding=self.product_uom_id.rounding,
- rounding_method='UP')
- candidate.reserved_uom_qty = self.product_id.uom_id._compute_quantity(quantity_split, candidate.product_uom_id, rounding_method='HALF-UP')
- move_to_recompute_state |= candidate.move_id
+ # As the move's state is not computed over the move lines, we'll have to manually
+ # recompute the moves which we adapted their lines.
+ move_to_reassign = self.env['stock.move']
+ to_unlink_candidate_ids = set()
+
+ rounding = self.product_uom_id.rounding
+ for candidate in outdated_candidates:
+ move_to_reassign |= candidate.move_id
+ if float_compare(candidate.quantity_product_uom, quantity, precision_rounding=rounding) <= 0:
+ quantity -= candidate.quantity_product_uom
+ to_unlink_candidate_ids.add(candidate.id)
+ if float_is_zero(quantity, precision_rounding=rounding):
break
- self.env['stock.move.line'].browse(to_unlink_candidate_ids).unlink()
- move_to_recompute_state._recompute_state()
+ else:
+ candidate.quantity -= candidate.product_id.uom_id._compute_quantity(quantity, candidate.product_uom_id, rounding_method='HALF-UP')
+ break
+
+ self.env['stock.move.line'].browse(to_unlink_candidate_ids).unlink()
+ move_to_reassign._action_assign()
def _get_aggregated_product_quantities(self, **kwargs):
""" Returns a dictionary of products (key = id+name+description+uom+packaging) and corresponding values of interest.
@@ -829,7 +745,7 @@ class StockMoveLine(models.Model):
the products by (i.e. so data is not lost). This function purposely ignores lots/SNs because these are
expected to already be properly grouped by line.
- returns: dictionary {product_id+name+description+uom+packaging: {product, name, description, qty_done, product_uom, packaging}, ...}
+ returns: dictionary {product_id+name+description+uom+packaging: {product, name, description, quantity, product_uom, packaging}, ...}
"""
aggregated_move_lines = {}
@@ -849,7 +765,7 @@ class StockMoveLine(models.Model):
for line in aggregated_move_lines.values():
if line['packaging']:
line['packaging_qty'] = line['packaging']._compute_qty(line['qty_ordered'], line['product_uom'])
- line['packaging_qty_done'] = line['packaging']._compute_qty(line['qty_done'], line['product_uom'])
+ line['packaging_quantity'] = line['packaging']._compute_qty(line['quantity'], line['product_uom'])
return aggregated_move_lines
# Loops to get backorders, backorders' backorders, and so and so...
@@ -863,7 +779,7 @@ class StockMoveLine(models.Model):
if kwargs.get('except_package') and move_line.result_package_id:
continue
line_key, name, description, uom, packaging = get_aggregated_properties(move_line=move_line)
- qty_done = move_line.product_uom_id._compute_quantity(move_line.qty_done, uom)
+ quantity = move_line.product_uom_id._compute_quantity(move_line.quantity, uom)
if line_key not in aggregated_move_lines:
qty_ordered = None
if backorders and not kwargs.get('strict'):
@@ -878,19 +794,19 @@ class StockMoveLine(models.Model):
previous_move_lines = move_line.move_id.move_line_ids.filtered(
lambda ml: get_aggregated_properties(move=ml.move_id)[0] == line_key and ml.id != move_line.id
)
- qty_ordered -= sum(map(lambda m: m.product_uom_id._compute_quantity(m.qty_done, uom), previous_move_lines))
+ qty_ordered -= sum([m.product_uom_id._compute_quantity(m.quantity, uom) for m in previous_move_lines])
aggregated_move_lines[line_key] = {
'name': name,
'description': description,
- 'qty_done': qty_done,
- 'qty_ordered': qty_ordered or qty_done,
+ 'quantity': quantity,
+ 'qty_ordered': qty_ordered or quantity,
'product_uom': uom,
'product': move_line.product_id,
'packaging': packaging,
}
else:
- aggregated_move_lines[line_key]['qty_ordered'] += qty_done
- aggregated_move_lines[line_key]['qty_done'] += qty_done
+ aggregated_move_lines[line_key]['qty_ordered'] += quantity
+ aggregated_move_lines[line_key]['quantity'] += quantity
# Does the same for empty move line to retrieve the ordered qty. for partially done moves
# (as they are splitted when the transfer is done and empty moves don't have move lines).
@@ -899,7 +815,7 @@ class StockMoveLine(models.Model):
pickings = (self.picking_id | backorders)
for empty_move in pickings.move_ids:
if not (empty_move.state == "cancel" and empty_move.product_uom_qty
- and float_is_zero(empty_move.quantity_done, precision_rounding=empty_move.product_uom.rounding)):
+ and float_is_zero(empty_move.quantity, precision_rounding=empty_move.product_uom.rounding)):
continue
line_key, name, description, uom, packaging = get_aggregated_properties(move=empty_move)
@@ -908,7 +824,7 @@ class StockMoveLine(models.Model):
aggregated_move_lines[line_key] = {
'name': name,
'description': description,
- 'qty_done': False,
+ 'quantity': False,
'qty_ordered': qty_ordered,
'product_uom': uom,
'product': empty_move.product_id,
@@ -929,11 +845,12 @@ class StockMoveLine(models.Model):
return {
'name': _('New Move:') + self.product_id.display_name,
'product_id': self.product_id.id,
- 'product_uom_qty': 0 if self.picking_id and self.picking_id.state != 'done' else self.qty_done,
+ 'product_uom_qty': 0 if self.picking_id and self.picking_id.state != 'done' else self.quantity,
'product_uom': self.product_uom_id.id,
'description_picking': self.description_picking,
'location_id': self.picking_id.location_id.id,
'location_dest_id': self.picking_id.location_dest_id.id,
+ 'picked': self.picked,
'picking_id': self.picking_id.id,
'state': self.picking_id.state,
'picking_type_id': self.picking_id.picking_type_id.id,
@@ -945,12 +862,6 @@ class StockMoveLine(models.Model):
def _copy_quant_info(self, vals):
quant = self.env['stock.quant'].browse(vals.get('quant_id', 0))
- if self:
- uom = self.product_uom_id
- elif vals.get('product_uom_id'):
- uom = self.env['uom.uom'].browse(vals.get('product_uom_id'))
- else:
- uom = quant.product_uom_id
line_data = {
'product_id': quant.product_id.id,
'lot_id': quant.lot_id.id,
@@ -979,16 +890,17 @@ class StockMoveLine(models.Model):
'name':_('%s [reverted]', self.reference),
'product_id': self.product_id.id,
'product_uom': self.product_uom_id.id,
- 'product_uom_qty': self.qty_done,
+ 'product_uom_qty': self.quantity,
'company_id': self.company_id.id or self.env.company.id,
'state': 'confirmed',
'location_id': self.location_dest_id.id,
'location_dest_id': self.location_id.id,
'is_inventory': True,
+ 'picked': True,
'move_line_ids': [(0, 0, {
'product_id': self.product_id.id,
'product_uom_id': self.product_uom_id.id,
- 'qty_done': self.qty_done,
+ 'quantity': self.quantity,
'location_id': self.location_dest_id.id,
'location_dest_id': self.location_id.id,
'company_id': self.company_id.id or self.env.company.id,
@@ -1005,7 +917,7 @@ class StockMoveLine(models.Model):
self = self.with_context(inventory_mode=False)
processed_move_line = self.env['stock.move.line']
for move_line in self:
- if move_line.is_inventory and not float_is_zero(move_line.qty_done, precision_digits=move_line.product_uom_id.rounding):
+ if move_line.is_inventory and not float_is_zero(move_line.quantity, precision_digits=move_line.product_uom_id.rounding):
processed_move_line += move_line
move_vals.append(move_line._get_revert_inventory_move_values())
if not processed_move_line:
diff --git a/addons/stock/models/stock_package_level.py b/addons/stock/models/stock_package_level.py
index 5ff6d481241..bb80780a834 100644
--- a/addons/stock/models/stock_package_level.py
+++ b/addons/stock/models/stock_package_level.py
@@ -39,20 +39,23 @@ class StockPackageLevel(models.Model):
show_lots_text = fields.Boolean(compute='_compute_show_lot')
company_id = fields.Many2one('res.company', 'Company', required=True, index=True)
- @api.depends('move_line_ids', 'move_line_ids.qty_done')
+ @api.depends('move_line_ids', 'move_line_ids.quantity')
def _compute_is_done(self):
for package_level in self:
# If it is an existing package
if package_level.is_fresh_package:
package_level.is_done = True
else:
- package_level.is_done = package_level._check_move_lines_map_quant_package(package_level.package_id, 'qty_done')
+ package_level.is_done = package_level._check_move_lines_map_quant_package(package_level.package_id, only_picked=True)
def _set_is_done(self):
for package_level in self:
if package_level.is_done:
if not package_level.is_fresh_package:
ml_update_dict = defaultdict(float)
+ package_level.picking_id.move_line_ids.filtered(
+ lambda ml: not ml.package_level_id and ml.package_id == package_level.package_id
+ ).unlink()
for quant in package_level.package_id.quant_ids:
corresponding_mls = package_level.move_line_ids.filtered(lambda ml: ml.product_id == quant.product_id and ml.lot_id == quant.lot_id)
to_dispatch = quant.quantity
@@ -70,7 +73,7 @@ class StockPackageLevel(models.Model):
'location_dest_id': package_level.location_dest_id.id,
'picking_id': package_level.picking_id.id,
'product_id': quant.product_id.id,
- 'qty_done': quant.quantity,
+ 'quantity': quant.quantity,
'product_uom_id': quant.product_id.uom_id.id,
'lot_id': quant.lot_id.id,
'package_id': package_level.package_id.id,
@@ -78,12 +81,13 @@ class StockPackageLevel(models.Model):
'package_level_id': package_level.id,
'move_id': corresponding_move.id,
'owner_id': quant.owner_id.id,
+ 'picked': True,
})
for rec, quant in ml_update_dict.items():
- rec.qty_done = quant
+ rec.quantity = quant
+ rec.picked = True
else:
- package_level.move_line_ids.filtered(lambda ml: ml.reserved_qty == 0).unlink()
- package_level.move_line_ids.filtered(lambda ml: ml.reserved_qty != 0).write({'qty_done': 0})
+ package_level.move_line_ids.unlink()
@api.depends('move_line_ids', 'move_line_ids.package_id', 'move_line_ids.result_package_id')
def _compute_fresh_pack(self):
@@ -103,7 +107,7 @@ class StockPackageLevel(models.Model):
elif package_level.move_line_ids and not package_level.move_line_ids.filtered(lambda ml: ml.state in ('done', 'cancel')):
if package_level.is_fresh_package:
package_level.state = 'new'
- elif package_level._check_move_lines_map_quant_package(package_level.package_id, 'reserved_uom_qty'):
+ elif package_level._check_move_lines_map_quant_package(package_level.package_id):
package_level.state = 'assigned'
else:
package_level.state = 'confirmed'
@@ -168,8 +172,11 @@ class StockPackageLevel(models.Model):
self.mapped('move_line_ids').write({'result_package_id': False})
return super(StockPackageLevel, self).unlink()
- def _check_move_lines_map_quant_package(self, package, field):
- return package._check_move_lines_map_quant(self.move_line_ids, field)
+ def _check_move_lines_map_quant_package(self, package, only_picked=False):
+ mls = self.move_line_ids
+ if only_picked:
+ mls = mls.filtered(lambda ml: ml.picked)
+ return package._check_move_lines_map_quant(mls)
@api.depends('package_id', 'state', 'is_fresh_package', 'move_ids', 'move_line_ids')
def _compute_location_id(self):
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 225500b9daf..7c9d446738a 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -322,14 +322,9 @@ class PickingType(models.Model):
if self:
action['display_name'] = self.display_name
- default_immediate_tranfer = True
- if self.env['ir.config_parameter'].sudo().get_param('stock.no_default_immediate_tranfer'):
- default_immediate_tranfer = False
-
context = {
'search_default_picking_type_id': [self.id],
'default_picking_type_id': self.id,
- 'default_immediate_transfer': default_immediate_tranfer,
'default_company_id': self.company_id.id,
}
@@ -416,7 +411,7 @@ class Picking(models.Model):
('assigned', 'Ready'),
('done', 'Done'),
('cancel', 'Cancelled'),
- ], string='Status', compute='_compute_state', default='assigned',
+ ], string='Status', compute='_compute_state',
copy=False, index=True, readonly=True, store=True, tracking=True,
help=" * Draft: The transfer is not confirmed yet. Reservation doesn't apply.\n"
" * Waiting another operation: This transfer is waiting for another operation before being ready.\n"
@@ -483,9 +478,6 @@ class Picking(models.Model):
default=lambda self: self.env.user)
move_line_ids = fields.One2many('stock.move.line', 'picking_id', 'Operations')
move_line_ids_without_package = fields.One2many('stock.move.line', 'picking_id', 'Operations without package', domain=['|',('package_level_id', '=', False), ('picking_type_entire_packs', '=', False)])
- move_line_nosuggest_ids = fields.One2many(
- 'stock.move.line', 'picking_id',
- domain=['|', ('reserved_qty', '=', 0.0), '&', ('reserved_qty', '!=', 0.0), ('qty_done', '!=', 0.0)])
move_line_exist = fields.Boolean(
'Has Pack Operations', compute='_compute_move_line_exist',
help='Check the existence of pack operation on the picking')
@@ -495,9 +487,6 @@ class Picking(models.Model):
show_check_availability = fields.Boolean(
compute='_compute_show_check_availability',
help='Technical field used to compute whether the button "Check Availability" should be displayed.')
- show_validate = fields.Boolean(
- compute='_compute_show_validate',
- help='Technical field used to decide whether the button "Validate" should be displayed.')
show_allocation = fields.Boolean(
compute='_compute_show_allocation',
help='Technical Field used to decide whether the button "Allocation" should be displayed.')
@@ -519,7 +508,6 @@ class Picking(models.Model):
show_reserved = fields.Boolean(related='picking_type_id.show_reserved')
show_lots_text = fields.Boolean(compute='_compute_show_lots_text')
has_tracking = fields.Boolean(compute='_compute_has_tracking')
- immediate_transfer = fields.Boolean(default=True)
package_level_ids = fields.One2many('stock.package_level', 'picking_id')
package_level_ids_details = fields.One2many('stock.package_level', 'picking_id')
products_availability = fields.Char(
@@ -541,18 +529,16 @@ class Picking(models.Model):
('name_uniq', 'unique(name, company_id)', 'Reference must be unique per company!'),
]
- @api.depends('show_validate',
- 'move_ids.reserved_availability',
- 'move_ids.quantity_done')
+ @api.depends('move_ids.product_uom_qty', 'move_ids.quantity')
def _compute_show_qty_button(self):
self.show_set_qty_button = False
self.show_clear_qty_button = False
for picking in self:
- if not picking.show_validate:
+ if picking.state in ['draft', 'done', 'cancel']:
continue
- if any(float_is_zero(m.quantity_done, precision_rounding=m.product_uom.rounding) and not float_is_zero(m.reserved_availability, precision_rounding=m.product_uom.rounding) for m in picking.move_ids):
+ if any(float_is_zero(m.quantity, precision_rounding=m.product_uom.rounding) and not float_is_zero(m.product_uom_qty, precision_rounding=m.product_uom.rounding) for m in picking.move_ids):
picking.show_set_qty_button = True
- elif any(not float_is_zero(m.quantity_done, precision_rounding=m.product_uom.rounding) and float_compare(m.quantity_done, m.reserved_availability, precision_rounding=m.product_uom.rounding) == 0 for m in picking.move_ids):
+ elif any(not float_is_zero(m.quantity, precision_rounding=m.product_uom.rounding) for m in picking.move_ids):
picking.show_clear_qty_button = True
def _compute_has_tracking(self):
@@ -673,11 +659,7 @@ class Picking(models.Model):
picking_move_lines[picking_id.id].add(move.id)
for picking in self:
picking_id = (picking.ids and picking.ids[0]) or picking.id
- if not picking_moves_state_map[picking_id] and picking.immediate_transfer:
- continue
- elif not picking_moves_state_map[picking_id]:
- picking.state = 'draft'
- elif picking_moves_state_map[picking_id]['any_draft']:
+ if not picking_moves_state_map[picking_id] or picking_moves_state_map[picking_id]['any_draft']:
picking.state = 'draft'
elif picking_moves_state_map[picking_id]['all_cancel']:
picking.state = 'cancel'
@@ -688,9 +670,7 @@ class Picking(models.Model):
picking.state = 'done'
else:
relevant_move_state = self.env['stock.move'].browse(picking_move_lines[picking_id])._get_relevant_state_among_moves()
- if picking.immediate_transfer and relevant_move_state not in ('draft', 'cancel', 'done'):
- picking.state = 'assigned'
- elif relevant_move_state == 'partially_available':
+ if relevant_move_state == 'partially_available':
picking.state = 'assigned'
else:
picking.state = relevant_move_state
@@ -740,10 +720,10 @@ class Picking(models.Model):
displayed in the form view of a picking.
"""
for picking in self:
- if picking.immediate_transfer and picking.picking_type_code == 'incoming':
+ if picking.state not in ('confirmed', 'waiting', 'assigned'):
picking.show_check_availability = False
continue
- if picking.state not in ('confirmed', 'waiting', 'assigned'):
+ if all(m.picked for m in picking.move_ids):
picking.show_check_availability = False
continue
picking.show_check_availability = any(
@@ -752,15 +732,6 @@ class Picking(models.Model):
for move in picking.move_ids
)
- @api.depends('state')
- def _compute_show_validate(self):
- for picking in self:
- if picking.state == 'draft':
- picking.show_validate = False
- elif picking.state not in ('draft', 'waiting', 'confirmed', 'assigned'):
- picking.show_validate = False
- else:
- picking.show_validate = True
@api.depends('state', 'move_ids', 'picking_type_id')
def _compute_show_allocation(self):
self.show_allocation = False
@@ -857,7 +828,7 @@ class Picking(models.Model):
"location_id": self.location_id,
"location_dest_id": self.location_dest_id
})
- if any(line.reserved_qty or line.qty_done for line in self.move_ids.move_line_ids):
+ if any(line.quantity for line in self.move_ids.move_line_ids):
return {'warning': {
'title': 'Locations to update',
'message': _("You might want to update the locations of this transfer's operations")
@@ -878,11 +849,6 @@ class Picking(models.Model):
# order to get a determinist execution of `_set_scheduled_date`
scheduled_dates.append(vals.pop('scheduled_date', False))
- # immediate transfer is a default value allow in specific cases (interface only)
- if vals.get('state', 'assigned') != 'assigned':
- vals['immediate_transfer'] = False
- if self.env['ir.config_parameter'].sudo().get_param('stock.no_default_immediate_tranfer'):
- vals['immediate_transfer'] = False
pickings = super().create(vals_list)
for picking, scheduled_date in zip(pickings, scheduled_dates):
@@ -949,8 +915,6 @@ class Picking(models.Model):
def action_confirm(self):
self._check_company()
- if not self.env.context.get('skip_draft'):
- self.filtered(lambda p: p.state in ['assigned', 'draft'] and p.immediate_transfer).action_reset_draft()
self.mapped('package_level_ids').filtered(lambda pl: pl.state == 'draft' and not pl.move_ids)._generate_moves()
# call `_action_confirm` on every draft move
self.move_ids.filtered(lambda move: move.state == 'draft')._action_confirm()
@@ -987,17 +951,6 @@ class Picking(models.Model):
self.filtered(lambda x: not x.move_ids).state = 'cancel'
return True
- def action_reset_draft(self):
- picking_to_reset = self.filtered(lambda p: p.state not in ('done', 'cancel'))
- picking_to_reset.do_unreserve()
- picking_to_reset.immediate_transfer = False
- if picking_to_reset.move_ids:
- picking_to_reset.move_ids.quantity_done = 0
- picking_to_reset.move_ids.move_line_ids.unlink()
- picking_to_reset.move_ids.state = 'draft'
- else:
- picking_to_reset.state = 'draft'
-
def _action_done(self):
"""Call `_action_done` on the `stock.move` of the `stock.picking` in `self`.
This method makes sure every `stock.move.line` is linked to a `stock.move` by either
@@ -1036,7 +989,7 @@ class Picking(models.Model):
)
def _check_move_lines_map_quant_package(self, package):
- return package._check_move_lines_map_quant(self.move_line_ids.filtered(lambda ml: ml.package_id == package), 'reserved_qty')
+ return package._check_move_lines_map_quant(self.move_line_ids.filtered(lambda ml: ml.package_id == package))
def _get_entire_pack_location_dest(self, move_line_ids):
location_dest_ids = move_line_ids.mapped('location_dest_id')
@@ -1054,9 +1007,7 @@ class Picking(models.Model):
move_lines_to_pack = picking.move_line_ids.filtered(lambda ml: ml.package_id == pack and not ml.result_package_id and ml.state not in ('done', 'cancel'))
if not package_level_ids:
package_location = self._get_entire_pack_location_dest(move_lines_to_pack) or picking.location_dest_id.id
- self.env['stock.package_level'].with_context(
- bypass_reservation_update=package_location
- ).create({
+ self.env['stock.package_level'].create({
'picking_id': picking.id,
'package_id': pack.id,
'location_id': pack.location_id.id,
@@ -1066,9 +1017,7 @@ class Picking(models.Model):
})
# Propagate the result package in the next move for disposable packages only.
if pack.package_use == 'disposable':
- move_lines_to_pack.with_context(
- bypass_reservation_update=package_location
- ).write({'result_package_id': pack.id})
+ move_lines_to_pack.write({'result_package_id': pack.id})
else:
move_lines_in_package_level = move_lines_to_pack.filtered(lambda ml: ml.move_id.package_level_id)
move_lines_without_package_level = move_lines_to_pack - move_lines_in_package_level
@@ -1090,25 +1039,25 @@ class Picking(models.Model):
def _get_lot_move_lines_for_sanity_check(self, none_done_picking_ids, separate_pickings=True):
""" Get all move_lines with tracked products that need to be checked over in the sanity check.
- :param none_done_picking_ids: Set of all pickings ids that have no qty_done set on any move_line.
+ :param none_done_picking_ids: Set of all pickings ids that have no quantity set on any move_line.
:param separate_pickings: Indicates if pickings should be checked independently for lot/serial numbers or not.
"""
def get_relevant_move_line_ids(none_done_picking_ids, picking):
- # Get all move_lines if picking has no qty_done set, otherwise only get the move_lines with some qty_done set.
+ # Get all move_lines if picking has no quantity set, otherwise only get the move_lines with some quantity set.
if picking.id in none_done_picking_ids:
return picking.move_line_ids.filtered(lambda ml: ml.product_id and ml.product_id.tracking != 'none').ids
else:
return get_line_with_done_qty_ids(picking.move_line_ids)
def get_line_with_done_qty_ids(move_lines):
- # Get only move_lines that has some qty_done set.
- return move_lines.filtered(lambda ml: ml.product_id and ml.product_id.tracking != 'none' and float_compare(ml.qty_done, 0, precision_rounding=ml.product_uom_id.rounding)).ids
+ # Get only move_lines that has some quantity set.
+ return move_lines.filtered(lambda ml: ml.product_id and ml.product_id.tracking != 'none' and float_compare(ml.quantity, 0, precision_rounding=ml.product_uom_id.rounding)).ids
if separate_pickings:
- # If pickings are checked independently, get full/partial move_lines depending if each picking has no qty_done set.
+ # If pickings are checked independently, get full/partial move_lines depending if each picking has no quantity set.
lines_to_check_ids = [line_id for picking in self for line_id in get_relevant_move_line_ids(none_done_picking_ids, picking)]
else:
- # If pickings are checked as one (like in a batch), then get only the move_lines with qty_done across all pickings if there is at least one.
+ # If pickings are checked as one (like in a batch), then get only the move_lines with quantity across all pickings if there is at least one.
if any(picking.id not in none_done_picking_ids for picking in self):
lines_to_check_ids = get_line_with_done_qty_ids(self.move_line_ids)
else:
@@ -1126,13 +1075,10 @@ class Picking(models.Model):
precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
no_quantities_done_ids = set()
- no_reserved_quantities_ids = set()
+ pickings_without_quantities = self.env['stock.picking']
for picking in self:
- if all(float_is_zero(move_line.qty_done, precision_digits=precision_digits) for move_line in picking.move_line_ids.filtered(lambda m: m.state not in ('done', 'cancel'))):
- no_quantities_done_ids.add(picking.id)
- if all(float_is_zero(move_line.reserved_qty, precision_rounding=move_line.product_uom_id.rounding) for move_line in picking.move_line_ids):
- no_reserved_quantities_ids.add(picking.id)
- pickings_without_quantities = self.filtered(lambda p: p.id in no_quantities_done_ids and p.id in no_reserved_quantities_ids and not p.immediate_transfer)
+ if all(float_is_zero(move.quantity, precision_digits=precision_digits) for move in picking.move_ids.filtered(lambda m: m.state not in ('done', 'cancel'))):
+ pickings_without_quantities |= picking
pickings_using_lots = self.filtered(lambda p: p.picking_type_id.use_create_lots or p.picking_type_id.use_existing_lots)
if pickings_using_lots:
@@ -1153,8 +1099,6 @@ class Picking(models.Model):
message = ""
if pickings_without_moves:
message += _('Transfers %s: Please add some items to move.', ', '.join(pickings_without_moves.mapped('name')))
- if pickings_without_quantities:
- message += _('\n\nTransfers %s: You cannot validate these transfers if no quantities are reserved nor done. To force these transfers, switch in edit more and encode the done quantities.', ', '.join(pickings_without_quantities.mapped('name')))
if pickings_without_lots:
message += _('\n\nTransfers %s: You need to supply a Lot/Serial number for products %s.', ', '.join(pickings_without_lots.mapped('name')), ', '.join(products_without_lots.mapped('display_name')))
if message:
@@ -1165,16 +1109,9 @@ class Picking(models.Model):
self.package_level_ids.filtered(lambda p: not p.move_ids).unlink()
def button_validate(self):
- # Clean-up the context key at validation to avoid forcing the creation of immediate
- # transfers.
- ctx = dict(self.env.context)
- ctx.pop('default_immediate_transfer', None)
- self = self.with_context(ctx)
-
# Sanity checks.
if not self.env.context.get('skip_sanity_check', False):
self._sanity_check()
-
self.message_subscribe([self.env.user.partner_id.id])
# Run the pre-validation wizards. Processing a pre-validation wizard should work on the
@@ -1198,7 +1135,7 @@ class Picking(models.Model):
another_action = False
if self.user_has_groups('stock.group_reception_report'):
pickings_show_report = self.filtered(lambda p: p.picking_type_id.auto_show_reception_report)
- lines = pickings_show_report.move_ids.filtered(lambda m: m.product_id.type == 'product' and m.state != 'cancel' and m.quantity_done and not m.move_dest_ids)
+ lines = pickings_show_report.move_ids.filtered(lambda m: m.product_id.type == 'product' and m.state != 'cancel' and m.quantity and not m.move_dest_ids)
if lines:
# don't show reception report if all already assigned/nothing to assign
wh_location_ids = self.env['stock.location']._search([('id', 'child_of', pickings_show_report.picking_type_id.warehouse_id.view_location_id.ids), ('usage', '!=', 'supplier')])
@@ -1225,34 +1162,17 @@ class Picking(models.Model):
}
return True
- def action_set_quantities_to_reservation(self):
- self.move_ids.filtered(lambda m: float_is_zero(m.quantity_done, precision_rounding=m.product_uom.rounding))._set_quantities_to_reservation()
-
def action_clear_quantities_to_zero(self):
- self.move_ids.filtered(lambda m: float_compare(m.quantity_done, m.reserved_availability, precision_rounding=m.product_uom.rounding) == 0)._clear_quantities_to_zero()
+ self.move_ids.filtered(lambda m: not m.picked)._do_unreserve()
def _pre_action_done_hook(self):
- if not self.env.context.get('skip_immediate'):
- pickings_to_immediate = self._check_immediate()
- if pickings_to_immediate:
- return pickings_to_immediate._action_generate_immediate_wizard(show_transfers=self._should_show_transfers())
-
+ for picking in self:
+ if all(not move.picked for move in picking.move_ids):
+ picking.move_ids.picked = True
if not self.env.context.get('skip_backorder'):
pickings_to_backorder = self._check_backorder()
if pickings_to_backorder:
return pickings_to_backorder._action_generate_backorder_wizard(show_transfers=self._should_show_transfers())
-
- message = ''
- for move in self.move_ids:
- if float_compare(move.quantity_done, move.product_uom_qty, precision_rounding=move.product_uom.rounding) > 0 \
- and not float_is_zero(move.product_uom_qty, precision_rounding=move.product_uom.rounding) \
- and move.from_immediate_transfer:
- message += _('%(name)s has a quantity of %(initial_qty)s %(uom)s done, but %(done_qty)s %(uom)s reserved\n', name=move.product_id.display_name, initial_qty=move.product_uom_qty, done_qty=move.quantity_done, uom=move.product_uom.name)
- if move.from_immediate_transfer and float_compare(move.product_qty, move.quantity_done, precision_rounding=move.product_uom.rounding) > 0:
- move.quantity_done = move.product_qty
- if message:
- message = _('The product(s)\n') + message + _('Update quantities of those products.')
- raise UserError(message)
return True
def _should_show_transfers(self):
@@ -1260,14 +1180,14 @@ class Picking(models.Model):
return len(self) > 1
def _get_without_quantities_error_message(self):
- """ Returns the error message raised in validation if no quantities are reserved or done.
+ """ Returns the error message raised in validation if no quantities are reserved.
The purpose of this method is to be overridden in case we want to adapt this message.
:return: Translated error message
:rtype: str
"""
return _(
- 'You cannot validate a transfer if no quantities are reserved nor done. '
+ 'You cannot validate a transfer if no quantities are reserved. '
'To force the transfer, switch in edit mode and encode the done quantities.'
)
@@ -1284,19 +1204,6 @@ class Picking(models.Model):
'context': dict(self.env.context, default_show_transfers=show_transfers, default_pick_ids=[(4, p.id) for p in self]),
}
- def _action_generate_immediate_wizard(self, show_transfers=False):
- view = self.env.ref('stock.view_immediate_transfer')
- return {
- 'name': _('Immediate Transfer?'),
- 'type': 'ir.actions.act_window',
- 'view_mode': 'form',
- 'res_model': 'stock.immediate.transfer',
- 'views': [(view.id, 'form')],
- 'view_id': view.id,
- 'target': 'new',
- 'context': dict(self.env.context, default_show_transfers=show_transfers, default_pick_ids=[(4, p.id) for p in self]),
- }
-
def action_toggle_is_locked(self):
self.ensure_one()
self.is_locked = not self.is_locked
@@ -1309,41 +1216,28 @@ class Picking(models.Model):
if picking.picking_type_id.create_backorder != 'ask':
continue
if any(
- float_compare(move.quantity_done, move.product_uom_qty, precision_digits=prec) < 0
+ float_compare(move.quantity, move.product_uom_qty, precision_digits=prec) < 0 or
+ (move.product_uom_qty and not move.picked)
for move in picking.move_ids
if move.state != 'cancel'
):
backorder_pickings |= picking
return backorder_pickings
- def _check_immediate(self):
- immediate_pickings = self.browse()
- precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
- for picking in self:
- if picking.immediate_transfer:
- continue
- if all(float_is_zero(move_line.qty_done, precision_digits=precision_digits) for move_line in picking.move_line_ids.filtered(lambda m: m.state not in ('done', 'cancel'))):
- immediate_pickings |= picking
- return immediate_pickings
-
def _autoconfirm_picking(self):
- """ Automatically run `action_confirm` on `self` if the picking is an immediate transfer or
- if the picking is a planned transfer and one of its move was added after the initial
+ """ Automatically run `action_confirm` on `self` if one of the
+ picking's move was added after the initial
call to `action_confirm`. Note that `action_confirm` will only work on draft moves.
"""
- # Clean-up the context key to avoid forcing the creation of immediate transfers.
- ctx = dict(self.env.context)
- ctx.pop('default_immediate_transfer', None)
- self = self.with_context(ctx)
for picking in self:
if picking.state in ('done', 'cancel'):
continue
if not picking.move_ids and not picking.package_level_ids:
continue
if any(move.additional for move in picking.move_ids):
- picking.with_context(skip_draft=picking.immediate_transfer).action_confirm()
- if picking.immediate_transfer:
- picking.move_ids.write({'state': 'assigned'})
+ picking.action_confirm()
+ to_confirm = self.move_ids.filtered(lambda m: m.state == 'draft' and not m.product_uom_qty and m.quantity)
+ to_confirm._action_confirm()
def _create_backorder(self):
""" This method is called when the user chose to create a backorder. It will create a new
@@ -1365,7 +1259,8 @@ class Picking(models.Model):
body=_('The backorder %s has been created.', backorder_picking._get_html_link())
)
moves_to_backorder.write({'picking_id': backorder_picking.id})
- moves_to_backorder.move_line_ids.package_level_id.write({'picking_id':backorder_picking.id})
+ moves_to_backorder.move_line_ids.package_level_id.write({'picking_id': backorder_picking.id})
+ # moves_to_backorder._do_unreserve()
moves_to_backorder.mapped('move_line_ids').write({'picking_id': backorder_picking.id})
backorders |= backorder_picking
if backorder_picking.picking_type_id.reservation_method == 'at_confirm':
@@ -1555,43 +1450,19 @@ class Picking(models.Model):
def _put_in_pack(self, move_line_ids, create_package_level=True):
self.ensure_one()
- move_lines_to_pack = self.env['stock.move.line']
package = self.env['stock.quant.package'].create({})
- precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
- if float_is_zero(move_line_ids[0].qty_done, precision_digits=precision_digits):
- for line in move_line_ids:
- line.qty_done = line.reserved_uom_qty
- for ml in move_line_ids:
- if float_compare(ml.qty_done, ml.reserved_uom_qty, precision_rounding=ml.product_uom_id.rounding) >= 0:
- move_lines_to_pack |= ml
- else:
- quantity_left_todo = float_round(
- ml.reserved_uom_qty - ml.qty_done,
- precision_rounding=ml.product_uom_id.rounding,
- rounding_method='HALF-UP')
- done_to_keep = ml.qty_done
- new_move_line = ml.copy(
- default={'reserved_uom_qty': 0, 'qty_done': ml.qty_done})
- vals = {'reserved_uom_qty': quantity_left_todo, 'qty_done': 0.0}
- if self.picking_type_id.code == 'incoming':
- if ml.lot_id:
- vals['lot_id'] = False
- if ml.lot_name:
- vals['lot_name'] = False
- ml.write(vals)
- new_move_line.write({'reserved_uom_qty': done_to_keep})
- move_lines_to_pack |= new_move_line
- package_type = move_lines_to_pack.move_id.product_packaging_id.package_type_id
- if len(package_type) == 1:
- package.package_type_id = package_type
- if len(move_lines_to_pack) == 1:
- default_dest_location = move_lines_to_pack._get_default_dest_location()
- move_lines_to_pack.location_dest_id = default_dest_location._get_putaway_strategy(
- product=move_lines_to_pack.product_id,
- quantity=move_lines_to_pack.reserved_uom_qty,
+ if not package.package_type_id:
+ package_type = move_line_ids.move_id.product_packaging_id.package_type_id
+ if len(package_type) == 1:
+ package.package_type_id = package_type
+ if len(move_line_ids) == 1:
+ default_dest_location = move_line_ids._get_default_dest_location()
+ move_line_ids.location_dest_id = default_dest_location._get_putaway_strategy(
+ product=move_line_ids.product_id,
+ quantity=move_line_ids.quantity,
package=package)
- move_lines_to_pack.write({
+ move_line_ids.write({
'result_package_id': package.id,
})
if create_package_level:
@@ -1599,8 +1470,8 @@ class Picking(models.Model):
'package_id': package.id,
'picking_id': self.id,
'location_id': False,
- 'location_dest_id': move_lines_to_pack.mapped('location_dest_id').id,
- 'move_line_ids': [Command.set(move_lines_to_pack.ids)],
+ 'location_dest_id': move_line_ids.mapped('location_dest_id').id,
+ 'move_line_ids': [(6, 0, move_line_ids.ids)],
'company_id': self.company_id.id,
})
return package
@@ -1620,33 +1491,23 @@ class Picking(models.Model):
def action_put_in_pack(self):
self.ensure_one()
if self.state not in ('done', 'cancel'):
- if self.immediate_transfer:
- for move in self.move_ids:
- if float_is_zero(move.quantity_done, precision_rounding=move.product_uom.rounding):
- move.quantity_done = move.product_qty
- picking_move_lines = self.move_line_ids
- if (
- not self.picking_type_id.show_reserved
- and not self.env.context.get('barcode_view')
- ):
- picking_move_lines = self.move_line_nosuggest_ids
- move_line_ids = picking_move_lines.filtered(lambda ml:
- float_compare(ml.qty_done, 0.0, precision_rounding=ml.product_uom_id.rounding) > 0
- and not ml.result_package_id
+ quantity_move_line_ids = self.move_line_ids.filtered(
+ lambda ml:
+ float_compare(ml.quantity, 0.0, precision_rounding=ml.product_uom_id.rounding) > 0 and
+ not ml.result_package_id
)
+ move_line_ids = quantity_move_line_ids.filtered(lambda ml: ml.picked)
if not move_line_ids:
- move_line_ids = picking_move_lines.filtered(lambda ml: float_compare(ml.reserved_uom_qty, 0.0,
- precision_rounding=ml.product_uom_id.rounding) > 0 and float_compare(ml.qty_done, 0.0,
- precision_rounding=ml.product_uom_id.rounding) == 0)
+ move_line_ids = quantity_move_line_ids
if move_line_ids:
res = self._pre_put_in_pack_hook(move_line_ids)
if not res:
package = self._put_in_pack(move_line_ids)
+ self.action_assign()
return self._post_put_in_pack_hook(package)
return res
- else:
- raise UserError(_("Please add 'Done' quantities to the picking to create a new pack."))
+ raise UserError(_("Please add 'Done' quantities to the picking to create a new pack."))
def button_scrap(self):
self.ensure_one()
diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py
index 516ae683b0e..a8a59cc6e22 100644
--- a/addons/stock/models/stock_quant.py
+++ b/addons/stock/models/stock_quant.py
@@ -223,9 +223,13 @@ class StockQuant(models.Model):
"""
if not self._is_inventory_mode():
return
+ quant_to_inventory = self.env['stock.quant']
for quant in self:
+ if quant.quantity == quant.inventory_quantity_auto_apply:
+ continue
quant.inventory_quantity = quant.inventory_quantity_auto_apply
- self.action_apply_inventory()
+ quant_to_inventory |= quant
+ quant_to_inventory.action_apply_inventory()
def _search_on_hand(self, operator, value):
"""Handle the "on_hand" filter, indirectly calling `_get_domain_locations`."""
@@ -598,6 +602,8 @@ class StockQuant(models.Model):
@api.model
def _get_removal_strategy(self, product_id, location_id):
+ product_id = product_id.sudo()
+ location_id = location_id.sudo()
if product_id.categ_id.removal_strategy_id:
return product_id.categ_id.removal_strategy_id.method
loc = location_id
@@ -991,8 +997,8 @@ class StockQuant(models.Model):
return quants_by_product
@api.model
- def _update_available_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, in_date=None):
- """ Increase or decrease `reserved_quantity` of a set of quants for a given set of
+ def _update_available_quantity(self, product_id, location_id, quantity=False, reserved_quantity=False, lot_id=None, package_id=None, owner_id=None, in_date=None):
+ """ Increase or decrease `quantity` or 'reserved quantity' of a set of quants for a given set of
product_id/location_id/lot_id/package_id/owner_id.
:param product_id:
@@ -1006,6 +1012,8 @@ class StockQuant(models.Model):
current datetime will be used.
:return: tuple (available_quantity, in_date as a datetime)
"""
+ if not (quantity or reserved_quantity):
+ raise ValidationError(_('Quantity or Reserved Quantity should be set.'))
self = self.sudo()
quants = self._gather(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=True)
if lot_id and quantity > 0:
@@ -1034,39 +1042,42 @@ class StockQuant(models.Model):
quant = self.browse(stock_quant_result[0])
if quant:
- quant.write({
- 'quantity': quant.quantity + quantity,
- 'in_date': in_date,
- })
+ vals = {'in_date': in_date}
+ if quantity:
+ vals['quantity'] = quant.quantity + quantity
+ if reserved_quantity:
+ vals['reserved_quantity'] = quant.reserved_quantity + reserved_quantity
+ quant.write(vals)
else:
- self.create({
+ vals = {
'product_id': product_id.id,
'location_id': location_id.id,
- 'quantity': quantity,
'lot_id': lot_id and lot_id.id,
'package_id': package_id and package_id.id,
'owner_id': owner_id and owner_id.id,
'in_date': in_date,
- })
+ }
+ if quantity:
+ vals['quantity'] = quantity
+ if reserved_quantity:
+ vals['reserved_quantity'] = reserved_quantity
+ self.create(vals)
return self._get_available_quantity(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=False, allow_negative=True), in_date
- def _update_reserved_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, strict=False):
- """ Increase the reserved quantity, i.e. increase `reserved_quantity` for the set of quants
- sharing the combination of `product_id, location_id` if `strict` is set to False or sharing
- the *exact same characteristics* otherwise. Typically, this method is called when reserving
- a move or updating a reserved move line. When reserving a chained move, the strict flag
- should be enabled (to reserve exactly what was brought). When the move is MTS,it could take
- anything from the stock, so we disable the flag. When editing a move line, we naturally
- enable the flag, to reflect the reservation according to the edition.
+ @api.model
+ def _update_reserved_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, strict=True):
+ """ Increase or decrease `reserved_quantity` of a set of quants for a given set of
+ product_id/location_id/lot_id/package_id/owner_id.
- :return: a list of tuples (quant, quantity_reserved) showing on which quant the reservation
- was done and how much the system was able to reserve on it
+ :param product_id:
+ :param location_id:
+ :param quantity:
+ :param lot_id:
+ :param package_id:
+ :param owner_id:
+ :return: available_quantity
"""
- self = self.sudo()
- quants_to_reserve = self._get_reserve_quantity(product_id, location_id, quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict)
- for quant, qty_to_reserve in quants_to_reserve:
- quant.reserved_quantity += qty_to_reserve
- return quants_to_reserve
+ self._update_available_quantity(product_id, location_id, reserved_quantity=quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id)
@api.model
def _unlink_zero_quants(self):
@@ -1192,10 +1203,11 @@ class StockQuant(models.Model):
'location_id': location_id.id,
'location_dest_id': location_dest_id.id,
'is_inventory': True,
+ 'picked': True,
'move_line_ids': [(0, 0, {
'product_id': self.product_id.id,
'product_uom_id': self.product_uom_id.id,
- 'qty_done': qty,
+ 'quantity': qty,
'location_id': location_id.id,
'location_dest_id': location_dest_id.id,
'company_id': self.company_id.id or self.env.company.id,
@@ -1361,6 +1373,7 @@ class StockQuant(models.Model):
moves = self.env['stock.move'].create(move_vals)
moves._action_done()
+
class QuantPackage(models.Model):
""" Packages containing quants and/or other packages """
_name = "stock.quant.package"
@@ -1441,7 +1454,7 @@ class QuantPackage(models.Model):
action['domain'] = [('id', 'in', pickings.ids)]
return action
- def _check_move_lines_map_quant(self, move_lines, field):
+ def _check_move_lines_map_quant(self, move_lines):
""" This method checks that all product (quants) of self (package) are well present in the `move_line_ids`. """
precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
@@ -1454,7 +1467,7 @@ class QuantPackage(models.Model):
grouped_ops = {}
for k, g in groupby(move_lines, key=_keys_groupby):
- grouped_ops[k] = sum(self.env['stock.move.line'].concat(*g).mapped(field))
+ grouped_ops[k] = sum(self.env['stock.move.line'].concat(*g).mapped('quantity'))
if any(not float_is_zero(grouped_quants.get(key, 0) - grouped_ops.get(key, 0), precision_digits=precision_digits) for key in grouped_quants) \
or any(not float_is_zero(grouped_ops.get(key, 0) - grouped_quants.get(key, 0), precision_digits=precision_digits) for key in grouped_ops):
diff --git a/addons/stock/models/stock_scrap.py b/addons/stock/models/stock_scrap.py
index 68ecb960f7d..c2019fb12ed 100644
--- a/addons/stock/models/stock_scrap.py
+++ b/addons/stock/models/stock_scrap.py
@@ -84,12 +84,12 @@ class StockScrap(models.Model):
for scrap in self:
scrap.scrap_location_id = locations_per_company[scrap.company_id.id]
- @api.depends('move_ids', 'move_ids.move_line_ids.qty_done', 'product_id')
+ @api.depends('move_ids', 'move_ids.move_line_ids.quantity', 'product_id')
def _compute_scrap_qty(self):
self.scrap_qty = 1
for scrap in self:
if scrap.move_ids:
- scrap.scrap_qty = scrap.move_ids[0].quantity_done
+ scrap.scrap_qty = scrap.move_ids[0].quantity
@api.onchange('lot_id')
def _onchange_serial_number(self):
@@ -123,15 +123,18 @@ class StockScrap(models.Model):
'scrapped': True,
'scrap_id': self.id,
'location_dest_id': self.scrap_location_id.id,
- 'move_line_ids': [(0, 0, {'product_id': self.product_id.id,
- 'product_uom_id': self.product_uom_id.id,
- 'qty_done': self.scrap_qty,
- 'location_id': self.location_id.id,
- 'location_dest_id': self.scrap_location_id.id,
- 'package_id': self.package_id.id,
- 'owner_id': self.owner_id.id,
- 'lot_id': self.lot_id.id, })],
-# 'restrict_partner_id': self.owner_id.id,
+ 'move_line_ids': [(0, 0, {
+ 'product_id': self.product_id.id,
+ 'product_uom_id': self.product_uom_id.id,
+ 'quantity': self.scrap_qty,
+ 'location_id': self.location_id.id,
+ 'location_dest_id': self.scrap_location_id.id,
+ 'package_id': self.package_id.id,
+ 'owner_id': self.owner_id.id,
+ 'lot_id': self.lot_id.id,
+ })],
+ # 'restrict_partner_id': self.owner_id.id,
+ 'picked': True,
'picking_id': self.picking_id.id
}
diff --git a/addons/stock/populate/stock.py b/addons/stock/populate/stock.py
index 3793f37481d..b03510b1087 100644
--- a/addons/stock/populate/stock.py
+++ b/addons/stock/populate/stock.py
@@ -495,9 +495,9 @@ class StockMove(models.Model):
for move in picking.move_ids:
# For assigned moves
for move_line in move._get_move_lines():
- move_line.qty_done = move_line.reserved_uom_qty
+ move_line.quantity = move_line.reserved_uom_qty
# Create move line for remaining qty
- missing_to_do = move.product_qty - move.quantity_done
+ missing_to_do = move.product_qty - move.quantity
missing_to_do = move.product_uom._compute_quantity(missing_to_do, move.product_uom, rounding_method='HALF-UP')
if move.product_id.tracking == 'serial':
for i in range(int(missing_to_do)):
@@ -508,7 +508,7 @@ class StockMove(models.Model):
})
sml_values.append(dict(
**move._prepare_move_line_vals(),
- qty_done=1,
+ quantity=1,
lot_id=len(lot_values) - 1,
package_id=package_for_picking and len(package_values) - 1 or False
))
@@ -520,14 +520,14 @@ class StockMove(models.Model):
})
sml_values.append(dict(
**move._prepare_move_line_vals(),
- qty_done=missing_to_do,
+ quantity=missing_to_do,
lot_id=len(lot_values) - 1,
package_id=package_for_picking and len(package_values) - 1 or False
))
else:
sml_values.append(dict(
**move._prepare_move_line_vals(),
- qty_done=missing_to_do,
+ quantity=missing_to_do,
package_id=package_for_picking and len(package_values) - 1 or False
))
if package_for_picking:
diff --git a/addons/stock/report/picking_templates.xml b/addons/stock/report/picking_templates.xml
index e14c67b2dce..c3ad25da95d 100644
--- a/addons/stock/report/picking_templates.xml
+++ b/addons/stock/report/picking_templates.xml
@@ -5,12 +5,12 @@
-
+
-
-
+
+
@@ -48,12 +48,12 @@
-
+
-
-
+
+
diff --git a/addons/stock/report/report_deliveryslip.xml b/addons/stock/report/report_deliveryslip.xml
index e1e8bc8fbf5..0f5c25e9ebe 100644
--- a/addons/stock/report/report_deliveryslip.xml
+++ b/addons/stock/report/report_deliveryslip.xml
@@ -83,10 +83,10 @@
|
- 3.00
+ 3.00
units
- ( )
+ ( )
|
@@ -229,8 +229,8 @@