Skip to content

Commit

Permalink
Add shopfloor_location_package_restriction
Browse files Browse the repository at this point in the history
  • Loading branch information
TDu committed Aug 25, 2023
1 parent 410567f commit 63f8829
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 28 deletions.
6 changes: 6 additions & 0 deletions setup/shopfloor_location_package_restriction/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
8 changes: 8 additions & 0 deletions shopfloor/actions/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ def location_requires_package(self):
),
}

def location_has_restrictions(self):
return {
"message_type": "warning",
"body": _(
"This location has restrictions. It requires a package and may have some limit on package quantity."
),
}

def already_running_ask_confirmation(self):
return {
"message_type": "warning",
Expand Down
25 changes: 15 additions & 10 deletions shopfloor/services/single_pack_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,21 @@ def _create_package_level(self, package):
def _is_move_state_valid(self, moves):
return all(move.state != "cancel" for move in moves)

def _validate_destination_location(self, package_level, location):
moves = package_level.move_line_ids.move_id
if not location:
return self._response_for_scan_location(
package_level, message=self.msg_store.no_location_found()
)
if not self.is_dest_location_valid(moves, location):
return self._response_for_scan_location(
package_level, message=self.msg_store.dest_location_not_allowed()
)
return None

def validate(self, package_level_id, location_barcode, confirmation=False):
"""Validate the transfer"""
search = self._actions_for("search")

package_level = self.env["stock.package_level"].browse(package_level_id)
if not package_level.exists():
return self._response_for_start(
Expand All @@ -225,15 +236,9 @@ def validate(self, package_level_id, location_barcode, confirmation=False):
)

scanned_location = search.location_from_scan(location_barcode)
if not scanned_location:
return self._response_for_scan_location(
package_level, message=self.msg_store.no_location_found()
)

if not self.is_dest_location_valid(moves, scanned_location):
return self._response_for_scan_location(
package_level, message=self.msg_store.dest_location_not_allowed()
)
response = self._validate_destination_location(package_level, scanned_location)
if response:
return response

if not confirmation and self.is_dest_location_to_confirm(
package_level.location_dest_id, scanned_location
Expand Down
18 changes: 0 additions & 18 deletions shopfloor/tests/test_single_pack_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
# Copyright 2020 Akretion (http://www.akretion.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo.tests.common import Form

from .test_single_pack_transfer_base import SinglePackTransferCommonBase


Expand Down Expand Up @@ -46,22 +44,6 @@ def setUpClassBaseData(cls, *args, **kwargs):
lines=[(cls.product_a, 1), (cls.product_b, 1)]
)

@classmethod
def _create_initial_move(cls, lines):
"""Create the move to satisfy the pre-condition before /start"""
picking_form = Form(cls.env["stock.picking"])
picking_form.picking_type_id = cls.picking_type
picking_form.location_id = cls.stock_location
picking_form.location_dest_id = cls.shelf2
for line in lines:
with picking_form.move_ids_without_package.new() as move:
move.product_id = line[0]
move.product_uom_qty = line[1]
picking = picking_form.save()
picking.action_confirm()
picking.action_assign()
return picking

def _simulate_started(self, package):
"""Replicate what the /start endpoint would do on the given package.
Expand Down
1 change: 1 addition & 0 deletions shopfloor/tests/test_single_pack_transfer_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from .common import CommonCase

from odoo.tests.common import Form

class SinglePackTransferCommonBase(CommonCase):
@classmethod
Expand Down
1 change: 1 addition & 0 deletions shopfloor_location_package_restriction/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import services
18 changes: 18 additions & 0 deletions shopfloor_location_package_restriction/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

{
"name": "Shopfloor Location Package Restriction",
"summary": "Glue module between shopfloor and location package restriction",
"version": "14.0.1.0.0",
"category": "Inventory",
"website": "https://github.com/OCA/wms",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "AGPL-3",
"depends": [
"shopfloor",
# OCA/stock-logistics-warehouse
"stock_location_package_restriction",
],
"auto_install": True,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Thierry Ducrest <[email protected]>
3 changes: 3 additions & 0 deletions shopfloor_location_package_restriction/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Glue module between `shopfloor` and `stock_location_package_restriction`.
It allows to send proper error message to the frontend instead of a stack
trace error being displayed.
2 changes: 2 additions & 0 deletions shopfloor_location_package_restriction/services/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import single_pack_transfer
from . import zone_picking
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)


from odoo.exceptions import ValidationError

from odoo.addons.component.core import Component


class ShopfloorSinglePackTransfer(Component):
_inherit = "shopfloor.single.pack.transfer"

def _validate_destination_location(self, package_level, location):
response = super()._validate_destination_location(package_level, location)
if response:
return response
if location.package_restriction != "norestriction":
# Not sure about this
# Could there be more move lines being checked than intended ?
moves = package_level.move_line_ids.move_id
try:
moves._check_location_package_restriction(location)
except ValidationError:
return self._response_for_scan_location(
package_level, message=self.msg_store.location_has_restrictions()
)
21 changes: 21 additions & 0 deletions shopfloor_location_package_restriction/services/zone_picking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)


from odoo.exceptions import ValidationError

from odoo.addons.component.core import Component


class ShopfloorZonePicking(Component):
_inherit = "shopfloor.zone.picking"

def _validate_destination(self, location, moves):
message = super()._validate_destination(location, moves)
if message:
return message
if location.package_restriction != "norestriction":
try:
moves._check_location_package_restriction(only_qty_done=False)
except ValidationError:
return self.msg_store.location_has_restrictions()
2 changes: 2 additions & 0 deletions shopfloor_location_package_restriction/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import test_single_pack_transfer_force_package
from . import test_zone_picking_force_package
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo.addons.shopfloor.tests.test_single_pack_transfer_base import (
SinglePackTransferCommonBase,
)


class TestSinglePackTransferForcePackage(SinglePackTransferCommonBase):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Prepare the pack and related picking has started
cls.pack_a = cls.env["stock.quant.package"].create(
{"location_id": cls.stock_location.id}
)
cls.quant_a = (
cls.env["stock.quant"]
.sudo()
.create(
{
"product_id": cls.product_a.id,
"location_id": cls.shelf1.id,
"quantity": 1,
"package_id": cls.pack_a.id,
}
)
)
cls.picking = cls._create_initial_move(lines=[(cls.product_a, 1)])
cls.package_level = cls.picking.move_line_ids.package_level_id
cls.package_level.is_done = True
cls.picking.move_line_ids.qty_done = 1
# Add restriction on destination location
cls.shelf2.sudo().package_restriction = "singlepackage"
# Add a package on the destination location
cls._update_qty_in_location(
cls.shelf2,
cls.product_a,
1,
package=cls.env["stock.quant.package"].create(
{"location_id": cls.shelf2.id}
),
)

def test_scan_location_has_restrictions(self):
""" """
response = self.service.dispatch(
"validate",
params={
"package_level_id": self.package_level.id,
"location_barcode": self.shelf2.barcode,
},
)
self.assert_response(
response,
next_state="scan_location",
data=self.ANY,
message=self.service.msg_store.location_has_restrictions(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo.addons.shopfloor.tests.test_zone_picking_base import ZonePickingCommonCase


class TestZonePickingForcePackage(ZonePickingCommonCase):
def setUp(self):
super().setUp()
self.service.work.current_picking_type = self.picking1.picking_type_id

def test_set_destination_location_package_restriction(self):
""""""
# Add a restriction on the location
self.packing_location.sudo().package_restriction = "singlepackage"
# Add a first package on the location
self.pack_1 = self.env["stock.quant.package"].create(
{"location_id": self.packing_location.id}
)
self._update_qty_in_location(
self.packing_location, self.product_a, 1, package=self.pack_1
)
picking_type = self.picking1.picking_type_id
move_line = self.picking1.move_lines.move_line_ids
move_line.qty_done = move_line.product_uom_qty
response = self.service.dispatch(
"set_destination",
params={
"move_line_id": move_line.id,
"barcode": self.packing_location.barcode,
"quantity": move_line.product_uom_qty,
"confirmation": False,
},
)
self.assert_response_set_line_destination(
response,
self.zone_location,
picking_type,
move_line,
message=self.service.msg_store.location_has_restrictions(),
qty_done=10.0,
)

0 comments on commit 63f8829

Please sign in to comment.