mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
@@ -62,8 +62,8 @@ If you want to transfer a full quant:
|
||||
- Select the quantities which you want move to another location
|
||||
|
||||
If you go to the Inventory Dashboard you can see the button "Move from
|
||||
location" in each of the picking types (only applicable to internal
|
||||
transfers). Press it and you will be directed to the wizard.
|
||||
location" in each of the picking types (only applicable to internal and
|
||||
outgoing transfers). Press it and you will be directed to the wizard.
|
||||
|
||||
|image1|
|
||||
|
||||
@@ -143,6 +143,8 @@ Contributors
|
||||
|
||||
- Aung Ko Ko Lin
|
||||
|
||||
- Laurent Mignon <laurent.mignon@acsone.eu>
|
||||
|
||||
Maintainers
|
||||
-----------
|
||||
|
||||
|
||||
@@ -13,3 +13,4 @@
|
||||
- Abraham Anes \<<abraham@studio73.es>\>
|
||||
- Quartile \<<https://www.quartile.co>\>
|
||||
- Aung Ko Ko Lin
|
||||
- Laurent Mignon \<<laurent.mignon@acsone.eu>\>
|
||||
|
||||
@@ -1,43 +1,37 @@
|
||||
- A new menu item Operations \> Move from location... opens a wizard
|
||||
where 2 locations can be specified.
|
||||
- Select origin and destination locations and press "IMMEDIATE TRANSFER"
|
||||
or "PLANNED TRANSFER"
|
||||
- A new menu item Operations \> Move from location... opens a wizard where 2 locations
|
||||
can be specified.
|
||||
- Select origin and destination locations and press "IMMEDIATE TRANSFER" or "PLANNED
|
||||
TRANSFER"
|
||||
- Press ADD ALL button to add all products available
|
||||
- Those lines can be edited. Move quantity can't be more than a max
|
||||
available quantity
|
||||
- Those lines can be edited. Move quantity can't be more than a max available quantity
|
||||
- Move doesn't care about the reservations and will move stuff anyway
|
||||
- If during your operation with the wizard the real quantity will change
|
||||
it will move only the available quantity at the button press
|
||||
- Products will be moved and a form view of picking that did that will
|
||||
show up
|
||||
- If "PLANNED TRANSFER" is used - the picking won't be validated
|
||||
automatically
|
||||
- If during your operation with the wizard the real quantity will change it will move
|
||||
only the available quantity at the button press
|
||||
- Products will be moved and a form view of picking that did that will show up
|
||||
- If "PLANNED TRANSFER" is used - the picking won't be validated automatically
|
||||
|
||||
If you want to transfer a full quant:
|
||||
|
||||
- Go to Inventory \> Products \> Products and click "On hand" smart
|
||||
button or Inventory \> Reporting \> Inventory, the quants view will be
|
||||
opened.
|
||||
- Go to Inventory \> Products \> Products and click "On hand" smart button or Inventory
|
||||
\> Reporting \> Inventory, the quants view will be opened.
|
||||
- Select the quantities which you want move to another location
|
||||
|
||||
If you go to the Inventory Dashboard you can see the button "Move from
|
||||
location" in each of the picking types (only applicable to internal
|
||||
transfers). Press it and you will be directed to the wizard.
|
||||
If you go to the Inventory Dashboard you can see the button "Move from location" in each
|
||||
of the picking types (only applicable to internal and outgoing transfers). Press it and
|
||||
you will be directed to the wizard.
|
||||
|
||||

|
||||
|
||||
To enable this option, check "Show Move On Hand Stock" in the Picking Type configuration.
|
||||
To enable this option, check "Show Move On Hand Stock" in the Picking Type
|
||||
configuration.
|
||||
|
||||

|
||||
|
||||
If you want transfer everything from stock.location
|
||||
|
||||
On a draft picking, add a button to fill with moves lines for all
|
||||
products in the source destination. This allows to create a picking to
|
||||
move all the content of a location. The Origin Location must have stock.
|
||||
The Destination Location has to be a final location.
|
||||
If some quants are not available
|
||||
(i.e. reserved) the picking will be in partially available state and
|
||||
reserved moves won't be listed in the operations. Use barcode interface
|
||||
to scan a location and create an empty picking. Then use the fill with
|
||||
stock button.
|
||||
On a draft picking, add a button to fill with moves lines for all products in the source
|
||||
destination. This allows to create a picking to move all the content of a location. The
|
||||
Origin Location must have stock. The Destination Location has to be a final location. If
|
||||
some quants are not available (i.e. reserved) the picking will be in partially available
|
||||
state and reserved moves won't be listed in the operations. Use barcode interface to
|
||||
scan a location and create an empty picking. Then use the fill with stock button.
|
||||
|
||||
@@ -412,8 +412,8 @@ opened.</li>
|
||||
<li>Select the quantities which you want move to another location</li>
|
||||
</ul>
|
||||
<p>If you go to the Inventory Dashboard you can see the button “Move from
|
||||
location” in each of the picking types (only applicable to internal
|
||||
transfers). Press it and you will be directed to the wizard.</p>
|
||||
location” in each of the picking types (only applicable to internal and
|
||||
outgoing transfers). Press it and you will be directed to the wizard.</p>
|
||||
<p><img alt="image1" src="https://user-images.githubusercontent.com/147538094/281480833-208ea309-0bad-43e7-bd6f-8384520afe00.png" /></p>
|
||||
<p>To enable this option, check “Show Move On Hand Stock” in the Picking
|
||||
Type configuration.</p>
|
||||
@@ -483,6 +483,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
|
||||
<li>Aung Ko Ko Lin</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Laurent Mignon <<a class="reference external" href="mailto:laurent.mignon@acsone.eu">laurent.mignon@acsone.eu</a>></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
|
||||
@@ -92,46 +92,49 @@ class TestsCommon(common.TransactionCase):
|
||||
)
|
||||
cls.package = cls.env["stock.quant.package"].create({})
|
||||
cls.package1 = cls.env["stock.quant.package"].create({})
|
||||
|
||||
cls.package2 = cls.env["stock.quant.package"].create({})
|
||||
|
||||
def setup_product_amounts(self):
|
||||
self.set_product_amount(self.product_no_lots, self.internal_loc_1, 123)
|
||||
self.set_product_amount(
|
||||
self.product_lots, self.internal_loc_1, 1.0, lot_id=self.lot1
|
||||
@classmethod
|
||||
def setup_product_amounts(cls):
|
||||
cls.set_product_amount(cls.product_no_lots, cls.internal_loc_1, 123)
|
||||
cls.set_product_amount(
|
||||
cls.product_lots, cls.internal_loc_1, 1.0, lot_id=cls.lot1
|
||||
)
|
||||
self.set_product_amount(
|
||||
self.product_lots, self.internal_loc_1, 1.0, lot_id=self.lot2
|
||||
cls.set_product_amount(
|
||||
cls.product_lots, cls.internal_loc_1, 1.0, lot_id=cls.lot2
|
||||
)
|
||||
self.set_product_amount(
|
||||
self.product_lots, self.internal_loc_1, 1.0, lot_id=self.lot3
|
||||
cls.set_product_amount(
|
||||
cls.product_lots, cls.internal_loc_1, 1.0, lot_id=cls.lot3
|
||||
)
|
||||
self.set_product_amount(
|
||||
self.product_package,
|
||||
self.internal_loc_1,
|
||||
cls.set_product_amount(
|
||||
cls.product_package,
|
||||
cls.internal_loc_1,
|
||||
1.0,
|
||||
lot_id=self.lot4,
|
||||
package_id=self.package,
|
||||
lot_id=cls.lot4,
|
||||
package_id=cls.package,
|
||||
)
|
||||
self.set_product_amount(
|
||||
self.product_package,
|
||||
self.internal_loc_1,
|
||||
cls.set_product_amount(
|
||||
cls.product_package,
|
||||
cls.internal_loc_1,
|
||||
1.0,
|
||||
lot_id=self.lot4,
|
||||
package_id=self.package1,
|
||||
lot_id=cls.lot4,
|
||||
package_id=cls.package1,
|
||||
)
|
||||
self.set_product_amount(
|
||||
self.product_package,
|
||||
self.internal_loc_1,
|
||||
cls.set_product_amount(
|
||||
cls.product_package,
|
||||
cls.internal_loc_1,
|
||||
1.0,
|
||||
lot_id=self.lot5,
|
||||
package_id=self.package2,
|
||||
owner_id=self.partner,
|
||||
lot_id=cls.lot5,
|
||||
package_id=cls.package2,
|
||||
owner_id=cls.partner,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def set_product_amount(
|
||||
self, product, location, amount, lot_id=None, package_id=None, owner_id=None
|
||||
cls, product, location, amount, lot_id=None, package_id=None, owner_id=None
|
||||
):
|
||||
self.env["stock.quant"]._update_available_quantity(
|
||||
cls.env["stock.quant"]._update_available_quantity(
|
||||
product,
|
||||
location,
|
||||
amount,
|
||||
|
||||
@@ -8,9 +8,10 @@ from .test_common import TestsCommon
|
||||
|
||||
|
||||
class TestMoveLocation(TestsCommon):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.setup_product_amounts()
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.setup_product_amounts()
|
||||
|
||||
def test_move_location_wizard(self):
|
||||
"""Test a simple move."""
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<field name="show_operations" position="after">
|
||||
<field
|
||||
name="show_move_onhand"
|
||||
attrs='{"invisible": [("code", "not in", ["internal"])]}'
|
||||
attrs='{"invisible": [("code", "not in", ["internal", "outgoing"])]}'
|
||||
/>
|
||||
</field>
|
||||
</field>
|
||||
|
||||
@@ -71,7 +71,7 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
for rec in self:
|
||||
picking_type = self.env["stock.picking.type"]
|
||||
base_domain = [
|
||||
("code", "=", "internal"),
|
||||
("code", "in", ("internal", "outgoing")),
|
||||
("warehouse_id.company_id", "=", company_id),
|
||||
]
|
||||
if rec.origin_location_id:
|
||||
@@ -303,25 +303,32 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
)
|
||||
return action
|
||||
|
||||
def _get_quants_domain(self):
|
||||
return [("location_id", "=", self.origin_location_id.id)]
|
||||
|
||||
def _get_group_quants(self):
|
||||
location_id = self.origin_location_id
|
||||
# Using sql as search_group doesn't support aggregation functions
|
||||
# leading to overhead in queries to DB
|
||||
query = """
|
||||
SELECT product_id, lot_id, package_id, owner_id, SUM(quantity) AS quantity,
|
||||
SUM(reserved_quantity) AS reserved_quantity
|
||||
FROM stock_quant
|
||||
WHERE location_id = %s
|
||||
GROUP BY product_id, lot_id, package_id, owner_id
|
||||
"""
|
||||
self.env.cr.execute(query, (location_id.id,))
|
||||
return self.env.cr.dictfetchall()
|
||||
domain = self._get_quants_domain()
|
||||
result = self.env["stock.quant"].read_group(
|
||||
domain=domain,
|
||||
fields=[
|
||||
"product_id",
|
||||
"lot_id",
|
||||
"package_id",
|
||||
"owner_id",
|
||||
"quantity:sum",
|
||||
"reserved_quantity:sum",
|
||||
],
|
||||
groupby=["product_id", "lot_id", "package_id", "owner_id"],
|
||||
orderby="id",
|
||||
lazy=False,
|
||||
)
|
||||
return result
|
||||
|
||||
def _get_stock_move_location_lines_values(self):
|
||||
product_obj = self.env["product.product"]
|
||||
product_data = []
|
||||
for group in self._get_group_quants():
|
||||
product = product_obj.browse(group.get("product_id")).exists()
|
||||
product = product_obj.browse(group["product_id"][0]).exists()
|
||||
# Apply the putaway strategy
|
||||
location_dest_id = (
|
||||
self.apply_putaway_strategy
|
||||
@@ -337,15 +344,33 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
"origin_location_id": self.origin_location_id.id,
|
||||
"destination_location_id": location_dest_id,
|
||||
# cursor returns None instead of False
|
||||
"lot_id": group.get("lot_id") or False,
|
||||
"package_id": group.get("package_id") or False,
|
||||
"owner_id": group.get("owner_id") or False,
|
||||
"lot_id": group["lot_id"][0] if group.get("lot_id") else False,
|
||||
"package_id": group["package_id"][0]
|
||||
if group.get("package_id")
|
||||
else False,
|
||||
"owner_id": group["owner_id"][0]
|
||||
if group.get("owner_id")
|
||||
else False,
|
||||
"product_uom_id": product.uom_id.id,
|
||||
"custom": False,
|
||||
}
|
||||
)
|
||||
return product_data
|
||||
|
||||
def _reset_stock_move_location_lines(self):
|
||||
lines = []
|
||||
line_model = self.env["wiz.stock.move.location.line"]
|
||||
for line_val in self._get_stock_move_location_lines_values():
|
||||
if line_val.get("max_quantity") <= 0:
|
||||
continue
|
||||
line = line_model.create(line_val)
|
||||
line.max_quantity = line.get_max_quantity()
|
||||
line.reserved_quantity = line.reserved_quantity
|
||||
lines.append(line)
|
||||
self.update(
|
||||
{"stock_move_location_line_ids": [(6, 0, [line.id for line in lines])]}
|
||||
)
|
||||
|
||||
@api.onchange("origin_location_id")
|
||||
def onchange_origin_location(self):
|
||||
# Get origin_location_disable context key to prevent load all origin
|
||||
@@ -355,18 +380,7 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
not self.env.context.get("origin_location_disable")
|
||||
and self.origin_location_id
|
||||
):
|
||||
lines = []
|
||||
line_model = self.env["wiz.stock.move.location.line"]
|
||||
for line_val in self._get_stock_move_location_lines_values():
|
||||
if line_val.get("max_quantity") <= 0:
|
||||
continue
|
||||
line = line_model.create(line_val)
|
||||
line.max_quantity = line.get_max_quantity()
|
||||
line.reserved_quantity = line.reserved_quantity
|
||||
lines.append(line)
|
||||
self.update(
|
||||
{"stock_move_location_line_ids": [(6, 0, [line.id for line in lines])]}
|
||||
)
|
||||
self._reset_stock_move_location_lines()
|
||||
|
||||
def clear_lines(self):
|
||||
self._clear_lines()
|
||||
|
||||
@@ -10,18 +10,15 @@
|
||||
<form>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box" />
|
||||
<div>
|
||||
<label for="edit_locations">
|
||||
Edit Locations
|
||||
</label>
|
||||
<group name="options">
|
||||
<field name="edit_locations" widget="boolean_toggle" />
|
||||
</div>
|
||||
<div groups="stock.group_stock_multi_locations">
|
||||
<label for="apply_putaway_strategy">
|
||||
Apply putaway strategy for moving products
|
||||
</label>
|
||||
<field name="apply_putaway_strategy" widget="boolean_toggle" />
|
||||
</div>
|
||||
<field
|
||||
name="apply_putaway_strategy"
|
||||
string="Apply putaway strategy for moving products"
|
||||
widget="boolean_toggle"
|
||||
groups="stock.group_stock_multi_locations"
|
||||
/>
|
||||
</group>
|
||||
<group name="picking_type">
|
||||
<field name="picking_type_id" />
|
||||
</group>
|
||||
@@ -37,6 +34,8 @@
|
||||
attrs="{'readonly': [('destination_location_disable', '=', True)]}"
|
||||
/>
|
||||
</group>
|
||||
<group name="filters">
|
||||
</group>
|
||||
<group name="lines">
|
||||
<field
|
||||
name="stock_move_location_line_ids"
|
||||
|
||||
Reference in New Issue
Block a user