diff --git a/openupgrade_scripts/scripts/stock/18.0.1.1/post-migration.py b/openupgrade_scripts/scripts/stock/18.0.1.1/post-migration.py index ae2372ce6d17..bd5ad2bc8c11 100644 --- a/openupgrade_scripts/scripts/stock/18.0.1.1/post-migration.py +++ b/openupgrade_scripts/scripts/stock/18.0.1.1/post-migration.py @@ -88,11 +88,23 @@ def _set_inter_company_locations(env): inter_company_location.sudo().write({"active": False}) +def fill_stock_picking_type_default_locations(env): + picking_types = env["stock.picking.type"].search( + [("default_location_src_id", "=", False)] + ) + picking_types._compute_default_location_src_id() + picking_types = env["stock.picking.type"].search( + [("default_location_dest_id", "=", False)] + ) + picking_types._compute_default_location_dest_id() + + @openupgrade.migrate() def migrate(env, version): convert_company_dependent(env) _create_default_new_types_for_all_warehouses(env) _set_inter_company_locations(env) + fill_stock_picking_type_default_locations(env) openupgrade.load_data(env, "stock", "18.0.1.1/noupdate_changes.xml") openupgrade.delete_records_safely_by_xml_id( env, ["stock.property_stock_customer", "stock.property_stock_supplier"] diff --git a/openupgrade_scripts/scripts/stock/18.0.1.1/pre-migration.py b/openupgrade_scripts/scripts/stock/18.0.1.1/pre-migration.py index 5a95b0fd577b..6887336fcfe5 100644 --- a/openupgrade_scripts/scripts/stock/18.0.1.1/pre-migration.py +++ b/openupgrade_scripts/scripts/stock/18.0.1.1/pre-migration.py @@ -2,6 +2,10 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from openupgradelib import openupgrade +_columns_copy = { + "stock_move": [("location_dest_id", None, None)], +} + _field_renames = [ ("stock.move", "stock_move", "location_dest_id", "location_final_id"), ( @@ -51,12 +55,63 @@ def fill_stock_move_location_dest_id(env): openupgrade.logged_query( env.cr, """ + WITH RECURSIVE sub AS ( + (SELECT rel.move_orig_id, rel.move_dest_id + FROM stock_move_move_rel rel + LEFT JOIN stock_move_move_rel rel2 ON rel.move_dest_id = rel2.move_orig_id + WHERE rel2.move_orig_id IS NULL) + UNION + (SELECT rel.move_orig_id, sub.move_dest_id + FROM stock_move_move_rel rel + JOIN sub ON sub.move_orig_id = rel.move_dest_id) + ) + UPDATE stock_move sm2 + SET location_final_id = sm.location_final_id + FROM stock_rule sr, stock_move sm + JOIN sub ON sub.move_dest_id = sm.id + WHERE sm2.rule_id = sr.id AND sub.move_orig_id = sm2.id + AND sr.action IN ('push', 'pull_push') + """, + ) + openupgrade.logged_query( + env.cr, + """ + WITH sub AS ( + UPDATE stock_move sm + SET location_final_id = sr.location_dest_id + FROM stock_rule sr + WHERE sm.rule_id = sr.id AND sr.location_dest_id IS NOT NULL + AND sr.location_dest_id != sm.location_final_id + AND sr.location_dest_id != sm.location_dest_id + AND sr.action IN ('pull', 'pull_push') + RETURNING rule_id + ), sub2 AS ( + SELECT rule_id + FROM sub + GROUP BY rule_id + ) UPDATE stock_rule sr SET location_dest_from_rule = TRUE - FROM stock_move sm - WHERE sm.rule_id = sr.id - AND sm.location_dest_id != sm.location_final_id - AND sr.action IN ('pull', 'pull_push') + FROM sub2 + WHERE sub2.rule_id = sr.id + """, + ) + openupgrade.logged_query( + env.cr, + """ + WITH sub AS ( + SELECT sm.rule_id + FROM stock_move sm + JOIN stock_move_move_rel rel ON + rel.move_orig_id = sm.id OR rel.move_dest_id = sm.id + JOIN stock_rule sr ON sm.rule_id = sr.id + WHERE sr.action IN ('pull', 'pull_push') + GROUP BY sm.rule_id + ) + UPDATE stock_rule sr + SET location_dest_from_rule = TRUE + FROM sub + WHERE sub.rule_id = sr.id """, ) @@ -73,6 +128,7 @@ def fill_stock_putaway_rule_sublocation(env): @openupgrade.migrate() def migrate(env, version=None): + openupgrade.copy_columns(env.cr, _columns_copy) openupgrade.rename_fields(env, _field_renames) openupgrade.rename_xmlids(env.cr, _xmlid_renames) openupgrade.add_columns(env, _new_columns) diff --git a/openupgrade_scripts/scripts/stock/18.0.1.1/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/stock/18.0.1.1/upgrade_analysis_work.txt index 281bbd6324d4..2d8b2dde5c34 100644 --- a/openupgrade_scripts/scripts/stock/18.0.1.1/upgrade_analysis_work.txt +++ b/openupgrade_scripts/scripts/stock/18.0.1.1/upgrade_analysis_work.txt @@ -48,7 +48,7 @@ stock / stock.picking.type / _order : _order stock / stock.picking.type / default_location_dest_id (many2one): now required stock / stock.picking.type / default_location_src_id (many2one): now required -# NOTHING TO DO? (not sure if we can assure it someway) +# DONE: post-migration: assured is filled by calling computes stock / stock.picking.type / favorite_user_ids (many2many) : NEW relation: res.users # NOTHING TO DO: new feature diff --git a/openupgrade_scripts/scripts/stock/tests/data_pull.py b/openupgrade_scripts/scripts/stock/tests/data_pull.py new file mode 100644 index 000000000000..56d375429acd --- /dev/null +++ b/openupgrade_scripts/scripts/stock/tests/data_pull.py @@ -0,0 +1,79 @@ +env = locals().get("env") +# create two step pull route, procure a product with it +intermediate_location = env["stock.location"].create( + { + "name": "Intermediate location", + "usage": "internal", + } +) +env["ir.model.data"]._update_xmlids( + [ + { + "xml_id": "openupgrade_test_stock.intermediate_pull_location", + "record": intermediate_location, + } + ] +) +two_step_route = env["stock.route"].create( + { + "name": "2 steps", + "rule_ids": [ + ( + 0, + 0, + { + "name": "Stock → Intermediate", + "location_src_id": env.ref("stock.stock_location_stock").id, + "location_dest_id": intermediate_location.id, + "picking_type_id": env.ref("stock.picking_type_internal").id, + "action": "pull", + # 'location_dest_from_rule': True, # v18 + }, + ), + ( + 0, + 0, + { + "name": "Intermediate → Customer", + "location_src_id": intermediate_location.id, + "location_dest_id": env.ref("stock.stock_location_customers").id, + "picking_type_id": env.ref("stock.picking_type_internal").id, + "procure_method": "make_to_order", + "action": "pull", + # 'location_dest_from_rule': True, # v18 + }, + ), + ], + } +) +product = env["product.product"].create( + { + "name": "2 step product (pull)", + "type": "product", + # 'type': 'consu', # v18 + "route_ids": [(6, 0, two_step_route.ids)], + } +) +env["ir.model.data"]._update_xmlids( + [{"xml_id": "openupgrade_test_stock.pull_product", "record": product}] +) +procurement_group = env["procurement.group"].create( + { + "name": "2 step procurement", + } +) +env["procurement.group"].run( + [ + env["procurement.group"].Procurement( + product_id=product, + product_qty=42, + product_uom=product.uom_id, + location_id=env.ref("stock.stock_location_customers"), + name="2 step procurement", + origin="/", + company_id=env.company, + values={"group_id": procurement_group}, + ), + ] +) +env.cr.commit() diff --git a/openupgrade_scripts/scripts/stock/tests/data_push.py b/openupgrade_scripts/scripts/stock/tests/data_push.py new file mode 100644 index 000000000000..89990caee5f5 --- /dev/null +++ b/openupgrade_scripts/scripts/stock/tests/data_push.py @@ -0,0 +1,72 @@ +env = locals().get("env") +# create two step push route, move a product there +intermediate_location = env["stock.location"].create( + { + "name": "Intermediate location", + "usage": "internal", + } +) +env["ir.model.data"]._update_xmlids( + [ + { + "xml_id": "openupgrade_test_stock.intermediate_push_location", + "record": intermediate_location, + } + ] +) +two_step_route = env["stock.route"].create( + { + "name": "2 steps", + "rule_ids": [ + ( + 0, + 0, + { + "name": "Stock → Intermediate", + "location_src_id": env.ref("stock.stock_location_stock").id, + "location_dest_id": intermediate_location.id, + "picking_type_id": env.ref("stock.picking_type_internal").id, + "action": "push", + }, + ), + ( + 0, + 0, + { + "name": "Intermediate → Customer", + "location_src_id": intermediate_location.id, + "location_dest_id": env.ref("stock.stock_location_customers").id, + "picking_type_id": env.ref("stock.picking_type_out").id, + "action": "push", + }, + ), + ], + } +) +product = env["product.product"].create( + { + "name": "2 step product (push)", + "type": "product", + # 'type': 'consu', # v18 + "route_ids": [(6, 0, two_step_route.ids)], + } +) +env["ir.model.data"]._update_xmlids( + [{"xml_id": "openupgrade_test_stock.push_product", "record": product}] +) +in_move = env["stock.move"].create( + { + "name": "in", + "location_id": env.ref("stock.stock_location_suppliers").id, + "location_dest_id": env.ref("stock.stock_location_stock").id, + # 'location_final_id': env.ref('stock.stock_location_customers').id, + "route_ids": [(6, 0, two_step_route.ids)], + "product_id": product.id, + "quantity": 42, + "product_uom_qty": 42, + "picked": True, + } +) +in_move._action_done() +in_move.move_dest_ids._action_done() +env.cr.commit() diff --git a/openupgrade_scripts/scripts/stock/tests/test_migration.py b/openupgrade_scripts/scripts/stock/tests/test_migration.py new file mode 100644 index 000000000000..948277827fe9 --- /dev/null +++ b/openupgrade_scripts/scripts/stock/tests/test_migration.py @@ -0,0 +1,137 @@ +from odoo.tests import TransactionCase + +from odoo.addons.openupgrade_framework import openupgrade_test + + +@openupgrade_test +class TestStockMigration(TransactionCase): + def test_picking_type_required_fields(self): + """Test that newly required fields are set""" + for picking_type in self.env["stock.picking.type"].search([]): + self.assertTrue(picking_type.default_location_src_id) + self.assertTrue(picking_type.default_location_dest_id) + + def test_pull_moves(self): + """ + Test that pull moves have been migrated correctly and new moves yield the + same result + """ + product = self.env.ref("openupgrade_test_stock.pull_product") + stock_location = self.env.ref("stock.stock_location_stock") + intermediate_location = self.env.ref( + "openupgrade_test_stock.intermediate_pull_location" + ) + customer_location = self.env.ref("stock.stock_location_customers") + + moves = self.env["stock.move"].search([("product_id", "=", product.id)]) + from_stock = moves.filtered(lambda x: x.location_id == stock_location) + from_intermediate = moves.filtered( + lambda x: x.location_id == intermediate_location + ) + + self.assertEqual(from_stock.location_dest_id, intermediate_location) + self.assertEqual(from_stock.location_final_id, intermediate_location) + + self.assertEqual(from_intermediate.location_dest_id, customer_location) + self.assertEqual(from_intermediate.location_final_id, customer_location) + + rules = self.env["stock.rule"].search( + [ + "|", + ("location_src_id", "=", intermediate_location.id), + ("location_dest_id", "=", intermediate_location.id), + ] + ) + for rule in rules: + self.assertEqual(rule.location_dest_from_rule, True) + + procurement_group = self.env["procurement.group"].create( + { + "name": "2 step procurement v18", + } + ) + self.env["procurement.group"].run( + [ + self.env["procurement.group"].Procurement( + product_id=product, + product_qty=42, + product_uom=product.uom_id, + location_id=customer_location, + name="2 step procurement", + origin="/", + company_id=self.env.company, + values={"group_id": procurement_group}, + ), + ] + ) + + new_moves = ( + self.env["stock.move"].search([("product_id", "=", product.id)]) - moves + ) + from_stock = new_moves.filtered(lambda x: x.location_id == stock_location) + from_intermediate = new_moves.filtered( + lambda x: x.location_id == intermediate_location + ) + + self.assertEqual(from_stock.location_dest_id, intermediate_location) + self.assertEqual(from_stock.location_final_id, intermediate_location) + + self.assertEqual(from_intermediate.location_dest_id, customer_location) + self.assertEqual(from_intermediate.location_final_id, customer_location) + + def test_push_moves(self): + """ + Test that push moves have been migrated correctly and new moves yield the + same result + """ + product = self.env.ref("openupgrade_test_stock.push_product") + stock_location = self.env.ref("stock.stock_location_stock") + intermediate_location = self.env.ref( + "openupgrade_test_stock.intermediate_push_location" + ) + customer_location = self.env.ref("stock.stock_location_customers") + + moves = self.env["stock.move"].search([("product_id", "=", product.id)]) + + from_stock = moves.filtered(lambda x: x.location_id == stock_location) + from_intermediate = moves.filtered( + lambda x: x.location_id == intermediate_location + ) + + self.assertEqual(from_stock.location_dest_id, intermediate_location) + self.assertEqual(from_stock.location_final_id, customer_location) + + self.assertEqual(from_intermediate.location_dest_id, customer_location) + self.assertEqual(from_intermediate.location_final_id, customer_location) + + in_move = self.env["stock.move"].create( + { + "name": "in", + "location_id": self.env.ref("stock.stock_location_suppliers").id, + "location_dest_id": stock_location.id, + "location_final_id": customer_location.id, + "route_ids": [(6, 0, moves.route_ids.ids)], + "product_id": product.id, + "quantity": 42, + "product_uom_qty": 42, + "picked": True, + } + ) + in_move._action_done() + in_move.move_dest_ids.picked = True + in_move.move_dest_ids._action_done() + + new_moves = ( + self.env["stock.move"].search([("product_id", "=", product.id)]) - moves + ) + + from_stock = new_moves.filtered(lambda x: x.location_id == stock_location) + from_intermediate = new_moves.filtered( + lambda x: x.location_id == intermediate_location + ) + + self.assertEqual(from_stock.location_dest_id, intermediate_location) + self.assertEqual(from_stock.location_final_id, customer_location) + + self.assertEqual(from_intermediate.location_dest_id, customer_location) + self.assertEqual(from_intermediate.location_final_id, customer_location)