diff --git a/stock_barcodes/wizard/stock_barcodes_read_picking.py b/stock_barcodes/wizard/stock_barcodes_read_picking.py index d868550fd5ab..a0e06291c173 100644 --- a/stock_barcodes/wizard/stock_barcodes_read_picking.py +++ b/stock_barcodes/wizard/stock_barcodes_read_picking.py @@ -1,11 +1,13 @@ # Copyright 2019 Sergio Teruel # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import logging +from collections import OrderedDict, defaultdict from odoo import _, api, fields, models from odoo.exceptions import ValidationError from odoo.fields import first from odoo.tools.float_utils import float_compare +from odoo.tools.safe_eval import safe_eval _logger = logging.getLogger(__name__) @@ -195,7 +197,7 @@ def get_moves_or_move_lines(self): def fill_todo_records(self): move_lines = self.get_sorted_move_lines(self.get_moves_or_move_lines()) - self.env["wiz.stock.barcodes.read.todo"].fill_records(self, [move_lines]) + self.fill_records([move_lines]) @api.model def _get_fields_filled_special(self): @@ -784,6 +786,138 @@ def _option_required_hook(self, option_required): return bool(self.location_dest_id) return super()._option_required_hook(option_required) + def _group_key(self, line): + group_key_for_todo_records = self.option_group_id.group_key_for_todo_records + if group_key_for_todo_records: + return safe_eval(group_key_for_todo_records, globals_dict={"object": line}) + if self.option_group_id.source_pending_moves == "move_line_ids": + return (line.location_id, line.product_id, line.lot_id, line.package_id) + else: + return (line.location_id, line.product_id) + + def _get_all_products_quantities_in_package(self, package): + res = {} + for quant in package._get_contained_quants(): + if quant.product_id not in res: + res[quant.product_id] = 0 + res[quant.product_id] += quant.quantity + return res + + def _prepare_fill_record_values(self, line, position): + vals = { + "wiz_barcode_id": self.id, + "product_id": line.product_id.id, + "product_uom_qty": line.product_uom_qty, + "name": "To do action", + "position_index": position, + "picking_code": line.picking_code, + } + if line._name == "stock.move.line": + package_product_dic = self._get_all_products_quantities_in_package( + line.package_id + ) + vals.update( + { + "location_id": line.location_id.id, + "location_dest_id": line.location_dest_id.id, + "lot_id": line.lot_id.id, + "package_id": line.package_id.id, + "result_package_id": line.result_package_id.id, + "uom_id": line.product_uom_id.id, + "product_qty_reserved": line.product_qty, + "line_ids": [(6, 0, line.ids)], + "stock_move_ids": [(6, 0, line.move_id.ids)], + "package_product_qty": package_product_dic + and package_product_dic[line.product_id] + or 0.0, + } + ) + else: + vals.update( + { + "location_id": (line.move_line_ids[:1] or line).location_id.id, + "location_dest_id": ( + line.move_line_ids[:1] or line + ).location_dest_id.id, + "uom_id": line.product_uom.id, + "product_qty_reserved": line.move_line_ids + and sum(line.move_line_ids.mapped("product_qty")) + or line.product_uom_qty, + "line_ids": [(6, 0, line.move_line_ids.ids)], + "stock_move_ids": [(6, 0, line.ids)], + } + ) + return vals + + def _update_fill_record_values(self, line, vals): + vals["product_uom_qty"] += line.product_uom_qty + if self.option_group_id.source_pending_moves == "move_line_ids": + vals["product_qty_reserved"] += line.product_qty + vals["line_ids"][0][2].append(line.id) + vals["stock_move_ids"][0][2].append(line.move_id.id) + else: + vals["product_qty_reserved"] += ( + line.move_line_ids + and sum(line.move_line_ids.mapped("product_qty")) + or line.product_uom_qty + ) + vals["line_ids"][0][2].extend(line.move_line_ids.ids) + vals["stock_move_ids"][0][2].extend(line.ids) + return vals + + def fill_records(self, lines_list): + """ + :param lines_list: browse list + :return: + """ + ReadTodo = self.env["wiz.stock.barcodes.read.todo"] + self.todo_line_ids.unlink() + self.todo_line_id = False + # self.position_index = 0 + todo_vals = OrderedDict() + position = 0 + move_qty_dic = defaultdict(float) + is_stock_move_line_origin = lines_list[0]._name == "stock.move.line" + for lines in lines_list: + for line in lines: + key = self._group_key(line) + if key not in todo_vals: + todo_vals[key] = self._prepare_fill_record_values(line, position) + position += 1 + else: + todo_vals[key] = self._update_fill_record_values( + line, todo_vals[key] + ) + if is_stock_move_line_origin: + move_qty_dic[line.move_id] += max( + line.product_uom_qty, line.qty_done + ) + else: + move_qty_dic[line] += max(line.product_uom_qty, line.quantity_done) + for move in self.get_moves(): + qty = move_qty_dic[move] + if ( + move.barcode_backorder_action == "pending" + and move.product_uom_qty > qty + ): + vals = self._prepare_fill_record_values(move, position) + vals.update( + { + "product_uom_qty": move.product_uom_qty - qty, + "product_qty_reserved": 0.0, + "line_ids": False, + "is_extra_line": True, + } + ) + todo_vals[ + ( + move, + "M", + ) + ] = vals + position += 1 + self.todo_line_ids = ReadTodo.create(list(todo_vals.values())) + class WizCandidatePicking(models.TransientModel): """ diff --git a/stock_barcodes/wizard/stock_barcodes_read_todo.py b/stock_barcodes/wizard/stock_barcodes_read_todo.py index bd69356fa965..4c9e43786375 100644 --- a/stock_barcodes/wizard/stock_barcodes_read_todo.py +++ b/stock_barcodes/wizard/stock_barcodes_read_todo.py @@ -1,9 +1,7 @@ # Copyright 2019 Sergio Teruel # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from collections import OrderedDict from odoo import api, fields, models -from odoo.tools.safe_eval import safe_eval class WizStockBarcodesReadTodo(models.TransientModel): @@ -63,107 +61,6 @@ class WizStockBarcodesReadTodo(models.TransientModel): position_index = fields.Integer() picking_code = fields.Char("Type of Operation") - def _group_key(self, wiz, line): - group_key_for_todo_records = wiz.option_group_id.group_key_for_todo_records - if group_key_for_todo_records: - return safe_eval(group_key_for_todo_records, globals_dict={"object": line}) - if wiz.option_group_id.source_pending_moves == "move_line_ids": - return (line.location_id, line.product_id, line.lot_id, line.package_id) - else: - return (line.location_id, line.product_id) - - def _get_all_products_quantities_in_package(self, package): - res = {} - for quant in package._get_contained_quants(): - if quant.product_id not in res: - res[quant.product_id] = 0 - res[quant.product_id] += quant.quantity - return res - - def _prepare_fill_record_values(self, wiz_barcode, line, position): - vals = { - "product_id": line.product_id.id, - "product_uom_qty": line.product_uom_qty, - "name": "To do action", - "position_index": position, - "picking_code": line.picking_code, - } - if wiz_barcode.option_group_id.source_pending_moves == "move_line_ids": - package_product_dic = self._get_all_products_quantities_in_package( - line.package_id - ) - vals.update( - { - "location_id": line.location_id.id, - "location_dest_id": line.location_dest_id.id, - "lot_id": line.lot_id.id, - "package_id": line.package_id.id, - "result_package_id": line.result_package_id.id, - "uom_id": line.product_uom_id.id, - "product_qty_reserved": line.product_qty, - "line_ids": [(6, 0, line.ids)], - "stock_move_ids": [(6, 0, line.move_id.ids)], - "package_product_qty": package_product_dic - and package_product_dic[line.product_id] - or 0.0, - } - ) - else: - vals.update( - { - "location_id": (line.move_line_ids[:1] or line).location_id.id, - "location_dest_id": ( - line.move_line_ids[:1] or line - ).location_dest_id.id, - "uom_id": line.product_uom.id, - "product_qty_reserved": line.move_line_ids - and sum(line.move_line_ids.mapped("product_qty")) - or line.product_uom_qty, - "line_ids": [(6, 0, line.move_line_ids.ids)], - "stock_move_ids": [(6, 0, line.ids)], - } - ) - return vals - - def _update_fill_record_values(self, wiz_barcode, line, vals): - vals["product_uom_qty"] += line.product_uom_qty - if wiz_barcode.option_group_id.source_pending_moves == "move_line_ids": - vals["product_qty_reserved"] += line.product_qty - vals["line_ids"][0][2].append(line.id) - vals["stock_move_ids"][0][2].append(line.move_id.id) - else: - vals["product_qty_reserved"] += ( - line.move_line_ids - and sum(line.move_line_ids.mapped("product_qty")) - or line.product_uom_qty - ) - vals["line_ids"][0][2].extend(line.move_line_ids.ids) - vals["stock_move_ids"][0][2].extend(line.ids) - return vals - - @api.model - def fill_records(self, wiz_barcode, lines_list): - """ - :param lines_list: browse list - :return: - """ - wiz_barcode.todo_line_ids = self.browse() - todo_vals = OrderedDict() - position = 0 - for lines in lines_list: - for line in lines: - key = self._group_key(wiz_barcode, line) - if key not in todo_vals: - todo_vals[key] = self._prepare_fill_record_values( - wiz_barcode, line, position - ) - position += 1 - else: - todo_vals[key] = self._update_fill_record_values( - wiz_barcode, line, todo_vals[key] - ) - wiz_barcode.todo_line_ids = self.create(list(todo_vals.values())) - def action_todo_next(self): self.state = "done_forced" self.line_ids.barcode_scan_state = "done_forced" diff --git a/stock_barcodes_elaboration/wizard/__init__.py b/stock_barcodes_elaboration/wizard/__init__.py index 8cc0c22b3a38..571c23004134 100644 --- a/stock_barcodes_elaboration/wizard/__init__.py +++ b/stock_barcodes_elaboration/wizard/__init__.py @@ -1 +1,2 @@ +from . import stock_barcodes_read_picking from . import stock_barcodes_read_todo diff --git a/stock_barcodes_elaboration/wizard/stock_barcodes_read_picking.py b/stock_barcodes_elaboration/wizard/stock_barcodes_read_picking.py new file mode 100644 index 000000000000..5b58dd497575 --- /dev/null +++ b/stock_barcodes_elaboration/wizard/stock_barcodes_read_picking.py @@ -0,0 +1,12 @@ +# Copyright 2019 Sergio Teruel +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import models + + +class WizStockBarcodesReadPicking(models.TransientModel): + _inherit = "wiz.stock.barcodes.read.picking" + + def _group_key(self, line): + key = super()._group_key(line) + key += (line.elaboration_ids,) + return key diff --git a/stock_barcodes_elaboration/wizard/stock_barcodes_read_todo.py b/stock_barcodes_elaboration/wizard/stock_barcodes_read_todo.py index d70dde3eabdf..d479c4c86521 100644 --- a/stock_barcodes_elaboration/wizard/stock_barcodes_read_todo.py +++ b/stock_barcodes_elaboration/wizard/stock_barcodes_read_todo.py @@ -21,8 +21,3 @@ def _compute_elaboration_ids(self): line.elaboration_note = ". ".join( m.elaboration_note for m in moves if m.elaboration_note ) - - def _group_key(self, wiz, line): - key = super(WizStockBarcodesReadTodo, self)._group_key(wiz, line) - key += (line.elaboration_ids,) - return key diff --git a/stock_barcodes_gs1_secondary_unit/wizard/stock_barcodes_read_picking.py b/stock_barcodes_gs1_secondary_unit/wizard/stock_barcodes_read_picking.py index 80b55f59f41b..a324fafeab3a 100644 --- a/stock_barcodes_gs1_secondary_unit/wizard/stock_barcodes_read_picking.py +++ b/stock_barcodes_gs1_secondary_unit/wizard/stock_barcodes_read_picking.py @@ -1,6 +1,7 @@ # Copyright 2019 Sergio Teruel # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import api, fields, models +from odoo.tools import float_compare class WizStockBarcodesReadPicking(models.TransientModel): @@ -51,3 +52,30 @@ def _update_stock_move_line(self, line, sml_vals): line.secondary_uom_qty + self.secondary_uom_qty ) return super()._update_stock_move_line(line, sml_vals) + + def _prepare_fill_record_values(self, line, position): + vals = super()._prepare_fill_record_values(line, position) + vals["secondary_uom_id"] = line.secondary_uom_id.id + if line._name == "stock.move.line": + move = line.move_id + # Set secondary qty when stock.move full match with stock.move.line + if not (move.move_line_ids - line) and not float_compare( + move.product_uom_qty, + line.product_uom_qty, + precision_rounding=line.product_uom_id.rounding, + ): + vals["secondary_uom_qty"] = move.secondary_uom_qty + elif line._name == "stock.move": + # Set secondary qty when stock.move all quantity is available + if not float_compare( + line.reserved_availability, + line.product_uom_qty, + precision_rounding=line.product_uom.rounding, + ): + vals["secondary_uom_qty"] = line.secondary_uom_qty + return vals + + def _group_key(self, line): + key = super()._group_key(line) + key += (line.secondary_uom_id,) + return key diff --git a/stock_barcodes_gs1_secondary_unit/wizard/stock_barcodes_read_todo.py b/stock_barcodes_gs1_secondary_unit/wizard/stock_barcodes_read_todo.py index 84041f9cc81b..edc28e5353d4 100644 --- a/stock_barcodes_gs1_secondary_unit/wizard/stock_barcodes_read_todo.py +++ b/stock_barcodes_gs1_secondary_unit/wizard/stock_barcodes_read_todo.py @@ -2,7 +2,6 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import api, models -from odoo.tools import float_compare class WizStockBarcodesReadTodo(models.TransientModel): @@ -13,35 +12,8 @@ class WizStockBarcodesReadTodo(models.TransientModel): "uom_field": "uom_id", } - def _prepare_fill_record_values(self, wiz_barcode, line, position): - vals = super()._prepare_fill_record_values(wiz_barcode, line, position) - vals["secondary_uom_id"] = line.secondary_uom_id.id - if line._name == "stock.move.line": - move = line.move_id - # Set secondary qty when stock.move full match with stock.move.line - if not (move.move_line_ids - line) and not float_compare( - move.product_uom_qty, - line.product_uom_qty, - precision_rounding=line.product_uom_id.rounding, - ): - vals["secondary_uom_qty"] = move.secondary_uom_qty - elif line._name == "stock.move": - # Set secondary qty when stock.move all quantity is available - if not float_compare( - line.reserved_availability, - line.product_uom_qty, - precision_rounding=line.product_uom.rounding, - ): - vals["secondary_uom_qty"] = line.secondary_uom_qty - return vals - @api.model def fields_to_fill_from_pending_line(self): res = super().fields_to_fill_from_pending_line() res.append("secondary_uom_id") return res - - def _group_key(self, wiz, line): - key = super()._group_key(wiz, line) - key += (line.secondary_uom_id,) - return key