[REF] Code quality improvements and structure fixes
- Add mypy.ini configuration to exclude migration scripts - Rename migration files to proper snake_case (post-migration.py → post_migration.py) - Add __init__.py to migration directories for proper Python package structure - Add new portal access tests for website_sale_aplicoop - Code formatting improvements (black, isort) - Update copilot instructions and project configuration Related to previous code quality refactoring work.
This commit is contained in:
parent
380d05785f
commit
cf9ea887c1
30 changed files with 1129 additions and 1102 deletions
|
|
@ -303,7 +303,7 @@ class TestLoadDraftOrder(TransactionCase):
|
|||
}
|
||||
)
|
||||
|
||||
other_user = self.env["res.users"].create(
|
||||
self.env["res.users"].create(
|
||||
{
|
||||
"name": "Other User",
|
||||
"login": "other@test.com",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ from datetime import timedelta
|
|||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.exceptions import ValidationError # noqa: F401
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
|
|
@ -430,7 +430,7 @@ class TestOrderWithoutEndDate(TransactionCase):
|
|||
"""Test order with end_date = NULL (ongoing order)."""
|
||||
start = date.today()
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
self.env["group.order"].create(
|
||||
{
|
||||
"name": "Permanent Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ Coverage:
|
|||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests.common import HttpCase
|
||||
from odoo.exceptions import AccessError # noqa: F401
|
||||
from odoo.exceptions import ValidationError # noqa: F401
|
||||
from odoo.tests.common import HttpCase # noqa: F401
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
|
|
@ -467,7 +467,7 @@ class TestConfirmOrderEndpoint(TransactionCase):
|
|||
}
|
||||
)
|
||||
|
||||
other_order = self.env["group.order"].create(
|
||||
self.env["group.order"].create(
|
||||
{
|
||||
"name": "Other Order",
|
||||
"group_ids": [(6, 0, [other_group.id])],
|
||||
|
|
@ -601,7 +601,7 @@ class TestLoadDraftEndpoint(TransactionCase):
|
|||
expired_order.action_open()
|
||||
expired_order.action_close()
|
||||
|
||||
old_sale = self.env["sale.order"].create(
|
||||
self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": expired_order.id,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from psycopg2 import IntegrityError
|
||||
from psycopg2 import IntegrityError # noqa: F401
|
||||
|
||||
from odoo import fields
|
||||
from odoo.exceptions import ValidationError
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class TestMultiCompanyGroupOrder(TransactionCase):
|
|||
}
|
||||
)
|
||||
|
||||
order2 = self.env["group.order"].create(
|
||||
self.env["group.order"].create(
|
||||
{
|
||||
"name": "Pedido Company 2",
|
||||
"group_ids": [(6, 0, [self.group2.id])],
|
||||
|
|
|
|||
83
website_sale_aplicoop/tests/test_portal_access.py
Normal file
83
website_sale_aplicoop/tests/test_portal_access.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Copyright 2026
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import HttpCase
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestPortalAccess(HttpCase):
|
||||
"""Verifica que un usuario portal pueda acceder a la página de un pedido (eskaera)."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Create a consumer group and a member partner
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Portal Test Group",
|
||||
"is_company": True,
|
||||
"email": "portal-group@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Portal Member",
|
||||
"email": "portal-member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
# Add member to the group
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
# Create a portal user (password = login for HttpCase.authenticate convenience)
|
||||
login = "portal.user@test.com"
|
||||
self.portal_user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Portal User",
|
||||
"login": login,
|
||||
"password": login,
|
||||
"partner_id": self.member_partner.id,
|
||||
# Add portal group
|
||||
"groups_id": [(4, self.env.ref("base.group_portal").id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Create and open a group.order belonging to the same company
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Portal Access Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_portal_user_can_view_eskaera_page(self):
|
||||
"""El endpoint /eskaera/<id> debe ser accesible por un usuario portal que pertenezca a la compañía."""
|
||||
# Authenticate as portal user
|
||||
self.authenticate(self.portal_user.login, self.portal_user.login)
|
||||
|
||||
# Request the eskaera page
|
||||
response = self.url_open(
|
||||
f"/eskaera/{self.group_order.id}", allow_redirects=True
|
||||
)
|
||||
|
||||
# Should return 200 OK and not redirect to login
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# Simple sanity: page should contain the group order name
|
||||
content = (
|
||||
response.get_data(as_text=True)
|
||||
if hasattr(response, "get_data")
|
||||
else getattr(response, "text", "")
|
||||
)
|
||||
self.assertIn(self.group_order.name, content)
|
||||
85
website_sale_aplicoop/tests/test_portal_get_routes.py
Normal file
85
website_sale_aplicoop/tests/test_portal_get_routes.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# Copyright 2026
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import HttpCase
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestPortalGetRoutes(HttpCase):
|
||||
"""Comprueba que las rutas GET principales devuelvan 200 para un usuario portal."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
# Create a consumer group and a member partner
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Portal Routes Group",
|
||||
"is_company": True,
|
||||
"email": "routes-group@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{"name": "Routes Member", "email": "routes-member@test.com"}
|
||||
)
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
# Create a portal user (password = login for HttpCase.authenticate convenience)
|
||||
login = "portal.routes@test.com"
|
||||
self.portal_user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Portal Routes User",
|
||||
"login": login,
|
||||
"password": login,
|
||||
"partner_id": self.member_partner.id,
|
||||
"groups_id": [(4, self.env.ref("base.group_portal").id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Create and open a minimal group.order
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Routes Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_portal_get_routes_return_200(self):
|
||||
"""Verifica que las rutas principales GET devuelvan 200 para usuario portal."""
|
||||
# Authenticate as portal user
|
||||
self.authenticate(self.portal_user.login, self.portal_user.login)
|
||||
|
||||
routes = [
|
||||
"/eskaera",
|
||||
f"/eskaera/{self.group_order.id}",
|
||||
f"/eskaera/{self.group_order.id}/checkout",
|
||||
f"/eskaera/{self.group_order.id}/load-page?page=1",
|
||||
"/eskaera/labels",
|
||||
]
|
||||
|
||||
for route in routes:
|
||||
response = self.url_open(route, allow_redirects=True)
|
||||
status = getattr(response, "status_code", None) or getattr(
|
||||
response, "status", None
|
||||
)
|
||||
# HttpCase returns werkzeug response-like objects; ensure we check 200
|
||||
try:
|
||||
code = int(status)
|
||||
except Exception:
|
||||
# Fallback: check content exists
|
||||
code = 200 if response.get_data(as_text=True) else 500
|
||||
|
||||
self.assertEqual(code, 200, msg=f"Ruta {route} devolvió {code}")
|
||||
101
website_sale_aplicoop/tests/test_portal_product_uom_access.py
Normal file
101
website_sale_aplicoop/tests/test_portal_product_uom_access.py
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# Copyright 2026
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import HttpCase
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestPortalProductUoMAccess(HttpCase):
|
||||
"""Verifica que un usuario portal pueda acceder a la página de tienda (eskaera)
|
||||
y que la lectura de UoM para display no provoque AccessError.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Grupo / partner / usuario portal (reusa patrón del otro test)
|
||||
self.group = self.env["res.partner"].create(
|
||||
{"name": "Portal UoM Group", "is_company": True}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{"name": "Portal UoM Member"}
|
||||
)
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
login = "portal.uom@test.com"
|
||||
self.portal_user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Portal UoM User",
|
||||
"login": login,
|
||||
"password": login,
|
||||
"partner_id": self.member_partner.id,
|
||||
"groups_id": [(4, self.env.ref("base.group_portal").id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Crear una categoría de UoM y una UoM personalizada (posible restringida)
|
||||
uom_cat = self.env["uom.uom.categ"].create({"name": "Test UoM Cat"})
|
||||
self.uom = self.env["uom.uom"].create(
|
||||
{
|
||||
"name": "Test UoM",
|
||||
"uom_type": "reference",
|
||||
"factor_inv": 1.0,
|
||||
"category_id": uom_cat.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Crear producto y asignar la UoM creada
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Producto UoM Test",
|
||||
"type": "consu",
|
||||
"list_price": 12.5,
|
||||
"uom_id": self.uom.id,
|
||||
"active": True,
|
||||
}
|
||||
)
|
||||
# Publicar el template para que aparezca en la tienda
|
||||
self.product.product_tmpl_id.write({"is_published": True, "sale_ok": True})
|
||||
|
||||
# Crear order y añadir producto
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Portal UoM Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
"product_ids": [(6, 0, [self.product.id])],
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_portal_user_can_view_shop_with_uom(self):
|
||||
# Authenticate as portal user
|
||||
self.authenticate(self.portal_user.login, self.portal_user.login)
|
||||
|
||||
# Request the eskaera page which renders product cards (and reads uom)
|
||||
response = self.url_open(
|
||||
f"/eskaera/{self.group_order.id}", allow_redirects=True
|
||||
)
|
||||
|
||||
# Debe retornar 200 OK
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
content = (
|
||||
response.get_data(as_text=True)
|
||||
if hasattr(response, "get_data")
|
||||
else getattr(response, "text", "")
|
||||
)
|
||||
|
||||
# Página debe contener el nombre del producto y la categoría UoM (display-safe)
|
||||
self.assertIn(self.product.name, content)
|
||||
self.assertIn("Test UoM Cat", content)
|
||||
|
|
@ -490,6 +490,6 @@ class TestPricingWithPricelist(TransactionCase):
|
|||
)
|
||||
# If it doesn't raise, check the result is valid
|
||||
self.assertIsNotNone(result)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
# If it raises, that's also acceptable behavior
|
||||
self.assertTrue(True, "Negative quantity properly rejected")
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@ class TestProductDiscoveryUnion(TransactionCase):
|
|||
"""Test discovery includes products from linked categories."""
|
||||
self.group_order.category_ids = [(4, self.category1.id)]
|
||||
|
||||
discovered = self.group_order.product_ids # Computed
|
||||
# Computed placeholder to ensure discovery logic is exercised during test setup
|
||||
_ = self.group_order.product_ids
|
||||
# Should include cat1_product and supplier_product (both in category1)
|
||||
# Note: depends on how discovery is computed
|
||||
|
||||
|
|
@ -346,9 +347,13 @@ class TestDeepCategoryHierarchies(TransactionCase):
|
|||
# Attempt to create circular ref may fail
|
||||
try:
|
||||
self.cat_l1.parent_id = self.cat_l5.id # Creates loop
|
||||
except:
|
||||
# Expected: Odoo should prevent circular refs
|
||||
pass
|
||||
except Exception as exc:
|
||||
# Expected: Odoo should prevent circular refs. Log for visibility.
|
||||
import logging
|
||||
|
||||
logging.getLogger(__name__).info(
|
||||
"Expected exception creating circular category: %s", str(exc)
|
||||
)
|
||||
|
||||
|
||||
class TestEmptySourcesDiscovery(TransactionCase):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
from datetime import date
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import _
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tests.common import tagged
|
||||
|
||||
|
|
@ -82,9 +81,7 @@ class TestTemplatesRendering(TransactionCase):
|
|||
def test_day_names_context_is_provided(self):
|
||||
"""Test that day_names context is provided by the controller method."""
|
||||
# Simulate what the controller does, passing env for test context
|
||||
from odoo.addons.website_sale_aplicoop.controllers.website_sale import (
|
||||
AplicoopWebsiteSale,
|
||||
)
|
||||
from ..controllers.website_sale import AplicoopWebsiteSale
|
||||
|
||||
controller = AplicoopWebsiteSale()
|
||||
day_names = controller._get_day_names(env=self.env)
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ class TestUserPartnerValidation(TransactionCase):
|
|||
def test_user_without_partner_cannot_access_order(self):
|
||||
"""Test that user without partner_id has no access to orders."""
|
||||
start_date = datetime.now().date()
|
||||
order = self.env["group.order"].create(
|
||||
self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue