diff --git a/addons/stock/models/res_config_settings.py b/addons/stock/models/res_config_settings.py index 87879c9d324..7ee5d5e5842 100644 --- a/addons/stock/models/res_config_settings.py +++ b/addons/stock/models/res_config_settings.py @@ -23,7 +23,9 @@ class ResConfigSettings(models.TransientModel): help="Add and customize route operations to process product moves in your warehouse(s): e.g. unload > quality control > stock for incoming products, pick > pack > ship for outgoing products. \n You can also set putaway strategies on warehouse locations in order to send incoming products into specific child locations straight away (e.g. specific bins, racks).") group_warning_stock = fields.Boolean("Warnings for Stock", implied_group='stock.group_warning_stock') group_stock_sign_delivery = fields.Boolean("Signature", implied_group='stock.group_stock_sign_delivery') - module_stock_picking_batch = fields.Boolean("Batch Pickings") + module_stock_picking_batch = fields.Boolean("Batch Transfers") + group_stock_picking_wave = fields.Boolean('Wave Transfers', implied_group='stock.group_stock_picking_wave', + help="Group your move operations in wave transfer to process them together") module_stock_barcode = fields.Boolean("Barcode Scanner") stock_move_email_validation = fields.Boolean(related='company_id.stock_move_email_validation', readonly=False) stock_mail_confirmation_template_id = fields.Many2one(related='company_id.stock_mail_confirmation_template_id', readonly=False) diff --git a/addons/stock/security/stock_security.xml b/addons/stock/security/stock_security.xml index f66a8a8d834..5bc1f91aa1c 100644 --- a/addons/stock/security/stock_security.xml +++ b/addons/stock/security/stock_security.xml @@ -78,6 +78,10 @@ Display Reception Report at Validation + + Use wave pickings + + diff --git a/addons/stock/views/res_config_settings_views.xml b/addons/stock/views/res_config_settings_views.xml index 032c9211921..ce18bbedad4 100644 --- a/addons/stock/views/res_config_settings_views.xml +++ b/addons/stock/views/res_config_settings_views.xml @@ -34,6 +34,13 @@
Process transfers in batch per worker
+
+ +
+
+
diff --git a/addons/stock_picking_batch/__manifest__.py b/addons/stock_picking_batch/__manifest__.py index aa3a0d2b35a..1e300bca7ca 100644 --- a/addons/stock_picking_batch/__manifest__.py +++ b/addons/stock_picking_batch/__manifest__.py @@ -13,14 +13,22 @@ This module adds the batch transfer option in warehouse management 'data': [ 'security/ir.model.access.csv', 'views/stock_picking_batch_views.xml', + 'views/stock_picking_wave_views.xml', + 'views/stock_move_line_views.xml', 'data/stock_picking_batch_data.xml', 'wizard/stock_picking_to_batch_views.xml', + 'wizard/stock_add_to_wave_views.xml', 'report/stock_picking_batch_report_views.xml', 'report/report_picking_batch.xml', ], 'demo': [ 'data/stock_picking_batch_demo.xml', ], + 'assets': { + 'web.assets_backend': [ + 'stock_picking_batch/static/src/js/*', + ] + }, 'installable': True, 'license': 'LGPL-3', } diff --git a/addons/stock_picking_batch/data/stock_picking_batch_data.xml b/addons/stock_picking_batch/data/stock_picking_batch_data.xml index 6397e02a31d..2cb0c42ba91 100644 --- a/addons/stock_picking_batch/data/stock_picking_batch_data.xml +++ b/addons/stock_picking_batch/data/stock_picking_batch_data.xml @@ -15,4 +15,12 @@ 5 + + + Wave Transfer + picking.wave + WAVE/ + 5 + + diff --git a/addons/stock_picking_batch/models/__init__.py b/addons/stock_picking_batch/models/__init__.py index a5f3f55679c..bafa2582bf2 100644 --- a/addons/stock_picking_batch/models/__init__.py +++ b/addons/stock_picking_batch/models/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import stock_move_line from . import stock_picking from . import stock_picking_batch diff --git a/addons/stock_picking_batch/models/stock_move_line.py b/addons/stock_picking_batch/models/stock_move_line.py new file mode 100644 index 00000000000..4dbf5414d49 --- /dev/null +++ b/addons/stock_picking_batch/models/stock_move_line.py @@ -0,0 +1,78 @@ +# -*- 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 + + +class StockMoveLine(models.Model): + _inherit = "stock.move.line" + + batch_id = fields.Many2one(related='picking_id.batch_id') + + 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 + }) + line_by_picking = defaultdict(lambda: self.env['stock.move.line']) + for line in self: + # if not wave and line.orig_picking_id.is_wave: + # continue + 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 + if lines == picking.move_line_ids: + 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_lines': [], + 'move_line_ids': [], + 'batch_id': wave.id, + })[0] + line_by_move = defaultdict(lambda: self.env['stock.move.line']) + for line in lines: + line_by_move[line.move_id] |= line + 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_lines'] += [Command.link(move.id)] + continue + # Split the move + qty = sum(lines.mapped('product_qty')) + new_move = move._split(qty) + new_move[0]['move_line_ids'] = [Command.set(move_lines.ids)] + picking_to_wave_vals['move_lines'] += [Command.create(new_move)] + + 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() diff --git a/addons/stock_picking_batch/models/stock_picking.py b/addons/stock_picking_batch/models/stock_picking.py index 52d994787ed..7d928f821d6 100644 --- a/addons/stock_picking_batch/models/stock_picking.py +++ b/addons/stock_picking_batch/models/stock_picking.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models +from odoo import _, api, fields, models class StockPicking(models.Model): @@ -30,6 +30,27 @@ class StockPicking(models.Model): self.batch_id._sanity_check() return res + def action_add_operations(self): + view = self.env.ref('stock_picking_batch.view_move_line_tree_detailed_wave') + return { + 'name': _('Add Operations'), + 'type': 'ir.actions.act_window', + 'view_mode': 'list', + 'view': view, + 'views': [(view.id, 'tree')], + 'res_model': 'stock.move.line', + 'target': 'new', + 'domain': [ + ('picking_id', 'in', self.ids), + ('state', '!=', 'done') + ], + 'context': dict( + self.env.context, + picking_to_wave=self.ids, + active_wave_id=self.env.context.get('active_wave_id').id, + search_default_by_location=True, + )} + def _should_show_transfers(self): if len(self.batch_id) == 1 and self == self.batch_id.picking_ids: return False diff --git a/addons/stock_picking_batch/models/stock_picking_batch.py b/addons/stock_picking_batch/models/stock_picking_batch.py index d7f0047d458..1196a114760 100644 --- a/addons/stock_picking_batch/models/stock_picking_batch.py +++ b/addons/stock_picking_batch/models/stock_picking_batch.py @@ -59,6 +59,7 @@ class StockPickingBatch(models.Model): - If manually set then scheduled date for all transfers in batch will automatically update to this date. - If not manually changed and transfers are added/removed/updated then this will be their earliest scheduled date but this scheduled date will not be set for all transfers in batch.""") + is_wave = fields.Boolean('This batch is a wave') @api.depends('company_id', 'picking_type_id', 'state') def _compute_allowed_picking_ids(self): @@ -127,7 +128,10 @@ class StockPickingBatch(models.Model): @api.model def create(self, vals): if vals.get('name', '/') == '/': - vals['name'] = self.env['ir.sequence'].next_by_code('picking.batch') or '/' + if vals.get('is_wave'): + vals['name'] = self.env['ir.sequence'].next_by_code('picking.wave') or '/' + else: + vals['name'] = self.env['ir.sequence'].next_by_code('picking.batch') or '/' return super().create(vals) def write(self, vals): diff --git a/addons/stock_picking_batch/security/ir.model.access.csv b/addons/stock_picking_batch/security/ir.model.access.csv index 31a6de03836..78ecda8bb38 100644 --- a/addons/stock_picking_batch/security/ir.model.access.csv +++ b/addons/stock_picking_batch/security/ir.model.access.csv @@ -1,3 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_stock_picking_batch,stock.picking.batch stock users,model_stock_picking_batch,stock.group_stock_user,1,1,1,1 access_stock_picking_to_batch,access.stock.picking.to.batch,model_stock_picking_to_batch,stock.group_stock_user,1,1,1,0 +access_stock_add_to_wave,access.stock.picking.to.wave,model_stock_add_to_wave,stock.group_stock_user,1,1,1,0 diff --git a/addons/stock_picking_batch/static/src/js/choose_lines_widget.js b/addons/stock_picking_batch/static/src/js/choose_lines_widget.js new file mode 100644 index 00000000000..92604757b37 --- /dev/null +++ b/addons/stock_picking_batch/static/src/js/choose_lines_widget.js @@ -0,0 +1,43 @@ +odoo.define('stock_picking_wave.choose_lines_widget', function (require) { +const relationalFields = require('web.relational_fields'); +const FieldsRegistry = require('web.field_registry'); +const core = require('web.core'); + +var ChoosePickingWidget = relationalFields.FieldOne2Many.extend({ + + init: function (parent, name, record, options) { + this._super.apply(this, arguments); + this.isMany2Many = true; + this.isWave = record.data.is_wave; + }, + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + /** + * Opens a SelectCreateDialog + */ + _setValue: function (value, options) { + return this._super(value, options).then(() => { + if (value.operation === 'ADD_M2M') { + core.bus.trigger('add_move_lines', value.ids); + } + }); + }, + +}); + +var ChooseLinesWidget = relationalFields.FieldMany2Many.extend({ + + start: function () { + core.bus.on('add_move_lines', this, this.onAddRecordOpenDialog); + return this._super(); + }, +}); + +FieldsRegistry.add('choose_lines_widget', ChooseLinesWidget); +FieldsRegistry.add('choose_picking_widget', ChoosePickingWidget); + +return ChooseLinesWidget, ChoosePickingWidget; + +}); diff --git a/addons/stock_picking_batch/views/stock_move_line_views.xml b/addons/stock_picking_batch/views/stock_move_line_views.xml new file mode 100644 index 00000000000..da81aba9aa9 --- /dev/null +++ b/addons/stock_picking_batch/views/stock_move_line_views.xml @@ -0,0 +1,18 @@ + + + + stock_picking_wave.move.line.tree.wave + stock.move.line + + + +
+
+
+ + + +
+
+
diff --git a/addons/stock_picking_batch/views/stock_picking_batch_views.xml b/addons/stock_picking_batch/views/stock_picking_batch_views.xml index 8c056114ca4..0c930041042 100644 --- a/addons/stock_picking_batch/views/stock_picking_batch_views.xml +++ b/addons/stock_picking_batch/views/stock_picking_batch_views.xml @@ -14,7 +14,22 @@
- + + stock_picking_batch.picking.tree.batch + stock.picking + primary + + + + + + + + + + + + stock_picking_batch.picking.move.tree @@ -70,6 +85,7 @@ +