mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
@@ -11,3 +11,4 @@
|
||||
* Jacques-Etienne Baudoux <je@bcim.be>
|
||||
* Iryna Vyshnevska <i.vyshnevska@mobilunity.com>
|
||||
* Alexei Rivera <arivera@archeti.com>
|
||||
* Abraham Anes <abraham@studio73.es>
|
||||
|
||||
@@ -15,6 +15,7 @@ class TestsCommon(common.TransactionCase):
|
||||
cls.wizard_obj = cls.env["wiz.stock.move.location"]
|
||||
cls.quant_obj = cls.env["stock.quant"]
|
||||
cls.company = cls.env.ref("base.main_company")
|
||||
cls.partner = cls.env.ref("base.res_partner_category_0")
|
||||
|
||||
cls.internal_loc_1 = cls.location_obj.create(
|
||||
{
|
||||
@@ -48,6 +49,9 @@ class TestsCommon(common.TransactionCase):
|
||||
cls.product_lots = product_obj.create(
|
||||
{"name": "Apple", "type": "product", "tracking": "lot"}
|
||||
)
|
||||
cls.product_package = product_obj.create(
|
||||
{"name": "Orange", "type": "product", "tracking": "lot"}
|
||||
)
|
||||
cls.lot1 = cls.env["stock.lot"].create(
|
||||
{
|
||||
"name": "lot1",
|
||||
@@ -69,6 +73,26 @@ class TestsCommon(common.TransactionCase):
|
||||
"company_id": cls.company.id,
|
||||
}
|
||||
)
|
||||
cls.product_package = product_obj.create(
|
||||
{"name": "Orange", "type": "product", "tracking": "lot"}
|
||||
)
|
||||
cls.lot4 = cls.env["stock.lot"].create(
|
||||
{
|
||||
"name": "lot4",
|
||||
"product_id": cls.product_package.id,
|
||||
"company_id": cls.company.id,
|
||||
}
|
||||
)
|
||||
cls.lot5 = cls.env["stock.lot"].create(
|
||||
{
|
||||
"name": "lot5",
|
||||
"product_id": cls.product_package.id,
|
||||
"company_id": cls.company.id,
|
||||
}
|
||||
)
|
||||
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)
|
||||
@@ -81,16 +105,51 @@ class TestsCommon(common.TransactionCase):
|
||||
self.set_product_amount(
|
||||
self.product_lots, self.internal_loc_1, 1.0, lot_id=self.lot3
|
||||
)
|
||||
|
||||
def set_product_amount(self, product, location, amount, lot_id=None):
|
||||
self.env["stock.quant"]._update_available_quantity(
|
||||
product, location, amount, lot_id=lot_id
|
||||
self.set_product_amount(
|
||||
self.product_package,
|
||||
self.internal_loc_1,
|
||||
1.0,
|
||||
lot_id=self.lot4,
|
||||
package_id=self.package,
|
||||
)
|
||||
self.set_product_amount(
|
||||
self.product_package,
|
||||
self.internal_loc_1,
|
||||
1.0,
|
||||
lot_id=self.lot4,
|
||||
package_id=self.package1,
|
||||
)
|
||||
self.set_product_amount(
|
||||
self.product_package,
|
||||
self.internal_loc_1,
|
||||
1.0,
|
||||
lot_id=self.lot5,
|
||||
package_id=self.package2,
|
||||
owner_id=self.partner,
|
||||
)
|
||||
|
||||
def check_product_amount(self, product, location, amount, lot_id=None):
|
||||
def set_product_amount(
|
||||
self, product, location, amount, lot_id=None, package_id=None, owner_id=None
|
||||
):
|
||||
self.env["stock.quant"]._update_available_quantity(
|
||||
product,
|
||||
location,
|
||||
amount,
|
||||
lot_id=lot_id,
|
||||
package_id=package_id,
|
||||
owner_id=owner_id,
|
||||
)
|
||||
|
||||
def check_product_amount(
|
||||
self, product, location, amount, lot_id=None, package_id=None, owner_id=None
|
||||
):
|
||||
self.assertEqual(
|
||||
self.env["stock.quant"]._get_available_quantity(
|
||||
product, location, lot_id=lot_id
|
||||
product,
|
||||
location,
|
||||
lot_id=lot_id,
|
||||
package_id=package_id,
|
||||
owner_id=owner_id,
|
||||
),
|
||||
amount,
|
||||
)
|
||||
|
||||
@@ -21,10 +21,38 @@ class TestMoveLocation(TestsCommon):
|
||||
self.check_product_amount(self.product_lots, self.internal_loc_1, 0, self.lot1)
|
||||
self.check_product_amount(self.product_lots, self.internal_loc_1, 0, self.lot2)
|
||||
self.check_product_amount(self.product_lots, self.internal_loc_1, 0, self.lot3)
|
||||
self.check_product_amount(
|
||||
self.product_package, self.internal_loc_1, 0, self.lot4, self.package
|
||||
)
|
||||
self.check_product_amount(
|
||||
self.product_package, self.internal_loc_1, 0, self.lot4, self.package1
|
||||
)
|
||||
self.check_product_amount(
|
||||
self.product_package,
|
||||
self.internal_loc_1,
|
||||
0,
|
||||
self.lot5,
|
||||
self.package2,
|
||||
self.partner,
|
||||
)
|
||||
self.check_product_amount(self.product_no_lots, self.internal_loc_2, 123)
|
||||
self.check_product_amount(self.product_lots, self.internal_loc_2, 1, self.lot1)
|
||||
self.check_product_amount(self.product_lots, self.internal_loc_2, 1, self.lot2)
|
||||
self.check_product_amount(self.product_lots, self.internal_loc_2, 1, self.lot3)
|
||||
self.check_product_amount(
|
||||
self.product_package, self.internal_loc_2, 1, self.lot4, self.package
|
||||
)
|
||||
self.check_product_amount(
|
||||
self.product_package, self.internal_loc_2, 1, self.lot4, self.package1
|
||||
)
|
||||
self.check_product_amount(
|
||||
self.product_package,
|
||||
self.internal_loc_2,
|
||||
1,
|
||||
self.lot5,
|
||||
self.package2,
|
||||
self.partner,
|
||||
)
|
||||
|
||||
def test_move_location_wizard_amount(self):
|
||||
"""Can't move more than exists."""
|
||||
@@ -54,9 +82,9 @@ class TestMoveLocation(TestsCommon):
|
||||
"""Test lines getting cleared properly."""
|
||||
wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2)
|
||||
wizard.onchange_origin_location()
|
||||
self.assertEqual(len(wizard.stock_move_location_line_ids), 4)
|
||||
self.assertEqual(len(wizard.stock_move_location_line_ids), 7)
|
||||
wizard._onchange_destination_location_id()
|
||||
self.assertEqual(len(wizard.stock_move_location_line_ids), 4)
|
||||
self.assertEqual(len(wizard.stock_move_location_line_ids), 7)
|
||||
dest_location_line = wizard.stock_move_location_line_ids.mapped(
|
||||
"destination_location_id"
|
||||
)
|
||||
@@ -96,9 +124,10 @@ class TestMoveLocation(TestsCommon):
|
||||
wizard.action_move_location()
|
||||
picking = wizard.picking_id
|
||||
self.assertEqual(picking.state, "assigned")
|
||||
self.assertEqual(len(picking.move_line_ids), 4)
|
||||
self.assertEqual(len(picking.move_line_ids), 7)
|
||||
self.assertEqual(
|
||||
sorted(picking.move_line_ids.mapped("reserved_uom_qty")), [1, 1, 1, 123]
|
||||
sorted(picking.move_line_ids.mapped("reserved_uom_qty")),
|
||||
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 123.0],
|
||||
)
|
||||
|
||||
def test_quant_transfer(self):
|
||||
|
||||
@@ -102,6 +102,8 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
"max_quantity": quant.quantity,
|
||||
"origin_location_id": quant.location_id.id,
|
||||
"lot_id": quant.lot_id.id,
|
||||
"package_id": quant.package_id.id,
|
||||
"owner_id": quant.owner_id.id,
|
||||
"product_uom_id": quant.product_uom_id.id,
|
||||
"custom": False,
|
||||
},
|
||||
@@ -128,6 +130,8 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
"max_quantity": qty,
|
||||
"origin_location_id": quant.location_id.id,
|
||||
"lot_id": quant.lot_id.id,
|
||||
"package_id": quant.package_id.id,
|
||||
"owner_id": quant.owner_id.id,
|
||||
"product_uom_id": quant.product_uom_id.id,
|
||||
"custom": False,
|
||||
},
|
||||
@@ -229,6 +233,8 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
("product_id", "=", line.product_id.id),
|
||||
("location_id", "=", line.origin_location_id.id),
|
||||
("lot_id", "=", line.lot_id.id),
|
||||
("package_id", "=", line.package_id.id),
|
||||
("owner_id", "=", line.owner_id.id),
|
||||
("qty_done", ">", 0.0),
|
||||
]
|
||||
)
|
||||
@@ -255,11 +261,13 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
self.picking_id = picking
|
||||
return self._get_picking_action(picking.id)
|
||||
|
||||
def _get_picking_action(self, pickinig_id):
|
||||
action = self.env.ref("stock.action_picking_tree_all").read()[0]
|
||||
def _get_picking_action(self, picking_id):
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"stock.action_picking_tree_all"
|
||||
)
|
||||
form_view = self.env.ref("stock.view_picking_form").id
|
||||
action.update(
|
||||
{"view_mode": "form", "views": [(form_view, "form")], "res_id": pickinig_id}
|
||||
{"view_mode": "form", "views": [(form_view, "form")], "res_id": picking_id}
|
||||
)
|
||||
return action
|
||||
|
||||
@@ -268,11 +276,11 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
# Using sql as search_group doesn't support aggregation functions
|
||||
# leading to overhead in queries to DB
|
||||
query = """
|
||||
SELECT product_id, lot_id, SUM(quantity) AS quantity,
|
||||
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
|
||||
GROUP BY product_id, lot_id, package_id, owner_id
|
||||
"""
|
||||
self.env.cr.execute(query, (location_id.id,))
|
||||
return self.env.cr.dictfetchall()
|
||||
@@ -298,6 +306,8 @@ class StockMoveLocationWizard(models.TransientModel):
|
||||
"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,
|
||||
"product_uom_id": product.uom_id.id,
|
||||
"custom": False,
|
||||
}
|
||||
|
||||
@@ -76,6 +76,12 @@
|
||||
groups="stock.group_production_lot"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
<field
|
||||
name="package_id"
|
||||
domain="[('location_id', '=', origin_location_id)]"
|
||||
options="{'no_create': True}"
|
||||
/>
|
||||
<field name="owner_id" options="{'no_create': True}" />
|
||||
<field name="move_quantity" />
|
||||
<field name="custom" invisible="1" />
|
||||
<field
|
||||
|
||||
@@ -32,6 +32,12 @@ class StockMoveLocationWizardLine(models.TransientModel):
|
||||
comodel_name="stock.lot",
|
||||
domain="[('product_id','=',product_id)]",
|
||||
)
|
||||
package_id = fields.Many2one(
|
||||
string="Package Number",
|
||||
comodel_name="stock.quant.package",
|
||||
domain="[('location_id', '=', origin_location_id)]",
|
||||
)
|
||||
owner_id = fields.Many2one(comodel_name="res.partner", string="From Owner")
|
||||
move_quantity = fields.Float(
|
||||
string="Quantity to move", digits="Product Unit of Measure"
|
||||
)
|
||||
@@ -68,6 +74,14 @@ class StockMoveLocationWizardLine(models.TransientModel):
|
||||
search_args.append(("lot_id", "=", self.lot_id.id))
|
||||
else:
|
||||
search_args.append(("lot_id", "=", False))
|
||||
if self.package_id:
|
||||
search_args.append(("package_id", "=", self.package_id.id))
|
||||
else:
|
||||
search_args.append(("package_id", "=", False))
|
||||
if self.owner_id:
|
||||
search_args.append(("owner_id", "=", self.owner_id.id))
|
||||
else:
|
||||
search_args.append(("owner_id", "=", False))
|
||||
res = self.env["stock.quant"].read_group(search_args, ["quantity"], [])
|
||||
max_quantity = res[0]["quantity"]
|
||||
return max_quantity
|
||||
@@ -91,6 +105,9 @@ class StockMoveLocationWizardLine(models.TransientModel):
|
||||
return {
|
||||
"product_id": self.product_id.id,
|
||||
"lot_id": self.lot_id.id,
|
||||
"package_id": self.package_id.id,
|
||||
"result_package_id": self.package_id.id,
|
||||
"owner_id": self.owner_id.id,
|
||||
"location_id": self.origin_location_id.id,
|
||||
"location_dest_id": location_dest_id,
|
||||
"qty_done": qty_done,
|
||||
@@ -118,6 +135,14 @@ class StockMoveLocationWizardLine(models.TransientModel):
|
||||
search_args.append(("lot_id", "=", self.lot_id.id))
|
||||
else:
|
||||
search_args.append(("lot_id", "=", False))
|
||||
if self.package_id:
|
||||
search_args.append(("package_id", "=", self.package_id.id))
|
||||
else:
|
||||
search_args.append(("package_id", "=", False))
|
||||
if self.owner_id:
|
||||
search_args.append(("owner_id", "=", self.owner_id.id))
|
||||
else:
|
||||
search_args.append(("owner_id", "=", False))
|
||||
res = self.env["stock.quant"].read_group(search_args, ["quantity"], [])
|
||||
available_qty = res[0]["quantity"]
|
||||
if not available_qty:
|
||||
|
||||
Reference in New Issue
Block a user