Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0] stock_picking_batch_creation: Allows to split picking #932

Open
wants to merge 3 commits into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions stock_picking_batch_creation/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,23 @@ are for the same partner. When activated, the computation of the
number of bins consumed by the picking into the batch will take into account
the volume of the pickings for the same partners already.

Splitting picking if needed
^^^^^^^^^^^^^^^^^^^^^^^^^^^

You can also activate the option *Split picking exceeding the limits* on the
wizard. In this case, when the system select the first picking to add to the
batch, it will disable the criteria based on the volume, weight and number of
lines. If the picking is exceeding the limits, the system will then try to split
the picking so that the new picking fits the criteria and can be added to the
batch. If the picking can't be split, an exception will be raised.

This option is useful to allow to create a batch picking with pickings that
are exceeding the limits defined in the wizard. It also ensures that the
processing of pickings is done in the order of the pickings. If the option is
not activated, the system will try to find a picking that fits the criteria
and will ignore those that are exceeding the limits even if they are to be
processed first.

Bug Tracker
===========

Expand Down
3 changes: 2 additions & 1 deletion stock_picking_batch_creation/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"name": "Stock Picking Batch Creation",
"summary": """
Create a batch of pickings to be processed all together""",
"version": "16.0.1.0.0",
"version": "16.0.2.0.0",
"license": "AGPL-3",
"author": "ACSONE SA/NV,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/wms",
Expand All @@ -16,6 +16,7 @@
"delivery", # weight on picking
"stock_picking_batch",
"stock_picking_volume", # OCA/stock-logistics-warehouse
"stock_split_picking_dimension", # OCA/stock-logistics-workflow
],
"data": [
"views/stock_device_type.xml",
Expand Down
16 changes: 14 additions & 2 deletions stock_picking_batch_creation/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@


class NoPickingCandidateError(UserError):
def __init__(self):
def __init__(self, env):
self.env = env

Check warning on line 10 in stock_picking_batch_creation/exceptions.py

View check run for this annotation

Codecov / codecov/patch

stock_picking_batch_creation/exceptions.py#L10

Added line #L10 was not covered by tests
super(NoPickingCandidateError, self).__init__(
_("no candidate pickings to batch")
)


class PickingCandidateNumberLineExceedError(UserError):
def __init__(self, picking, max_line):
self.env = picking.env
self.picking = picking
super(PickingCandidateNumberLineExceedError, self).__init__(
_(
Expand All @@ -28,7 +30,8 @@


class NoSuitableDeviceError(UserError):
def __init__(self, pickings):
def __init__(self, env, pickings):
self.env = env
self.pickings = pickings
message = _("No device found for batch picking.")
if pickings:
Expand All @@ -37,3 +40,12 @@
names=", ".join(self.pickings.mapped("name")),
)
super(NoSuitableDeviceError, self).__init__(message)


class PickingSplitNotPossibleError(UserError):
def __init__(self, picking):
self.env = picking.env
self.picking = picking
super(PickingSplitNotPossibleError, self).__init_(

Check warning on line 49 in stock_picking_batch_creation/exceptions.py

View check run for this annotation

Codecov / codecov/patch

stock_picking_batch_creation/exceptions.py#L47-L49

Added lines #L47 - L49 were not covered by tests
_("Picking %(name)s cannot be split", name=self.picking.name)
)
17 changes: 17 additions & 0 deletions stock_picking_batch_creation/readme/USAGE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,20 @@ will prevent to consume at least one bin for each picking if pickings
are for the same partner. When activated, the computation of the
number of bins consumed by the picking into the batch will take into account
the volume of the pickings for the same partners already.

Splitting picking if needed
^^^^^^^^^^^^^^^^^^^^^^^^^^^

You can also activate the option *Split picking exceeding the limits* on the
wizard. In this case, when the system select the first picking to add to the
batch, it will disable the criteria based on the volume, weight and number of
lines. If the picking is exceeding the limits, the system will then try to split
the picking so that the new picking fits the criteria and can be added to the
batch. If the picking can't be split, an exception will be raised.

This option is useful to allow to create a batch picking with pickings that
are exceeding the limits defined in the wizard. It also ensures that the
processing of pickings is done in the order of the pickings. If the option is
not activated, the system will try to find a picking that fits the criteria
and will ignore those that are exceeding the limits even if they are to be
processed first.
52 changes: 35 additions & 17 deletions stock_picking_batch_creation/static/description/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
Expand All @@ -9,10 +8,11 @@

/*
:Author: David Goodger ([email protected])
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.

See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
Expand Down Expand Up @@ -275,7 +275,7 @@
margin-left: 2em ;
margin-right: 2em }

pre.code .ln { color: grey; } /* line numbers */
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
Expand All @@ -301,7 +301,7 @@
span.pre {
white-space: pre }

span.problematic {
span.problematic, pre.problematic {
color: red }

span.section-subtitle {
Expand Down Expand Up @@ -409,16 +409,17 @@ <h1>Stock device types</h1>
<li><a class="reference internal" href="#advanced-configuration" id="toc-entry-3">Advanced configuration</a><ul>
<li><a class="reference internal" href="#locking" id="toc-entry-4">Locking</a></li>
<li><a class="reference internal" href="#grouping-by-partner" id="toc-entry-5">Grouping by partner</a></li>
<li><a class="reference internal" href="#splitting-picking-if-needed" id="toc-entry-6">Splitting picking if needed</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-6">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-7">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-8">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-9">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-10">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-11">Maintainers</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-7">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-8">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-9">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-10">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-11">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-12">Maintainers</a></li>
</ul>
</li>
</ul>
Expand Down Expand Up @@ -483,43 +484,60 @@ <h4><a class="toc-backref" href="#toc-entry-5">Grouping by partner</a></h4>
number of bins consumed by the picking into the batch will take into account
the volume of the pickings for the same partners already.</p>
</div>
<div class="section" id="splitting-picking-if-needed">
<h4><a class="toc-backref" href="#toc-entry-6">Splitting picking if needed</a></h4>
<p>You can also activate the option <em>Split picking exceeding the limits</em> on the
wizard. In this case, when the system select the first picking to add to the
batch, it will disable the criteria based on the volume, weight and number of
lines. If the picking is exceeding the limits, the system will then try to split
the picking so that the new picking fits the criteria and can be added to the
batch. If the picking can’t be split, an exception will be raised.</p>
<p>This option is useful to allow to create a batch picking with pickings that
are exceeding the limits defined in the wizard. It also ensures that the
processing of pickings is done in the order of the pickings. If the option is
not activated, the system will try to find a picking that fits the criteria
and will ignore those that are exceeding the limits even if they are to be
processed first.</p>
</div>
</div>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-6">Bug Tracker</a></h2>
<h2><a class="toc-backref" href="#toc-entry-7">Bug Tracker</a></h2>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/wms/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/wms/issues/new?body=module:%20stock_picking_batch_creation%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-7">Credits</a></h2>
<h2><a class="toc-backref" href="#toc-entry-8">Credits</a></h2>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-8">Authors</a></h3>
<h3><a class="toc-backref" href="#toc-entry-9">Authors</a></h3>
<ul class="simple">
<li>ACSONE SA/NV</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-9">Contributors</a></h3>
<h3><a class="toc-backref" href="#toc-entry-10">Contributors</a></h3>
<ul class="simple">
<li>Laurent Mignon &lt;<a class="reference external" href="mailto:laurent.mignon&#64;acsone.eu">laurent.mignon&#64;acsone.eu</a>&gt; (<a class="reference external" href="https://www.acsone.eu/">https://www.acsone.eu/</a>)</li>
<li>Lindsay Marion &lt;<a class="reference external" href="mailto:lindsay.marion&#64;acsone.eu">lindsay.marion&#64;acsone.eu</a>&gt; (<a class="reference external" href="https://www.acsone.eu/">https://www.acsone.eu/</a>)</li>
</ul>
</div>
<div class="section" id="other-credits">
<h3><a class="toc-backref" href="#toc-entry-10">Other credits</a></h3>
<h3><a class="toc-backref" href="#toc-entry-11">Other credits</a></h3>
<p>The development of this module has been financially supported by:</p>
<ul class="simple">
<li>ACSONE SA/NV</li>
<li>Alcyon Benelux</li>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-11">Maintainers</a></h3>
<h3><a class="toc-backref" href="#toc-entry-12">Maintainers</a></h3>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
Expand Down
140 changes: 136 additions & 4 deletions stock_picking_batch_creation/tests/test_clustering_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ def test_pickings_with_different_partners(self):
batch2 = self.make_picking_batch._create_batch()
self.assertEqual(self.pick1 | self.pick2, batch2.picking_ids)

def test_picking_with_maximum_number_of_lines_exceed(self):
def test_picking_split_with_maximum_number_of_lines_exceed(self):
# pick 3 has 2 lines
# create a batch picking with maximum number of lines = 1
self.pick1.action_cancel()
Expand All @@ -441,12 +441,144 @@ def test_picking_with_maximum_number_of_lines_exceed(self):
self.make_picking_batch.write(
{
"maximum_number_of_preparation_lines": 1,
"no_line_limit_if_no_candidate": False,
"split_picking_exceeding_limits": False,
}
)
with self.assertRaises(PickingCandidateNumberLineExceedError):
self.make_picking_batch._create_batch(raise_if_not_possible=True)
self.make_picking_batch.no_line_limit_if_no_candidate = True
self.make_picking_batch.split_picking_exceeding_limits = True
batch = self.make_picking_batch._create_batch()
self.assertEqual(self.pick3, batch.picking_ids)
self.assertEqual(len(batch.move_line_ids), 1)

def test_picking_split_with_weight_exceed(self):
# pick 3 has 2 lines
# we will set a weight by line under the maximum weight of the device
# but the total weight of the picking will exceed the maximum weight of the device
# when the batch is created, the picking 3 should be split and the batch
# should contain only pick3 with 1 line

self.pick1.action_cancel()
self.pick2.action_cancel()
self.assertEqual(len(self.pick3.move_line_ids), 2)
max_weight = 200
device = self.env["stock.device.type"].create(
{
"name": "test volume null devices and one bin",
"min_volume": 0,
"max_volume": 200,
"max_weight": max_weight,
"nbr_bins": 1,
"sequence": 50,
}
)

self.make_picking_batch.write(
{
"split_picking_exceeding_limits": False,
"stock_device_type_ids": [(6, 0, [device.id])],
}
)
self.pick3.move_ids.product_id.weight = max_weight - 1
self.pick3.move_ids._cal_move_weight()
with self.assertRaises(NoSuitableDeviceError):
self.make_picking_batch._create_batch(raise_if_not_possible=True)
self.make_picking_batch.split_picking_exceeding_limits = True
batch = self.make_picking_batch._create_batch()
self.assertEqual(self.pick3, batch.picking_ids)
self.assertEqual(len(batch.move_line_ids), 1)

def test_picking_split_with_volume_exceed(self):
# pick 3 has 2 lines
# we will set a volume by line under the maximum volume of the device
# but the total volume of the picking will exceed the maximum volume of the device
# when the batch is created, the picking 3 should be split and the batch
# should contain only pick3 with 1 line

self.pick1.action_cancel()
self.pick2.action_cancel()
self.assertEqual(len(self.pick3.move_line_ids), 2)

max_volume = 200
device = self.env["stock.device.type"].create(
{
"name": "test volume null devices and one bin",
"min_volume": 0,
"max_volume": max_volume,
"max_weight": 300,
"nbr_bins": 1,
"sequence": 50,
}
)

self.make_picking_batch.write(
{
"split_picking_exceeding_limits": False,
"stock_device_type_ids": [(6, 0, [device.id])],
}
)
# each product has a volume of 120
self.pick3.move_ids.product_id.write(
{
"product_length": 12,
"product_height": 5,
"product_width": 2,
}
)
self.pick3.move_ids._compute_volume()
with self.assertRaises(NoSuitableDeviceError):
self.make_picking_batch._create_batch(raise_if_not_possible=True)
self.make_picking_batch.split_picking_exceeding_limits = True
batch = self.make_picking_batch._create_batch()
self.assertEqual(self.pick3, batch.picking_ids)
self.assertEqual(len(batch.move_line_ids), 1)

def test_picking_split_priority(self):
# We ensure than even if a picking with a higher priority has a volume
# exceeding the device capacity, it will be split and processed first
# if the split_picking_exceeding_limits is set to True
# the processing order for picks of type 1 will be:
# pick3 (priority), pick1 (lower id), pick2
self.assertEqual(len(self.pick3.move_line_ids), 2)

max_volume = 200
device = self.env["stock.device.type"].create(
{
"name": "test volume null devices and one bin",
"min_volume": 0,
"max_volume": max_volume,
"max_weight": 300,
"nbr_bins": 1,
"sequence": 50,
}
)

self.make_picking_batch.write(
{
"split_picking_exceeding_limits": False,
"stock_device_type_ids": [(6, 0, [device.id])],
}
)
# each product has a volume of 120
self.pick3.move_ids.product_id.write(
{
"product_length": 12,
"product_height": 5,
"product_width": 2,
}
)
self.pick3.move_ids._compute_volume()

# since pick3 exceeds the device capacity and
# the split_picking_exceeding_limits is set to False
# the next picking to process should be pick1
batch = self.make_picking_batch._create_batch()
self.assertEqual(self.pick1, batch.picking_ids)

batch.unlink()

# if the split_picking_exceeding_limits is set to True.
# then pick3 should be split and processed first
self.make_picking_batch.split_picking_exceeding_limits = True
batch = self.make_picking_batch._create_batch()
self.assertEqual(self.pick3, batch.picking_ids)
self.assertEqual(len(batch.move_line_ids), 2)
Loading
Loading