We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[11.0] stock_move_location: travis is red
@sebalix stock_move_location is going red in tests, so 11.0 branch is in bad state:

https://travis-ci.org/OCA/stock-logistics-warehouse/jobs/487479800

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `stock_move_location/__manifest__.py`
Content:
```
1 # Copyright (C) 2011 Julius Network Solutions SARL <contact@julius.fr>
2 # Copyright 2018 Camptocamp SA
3 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
4 
5 {
6     "name": "Move Stock Location",
7     "version": "11.0.1.0.0",
8     "author": "Julius Network Solutions, "
9               "Odoo Community Association (OCA)",
10     "summary": "This module allows to move all stock "
11                "in a stock location to an other one.",
12     "website": "https://github.com/OCA/stock-logistics-warehouse",
13     'license': 'AGPL-3',
14     "depends": [
15         "stock",
16     ],
17     "category": "Stock",
18     "data": [
19         'wizard/stock_move_location.xml',
20     ],
21 }
22
```

Path: `stock_move_location/wizard/stock_move_location.py`
Content:
```
1 # Copyright (C) 2011 Julius Network Solutions SARL <contact@julius.fr>
2 # Copyright 2018 Camptocamp SA
3 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
4 
5 from itertools import groupby
6 
7 from odoo import api, fields, models
8 
9 
10 class StockMoveLocationWizard(models.TransientModel):
11     _name = "wiz.stock.move.location"
12 
13     origin_location_id = fields.Many2one(
14         string='Origin Location',
15         comodel_name='stock.location',
16         required=True,
17         domain=lambda self: self._get_locations_domain(),
18     )
19     destination_location_id = fields.Many2one(
20         string='Destination Location',
21         comodel_name='stock.location',
22         required=True,
23         domain=lambda self: self._get_locations_domain(),
24     )
25     stock_move_location_line_ids = fields.One2many(
26         string="Move Location lines",
27         comodel_name="wiz.stock.move.location.line",
28         inverse_name="move_location_wizard_id",
29     )
30     picking_id = fields.Many2one(
31         string="Connected Picking",
32         comodel_name="stock.picking",
33     )
34 
35     @api.onchange('origin_location_id', 'destination_location_id')
36     def _onchange_locations(self):
37         self._clear_lines()
38 
39     def _clear_lines(self):
40         origin = self.origin_location_id
41         destination = self.destination_location_id
42         # there is `invalidate_cache` call inside the unlink
43         # which will clear the wizard - not cool.
44         # we have to keep the values somehow
45         self.stock_move_location_line_ids.unlink()
46         self.origin_location_id = origin
47         self.destination_location_id = destination
48 
49     def _get_locations_domain(self):
50         return [('usage', '=', 'internal')]
51 
52     def _create_picking(self):
53         return self.env['stock.picking'].create({
54             'picking_type_id': self.env.ref('stock.picking_type_internal').id,
55             'location_id': self.origin_location_id.id,
56             'location_dest_id': self.destination_location_id.id,
57         })
58 
59     @api.multi
60     def group_lines(self):
61         sorted_lines = sorted(
62             self.stock_move_location_line_ids,
63             key=lambda x: x.product_id,
64         )
65         groups = groupby(sorted_lines, key=lambda x: x.product_id)
66         groups_dict = {}
67         for prod, lines in groups:
68             groups_dict[prod.id] = list(lines)
69         return groups_dict
70 
71     @api.multi
72     def _create_moves(self, picking):
73         self.ensure_one()
74         groups = self.group_lines()
75         moves = self.env["stock.move"]
76         for group, lines in groups.items():
77             move = self._create_move(picking, lines)
78             moves |= move
79         return moves
80 
81     def _get_move_values(self, picking, lines):
82         # locations are same for the products
83         location_from_id = lines[0].origin_location_id.id
84         location_to_id = lines[0].destination_location_id.id
85         product_id = lines[0].product_id.id
86         product_uom_id = lines[0].product_uom_id.id
87         qty = sum([x.move_quantity for x in lines])
88         return {
89             "name": "test",
90             "location_id": location_from_id,
91             "location_dest_id": location_to_id,
92             "product_id": product_id,
93             "product_uom": product_uom_id,
94             "product_uom_qty": qty,
95             "picking_id": picking.id,
96             "location_move": True,
97         }
98 
99     @api.multi
100     def _create_move(self, picking, lines):
101         self.ensure_one()
102         move = self.env["stock.move"].create(
103             self._get_move_values(picking, lines),
104         )
105         for line in lines:
106             line.create_move_lines(picking, move)
107         return move
108 
109     @api.multi
110     def action_move_location(self):
111         self.ensure_one()
112         picking = self._create_picking()
113         self._create_moves(picking)
114         if not self.env.context.get("planned"):
115             picking.action_confirm()
116             picking.action_assign()
117             picking.button_validate()
118         self.picking_id = picking
119         return self._get_picking_action(picking.id)
120 
121     def _get_picking_action(self, pickinig_id):
122         action = self.env.ref("stock.action_picking_tree_all").read()[0]
123         form_view = self.env.ref("stock.view_picking_form").id
124         action.update({
125             "view_mode": "form",
126             "views": [(form_view, "form")],
127             "res_id": pickinig_id,
128         })
129         return action
130 
131     def _get_group_quants(self):
132         location_id = self.origin_location_id.id
133         company = self.env['res.company']._company_default_get(
134             'stock.inventory',
135         )
136         # Using sql as search_group doesn't support aggregation functions
137         # leading to overhead in queries to DB
138         query = """
139             SELECT product_id, lot_id, SUM(quantity)
140             FROM stock_quant
141             WHERE location_id = %s
142             AND company_id = %s
143             GROUP BY product_id, lot_id
144         """
145         self.env.cr.execute(query, (location_id, company.id))
146         return self.env.cr.dictfetchall()
147 
148     def _get_stock_move_location_lines_values(self):
149         product_obj = self.env['product.product']
150         product_data = []
151         for group in self._get_group_quants():
152             product = product_obj.browse(group.get("product_id")).exists()
153             product_data.append({
154                 'product_id': product.id,
155                 'move_quantity': group.get("sum"),
156                 'max_quantity': group.get("sum"),
157                 'origin_location_id': self.origin_location_id.id,
158                 'destination_location_id': self.destination_location_id.id,
159                 # cursor returns None instead of False
160                 'lot_id': group.get("lot_id") or False,
161                 'product_uom_id': product.uom_id.id,
162                 'move_location_wizard_id': self.id,
163                 'custom': False,
164             })
165         return product_data
166 
167     def add_lines(self):
168         self.ensure_one()
169         line_model = self.env["wiz.stock.move.location.line"]
170         if not self.stock_move_location_line_ids:
171             for line_val in self._get_stock_move_location_lines_values():
172                 if line_val.get('max_quantity') <= 0:
173                     continue
174                 line = line_model.create(line_val)
175                 line.onchange_product_id()
176         return {
177             "type": "ir.actions.do_nothing",
178         }
179 
180     def clear_lines(self):
181         self._clear_lines()
182         return {
183             "type": "ir.action.do_nothing",
184         }
185
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/stock_move_location/__manifest__.py b/stock_move_location/__manifest__.py
--- a/stock_move_location/__manifest__.py
+++ b/stock_move_location/__manifest__.py
@@ -4,7 +4,7 @@
 
 {
     "name": "Move Stock Location",
-    "version": "11.0.1.0.0",
+    "version": "11.0.1.0.1",
     "author": "Julius Network Solutions, "
               "Odoo Community Association (OCA)",
     "summary": "This module allows to move all stock "
diff --git a/stock_move_location/wizard/stock_move_location.py b/stock_move_location/wizard/stock_move_location.py
--- a/stock_move_location/wizard/stock_move_location.py
+++ b/stock_move_location/wizard/stock_move_location.py
@@ -2,8 +2,6 @@
 # Copyright 2018 Camptocamp SA
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
 
-from itertools import groupby
-
 from odoo import api, fields, models
 
 
@@ -58,22 +56,21 @@
 
     @api.multi
     def group_lines(self):
-        sorted_lines = sorted(
-            self.stock_move_location_line_ids,
-            key=lambda x: x.product_id,
-        )
-        groups = groupby(sorted_lines, key=lambda x: x.product_id)
-        groups_dict = {}
-        for prod, lines in groups:
-            groups_dict[prod.id] = list(lines)
-        return groups_dict
+        lines_grouped = {}
+        for line in self.stock_move_location_line_ids:
+            lines_grouped.setdefault(
+                line.product_id.id,
+                self.env["wiz.stock.move.location.line"].browse(),
+            )
+            lines_grouped[line.product_id.id] |= line
+        return lines_grouped
 
     @api.multi
     def _create_moves(self, picking):
         self.ensure_one()
         groups = self.group_lines()
         moves = self.env["stock.move"]
-        for group, lines in groups.items():
+        for lines in groups.values():
             move = self._create_move(picking, lines)
             moves |= move
         return moves
@@ -82,14 +79,14 @@
         # locations are same for the products
         location_from_id = lines[0].origin_location_id.id
         location_to_id = lines[0].destination_location_id.id
-        product_id = lines[0].product_id.id
+        product = lines[0].product_id
         product_uom_id = lines[0].product_uom_id.id
         qty = sum([x.move_quantity for x in lines])
         return {
-            "name": "test",
+            "name": product.display_name,
             "location_id": location_from_id,
             "location_dest_id": location_to_id,
-            "product_id": product_id,
+            "product_id": product.id,
             "product_uom": product_uom_id,
             "product_uom_qty": qty,
             "picking_id": picking.id,

{"golden_diff": "diff --git a/stock_move_location/__manifest__.py b/stock_move_location/__manifest__.py\n--- a/stock_move_location/__manifest__.py\n+++ b/stock_move_location/__manifest__.py\n@@ -4,7 +4,7 @@\n \n {\n     \"name\": \"Move Stock Location\",\n-    \"version\": \"11.0.1.0.0\",\n+    \"version\": \"11.0.1.0.1\",\n     \"author\": \"Julius Network Solutions, \"\n               \"Odoo Community Association (OCA)\",\n     \"summary\": \"This module allows to move all stock \"\ndiff --git a/stock_move_location/wizard/stock_move_location.py b/stock_move_location/wizard/stock_move_location.py\n--- a/stock_move_location/wizard/stock_move_location.py\n+++ b/stock_move_location/wizard/stock_move_location.py\n@@ -2,8 +2,6 @@\n # Copyright 2018 Camptocamp SA\n # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)\n \n-from itertools import groupby\n-\n from odoo import api, fields, models\n \n \n@@ -58,22 +56,21 @@\n \n     @api.multi\n     def group_lines(self):\n-        sorted_lines = sorted(\n-            self.stock_move_location_line_ids,\n-            key=lambda x: x.product_id,\n-        )\n-        groups = groupby(sorted_lines, key=lambda x: x.product_id)\n-        groups_dict = {}\n-        for prod, lines in groups:\n-            groups_dict[prod.id] = list(lines)\n-        return groups_dict\n+        lines_grouped = {}\n+        for line in self.stock_move_location_line_ids:\n+            lines_grouped.setdefault(\n+                line.product_id.id,\n+                self.env[\"wiz.stock.move.location.line\"].browse(),\n+            )\n+            lines_grouped[line.product_id.id] |= line\n+        return lines_grouped\n \n     @api.multi\n     def _create_moves(self, picking):\n         self.ensure_one()\n         groups = self.group_lines()\n         moves = self.env[\"stock.move\"]\n-        for group, lines in groups.items():\n+        for lines in groups.values():\n             move = self._create_move(picking, lines)\n             moves |= move\n         return moves\n@@ -82,14 +79,14 @@\n         # locations are same for the products\n         location_from_id = lines[0].origin_location_id.id\n         location_to_id = lines[0].destination_location_id.id\n-        product_id = lines[0].product_id.id\n+        product = lines[0].product_id\n         product_uom_id = lines[0].product_uom_id.id\n         qty = sum([x.move_quantity for x in lines])\n         return {\n-            \"name\": \"test\",\n+            \"name\": product.display_name,\n             \"location_id\": location_from_id,\n             \"location_dest_id\": location_to_id,\n-            \"product_id\": product_id,\n+            \"product_id\": product.id,\n             \"product_uom\": product_uom_id,\n             \"product_uom_qty\": qty,\n             \"picking_id\": picking.id,\n", "issue": "[11.0] stock_move_location: travis is red\n@sebalix stock_move_location is going red in tests, so 11.0 branch is in bad state:\r\n\r\nhttps://travis-ci.org/OCA/stock-logistics-warehouse/jobs/487479800\n", "before_files": [{"content": "# Copyright (C) 2011 Julius Network Solutions SARL <contact@julius.fr>\n# Copyright 2018 Camptocamp SA\n# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)\n\n{\n    \"name\": \"Move Stock Location\",\n    \"version\": \"11.0.1.0.0\",\n    \"author\": \"Julius Network Solutions, \"\n              \"Odoo Community Association (OCA)\",\n    \"summary\": \"This module allows to move all stock \"\n               \"in a stock location to an other one.\",\n    \"website\": \"https://github.com/OCA/stock-logistics-warehouse\",\n    'license': 'AGPL-3',\n    \"depends\": [\n        \"stock\",\n    ],\n    \"category\": \"Stock\",\n    \"data\": [\n        'wizard/stock_move_location.xml',\n    ],\n}\n", "path": "stock_move_location/__manifest__.py"}, {"content": "# Copyright (C) 2011 Julius Network Solutions SARL <contact@julius.fr>\n# Copyright 2018 Camptocamp SA\n# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)\n\nfrom itertools import groupby\n\nfrom odoo import api, fields, models\n\n\nclass StockMoveLocationWizard(models.TransientModel):\n    _name = \"wiz.stock.move.location\"\n\n    origin_location_id = fields.Many2one(\n        string='Origin Location',\n        comodel_name='stock.location',\n        required=True,\n        domain=lambda self: self._get_locations_domain(),\n    )\n    destination_location_id = fields.Many2one(\n        string='Destination Location',\n        comodel_name='stock.location',\n        required=True,\n        domain=lambda self: self._get_locations_domain(),\n    )\n    stock_move_location_line_ids = fields.One2many(\n        string=\"Move Location lines\",\n        comodel_name=\"wiz.stock.move.location.line\",\n        inverse_name=\"move_location_wizard_id\",\n    )\n    picking_id = fields.Many2one(\n        string=\"Connected Picking\",\n        comodel_name=\"stock.picking\",\n    )\n\n    @api.onchange('origin_location_id', 'destination_location_id')\n    def _onchange_locations(self):\n        self._clear_lines()\n\n    def _clear_lines(self):\n        origin = self.origin_location_id\n        destination = self.destination_location_id\n        # there is `invalidate_cache` call inside the unlink\n        # which will clear the wizard - not cool.\n        # we have to keep the values somehow\n        self.stock_move_location_line_ids.unlink()\n        self.origin_location_id = origin\n        self.destination_location_id = destination\n\n    def _get_locations_domain(self):\n        return [('usage', '=', 'internal')]\n\n    def _create_picking(self):\n        return self.env['stock.picking'].create({\n            'picking_type_id': self.env.ref('stock.picking_type_internal').id,\n            'location_id': self.origin_location_id.id,\n            'location_dest_id': self.destination_location_id.id,\n        })\n\n    @api.multi\n    def group_lines(self):\n        sorted_lines = sorted(\n            self.stock_move_location_line_ids,\n            key=lambda x: x.product_id,\n        )\n        groups = groupby(sorted_lines, key=lambda x: x.product_id)\n        groups_dict = {}\n        for prod, lines in groups:\n            groups_dict[prod.id] = list(lines)\n        return groups_dict\n\n    @api.multi\n    def _create_moves(self, picking):\n        self.ensure_one()\n        groups = self.group_lines()\n        moves = self.env[\"stock.move\"]\n        for group, lines in groups.items():\n            move = self._create_move(picking, lines)\n            moves |= move\n        return moves\n\n    def _get_move_values(self, picking, lines):\n        # locations are same for the products\n        location_from_id = lines[0].origin_location_id.id\n        location_to_id = lines[0].destination_location_id.id\n        product_id = lines[0].product_id.id\n        product_uom_id = lines[0].product_uom_id.id\n        qty = sum([x.move_quantity for x in lines])\n        return {\n            \"name\": \"test\",\n            \"location_id\": location_from_id,\n            \"location_dest_id\": location_to_id,\n            \"product_id\": product_id,\n            \"product_uom\": product_uom_id,\n            \"product_uom_qty\": qty,\n            \"picking_id\": picking.id,\n            \"location_move\": True,\n        }\n\n    @api.multi\n    def _create_move(self, picking, lines):\n        self.ensure_one()\n        move = self.env[\"stock.move\"].create(\n            self._get_move_values(picking, lines),\n        )\n        for line in lines:\n            line.create_move_lines(picking, move)\n        return move\n\n    @api.multi\n    def action_move_location(self):\n        self.ensure_one()\n        picking = self._create_picking()\n        self._create_moves(picking)\n        if not self.env.context.get(\"planned\"):\n            picking.action_confirm()\n            picking.action_assign()\n            picking.button_validate()\n        self.picking_id = picking\n        return self._get_picking_action(picking.id)\n\n    def _get_picking_action(self, pickinig_id):\n        action = self.env.ref(\"stock.action_picking_tree_all\").read()[0]\n        form_view = self.env.ref(\"stock.view_picking_form\").id\n        action.update({\n            \"view_mode\": \"form\",\n            \"views\": [(form_view, \"form\")],\n            \"res_id\": pickinig_id,\n        })\n        return action\n\n    def _get_group_quants(self):\n        location_id = self.origin_location_id.id\n        company = self.env['res.company']._company_default_get(\n            'stock.inventory',\n        )\n        # Using sql as search_group doesn't support aggregation functions\n        # leading to overhead in queries to DB\n        query = \"\"\"\n            SELECT product_id, lot_id, SUM(quantity)\n            FROM stock_quant\n            WHERE location_id = %s\n            AND company_id = %s\n            GROUP BY product_id, lot_id\n        \"\"\"\n        self.env.cr.execute(query, (location_id, company.id))\n        return self.env.cr.dictfetchall()\n\n    def _get_stock_move_location_lines_values(self):\n        product_obj = self.env['product.product']\n        product_data = []\n        for group in self._get_group_quants():\n            product = product_obj.browse(group.get(\"product_id\")).exists()\n            product_data.append({\n                'product_id': product.id,\n                'move_quantity': group.get(\"sum\"),\n                'max_quantity': group.get(\"sum\"),\n                'origin_location_id': self.origin_location_id.id,\n                'destination_location_id': self.destination_location_id.id,\n                # cursor returns None instead of False\n                'lot_id': group.get(\"lot_id\") or False,\n                'product_uom_id': product.uom_id.id,\n                'move_location_wizard_id': self.id,\n                'custom': False,\n            })\n        return product_data\n\n    def add_lines(self):\n        self.ensure_one()\n        line_model = self.env[\"wiz.stock.move.location.line\"]\n        if not self.stock_move_location_line_ids:\n            for line_val in self._get_stock_move_location_lines_values():\n                if line_val.get('max_quantity') <= 0:\n                    continue\n                line = line_model.create(line_val)\n                line.onchange_product_id()\n        return {\n            \"type\": \"ir.actions.do_nothing\",\n        }\n\n    def clear_lines(self):\n        self._clear_lines()\n        return {\n            \"type\": \"ir.action.do_nothing\",\n        }\n", "path": "stock_move_location/wizard/stock_move_location.py"}], "after_files": [{"content": "# Copyright (C) 2011 Julius Network Solutions SARL <contact@julius.fr>\n# Copyright 2018 Camptocamp SA\n# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)\n\n{\n    \"name\": \"Move Stock Location\",\n    \"version\": \"11.0.1.0.1\",\n    \"author\": \"Julius Network Solutions, \"\n              \"Odoo Community Association (OCA)\",\n    \"summary\": \"This module allows to move all stock \"\n               \"in a stock location to an other one.\",\n    \"website\": \"https://github.com/OCA/stock-logistics-warehouse\",\n    'license': 'AGPL-3',\n    \"depends\": [\n        \"stock\",\n    ],\n    \"category\": \"Stock\",\n    \"data\": [\n        'wizard/stock_move_location.xml',\n    ],\n}\n", "path": "stock_move_location/__manifest__.py"}, {"content": "# Copyright (C) 2011 Julius Network Solutions SARL <contact@julius.fr>\n# Copyright 2018 Camptocamp SA\n# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)\n\nfrom odoo import api, fields, models\n\n\nclass StockMoveLocationWizard(models.TransientModel):\n    _name = \"wiz.stock.move.location\"\n\n    origin_location_id = fields.Many2one(\n        string='Origin Location',\n        comodel_name='stock.location',\n        required=True,\n        domain=lambda self: self._get_locations_domain(),\n    )\n    destination_location_id = fields.Many2one(\n        string='Destination Location',\n        comodel_name='stock.location',\n        required=True,\n        domain=lambda self: self._get_locations_domain(),\n    )\n    stock_move_location_line_ids = fields.One2many(\n        string=\"Move Location lines\",\n        comodel_name=\"wiz.stock.move.location.line\",\n        inverse_name=\"move_location_wizard_id\",\n    )\n    picking_id = fields.Many2one(\n        string=\"Connected Picking\",\n        comodel_name=\"stock.picking\",\n    )\n\n    @api.onchange('origin_location_id', 'destination_location_id')\n    def _onchange_locations(self):\n        self._clear_lines()\n\n    def _clear_lines(self):\n        origin = self.origin_location_id\n        destination = self.destination_location_id\n        # there is `invalidate_cache` call inside the unlink\n        # which will clear the wizard - not cool.\n        # we have to keep the values somehow\n        self.stock_move_location_line_ids.unlink()\n        self.origin_location_id = origin\n        self.destination_location_id = destination\n\n    def _get_locations_domain(self):\n        return [('usage', '=', 'internal')]\n\n    def _create_picking(self):\n        return self.env['stock.picking'].create({\n            'picking_type_id': self.env.ref('stock.picking_type_internal').id,\n            'location_id': self.origin_location_id.id,\n            'location_dest_id': self.destination_location_id.id,\n        })\n\n    @api.multi\n    def group_lines(self):\n        lines_grouped = {}\n        for line in self.stock_move_location_line_ids:\n            lines_grouped.setdefault(\n                line.product_id.id,\n                self.env[\"wiz.stock.move.location.line\"].browse(),\n            )\n            lines_grouped[line.product_id.id] |= line\n        return lines_grouped\n\n    @api.multi\n    def _create_moves(self, picking):\n        self.ensure_one()\n        groups = self.group_lines()\n        moves = self.env[\"stock.move\"]\n        for lines in groups.values():\n            move = self._create_move(picking, lines)\n            moves |= move\n        return moves\n\n    def _get_move_values(self, picking, lines):\n        # locations are same for the products\n        location_from_id = lines[0].origin_location_id.id\n        location_to_id = lines[0].destination_location_id.id\n        product = lines[0].product_id\n        product_uom_id = lines[0].product_uom_id.id\n        qty = sum([x.move_quantity for x in lines])\n        return {\n            \"name\": product.display_name,\n            \"location_id\": location_from_id,\n            \"location_dest_id\": location_to_id,\n            \"product_id\": product.id,\n            \"product_uom\": product_uom_id,\n            \"product_uom_qty\": qty,\n            \"picking_id\": picking.id,\n            \"location_move\": True,\n        }\n\n    @api.multi\n    def _create_move(self, picking, lines):\n        self.ensure_one()\n        move = self.env[\"stock.move\"].create(\n            self._get_move_values(picking, lines),\n        )\n        for line in lines:\n            line.create_move_lines(picking, move)\n        return move\n\n    @api.multi\n    def action_move_location(self):\n        self.ensure_one()\n        picking = self._create_picking()\n        self._create_moves(picking)\n        if not self.env.context.get(\"planned\"):\n            picking.action_confirm()\n            picking.action_assign()\n            picking.button_validate()\n        self.picking_id = picking\n        return self._get_picking_action(picking.id)\n\n    def _get_picking_action(self, pickinig_id):\n        action = self.env.ref(\"stock.action_picking_tree_all\").read()[0]\n        form_view = self.env.ref(\"stock.view_picking_form\").id\n        action.update({\n            \"view_mode\": \"form\",\n            \"views\": [(form_view, \"form\")],\n            \"res_id\": pickinig_id,\n        })\n        return action\n\n    def _get_group_quants(self):\n        location_id = self.origin_location_id.id\n        company = self.env['res.company']._company_default_get(\n            'stock.inventory',\n        )\n        # Using sql as search_group doesn't support aggregation functions\n        # leading to overhead in queries to DB\n        query = \"\"\"\n            SELECT product_id, lot_id, SUM(quantity)\n            FROM stock_quant\n            WHERE location_id = %s\n            AND company_id = %s\n            GROUP BY product_id, lot_id\n        \"\"\"\n        self.env.cr.execute(query, (location_id, company.id))\n        return self.env.cr.dictfetchall()\n\n    def _get_stock_move_location_lines_values(self):\n        product_obj = self.env['product.product']\n        product_data = []\n        for group in self._get_group_quants():\n            product = product_obj.browse(group.get(\"product_id\")).exists()\n            product_data.append({\n                'product_id': product.id,\n                'move_quantity': group.get(\"sum\"),\n                'max_quantity': group.get(\"sum\"),\n                'origin_location_id': self.origin_location_id.id,\n                'destination_location_id': self.destination_location_id.id,\n                # cursor returns None instead of False\n                'lot_id': group.get(\"lot_id\") or False,\n                'product_uom_id': product.uom_id.id,\n                'move_location_wizard_id': self.id,\n                'custom': False,\n            })\n        return product_data\n\n    def add_lines(self):\n        self.ensure_one()\n        line_model = self.env[\"wiz.stock.move.location.line\"]\n        if not self.stock_move_location_line_ids:\n            for line_val in self._get_stock_move_location_lines_values():\n                if line_val.get('max_quantity') <= 0:\n                    continue\n                line = line_model.create(line_val)\n                line.onchange_product_id()\n        return {\n            \"type\": \"ir.actions.do_nothing\",\n        }\n\n    def clear_lines(self):\n        self._clear_lines()\n        return {\n            \"type\": \"ir.action.do_nothing\",\n        }\n", "path": "stock_move_location/wizard/stock_move_location.py"}]}