diff --git a/addons/stock/__manifest__.py b/addons/stock/__manifest__.py
index a5d8b3ff751..ca9d20b5306 100644
--- a/addons/stock/__manifest__.py
+++ b/addons/stock/__manifest__.py
@@ -65,6 +65,8 @@
'wizard/stock_package_destination_views.xml',
'wizard/stock_inventory_adjustment_name.xml',
'wizard/stock_inventory_warning.xml',
+ 'wizard/stock_label_type.xml',
+ 'wizard/stock_lot_label_layout.xml',
'views/res_partner_views.xml',
'views/product_strategy_views.xml',
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 589792f7b2b..9ac69b8f43d 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -1496,6 +1496,19 @@ class Picking(models.Model):
'default_picking_quantity': 'picking'},
}
+ def action_open_label_type(self):
+ if self.user_has_groups('stock.group_production_lot') and self.move_line_ids.lot_id:
+ view = self.env.ref('stock.picking_label_type_form')
+ return {
+ 'name': _('Choose Type of Labels To Print'),
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'picking.label.type',
+ 'views': [(view.id, 'form')],
+ 'target': 'new',
+ 'context': {'default_picking_ids': self.ids},
+ }
+ return self.action_open_label_layout()
+
def _attach_sign(self):
""" Render the delivery report in pdf and attach it to the picking in `self`. """
self.ensure_one()
diff --git a/addons/stock/security/ir.model.access.csv b/addons/stock/security/ir.model.access.csv
index 5368089451a..98178bcf2ca 100644
--- a/addons/stock/security/ir.model.access.csv
+++ b/addons/stock/security/ir.model.access.csv
@@ -88,3 +88,5 @@ access_stock_inventory_warning,stock.inventory.warning,model_stock_inventory_war
access_stock_inventory_adjustment_name,stock.inventory.adjustment.name,model_stock_inventory_adjustment_name,stock.group_stock_manager,1,1,1,0
access_stock_request_count,stock.request.count,model_stock_request_count,stock.group_stock_manager,1,1,1,0
access_stock_replenishment_info,stock.replenishment.info,model_stock_replenishment_info,stock.group_stock_manager,1,1,1,0
+access_stock_picking_label_type_user,picking.label.type.user,model_picking_label_type,stock.group_stock_user,1,1,1,0
+access_stock_lot_label_layout_user,lot.label.layout.user,model_lot_label_layout,stock.group_stock_user,1,1,1,0
diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml
index 99b02f1b2da..ef53efd6fec 100644
--- a/addons/stock/views/stock_picking_views.xml
+++ b/addons/stock/views/stock_picking_views.xml
@@ -253,7 +253,7 @@
attrs="{'invisible': ['|', '|', ('id', '=', False), ('picking_type_code', '!=', 'outgoing'), ('state', '=', 'done')]}"
full_name="partner_id" groups="stock.group_stock_sign_delivery"/>
-
+
diff --git a/addons/stock/wizard/__init__.py b/addons/stock/wizard/__init__.py
index 65d91a0abe3..bfef3be7214 100644
--- a/addons/stock/wizard/__init__.py
+++ b/addons/stock/wizard/__init__.py
@@ -8,6 +8,8 @@ from . import stock_change_product_qty
from . import stock_inventory_conflict
from . import stock_inventory_warning
from . import stock_inventory_adjustment_name
+from . import stock_label_type
+from . import stock_lot_label_layout
from . import stock_scheduler_compute
from . import stock_immediate_transfer
from . import stock_backorder_confirmation
diff --git a/addons/stock/wizard/stock_label_type.py b/addons/stock/wizard/stock_label_type.py
new file mode 100644
index 00000000000..a4792372a9d
--- /dev/null
+++ b/addons/stock/wizard/stock_label_type.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import _, fields, models
+
+
+class ProductLabelLayout(models.TransientModel):
+ _name = 'picking.label.type'
+ _description = 'Choose whether to print product or lot/sn labels'
+
+ picking_ids = fields.Many2many('stock.picking')
+ label_type = fields.Selection([
+ ('products', 'Product Labels'),
+ ('lots', 'Lot/SN Labels')], string="Labels to print", required=True, default='products')
+
+ def process(self):
+ if self.label_type == 'products':
+ return self.picking_ids.action_open_label_layout()
+ view = self.env.ref('stock.lot_label_layout_form_picking')
+ return {
+ 'name': _('Choose Labels Layout'),
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'lot.label.layout',
+ 'views': [(view.id, 'form')],
+ 'target': 'new',
+ 'context': {'default_picking_ids': self.picking_ids.ids},
+ }
diff --git a/addons/stock/wizard/stock_label_type.xml b/addons/stock/wizard/stock_label_type.xml
new file mode 100644
index 00000000000..bace1e07cc6
--- /dev/null
+++ b/addons/stock/wizard/stock_label_type.xml
@@ -0,0 +1,20 @@
+
+
+
+ picking.label.type.form
+ picking.label.type
+ primary
+ 25
+
+
+
+
+
diff --git a/addons/stock/wizard/stock_lot_label_layout.py b/addons/stock/wizard/stock_lot_label_layout.py
new file mode 100644
index 00000000000..505d4411530
--- /dev/null
+++ b/addons/stock/wizard/stock_lot_label_layout.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from collections import defaultdict
+from odoo import fields, models
+
+
+class ProductLabelLayout(models.TransientModel):
+ _name = 'lot.label.layout'
+ _description = 'Choose the sheet layout to print lot labels'
+
+ picking_ids = fields.Many2many('stock.picking')
+ label_quantity = fields.Selection([
+ ('lots', 'One per lot/SN'),
+ ('units', 'One per unit')], string="Quantity to print", required=True, default='lots')
+ print_format = fields.Selection([
+ ('4x12', '4 x 12'),
+ ('zpl', 'ZPL Labels')], string="Format", default='4x12', required=True)
+
+ def process(self):
+ self.ensure_one()
+ xml_id = 'stock.action_report_lot_label'
+ if self.print_format == 'zpl':
+ xml_id = 'stock.label_lot_template'
+ if self.label_quantity == 'lots':
+ docids = self.picking_ids.move_line_ids.lot_id.ids
+ else:
+ uom_categ_unit = self.env.ref('uom.product_uom_categ_unit')
+ quantity_by_lot = defaultdict(int)
+ for move_line in self.picking_ids.move_line_ids:
+ if not move_line.lot_id:
+ continue
+ if move_line.product_uom_id.category_id == uom_categ_unit:
+ quantity_by_lot[move_line.lot_id.id] += int(move_line.qty_done)
+ else:
+ quantity_by_lot[move_line.lot_id.id] += 1
+ docids = []
+ for lot_id, qty in quantity_by_lot.items():
+ docids.append([lot_id] * qty)
+ report_action = self.env.ref(xml_id).report_action(docids)
+ report_action.update({'close_on_report_download': True})
+ return report_action
diff --git a/addons/stock/wizard/stock_lot_label_layout.xml b/addons/stock/wizard/stock_lot_label_layout.xml
new file mode 100644
index 00000000000..525bbfd7563
--- /dev/null
+++ b/addons/stock/wizard/stock_lot_label_layout.xml
@@ -0,0 +1,21 @@
+
+
+
+ lot.label.layout.form
+ lot.label.layout
+ primary
+ 25
+
+
+
+
+
diff --git a/addons/stock_picking_batch/models/stock_picking_batch.py b/addons/stock_picking_batch/models/stock_picking_batch.py
index 32cc0f1ab61..bc5ad6466ca 100644
--- a/addons/stock_picking_batch/models/stock_picking_batch.py
+++ b/addons/stock_picking_batch/models/stock_picking_batch.py
@@ -280,6 +280,16 @@ class StockPickingBatch(models.Model):
return action
def action_open_label_layout(self):
+ if self.user_has_groups('stock.group_production_lot') and self.move_line_ids.lot_id:
+ view = self.env.ref('stock.picking_label_type_form')
+ return {
+ 'name': _('Choose Type of Labels To Print'),
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'picking.label.type',
+ 'views': [(view.id, 'form')],
+ 'target': 'new',
+ 'context': {'default_picking_ids': self.picking_ids.ids},
+ }
view = self.env.ref('stock.product_label_layout_form_picking')
return {
'name': _('Choose Labels Layout'),