Skip to content

Commit

Permalink
[IMP] shopfloor: Zone picking no packing
Browse files Browse the repository at this point in the history
Add an option to skip the packing step when processing a line into the zone picking scenario. Thanks to this option the processing of a line can be done by processing the location, set the qty and scan the destination even if the oroduct is not into a package.
  • Loading branch information
lmignon authored and rousseldenis committed Jan 13, 2025
1 parent 0f76e45 commit d316794
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 4 deletions.
2 changes: 1 addition & 1 deletion shopfloor/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{
"name": "Shopfloor",
"summary": "manage warehouse operations with barcode scanners",
"version": "16.0.2.4.1",
"version": "16.0.2.4.2",
"development_status": "Beta",
"category": "Inventory",
"website": "https://github.com/OCA/wms",
Expand Down
3 changes: 2 additions & 1 deletion shopfloor/data/shopfloor_scenario_data.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"scan_location_or_pack_first": true,
"allow_alternative_destination_package": true,
"allow_move_line_search_sort_order": false,
"allow_move_line_search_additional_domain": true
"allow_move_line_search_additional_domain": true,
"require_destination_package": true
}
</field>
</record>
Expand Down
29 changes: 29 additions & 0 deletions shopfloor/migrations/16.0.2.4.2/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright 2024 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import json
import logging

from odoo import SUPERUSER_ID, api

_logger = logging.getLogger(__name__)


def migrate(cr, version):
_logger.info("Updating scenario Zone Picking")
if not version:
return
env = api.Environment(cr, SUPERUSER_ID, {})
zone_picking_scenario = env.ref("shopfloor.scenario_zone_picking")
_update_scenario_options(zone_picking_scenario)


def _update_scenario_options(scenario):
options = scenario.options
if "require_destination_package" not in options:
options["require_destination_package"] = True
options_edit = json.dumps(options or {}, indent=4, sort_keys=True)
scenario.write({"options_edit": options_edit})
_logger.info(
"Option require_destination_package added to scenario Zone Picking"
)
42 changes: 41 additions & 1 deletion shopfloor/models/shopfloor_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ class ShopfloorMenu(models.Model):
allow_alternative_destination_package_is_possible = fields.Boolean(
compute="_compute_allow_alternative_destination_package_is_possible"
)

move_line_search_additional_domain_is_possible = fields.Boolean(
compute="_compute_move_line_search_additional_domain_is_possible"
)
Expand All @@ -250,6 +249,16 @@ class ShopfloorMenu(models.Model):
move_line_search_sort_order_custom_code = fields.Text(
string="Custom sort key code", help="Python code to sort move lines. "
)
require_destination_package = fields.Boolean(
string="Destination package required",
default=True,
help="If set, the user will have to scan only the source location "
"and the destination location to process a line. The unload step will be skipped.",
)

require_destination_package_is_possible = fields.Boolean(
compute="_compute_require_destination_package_is_possible"
)

@api.onchange("unload_package_at_destination")
def _onchange_unload_package_at_destination(self):
Expand All @@ -267,6 +276,16 @@ def _onchange_pick_pack_same_time(self):
record.unload_package_at_destination = False
record.multiple_move_single_pack = False

@api.onchange("require_destination_package")
def _onchange_require_destination_package(self):
# require_destination_package is incompatible with pick_pack_same_time and
# unload_package_at_destination and multiple_move_single_pack
for record in self:
if not record.require_destination_package:
record.pick_pack_same_time = False
record.unload_package_at_destination = False
record.multiple_move_single_pack = False

@api.onchange("multiple_move_single_pack")
def _onchange_multiple_move_single_pack(self):
# multiple_move_single_pack is incompatible with pick_pack_same_time,
Expand All @@ -278,6 +297,7 @@ def _onchange_multiple_move_single_pack(self):
"unload_package_at_destination",
"pick_pack_same_time",
"multiple_move_single_pack",
"require_destination_package",
)
def _check_options(self):
if self.pick_pack_same_time and self.unload_package_at_destination:
Expand All @@ -294,6 +314,19 @@ def _check_options(self):
"'Multiple moves same destination package'."
)
)
elif not self.require_destination_package and (
self.pick_pack_same_time
or self.unload_package_at_destination
or self.multiple_move_single_pack
):
raise exceptions.UserError(
_(
"'No destination package required' is incompatible with "
"'Pick and pack at the same time',"
"'Unload package at destination' and 'Multiple moves "
"same destination package'."
)
)

@api.depends("scenario_id", "picking_type_ids")
def _compute_move_create_is_possible(self):
Expand Down Expand Up @@ -497,6 +530,13 @@ def _compute_move_line_search_sort_order_is_possible(self):
"allow_move_line_search_sort_order"
)

@api.depends("scenario_id")
def _compute_require_destination_package_is_possible(self):
for menu in self:
menu.require_destination_package_is_possible = menu.scenario_id.has_option(
"require_destination_package"
)

@api.constrains(
"move_line_search_sort_order", "move_line_search_sort_order_custom_code"
)
Expand Down
5 changes: 4 additions & 1 deletion shopfloor/services/zone_picking.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ def lines_order(self):
def _pick_pack_same_time(self):
return self.work.menu.pick_pack_same_time

def _packing_required(self):
return self.work.menu.require_destination_package

def _handle_complete_mix_pack(self, package):
packaging = self._actions_for("packaging")
return (
Expand Down Expand Up @@ -924,7 +927,7 @@ def _set_destination_location(
return (location_changed, response)

# If no destination package
if not move_line.result_package_id:
if self._packing_required() and not move_line.result_package_id:
response = self._response_for_set_line_destination(
move_line,
message=self.msg_store.dest_package_required(),
Expand Down
1 change: 1 addition & 0 deletions shopfloor/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
from . import test_zone_picking_unload_single
from . import test_zone_picking_unload_all
from . import test_zone_picking_unload_set_destination
from . import test_zone_picking_require_destination_package
from . import test_misc
from . import test_move_action_assign
from . import test_scan_anything
Expand Down
62 changes: 62 additions & 0 deletions shopfloor/tests/test_zone_picking_require_destination_package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from .test_zone_picking_base import ZonePickingCommonCase

# pylint: disable=missing-return


class ZonePickingNoPAcking(ZonePickingCommonCase):
"""Tests zone picking without packing steps.
* /set_destination
"""

def setUp(self):
super().setUp()
self.service.work.current_picking_type = self.picking1.picking_type_id
self.picking1.move_line_ids.result_package_id = False

def test_set_destination(self):
# when no packing is set, you can set the destination directly
# without the need to pack the product
self.service.work.menu.sudo().require_destination_package = True
zone_location = self.zone_location
picking_type = self.picking1.picking_type_id
move_line = self.picking1.move_line_ids[0]
response = self.service.dispatch(
"set_destination",
params={
"move_line_id": move_line.id,
"barcode": move_line.location_dest_id.barcode,
"quantity": move_line.reserved_uom_qty,
"confirmation": None,
},
)
self.assert_response_set_line_destination(
response,
zone_location,
picking_type,
move_line,
qty_done=move_line.reserved_uom_qty,
message=self.service.msg_store.dest_package_required(),
)
self.service.work.menu.sudo().require_destination_package = False
response = self.service.dispatch(
"set_destination",
params={
"move_line_id": move_line.id,
"barcode": move_line.location_dest_id.barcode,
"quantity": move_line.reserved_uom_qty,
"confirmation": None,
},
)
move_lines = self.service._find_location_move_lines()
move_lines = move_lines.sorted(lambda l: l.move_id.priority, reverse=True)
self.assert_response_select_line(
response,
zone_location,
picking_type,
move_lines,
message=self.service.msg_store.confirm_pack_moved(),
)
10 changes: 10 additions & 0 deletions shopfloor/views/shopfloor_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
>
<field name="ignore_no_putaway_available_is_possible" invisible="1" />
<field name="ignore_no_putaway_available" />
</group>
<group
name="require_destination_package"
attrs="{'invisible': [('require_destination_package_is_possible', '=', False)]}"
>
<field
name="require_destination_package_is_possible"
invisible="1"
/>
<field name="require_destination_package" />
</group>
<group
name="pick_pack_same_time"
Expand Down

0 comments on commit d316794

Please sign in to comment.