Skip to content

Commit 24c1cc1

Browse files
[ADD] stock_reserve_area
1 parent 9c13452 commit 24c1cc1

25 files changed

+1278
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../stock_reserve_area

setup/stock_reserve_area/setup.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import setuptools
2+
3+
setuptools.setup(
4+
setup_requires=['setuptools-odoo'],
5+
odoo_addon=True,
6+
)

stock_reserve_area/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from . import models
2+
from .hooks import post_init_hook
3+
from .hooks import pre_init_hook

stock_reserve_area/__manifest__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright 2023 ForgeFlow S.L.
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
{
4+
"name": "Stock Reservation Area",
5+
"summary": "Stock reservations on areas (group of locations)",
6+
"version": "14.0.1.0.0",
7+
"author": "ForgeFlow, Odoo Community Association (OCA)",
8+
"category": "Warehouse",
9+
"license": "AGPL-3",
10+
"complexity": "normal",
11+
"website": "https://github.com/OCA/stock-logistics-warehouse",
12+
"depends": ["stock"],
13+
"data": [
14+
"security/ir.model.access.csv",
15+
"security/stock_reserve_area_security.xml",
16+
"views/stock_reserve_area_views.xml",
17+
"views/stock_location_views.xml",
18+
"views/stock_move_views.xml",
19+
"views/stock_picking_views.xml",
20+
],
21+
"auto_install": False,
22+
"installable": True,
23+
"post_init_hook": "post_init_hook",
24+
"pre_init_hook": "pre_init_hook",
25+
}

stock_reserve_area/hooks.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright 2023 ForgeFlow SL.
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
4+
import logging
5+
6+
from odoo import SUPERUSER_ID, api
7+
from odoo.tools.sql import column_exists, table_exists
8+
9+
_logger = logging.getLogger(__name__)
10+
11+
12+
def pre_init_hook(cr):
13+
if not column_exists(cr, "stock_move", "area_reserved_availability"):
14+
cr.execute(
15+
"""
16+
ALTER TABLE "stock_move"
17+
ADD COLUMN "area_reserved_availability" double precision DEFAULT 0
18+
"""
19+
)
20+
cr.execute(
21+
"""
22+
ALTER TABLE "stock_move" ALTER COLUMN "area_reserved_availability" DROP DEFAULT
23+
"""
24+
)
25+
26+
if not table_exists(cr, "stock_move_stock_reserve_area_rel"):
27+
cr.execute(
28+
"""
29+
CREATE TABLE stock_move_stock_reserve_area_rel
30+
(stock_move_id INTEGER, stock_reserve_area_id INTEGER);
31+
"""
32+
)
33+
34+
35+
def assign_reserve_area_ids_to_stock_move_query(cr):
36+
query = """
37+
INSERT INTO stock_move_stock_reserve_area_rel (stock_move_id, stock_reserve_area_id)
38+
SELECT DISTINCT sm.id AS stock_move_id, srl.reserve_area_id AS stock_reserve_area_id
39+
FROM stock_move sm
40+
JOIN stock_location sl ON sm.location_id = sl.id
41+
JOIN stock_reserve_area_stock_location_rel srl ON sl.id = srl.location_id
42+
WHERE NOT EXISTS (
43+
SELECT 1
44+
FROM stock_move_stock_reserve_area_rel existing_rel
45+
WHERE existing_rel.stock_move_id = sm.id
46+
AND existing_rel.stock_reserve_area_id = srl.reserve_area_id
47+
);
48+
"""
49+
cr.execute(query)
50+
51+
52+
def post_init_hook(cr, registry):
53+
"""
54+
This post-init-hook will create a Reserve Area for each existing WH.
55+
"""
56+
_logger.info("Starting Post Init Hook")
57+
58+
env = api.Environment(cr, SUPERUSER_ID, dict())
59+
warehouse_obj = env["stock.warehouse"]
60+
warehouses = warehouse_obj.search([])
61+
reserve_area_obj = env["stock.reserve.area"]
62+
_logger.info("Creating a Reserve Area for each WH")
63+
for warehouse_id in warehouses.ids:
64+
warehouse = warehouse_obj.browse(warehouse_id)
65+
66+
all_locations = env["stock.location"].search(
67+
[("id", "child_of", warehouse.view_location_id.id)]
68+
)
69+
70+
reserve_area_obj.create(
71+
{
72+
"name": warehouse.name,
73+
"location_ids": [(6, 0, all_locations.ids)],
74+
"company_id": warehouse.company_id.id,
75+
}
76+
)
77+
78+
_logger.info("Starting assign_reserve_area_ids_to_stock_move_query")
79+
80+
assign_reserve_area_ids_to_stock_move_query(cr)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from . import stock_reserve_area
2+
from . import stock_move
3+
from . import stock_quant
4+
from . import stock_location
5+
from . import stock_picking
6+
from . import stock_warehouse
7+
from . import stock_move_line
8+
from . import stock_move_reserve_area_line
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright 2023 ForgeFlow SL.
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from odoo import api, fields, models
5+
6+
7+
class StockLocation(models.Model):
8+
_inherit = "stock.location"
9+
10+
reserve_area_ids = fields.Many2many(
11+
"stock.reserve.area",
12+
relation="stock_reserve_area_stock_location_rel",
13+
column1="location_id",
14+
column2="reserve_area_id",
15+
readonly=True,
16+
)
17+
18+
def write(self, vals):
19+
res = super().write(vals)
20+
return res
21+
22+
@api.depends("reserve_area_ids")
23+
def _update_impacted_moves(self, vals):
24+
"""If a location is moved outside/inside an area we have to check stock_moves"""
25+
if vals.get("reserve_area_ids"):
26+
new_reserve_areas = (
27+
self.env["stock.reserve.area"].sudo().browse(vals["reserve_area_ids"])
28+
)
29+
moves_poss_impacted = self.search(
30+
[
31+
"|",
32+
("location_id", "=", self),
33+
("location_dest_id", "=", self),
34+
("state", "in", ("confirmed", "waiting", "partially_available")),
35+
]
36+
)
37+
for move in moves_poss_impacted:
38+
for reserve_area in new_reserve_areas:
39+
if move._is_out_area(reserve_area):
40+
move.reserve_area_line_ids += self.env[
41+
"stock.move.reserve.area.line"
42+
].create(
43+
{
44+
"move_id": move.id,
45+
"reserve_area_id": reserve_area.id,
46+
}
47+
)

0 commit comments

Comments
 (0)