odoo-addon-shopfloor 16.0.1.0.0.24__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- odoo/addons/shopfloor/README.rst +160 -0
- odoo/addons/shopfloor/__init__.py +4 -0
- odoo/addons/shopfloor/__manifest__.py +65 -0
- odoo/addons/shopfloor/actions/__init__.py +15 -0
- odoo/addons/shopfloor/actions/change_package_lot.py +164 -0
- odoo/addons/shopfloor/actions/completion_info.py +42 -0
- odoo/addons/shopfloor/actions/data.py +329 -0
- odoo/addons/shopfloor/actions/data_detail.py +154 -0
- odoo/addons/shopfloor/actions/inventory.py +150 -0
- odoo/addons/shopfloor/actions/location_content_transfer_sorter.py +89 -0
- odoo/addons/shopfloor/actions/message.py +846 -0
- odoo/addons/shopfloor/actions/move_line_search.py +119 -0
- odoo/addons/shopfloor/actions/packaging.py +59 -0
- odoo/addons/shopfloor/actions/savepoint.py +44 -0
- odoo/addons/shopfloor/actions/schema.py +182 -0
- odoo/addons/shopfloor/actions/schema_detail.py +98 -0
- odoo/addons/shopfloor/actions/search.py +187 -0
- odoo/addons/shopfloor/actions/stock.py +239 -0
- odoo/addons/shopfloor/actions/stock_unreserve.py +66 -0
- odoo/addons/shopfloor/components/__init__.py +5 -0
- odoo/addons/shopfloor/components/scan_handler_location.py +26 -0
- odoo/addons/shopfloor/components/scan_handler_lot.py +26 -0
- odoo/addons/shopfloor/components/scan_handler_package.py +26 -0
- odoo/addons/shopfloor/components/scan_handler_product.py +26 -0
- odoo/addons/shopfloor/components/scan_handler_transfer.py +26 -0
- odoo/addons/shopfloor/data/shopfloor_scenario_data.xml +73 -0
- odoo/addons/shopfloor/demo/shopfloor_app_demo.xml +12 -0
- odoo/addons/shopfloor/demo/shopfloor_menu_demo.xml +64 -0
- odoo/addons/shopfloor/demo/shopfloor_profile_demo.xml +8 -0
- odoo/addons/shopfloor/demo/stock_picking_type_demo.xml +93 -0
- odoo/addons/shopfloor/docs/checkout_diag_seq.plantuml +61 -0
- odoo/addons/shopfloor/docs/checkout_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/cluster_picking_diag_seq.plantuml +112 -0
- odoo/addons/shopfloor/docs/cluster_picking_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/delivery_diag_seq.plantuml +56 -0
- odoo/addons/shopfloor/docs/delivery_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/location_content_transfer_diag_seq.plantuml +66 -0
- odoo/addons/shopfloor/docs/location_content_transfer_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/oca_logo.png +0 -0
- odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.plantuml +36 -0
- odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.png +0 -0
- odoo/addons/shopfloor/docs/zone_picking_diag_seq.plantuml +85 -0
- odoo/addons/shopfloor/docs/zone_picking_diag_seq.png +0 -0
- odoo/addons/shopfloor/exceptions.py +6 -0
- odoo/addons/shopfloor/i18n/ca.po +1802 -0
- odoo/addons/shopfloor/i18n/de.po +1791 -0
- odoo/addons/shopfloor/i18n/es_AR.po +2147 -0
- odoo/addons/shopfloor/i18n/pt_BR.po +1791 -0
- odoo/addons/shopfloor/i18n/shopfloor.pot +1877 -0
- odoo/addons/shopfloor/models/__init__.py +12 -0
- odoo/addons/shopfloor/models/priority_postpone_mixin.py +41 -0
- odoo/addons/shopfloor/models/shopfloor_app.py +9 -0
- odoo/addons/shopfloor/models/shopfloor_menu.py +436 -0
- odoo/addons/shopfloor/models/stock_location.py +76 -0
- odoo/addons/shopfloor/models/stock_move.py +119 -0
- odoo/addons/shopfloor/models/stock_move_line.py +307 -0
- odoo/addons/shopfloor/models/stock_package_level.py +50 -0
- odoo/addons/shopfloor/models/stock_picking.py +118 -0
- odoo/addons/shopfloor/models/stock_picking_batch.py +41 -0
- odoo/addons/shopfloor/models/stock_picking_type.py +26 -0
- odoo/addons/shopfloor/models/stock_quant.py +31 -0
- odoo/addons/shopfloor/models/stock_quant_package.py +101 -0
- odoo/addons/shopfloor/readme/CONTRIBUTORS.rst +18 -0
- odoo/addons/shopfloor/readme/CREDITS.rst +5 -0
- odoo/addons/shopfloor/readme/DESCRIPTION.rst +17 -0
- odoo/addons/shopfloor/readme/HISTORY.rst +4 -0
- odoo/addons/shopfloor/readme/ROADMAP.rst +4 -0
- odoo/addons/shopfloor/readme/USAGE.rst +6 -0
- odoo/addons/shopfloor/security/groups.xml +17 -0
- odoo/addons/shopfloor/services/__init__.py +16 -0
- odoo/addons/shopfloor/services/checkout.py +1763 -0
- odoo/addons/shopfloor/services/cluster_picking.py +1628 -0
- odoo/addons/shopfloor/services/delivery.py +828 -0
- odoo/addons/shopfloor/services/forms/__init__.py +1 -0
- odoo/addons/shopfloor/services/forms/picking_form.py +78 -0
- odoo/addons/shopfloor/services/location_content_transfer.py +1194 -0
- odoo/addons/shopfloor/services/menu.py +60 -0
- odoo/addons/shopfloor/services/picking_batch.py +126 -0
- odoo/addons/shopfloor/services/service.py +101 -0
- odoo/addons/shopfloor/services/single_pack_transfer.py +366 -0
- odoo/addons/shopfloor/services/zone_picking.py +1938 -0
- odoo/addons/shopfloor/static/description/icon.png +0 -0
- odoo/addons/shopfloor/static/description/index.html +500 -0
- odoo/addons/shopfloor/tests/__init__.py +83 -0
- odoo/addons/shopfloor/tests/common.py +324 -0
- odoo/addons/shopfloor/tests/models.py +29 -0
- odoo/addons/shopfloor/tests/test_actions_change_package_lot.py +1175 -0
- odoo/addons/shopfloor/tests/test_actions_data.py +376 -0
- odoo/addons/shopfloor/tests/test_actions_data_base.py +244 -0
- odoo/addons/shopfloor/tests/test_actions_data_detail.py +322 -0
- odoo/addons/shopfloor/tests/test_actions_search.py +248 -0
- odoo/addons/shopfloor/tests/test_actions_stock.py +48 -0
- odoo/addons/shopfloor/tests/test_checkout_auto_post.py +67 -0
- odoo/addons/shopfloor/tests/test_checkout_base.py +81 -0
- odoo/addons/shopfloor/tests/test_checkout_cancel_line.py +154 -0
- odoo/addons/shopfloor/tests/test_checkout_change_packaging.py +184 -0
- odoo/addons/shopfloor/tests/test_checkout_done.py +133 -0
- odoo/addons/shopfloor/tests/test_checkout_list_delivery_packaging.py +131 -0
- odoo/addons/shopfloor/tests/test_checkout_list_package.py +327 -0
- odoo/addons/shopfloor/tests/test_checkout_new_package.py +88 -0
- odoo/addons/shopfloor/tests/test_checkout_no_package.py +95 -0
- odoo/addons/shopfloor/tests/test_checkout_scan.py +174 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_line.py +377 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_line_base.py +25 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_line_no_prefill_qty.py +91 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_package_action.py +451 -0
- odoo/addons/shopfloor/tests/test_checkout_scan_package_action_no_prefill_qty.py +107 -0
- odoo/addons/shopfloor/tests/test_checkout_select.py +74 -0
- odoo/addons/shopfloor/tests/test_checkout_select_line.py +130 -0
- odoo/addons/shopfloor/tests/test_checkout_select_package_base.py +64 -0
- odoo/addons/shopfloor/tests/test_checkout_set_qty.py +257 -0
- odoo/addons/shopfloor/tests/test_checkout_summary.py +69 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_base.py +83 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_batch.py +109 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_change_pack_lot.py +111 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_is_zero.py +98 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_destination.py +376 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_destination_no_prefill_qty.py +115 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_line.py +402 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_line_location_or_pack_first.py +114 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_scan_line_no_prefill_qty.py +70 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_select.py +387 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_skip.py +90 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_stock_issue.py +364 -0
- odoo/addons/shopfloor/tests/test_cluster_picking_unload.py +911 -0
- odoo/addons/shopfloor/tests/test_delivery_base.py +155 -0
- odoo/addons/shopfloor/tests/test_delivery_done.py +108 -0
- odoo/addons/shopfloor/tests/test_delivery_list_stock_picking.py +49 -0
- odoo/addons/shopfloor/tests/test_delivery_reset_qty_done_line.py +119 -0
- odoo/addons/shopfloor/tests/test_delivery_reset_qty_done_pack.py +107 -0
- odoo/addons/shopfloor/tests/test_delivery_scan_deliver.py +557 -0
- odoo/addons/shopfloor/tests/test_delivery_select.py +38 -0
- odoo/addons/shopfloor/tests/test_delivery_set_qty_done_line.py +91 -0
- odoo/addons/shopfloor/tests/test_delivery_set_qty_done_pack.py +135 -0
- odoo/addons/shopfloor/tests/test_delivery_sublocation.py +180 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_base.py +136 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_get_work.py +125 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_mix.py +509 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_putaway.py +143 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_scan_location.py +34 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_all.py +343 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_package_or_line.py +1074 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_single.py +748 -0
- odoo/addons/shopfloor/tests/test_location_content_transfer_start.py +359 -0
- odoo/addons/shopfloor/tests/test_menu_base.py +261 -0
- odoo/addons/shopfloor/tests/test_menu_counters.py +61 -0
- odoo/addons/shopfloor/tests/test_misc.py +25 -0
- odoo/addons/shopfloor/tests/test_move_action_assign.py +87 -0
- odoo/addons/shopfloor/tests/test_openapi.py +21 -0
- odoo/addons/shopfloor/tests/test_picking_form.py +62 -0
- odoo/addons/shopfloor/tests/test_scan_anything.py +49 -0
- odoo/addons/shopfloor/tests/test_single_pack_transfer.py +1121 -0
- odoo/addons/shopfloor/tests/test_single_pack_transfer_base.py +32 -0
- odoo/addons/shopfloor/tests/test_single_pack_transfer_putaway.py +104 -0
- odoo/addons/shopfloor/tests/test_stock_split.py +204 -0
- odoo/addons/shopfloor/tests/test_user.py +42 -0
- odoo/addons/shopfloor/tests/test_zone_picking_base.py +608 -0
- odoo/addons/shopfloor/tests/test_zone_picking_change_pack_lot.py +140 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_line.py +723 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_line_first_scan_location.py +207 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_line_first_scan_location.py.bak +202 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_line_no_prefill_qty.py +107 -0
- odoo/addons/shopfloor/tests/test_zone_picking_select_picking_type.py +26 -0
- odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination.py +643 -0
- odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_no_prefill_qty.py +146 -0
- odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_pick_pack.py +241 -0
- odoo/addons/shopfloor/tests/test_zone_picking_start.py +206 -0
- odoo/addons/shopfloor/tests/test_zone_picking_stock_issue.py +121 -0
- odoo/addons/shopfloor/tests/test_zone_picking_unload_all.py +353 -0
- odoo/addons/shopfloor/tests/test_zone_picking_unload_buffer_lines.py +113 -0
- odoo/addons/shopfloor/tests/test_zone_picking_unload_set_destination.py +374 -0
- odoo/addons/shopfloor/tests/test_zone_picking_unload_single.py +123 -0
- odoo/addons/shopfloor/tests/test_zone_picking_zero_check.py +43 -0
- odoo/addons/shopfloor/utils.py +13 -0
- odoo/addons/shopfloor/views/shopfloor_menu.xml +167 -0
- odoo/addons/shopfloor/views/stock_location.xml +20 -0
- odoo/addons/shopfloor/views/stock_move_line.xml +52 -0
- odoo/addons/shopfloor/views/stock_picking_type.xml +19 -0
- odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/METADATA +192 -0
- odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/RECORD +182 -0
- odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/WHEEL +5 -0
- odoo_addon_shopfloor-16.0.1.0.0.24.dist-info/top_level.txt +1 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
|
2
|
+
# Copyright 2020 Akretion (http://www.akretion.com)
|
3
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
4
|
+
from .common import CommonCase
|
5
|
+
|
6
|
+
# pylint: disable=missing-return
|
7
|
+
|
8
|
+
|
9
|
+
class SinglePackTransferCommonBase(CommonCase):
|
10
|
+
@classmethod
|
11
|
+
def setUpClassVars(cls, *args, **kwargs):
|
12
|
+
super().setUpClassVars(*args, **kwargs)
|
13
|
+
cls.menu = cls.env.ref("shopfloor.shopfloor_menu_demo_single_pallet_transfer")
|
14
|
+
cls.profile = cls.env.ref("shopfloor_base.profile_demo_1")
|
15
|
+
cls.picking_type = cls.menu.picking_type_ids
|
16
|
+
cls.wh = cls.picking_type.warehouse_id
|
17
|
+
|
18
|
+
@classmethod
|
19
|
+
def setUpClassBaseData(cls, *args, **kwargs):
|
20
|
+
super().setUpClassBaseData(*args, **kwargs)
|
21
|
+
# we activate the move creation in tests when needed
|
22
|
+
cls.menu.sudo().allow_move_create = False
|
23
|
+
|
24
|
+
# disable the completion on the picking type, we'll have specific test(s)
|
25
|
+
# to check the behavior of this screen
|
26
|
+
cls.picking_type.sudo().display_completion_info = False
|
27
|
+
|
28
|
+
def setUp(self):
|
29
|
+
super().setUp()
|
30
|
+
self.service = self.get_service(
|
31
|
+
"single_pack_transfer", menu=self.menu, profile=self.profile
|
32
|
+
)
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
3
|
+
|
4
|
+
from .test_single_pack_transfer_base import SinglePackTransferCommonBase
|
5
|
+
|
6
|
+
# pylint: disable=missing-return
|
7
|
+
|
8
|
+
|
9
|
+
class TestSinglePackTransferPutaway(SinglePackTransferCommonBase):
|
10
|
+
@classmethod
|
11
|
+
def setUpClassVars(cls, *args, **kwargs):
|
12
|
+
super().setUpClassVars(*args, **kwargs)
|
13
|
+
cls.pallets_storage_type = cls.env.ref(
|
14
|
+
"stock_storage_type.package_storage_type_pallets"
|
15
|
+
)
|
16
|
+
cls.main_pallets_location = cls.env.ref(
|
17
|
+
"stock_storage_type.stock_location_pallets"
|
18
|
+
)
|
19
|
+
cls.reserve_pallets_locations = cls.env.ref(
|
20
|
+
"stock_storage_type.stock_location_pallets_reserve"
|
21
|
+
)
|
22
|
+
cls.all_pallets_locations = (
|
23
|
+
cls.main_pallets_location.leaf_location_ids
|
24
|
+
| cls.reserve_pallets_locations.leaf_location_ids
|
25
|
+
)
|
26
|
+
|
27
|
+
@classmethod
|
28
|
+
def setUpClassBaseData(cls, *args, **kwargs):
|
29
|
+
super().setUpClassBaseData(*args, **kwargs)
|
30
|
+
cls.package = cls.env["stock.quant.package"].create(
|
31
|
+
{
|
32
|
+
# this will parameterize the putaway to use pallet locations,
|
33
|
+
# and if not, it will stay on the picking type's default dest.
|
34
|
+
"package_type_id": cls.pallets_storage_type.id,
|
35
|
+
}
|
36
|
+
)
|
37
|
+
cls._update_qty_in_location(cls.shelf1, cls.product_a, 10, package=cls.package)
|
38
|
+
cls.menu.sudo().ignore_no_putaway_available = True
|
39
|
+
cls.menu.sudo().allow_move_create = True
|
40
|
+
|
41
|
+
def test_normal_putaway(self):
|
42
|
+
"""Ensure putaway is applied on moves"""
|
43
|
+
response = self.service.dispatch(
|
44
|
+
"start", params={"barcode": self.shelf1.barcode}
|
45
|
+
)
|
46
|
+
self.assert_response(
|
47
|
+
response,
|
48
|
+
next_state="scan_location",
|
49
|
+
data=self.ANY,
|
50
|
+
)
|
51
|
+
package_level_id = response["data"]["scan_location"]["id"]
|
52
|
+
package_level = self.env["stock.package_level"].browse(package_level_id)
|
53
|
+
self.assertIn(package_level.location_dest_id, self.all_pallets_locations)
|
54
|
+
|
55
|
+
def test_ignore_no_putaway_available(self):
|
56
|
+
"""Ignore no putaway available is activated on the menu
|
57
|
+
|
58
|
+
In this case, when no putaway is possible, the changes
|
59
|
+
are rollbacked and an error is returned.
|
60
|
+
"""
|
61
|
+
for location in self.all_pallets_locations:
|
62
|
+
package = self.env["stock.quant.package"].create(
|
63
|
+
{"package_type_id": self.pallets_storage_type.id}
|
64
|
+
)
|
65
|
+
self._update_qty_in_location(location, self.product_a, 10, package=package)
|
66
|
+
|
67
|
+
response = self.service.dispatch(
|
68
|
+
"start", params={"barcode": self.shelf1.barcode}
|
69
|
+
)
|
70
|
+
self.assert_response(
|
71
|
+
response,
|
72
|
+
next_state="start",
|
73
|
+
message=self.service.msg_store.no_putaway_destination_available(),
|
74
|
+
)
|
75
|
+
|
76
|
+
package_levels = self.env["stock.package_level"].search(
|
77
|
+
[("package_id", "=", self.package.id)]
|
78
|
+
)
|
79
|
+
# no package level created to move the package
|
80
|
+
self.assertFalse(package_levels)
|
81
|
+
|
82
|
+
def test_putaway_move_dest_not_child_of_picking_dest(self):
|
83
|
+
"""Putaway is applied on move but the destination location is not a
|
84
|
+
child of the default picking type destination location.
|
85
|
+
Case where the picking is created by scanning a package level. Then the
|
86
|
+
move destination is according to the putaway and valid.
|
87
|
+
"""
|
88
|
+
# Change the default destination location of the picking type
|
89
|
+
# to get it outside of the putaway destination
|
90
|
+
self.picking_type.sudo().default_location_dest_id = self.main_pallets_location
|
91
|
+
# Create a standard putaway to move the package from pallet storage
|
92
|
+
# to a unrelated one (outside of the pallet storage tree)
|
93
|
+
self.env["stock.putaway.rule"].sudo().create(
|
94
|
+
{
|
95
|
+
"product_id": self.product_a.id,
|
96
|
+
"location_in_id": self.picking_type.default_location_dest_id.id,
|
97
|
+
"location_out_id": self.env.ref("stock.location_refrigerator_small").id,
|
98
|
+
}
|
99
|
+
)
|
100
|
+
# Check the result
|
101
|
+
response = self.service.dispatch(
|
102
|
+
"start", params={"barcode": self.shelf1.barcode}
|
103
|
+
)
|
104
|
+
self.assert_response(response, next_state="scan_location", data=self.ANY)
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
3
|
+
from odoo.tests import tagged
|
4
|
+
from odoo.tests.common import TransactionCase
|
5
|
+
|
6
|
+
# pylint: disable=missing-return
|
7
|
+
|
8
|
+
|
9
|
+
@tagged("post_install", "-at_install")
|
10
|
+
class TestStockSplit(TransactionCase):
|
11
|
+
@classmethod
|
12
|
+
def setUpClass(cls):
|
13
|
+
super(TestStockSplit, cls).setUpClass()
|
14
|
+
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
15
|
+
cls.warehouse = cls.env.ref("stock.warehouse0")
|
16
|
+
cls.warehouse.delivery_steps = "pick_pack_ship"
|
17
|
+
cls.customer_location = cls.env.ref("stock.stock_location_customers")
|
18
|
+
cls.pack_location = cls.warehouse.wh_pack_stock_loc_id
|
19
|
+
cls.ship_location = cls.warehouse.wh_output_stock_loc_id
|
20
|
+
cls.stock_location = cls.env.ref("stock.stock_location_stock")
|
21
|
+
# Create products
|
22
|
+
cls.product_a = (
|
23
|
+
cls.env["product.product"]
|
24
|
+
.sudo()
|
25
|
+
.create(
|
26
|
+
{
|
27
|
+
"name": "Product A",
|
28
|
+
"type": "product",
|
29
|
+
"default_code": "A",
|
30
|
+
"barcode": "A",
|
31
|
+
"weight": 2,
|
32
|
+
}
|
33
|
+
)
|
34
|
+
)
|
35
|
+
cls.product_a_packaging = (
|
36
|
+
cls.env["product.packaging"]
|
37
|
+
.sudo()
|
38
|
+
.create(
|
39
|
+
{
|
40
|
+
"name": "Box",
|
41
|
+
"product_id": cls.product_a.id,
|
42
|
+
"barcode": "ProductABox",
|
43
|
+
}
|
44
|
+
)
|
45
|
+
)
|
46
|
+
cls.product_b = (
|
47
|
+
cls.env["product.product"]
|
48
|
+
.sudo()
|
49
|
+
.create(
|
50
|
+
{
|
51
|
+
"name": "Product B",
|
52
|
+
"type": "product",
|
53
|
+
"default_code": "B",
|
54
|
+
"barcode": "B",
|
55
|
+
"weight": 2,
|
56
|
+
}
|
57
|
+
)
|
58
|
+
)
|
59
|
+
cls.product_b_packaging = (
|
60
|
+
cls.env["product.packaging"]
|
61
|
+
.sudo()
|
62
|
+
.create(
|
63
|
+
{
|
64
|
+
"name": "Box",
|
65
|
+
"product_id": cls.product_b.id,
|
66
|
+
"barcode": "ProductBBox",
|
67
|
+
}
|
68
|
+
)
|
69
|
+
)
|
70
|
+
# Put product_a quantities in different packages to get several move lines
|
71
|
+
cls.package_1 = cls.env["stock.quant.package"].create({"name": "PACKAGE_1"})
|
72
|
+
cls.package_2 = cls.env["stock.quant.package"].create({"name": "PACKAGE_2"})
|
73
|
+
cls.package_3 = cls.env["stock.quant.package"].create({"name": "PACKAGE_3"})
|
74
|
+
cls.package_4 = cls.env["stock.quant.package"].create({"name": "PACKAGE_4"})
|
75
|
+
cls._update_qty_in_location(
|
76
|
+
cls.stock_location, cls.product_a, 6, package=cls.package_1
|
77
|
+
)
|
78
|
+
cls._update_qty_in_location(
|
79
|
+
cls.stock_location, cls.product_a, 4, package=cls.package_2
|
80
|
+
)
|
81
|
+
cls._update_qty_in_location(
|
82
|
+
cls.stock_location, cls.product_a, 5, package=cls.package_3
|
83
|
+
)
|
84
|
+
# Put product_b quantities in stock
|
85
|
+
cls._update_qty_in_location(cls.stock_location, cls.product_b, 10)
|
86
|
+
# Create the pick/pack/ship transfer
|
87
|
+
cls.ship_move_a = cls.env["stock.move"].create(
|
88
|
+
{
|
89
|
+
"name": cls.product_a.display_name,
|
90
|
+
"product_id": cls.product_a.id,
|
91
|
+
"product_uom_qty": 15.0,
|
92
|
+
"product_uom": cls.product_a.uom_id.id,
|
93
|
+
"location_id": cls.ship_location.id,
|
94
|
+
"location_dest_id": cls.customer_location.id,
|
95
|
+
"warehouse_id": cls.warehouse.id,
|
96
|
+
"picking_type_id": cls.warehouse.out_type_id.id,
|
97
|
+
"procure_method": "make_to_order",
|
98
|
+
"state": "draft",
|
99
|
+
}
|
100
|
+
)
|
101
|
+
cls.ship_move_b = cls.env["stock.move"].create(
|
102
|
+
{
|
103
|
+
"name": cls.product_b.display_name,
|
104
|
+
"product_id": cls.product_b.id,
|
105
|
+
"product_uom_qty": 4,
|
106
|
+
"product_uom": cls.product_b.uom_id.id,
|
107
|
+
"location_id": cls.ship_location.id,
|
108
|
+
"location_dest_id": cls.customer_location.id,
|
109
|
+
"warehouse_id": cls.warehouse.id,
|
110
|
+
"picking_type_id": cls.warehouse.out_type_id.id,
|
111
|
+
"procure_method": "make_to_order",
|
112
|
+
"state": "draft",
|
113
|
+
}
|
114
|
+
)
|
115
|
+
(cls.ship_move_a | cls.ship_move_b)._assign_picking()
|
116
|
+
(cls.ship_move_a | cls.ship_move_b)._action_confirm(merge=False)
|
117
|
+
cls.pack_move_a = cls.ship_move_a.move_orig_ids[0]
|
118
|
+
cls.pick_move_a = cls.pack_move_a.move_orig_ids[0]
|
119
|
+
cls.pack_move_b = cls.ship_move_b.move_orig_ids[0]
|
120
|
+
cls.pick_move_b = cls.pack_move_b.move_orig_ids[0]
|
121
|
+
cls.picking = cls.pick_move_a.picking_id
|
122
|
+
cls.packing = cls.pack_move_a.picking_id
|
123
|
+
cls.picking.action_assign()
|
124
|
+
|
125
|
+
@classmethod
|
126
|
+
def _update_qty_in_location(
|
127
|
+
cls, location, product, quantity, package=None, lot=None
|
128
|
+
):
|
129
|
+
quants = cls.env["stock.quant"]._gather(
|
130
|
+
product, location, lot_id=lot, package_id=package, strict=True
|
131
|
+
)
|
132
|
+
# this method adds the quantity to the current quantity, so remove it
|
133
|
+
quantity -= sum(quants.mapped("quantity"))
|
134
|
+
cls.env["stock.quant"]._update_available_quantity(
|
135
|
+
product, location, quantity, package_id=package, lot_id=lot
|
136
|
+
)
|
137
|
+
|
138
|
+
def test_split_pickings_from_source_location(self):
|
139
|
+
dest_location = self.pick_move_a.location_dest_id.sudo().copy(
|
140
|
+
{
|
141
|
+
"name": self.pick_move_a.location_dest_id.name + "_2",
|
142
|
+
"barcode": self.pick_move_a.location_dest_id.barcode + "_2",
|
143
|
+
"location_id": self.pick_move_a.location_dest_id.id,
|
144
|
+
}
|
145
|
+
)
|
146
|
+
# Pick goods from stock and move some of them to a different destination
|
147
|
+
self.assertEqual(self.pick_move_a.state, "assigned")
|
148
|
+
for i, move_line in enumerate(self.pick_move_a.move_line_ids):
|
149
|
+
move_line.qty_done = move_line.reserved_uom_qty
|
150
|
+
if i % 2:
|
151
|
+
move_line.location_dest_id = dest_location
|
152
|
+
self.pick_move_a.extract_and_action_done()
|
153
|
+
self.assertEqual(self.pick_move_a.state, "done")
|
154
|
+
# Pack step, we want to split move lines from common source location
|
155
|
+
self.assertEqual(self.pack_move_a.state, "assigned")
|
156
|
+
move_lines_to_process = self.pack_move_a.move_line_ids.filtered(
|
157
|
+
lambda ml: ml.location_id == dest_location
|
158
|
+
)
|
159
|
+
self.assertEqual(len(self.pack_move_a.move_line_ids), 3)
|
160
|
+
self.assertEqual(len(self.packing.package_level_ids), 3)
|
161
|
+
self.assertEqual(len(move_lines_to_process), 1)
|
162
|
+
new_packing = move_lines_to_process._split_pickings_from_source_location()
|
163
|
+
self.assertEqual(len(self.packing.package_level_ids), 2)
|
164
|
+
self.assertEqual(len(new_packing.package_level_ids), 1)
|
165
|
+
self.assertEqual(len(new_packing.move_line_ids), 1)
|
166
|
+
self.assertTrue(new_packing != self.packing)
|
167
|
+
self.assertEqual(new_packing.backorder_id, self.packing)
|
168
|
+
self.assertEqual(
|
169
|
+
self.pick_move_a.move_dest_ids.picking_id, self.packing | new_packing
|
170
|
+
)
|
171
|
+
self.assertEqual(move_lines_to_process.state, "assigned")
|
172
|
+
self.assertEqual(
|
173
|
+
set(self.pack_move_a.move_line_ids.mapped("state")), {"assigned"}
|
174
|
+
)
|
175
|
+
|
176
|
+
def test_extract_and_action_done_one_assigned_move(self):
|
177
|
+
self.assertFalse(self.picking.backorder_ids)
|
178
|
+
self.assertEqual(self.picking.state, "assigned")
|
179
|
+
for move_line in self.pick_move_b.move_line_ids:
|
180
|
+
move_line.qty_done = move_line.reserved_uom_qty
|
181
|
+
self.pick_move_b.extract_and_action_done()
|
182
|
+
new_picking = self.picking.backorder_ids
|
183
|
+
self.assertTrue(new_picking)
|
184
|
+
# Check move lines repartition
|
185
|
+
self.assertNotIn(self.pick_move_b, self.picking.move_ids)
|
186
|
+
self.assertEqual(new_picking.move_ids, self.pick_move_b)
|
187
|
+
# Check states
|
188
|
+
self.assertEqual(self.picking.state, "assigned")
|
189
|
+
self.assertEqual(self.pick_move_b.state, "done")
|
190
|
+
self.assertEqual(new_picking.state, "done")
|
191
|
+
|
192
|
+
def test_extract_and_action_done_multiple_assigned_moves(self):
|
193
|
+
self.assertFalse(self.picking.backorder_ids)
|
194
|
+
self.assertEqual(self.picking.state, "assigned")
|
195
|
+
for move_line in self.picking.move_line_ids:
|
196
|
+
move_line.qty_done = move_line.reserved_uom_qty
|
197
|
+
self.picking.move_ids.extract_and_action_done()
|
198
|
+
# No backorder as all moves of the picking have been validated
|
199
|
+
new_picking = self.picking.backorder_ids
|
200
|
+
self.assertFalse(new_picking)
|
201
|
+
# Check move lines repartition
|
202
|
+
self.assertEqual(len(self.picking.move_ids), 2)
|
203
|
+
# Check states
|
204
|
+
self.assertEqual(self.picking.state, "done")
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
3
|
+
|
4
|
+
from .test_menu_base import CommonMenuCase
|
5
|
+
|
6
|
+
# pylint: disable=missing-return
|
7
|
+
|
8
|
+
|
9
|
+
class UserCase(CommonMenuCase):
|
10
|
+
@classmethod
|
11
|
+
def setUpClassVars(cls, *args, **kwargs):
|
12
|
+
super().setUpClassVars(*args, **kwargs)
|
13
|
+
ref = cls.env.ref
|
14
|
+
cls.wms_profile = ref("shopfloor.profile_demo_1")
|
15
|
+
cls.wms_profile2 = ref("shopfloor.profile_demo_2")
|
16
|
+
|
17
|
+
def test_menu_by_profile(self):
|
18
|
+
"""Request /user/menu w/ a specific profile but no picking types"""
|
19
|
+
|
20
|
+
service = self.get_service("user", profile=self.wms_profile)
|
21
|
+
menus = (
|
22
|
+
self.env["shopfloor.menu"]
|
23
|
+
.sudo()
|
24
|
+
.search([("profile_id", "=", self.wms_profile.id)])
|
25
|
+
)
|
26
|
+
response = service.dispatch("menu")
|
27
|
+
self.assert_response(
|
28
|
+
response,
|
29
|
+
data={"menus": [self._data_for_menu_item(menu) for menu in menus]},
|
30
|
+
)
|
31
|
+
|
32
|
+
service = self.get_service("user", profile=self.wms_profile2)
|
33
|
+
menus = (
|
34
|
+
self.env["shopfloor.menu"]
|
35
|
+
.sudo()
|
36
|
+
.search([("profile_id", "=", self.wms_profile2.id)])
|
37
|
+
)
|
38
|
+
response = service.dispatch("menu")
|
39
|
+
self.assert_response(
|
40
|
+
response,
|
41
|
+
data={"menus": [self._data_for_menu_item(menu) for menu in menus]},
|
42
|
+
)
|