# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from collections import defaultdict from odoo import _, fields, models from odoo import Command from odoo.tools.float_utils import float_compare class StockMoveLine(models.Model): _inherit = "stock.move.line" batch_id = fields.Many2one(related='picking_id.batch_id', store=True) def action_open_add_to_wave(self): # This action can be called from the move line list view or from the 'Add to wave' wizard if 'active_wave_id' in self.env.context: wave = self.env['stock.picking.batch'].browse(self.env.context.get('active_wave_id')) return self._add_to_wave(wave) view = self.env.ref('stock_picking_batch.stock_add_to_wave_form') return { 'name': _('Add to Wave'), 'type': 'ir.actions.act_window', 'view_mode': 'form', 'res_model': 'stock.add.to.wave', 'views': [(view.id, 'form')], 'view_id': view.id, 'target': 'new', } def _add_to_wave(self, wave=False): """ Detach lines (and corresponding stock move from a picking to another). If wave is passed, attach new picking into it. If not attach line to their original picking. :param int wave: id of the wave picking on which to put the move lines. """ if not wave: wave = self.env['stock.picking.batch'].create({ 'is_wave': True, 'picking_type_id': self.picking_type_id and self.picking_type_id[0].id, 'user_id': self.env.context.get('active_owner_id'), }) line_by_picking = defaultdict(lambda: self.env['stock.move.line']) for line in self: line_by_picking[line.picking_id] |= line picking_to_wave_vals_list = [] for picking, lines in line_by_picking.items(): # Move the entire picking if all the line are taken line_by_move = defaultdict(lambda: self.env['stock.move.line']) qty_by_move = defaultdict(float) for line in lines: move = line.move_id line_by_move[move] |= line qty = line.product_uom_id._compute_quantity(line.quantity, line.product_id.uom_id, rounding_method='HALF-UP') qty_by_move[line.move_id] += qty if lines == picking.move_line_ids and lines.move_id == picking.move_ids: move_complete = True for move, qty in qty_by_move.items(): if float_compare(move.product_qty, qty, precision_rounding=move.product_uom.rounding) != 0: move_complete = False break if move_complete: wave.picking_ids = [Command.link(picking.id)] continue # Split the picking in two part to extract only line that are taken on the wave picking_to_wave_vals = picking.copy_data({ 'move_ids': [], 'move_line_ids': [], 'batch_id': wave.id, })[0] for move, move_lines in line_by_move.items(): picking_to_wave_vals['move_line_ids'] += [Command.link(line.id) for line in lines] # if all the line of a stock move are taken we change the picking on the stock move if move_lines == move.move_line_ids: picking_to_wave_vals['move_ids'] += [Command.link(move.id)] continue # Split the move qty = qty_by_move[move] new_move = move._split(qty) new_move[0]['move_line_ids'] = [Command.set(move_lines.ids)] picking_to_wave_vals['move_ids'] += [Command.create(new_move[0])] picking_to_wave_vals_list.append(picking_to_wave_vals) if picking_to_wave_vals_list: self.env['stock.picking'].create(picking_to_wave_vals_list) wave.action_confirm()