odoo-addon-shopfloor 16.0.2.12.0.1__py3-none-any.whl → 18.0.0.1.0.15__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 (105) hide show
  1. odoo/addons/shopfloor/README.rst +79 -52
  2. odoo/addons/shopfloor/__manifest__.py +11 -4
  3. odoo/addons/shopfloor/actions/__init__.py +0 -1
  4. odoo/addons/shopfloor/actions/change_package_lot.py +4 -6
  5. odoo/addons/shopfloor/actions/data.py +7 -6
  6. odoo/addons/shopfloor/actions/inventory.py +1 -1
  7. odoo/addons/shopfloor/actions/message.py +1 -1
  8. odoo/addons/shopfloor/actions/move_line_search.py +1 -1
  9. odoo/addons/shopfloor/actions/search.py +8 -32
  10. odoo/addons/shopfloor/actions/stock.py +7 -6
  11. odoo/addons/shopfloor/i18n/ca.po +0 -5
  12. odoo/addons/shopfloor/i18n/de.po +0 -5
  13. odoo/addons/shopfloor/i18n/es_AR.po +0 -5
  14. odoo/addons/shopfloor/i18n/it.po +2 -8
  15. odoo/addons/shopfloor/i18n/pt_BR.po +0 -5
  16. odoo/addons/shopfloor/i18n/shopfloor.pot +7 -194
  17. odoo/addons/shopfloor/models/stock_location.py +5 -5
  18. odoo/addons/shopfloor/models/stock_move.py +24 -7
  19. odoo/addons/shopfloor/models/stock_move_line.py +29 -82
  20. odoo/addons/shopfloor/models/stock_picking.py +8 -6
  21. odoo/addons/shopfloor/models/stock_quant_package.py +2 -2
  22. odoo/addons/shopfloor/readme/CONTRIBUTORS.md +17 -0
  23. odoo/addons/shopfloor/readme/CREDITS.md +5 -0
  24. odoo/addons/shopfloor/readme/DESCRIPTION.md +37 -0
  25. odoo/addons/shopfloor/readme/{HISTORY.rst → HISTORY.md} +1 -2
  26. odoo/addons/shopfloor/readme/ROADMAP.md +10 -0
  27. odoo/addons/shopfloor/readme/USAGE.md +6 -0
  28. odoo/addons/shopfloor/services/checkout.py +9 -9
  29. odoo/addons/shopfloor/services/cluster_picking.py +2 -2
  30. odoo/addons/shopfloor/services/delivery.py +4 -6
  31. odoo/addons/shopfloor/services/forms/picking_form.py +4 -1
  32. odoo/addons/shopfloor/services/location_content_transfer.py +1 -1
  33. odoo/addons/shopfloor/services/single_pack_transfer.py +1 -1
  34. odoo/addons/shopfloor/services/zone_picking.py +5 -9
  35. odoo/addons/shopfloor/static/description/index.html +41 -18
  36. odoo/addons/shopfloor/tests/__init__.py +74 -73
  37. odoo/addons/shopfloor/tests/common.py +9 -9
  38. odoo/addons/shopfloor/tests/test_actions_change_package_lot.py +104 -71
  39. odoo/addons/shopfloor/tests/test_actions_data.py +17 -21
  40. odoo/addons/shopfloor/tests/test_actions_data_base.py +9 -3
  41. odoo/addons/shopfloor/tests/test_actions_data_detail.py +17 -19
  42. odoo/addons/shopfloor/tests/test_actions_search.py +2 -1
  43. odoo/addons/shopfloor/tests/test_actions_stock.py +0 -1
  44. odoo/addons/shopfloor/tests/test_checkout_auto_post.py +3 -3
  45. odoo/addons/shopfloor/tests/test_checkout_base.py +1 -1
  46. odoo/addons/shopfloor/tests/test_checkout_list_delivery_packaging.py +1 -1
  47. odoo/addons/shopfloor/tests/test_checkout_list_package.py +4 -4
  48. odoo/addons/shopfloor/tests/test_checkout_new_package.py +3 -3
  49. odoo/addons/shopfloor/tests/test_checkout_no_package.py +3 -3
  50. odoo/addons/shopfloor/tests/test_checkout_scan_dest_location.py +1 -1
  51. odoo/addons/shopfloor/tests/test_checkout_scan_package_action.py +11 -11
  52. odoo/addons/shopfloor/tests/test_checkout_select_package_base.py +1 -1
  53. odoo/addons/shopfloor/tests/test_checkout_set_qty.py +17 -17
  54. odoo/addons/shopfloor/tests/test_checkout_summary.py +2 -2
  55. odoo/addons/shopfloor/tests/test_cluster_picking_base.py +1 -1
  56. odoo/addons/shopfloor/tests/test_cluster_picking_batch.py +2 -2
  57. odoo/addons/shopfloor/tests/test_cluster_picking_change_pack_lot.py +1 -1
  58. odoo/addons/shopfloor/tests/test_cluster_picking_is_zero.py +1 -1
  59. odoo/addons/shopfloor/tests/test_cluster_picking_scan_destination.py +17 -19
  60. odoo/addons/shopfloor/tests/test_cluster_picking_scan_line_no_prefill_qty.py +1 -1
  61. odoo/addons/shopfloor/tests/test_cluster_picking_stock_issue.py +5 -5
  62. odoo/addons/shopfloor/tests/test_delivery_base.py +4 -6
  63. odoo/addons/shopfloor/tests/test_delivery_done.py +1 -1
  64. odoo/addons/shopfloor/tests/test_delivery_reset_qty_done_line.py +1 -1
  65. odoo/addons/shopfloor/tests/test_delivery_reset_qty_done_pack.py +1 -1
  66. odoo/addons/shopfloor/tests/test_delivery_scan_deliver.py +6 -6
  67. odoo/addons/shopfloor/tests/test_location_content_transfer_base.py +2 -2
  68. odoo/addons/shopfloor/tests/test_location_content_transfer_mix.py +8 -8
  69. odoo/addons/shopfloor/tests/test_location_content_transfer_set_destination_package_or_line.py +41 -41
  70. odoo/addons/shopfloor/tests/test_location_content_transfer_single.py +3 -3
  71. odoo/addons/shopfloor/tests/test_menu_base.py +4 -4
  72. odoo/addons/shopfloor/tests/test_move_action_assign.py +19 -4
  73. odoo/addons/shopfloor/tests/test_single_pack_transfer.py +3 -3
  74. odoo/addons/shopfloor/tests/test_stock_split.py +77 -17
  75. odoo/addons/shopfloor/tests/test_zone_picking_base.py +5 -5
  76. odoo/addons/shopfloor/tests/test_zone_picking_change_pack_lot.py +2 -2
  77. odoo/addons/shopfloor/tests/test_zone_picking_complete_mix_pack_flux.py +2 -2
  78. odoo/addons/shopfloor/tests/test_zone_picking_require_destination_package.py +3 -3
  79. odoo/addons/shopfloor/tests/test_zone_picking_select_line.py +4 -4
  80. odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination.py +29 -29
  81. odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_package_not_allowed.py +2 -2
  82. odoo/addons/shopfloor/tests/test_zone_picking_set_line_destination_pick_pack.py +12 -12
  83. odoo/addons/shopfloor/tests/test_zone_picking_start.py +1 -1
  84. odoo/addons/shopfloor/tests/test_zone_picking_unload_all.py +12 -12
  85. odoo/addons/shopfloor/tests/test_zone_picking_unload_buffer_lines.py +4 -4
  86. odoo/addons/shopfloor/tests/test_zone_picking_unload_set_destination.py +10 -10
  87. odoo/addons/shopfloor/tests/test_zone_picking_unload_single.py +3 -3
  88. odoo/addons/shopfloor/views/shopfloor_menu.xml +33 -102
  89. odoo/addons/shopfloor/views/stock_move_line.xml +2 -2
  90. odoo/addons/shopfloor/views/stock_picking_type.xml +1 -1
  91. odoo_addon_shopfloor-18.0.0.1.0.15.dist-info/METADATA +222 -0
  92. {odoo_addon_shopfloor-16.0.2.12.0.1.dist-info → odoo_addon_shopfloor-18.0.0.1.0.15.dist-info}/RECORD +94 -98
  93. {odoo_addon_shopfloor-16.0.2.12.0.1.dist-info → odoo_addon_shopfloor-18.0.0.1.0.15.dist-info}/WHEEL +1 -1
  94. odoo_addon_shopfloor-18.0.0.1.0.15.dist-info/top_level.txt +1 -0
  95. odoo/addons/shopfloor/actions/barcode_parser.py +0 -44
  96. odoo/addons/shopfloor/migrations/16.0.2.0.0/post-migration.py +0 -41
  97. odoo/addons/shopfloor/migrations/16.0.2.4.2/post-init_search_move_line_options.py +0 -33
  98. odoo/addons/shopfloor/migrations/16.0.2.4.2/post-migration.py +0 -29
  99. odoo/addons/shopfloor/readme/CONTRIBUTORS.rst +0 -18
  100. odoo/addons/shopfloor/readme/CREDITS.rst +0 -5
  101. odoo/addons/shopfloor/readme/DESCRIPTION.rst +0 -17
  102. odoo/addons/shopfloor/readme/ROADMAP.rst +0 -4
  103. odoo/addons/shopfloor/readme/USAGE.rst +0 -6
  104. odoo_addon_shopfloor-16.0.2.12.0.1.dist-info/METADATA +0 -193
  105. odoo_addon_shopfloor-16.0.2.12.0.1.dist-info/top_level.txt +0 -1
@@ -26,7 +26,7 @@ class StockLocation(models.Model):
26
26
  return self.env["stock.move.line"].search(
27
27
  [
28
28
  ("location_id", "child_of", self.id),
29
- ("reserved_uom_qty", ">", 0),
29
+ ("quantity", ">", 0),
30
30
  ("state", "not in", ("done", "cancel")),
31
31
  ]
32
32
  )
@@ -40,7 +40,7 @@ class StockLocation(models.Model):
40
40
 
41
41
  Used for the "zero check". We need to know if a location is empty, but since
42
42
  we set the move lines to "done" only at the end of the unload workflow, we
43
- have to look at the qty_done of the move lines from this location.
43
+ have to look at the picked quantity of the move lines from this location.
44
44
 
45
45
  With `move_lines` we can force the use of the given move lines for the check.
46
46
  This allows to know that the location will be empty if we process only
@@ -51,18 +51,18 @@ class StockLocation(models.Model):
51
51
  [("quantity", ">", 0), ("location_id", "=", self.id)]
52
52
  )
53
53
  remaining = sum(quants.mapped("quantity"))
54
- move_line_qty_field = "qty_done"
54
+ move_line_qty_field = "qty_picked"
55
55
  if move_lines:
56
56
  move_lines = move_lines.filtered(
57
57
  lambda m: m.state not in ("cancel", "done")
58
58
  )
59
- move_line_qty_field = "reserved_uom_qty"
59
+ move_line_qty_field = "quantity"
60
60
  else:
61
61
  move_lines = self.env["stock.move.line"].search(
62
62
  [
63
63
  ("state", "not in", ("cancel", "done")),
64
64
  ("location_id", "=", self.id),
65
- ("qty_done", ">", 0),
65
+ ("picked", "=", True),
66
66
  ]
67
67
  )
68
68
  planned = remaining - sum(move_lines.mapped(move_line_qty_field))
@@ -1,16 +1,26 @@
1
1
  # Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
2
2
  # Copyright 2022 Jacques-Etienne Baudoux (BCIM) <je@bcim.be>
3
3
  # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4
- from odoo import _, models
4
+ from odoo import api, fields, models
5
5
  from odoo.tools.float_utils import float_compare
6
6
 
7
7
 
8
8
  class StockMove(models.Model):
9
9
  _inherit = "stock.move"
10
10
 
11
+ quantity_picked = fields.Float(compute="_compute_quantity_picked")
12
+
13
+ @api.depends("move_line_ids.picked", "move_line_ids.qty_picked")
14
+ def _compute_quantity_picked(self):
15
+ for move in self:
16
+ move.quantity_picked = sum(
17
+ ml.qty_picked for ml in move.move_line_ids if ml.picked
18
+ )
19
+
11
20
  def _qty_is_satisfied(self):
12
21
  compare = float_compare(
13
- self.quantity_done,
22
+ # TODO: in theory we should use ``quantity`` + ``picked``
23
+ self.quantity_picked,
14
24
  self.product_uom_qty,
15
25
  precision_rounding=self.product_uom.rounding,
16
26
  )
@@ -32,11 +42,18 @@ class StockMove(models.Model):
32
42
  to_move = other_move_lines
33
43
  if other_move_lines or self.state == "partially_available":
34
44
  if intersection:
35
- qty_to_split = sum(to_move.mapped("reserved_uom_qty"))
45
+ qty_to_split = sum(to_move.mapped("quantity"))
36
46
  else:
37
- qty_to_split = self.product_uom_qty - sum(
38
- move_lines.mapped("reserved_uom_qty")
39
- )
47
+ qty_to_split = self.product_uom_qty - sum(move_lines.mapped("quantity"))
48
+ prec = self.env["decimal.precision"].precision_get(
49
+ "Product Unit of Measure"
50
+ )
51
+ # Do not split if we have full quantity to split
52
+ if (
53
+ float_compare(qty_to_split, self.product_uom_qty, precision_digits=prec)
54
+ == 0
55
+ ):
56
+ return self.browse()
40
57
  split_move_vals = self._split(qty_to_split)
41
58
  split_move = self.create(split_move_vals)
42
59
  split_move.move_line_ids = to_move
@@ -80,7 +97,7 @@ class StockMove(models.Model):
80
97
  new_picking.id,
81
98
  new_picking.name,
82
99
  )
83
- message = (_("The split order {} has been created.")).format(link)
100
+ message = (self.env._("The split order {} has been created.")).format(link)
84
101
  picking.message_post(body=message)
85
102
  self.picking_id = new_picking.id
86
103
  self.package_level_id.picking_id = new_picking.id
@@ -29,6 +29,8 @@ class StockMoveLine(models.Model):
29
29
  # allow domain on picking_id.xxx without too much perf penalty
30
30
  picking_id = fields.Many2one(auto_join=True)
31
31
 
32
+ is_shopfloor_created = fields.Boolean()
33
+
32
34
  def _split_partial_quantity(self):
33
35
  """Create new move line for the quantity remaining to do
34
36
 
@@ -36,23 +38,23 @@ class StockMoveLine(models.Model):
36
38
  """
37
39
  self.ensure_one()
38
40
  rounding = self.product_uom_id.rounding
39
- if float_is_zero(self.qty_done, precision_rounding=rounding):
41
+ if float_is_zero(self.qty_picked, precision_rounding=rounding):
40
42
  return self.browse()
41
43
  compare = float_compare(
42
- self.qty_done, self.reserved_uom_qty, precision_rounding=rounding
44
+ self.qty_picked, self.quantity, precision_rounding=rounding
43
45
  )
44
46
  qty_lesser = compare == -1
45
47
  qty_greater = compare == 1
46
48
  assert not qty_greater, "Quantity done cannot exceed quantity to do"
47
49
  if qty_lesser:
48
- remaining = self.reserved_uom_qty - self.qty_done
49
- new_line = self.copy({"reserved_uom_qty": remaining, "qty_done": 0})
50
+ remaining = self.quantity - self.qty_picked
51
+ new_line = self.copy(
52
+ {"quantity": remaining, "qty_picked": 0, "picked": False}
53
+ )
50
54
  # if we didn't bypass reservation update, the quant reservation
51
55
  # would be reduced as much as the deduced quantity, which is wrong
52
56
  # as we only moved the quantity to a new move line
53
- self.with_context(
54
- bypass_reservation_update=True
55
- ).reserved_uom_qty = self.qty_done
57
+ self.with_context(bypass_reservation_update=True).quantity = self.qty_picked
56
58
  return new_line
57
59
  return self.browse()
58
60
 
@@ -95,58 +97,6 @@ class StockMoveLine(models.Model):
95
97
  default=default, backorder=True
96
98
  )
97
99
 
98
- def _split_pickings_from_source_location(self):
99
- """Ensure that the related pickings will have the same source location.
100
-
101
- Some pickings related could have other unrelated move lines, as such we
102
- have to split them to contain only the move lines related to the expected
103
- source location.
104
-
105
- Example:
106
-
107
- Initial data:
108
-
109
- PICK1:
110
- - move line with source location LOC1
111
- - move line with source location LOC2
112
- PICK2:
113
- - move line with source location LOC2
114
- - move line with source location LOC3
115
-
116
- Then we process move lines related to LOC2 with this method, we get:
117
-
118
- PICK1:
119
- - move line with source location LOC1
120
- PICK2:
121
- - move line with source location LOC3
122
- PICK3:
123
- - move line with source location LOC2
124
- - move line with source location LOC2
125
-
126
- Return the pickings containing the given move lines.
127
- """
128
- _logger.warning(
129
- "`_split_pickings_from_source_location` is deprecated "
130
- "and replaced by `_extract_in_split_order`"
131
- )
132
- location_src_to_process = self.location_id
133
- if location_src_to_process and len(location_src_to_process) != 1:
134
- raise UserError(
135
- _("Move lines processed have to share the same source location.")
136
- )
137
- pickings = self.picking_id
138
- move_lines_to_process_ids = []
139
- for picking in pickings:
140
- location_src = picking.move_line_ids.location_id
141
- if len(location_src) == 1:
142
- continue
143
- (picking.move_line_ids & self)._extract_in_split_order()
144
- # Get the related move lines among the picking and split them
145
- move_lines_to_process_ids.extend(
146
- set(picking.move_line_ids.ids) & set(self.ids)
147
- )
148
- return self.picking_id
149
-
150
100
  def _split_qty_to_be_done(self, qty_done, split_partial=True, **split_default_vals):
151
101
  """Check qty to be done for current move line. Split it if needed.
152
102
 
@@ -154,14 +104,12 @@ class StockMoveLine(models.Model):
154
104
  :param split_partial: split if qty is less than expected
155
105
  otherwise rely on a backorder.
156
106
  """
157
- if self.reserved_uom_qty < 0:
107
+ if self.quantity < 0:
158
108
  raise UserError(_("The demand cannot be negative"))
159
109
  # store a new line if we have split our line (not enough qty)
160
110
  new_line = self.env["stock.move.line"]
161
111
  rounding = self.product_uom_id.rounding
162
- compare = float_compare(
163
- qty_done, self.reserved_uom_qty, precision_rounding=rounding
164
- )
112
+ compare = float_compare(qty_done, self.quantity, precision_rounding=rounding)
165
113
  qty_lesser = compare == -1
166
114
  qty_greater = compare == 1
167
115
  if qty_greater:
@@ -180,16 +128,14 @@ class StockMoveLine(models.Model):
180
128
  # split the move line which will be processed later (maybe the user
181
129
  # has to pick some goods from another place because the location
182
130
  # contained less items than expected)
183
- remaining = self.reserved_uom_qty - quantity_done
184
- vals = {"reserved_uom_qty": remaining, "qty_done": 0}
131
+ remaining = self.quantity - quantity_done
132
+ vals = {"quantity": remaining, "picked": False, "qty_picked": 0}
185
133
  vals.update(split_default_vals)
186
134
  new_line = self.copy(vals)
187
135
  # if we didn't bypass reservation update, the quant reservation
188
136
  # would be reduced as much as the deduced quantity, which is wrong
189
137
  # as we only moved the quantity to a new move line
190
- self.with_context(
191
- bypass_reservation_update=True
192
- ).reserved_uom_qty = quantity_done
138
+ self.with_context(bypass_reservation_update=True).quantity = quantity_done
193
139
  return new_line
194
140
 
195
141
  def replace_package(self, new_package):
@@ -205,9 +151,7 @@ class StockMoveLine(models.Model):
205
151
  )
206
152
 
207
153
  # we can't change already picked lines
208
- unreservable_lines = other_reserved_lines.filtered(
209
- lambda line: line.qty_done == 0
210
- )
154
+ unreservable_lines = other_reserved_lines.filtered(lambda line: not line.picked)
211
155
  to_assign_moves = unreservable_lines.move_id
212
156
 
213
157
  # if we leave the package level, it will try to reserve the same
@@ -266,26 +210,29 @@ class StockMoveLine(models.Model):
266
210
  "lot_id": quant.lot_id.id,
267
211
  "owner_id": quant.owner_id.id,
268
212
  "result_package_id": False,
213
+ # Always set the 'quantity' value in 'values', this ensure quants are
214
+ # synchronized with the data set on the move line starting from Odoo
215
+ # 18.0 (see '<stock.move.line.write()' method in 'stock' module).
216
+ "quantity": self.quantity,
269
217
  }
270
218
 
271
219
  available_quantity = quant.quantity - quant.reserved_quantity
272
220
  if is_lesser(
273
- available_quantity, self.reserved_qty, quant.product_uom_id.rounding
221
+ available_quantity, self.quantity_product_uom, quant.product_uom_id.rounding
274
222
  ):
275
223
  new_uom_qty = self.product_id.uom_id._compute_quantity(
276
224
  available_quantity, self.product_uom_id, rounding_method="HALF-UP"
277
225
  )
278
- values["reserved_uom_qty"] = new_uom_qty
226
+ values["quantity"] = new_uom_qty
279
227
 
280
228
  self.write(values)
281
229
 
282
- # try reassign the move in case we had a partial qty, also, it will
283
- # recreate a package level if it applies
284
- if "reserved_uom_qty" in values:
285
- # when we change the quantity of the move, the state
286
- # will still be "assigned" and be skipped by "_action_assign",
287
- # recompute the state to be "partially_available"
288
- self.move_id._recompute_state()
230
+ # Try reassign the move in case we had a partial qty, also, it will
231
+ # recreate a package level if it applies.
232
+ # When we change the quantity of the move, the state
233
+ # will still be "assigned" and be skipped by "_action_assign",
234
+ # recompute the state to be "partially_available"
235
+ self.move_id._recompute_state()
289
236
 
290
237
  # if the new package has less quantities, assign will create new move
291
238
  # lines
@@ -312,9 +259,9 @@ class StockMoveLine(models.Model):
312
259
  def shopfloor_postpone(self, *recordsets):
313
260
  """
314
261
  Specific behavior for move lines.
315
- As we need to reset qty_done.
262
+ As we need to reset the quantity picked.
316
263
 
317
264
  """
318
265
  res = super().shopfloor_postpone(*recordsets)
319
- self.qty_done = 0.0
266
+ self.picked = False
320
267
  return res
@@ -26,7 +26,9 @@ class StockPicking(models.Model):
26
26
  is_shopfloor_created = fields.Boolean()
27
27
 
28
28
  @api.depends(
29
- "move_line_ids", "move_line_ids.reserved_qty", "move_line_ids.product_id.weight"
29
+ "move_line_ids",
30
+ "move_line_ids.quantity_product_uom",
31
+ "move_line_ids.product_id.weight",
30
32
  )
31
33
  def _compute_picking_info(self):
32
34
  for item in self:
@@ -47,7 +49,7 @@ class StockPicking(models.Model):
47
49
  def _calc_weight(self):
48
50
  weight = 0.0
49
51
  for move_line in self.mapped("move_line_ids"):
50
- weight += move_line.reserved_qty * move_line.product_id.weight
52
+ weight += move_line.quantity_product_uom * move_line.product_id.weight
51
53
  return weight
52
54
 
53
55
  def _check_move_lines_map_quant_package(self, package):
@@ -55,9 +57,9 @@ class StockPicking(models.Model):
55
57
  pack_move_lines = self.move_line_ids.filtered(
56
58
  lambda ml: ml.package_id == package
57
59
  )
58
- # if we set a qty_done on any line, it's picked, we don't want
60
+ # if we flag a line as picked, we don't want
59
61
  # to change it in any case, so we ignore the package level
60
- if any(pack_move_lines.mapped("qty_done")):
62
+ if any(pack_move_lines.mapped("picked")):
61
63
  return False
62
64
  # if we already changed the destination package, do not create
63
65
  # a new package level
@@ -119,13 +121,13 @@ class StockPicking(models.Model):
119
121
  assigned_moves._action_assign()
120
122
  return new_picking.id
121
123
 
122
- def _put_in_pack(self, move_line_ids, create_package_level=True):
124
+ def _put_in_pack(self, move_line_ids):
123
125
  """
124
126
  Marks the corresponding move lines as 'shopfloor_checkout_done'
125
127
  when the package is created in the backend.
126
128
 
127
129
  """
128
- new_package = super()._put_in_pack(move_line_ids, create_package_level)
130
+ new_package = super()._put_in_pack(move_line_ids)
129
131
  lines = move_line_ids.filtered(lambda p: p.result_package_id == new_package)
130
132
  lines.write({"shopfloor_checkout_done": True})
131
133
  return new_package
@@ -41,11 +41,11 @@ class StockQuantPackage(models.Model):
41
41
  for rec in self:
42
42
  rec.update({"reserved_move_line_ids": rec._get_reserved_move_lines()})
43
43
 
44
- @api.depends("pack_weight", "estimated_pack_weight_kg")
44
+ @api.depends("pack_weight", "weight")
45
45
  @api.depends_context("picking_id")
46
46
  def _compute_shopfloor_weight(self):
47
47
  for rec in self:
48
- rec.shopfloor_weight = rec.pack_weight or rec.estimated_pack_weight_kg
48
+ rec.shopfloor_weight = rec.pack_weight or rec.weight
49
49
 
50
50
  # TODO: we should refactor this like
51
51
 
@@ -0,0 +1,17 @@
1
+ - Guewen Baconnier \<<guewen.baconnier@camptocamp.com>\>
2
+ - Simone Orsi \<<simahawk@gmail.com>\>
3
+ - Sébastien Alix \<<sebastien.alix@camptocamp.com>\>
4
+ - Alexandre Fayolle \<<alexandre.fayolle@camptocamp.com>\>
5
+ - Benoit Guillot \<<benoit.guillot@akretion.com>\>
6
+ - Thierry Ducrest \<<thierry.ducrest@camptocamp.com>\>
7
+ - Raphaël Reverdy \<<raphael.reverdy@akretion.com>\>
8
+ - Jacques-Etienne Baudoux \<<je@bcim.be>\>
9
+ - Juan Miguel Sánchez Arce \<<juan.sanchez@camptocamp.com>\>
10
+ - Michael Tietz (MT Software) \<<mtietz@mt-software.de>\>
11
+ - Souheil Bejaoui \<<souheil.bejaoui@acsone.eu>\>
12
+ - Laurent Mignon \<<laurent.mignon@acsone.eu>\>
13
+
14
+ ## Design
15
+
16
+ - Joël Grand-Guillaume \<<joel.grandguillaume@camptocamp.com>\>
17
+ - Jacques-Etienne Baudoux \<<je@bcim.be>\>
@@ -0,0 +1,5 @@
1
+ **Financial support**
2
+
3
+ - Cosanum
4
+ - Camptocamp R&D
5
+ - Akretion R&D
@@ -0,0 +1,37 @@
1
+ Shopfloor is a barcode scanner application for internal warehouse
2
+ operations.
3
+
4
+ The application supports scenarios, to relate to Operation Types:
5
+
6
+ - Cluster Picking
7
+ - Zone Picking
8
+ - Checkout/Packing
9
+ - Delivery
10
+ - Location Content Transfer
11
+ - Single Pack Transfer
12
+
13
+ This module provides REST APIs to support the scenarios. It needs a
14
+ frontend to consume the backend APIs and provide screens for users on
15
+ barcode devices. A default front-end application is provided by
16
+ `shopfloor_mobile`.
17
+
18
+ Note: if you want to enable a new scenario on an existing application,
19
+ you must trigger the registry sync on the shopfloor.app in a
20
+ post_init_hook or a post-migrate script.
21
+ See an example
22
+ [here](https://github.com/OCA/wms/pull/520/commits/bccdfd445a9bc943998c4848f183a076e8459a98).
23
+
24
+
25
+ **WARNING v18**
26
+
27
+ Scenario will be migrated one by one.
28
+
29
+ Current availability status:
30
+
31
+ - [ ] checkout
32
+ - [ ] cluster picking
33
+ - [ ] zone picking
34
+ - [ ] delivery
35
+ - [ ] location content transfer
36
+ - [ ] single pack transfer (to be discarded in favor of shopfloor_single_product_transfer)
37
+ - [ ] zone picking
@@ -1,4 +1,3 @@
1
- 13.0.1.0.0
2
- ~~~~~~~~~~
1
+ ## 13.0.1.0.0
3
2
 
4
3
  First official version.
@@ -0,0 +1,10 @@
1
+ - improve documentation
2
+ - split out scenario components to their own modules
3
+ - maybe split common stock features to shopfloor_stock_base and move
4
+ scenario to shopfloor_wms?
5
+
6
+
7
+ **WARNING v18**
8
+
9
+ We don't want to split now the scenario to keep it as much as possible in line w/ v16.
10
+ We'll do it later.
@@ -0,0 +1,6 @@
1
+ An API key is created in the Demo data (for development), using the Demo
2
+ user. The key to use in the HTTP header `API-KEY` is: 72B044F7AC780DAC
3
+
4
+ Curl example:
5
+
6
+ curl -X POST "http://localhost:8069/shopfloor/user/menu" -H "accept: */*" -H "Content-Type: application/json" -H "API-KEY: 72B044F7AC780DAC"
@@ -303,7 +303,7 @@ class Checkout(Component):
303
303
  # The picking should have a move line for the product
304
304
  # where qty >= packaging.qty, since it doesn't makes sense
305
305
  # to select a move line which have less qty than the packaging
306
- line_domain = [("reserved_uom_qty", ">=", packaging.qty)]
306
+ line_domain = [("quantity", ">=", packaging.qty)]
307
307
  return self._select_document_from_product(product, line_domain=line_domain)
308
308
 
309
309
  def _select_document_from_none(self, *args, barcode=None, **kwargs):
@@ -428,7 +428,7 @@ class Checkout(Component):
428
428
  # For prefill quantity we only want to increment one line
429
429
  line.qty_done += prefill_qty
430
430
  elif not self.work.menu.no_prefill_qty:
431
- line.qty_done = line.reserved_uom_qty
431
+ line.qty_done = line.quantity
432
432
  line.shopfloor_user_id = self.env.user
433
433
 
434
434
  picking = lines.mapped("picking_id")
@@ -845,7 +845,7 @@ class Checkout(Component):
845
845
  move_line.qty_done = qty_done
846
846
  if new_line:
847
847
  selected_line_ids.append(new_line.id)
848
- if qty_done > move_line.reserved_uom_qty:
848
+ if qty_done > move_line.quantity:
849
849
  return self._response_for_select_package(
850
850
  picking,
851
851
  self.env["stock.move.line"].browse(selected_line_ids).exists(),
@@ -884,7 +884,7 @@ class Checkout(Component):
884
884
  as selected
885
885
  """
886
886
  return self._change_line_qty(
887
- picking_id, selected_line_ids, [move_line_id], lambda x: x.reserved_uom_qty
887
+ picking_id, selected_line_ids, [move_line_id], lambda x: x.quantity
888
888
  )
889
889
 
890
890
  def set_custom_qty(self, picking_id, selected_line_ids, move_line_id, qty_done):
@@ -917,7 +917,7 @@ class Checkout(Component):
917
917
  picking.id,
918
918
  selected_lines.ids,
919
919
  switch_lines.ids,
920
- lambda x: x.reserved_uom_qty,
920
+ lambda x: x.quantity,
921
921
  )
922
922
 
923
923
  def _increment_custom_qty(
@@ -983,7 +983,7 @@ class Checkout(Component):
983
983
 
984
984
  def _put_lines_in_allowed_package(self, picking, lines_to_pack, package):
985
985
  for line in lines_to_pack:
986
- if line.qty_done < line.reserved_uom_qty:
986
+ if line.qty_done < line.quantity:
987
987
  line._split_partial_quantity_to_be_done(line.qty_done, {})
988
988
  lines_to_pack.write(
989
989
  {"result_package_id": package.id, "shopfloor_checkout_done": True}
@@ -1104,7 +1104,7 @@ class Checkout(Component):
1104
1104
  If none are found, return the first line for that product.
1105
1105
  """
1106
1106
  return next(
1107
- (line for line in product_lines if line.qty_done < line.reserved_uom_qty),
1107
+ (line for line in product_lines if line.qty_done < line.quantity),
1108
1108
  fields.first(product_lines),
1109
1109
  )
1110
1110
 
@@ -1308,7 +1308,7 @@ class Checkout(Component):
1308
1308
  # Do not allow to proceed if the qty_done of
1309
1309
  # any of the selected lines
1310
1310
  # is higher than the quantity to do.
1311
- if line.qty_done > line.reserved_uom_qty:
1311
+ if line.qty_done > line.quantity:
1312
1312
  return self._response_for_select_package(
1313
1313
  picking,
1314
1314
  lines,
@@ -1519,7 +1519,7 @@ class Checkout(Component):
1519
1519
  return self._response_for_select_document(message=message)
1520
1520
  lines = picking.move_line_ids
1521
1521
  if not confirmation:
1522
- if not all(line.qty_done == line.reserved_uom_qty for line in lines):
1522
+ if not all(line.qty_done == line.quantity for line in lines):
1523
1523
  return self._response_for_summary(
1524
1524
  picking,
1525
1525
  need_confirm=True,
@@ -508,7 +508,7 @@ class ClusterPicking(Component):
508
508
  """Returns the quantity to increment depending on no_prefill_qty optione."""
509
509
  if self.work.menu.no_prefill_qty:
510
510
  return qty
511
- return move_line.reserved_uom_qty
511
+ return move_line.quantity
512
512
 
513
513
  def _check_first_scan_location_or_pack_first(
514
514
  self, move_line, sublocation=None, location_scanned=False
@@ -762,7 +762,7 @@ class ClusterPicking(Component):
762
762
  if qty_check == "greater":
763
763
  return self._response_for_scan_destination(
764
764
  move_line,
765
- message=self.msg_store.unable_to_pick_more(move_line.reserved_uom_qty),
765
+ message=self.msg_store.unable_to_pick_more(move_line.quantity),
766
766
  qty_done=quantity,
767
767
  )
768
768
 
@@ -221,7 +221,7 @@ class Delivery(Component):
221
221
  for line in lines:
222
222
  # note: the package level is automatically set to "is_done" when
223
223
  # the qty_done is full
224
- line.qty_done = line.reserved_uom_qty
224
+ line.qty_done = line.quantity
225
225
  picking = fields.first(lines.mapped("picking_id"))
226
226
  return self._action_picking_done(picking, force=allow_prepackaged_product)
227
227
 
@@ -288,7 +288,7 @@ class Delivery(Component):
288
288
  if product_qty:
289
289
  domain.extend(
290
290
  [
291
- ("reserved_qty", ">=", product_qty),
291
+ ("quantity_product_uom", ">=", product_qty),
292
292
  ]
293
293
  )
294
294
  if picking:
@@ -317,7 +317,7 @@ class Delivery(Component):
317
317
  if product_qty:
318
318
  domain.extend(
319
319
  [
320
- ("reserved_qty", ">=", product_qty),
320
+ ("quantity_product_uom", ">=", product_qty),
321
321
  ]
322
322
  )
323
323
  if picking:
@@ -420,9 +420,7 @@ class Delivery(Component):
420
420
  message=self.msg_store.product_not_unitary_in_package_scan_package(),
421
421
  )
422
422
  # We focus only on lines on which we can increase the 'qty_done'
423
- lines = lines.filtered(
424
- lambda x: (x.qty_done + product_qty) <= x.reserved_uom_qty
425
- )
423
+ lines = lines.filtered(lambda x: (x.qty_done + product_qty) <= x.quantity)
426
424
  # Filter lines to keep only ones from one delivery operation
427
425
  # (we do not want to process lines of another delivery operation)
428
426
  lines = lines._filter_on_picking(picking)
@@ -34,7 +34,10 @@ class ShopfloorPickingForm(Component):
34
34
  company_carriers = self.env["delivery.carrier"].search(
35
35
  ["|", ("company_id", "=", False), ("company_id", "=", record.company_id.id)]
36
36
  )
37
- available_carriers = company_carriers.available_carriers(record.partner_id)
37
+ # TODO: this imply a dependency on sale_stock
38
+ available_carriers = company_carriers.available_carriers(
39
+ record.partner_id, record.sale_id
40
+ )
38
41
  return available_carriers
39
42
 
40
43
 
@@ -770,7 +770,7 @@ class LocationContentTransfer(Component):
770
770
  backorders = stock.validate_moves(move_line.move_id)
771
771
  if backorders:
772
772
  for move_line in backorders.mapped("move_line_ids"):
773
- move_line.qty_done = move_line.reserved_uom_qty
773
+ move_line.qty_done = move_line.quantity
774
774
  backorders.user_id = self.env.user
775
775
  # process first backorder of current line
776
776
  move_lines = backorders.move_line_ids
@@ -31,7 +31,7 @@ class SinglePackTransfer(Component):
31
31
  "name": package.name,
32
32
  "weight_uom": package.weight_uom_id.name,
33
33
  "weight": package.pack_weight,
34
- "estimated_weight_kg": package.estimated_pack_weight_kg,
34
+ "estimated_weight_kg": package.shopfloor_weight,
35
35
  "location_src": self.data.location(package.location_id),
36
36
  "location_dest": self.data.location(package_level.location_dest_id),
37
37
  "products": self.data.products(move_lines.product_id),