odoo-addon-stock-barcodes 15.0.3.1.6__py3-none-any.whl → 16.0.1.0.0.19__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/stock_barcodes/README.rst +6 -6
- odoo/addons/stock_barcodes/__manifest__.py +8 -7
- odoo/addons/stock_barcodes/data/stock_barcodes_option.xml +1 -2
- odoo/addons/stock_barcodes/hooks.py +15 -13
- odoo/addons/stock_barcodes/i18n/es.po +305 -189
- odoo/addons/stock_barcodes/i18n/it.po +282 -180
- odoo/addons/stock_barcodes/i18n/stock_barcodes.pot +190 -160
- odoo/addons/stock_barcodes/models/__init__.py +1 -1
- odoo/addons/stock_barcodes/models/stock_barcodes_action.py +2 -1
- odoo/addons/stock_barcodes/models/stock_barcodes_option.py +2 -4
- odoo/addons/stock_barcodes/models/stock_move.py +37 -0
- odoo/addons/stock_barcodes/models/stock_move_line.py +8 -14
- odoo/addons/stock_barcodes/models/stock_picking.py +9 -36
- odoo/addons/stock_barcodes/models/stock_picking_type.py +5 -6
- odoo/addons/stock_barcodes/models/stock_quant.py +3 -4
- odoo/addons/stock_barcodes/security/ir.model.access.csv +0 -2
- odoo/addons/stock_barcodes/static/description/index.html +9 -11
- odoo/addons/stock_barcodes/static/src/css/stock.scss +41 -5
- odoo/addons/stock_barcodes/static/src/utils/barcode_handler_field.esm.js +36 -0
- odoo/addons/stock_barcodes/static/src/utils/barcodes_models_utils.esm.js +25 -0
- odoo/addons/stock_barcodes/static/src/views/form_view.esm.js +17 -0
- odoo/addons/stock_barcodes/static/src/views/kanban_renderer.esm.js +149 -0
- odoo/addons/stock_barcodes/static/src/views/view_compiler.esm.js +16 -0
- odoo/addons/stock_barcodes/static/src/views/views.esm.js +193 -0
- odoo/addons/stock_barcodes/static/src/widgets/boolean_toggle.esm.js +26 -0
- odoo/addons/stock_barcodes/static/src/widgets/numeric_step.esm.js +40 -0
- odoo/addons/stock_barcodes/static/src/widgets/numeric_step.xml +17 -0
- odoo/addons/stock_barcodes/static/src/widgets/view_button.esm.js +8 -0
- odoo/addons/stock_barcodes/static/src/widgets/view_button.xml +14 -0
- odoo/addons/stock_barcodes/tests/common.py +167 -0
- odoo/addons/stock_barcodes/tests/test_stock_barcodes.py +4 -172
- odoo/addons/stock_barcodes/tests/test_stock_barcodes_new_lot.py +2 -2
- odoo/addons/stock_barcodes/tests/test_stock_barcodes_picking.py +8 -8
- odoo/addons/stock_barcodes/views/stock_barcodes_option_view.xml +1 -1
- odoo/addons/stock_barcodes/views/stock_picking_views.xml +4 -3
- odoo/addons/stock_barcodes/wizard/stock_barcodes_read.py +45 -91
- odoo/addons/stock_barcodes/wizard/stock_barcodes_read_inventory.py +1 -4
- odoo/addons/stock_barcodes/wizard/stock_barcodes_read_inventory_views.xml +14 -15
- odoo/addons/stock_barcodes/wizard/stock_barcodes_read_picking.py +256 -92
- odoo/addons/stock_barcodes/wizard/stock_barcodes_read_picking_views.xml +59 -37
- odoo/addons/stock_barcodes/wizard/stock_barcodes_read_todo.py +33 -107
- odoo/addons/stock_barcodes/wizard/stock_barcodes_read_todo_view.xml +70 -28
- odoo/addons/stock_barcodes/wizard/stock_barcodes_read_views.xml +172 -189
- odoo/addons/stock_barcodes/wizard/stock_production_lot.py +2 -2
- odoo/addons/stock_barcodes/wizard/stock_production_lot_views.xml +6 -8
- {odoo_addon_stock_barcodes-15.0.3.1.6.dist-info → odoo_addon_stock_barcodes-16.0.1.0.0.19.dist-info}/METADATA +11 -11
- odoo_addon_stock_barcodes-16.0.1.0.0.19.dist-info/RECORD +66 -0
- {odoo_addon_stock_barcodes-15.0.3.1.6.dist-info → odoo_addon_stock_barcodes-16.0.1.0.0.19.dist-info}/WHEEL +1 -1
- odoo/addons/stock_barcodes/migrations/15.0.1.0.0/pre-migration.py +0 -14
- odoo/addons/stock_barcodes/models/stock_barcodes_read_log.py +0 -51
- odoo/addons/stock_barcodes/static/src/css/stock.css +0 -5
- odoo/addons/stock_barcodes/static/src/js/barcodes_models_mixin.js +0 -34
- odoo/addons/stock_barcodes/static/src/js/basic_controller.js +0 -412
- odoo/addons/stock_barcodes/static/src/js/basic_fields.js +0 -59
- odoo/addons/stock_barcodes/static/src/js/form_view.js +0 -24
- odoo/addons/stock_barcodes/static/src/js/kanban_renderer.js +0 -47
- odoo/addons/stock_barcodes/static/src/js/numeric_step.js +0 -43
- odoo_addon_stock_barcodes-15.0.3.1.6.dist-info/RECORD +0 -62
- {odoo_addon_stock_barcodes-15.0.3.1.6.dist-info → odoo_addon_stock_barcodes-16.0.1.0.0.19.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,13 @@
|
|
1
1
|
# Copyright 2019 Sergio Teruel <sergio.teruel@tecnativa.com>
|
2
2
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
3
3
|
import logging
|
4
|
+
from collections import OrderedDict, defaultdict
|
4
5
|
|
5
6
|
from odoo import _, api, fields, models
|
6
7
|
from odoo.exceptions import ValidationError
|
7
8
|
from odoo.fields import first
|
8
|
-
from odoo.tools.float_utils import float_compare
|
9
|
+
from odoo.tools.float_utils import float_compare, float_round
|
10
|
+
from odoo.tools.safe_eval import safe_eval
|
9
11
|
|
10
12
|
_logger = logging.getLogger(__name__)
|
11
13
|
|
@@ -74,22 +76,30 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
74
76
|
picking_location_id = fields.Many2one(related="picking_id.location_id")
|
75
77
|
picking_location_dest_id = fields.Many2one(related="picking_id.location_dest_id")
|
76
78
|
company_id = fields.Many2one(related="picking_id.company_id")
|
79
|
+
todo_line_is_extra_line = fields.Boolean(related="todo_line_id.is_extra_line")
|
80
|
+
forced_todo_key = fields.Char()
|
81
|
+
qty_available = fields.Float(compute="_compute_qty_available")
|
77
82
|
|
78
83
|
@api.depends("todo_line_id")
|
79
84
|
def _compute_todo_line_display_ids(self):
|
80
85
|
"""Technical field to display only the first record in kanban view"""
|
81
86
|
self.todo_line_display_ids = self.todo_line_id
|
82
87
|
|
83
|
-
@api.depends("todo_line_ids")
|
88
|
+
@api.depends("todo_line_ids", "picking_id.move_line_ids.qty_done")
|
84
89
|
def _compute_pending_move_ids(self):
|
85
90
|
if self.option_group_id.show_pending_moves:
|
86
91
|
self.pending_move_ids = self.todo_line_ids.filtered(
|
87
92
|
lambda t: t.state == "pending"
|
93
|
+
and any(
|
94
|
+
sm.barcode_backorder_action == "pending" for sm in t.stock_move_ids
|
95
|
+
)
|
88
96
|
)
|
89
97
|
else:
|
90
98
|
self.pending_move_ids = False
|
91
99
|
|
92
|
-
@api.depends(
|
100
|
+
@api.depends(
|
101
|
+
"todo_line_ids", "todo_line_ids.qty_done", "picking_id.move_line_ids.qty_done"
|
102
|
+
)
|
93
103
|
def _compute_move_line_ids(self):
|
94
104
|
self.move_line_ids = self.picking_id.move_line_ids.filtered("qty_done").sorted(
|
95
105
|
key=lambda sml: (sml.write_date, sml.create_date), reverse=True
|
@@ -100,7 +110,7 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
100
110
|
self.total_product_uom_qty = 0.0
|
101
111
|
self.total_product_qty_done = 0.0
|
102
112
|
for rec in self:
|
103
|
-
product_moves = rec.picking_id.
|
113
|
+
product_moves = rec.picking_id.move_ids.filtered(
|
104
114
|
lambda ln: ln.product_id.ids == self.product_id.ids
|
105
115
|
and ln.state != "cancel"
|
106
116
|
)
|
@@ -108,6 +118,40 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
108
118
|
rec.total_product_uom_qty += line.product_uom_qty
|
109
119
|
rec.total_product_qty_done += line.quantity_done
|
110
120
|
|
121
|
+
@api.depends("location_id", "product_id", "lot_id")
|
122
|
+
def _compute_qty_available(self):
|
123
|
+
if not self.product_id or self.location_id.usage != "internal":
|
124
|
+
self.qty_available = 0.0
|
125
|
+
return
|
126
|
+
domain_quant = [
|
127
|
+
("product_id", "=", self.product_id.id),
|
128
|
+
("location_id", "=", self.location_id.id),
|
129
|
+
]
|
130
|
+
if self.lot_id:
|
131
|
+
domain_quant.append(("lot_id", "=", self.lot_id.id))
|
132
|
+
# if self.package_id:
|
133
|
+
# domain_quant.append(('package_id', '=', self.package_id.id))
|
134
|
+
groups = self.env["stock.quant"].read_group(
|
135
|
+
domain_quant, ["quantity"], [], orderby="id"
|
136
|
+
)
|
137
|
+
self.qty_available = groups[0]["quantity"]
|
138
|
+
# Unexpected done quantities must reduce qty_available
|
139
|
+
if self.lot_id:
|
140
|
+
done_move_lines = self.move_line_ids.filtered(
|
141
|
+
lambda m: m.product_id == self.product_id and m.lot_id == self.lot_id
|
142
|
+
)
|
143
|
+
else:
|
144
|
+
done_move_lines = self.move_line_ids.filtered(
|
145
|
+
lambda m: m.product_id == self.product_id
|
146
|
+
)
|
147
|
+
for sml in done_move_lines:
|
148
|
+
over_done_qty = float_round(
|
149
|
+
sml.qty_done - sml.reserved_uom_qty,
|
150
|
+
precision_rounding=sml.product_uom_id.rounding,
|
151
|
+
)
|
152
|
+
if over_done_qty > 0.0:
|
153
|
+
self.qty_available -= over_done_qty
|
154
|
+
|
111
155
|
def name_get(self):
|
112
156
|
return [
|
113
157
|
(
|
@@ -126,14 +170,15 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
126
170
|
if picking_id:
|
127
171
|
self._set_candidate_pickings(self.env["stock.picking"].browse(picking_id))
|
128
172
|
|
129
|
-
@api.
|
130
|
-
def create(self,
|
173
|
+
@api.model_create_multi
|
174
|
+
def create(self, vals_list):
|
131
175
|
# When user click any view button the wizard record is create and the
|
132
176
|
# picking candidates have been lost, so we need set it.
|
133
|
-
|
134
|
-
|
135
|
-
wiz.
|
136
|
-
|
177
|
+
wizards = super().create(vals_list)
|
178
|
+
for wiz in wizards:
|
179
|
+
if wiz.picking_id:
|
180
|
+
wiz._set_candidate_pickings(wiz.picking_id)
|
181
|
+
return wizards
|
137
182
|
|
138
183
|
@api.onchange("picking_id")
|
139
184
|
def onchange_picking_id(self):
|
@@ -141,8 +186,8 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
141
186
|
# view, so for create a candidate picking with the same default picking
|
142
187
|
# we need create it in this onchange
|
143
188
|
self._set_default_picking()
|
144
|
-
self.determine_todo_action()
|
145
189
|
self.fill_pending_moves()
|
190
|
+
self.determine_todo_action()
|
146
191
|
|
147
192
|
def get_sorted_move_lines(self, move_lines):
|
148
193
|
location_field = self.option_group_id.location_field_to_sort
|
@@ -175,27 +220,26 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
175
220
|
def _get_stock_move_lines_todo(self):
|
176
221
|
move_lines = self.picking_id.move_line_ids.filtered(
|
177
222
|
lambda ml: (not ml.barcode_scan_state or ml.barcode_scan_state == "pending")
|
178
|
-
and ml.qty_done < ml.
|
223
|
+
and ml.qty_done < ml.reserved_qty
|
179
224
|
)
|
180
225
|
return move_lines
|
181
226
|
|
182
227
|
def fill_pending_moves(self):
|
183
|
-
|
184
|
-
|
185
|
-
and self.option_group_id.show_pending_moves
|
186
|
-
and not self.todo_line_ids
|
187
|
-
):
|
188
|
-
self.fill_todo_records()
|
228
|
+
# TODO: Unify method
|
229
|
+
self.fill_todo_records()
|
189
230
|
|
190
231
|
def get_moves_or_move_lines(self):
|
191
232
|
if self.option_group_id.source_pending_moves == "move_line_ids":
|
192
233
|
return self.picking_id.move_line_ids.filtered(lambda ln: ln.move_id)
|
193
234
|
else:
|
194
|
-
return self.picking_id.
|
235
|
+
return self.picking_id.move_ids
|
236
|
+
|
237
|
+
def get_moves(self):
|
238
|
+
return self.picking_id.move_ids
|
195
239
|
|
196
240
|
def fill_todo_records(self):
|
197
241
|
move_lines = self.get_sorted_move_lines(self.get_moves_or_move_lines())
|
198
|
-
self.
|
242
|
+
self.fill_records([move_lines])
|
199
243
|
|
200
244
|
@api.model
|
201
245
|
def _get_fields_filled_special(self):
|
@@ -211,12 +255,6 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
211
255
|
self.visible_force_done = self.env.context.get("visible_force_done", False)
|
212
256
|
if not self.option_group_id.barcode_guided_mode == "guided":
|
213
257
|
return False
|
214
|
-
if not self.todo_line_ids:
|
215
|
-
self.fill_todo_records()
|
216
|
-
# When scanning all information in one step (e.g. using GS-1), the
|
217
|
-
# status and qty processed might have not been update, we ensure it
|
218
|
-
# invalidating the cache.
|
219
|
-
self.todo_line_ids.invalidate_cache()
|
220
258
|
self.todo_line_id = (
|
221
259
|
forced_todo_line
|
222
260
|
or self.todo_line_ids.filtered(lambda t: t._origin.state == "pending")[:1]
|
@@ -264,11 +302,7 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
264
302
|
self.picking_product_qty = move_line.qty_done
|
265
303
|
|
266
304
|
def action_done(self):
|
267
|
-
|
268
|
-
res = super(
|
269
|
-
WizStockBarcodesReadPicking,
|
270
|
-
self.with_context(_stock_barcodes_skip_read_log=True),
|
271
|
-
).action_done()
|
305
|
+
res = super().action_done()
|
272
306
|
if res:
|
273
307
|
move_dic = self._process_stock_move_line()
|
274
308
|
if move_dic:
|
@@ -278,18 +312,34 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
278
312
|
if not self.keep_screen_values or self.todo_line_id.state != "pending":
|
279
313
|
if not self.env.context.get("skip_clean_values", False):
|
280
314
|
self.action_clean_values()
|
281
|
-
|
315
|
+
keep_vals = {}
|
282
316
|
else:
|
283
|
-
self.
|
284
|
-
|
285
|
-
|
286
|
-
|
317
|
+
keep_vals = self._convert_to_write(self._cache)
|
318
|
+
self.fill_todo_records()
|
319
|
+
if self.forced_todo_key:
|
320
|
+
self.todo_line_id = self.pending_move_ids.filtered(
|
321
|
+
lambda ln: str(self._group_key(ln)) == self.forced_todo_key
|
322
|
+
)[:1]
|
323
|
+
self.selected_pending_move_id = self.todo_line_id
|
324
|
+
self.determine_todo_action(self.todo_line_id)
|
325
|
+
else:
|
326
|
+
self.determine_todo_action()
|
327
|
+
self.action_show_step()
|
328
|
+
if keep_vals:
|
329
|
+
self.update_keep_values(keep_vals)
|
330
|
+
# Force refresh candidate pickings to show green if not pending moves
|
331
|
+
if not self.pending_move_ids:
|
332
|
+
self._set_candidate_pickings(self.picking_id)
|
287
333
|
return move_dic
|
288
|
-
# Add read log normally.
|
289
|
-
_logger.info("Add scanned log barcode:{}".format(self.barcode))
|
290
|
-
self._add_read_log()
|
291
334
|
return res
|
292
335
|
|
336
|
+
def update_keep_values(self, keep_vals):
|
337
|
+
options = self.option_group_id.option_ids
|
338
|
+
fields_to_keep = options.filtered(
|
339
|
+
lambda op: self._fields[op.field_name].type != "float"
|
340
|
+
).mapped("field_name")
|
341
|
+
self.update({f_name: keep_vals[f_name] for f_name in fields_to_keep})
|
342
|
+
|
293
343
|
def action_manual_entry(self):
|
294
344
|
result = super().action_manual_entry()
|
295
345
|
if result:
|
@@ -456,6 +506,10 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
456
506
|
domain = self._prepare_stock_moves_domain()
|
457
507
|
if self.option_group_id.barcode_guided_mode == "guided":
|
458
508
|
moves_todo = self.todo_line_id.stock_move_ids
|
509
|
+
elif self.picking_id:
|
510
|
+
moves_todo = self.picking_id.move_ids.filtered(
|
511
|
+
lambda sm: sm.product_id == self.product_id
|
512
|
+
)
|
459
513
|
else:
|
460
514
|
moves_todo = StockMove.search(domain)
|
461
515
|
if not getattr(
|
@@ -530,9 +584,9 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
530
584
|
return False
|
531
585
|
move_lines_dic = {}
|
532
586
|
for line in lines:
|
533
|
-
if line.
|
587
|
+
if line.reserved_uom_qty and len(lines) > 1:
|
534
588
|
assigned_qty = min(
|
535
|
-
max(line.
|
589
|
+
max(line.reserved_uom_qty - line.qty_done, 0.0), available_qty
|
536
590
|
)
|
537
591
|
else:
|
538
592
|
assigned_qty = available_qty
|
@@ -563,7 +617,7 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
563
617
|
elif line.result_package_id == line.package_id:
|
564
618
|
sml_vals.update({"result_package_id": False})
|
565
619
|
self._update_stock_move_line(line, sml_vals)
|
566
|
-
if line.qty_done >= line.
|
620
|
+
if line.qty_done >= line.reserved_uom_qty:
|
567
621
|
line.barcode_scan_state = "done"
|
568
622
|
elif self.env.context.get("done_forced"):
|
569
623
|
line.barcode_scan_state = "done_forced"
|
@@ -597,7 +651,7 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
597
651
|
move_to_link_in_todo_line = True
|
598
652
|
if not moves_to_link:
|
599
653
|
move_to_link_in_todo_line = False
|
600
|
-
moves_to_link = self.picking_id.
|
654
|
+
moves_to_link = self.picking_id.move_ids.filtered(
|
601
655
|
lambda mv: mv.product_id == self.product_id
|
602
656
|
)
|
603
657
|
stock_move_lines = self.create_new_stock_move_line(
|
@@ -615,13 +669,14 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
615
669
|
# link this new lines to the todo line details
|
616
670
|
# If user scan a product distinct of the todo line we need link to other
|
617
671
|
# alternative move
|
618
|
-
if
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
672
|
+
if self.option_group_id.source_pending_moves != "move_line_ids":
|
673
|
+
if move_to_link_in_todo_line and self.todo_line_id:
|
674
|
+
todo_line = self.todo_line_id
|
675
|
+
else:
|
676
|
+
todo_line = self.todo_line_ids.filtered(
|
677
|
+
lambda ln: ln.product_id == self.product_id
|
678
|
+
)
|
679
|
+
todo_line.line_ids = [(4, sml.id) for sml in stock_move_lines]
|
625
680
|
self.update_fields_after_process_stock(moves_todo)
|
626
681
|
return move_lines_dic
|
627
682
|
|
@@ -695,46 +750,6 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
695
750
|
return False
|
696
751
|
return res
|
697
752
|
|
698
|
-
def _prepare_scan_log_values(self, log_detail=False):
|
699
|
-
# Store in read log line each line added with the quantities assigned
|
700
|
-
vals = super()._prepare_scan_log_values(log_detail=log_detail)
|
701
|
-
vals["picking_id"] = self.picking_id.id
|
702
|
-
if log_detail:
|
703
|
-
vals["log_line_ids"] = [
|
704
|
-
(0, 0, {"move_line_id": x[0], "product_qty": x[1]})
|
705
|
-
for x in log_detail.items()
|
706
|
-
]
|
707
|
-
return vals
|
708
|
-
|
709
|
-
def remove_scanning_log(self, scanning_log):
|
710
|
-
for log in scanning_log:
|
711
|
-
for log_scan_line in log.log_line_ids:
|
712
|
-
sml = log_scan_line.move_line_id
|
713
|
-
if sml.state not in ["draft", "assigned", "confirmed"]:
|
714
|
-
raise ValidationError(
|
715
|
-
_(
|
716
|
-
"You cannot remove an entry linked to a operation "
|
717
|
-
"in state new, assigned or confirmed"
|
718
|
-
)
|
719
|
-
)
|
720
|
-
qty = sml.qty_done - log_scan_line.product_qty
|
721
|
-
log_scan_line.move_line_id.qty_done = max(qty, 0.0)
|
722
|
-
if sml.state == "draft" and sml.move_id.quantity_done == 0.0:
|
723
|
-
# This move has been created by the last scan, remove it.
|
724
|
-
sml.move_id.unlink()
|
725
|
-
self.picking_product_qty = sum(
|
726
|
-
log.log_line_ids.mapped("move_line_id.move_id.quantity_done")
|
727
|
-
)
|
728
|
-
log.unlink()
|
729
|
-
|
730
|
-
def action_undo_last_scan(self):
|
731
|
-
res = super().action_undo_last_scan()
|
732
|
-
log_scan = first(
|
733
|
-
self.scan_log_ids.filtered(lambda x: x.create_uid == self.env.user)
|
734
|
-
)
|
735
|
-
self.remove_scanning_log(log_scan)
|
736
|
-
return res
|
737
|
-
|
738
753
|
def get_lot_by_removal_strategy(self):
|
739
754
|
quants = first(
|
740
755
|
self.env["stock.quant"]._gather(self.product_id, self.location_id)
|
@@ -784,6 +799,155 @@ class WizStockBarcodesReadPicking(models.TransientModel):
|
|
784
799
|
return bool(self.location_dest_id)
|
785
800
|
return super()._option_required_hook(option_required)
|
786
801
|
|
802
|
+
def _group_key(self, line):
|
803
|
+
group_key_for_todo_records = self.option_group_id.group_key_for_todo_records
|
804
|
+
if group_key_for_todo_records:
|
805
|
+
return safe_eval(group_key_for_todo_records, globals_dict={"object": line})
|
806
|
+
if self.option_group_id.source_pending_moves == "move_line_ids":
|
807
|
+
return (
|
808
|
+
line.location_id.id,
|
809
|
+
line.product_id.id,
|
810
|
+
line.lot_id.id,
|
811
|
+
line.package_id.id,
|
812
|
+
)
|
813
|
+
else:
|
814
|
+
return (line.location_id.id, line.product_id.id)
|
815
|
+
|
816
|
+
def _get_all_products_quantities_in_package(self, package):
|
817
|
+
res = {}
|
818
|
+
# TODO: Check if domain is applied and we must recover _get_contained_quants
|
819
|
+
for quant in package.quant_ids:
|
820
|
+
if quant.product_id not in res:
|
821
|
+
res[quant.product_id] = 0
|
822
|
+
res[quant.product_id] += quant.quantity
|
823
|
+
return res
|
824
|
+
|
825
|
+
def _prepare_fill_record_values(self, line, position):
|
826
|
+
vals = {
|
827
|
+
"wiz_barcode_id": self.id,
|
828
|
+
"product_id": line.product_id.id,
|
829
|
+
"name": "To do action",
|
830
|
+
"position_index": position,
|
831
|
+
"picking_code": line.picking_code,
|
832
|
+
}
|
833
|
+
if line._name == "stock.move.line":
|
834
|
+
package_product_dic = self._get_all_products_quantities_in_package(
|
835
|
+
line.package_id
|
836
|
+
)
|
837
|
+
vals.update(
|
838
|
+
{
|
839
|
+
"location_id": line.location_id.id,
|
840
|
+
"location_dest_id": line.location_dest_id.id,
|
841
|
+
"lot_id": line.lot_id.id,
|
842
|
+
"package_id": line.package_id.id,
|
843
|
+
"result_package_id": line.result_package_id.id,
|
844
|
+
"uom_id": line.product_uom_id.id,
|
845
|
+
"product_uom_qty": line.reserved_uom_qty,
|
846
|
+
"product_qty_reserved": line.reserved_qty,
|
847
|
+
"line_ids": [(6, 0, line.ids)],
|
848
|
+
"stock_move_ids": [(6, 0, line.move_id.ids)],
|
849
|
+
"package_product_qty": package_product_dic
|
850
|
+
and package_product_dic[line.product_id]
|
851
|
+
or 0.0,
|
852
|
+
"is_stock_move_line_origin": True,
|
853
|
+
}
|
854
|
+
)
|
855
|
+
else:
|
856
|
+
vals.update(
|
857
|
+
{
|
858
|
+
"location_id": (line.move_line_ids[:1] or line).location_id.id,
|
859
|
+
"location_dest_id": (
|
860
|
+
line.move_line_ids[:1] or line
|
861
|
+
).location_dest_id.id,
|
862
|
+
"uom_id": line.product_uom.id,
|
863
|
+
"product_uom_qty": line.product_uom_qty,
|
864
|
+
"product_qty_reserved": line.move_line_ids
|
865
|
+
# TODO: Use reserved_qty or reserved_uom_qty
|
866
|
+
and sum(line.move_line_ids.mapped("reserved_qty"))
|
867
|
+
or line.product_uom_qty,
|
868
|
+
"line_ids": [(6, 0, line.move_line_ids.ids)],
|
869
|
+
"stock_move_ids": [(6, 0, line.ids)],
|
870
|
+
"is_stock_move_line_origin": False,
|
871
|
+
}
|
872
|
+
)
|
873
|
+
return vals
|
874
|
+
|
875
|
+
def _update_fill_record_values(self, line, vals):
|
876
|
+
if vals["is_stock_move_line_origin"]:
|
877
|
+
vals["product_uom_qty"] += line.reserved_uom_qty
|
878
|
+
vals["product_qty_reserved"] += line.reserved_qty
|
879
|
+
vals["line_ids"][0][2].append(line.id)
|
880
|
+
vals["stock_move_ids"][0][2].append(line.move_id.id)
|
881
|
+
else:
|
882
|
+
vals["product_uom_qty"] += line.product_uom_qty
|
883
|
+
vals["product_qty_reserved"] += (
|
884
|
+
line.move_line_ids
|
885
|
+
# TODO: Use reserved_qty or reserved_uom_qty
|
886
|
+
and sum(line.move_line_ids.mapped("reserved_qty"))
|
887
|
+
or line.product_uom_qty
|
888
|
+
)
|
889
|
+
vals["line_ids"][0][2].extend(line.move_line_ids.ids)
|
890
|
+
vals["stock_move_ids"][0][2].extend(line.ids)
|
891
|
+
return vals
|
892
|
+
|
893
|
+
@api.model
|
894
|
+
def fill_records(self, lines_list):
|
895
|
+
"""
|
896
|
+
:param lines_list: browse list
|
897
|
+
:return:
|
898
|
+
"""
|
899
|
+
self.forced_todo_key = str(
|
900
|
+
self._group_key(self.todo_line_id or self.selected_pending_move_id)
|
901
|
+
)
|
902
|
+
self.todo_line_ids.unlink()
|
903
|
+
self.todo_line_id = False
|
904
|
+
# self.position_index = 0
|
905
|
+
todo_vals = OrderedDict()
|
906
|
+
position = 0
|
907
|
+
move_qty_dic = defaultdict(float)
|
908
|
+
is_stock_move_line_origin = lines_list[0]._name == "stock.move.line"
|
909
|
+
for lines in lines_list:
|
910
|
+
for line in lines:
|
911
|
+
key = self._group_key(line)
|
912
|
+
if key not in todo_vals:
|
913
|
+
todo_vals[key] = self._prepare_fill_record_values(line, position)
|
914
|
+
position += 1
|
915
|
+
else:
|
916
|
+
todo_vals[key] = self._update_fill_record_values(
|
917
|
+
line, todo_vals[key]
|
918
|
+
)
|
919
|
+
if is_stock_move_line_origin:
|
920
|
+
move_qty_dic[line.move_id] += max(
|
921
|
+
line.reserved_uom_qty, line.qty_done
|
922
|
+
)
|
923
|
+
else:
|
924
|
+
move_qty_dic[line] += max(line.product_uom_qty, line.quantity_done)
|
925
|
+
for move in self.get_moves():
|
926
|
+
qty = move_qty_dic[move]
|
927
|
+
if (
|
928
|
+
move.barcode_backorder_action == "pending"
|
929
|
+
and move.product_uom_qty > qty
|
930
|
+
):
|
931
|
+
vals = self._prepare_fill_record_values(move, position)
|
932
|
+
vals.update(
|
933
|
+
{
|
934
|
+
"product_uom_qty": move.product_uom_qty - qty,
|
935
|
+
"product_qty_reserved": 0.0,
|
936
|
+
"line_ids": False,
|
937
|
+
"is_extra_line": True,
|
938
|
+
}
|
939
|
+
)
|
940
|
+
todo_vals[
|
941
|
+
(
|
942
|
+
move,
|
943
|
+
"M",
|
944
|
+
)
|
945
|
+
] = vals
|
946
|
+
position += 1
|
947
|
+
self.todo_line_ids = self.env["wiz.stock.barcodes.read.todo"].create(
|
948
|
+
list(todo_vals.values())
|
949
|
+
)
|
950
|
+
|
787
951
|
|
788
952
|
class WizCandidatePicking(models.TransientModel):
|
789
953
|
"""
|
@@ -850,9 +1014,9 @@ class WizCandidatePicking(models.TransientModel):
|
|
850
1014
|
qty_demand = 0
|
851
1015
|
qty_done = 0
|
852
1016
|
candidate.product_qty_reserved = sum(
|
853
|
-
candidate.picking_id.mapped("
|
1017
|
+
candidate.picking_id.mapped("move_ids.reserved_availability")
|
854
1018
|
)
|
855
|
-
for move in candidate.picking_id.
|
1019
|
+
for move in candidate.picking_id.move_ids:
|
856
1020
|
qty_reserved += move.reserved_availability
|
857
1021
|
qty_demand += move.product_uom_qty
|
858
1022
|
qty_done += move.quantity_done
|