odoo-addon-shopfloor 16.0.1.0.0.25__py3-none-any.whl → 16.0.2.1.0.1__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.
Files changed (76) hide show
  1. odoo/addons/shopfloor/README.rst +1 -1
  2. odoo/addons/shopfloor/__manifest__.py +1 -1
  3. odoo/addons/shopfloor/actions/data.py +69 -34
  4. odoo/addons/shopfloor/actions/data_detail.py +20 -0
  5. odoo/addons/shopfloor/actions/message.py +94 -2
  6. odoo/addons/shopfloor/actions/move_line_search.py +2 -2
  7. odoo/addons/shopfloor/actions/packaging.py +10 -0
  8. odoo/addons/shopfloor/actions/schema.py +11 -0
  9. odoo/addons/shopfloor/actions/schema_detail.py +14 -8
  10. odoo/addons/shopfloor/actions/search.py +9 -6
  11. odoo/addons/shopfloor/components/scan_handler_product.py +2 -0
  12. odoo/addons/shopfloor/data/shopfloor_scenario_data.xml +4 -2
  13. odoo/addons/shopfloor/docs/checkout_diag_seq.plantuml +19 -5
  14. odoo/addons/shopfloor/docs/checkout_diag_seq.png +0 -0
  15. odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.plantuml +4 -4
  16. odoo/addons/shopfloor/docs/single_pack_transfer_diag_seq.png +0 -0
  17. odoo/addons/shopfloor/i18n/ca.po +373 -143
  18. odoo/addons/shopfloor/i18n/de.po +357 -145
  19. odoo/addons/shopfloor/i18n/es_AR.po +489 -174
  20. odoo/addons/shopfloor/i18n/it.po +642 -252
  21. odoo/addons/shopfloor/i18n/pt_BR.po +357 -145
  22. odoo/addons/shopfloor/i18n/shopfloor.pot +133 -8
  23. odoo/addons/shopfloor/migrations/16.0.2.0.0/post-migration.py +43 -0
  24. odoo/addons/shopfloor/models/shopfloor_menu.py +29 -5
  25. odoo/addons/shopfloor/models/stock_move_line.py +3 -0
  26. odoo/addons/shopfloor/models/stock_picking.py +11 -0
  27. odoo/addons/shopfloor/services/checkout.py +216 -61
  28. odoo/addons/shopfloor/services/cluster_picking.py +33 -18
  29. odoo/addons/shopfloor/services/delivery.py +25 -7
  30. odoo/addons/shopfloor/services/location_content_transfer.py +42 -28
  31. odoo/addons/shopfloor/services/single_pack_transfer.py +36 -13
  32. odoo/addons/shopfloor/services/zone_picking.py +187 -67
  33. odoo/addons/shopfloor/static/description/index.html +1 -1
  34. odoo/addons/shopfloor/tests/__init__.py +2 -0
  35. odoo/addons/shopfloor/tests/common.py +3 -1
  36. odoo/addons/shopfloor/tests/test_actions_data.py +46 -7
  37. odoo/addons/shopfloor/tests/test_actions_data_base.py +15 -0
  38. odoo/addons/shopfloor/tests/test_actions_data_detail.py +30 -8
  39. odoo/addons/shopfloor/tests/test_actions_packaging.py +43 -0
  40. odoo/addons/shopfloor/tests/test_checkout_base.py +15 -5
  41. odoo/addons/shopfloor/tests/test_checkout_done.py +40 -5
  42. odoo/addons/shopfloor/tests/test_checkout_list_delivery_packaging.py +1 -0
  43. odoo/addons/shopfloor/tests/test_checkout_list_package.py +3 -1
  44. odoo/addons/shopfloor/tests/test_checkout_scan.py +19 -0
  45. odoo/addons/shopfloor/tests/test_checkout_scan_dest_location.py +99 -0
  46. odoo/addons/shopfloor/tests/test_checkout_scan_line.py +3 -2
  47. odoo/addons/shopfloor/tests/test_checkout_scan_line_no_prefill_qty.py +48 -0
  48. odoo/addons/shopfloor/tests/test_checkout_scan_package_action.py +26 -0
  49. odoo/addons/shopfloor/tests/test_checkout_scan_package_action_no_prefill_qty.py +16 -0
  50. odoo/addons/shopfloor/tests/test_checkout_select_package_base.py +4 -1
  51. odoo/addons/shopfloor/tests/test_checkout_summary.py +1 -1
  52. odoo/addons/shopfloor/tests/test_cluster_picking_unload.py +37 -8
  53. odoo/addons/shopfloor/tests/test_delivery_list_stock_picking.py +5 -0
  54. odoo/addons/shopfloor/tests/test_location_content_transfer_base.py +4 -4
  55. odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_all.py +24 -2
  56. odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_package_or_line.py +6 -4
  57. odoo/addons/shopfloor/tests/test_location_content_transfer_single.py +45 -0
  58. odoo/addons/shopfloor/tests/test_scan_anything.py +7 -0
  59. odoo/addons/shopfloor/tests/test_single_pack_transfer.py +59 -8
  60. odoo/addons/shopfloor/tests/test_zone_picking_base.py +36 -10
  61. odoo/addons/shopfloor/tests/test_zone_picking_change_pack_lot.py +2 -0
  62. odoo/addons/shopfloor/tests/test_zone_picking_complete_mix_pack_flux.py +59 -0
  63. odoo/addons/shopfloor/tests/test_zone_picking_select_line.py +33 -2
  64. odoo/addons/shopfloor/tests/test_zone_picking_select_line_first_scan_location.py +8 -3
  65. odoo/addons/shopfloor/tests/test_zone_picking_select_line_no_prefill_qty.py +19 -2
  66. odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination.py +88 -19
  67. odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_package_not_allowed.py +94 -0
  68. odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_pick_pack.py +1 -5
  69. odoo/addons/shopfloor/tests/test_zone_picking_start.py +4 -4
  70. odoo/addons/shopfloor/tests/test_zone_picking_unload_all.py +1 -1
  71. odoo/addons/shopfloor/tests/test_zone_picking_unload_set_destination.py +4 -4
  72. odoo/addons/shopfloor/views/shopfloor_menu.xml +30 -0
  73. {odoo_addon_shopfloor-16.0.1.0.0.25.dist-info → odoo_addon_shopfloor-16.0.2.1.0.1.dist-info}/METADATA +2 -2
  74. {odoo_addon_shopfloor-16.0.1.0.0.25.dist-info → odoo_addon_shopfloor-16.0.2.1.0.1.dist-info}/RECORD +76 -71
  75. {odoo_addon_shopfloor-16.0.1.0.0.25.dist-info → odoo_addon_shopfloor-16.0.2.1.0.1.dist-info}/WHEEL +0 -0
  76. {odoo_addon_shopfloor-16.0.1.0.0.25.dist-info → odoo_addon_shopfloor-16.0.2.1.0.1.dist-info}/top_level.txt +0 -0
@@ -176,6 +176,19 @@ class ZonePickingCommonCase(CommonCase):
176
176
  }
177
177
  )
178
178
  )
179
+ cls.product_i = (
180
+ cls.env["product.product"]
181
+ .sudo()
182
+ .create(
183
+ {
184
+ "name": "Product I",
185
+ "type": "product",
186
+ "default_code": "I",
187
+ "barcode": "I",
188
+ "weight": 3,
189
+ }
190
+ )
191
+ )
179
192
  products = (
180
193
  cls.product_a
181
194
  + cls.product_b
@@ -185,6 +198,7 @@ class ZonePickingCommonCase(CommonCase):
185
198
  + cls.product_f
186
199
  + cls.product_g
187
200
  + cls.product_h
201
+ + cls.product_i
188
202
  )
189
203
  for product in products:
190
204
  cls.env["stock.putaway.rule"].sudo().create(
@@ -218,12 +232,12 @@ class ZonePickingCommonCase(CommonCase):
218
232
  cls._update_qty_in_location(cls.zone_sublocation4, cls.product_e, 4)
219
233
  # 2 products in a package available in zone_sublocation4
220
234
  cls.picking5 = picking5 = cls._create_picking(
221
- lines=[(cls.product_b, 10), (cls.product_f, 10)]
235
+ lines=[(cls.product_i, 10), (cls.product_f, 10)]
222
236
  )
223
237
  cls._fill_stock_for_moves(
224
238
  picking5.move_ids,
225
239
  in_package=True,
226
- same_package=False,
240
+ same_package=True,
227
241
  location=cls.zone_sublocation4,
228
242
  )
229
243
  # 2 products available in zone_sublocation5, but one is partially available
@@ -261,6 +275,7 @@ class ZonePickingCommonCase(CommonCase):
261
275
  current_zone_location=self.zone_location,
262
276
  current_picking_type=self.picking_type,
263
277
  )
278
+ self.menu.sudo().allow_alternative_destination_package = True
264
279
 
265
280
  def _assert_response_select_zone(self, response, zone_locations, message=None):
266
281
  data = {"zones": self.service._data_for_select_zone(zone_locations)}
@@ -307,7 +322,7 @@ class ZonePickingCommonCase(CommonCase):
307
322
  move_lines,
308
323
  message=None,
309
324
  popup=None,
310
- confirmation_required=False,
325
+ confirmation_required=None,
311
326
  product=None,
312
327
  sublocation=None,
313
328
  location_first=None,
@@ -331,6 +346,9 @@ class ZonePickingCommonCase(CommonCase):
331
346
  data_move_line[
332
347
  "location_will_be_empty"
333
348
  ] = move_line.location_id.planned_qty_in_location_is_empty(move_line)
349
+ data_move_line[
350
+ "handle_complete_mix_pack"
351
+ ] = self.service._handle_complete_mix_pack(move_line.package_id)
334
352
  self.assert_response(
335
353
  response,
336
354
  next_state=state,
@@ -347,7 +365,7 @@ class ZonePickingCommonCase(CommonCase):
347
365
  move_lines,
348
366
  message=None,
349
367
  popup=None,
350
- confirmation_required=False,
368
+ confirmation_required=None,
351
369
  product=None,
352
370
  sublocation=None,
353
371
  location_first=False,
@@ -376,12 +394,16 @@ class ZonePickingCommonCase(CommonCase):
376
394
  picking_type,
377
395
  move_line,
378
396
  message=None,
379
- confirmation_required=False,
397
+ confirmation_required=None,
380
398
  qty_done=None,
399
+ handle_complete_mix_pack=False,
381
400
  ):
382
401
  expected_move_line = self.data.move_line(move_line, with_picking=True)
383
402
  if qty_done is not None:
384
403
  expected_move_line["qty_done"] = qty_done
404
+ allow_alternative_destination_package = (
405
+ self.menu.allow_alternative_destination_package
406
+ )
385
407
  self.assert_response(
386
408
  response,
387
409
  next_state=state,
@@ -390,6 +412,8 @@ class ZonePickingCommonCase(CommonCase):
390
412
  "picking_type": self.data.picking_type(picking_type),
391
413
  "move_line": expected_move_line,
392
414
  "confirmation_required": confirmation_required,
415
+ "allow_alternative_destination_package": allow_alternative_destination_package,
416
+ "handle_complete_mix_pack": handle_complete_mix_pack,
393
417
  },
394
418
  message=message,
395
419
  )
@@ -401,8 +425,9 @@ class ZonePickingCommonCase(CommonCase):
401
425
  picking_type,
402
426
  move_line,
403
427
  message=None,
404
- confirmation_required=False,
428
+ confirmation_required=None,
405
429
  qty_done=None,
430
+ handle_complete_mix_pack=False,
406
431
  ):
407
432
  self._assert_response_set_line_destination(
408
433
  "set_line_destination",
@@ -413,6 +438,7 @@ class ZonePickingCommonCase(CommonCase):
413
438
  message=message,
414
439
  confirmation_required=confirmation_required,
415
440
  qty_done=qty_done,
441
+ handle_complete_mix_pack=handle_complete_mix_pack,
416
442
  )
417
443
 
418
444
  def _assert_response_zero_check(
@@ -498,7 +524,7 @@ class ZonePickingCommonCase(CommonCase):
498
524
  picking_type,
499
525
  move_line,
500
526
  message=None,
501
- confirmation_required=False,
527
+ confirmation_required=None,
502
528
  ):
503
529
  self.assert_response(
504
530
  response,
@@ -519,7 +545,7 @@ class ZonePickingCommonCase(CommonCase):
519
545
  picking_type,
520
546
  move_line,
521
547
  message=None,
522
- confirmation_required=False,
548
+ confirmation_required=None,
523
549
  ):
524
550
  self._assert_response_unload_set_destination(
525
551
  "unload_set_destination",
@@ -539,7 +565,7 @@ class ZonePickingCommonCase(CommonCase):
539
565
  picking_type,
540
566
  move_lines,
541
567
  message=None,
542
- confirmation_required=False,
568
+ confirmation_required=None,
543
569
  ):
544
570
  self.assert_response(
545
571
  response,
@@ -560,7 +586,7 @@ class ZonePickingCommonCase(CommonCase):
560
586
  picking_type,
561
587
  move_lines,
562
588
  message=None,
563
- confirmation_required=False,
589
+ confirmation_required=None,
564
590
  ):
565
591
  self._assert_response_unload_all(
566
592
  "unload_all",
@@ -87,6 +87,7 @@ class ZonePickingChangePackLotCase(ZonePickingCommonCase):
87
87
  message=self.service.msg_store.package_replaced_by_package(
88
88
  previous_package, self.free_package
89
89
  ),
90
+ qty_done=self.service._get_prefill_qty(move_line),
90
91
  )
91
92
 
92
93
  def test_change_pack_lot_change_lot_ok(self):
@@ -137,4 +138,5 @@ class ZonePickingChangePackLotCase(ZonePickingCommonCase):
137
138
  message=self.service.msg_store.lot_replaced_by_lot(
138
139
  previous_lot, self.free_lot
139
140
  ),
141
+ qty_done=self.service._get_prefill_qty(move_line),
140
142
  )
@@ -0,0 +1,59 @@
1
+ # Copyright 2023 Camptocamp SA (http://www.camptocamp.com)
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3
+
4
+ from .test_zone_picking_base import ZonePickingCommonCase
5
+
6
+
7
+ class ZonePickingCompleteMixPackageFluxCase(ZonePickingCommonCase):
8
+ """Tests for the flux of complete mix packages."""
9
+
10
+ def setUp(self):
11
+ super().setUp()
12
+ self.service.work.current_picking_type = self.picking1.picking_type_id
13
+
14
+ def test_scan_source_and_set_destination_on_mixed_package(self):
15
+ package = self.picking5.package_level_ids[0].package_id
16
+ self.assertTrue(len(package.move_line_ids.product_id) > 1)
17
+ response = self.service.dispatch(
18
+ "scan_source",
19
+ params={"barcode": package.name},
20
+ )
21
+ self.assertTrue(
22
+ response["data"]["set_line_destination"]["handle_complete_mix_pack"]
23
+ )
24
+ move_lines = self.service._find_location_move_lines(
25
+ package=package,
26
+ )
27
+ move_lines = move_lines.sorted(lambda l: l.move_id.priority, reverse=True)
28
+ move_line = move_lines[0]
29
+ self.assert_response_set_line_destination(
30
+ response,
31
+ zone_location=self.zone_location,
32
+ picking_type=self.picking_type,
33
+ move_line=move_line,
34
+ qty_done=0,
35
+ handle_complete_mix_pack=True,
36
+ )
37
+ # Lets move this pack somwehere...
38
+ move_line.location_dest_id = self.shelf1
39
+ quantity_done = move_line.reserved_uom_qty
40
+ response = self.service.dispatch(
41
+ "set_destination",
42
+ params={
43
+ "move_line_id": move_line.id,
44
+ "barcode": self.packing_location.barcode,
45
+ "quantity": quantity_done,
46
+ "confirmation": self.packing_location.barcode,
47
+ "handle_complete_mix_pack": True,
48
+ },
49
+ )
50
+ # Check response
51
+ move_lines = self.service._find_location_move_lines()
52
+ move_lines = move_lines.sorted(lambda l: l.move_id.priority, reverse=True)
53
+ self.assert_response_select_line(
54
+ response,
55
+ zone_location=self.zone_location,
56
+ picking_type=self.picking_type,
57
+ move_lines=move_lines,
58
+ message=self.service.msg_store.confirm_pack_moved(),
59
+ )
@@ -73,6 +73,9 @@ class ZonePickingSelectLineCase(ZonePickingCommonCase):
73
73
 
74
74
  def test_list_move_lines_order_by_location(self):
75
75
  self.service.work.current_lines_order = "location"
76
+ last_move_line = self.picking1.move_line_ids[-1]
77
+ last_move_line_location = last_move_line.location_id
78
+ last_move_line_location.sudo().name = "z"
76
79
  response = self.service.dispatch("list_move_lines", params={})
77
80
  move_lines = self.service._find_location_move_lines()
78
81
  res = [
@@ -80,6 +83,7 @@ class ZonePickingSelectLineCase(ZonePickingCommonCase):
80
83
  for x in response["data"]["select_line"]["move_lines"]
81
84
  ]
82
85
  self.assertEqual(res, [x.location_id.name for x in move_lines])
86
+ self.assertEqual(res[-1], last_move_line_location.name)
83
87
  self.maxDiff = None
84
88
  self.assert_response_select_line(
85
89
  response,
@@ -260,7 +264,11 @@ class ZonePickingSelectLineCase(ZonePickingCommonCase):
260
264
  def test_scan_source_package_many_products(self):
261
265
  """Scan source: scanned package that several product, aborting
262
266
  next step 'select_line expected.
267
+
268
+ This is only when no prefill quantity option is enabled. If not
269
+ the related package will be move in one step.
263
270
  """
271
+ self.menu.sudo().no_prefill_qty = True
264
272
  pack = self.picking1.package_level_ids[0].package_id
265
273
  self._update_qty_in_location(pack.location_id, self.product_b, 2, pack)
266
274
  response = self.service.dispatch(
@@ -281,6 +289,28 @@ class ZonePickingSelectLineCase(ZonePickingCommonCase):
281
289
  location_first=False,
282
290
  )
283
291
 
292
+ def test_scan_source_empty_package(self):
293
+ """Scan source: scanned an empty package."""
294
+ pack_empty = self.env["stock.quant.package"].create({})
295
+ response = self.service.dispatch(
296
+ "scan_source",
297
+ params={"barcode": pack_empty.name},
298
+ )
299
+ move_lines = self.service._find_location_move_lines(
300
+ locations=self.zone_location
301
+ )
302
+ move_lines = move_lines.sorted(lambda l: l.move_id.priority, reverse=True)
303
+ self.assert_response_select_line(
304
+ response,
305
+ zone_location=self.zone_location,
306
+ picking_type=self.picking_type,
307
+ move_lines=move_lines,
308
+ message=self.service.msg_store.package_has_no_product_to_take(
309
+ pack_empty.name
310
+ ),
311
+ location_first=False,
312
+ )
313
+
284
314
  def test_scan_source_barcode_package_can_replace_in_line(self):
285
315
  """Scan source: scanned package has no related line but can replace
286
316
  next step 'select_line' expected with confirmation required set.
@@ -311,13 +341,13 @@ class ZonePickingSelectLineCase(ZonePickingCommonCase):
311
341
  picking_type=self.picking_type,
312
342
  move_lines=move_lines,
313
343
  message=self.service.msg_store.package_different_change(),
314
- confirmation_required=True,
344
+ confirmation_required=package1b.name,
315
345
  )
316
346
  self.assertEqual(self.picking1.package_level_ids[0].package_id, package1)
317
347
  # 2nd scan
318
348
  response = self.service.dispatch(
319
349
  "scan_source",
320
- params={"barcode": package1b.name, "confirmation": True},
350
+ params={"barcode": package1b.name, "confirmation": package1b.name},
321
351
  )
322
352
  self.assert_response_set_line_destination(
323
353
  response,
@@ -327,6 +357,7 @@ class ZonePickingSelectLineCase(ZonePickingCommonCase):
327
357
  message=self.service.msg_store.package_replaced_by_package(
328
358
  package1, package1b
329
359
  ),
360
+ qty_done=self.service._get_prefill_qty(move_lines[0]),
330
361
  )
331
362
  # Check the package has been changed on the move line
332
363
  self.assertEqual(self.picking1.package_level_ids[0].package_id, package1b)
@@ -136,14 +136,19 @@ class ZonePickingSelectLineFirstScanLocationCase(ZonePickingCommonCase):
136
136
 
137
137
  def test_scan_source_scan_package_first_with_two_product(self):
138
138
  """Scan a package with two product and then scan a product."""
139
- pickingA = self._create_picking(
140
- lines=[(self.product_a, 13), (self.product_b, 5)]
141
- )
139
+ pickingA = self._create_picking(lines=[(self.product_a, 13)])
142
140
  self._fill_stock_for_moves(
143
141
  pickingA.move_ids, in_package=True, location=self.zone_sublocation1
144
142
  )
145
143
  pickingA.action_assign()
146
144
  package = pickingA.package_level_ids[0].package_id
145
+
146
+ pickingB = self._create_picking(lines=[(self.product_b, 5)])
147
+ self._fill_stock_for_moves(
148
+ pickingB.move_ids, in_package=package, location=self.zone_sublocation1
149
+ )
150
+ # If all products in package are reserved, it will be handle as a full package
151
+ # pickingB.action_assign()
147
152
  response = self.service.dispatch(
148
153
  "scan_source",
149
154
  params={
@@ -34,8 +34,13 @@ class ZonePickingSelectLineCase(ZonePickingCommonCase):
34
34
  )
35
35
 
36
36
  def test_scan_source_barcode_package_no_prefill(self):
37
- """When a package is scanned, qty_done in response is False."""
37
+ """When a package is scanned.
38
+
39
+ The user is required to scan a product.
40
+ Then redirected to the next screen, qty_done in response is False.
41
+ """
38
42
  package = self.picking1.package_level_ids[0].package_id
43
+ # Scan package with one product
39
44
  response = self.service.dispatch(
40
45
  "scan_source",
41
46
  params={"barcode": package.name},
@@ -45,12 +50,24 @@ class ZonePickingSelectLineCase(ZonePickingCommonCase):
45
50
  )
46
51
  move_lines = move_lines.sorted(lambda l: l.move_id.priority, reverse=True)
47
52
  move_line = move_lines[0]
53
+ self.assert_response_select_line(
54
+ response,
55
+ self.zone_location,
56
+ self.picking1.picking_type_id,
57
+ move_lines,
58
+ package=package,
59
+ )
60
+ # Scan the product
61
+ response = self.service.dispatch(
62
+ "scan_source",
63
+ params={"barcode": move_line.product_id.barcode},
64
+ )
48
65
  self.assert_response_set_line_destination(
49
66
  response,
50
67
  zone_location=self.zone_location,
51
68
  picking_type=self.picking_type,
52
69
  move_line=move_line,
53
- qty_done=False,
70
+ qty_done=1.0,
54
71
  )
55
72
 
56
73
  def test_scan_source_barcode_product_no_prefill(self):
@@ -24,7 +24,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
24
24
  "move_line_id": 1234567890,
25
25
  "barcode": self.packing_location.barcode,
26
26
  "quantity": move_line.reserved_uom_qty,
27
- "confirmation": False,
27
+ "confirmation": None,
28
28
  },
29
29
  )
30
30
  self.assert_response_start(
@@ -48,7 +48,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
48
48
  "move_line_id": move_line.id,
49
49
  "barcode": self.packing_location.barcode,
50
50
  "quantity": quantity_done,
51
- "confirmation": False,
51
+ "confirmation": None,
52
52
  },
53
53
  )
54
54
  # Check response
@@ -60,7 +60,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
60
60
  message=self.service.msg_store.confirm_location_changed(
61
61
  move_line.location_dest_id, self.packing_location
62
62
  ),
63
- confirmation_required=True,
63
+ confirmation_required=self.packing_location.barcode,
64
64
  qty_done=quantity_done,
65
65
  )
66
66
  # Confirm the destination with a wrong destination (should not happen)
@@ -70,7 +70,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
70
70
  "move_line_id": move_line.id,
71
71
  "barcode": self.customer_location.barcode,
72
72
  "quantity": move_line.reserved_uom_qty,
73
- "confirmation": True,
73
+ "confirmation": self.packing_location.barcode,
74
74
  },
75
75
  )
76
76
  # Check response
@@ -89,7 +89,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
89
89
  "move_line_id": move_line.id,
90
90
  "barcode": self.packing_location.barcode,
91
91
  "quantity": move_line.reserved_uom_qty,
92
- "confirmation": True,
92
+ "confirmation": self.packing_location.barcode,
93
93
  },
94
94
  )
95
95
  # Check response
@@ -118,7 +118,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
118
118
  "move_line_id": move_line.id,
119
119
  "barcode": self.packing_sublocation_b.barcode,
120
120
  "quantity": quantity_done,
121
- "confirmation": True,
121
+ "confirmation": self.packing_sublocation_b.barcode,
122
122
  },
123
123
  )
124
124
  # Check response
@@ -158,7 +158,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
158
158
  "move_line_id": move_line.id,
159
159
  "barcode": self.packing_location.barcode,
160
160
  "quantity": move_line.reserved_uom_qty,
161
- "confirmation": False,
161
+ "confirmation": None,
162
162
  },
163
163
  )
164
164
  self.assertEqual(move_line.state, "done")
@@ -207,7 +207,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
207
207
  "move_line_id": move_line.id,
208
208
  "barcode": barcode,
209
209
  "quantity": 6,
210
- "confirmation": False,
210
+ "confirmation": None,
211
211
  },
212
212
  )
213
213
  self.assert_response_set_line_destination(
@@ -253,7 +253,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
253
253
  "move_line_id": move_line.id,
254
254
  "barcode": self.packing_location.barcode,
255
255
  "quantity": move_line.reserved_uom_qty, # 6 qty
256
- "confirmation": False,
256
+ "confirmation": None,
257
257
  },
258
258
  )
259
259
  self.assertEqual(move_line.state, "done")
@@ -315,7 +315,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
315
315
  "move_line_id": move_line.id,
316
316
  "barcode": barcode,
317
317
  "quantity": 4, # 4/6 qty
318
- "confirmation": False,
318
+ "confirmation": None,
319
319
  },
320
320
  )
321
321
  self.assert_response_set_line_destination(
@@ -346,7 +346,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
346
346
  "move_line_id": move_line.id,
347
347
  "barcode": self.packing_location.barcode,
348
348
  "quantity": move_line.reserved_uom_qty,
349
- "confirmation": False,
349
+ "confirmation": None,
350
350
  },
351
351
  )
352
352
  self.assertTrue(location_is_empty())
@@ -380,7 +380,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
380
380
  "move_line_id": move_line.id,
381
381
  "barcode": self.free_package.name,
382
382
  "quantity": move_line.reserved_uom_qty,
383
- "confirmation": False,
383
+ "confirmation": None,
384
384
  },
385
385
  )
386
386
  # Check picking data
@@ -434,7 +434,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
434
434
  "move_line_id": move_line.id,
435
435
  "barcode": self.free_package.name,
436
436
  "quantity": 6,
437
- "confirmation": False,
437
+ "confirmation": None,
438
438
  },
439
439
  )
440
440
  # Check picking data
@@ -496,7 +496,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
496
496
  "move_line_id": move_line.id,
497
497
  "barcode": self.free_package.name,
498
498
  "quantity": move_line.reserved_uom_qty,
499
- "confirmation": False,
499
+ "confirmation": None,
500
500
  },
501
501
  )
502
502
  self.assertTrue(location_is_empty())
@@ -523,7 +523,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
523
523
  "move_line_id": move_line.id,
524
524
  "barcode": self.free_package.name,
525
525
  "quantity": move_line.reserved_uom_qty,
526
- "confirmation": False,
526
+ "confirmation": None,
527
527
  },
528
528
  )
529
529
  self.assertTrue(location_is_empty())
@@ -545,7 +545,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
545
545
  "move_line_id": move_line.id,
546
546
  "barcode": self.free_package.name,
547
547
  "quantity": move_line.reserved_uom_qty,
548
- "confirmation": False,
548
+ "confirmation": None,
549
549
  },
550
550
  )
551
551
  self.assertEqual(
@@ -568,7 +568,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
568
568
  "move_line_id": move_line.id,
569
569
  "barcode": self.free_package.name,
570
570
  "quantity": move_line.reserved_uom_qty,
571
- "confirmation": False,
571
+ "confirmation": None,
572
572
  },
573
573
  )
574
574
  # We now have no error in the response
@@ -582,6 +582,41 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
582
582
  message=self.service.msg_store.confirm_pack_moved(),
583
583
  )
584
584
 
585
+ def test_set_same_destination_package_different_picking_type(self):
586
+ self.menu.sudo().write({"multiple_move_single_pack": True})
587
+ picking_type1 = self.picking1.picking_type_id
588
+ self._update_qty_in_location(
589
+ picking_type1.default_location_src_id, self.product_a, 100
590
+ )
591
+ picking_type = picking_type1.sudo().copy(
592
+ {"name": "test", "shopfloor_menu_ids": False}
593
+ )
594
+ picking = self._create_picking(
595
+ picking_type=picking_type, lines=[(self.product_a, 10)]
596
+ )
597
+ self.assertEqual(picking.picking_type_id, picking_type)
598
+ picking.action_assign()
599
+ move_line = picking.move_line_ids
600
+ move_line.result_package_id = self.free_package.id
601
+ self.assertEqual(self.free_package.planned_move_line_ids, move_line)
602
+ response = self.service.dispatch(
603
+ "set_destination",
604
+ params={
605
+ "move_line_id": move_line.id,
606
+ "barcode": self.free_package.name,
607
+ "quantity": move_line.reserved_uom_qty,
608
+ "confirmation": None,
609
+ },
610
+ )
611
+ self.assertEqual(
612
+ response["message"],
613
+ {
614
+ "body": "Package FREE_PACKAGE contains already lines"
615
+ " from a different operation type test.",
616
+ "message_type": "warning",
617
+ },
618
+ )
619
+
585
620
  def test_set_destination_location_zero_quantity(self):
586
621
  """Scanned barcode is the destination location.
587
622
 
@@ -609,7 +644,7 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
609
644
  qty_done=move_line.reserved_uom_qty,
610
645
  )
611
646
 
612
- def test_set_destination_error_concurent_work(self):
647
+ def test_set_destination_package_error_concurent_work(self):
613
648
  """Scanned barcode is the destination package.
614
649
 
615
650
  Move line is already being worked on by someone else
@@ -626,7 +661,41 @@ class ZonePickingSetLineDestinationCase(ZonePickingCommonCase):
626
661
  "move_line_id": move_line.id,
627
662
  "barcode": self.free_package.name,
628
663
  "quantity": move_line.reserved_uom_qty,
629
- "confirmation": False,
664
+ "confirmation": None,
665
+ },
666
+ )
667
+ # Check response
668
+ self.assert_response_set_line_destination(
669
+ response,
670
+ zone_location,
671
+ picking_type,
672
+ move_line,
673
+ message={
674
+ "message_type": "error",
675
+ "body": "Someone is already working on these transfers",
676
+ },
677
+ qty_done=move_line.reserved_uom_qty,
678
+ )
679
+
680
+ def test_set_destination_location_error_concurent_work(self):
681
+ """Scanned barcode is the destination location.
682
+
683
+ Move line is already being worked on by someone else
684
+ """
685
+ zone_location = self.zone_location
686
+ picking_type = self.picking1.picking_type_id
687
+ picking_type.sudo().shopfloor_zero_check = True
688
+ self.assertEqual(len(self.picking1.move_line_ids), 1)
689
+ move_line = self.picking1.move_line_ids
690
+ move_line.picking_id.user_id = self.shopfloor_manager
691
+ response = self.service.dispatch(
692
+ "set_destination",
693
+ params={
694
+ "move_line_id": move_line.id,
695
+ "package_id": self.free_package.id,
696
+ "barcode": self.packing_location.barcode,
697
+ "quantity": move_line.reserved_uom_qty,
698
+ "confirmation": None,
630
699
  },
631
700
  )
632
701
  # Check response