odoo-addon-stock-move-location 16.0.1.4.1__py3-none-any.whl → 18.0.1.0.0.4__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_move_location/README.rst +8 -7
- odoo/addons/stock_move_location/__manifest__.py +1 -1
- odoo/addons/stock_move_location/i18n/sk.po +301 -0
- odoo/addons/stock_move_location/i18n/stock_move_location.pot +37 -10
- odoo/addons/stock_move_location/init_hook.py +1 -5
- odoo/addons/stock_move_location/models/stock_picking.py +9 -7
- odoo/addons/stock_move_location/readme/CONTRIBUTORS.md +2 -0
- odoo/addons/stock_move_location/readme/USAGE.md +0 -1
- odoo/addons/stock_move_location/static/description/index.html +6 -5
- odoo/addons/stock_move_location/tests/test_common.py +16 -13
- odoo/addons/stock_move_location/tests/test_move_location.py +19 -24
- odoo/addons/stock_move_location/tests/test_stock_fillwithstock.py +23 -28
- odoo/addons/stock_move_location/views/stock_picking.xml +1 -3
- odoo/addons/stock_move_location/views/stock_picking_type_views.xml +4 -7
- odoo/addons/stock_move_location/wizard/stock_move_location.py +46 -65
- odoo/addons/stock_move_location/wizard/stock_move_location.xml +60 -32
- odoo/addons/stock_move_location/wizard/stock_move_location_line.py +18 -30
- {odoo_addon_stock_move_location-16.0.1.4.1.dist-info → odoo_addon_stock_move_location-18.0.1.0.0.4.dist-info}/METADATA +14 -12
- {odoo_addon_stock_move_location-16.0.1.4.1.dist-info → odoo_addon_stock_move_location-18.0.1.0.0.4.dist-info}/RECORD +21 -20
- {odoo_addon_stock_move_location-16.0.1.4.1.dist-info → odoo_addon_stock_move_location-18.0.1.0.0.4.dist-info}/WHEEL +1 -1
- odoo_addon_stock_move_location-18.0.1.0.0.4.dist-info/top_level.txt +1 -0
- odoo_addon_stock_move_location-16.0.1.4.1.dist-info/top_level.txt +0 -1
@@ -1,17 +1,17 @@
|
|
1
1
|
# Copyright (C) 2011 Julius Network Solutions SARL <contact@julius.fr>
|
2
2
|
# Copyright 2018 Camptocamp SA
|
3
3
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
4
|
+
from odoo.tests import Form
|
4
5
|
|
5
|
-
from odoo.tests import
|
6
|
+
from odoo.addons.base.tests.common import BaseCommon
|
6
7
|
|
7
8
|
|
8
|
-
class TestsCommon(
|
9
|
+
class TestsCommon(BaseCommon):
|
9
10
|
@classmethod
|
10
11
|
def setUpClass(cls):
|
11
12
|
super().setUpClass()
|
12
|
-
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
13
13
|
cls.location_obj = cls.env["stock.location"]
|
14
|
-
product_obj = cls.env["product.product"]
|
14
|
+
cls.product_obj = cls.env["product.product"]
|
15
15
|
cls.wizard_obj = cls.env["wiz.stock.move.location"]
|
16
16
|
cls.quant_obj = cls.env["stock.quant"]
|
17
17
|
cls.company = cls.env.ref("base.main_company")
|
@@ -43,14 +43,14 @@ class TestsCommon(common.TransactionCase):
|
|
43
43
|
}
|
44
44
|
)
|
45
45
|
cls.uom_unit = cls.env.ref("uom.product_uom_unit")
|
46
|
-
cls.product_no_lots = product_obj.create(
|
47
|
-
{"name": "Pineapple", "
|
46
|
+
cls.product_no_lots = cls.product_obj.create(
|
47
|
+
{"name": "Pineapple", "is_storable": True, "tracking": "none"}
|
48
48
|
)
|
49
|
-
cls.product_lots = product_obj.create(
|
50
|
-
{"name": "Apple", "
|
49
|
+
cls.product_lots = cls.product_obj.create(
|
50
|
+
{"name": "Apple", "is_storable": True, "tracking": "lot"}
|
51
51
|
)
|
52
|
-
cls.product_package = product_obj.create(
|
53
|
-
{"name": "Orange", "
|
52
|
+
cls.product_package = cls.product_obj.create(
|
53
|
+
{"name": "Orange", "is_storable": True, "tracking": "lot"}
|
54
54
|
)
|
55
55
|
cls.lot1 = cls.env["stock.lot"].create(
|
56
56
|
{
|
@@ -73,8 +73,8 @@ class TestsCommon(common.TransactionCase):
|
|
73
73
|
"company_id": cls.company.id,
|
74
74
|
}
|
75
75
|
)
|
76
|
-
cls.product_package = product_obj.create(
|
77
|
-
{"name": "Orange", "
|
76
|
+
cls.product_package = cls.product_obj.create(
|
77
|
+
{"name": "Orange", "is_storable": True, "tracking": "lot"}
|
78
78
|
)
|
79
79
|
cls.lot4 = cls.env["stock.lot"].create(
|
80
80
|
{
|
@@ -157,12 +157,15 @@ class TestsCommon(common.TransactionCase):
|
|
157
157
|
amount,
|
158
158
|
)
|
159
159
|
|
160
|
-
def _create_wizard(
|
160
|
+
def _create_wizard(
|
161
|
+
self, origin_location, destination_location, exclude_reserved_qty=False
|
162
|
+
):
|
161
163
|
move_location_wizard = self.env["wiz.stock.move.location"]
|
162
164
|
return move_location_wizard.create(
|
163
165
|
{
|
164
166
|
"origin_location_id": origin_location.id,
|
165
167
|
"destination_location_id": destination_location.id,
|
168
|
+
"exclude_reserved_qty": exclude_reserved_qty,
|
166
169
|
}
|
167
170
|
)
|
168
171
|
|
@@ -84,20 +84,18 @@ class TestMoveLocation(TestsCommon):
|
|
84
84
|
wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2)
|
85
85
|
wizard.onchange_origin_location()
|
86
86
|
self.assertEqual(len(wizard.stock_move_location_line_ids), 7)
|
87
|
-
wizard._onchange_destination_location_id()
|
88
|
-
self.assertEqual(len(wizard.stock_move_location_line_ids), 7)
|
89
87
|
dest_location_line = wizard.stock_move_location_line_ids.mapped(
|
90
88
|
"destination_location_id"
|
91
89
|
)
|
92
90
|
self.assertEqual(dest_location_line, wizard.destination_location_id)
|
93
|
-
wizard.
|
91
|
+
wizard.clear_lines()
|
94
92
|
self.assertEqual(len(wizard.stock_move_location_line_ids), 0)
|
95
93
|
|
96
94
|
def test_wizard_onchange_origin_location(self):
|
97
95
|
"""Test a product that have existing quants with undefined quantity."""
|
98
96
|
|
99
97
|
product_not_available = self.env["product.product"].create(
|
100
|
-
{"name": "Mango", "
|
98
|
+
{"name": "Mango", "is_storable": True, "tracking": "none"}
|
101
99
|
)
|
102
100
|
self.quant_obj.create(
|
103
101
|
{
|
@@ -137,7 +135,7 @@ class TestMoveLocation(TestsCommon):
|
|
137
135
|
)
|
138
136
|
picking_lines = sorted(
|
139
137
|
[
|
140
|
-
(line.product_id.id, line.lot_id.id, line.
|
138
|
+
(line.product_id.id, line.lot_id.id, line.quantity)
|
141
139
|
for line in picking.move_line_ids
|
142
140
|
],
|
143
141
|
key=lambda x: (x[0], x[1]),
|
@@ -148,13 +146,13 @@ class TestMoveLocation(TestsCommon):
|
|
148
146
|
"Mismatch between move location lines and move lines",
|
149
147
|
)
|
150
148
|
self.assertEqual(
|
151
|
-
sorted(picking.move_line_ids.mapped("
|
149
|
+
sorted(picking.move_line_ids.mapped("quantity")),
|
152
150
|
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 123.0],
|
153
151
|
)
|
154
152
|
|
155
153
|
def test_planned_transfer_strict(self):
|
156
154
|
product = self.env["product.product"].create(
|
157
|
-
{"name": "Test", "
|
155
|
+
{"name": "Test", "is_storable": True, "tracking": "lot"}
|
158
156
|
)
|
159
157
|
lot = self.env["stock.lot"].create(
|
160
158
|
{
|
@@ -193,14 +191,14 @@ class TestMoveLocation(TestsCommon):
|
|
193
191
|
location_line.move_quantity,
|
194
192
|
]
|
195
193
|
line = picking.move_line_ids
|
196
|
-
picking_lines = [line.product_id.id, line.lot_id.id, line.
|
194
|
+
picking_lines = [line.product_id.id, line.lot_id.id, line.quantity]
|
197
195
|
self.assertEqual(
|
198
196
|
wizard_lines,
|
199
197
|
picking_lines,
|
200
198
|
"Mismatch between move location lines and move lines",
|
201
199
|
)
|
202
200
|
self.assertEqual(
|
203
|
-
picking.move_line_ids.
|
201
|
+
picking.move_line_ids.quantity,
|
204
202
|
10.0,
|
205
203
|
)
|
206
204
|
|
@@ -214,14 +212,10 @@ class TestMoveLocation(TestsCommon):
|
|
214
212
|
location_lines.unlink()
|
215
213
|
wizard.action_move_location()
|
216
214
|
picking = wizard.picking_id
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
)
|
221
|
-
self.assertEqual(
|
222
|
-
picking.move_line_ids.mapped("reserved_uom_qty"),
|
223
|
-
[0.0],
|
224
|
-
)
|
215
|
+
# Planned transfer state is "confirmed"
|
216
|
+
# move lines (quantity is zero) are removed
|
217
|
+
self.assertEqual(picking.state, "confirmed")
|
218
|
+
self.assertFalse(picking.move_line_ids)
|
225
219
|
|
226
220
|
def test_quant_transfer(self):
|
227
221
|
"""Test quants transfer."""
|
@@ -241,10 +235,8 @@ class TestMoveLocation(TestsCommon):
|
|
241
235
|
wizard.onchange_origin_location()
|
242
236
|
self.assertEqual(len(lines), 3)
|
243
237
|
wizard.destination_location_id = self.internal_loc_1
|
244
|
-
wizard._onchange_destination_location_id()
|
245
238
|
self.assertEqual(lines.mapped("destination_location_id"), self.internal_loc_1)
|
246
239
|
wizard.origin_location_id = self.internal_loc_2
|
247
|
-
wizard._onchange_destination_location_id()
|
248
240
|
self.assertEqual(len(lines), 3)
|
249
241
|
|
250
242
|
def test_readonly_location_computation(self):
|
@@ -276,7 +268,7 @@ class TestMoveLocation(TestsCommon):
|
|
276
268
|
lambda p: p.product_id == self.product_no_lots
|
277
269
|
)[0]
|
278
270
|
self.assertEqual(
|
279
|
-
putaway_line.destination_location_id,
|
271
|
+
putaway_line.destination_location_id, wizard.destination_location_id
|
280
272
|
)
|
281
273
|
picking_action = wizard.action_move_location()
|
282
274
|
picking = self.env["stock.picking"].browse(picking_action["res_id"])
|
@@ -302,6 +294,7 @@ class TestMoveLocation(TestsCommon):
|
|
302
294
|
|
303
295
|
# Create and assign a delivery picking to reserve some quantities
|
304
296
|
delivery_picking = self._create_picking(delivery_order_type)
|
297
|
+
# delivery_picking.location_id = wh_stock_shelf_1
|
305
298
|
delivery_move = self.env["stock.move"].create(
|
306
299
|
{
|
307
300
|
"name": "Delivery move",
|
@@ -315,12 +308,14 @@ class TestMoveLocation(TestsCommon):
|
|
315
308
|
)
|
316
309
|
delivery_picking.action_confirm()
|
317
310
|
self.assertEqual(delivery_picking.state, "assigned")
|
311
|
+
self.assertEqual(delivery_move.move_line_ids.location_id, wh_stock_shelf_1)
|
318
312
|
|
319
313
|
# Move all quantities to other location using module's wizard
|
320
314
|
wizard = self._create_wizard(wh_stock_shelf_1, wh_stock_shelf_2)
|
321
315
|
wizard.onchange_origin_location()
|
322
316
|
wizard.action_move_location()
|
323
|
-
self.assertEqual(delivery_picking.state, "
|
317
|
+
self.assertEqual(delivery_picking.state, "assigned")
|
318
|
+
self.assertEqual(delivery_move.move_line_ids.location_id, wh_stock_shelf_2)
|
324
319
|
|
325
320
|
# Do a planned transfer to move quantities to other location
|
326
321
|
# without using module's wizard
|
@@ -344,8 +339,8 @@ class TestMoveLocation(TestsCommon):
|
|
344
339
|
self.assertEqual(delivery_picking.state, "confirmed")
|
345
340
|
internal_picking.action_confirm()
|
346
341
|
internal_picking.action_assign()
|
347
|
-
internal_picking.move_line_ids.
|
348
|
-
internal_picking.move_line_ids.
|
342
|
+
internal_picking.move_line_ids.quantity = (
|
343
|
+
internal_picking.move_line_ids.quantity
|
349
344
|
)
|
350
345
|
internal_picking.button_validate()
|
351
346
|
self.assertEqual(internal_picking.state, "done")
|
@@ -354,5 +349,5 @@ class TestMoveLocation(TestsCommon):
|
|
354
349
|
self.assertEqual(delivery_picking.state, "assigned")
|
355
350
|
# The old reserved quantities must be in new location after confirm wizard
|
356
351
|
self.assertEqual(len(delivery_move.move_line_ids), 1)
|
357
|
-
self.assertEqual(delivery_move.move_line_ids.
|
352
|
+
self.assertEqual(delivery_move.move_line_ids.quantity, 20.0)
|
358
353
|
self.assertEqual(delivery_move.move_line_ids.location_id, wh_stock_shelf_3)
|
@@ -2,63 +2,58 @@
|
|
2
2
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
3
3
|
|
4
4
|
|
5
|
-
|
5
|
+
from odoo.addons.base.tests.common import BaseCommon
|
6
6
|
|
7
7
|
|
8
|
-
class TestFillwithStock(
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
context=dict(
|
13
|
-
self.env.context,
|
14
|
-
tracking_disable=True,
|
15
|
-
)
|
16
|
-
)
|
8
|
+
class TestFillwithStock(BaseCommon):
|
9
|
+
@classmethod
|
10
|
+
def setUpClass(cls):
|
11
|
+
super().setUpClass()
|
17
12
|
|
18
|
-
|
19
|
-
|
13
|
+
cls.stock_location = cls.env.ref("stock.stock_location_stock")
|
14
|
+
cls.pack_location = cls.env.ref("stock.location_pack_zone")
|
20
15
|
|
21
|
-
|
16
|
+
cls.shelf1_location = cls.env["stock.location"].create(
|
22
17
|
{
|
23
18
|
"name": "Test location",
|
24
19
|
"usage": "internal",
|
25
|
-
"location_id":
|
20
|
+
"location_id": cls.stock_location.id,
|
26
21
|
}
|
27
22
|
)
|
28
23
|
|
29
|
-
|
24
|
+
cls.product1 = cls.env["product.product"].create(
|
30
25
|
{
|
31
26
|
"name": "Product A",
|
32
|
-
"
|
27
|
+
"is_storable": True,
|
33
28
|
}
|
34
29
|
)
|
35
|
-
|
30
|
+
cls.product2 = cls.env["product.product"].create(
|
36
31
|
{
|
37
32
|
"name": "Product B",
|
38
|
-
"
|
33
|
+
"is_storable": True,
|
39
34
|
}
|
40
35
|
)
|
41
36
|
|
42
|
-
|
37
|
+
cls.env["stock.quant"].create(
|
43
38
|
{
|
44
|
-
"product_id":
|
45
|
-
"location_id":
|
39
|
+
"product_id": cls.product1.id,
|
40
|
+
"location_id": cls.shelf1_location.id,
|
46
41
|
"quantity": 5.0,
|
47
42
|
"reserved_quantity": 0.0,
|
48
43
|
}
|
49
44
|
)
|
50
|
-
|
45
|
+
cls.env["stock.quant"].create(
|
51
46
|
{
|
52
|
-
"product_id":
|
53
|
-
"location_id":
|
47
|
+
"product_id": cls.product1.id,
|
48
|
+
"location_id": cls.shelf1_location.id,
|
54
49
|
"quantity": 10.0,
|
55
50
|
"reserved_quantity": 5.0,
|
56
51
|
}
|
57
52
|
)
|
58
|
-
|
53
|
+
cls.env["stock.quant"].create(
|
59
54
|
{
|
60
|
-
"product_id":
|
61
|
-
"location_id":
|
55
|
+
"product_id": cls.product2.id,
|
56
|
+
"location_id": cls.shelf1_location.id,
|
62
57
|
"quantity": 5.0,
|
63
58
|
"reserved_quantity": 0.0,
|
64
59
|
}
|
@@ -80,7 +75,7 @@ class TestFillwithStock(common.TransactionCase):
|
|
80
75
|
picking_stock_pack.move_ids.filtered(
|
81
76
|
lambda m: m.product_id == self.product1
|
82
77
|
).product_uom_qty,
|
83
|
-
|
78
|
+
15.0,
|
84
79
|
)
|
85
80
|
self.assertEqual(
|
86
81
|
picking_stock_pack.move_ids.filtered(
|
@@ -1,6 +1,5 @@
|
|
1
1
|
<?xml version="1.0" ?>
|
2
2
|
<odoo>
|
3
|
-
|
4
3
|
<record id="view_picking_form" model="ir.ui.view">
|
5
4
|
<field name="name">stock.picking.form.fillwithstock</field>
|
6
5
|
<field name="model">stock.picking</field>
|
@@ -9,7 +8,7 @@
|
|
9
8
|
<button name="action_confirm" position="before">
|
10
9
|
<button
|
11
10
|
name="button_fillwithstock"
|
12
|
-
|
11
|
+
invisible="state != 'draft'"
|
13
12
|
string="Fill with stock"
|
14
13
|
type="object"
|
15
14
|
class="oe_highlight"
|
@@ -18,5 +17,4 @@
|
|
18
17
|
</button>
|
19
18
|
</field>
|
20
19
|
</record>
|
21
|
-
|
22
20
|
</odoo>
|
@@ -5,11 +5,8 @@
|
|
5
5
|
<field name="model">stock.picking.type</field>
|
6
6
|
<field name="inherit_id" ref="stock.view_picking_type_form" />
|
7
7
|
<field name="arch" type="xml">
|
8
|
-
<field name="
|
9
|
-
<field
|
10
|
-
name="show_move_onhand"
|
11
|
-
attrs='{"invisible": [("code", "not in", ["internal", "outgoing"])]}'
|
12
|
-
/>
|
8
|
+
<field name="create_backorder" position="after">
|
9
|
+
<field name="show_move_onhand" invisible="code != 'internal'" />
|
13
10
|
</field>
|
14
11
|
</field>
|
15
12
|
</record>
|
@@ -20,7 +17,7 @@
|
|
20
17
|
<field name="code" position="after">
|
21
18
|
<field name="show_move_onhand" />
|
22
19
|
</field>
|
23
|
-
<
|
20
|
+
<button name="get_action_picking_tree_ready" position="after">
|
24
21
|
<div t-if="record.show_move_onhand.raw_value">
|
25
22
|
<button
|
26
23
|
name="action_move_location"
|
@@ -31,7 +28,7 @@
|
|
31
28
|
Move On Hand
|
32
29
|
</button>
|
33
30
|
</div>
|
34
|
-
</
|
31
|
+
</button>
|
35
32
|
</field>
|
36
33
|
</record>
|
37
34
|
</odoo>
|
@@ -3,9 +3,8 @@
|
|
3
3
|
# Copyright 2019 Sergio Teruel - Tecnativa <sergio.teruel@tecnativa.com>
|
4
4
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
5
5
|
|
6
|
-
from itertools import groupby
|
7
6
|
|
8
|
-
from odoo import api, fields, models
|
7
|
+
from odoo import Command, api, fields, models
|
9
8
|
from odoo.fields import first
|
10
9
|
from odoo.osv import expression
|
11
10
|
|
@@ -39,17 +38,20 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
39
38
|
"move_location_wizard_id",
|
40
39
|
string="Move Location lines",
|
41
40
|
)
|
41
|
+
company_id = fields.Many2one("res.company", default=lambda self: self.env.company)
|
42
42
|
picking_type_id = fields.Many2one(
|
43
43
|
compute="_compute_picking_type_id",
|
44
44
|
comodel_name="stock.picking.type",
|
45
45
|
readonly=False,
|
46
46
|
store=True,
|
47
|
+
domain="[('company_id', '=', company_id), ('code', '=', 'internal')]",
|
47
48
|
)
|
48
49
|
picking_id = fields.Many2one(
|
49
50
|
string="Connected Picking", comodel_name="stock.picking"
|
50
51
|
)
|
51
52
|
edit_locations = fields.Boolean(default=True)
|
52
53
|
apply_putaway_strategy = fields.Boolean()
|
54
|
+
exclude_reserved_qty = fields.Boolean(default=True)
|
53
55
|
|
54
56
|
@api.depends("edit_locations")
|
55
57
|
def _compute_readonly_locations(self):
|
@@ -67,15 +69,20 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
67
69
|
@api.depends_context("company")
|
68
70
|
@api.depends("origin_location_id")
|
69
71
|
def _compute_picking_type_id(self):
|
70
|
-
company_id = self.env.context.get("company_id") or self.env.company.id
|
71
72
|
for rec in self:
|
72
73
|
picking_type = self.env["stock.picking.type"]
|
73
74
|
base_domain = [
|
74
|
-
("code", "
|
75
|
-
("warehouse_id.company_id", "=", company_id),
|
75
|
+
("code", "=", "internal"),
|
76
|
+
("warehouse_id.company_id", "=", self.company_id.id),
|
76
77
|
]
|
77
78
|
if rec.origin_location_id:
|
78
79
|
location_id = rec.origin_location_id
|
80
|
+
if (
|
81
|
+
location_id
|
82
|
+
and rec.picking_type_id
|
83
|
+
and rec.picking_type_id.default_location_src_id == location_id
|
84
|
+
):
|
85
|
+
continue
|
79
86
|
while location_id and not picking_type:
|
80
87
|
domain = [("default_location_src_id", "=", location_id.id)]
|
81
88
|
domain = expression.AND([base_domain, domain])
|
@@ -102,8 +109,7 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
102
109
|
@api.model
|
103
110
|
def _prepare_wizard_move_lines(self, quants):
|
104
111
|
res = []
|
105
|
-
|
106
|
-
if not exclude_reserved_qty:
|
112
|
+
if not self.exclude_reserved_qty:
|
107
113
|
res = [
|
108
114
|
(
|
109
115
|
0,
|
@@ -113,6 +119,7 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
113
119
|
"move_quantity": quant.quantity,
|
114
120
|
"max_quantity": quant.quantity,
|
115
121
|
"reserved_quantity": quant.reserved_quantity,
|
122
|
+
"total_quantity": quant.quantity,
|
116
123
|
"origin_location_id": quant.location_id.id,
|
117
124
|
"lot_id": quant.lot_id.id,
|
118
125
|
"package_id": quant.package_id.id,
|
@@ -125,12 +132,13 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
125
132
|
]
|
126
133
|
else:
|
127
134
|
# if need move only available qty per product on location
|
128
|
-
for
|
129
|
-
# we need only one quant per product
|
130
|
-
quant = list(quant)[0]
|
135
|
+
for quant in quants:
|
131
136
|
qty = quant._get_available_quantity(
|
132
137
|
quant.product_id,
|
133
138
|
quant.location_id,
|
139
|
+
quant.lot_id,
|
140
|
+
quant.package_id,
|
141
|
+
quant.owner_id,
|
134
142
|
)
|
135
143
|
if qty:
|
136
144
|
res.append(
|
@@ -142,6 +150,7 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
142
150
|
"move_quantity": qty,
|
143
151
|
"max_quantity": qty,
|
144
152
|
"reserved_quantity": quant.reserved_quantity,
|
153
|
+
"total_quantity": quant.quantity,
|
145
154
|
"origin_location_id": quant.location_id.id,
|
146
155
|
"lot_id": quant.lot_id.id,
|
147
156
|
"package_id": quant.package_id.id,
|
@@ -153,16 +162,6 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
153
162
|
)
|
154
163
|
return res
|
155
164
|
|
156
|
-
@api.onchange("origin_location_id")
|
157
|
-
def _onchange_origin_location_id(self):
|
158
|
-
if not self.env.context.get("origin_location_disable", False):
|
159
|
-
self._clear_lines()
|
160
|
-
|
161
|
-
@api.onchange("destination_location_id")
|
162
|
-
def _onchange_destination_location_id(self):
|
163
|
-
for line in self.stock_move_location_line_ids:
|
164
|
-
line.destination_location_id = self.destination_location_id
|
165
|
-
|
166
165
|
def _clear_lines(self):
|
167
166
|
self.stock_move_location_line_ids = False
|
168
167
|
|
@@ -196,8 +195,7 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
196
195
|
groups = self.group_lines()
|
197
196
|
moves = self.env["stock.move"]
|
198
197
|
for lines in groups.values():
|
199
|
-
|
200
|
-
moves |= move
|
198
|
+
moves |= self._create_move(picking, lines)
|
201
199
|
return moves
|
202
200
|
|
203
201
|
def _get_move_values(self, picking, lines):
|
@@ -224,17 +222,8 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
224
222
|
lines.create_move_lines(picking, move)
|
225
223
|
if self.env.context.get("planned"):
|
226
224
|
for line in lines:
|
227
|
-
available_quantity = self.env["stock.quant"]._get_available_quantity(
|
228
|
-
line.product_id,
|
229
|
-
line.origin_location_id,
|
230
|
-
lot_id=line.lot_id,
|
231
|
-
package_id=line.package_id,
|
232
|
-
owner_id=line.owner_id,
|
233
|
-
strict=True,
|
234
|
-
)
|
235
225
|
move._update_reserved_quantity(
|
236
226
|
line.move_quantity,
|
237
|
-
available_quantity,
|
238
227
|
line.origin_location_id,
|
239
228
|
lot_id=line.lot_id,
|
240
229
|
package_id=line.package_id,
|
@@ -244,10 +233,11 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
244
233
|
# Force the state to be assigned, instead of _action_assign,
|
245
234
|
# to avoid discarding the selected move_location_line.
|
246
235
|
move.state = "assigned"
|
236
|
+
move.move_line_ids.filtered(lambda ml: not ml.quantity).unlink()
|
247
237
|
move.move_line_ids.write({"state": "assigned"})
|
248
238
|
return move
|
249
239
|
|
250
|
-
def _unreserve_moves(self):
|
240
|
+
def _unreserve_moves(self, picking):
|
251
241
|
"""
|
252
242
|
Try to unreserve moves that they has reserved quantity before user
|
253
243
|
moves products from a location to other one and change move origin
|
@@ -256,9 +246,9 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
256
246
|
"""
|
257
247
|
moves_to_reassign = self.env["stock.move"]
|
258
248
|
lines_to_ckeck_reverve = self.stock_move_location_line_ids.filtered(
|
259
|
-
lambda
|
260
|
-
|
261
|
-
and not
|
249
|
+
lambda line: (
|
250
|
+
line.move_quantity > line.max_quantity
|
251
|
+
and not line.origin_location_id.should_bypass_reservation()
|
262
252
|
)
|
263
253
|
)
|
264
254
|
for line in lines_to_ckeck_reverve:
|
@@ -270,7 +260,8 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
270
260
|
("lot_id", "=", line.lot_id.id),
|
271
261
|
("package_id", "=", line.package_id.id),
|
272
262
|
("owner_id", "=", line.owner_id.id),
|
273
|
-
("
|
263
|
+
("quantity", ">", 0.0),
|
264
|
+
("picking_id", "!=", picking.id),
|
274
265
|
]
|
275
266
|
)
|
276
267
|
moves_to_unreserve = move_lines.mapped("move_id")
|
@@ -281,17 +272,10 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
281
272
|
|
282
273
|
def action_move_location(self):
|
283
274
|
self.ensure_one()
|
284
|
-
if
|
285
|
-
picking = self._create_picking()
|
286
|
-
else:
|
287
|
-
picking = self.picking_id
|
288
|
-
# Prevent putaway rules to be excuted when we don't need to
|
289
|
-
picking = picking.with_context(
|
290
|
-
avoid_putaway_rules=not self.apply_putaway_strategy
|
291
|
-
)
|
275
|
+
picking = self.picking_id if self.picking_id else self._create_picking()
|
292
276
|
self._create_moves(picking)
|
293
277
|
if not self.env.context.get("planned"):
|
294
|
-
moves_to_reassign = self._unreserve_moves()
|
278
|
+
moves_to_reassign = self._unreserve_moves(picking)
|
295
279
|
picking.button_validate()
|
296
280
|
moves_to_reassign._action_assign()
|
297
281
|
self.picking_id = picking
|
@@ -322,7 +306,7 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
322
306
|
"quantity:sum",
|
323
307
|
"reserved_quantity:sum",
|
324
308
|
],
|
325
|
-
groupby=["product_id", "lot_id", "package_id", "owner_id"],
|
309
|
+
groupby=["id", "product_id", "lot_id", "package_id", "owner_id"],
|
326
310
|
orderby="id",
|
327
311
|
lazy=False,
|
328
312
|
)
|
@@ -339,12 +323,18 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
339
323
|
and self.destination_location_id._get_putaway_strategy(product).id
|
340
324
|
or self.destination_location_id.id
|
341
325
|
)
|
326
|
+
res_qty = group.get("reserved_quantity", 0.0)
|
327
|
+
total_qty = group.get("quantity", 0.0)
|
328
|
+
max_qty = (
|
329
|
+
total_qty if not self.exclude_reserved_qty else total_qty - res_qty
|
330
|
+
)
|
342
331
|
product_data.append(
|
343
332
|
{
|
344
333
|
"product_id": product.id,
|
345
|
-
"move_quantity":
|
346
|
-
"max_quantity":
|
347
|
-
"reserved_quantity":
|
334
|
+
"move_quantity": max_qty,
|
335
|
+
"max_quantity": max_qty,
|
336
|
+
"reserved_quantity": res_qty,
|
337
|
+
"total_quantity": total_qty,
|
348
338
|
"origin_location_id": self.origin_location_id.id,
|
349
339
|
"destination_location_id": location_dest_id,
|
350
340
|
# cursor returns None instead of False
|
@@ -361,21 +351,7 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
361
351
|
)
|
362
352
|
return product_data
|
363
353
|
|
364
|
-
|
365
|
-
lines = []
|
366
|
-
line_model = self.env["wiz.stock.move.location.line"]
|
367
|
-
for line_val in self._get_stock_move_location_lines_values():
|
368
|
-
if line_val.get("max_quantity") <= 0:
|
369
|
-
continue
|
370
|
-
line = line_model.create(line_val)
|
371
|
-
line.max_quantity = line.get_max_quantity()
|
372
|
-
line.reserved_quantity = line.reserved_quantity
|
373
|
-
lines.append(line)
|
374
|
-
self.update(
|
375
|
-
{"stock_move_location_line_ids": [(6, 0, [line.id for line in lines])]}
|
376
|
-
)
|
377
|
-
|
378
|
-
@api.onchange("origin_location_id")
|
354
|
+
@api.onchange("origin_location_id", "exclude_reserved_qty")
|
379
355
|
def onchange_origin_location(self):
|
380
356
|
# Get origin_location_disable context key to prevent load all origin
|
381
357
|
# location products when user opens the wizard from stock quants to
|
@@ -384,7 +360,12 @@ class StockMoveLocationWizard(models.TransientModel):
|
|
384
360
|
not self.env.context.get("origin_location_disable")
|
385
361
|
and self.origin_location_id
|
386
362
|
):
|
387
|
-
|
363
|
+
lines = [Command.clear()] + [
|
364
|
+
Command.create(line_vals)
|
365
|
+
for line_vals in self._get_stock_move_location_lines_values()
|
366
|
+
if line_vals.get("max_quantity", 0.0) > 0.0
|
367
|
+
]
|
368
|
+
self.update({"stock_move_location_line_ids": lines})
|
388
369
|
|
389
370
|
def clear_lines(self):
|
390
371
|
self._clear_lines()
|