diff --git a/addons/l10n_it_stock_ddt/report/l10n_it_ddt_report.xml b/addons/l10n_it_stock_ddt/report/l10n_it_ddt_report.xml index 37abefa86b5..bc62a64054d 100644 --- a/addons/l10n_it_stock_ddt/report/l10n_it_ddt_report.xml +++ b/addons/l10n_it_stock_ddt/report/l10n_it_ddt_report.xml @@ -110,21 +110,21 @@ - + - + - + - + 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 @@ - -