Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions stock_ux/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Stock UX
#. Add a "All transfers" view form in Menu: Operations
#. Add a restriction to edit operation type for users with the "Restrict editing Operation Type in Pickings" check.
#. Add number of packages on pickings
#. Auto-activate the "Manage Several Warehouses" permission when a company has branches (child companies) with warehouses: warehouses are counted across the whole company tree (parent + branches) instead of per single company, so a setup with one warehouse per branch still enables the multi-warehouse UI.

Installation
============
Expand Down
1 change: 1 addition & 0 deletions stock_ux/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
from . import stock_location
from . import stock_forecasted
from . import stock_quant
from . import stock_warehouse
63 changes: 63 additions & 0 deletions stock_ux/models/stock_warehouse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from collections import defaultdict

from odoo import models


class StockWarehouse(models.Model):
_inherit = "stock.warehouse"

def _multiwarehouse_max_count(self):
"""Máximo de almacenes activos dentro de un mismo árbol de compañías
(compañía raíz + sus sucursales).

El método nativo ``_check_multiwarehouse_group`` cuenta los almacenes
agrupando por ``company_id``, así que solo activa "Gestionar varios
almacenes" cuando UNA compañía tiene más de un almacén. Como cada
sucursal es una compañía hija con su propio ``company_id``, un almacén
por sucursal deja el conteo en 1 por compañía y el grupo nunca se
activa. Acá agregamos el conteo por ``company_id.root_id`` para que las
sucursales cuenten junto con su compañía madre.

Para una compañía sin sucursales ``root_id`` es la propia compañía, con
lo cual el comportamiento es idéntico al nativo.
"""
cnt_by_company = (
self.env["stock.warehouse"]
.sudo()
._read_group([("active", "=", True)], ["company_id"], aggregates=["__count"])
)
count_by_root = defaultdict(int)
for company, count in cnt_by_company:
count_by_root[company.root_id] += count
return max(count_by_root.values(), default=0)

def _check_multiwarehouse_group(self):
"""Réplica del método nativo pero contando los almacenes por árbol de
compañías (ver ``_multiwarehouse_max_count``) en lugar de por
``company_id``. Mantener sincronizado con ``stock`` en cada upgrade de
versión.
"""
max_count = self._multiwarehouse_max_count()
if not max_count:
return
group_user = self.env.ref("base.group_user")
group_stock_multi_warehouses = self.env.ref("stock.group_stock_multi_warehouses")
group_stock_multi_locations = self.env.ref("stock.group_stock_multi_locations")
if max_count <= 1 and group_stock_multi_warehouses in group_user.implied_ids:
group_user.write({"implied_ids": [(3, group_stock_multi_warehouses.id)]})
group_stock_multi_warehouses.write({"user_ids": [(3, user.id) for user in group_user.all_user_ids]})
if max_count > 1 and group_stock_multi_warehouses not in group_user.implied_ids:
if group_stock_multi_locations not in group_user.implied_ids:
self.env["res.config.settings"].create({"group_stock_multi_locations": True}).execute()
group_user.write(
{
"implied_ids": [
(4, group_stock_multi_warehouses.id),
(4, group_stock_multi_locations.id),
]
}
)
5 changes: 5 additions & 0 deletions stock_ux/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from . import test_multiwarehouse_group
58 changes: 58 additions & 0 deletions stock_ux/tests/test_multiwarehouse_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from odoo.tests.common import TransactionCase


class TestMultiwarehouseGroupBranch(TransactionCase):
"""El grupo "Gestionar varios almacenes" debe activarse cuando una compañía
tiene sucursales (compañías hijas) con almacenes, aunque cada sucursal tenga
un solo almacén. En modo test, crear una ``res.company`` crea un almacén
para ella automáticamente (ver ``stock/models/res_company.py``), así que
crear madre + sucursal genera dos almacenes bajo la misma raíz.
"""

def _create_company(self, name, parent=None):
return self.env["res.company"].create({"name": name, "parent_id": parent.id if parent else False})

def test_branch_warehouses_share_root_and_aggregate(self):
"""Cada compañía tiene 1 almacén (conteo nativo por company_id = 1),
pero madre y sucursal comparten ``root_id``, así que el conteo por árbol
da 2."""
Warehouse = self.env["stock.warehouse"]
parent = self._create_company("UX Madre")
branch = self._create_company("UX Sucursal", parent=parent)

# La sucursal es una compañía hija cuya raíz es la madre.
self.assertEqual(parent.root_id, parent)
self.assertEqual(branch.root_id, parent)

# Conteo nativo (por company_id): un almacén por compañía.
native = Warehouse.sudo()._read_group(
[("active", "=", True), ("company_id", "in", (parent + branch).ids)],
["company_id"],
aggregates=["__count"],
)
self.assertEqual(sorted(count for _company, count in native), [1, 1])

# Conteo por árbol de compañías: la madre + sucursal suman 2.
self.assertGreaterEqual(Warehouse._multiwarehouse_max_count(), 2)

def test_branch_warehouse_activates_multi_wh_group(self):
"""Al crear una sucursal con almacén, el grupo multi-almacén queda
activo (implicado en el grupo de usuario interno)."""
group_user = self.env.ref("base.group_user")
group_multi_wh = self.env.ref("stock.group_stock_multi_warehouses")

parent = self._create_company("UX Madre Grupo")
# Crear la sucursal dispara la creación de su almacén y, con ello,
# _check_multiwarehouse_group.
self._create_company("UX Sucursal Grupo", parent=parent)

self.assertIn(
group_multi_wh,
group_user.implied_ids,
"Con una madre y una sucursal, cada una con un almacén, el permiso "
"'Gestionar varios almacenes' debe activarse automáticamente.",
)
Loading