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
|
- Select the quantities which you want move to another location
|
||||||
|
|
||||||
If you go to the Inventory Dashboard you can see the button "Move from
|
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
|
location" in each of the picking types (only applicable to internal and
|
||||||
transfers). Press it and you will be directed to the wizard.
|
outgoing transfers). Press it and you will be directed to the wizard.
|
||||||
|
|
||||||
|image1|
|
|image1|
|
||||||
|
|
||||||
@@ -143,6 +143,8 @@ Contributors
|
|||||||
|
|
||||||
- Aung Ko Ko Lin
|
- Aung Ko Ko Lin
|
||||||
|
|
||||||
|
- Laurent Mignon <laurent.mignon@acsone.eu>
|
||||||
|
|
||||||
Maintainers
|
Maintainers
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|||||||
@@ -13,3 +13,4 @@
|
|||||||
- Abraham Anes \<<abraham@studio73.es>\>
|
- Abraham Anes \<<abraham@studio73.es>\>
|
||||||
- Quartile \<<https://www.quartile.co>\>
|
- Quartile \<<https://www.quartile.co>\>
|
||||||
- Aung Ko Ko Lin
|
- 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
|
- A new menu item Operations \> Move from location... opens a wizard where 2 locations
|
||||||
where 2 locations can be specified.
|
can be specified.
|
||||||
- Select origin and destination locations and press "IMMEDIATE TRANSFER"
|
- Select origin and destination locations and press "IMMEDIATE TRANSFER" or "PLANNED
|
||||||
or "PLANNED TRANSFER"
|
TRANSFER"
|
||||||
- Press ADD ALL button to add all products available
|
- Press ADD ALL button to add all products available
|
||||||
- Those lines can be edited. Move quantity can't be more than a max
|
- Those lines can be edited. Move quantity can't be more than a max available quantity
|
||||||
available quantity
|
|
||||||
- Move doesn't care about the reservations and will move stuff anyway
|
- Move doesn't care about the reservations and will move stuff anyway
|
||||||
- If during your operation with the wizard the real quantity will change
|
- If during your operation with the wizard the real quantity will change it will move
|
||||||
it will move only the available quantity at the button press
|
only the available quantity at the button press
|
||||||
- Products will be moved and a form view of picking that did that will
|
- Products will be moved and a form view of picking that did that will show up
|
||||||
show up
|
- If "PLANNED TRANSFER" is used - the picking won't be validated automatically
|
||||||
- If "PLANNED TRANSFER" is used - the picking won't be validated
|
|
||||||
automatically
|
|
||||||
|
|
||||||
If you want to transfer a full quant:
|
If you want to transfer a full quant:
|
||||||
|
|
||||||
- Go to Inventory \> Products \> Products and click "On hand" smart
|
- Go to Inventory \> Products \> Products and click "On hand" smart button or Inventory
|
||||||
button or Inventory \> Reporting \> Inventory, the quants view will be
|
\> Reporting \> Inventory, the quants view will be opened.
|
||||||
opened.
|
|
||||||
- Select the quantities which you want move to another location
|
- Select the quantities which you want move to another location
|
||||||
|
|
||||||
If you go to the Inventory Dashboard you can see the button "Move from
|
If you go to the Inventory Dashboard you can see the button "Move from location" in each
|
||||||
location" in each of the picking types (only applicable to internal
|
of the picking types (only applicable to internal and outgoing transfers). Press it and
|
||||||
transfers). Press it and you will be directed to the wizard.
|
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
|
If you want transfer everything from stock.location
|
||||||
|
|
||||||
On a draft picking, add a button to fill with moves lines for all
|
On a draft picking, add a button to fill with moves lines for all products in the source
|
||||||
products in the source destination. This allows to create a picking to
|
destination. This allows to create a picking to move all the content of a location. The
|
||||||
move all the content of a location. The Origin Location must have stock.
|
Origin Location must have stock. The Destination Location has to be a final location. If
|
||||||
The Destination Location has to be a final location.
|
some quants are not available (i.e. reserved) the picking will be in partially available
|
||||||
If some quants are not available
|
state and reserved moves won't be listed in the operations. Use barcode interface to
|
||||||
(i.e. reserved) the picking will be in partially available state and
|
scan a location and create an empty picking. Then use the fill with stock button.
|
||||||
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>
|
<li>Select the quantities which you want move to another location</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>If you go to the Inventory Dashboard you can see the button “Move from
|
<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
|
location” in each of the picking types (only applicable to internal and
|
||||||
transfers). Press it and you will be directed to the wizard.</p>
|
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><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
|
<p>To enable this option, check “Show Move On Hand Stock” in the Picking
|
||||||
Type configuration.</p>
|
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>
|
<li>Aung Ko Ko Lin</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li>Laurent Mignon <<a class="reference external" href="mailto:laurent.mignon@acsone.eu">laurent.mignon@acsone.eu</a>></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="maintainers">
|
<div class="section" id="maintainers">
|
||||||
|
|||||||
@@ -92,46 +92,49 @@ class TestsCommon(common.TransactionCase):
|
|||||||
)
|
)
|
||||||
cls.package = cls.env["stock.quant.package"].create({})
|
cls.package = cls.env["stock.quant.package"].create({})
|
||||||
cls.package1 = cls.env["stock.quant.package"].create({})
|
cls.package1 = cls.env["stock.quant.package"].create({})
|
||||||
|
|
||||||
cls.package2 = cls.env["stock.quant.package"].create({})
|
cls.package2 = cls.env["stock.quant.package"].create({})
|
||||||
|
|
||||||
def setup_product_amounts(self):
|
@classmethod
|
||||||
self.set_product_amount(self.product_no_lots, self.internal_loc_1, 123)
|
def setup_product_amounts(cls):
|
||||||
self.set_product_amount(
|
cls.set_product_amount(cls.product_no_lots, cls.internal_loc_1, 123)
|
||||||
self.product_lots, self.internal_loc_1, 1.0, lot_id=self.lot1
|
cls.set_product_amount(
|
||||||
|
cls.product_lots, cls.internal_loc_1, 1.0, lot_id=cls.lot1
|
||||||
)
|
)
|
||||||
self.set_product_amount(
|
cls.set_product_amount(
|
||||||
self.product_lots, self.internal_loc_1, 1.0, lot_id=self.lot2
|
cls.product_lots, cls.internal_loc_1, 1.0, lot_id=cls.lot2
|
||||||
)
|
)
|
||||||
self.set_product_amount(
|
cls.set_product_amount(
|
||||||
self.product_lots, self.internal_loc_1, 1.0, lot_id=self.lot3
|
cls.product_lots, cls.internal_loc_1, 1.0, lot_id=cls.lot3
|
||||||
)
|
)
|
||||||
self.set_product_amount(
|
cls.set_product_amount(
|
||||||
self.product_package,
|
cls.product_package,
|
||||||
self.internal_loc_1,
|
cls.internal_loc_1,
|
||||||
1.0,
|
1.0,
|
||||||
lot_id=self.lot4,
|
lot_id=cls.lot4,
|
||||||
package_id=self.package,
|
package_id=cls.package,
|
||||||
)
|
)
|
||||||
self.set_product_amount(
|
cls.set_product_amount(
|
||||||
self.product_package,
|
cls.product_package,
|
||||||
self.internal_loc_1,
|
cls.internal_loc_1,
|
||||||
1.0,
|
1.0,
|
||||||
lot_id=self.lot4,
|
lot_id=cls.lot4,
|
||||||
package_id=self.package1,
|
package_id=cls.package1,
|
||||||
)
|
)
|
||||||
self.set_product_amount(
|
cls.set_product_amount(
|
||||||
self.product_package,
|
cls.product_package,
|
||||||
self.internal_loc_1,
|
cls.internal_loc_1,
|
||||||
1.0,
|
1.0,
|
||||||
lot_id=self.lot5,
|
lot_id=cls.lot5,
|
||||||
package_id=self.package2,
|
package_id=cls.package2,
|
||||||
owner_id=self.partner,
|
owner_id=cls.partner,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
def set_product_amount(
|
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,
|
product,
|
||||||
location,
|
location,
|
||||||
amount,
|
amount,
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ from .test_common import TestsCommon
|
|||||||
|
|
||||||
|
|
||||||
class TestMoveLocation(TestsCommon):
|
class TestMoveLocation(TestsCommon):
|
||||||
def setUp(self):
|
@classmethod
|
||||||
super().setUp()
|
def setUpClass(cls):
|
||||||
self.setup_product_amounts()
|
super().setUpClass()
|
||||||
|
cls.setup_product_amounts()
|
||||||
|
|
||||||
def test_move_location_wizard(self):
|
def test_move_location_wizard(self):
|
||||||
"""Test a simple move."""
|
"""Test a simple move."""
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<field name="show_operations" position="after">
|
<field name="show_operations" position="after">
|
||||||
<field
|
<field
|
||||||
name="show_move_onhand"
|
name="show_move_onhand"
|
||||||
attrs='{"invisible": [("code", "not in", ["internal"])]}'
|
attrs='{"invisible": [("code", "not in", ["internal", "outgoing"])]}'
|
||||||
/>
|
/>
|
||||||
</field>
|
</field>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class StockMoveLocationWizard(models.TransientModel):
|
|||||||
for rec in self:
|
for rec in self:
|
||||||
picking_type = self.env["stock.picking.type"]
|
picking_type = self.env["stock.picking.type"]
|
||||||
base_domain = [
|
base_domain = [
|
||||||
("code", "=", "internal"),
|
("code", "in", ("internal", "outgoing")),
|
||||||
("warehouse_id.company_id", "=", company_id),
|
("warehouse_id.company_id", "=", company_id),
|
||||||
]
|
]
|
||||||
if rec.origin_location_id:
|
if rec.origin_location_id:
|
||||||
@@ -303,25 +303,32 @@ class StockMoveLocationWizard(models.TransientModel):
|
|||||||
)
|
)
|
||||||
return action
|
return action
|
||||||
|
|
||||||
|
def _get_quants_domain(self):
|
||||||
|
return [("location_id", "=", self.origin_location_id.id)]
|
||||||
|
|
||||||
def _get_group_quants(self):
|
def _get_group_quants(self):
|
||||||
location_id = self.origin_location_id
|
domain = self._get_quants_domain()
|
||||||
# Using sql as search_group doesn't support aggregation functions
|
result = self.env["stock.quant"].read_group(
|
||||||
# leading to overhead in queries to DB
|
domain=domain,
|
||||||
query = """
|
fields=[
|
||||||
SELECT product_id, lot_id, package_id, owner_id, SUM(quantity) AS quantity,
|
"product_id",
|
||||||
SUM(reserved_quantity) AS reserved_quantity
|
"lot_id",
|
||||||
FROM stock_quant
|
"package_id",
|
||||||
WHERE location_id = %s
|
"owner_id",
|
||||||
GROUP BY product_id, lot_id, package_id, owner_id
|
"quantity:sum",
|
||||||
"""
|
"reserved_quantity:sum",
|
||||||
self.env.cr.execute(query, (location_id.id,))
|
],
|
||||||
return self.env.cr.dictfetchall()
|
groupby=["product_id", "lot_id", "package_id", "owner_id"],
|
||||||
|
orderby="id",
|
||||||
|
lazy=False,
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
def _get_stock_move_location_lines_values(self):
|
def _get_stock_move_location_lines_values(self):
|
||||||
product_obj = self.env["product.product"]
|
product_obj = self.env["product.product"]
|
||||||
product_data = []
|
product_data = []
|
||||||
for group in self._get_group_quants():
|
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
|
# Apply the putaway strategy
|
||||||
location_dest_id = (
|
location_dest_id = (
|
||||||
self.apply_putaway_strategy
|
self.apply_putaway_strategy
|
||||||
@@ -337,24 +344,20 @@ class StockMoveLocationWizard(models.TransientModel):
|
|||||||
"origin_location_id": self.origin_location_id.id,
|
"origin_location_id": self.origin_location_id.id,
|
||||||
"destination_location_id": location_dest_id,
|
"destination_location_id": location_dest_id,
|
||||||
# cursor returns None instead of False
|
# cursor returns None instead of False
|
||||||
"lot_id": group.get("lot_id") or False,
|
"lot_id": group["lot_id"][0] if group.get("lot_id") else False,
|
||||||
"package_id": group.get("package_id") or False,
|
"package_id": group["package_id"][0]
|
||||||
"owner_id": group.get("owner_id") or False,
|
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,
|
"product_uom_id": product.uom_id.id,
|
||||||
"custom": False,
|
"custom": False,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return product_data
|
return product_data
|
||||||
|
|
||||||
@api.onchange("origin_location_id")
|
def _reset_stock_move_location_lines(self):
|
||||||
def onchange_origin_location(self):
|
|
||||||
# Get origin_location_disable context key to prevent load all origin
|
|
||||||
# location products when user opens the wizard from stock quants to
|
|
||||||
# move it to other location.
|
|
||||||
if (
|
|
||||||
not self.env.context.get("origin_location_disable")
|
|
||||||
and self.origin_location_id
|
|
||||||
):
|
|
||||||
lines = []
|
lines = []
|
||||||
line_model = self.env["wiz.stock.move.location.line"]
|
line_model = self.env["wiz.stock.move.location.line"]
|
||||||
for line_val in self._get_stock_move_location_lines_values():
|
for line_val in self._get_stock_move_location_lines_values():
|
||||||
@@ -368,6 +371,17 @@ class StockMoveLocationWizard(models.TransientModel):
|
|||||||
{"stock_move_location_line_ids": [(6, 0, [line.id for line in lines])]}
|
{"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
|
||||||
|
# location products when user opens the wizard from stock quants to
|
||||||
|
# move it to other location.
|
||||||
|
if (
|
||||||
|
not self.env.context.get("origin_location_disable")
|
||||||
|
and self.origin_location_id
|
||||||
|
):
|
||||||
|
self._reset_stock_move_location_lines()
|
||||||
|
|
||||||
def clear_lines(self):
|
def clear_lines(self):
|
||||||
self._clear_lines()
|
self._clear_lines()
|
||||||
return {"type": "ir.action.do_nothing"}
|
return {"type": "ir.action.do_nothing"}
|
||||||
|
|||||||
@@ -10,18 +10,15 @@
|
|||||||
<form>
|
<form>
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_button_box" name="button_box" />
|
<div class="oe_button_box" name="button_box" />
|
||||||
<div>
|
<group name="options">
|
||||||
<label for="edit_locations">
|
|
||||||
Edit Locations
|
|
||||||
</label>
|
|
||||||
<field name="edit_locations" widget="boolean_toggle" />
|
<field name="edit_locations" widget="boolean_toggle" />
|
||||||
</div>
|
<field
|
||||||
<div groups="stock.group_stock_multi_locations">
|
name="apply_putaway_strategy"
|
||||||
<label for="apply_putaway_strategy">
|
string="Apply putaway strategy for moving products"
|
||||||
Apply putaway strategy for moving products
|
widget="boolean_toggle"
|
||||||
</label>
|
groups="stock.group_stock_multi_locations"
|
||||||
<field name="apply_putaway_strategy" widget="boolean_toggle" />
|
/>
|
||||||
</div>
|
</group>
|
||||||
<group name="picking_type">
|
<group name="picking_type">
|
||||||
<field name="picking_type_id" />
|
<field name="picking_type_id" />
|
||||||
</group>
|
</group>
|
||||||
@@ -37,6 +34,8 @@
|
|||||||
attrs="{'readonly': [('destination_location_disable', '=', True)]}"
|
attrs="{'readonly': [('destination_location_disable', '=', True)]}"
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
|
<group name="filters">
|
||||||
|
</group>
|
||||||
<group name="lines">
|
<group name="lines">
|
||||||
<field
|
<field
|
||||||
name="stock_move_location_line_ids"
|
name="stock_move_location_line_ids"
|
||||||
|
|||||||
Reference in New Issue
Block a user