[FIX] website_sale_aplicoop: Remove redundant string= attributes and fix OCA linting warnings

- Remove redundant string= from 17 field definitions where name matches string value (W8113)
- Convert @staticmethod to instance methods in selection methods for proper self.env._() access
- Fix W8161 (prefer-env-translation) by using self.env._() instead of standalone _()
- Fix W8301/W8115 (translation-not-lazy) by proper placement of % interpolation outside self.env._()
- Remove unused imports of odoo._ from group_order.py and sale_order_extension.py
- All OCA linting warnings in website_sale_aplicoop main models are now resolved

Changes:
- website_sale_aplicoop/models/group_order.py: 21 field definitions cleaned
- website_sale_aplicoop/models/sale_order_extension.py: 5 field definitions cleaned + @staticmethod conversion
- Consistent with OCA standards for addon submission
This commit is contained in:
snt 2026-02-18 17:54:43 +01:00
parent 5c89795e30
commit 6fbc7b9456
73 changed files with 5386 additions and 4354 deletions

View file

@ -1,7 +1,7 @@
# Análisis de Cobertura de Tests - website_sale_aplicoop
**Fecha**: 11 de febrero de 2026
**Estado**: ✅ **ACTUALIZADO** - Tests de pricing agregados
**Fecha**: 11 de febrero de 2026
**Estado**: ✅ **ACTUALIZADO** - Tests de pricing agregados
**Última actualización**: Sistema de precios completamente cubierto (16 nuevos tests)
---
@ -310,7 +310,7 @@ Sistema de precios: 0% coverage (CRÍTICO)
Sistema de precios: ~95% coverage (✅ RESUELTO)
```
**Tiempo invertido**: ~2 horas
**Tiempo invertido**: ~2 horas
**ROI**: Alto - Se cubrió funcionalidad crítica de cálculo de precios
---
@ -343,7 +343,7 @@ Si se necesita más cobertura, priorizar en este orden:
---
**Conclusión Final**:
**Conclusión Final**:
✅ **El sistema de precios está completamente testeado y producción-ready.**

View file

@ -13,7 +13,8 @@ Coverage:
- Draft timeline (very old draft, recent draft)
"""
from datetime import datetime, timedelta
from datetime import datetime
from datetime import timedelta
from odoo.tests.common import TransactionCase
@ -23,91 +24,117 @@ class TestSaveDraftOrder(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'email': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"email": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
self.category = self.env['product.category'].create({
'name': 'Test Category',
})
self.category = self.env["product.category"].create(
{
"name": "Test Category",
}
)
self.product1 = self.env['product.product'].create({
'name': 'Product 1',
'type': 'consu',
'list_price': 10.0,
'categ_id': self.category.id,
})
self.product1 = self.env["product.product"].create(
{
"name": "Product 1",
"type": "consu",
"list_price": 10.0,
"categ_id": self.category.id,
}
)
self.product2 = self.env['product.product'].create({
'name': 'Product 2',
'type': 'consu',
'list_price': 20.0,
'categ_id': self.category.id,
})
self.product2 = self.env["product.product"].create(
{
"name": "Product 2",
"type": "consu",
"list_price": 20.0,
"categ_id": self.category.id,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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',
'pickup_date': start_date + timedelta(days=3),
'cutoff_day': '0',
})
self.group_order = self.env["group.order"].create(
{
"name": "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",
"pickup_date": start_date + timedelta(days=3),
"cutoff_day": "0",
}
)
self.group_order.action_open()
self.group_order.product_ids = [(4, self.product1.id), (4, self.product2.id)]
def test_save_draft_with_items(self):
"""Test saving draft order with products."""
draft_order = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
'order_line': [
(0, 0, {
'product_id': self.product1.id,
'product_qty': 2,
'price_unit': self.product1.list_price,
}),
(0, 0, {
'product_id': self.product2.id,
'product_qty': 1,
'price_unit': self.product2.list_price,
}),
],
})
draft_order = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
"order_line": [
(
0,
0,
{
"product_id": self.product1.id,
"product_qty": 2,
"price_unit": self.product1.list_price,
},
),
(
0,
0,
{
"product_id": self.product2.id,
"product_qty": 1,
"price_unit": self.product2.list_price,
},
),
],
}
)
self.assertTrue(draft_order.exists())
self.assertEqual(draft_order.state, 'draft')
self.assertEqual(draft_order.state, "draft")
self.assertEqual(len(draft_order.order_line), 2)
def test_save_draft_empty_order(self):
"""Test saving draft order without items."""
# Edge case: empty draft
empty_draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
'order_line': [],
})
empty_draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
"order_line": [],
}
)
# Should be valid (user hasn't added products yet)
self.assertTrue(empty_draft.exists())
@ -116,15 +143,23 @@ class TestSaveDraftOrder(TransactionCase):
def test_save_draft_updates_existing(self):
"""Test that saving draft updates existing draft, not creates new."""
# Create initial draft
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
'order_line': [(0, 0, {
'product_id': self.product1.id,
'product_qty': 1,
})],
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
"order_line": [
(
0,
0,
{
"product_id": self.product1.id,
"product_qty": 1,
},
)
],
}
)
draft_id = draft.id
@ -132,29 +167,33 @@ class TestSaveDraftOrder(TransactionCase):
draft.order_line[0].product_qty = 5
# Should be same draft, not new one
updated_draft = self.env['sale.order'].browse(draft_id)
updated_draft = self.env["sale.order"].browse(draft_id)
self.assertTrue(updated_draft.exists())
self.assertEqual(updated_draft.order_line[0].product_qty, 5)
def test_save_draft_preserves_group_order_reference(self):
"""Test that group_order_id is preserved when saving."""
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
}
)
# Link must be preserved
self.assertEqual(draft.group_order_id, self.group_order)
def test_save_draft_preserves_pickup_date(self):
"""Test that pickup_date is preserved in draft."""
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'pickup_date': self.group_order.pickup_date,
'state': 'draft',
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"pickup_date": self.group_order.pickup_date,
"state": "draft",
}
)
self.assertEqual(draft.pickup_date, self.group_order.pickup_date)
@ -164,63 +203,83 @@ class TestLoadDraftOrder(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'email': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"email": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
self.product = self.env['product.product'].create({
'name': 'Test Product',
'type': 'consu',
'list_price': 10.0,
})
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"type": "consu",
"list_price": 10.0,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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_load_existing_draft(self):
"""Test loading an existing draft order."""
# Create draft
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
'order_line': [(0, 0, {
'product_id': self.product.id,
'product_qty': 3,
})],
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
"order_line": [
(
0,
0,
{
"product_id": self.product.id,
"product_qty": 3,
},
)
],
}
)
# Load it
loaded = self.env['sale.order'].search([
('id', '=', draft.id),
('partner_id', '=', self.member_partner.id),
('state', '=', 'draft'),
])
loaded = self.env["sale.order"].search(
[
("id", "=", draft.id),
("partner_id", "=", self.member_partner.id),
("state", "=", "draft"),
]
)
self.assertEqual(len(loaded), 1)
self.assertEqual(loaded[0].order_line[0].product_qty, 3)
@ -228,29 +287,37 @@ class TestLoadDraftOrder(TransactionCase):
def test_load_draft_not_visible_to_other_user(self):
"""Test that draft from one user not accessible to another."""
# Create draft for member_partner
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
}
)
# Create another user/partner
other_partner = self.env['res.partner'].create({
'name': 'Other Member',
'email': 'other@test.com',
})
other_partner = self.env["res.partner"].create(
{
"name": "Other Member",
"email": "other@test.com",
}
)
other_user = self.env['res.users'].create({
'name': 'Other User',
'login': 'other@test.com',
'partner_id': other_partner.id,
})
other_user = self.env["res.users"].create(
{
"name": "Other User",
"login": "other@test.com",
"partner_id": other_partner.id,
}
)
# Other user should not see original draft
other_drafts = self.env['sale.order'].search([
('id', '=', draft.id),
('partner_id', '=', other_partner.id),
])
other_drafts = self.env["sale.order"].search(
[
("id", "=", draft.id),
("partner_id", "=", other_partner.id),
]
)
self.assertEqual(len(other_drafts), 0)
@ -260,14 +327,16 @@ class TestLoadDraftOrder(TransactionCase):
self.group_order.action_close()
# Create draft before closure (simulated)
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
}
)
# Draft should still be loadable (but should warn)
loaded = self.env['sale.order'].browse(draft.id)
loaded = self.env["sale.order"].browse(draft.id)
self.assertTrue(loaded.exists())
# Controller should check: group_order.state and warn if closed
@ -277,41 +346,51 @@ class TestDraftConsistency(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
self.product = self.env['product.product'].create({
'name': 'Test Product',
'type': 'consu',
'list_price': 100.0,
})
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"type": "consu",
"list_price": 100.0,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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_draft_price_snapshot(self):
@ -319,16 +398,24 @@ class TestDraftConsistency(TransactionCase):
original_price = self.product.list_price
# Save draft with current price
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
'order_line': [(0, 0, {
'product_id': self.product.id,
'product_qty': 1,
'price_unit': original_price,
})],
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
"order_line": [
(
0,
0,
{
"product_id": self.product.id,
"product_qty": 1,
"price_unit": original_price,
},
)
],
}
)
saved_price = draft.order_line[0].price_unit
@ -342,18 +429,26 @@ class TestDraftConsistency(TransactionCase):
def test_draft_quantity_consistency(self):
"""Test that quantities are preserved across saves."""
# Save draft
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
'order_line': [(0, 0, {
'product_id': self.product.id,
'product_qty': 5,
})],
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
"order_line": [
(
0,
0,
{
"product_id": self.product.id,
"product_qty": 5,
},
)
],
}
)
# Re-load draft
reloaded = self.env['sale.order'].browse(draft.id)
reloaded = self.env["sale.order"].browse(draft.id)
self.assertEqual(reloaded.order_line[0].product_qty, 5)
@ -362,62 +457,80 @@ class TestProductArchivedInDraft(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
self.product = self.env['product.product'].create({
'name': 'Test Product',
'type': 'consu',
'list_price': 10.0,
'active': True,
})
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"type": "consu",
"list_price": 10.0,
"active": True,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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_load_draft_with_archived_product(self):
"""Test loading draft when product has been archived."""
# Create draft with active product
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
'order_line': [(0, 0, {
'product_id': self.product.id,
'product_qty': 2,
})],
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
"order_line": [
(
0,
0,
{
"product_id": self.product.id,
"product_qty": 2,
},
)
],
}
)
# Archive the product
self.product.active = False
# Load draft - should still work (historical data)
loaded = self.env['sale.order'].browse(draft.id)
loaded = self.env["sale.order"].browse(draft.id)
self.assertTrue(loaded.exists())
# But product may not be editable/accessible
@ -427,108 +540,128 @@ class TestDraftTimeline(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.product = self.env['product.product'].create({
'name': 'Test Product',
'type': 'consu',
'list_price': 10.0,
})
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"type": "consu",
"list_price": 10.0,
}
)
def test_draft_from_current_week(self):
"""Test draft from current/open group order."""
start_date = datetime.now().date()
current_order = self.env['group.order'].create({
'name': 'Current 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',
})
current_order = self.env["group.order"].create(
{
"name": "Current 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",
}
)
current_order.action_open()
draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': current_order.id,
'state': 'draft',
})
draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": current_order.id,
"state": "draft",
}
)
# Should be accessible and valid
self.assertTrue(draft.exists())
self.assertEqual(draft.group_order_id.state, 'open')
self.assertEqual(draft.group_order_id.state, "open")
def test_draft_from_old_order_6_months_ago(self):
"""Test draft from order that was 6 months ago."""
old_start = datetime.now().date() - timedelta(days=180)
old_end = old_start + timedelta(days=7)
old_order = self.env['group.order'].create({
'name': 'Old Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': old_start,
'end_date': old_end,
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
old_order = self.env["group.order"].create(
{
"name": "Old Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": old_start,
"end_date": old_end,
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
old_order.action_open()
old_order.action_close()
old_draft = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': old_order.id,
'state': 'draft',
})
old_draft = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": old_order.id,
"state": "draft",
}
)
# Should still exist but be inaccessible (order closed)
self.assertTrue(old_draft.exists())
self.assertEqual(old_order.state, 'closed')
self.assertEqual(old_order.state, "closed")
def test_draft_order_count_for_user(self):
"""Test counting total drafts for a user."""
# Create multiple orders and drafts
orders = []
for i in range(3):
start = datetime.now().date() + timedelta(days=i*7)
order = self.env['group.order'].create({
'name': f'Order {i}',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': start + timedelta(days=7),
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
start = datetime.now().date() + timedelta(days=i * 7)
order = self.env["group.order"].create(
{
"name": f"Order {i}",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": start + timedelta(days=7),
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
order.action_open()
orders.append(order)
# Create draft for each
for order in orders:
self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': order.id,
'state': 'draft',
})
self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": order.id,
"state": "draft",
}
)
# Count drafts for user
user_drafts = self.env['sale.order'].search([
('partner_id', '=', self.member_partner.id),
('state', '=', 'draft'),
])
user_drafts = self.env["sale.order"].search(
[
("partner_id", "=", self.member_partner.id),
("state", "=", "draft"),
]
)
self.assertEqual(len(user_drafts), 3)

View file

@ -13,11 +13,13 @@ Coverage:
- Extreme dates (year 1900, year 2099)
"""
from datetime import datetime, timedelta, date
from datetime import date
from datetime import timedelta
from dateutil.relativedelta import relativedelta
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestLeapYearHandling(TransactionCase):
@ -25,10 +27,12 @@ class TestLeapYearHandling(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
def test_order_spans_leap_day(self):
"""Test order that includes Feb 29 (leap year)."""
@ -36,16 +40,18 @@ class TestLeapYearHandling(TransactionCase):
start = date(2024, 2, 25)
end = date(2024, 3, 3) # Spans Feb 29
order = self.env['group.order'].create({
'name': 'Leap Year Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '2', # Wednesday (Feb 28 or 29 depending on week)
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Leap Year Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "2", # Wednesday (Feb 28 or 29 depending on week)
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
# Should correctly calculate pickup date
@ -57,16 +63,18 @@ class TestLeapYearHandling(TransactionCase):
start = date(2024, 2, 26) # Monday
end = date(2024, 3, 3)
order = self.env['group.order'].create({
'name': 'Feb 29 Pickup',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '3', # Thursday = Feb 29
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Feb 29 Pickup",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "3", # Thursday = Feb 29
"cutoff_day": "0",
}
)
self.assertEqual(order.pickup_date, date(2024, 2, 29))
@ -76,16 +84,18 @@ class TestLeapYearHandling(TransactionCase):
start = date(2023, 2, 25)
end = date(2023, 3, 3)
order = self.env['group.order'].create({
'name': 'Non-Leap Year Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '2',
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Non-Leap Year Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "2",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
# Pickup should be Feb 28 (last day of Feb)
@ -97,26 +107,30 @@ class TestLongDurationOrders(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
def test_order_spans_entire_year(self):
"""Test order running for 365 days."""
start = date(2024, 1, 1)
end = date(2024, 12, 31)
order = self.env['group.order'].create({
'name': 'Year-Long Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '3', # Same day each week
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Year-Long Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "3", # Same day each week
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
# Should handle 52+ weeks correctly
@ -128,16 +142,18 @@ class TestLongDurationOrders(TransactionCase):
start = date(2024, 1, 1)
end = date(2026, 12, 31) # 3 years
order = self.env['group.order'].create({
'name': 'Multi-Year Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'monthly',
'pickup_day': '15',
'cutoff_day': '10',
})
order = self.env["group.order"].create(
{
"name": "Multi-Year Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "monthly",
"pickup_day": "15",
"cutoff_day": "10",
}
)
self.assertTrue(order.exists())
days_diff = (end - start).days
@ -147,16 +163,18 @@ class TestLongDurationOrders(TransactionCase):
"""Test order with start_date == end_date (single day)."""
same_day = date(2024, 2, 15)
order = self.env['group.order'].create({
'name': 'One-Day Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'once',
'start_date': same_day,
'end_date': same_day,
'period': 'once',
'pickup_day': '0',
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "One-Day Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "once",
"start_date": same_day,
"end_date": same_day,
"period": "once",
"pickup_day": "0",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
@ -166,10 +184,12 @@ class TestPickupDayBoundary(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
def test_pickup_day_same_as_start_date(self):
"""Test when pickup_day equals start date (today)."""
@ -177,16 +197,18 @@ class TestPickupDayBoundary(TransactionCase):
start = today
end = today + timedelta(days=7)
order = self.env['group.order'].create({
'name': 'Today Pickup',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': str(start.weekday()), # Same as start
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Today Pickup",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": str(start.weekday()), # Same as start
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
# Pickup should be today
@ -198,16 +220,18 @@ class TestPickupDayBoundary(TransactionCase):
start = date(2024, 1, 24)
end = date(2024, 2, 1)
order = self.env['group.order'].create({
'name': 'Month-End Pickup',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'once',
'pickup_day': '2', # Wednesday = Jan 31
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Month-End Pickup",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "once",
"pickup_day": "2", # Wednesday = Jan 31
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
@ -217,16 +241,18 @@ class TestPickupDayBoundary(TransactionCase):
start = date(2024, 1, 28)
end = date(2024, 2, 5)
order = self.env['group.order'].create({
'name': 'Month Boundary Pickup',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '4', # Friday (Feb 2)
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Month Boundary Pickup",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "4", # Friday (Feb 2)
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
# Pickup should be in Feb
@ -238,16 +264,18 @@ class TestPickupDayBoundary(TransactionCase):
end = date(2024, 1, 8)
for day_num in range(7):
order = self.env['group.order'].create({
'name': f'Pickup Day {day_num}',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': str(day_num),
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": f"Pickup Day {day_num}",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": str(day_num),
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
# Each should have valid pickup_date
@ -259,10 +287,12 @@ class TestFutureStartDateOrders(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
def test_order_starts_tomorrow(self):
"""Test order starting tomorrow."""
@ -270,16 +300,18 @@ class TestFutureStartDateOrders(TransactionCase):
start = today + timedelta(days=1)
end = start + timedelta(days=7)
order = self.env['group.order'].create({
'name': 'Future Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Future Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
self.assertGreater(order.start_date, today)
@ -290,16 +322,18 @@ class TestFutureStartDateOrders(TransactionCase):
start = today + relativedelta(months=6)
end = start + timedelta(days=30)
order = self.env['group.order'].create({
'name': 'Far Future Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'monthly',
'pickup_day': '15',
'cutoff_day': '10',
})
order = self.env["group.order"].create(
{
"name": "Far Future Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "monthly",
"pickup_day": "15",
"cutoff_day": "10",
}
)
self.assertTrue(order.exists())
@ -309,26 +343,30 @@ class TestExtremeDate(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
def test_order_year_2000(self):
"""Test order in year 2000 (Y2K edge case)."""
start = date(2000, 1, 1)
end = date(2000, 12, 31)
order = self.env['group.order'].create({
'name': 'Y2K Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Y2K Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
@ -337,16 +375,18 @@ class TestExtremeDate(TransactionCase):
start = date(2099, 1, 1)
end = date(2099, 12, 31)
order = self.env['group.order'].create({
'name': 'Far Future Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Far Future Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
@ -355,16 +395,18 @@ class TestExtremeDate(TransactionCase):
start = date(1999, 12, 26)
end = date(2000, 1, 2)
order = self.env['group.order'].create({
'name': 'Century Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '6', # Saturday
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Century Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "6", # Saturday
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
# Should handle date arithmetic correctly across years
@ -377,25 +419,29 @@ class TestOrderWithoutEndDate(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
def test_permanent_order_with_null_end_date(self):
"""Test order with end_date = NULL (ongoing order)."""
start = date.today()
order = self.env['group.order'].create({
'name': 'Permanent Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': False, # No end date
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Permanent Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": False, # No end date
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
# If supported, should handle gracefully
# Otherwise, may be optional validation
@ -406,10 +452,12 @@ class TestPickupCalculationAccuracy(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
def test_pickup_date_calculation_multiple_weeks(self):
"""Test pickup_date calculation over multiple weeks."""
@ -417,16 +465,18 @@ class TestPickupCalculationAccuracy(TransactionCase):
start = date(2024, 1, 1)
end = date(2024, 1, 22)
order = self.env['group.order'].create({
'name': 'Multi-Week Pickup',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'weekly',
'pickup_day': '3', # Thursday
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Multi-Week Pickup",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "weekly",
"pickup_day": "3", # Thursday
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
# First pickup should be first Thursday on or after start
@ -438,16 +488,18 @@ class TestPickupCalculationAccuracy(TransactionCase):
start = date(2024, 2, 1)
end = date(2024, 3, 31)
order = self.env['group.order'].create({
'name': 'Monthly Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start,
'end_date': end,
'period': 'monthly',
'pickup_day': '15',
'cutoff_day': '10',
})
order = self.env["group.order"].create(
{
"name": "Monthly Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start,
"end_date": end,
"period": "monthly",
"pickup_day": "15",
"cutoff_day": "10",
}
)
self.assertTrue(order.exists())
# First pickup should be Feb 15

View file

@ -16,11 +16,13 @@ Coverage:
- /eskaera/labels (GET) - Get translated labels
"""
from datetime import datetime, timedelta
import json
from datetime import datetime
from datetime import timedelta
from odoo.tests.common import TransactionCase, HttpCase
from odoo.exceptions import ValidationError, AccessError
from odoo.exceptions import AccessError
from odoo.exceptions import ValidationError
from odoo.tests.common import HttpCase
from odoo.tests.common import TransactionCase
class TestEskaearaListEndpoint(TransactionCase):
@ -28,63 +30,75 @@ class TestEskaearaListEndpoint(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
'email': 'group@test.com',
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
"email": "group@test.com",
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'email': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"email": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
# Create multiple group orders (some open, some closed)
start_date = datetime.now().date()
self.open_order = self.env['group.order'].create({
'name': 'Open 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.open_order = self.env["group.order"].create(
{
"name": "Open 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.open_order.action_open()
self.draft_order = self.env['group.order'].create({
'name': 'Draft Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start_date - timedelta(days=14),
'end_date': start_date - timedelta(days=7),
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
self.draft_order = self.env["group.order"].create(
{
"name": "Draft Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start_date - timedelta(days=14),
"end_date": start_date - timedelta(days=7),
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
# Stay in draft
self.closed_order = self.env['group.order'].create({
'name': 'Closed Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start_date - timedelta(days=21),
'end_date': start_date - timedelta(days=14),
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
self.closed_order = self.env["group.order"].create(
{
"name": "Closed Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start_date - timedelta(days=21),
"end_date": start_date - timedelta(days=14),
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
self.closed_order.action_open()
self.closed_order.action_close()
@ -92,10 +106,12 @@ class TestEskaearaListEndpoint(TransactionCase):
"""Test that /eskaera shows only open/draft orders, not closed."""
# In controller context, only open and draft should be visible to members
# This is business logic: closed orders are historical
visible_orders = self.env['group.order'].search([
('state', 'in', ['open', 'draft']),
('group_ids', 'in', self.group.id),
])
visible_orders = self.env["group.order"].search(
[
("state", "in", ["open", "draft"]),
("group_ids", "in", self.group.id),
]
)
self.assertIn(self.open_order, visible_orders)
self.assertIn(self.draft_order, visible_orders)
@ -103,30 +119,36 @@ class TestEskaearaListEndpoint(TransactionCase):
def test_eskaera_list_filters_by_user_groups(self):
"""Test that user only sees orders from their groups."""
other_group = self.env['res.partner'].create({
'name': 'Other Group',
'is_company': True,
'email': 'other@test.com',
})
other_group = self.env["res.partner"].create(
{
"name": "Other Group",
"is_company": True,
"email": "other@test.com",
}
)
other_order = self.env['group.order'].create({
'name': 'Other Group Order',
'group_ids': [(6, 0, [other_group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': datetime.now().date() + timedelta(days=7),
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
other_order = self.env["group.order"].create(
{
"name": "Other Group Order",
"group_ids": [(6, 0, [other_group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": datetime.now().date() + timedelta(days=7),
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
other_order.action_open()
# User should not see orders from groups they're not in
user_groups = self.member_partner.group_ids
visible_orders = self.env['group.order'].search([
('state', 'in', ['open', 'draft']),
('group_ids', 'in', user_groups.ids),
])
visible_orders = self.env["group.order"].search(
[
("state", "in", ["open", "draft"]),
("group_ids", "in", user_groups.ids),
]
)
self.assertNotIn(other_order, visible_orders)
@ -136,61 +158,75 @@ class TestAddToCartEndpoint(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
'email': 'group@test.com',
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
"email": "group@test.com",
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'email': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"email": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
self.category = self.env['product.category'].create({
'name': 'Test Category',
})
self.category = self.env["product.category"].create(
{
"name": "Test Category",
}
)
# Published product
self.product = self.env['product.product'].create({
'name': 'Test Product',
'type': 'consu',
'list_price': 10.0,
'categ_id': self.category.id,
'sale_ok': True,
'is_published': True,
})
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"type": "consu",
"list_price": 10.0,
"categ_id": self.category.id,
"sale_ok": True,
"is_published": True,
}
)
# Unpublished product (should not be available)
self.unpublished_product = self.env['product.product'].create({
'name': 'Unpublished Product',
'type': 'consu',
'list_price': 15.0,
'categ_id': self.category.id,
'sale_ok': False,
'is_published': False,
})
self.unpublished_product = self.env["product.product"].create(
{
"name": "Unpublished Product",
"type": "consu",
"list_price": 15.0,
"categ_id": self.category.id,
"sale_ok": False,
"is_published": False,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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()
self.group_order.product_ids = [(4, self.product.id)]
@ -198,13 +234,13 @@ class TestAddToCartEndpoint(TransactionCase):
"""Test adding published product to cart."""
# Simulate controller logic
cart_line = {
'product_id': self.product.id,
'quantity': 2,
'group_order_id': self.group_order.id,
'partner_id': self.member_partner.id,
"product_id": self.product.id,
"quantity": 2,
"group_order_id": self.group_order.id,
"partner_id": self.member_partner.id,
}
# Should succeed
self.assertTrue(cart_line['product_id'])
self.assertTrue(cart_line["product_id"])
def test_add_to_cart_zero_quantity(self):
"""Test that adding zero quantity is rejected."""
@ -228,11 +264,13 @@ class TestAddToCartEndpoint(TransactionCase):
def test_add_to_cart_product_not_in_order(self):
"""Test that products not in the order cannot be added."""
# Create a product NOT associated with group_order
other_product = self.env['product.product'].create({
'name': 'Other Product',
'type': 'consu',
'list_price': 25.0,
})
other_product = self.env["product.product"].create(
{
"name": "Other Product",
"type": "consu",
"list_price": 25.0,
}
)
# Controller should check: product in group_order.product_ids
self.assertNotIn(other_product, self.group_order.product_ids)
@ -241,7 +279,7 @@ class TestAddToCartEndpoint(TransactionCase):
"""Test that adding to closed order is rejected."""
self.group_order.action_close()
# Controller should check: order.state == 'open'
self.assertEqual(self.group_order.state, 'closed')
self.assertEqual(self.group_order.state, "closed")
class TestCheckoutEndpoint(TransactionCase):
@ -249,38 +287,46 @@ class TestCheckoutEndpoint(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
'email': 'group@test.com',
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
"email": "group@test.com",
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'email': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"email": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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',
'pickup_date': start_date + timedelta(days=3),
'cutoff_day': '0',
})
self.group_order = self.env["group.order"].create(
{
"name": "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",
"pickup_date": start_date + timedelta(days=3),
"cutoff_day": "0",
}
)
self.group_order.action_open()
def test_checkout_page_loads(self):
@ -301,16 +347,18 @@ class TestCheckoutEndpoint(TransactionCase):
def test_checkout_order_without_products(self):
"""Test checkout when no products available."""
# Order with empty product_ids
empty_order = self.env['group.order'].create({
'name': 'Empty Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': datetime.now().date() + timedelta(days=7),
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
empty_order = self.env["group.order"].create(
{
"name": "Empty Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": datetime.now().date() + timedelta(days=7),
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
empty_order.action_open()
# Should handle gracefully
@ -322,95 +370,115 @@ class TestConfirmOrderEndpoint(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
'email': 'group@test.com',
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
"email": "group@test.com",
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'email': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"email": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
self.category = self.env['product.category'].create({
'name': 'Test Category',
})
self.category = self.env["product.category"].create(
{
"name": "Test Category",
}
)
self.product = self.env['product.product'].create({
'name': 'Test Product',
'type': 'consu',
'list_price': 10.0,
'categ_id': self.category.id,
})
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"type": "consu",
"list_price": 10.0,
"categ_id": self.category.id,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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',
'pickup_date': start_date + timedelta(days=3),
'cutoff_day': '0',
})
self.group_order = self.env["group.order"].create(
{
"name": "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",
"pickup_date": start_date + timedelta(days=3),
"cutoff_day": "0",
}
)
self.group_order.action_open()
self.group_order.product_ids = [(4, self.product.id)]
# Create a draft sale order
self.draft_sale = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'pickup_date': self.group_order.pickup_date,
'state': 'draft',
})
self.draft_sale = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"pickup_date": self.group_order.pickup_date,
"state": "draft",
}
)
def test_confirm_order_creates_sale_order(self):
"""Test that confirming creates a confirmed sale.order."""
# Controller should change state from draft to sale
self.draft_sale.action_confirm()
self.assertEqual(self.draft_sale.state, 'sale')
self.assertEqual(self.draft_sale.state, "sale")
def test_confirm_empty_order(self):
"""Test confirming order without items fails."""
# Order with no order_lines should fail
empty_sale = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
})
empty_sale = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
}
)
# Should validate: must have at least one line
self.assertEqual(len(empty_sale.order_line), 0)
def test_confirm_order_wrong_group(self):
"""Test that user cannot confirm order from different group."""
other_group = self.env['res.partner'].create({
'name': 'Other Group',
'is_company': True,
})
other_group = self.env["res.partner"].create(
{
"name": "Other Group",
"is_company": True,
}
)
other_order = self.env['group.order'].create({
'name': 'Other Order',
'group_ids': [(6, 0, [other_group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': datetime.now().date() + timedelta(days=7),
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
other_order = self.env["group.order"].create(
{
"name": "Other Order",
"group_ids": [(6, 0, [other_group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": datetime.now().date() + timedelta(days=7),
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
# User should not be in other_group
self.assertNotIn(self.member_partner, other_group.member_ids)
@ -421,76 +489,94 @@ class TestLoadDraftEndpoint(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
'email': 'group@test.com',
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
"email": "group@test.com",
}
)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member",
"email": "member@test.com",
}
)
self.group.member_ids = [(4, self.member_partner.id)]
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'email': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"email": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
self.category = self.env['product.category'].create({
'name': 'Test Category',
})
self.category = self.env["product.category"].create(
{
"name": "Test Category",
}
)
self.product = self.env['product.product'].create({
'name': 'Test Product',
'type': 'consu',
'list_price': 10.0,
'categ_id': self.category.id,
})
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"type": "consu",
"list_price": 10.0,
"categ_id": self.category.id,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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',
'pickup_date': start_date + timedelta(days=3),
'cutoff_day': '0',
})
self.group_order = self.env["group.order"].create(
{
"name": "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",
"pickup_date": start_date + timedelta(days=3),
"cutoff_day": "0",
}
)
self.group_order.action_open()
self.group_order.product_ids = [(4, self.product.id)]
def test_load_draft_from_history(self):
"""Test loading a previous draft order."""
# Create old draft sale
old_sale = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
})
old_sale = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
}
)
# Should be able to load
self.assertTrue(old_sale.exists())
def test_load_draft_not_owned_by_user(self):
"""Test that user cannot load draft from other user."""
other_partner = self.env['res.partner'].create({
'name': 'Other Member',
'email': 'other@test.com',
})
other_partner = self.env["res.partner"].create(
{
"name": "Other Member",
"email": "other@test.com",
}
)
other_sale = self.env['sale.order'].create({
'partner_id': other_partner.id,
'group_order_id': self.group_order.id,
'state': 'draft',
})
other_sale = self.env["sale.order"].create(
{
"partner_id": other_partner.id,
"group_order_id": self.group_order.id,
"state": "draft",
}
)
# User should not be able to load other's draft
self.assertNotEqual(other_sale.partner_id, self.member_partner)
@ -500,24 +586,28 @@ class TestLoadDraftEndpoint(TransactionCase):
old_start = datetime.now().date() - timedelta(days=30)
old_end = datetime.now().date() - timedelta(days=23)
expired_order = self.env['group.order'].create({
'name': 'Expired Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': old_start,
'end_date': old_end,
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
expired_order = self.env["group.order"].create(
{
"name": "Expired Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": old_start,
"end_date": old_end,
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
expired_order.action_open()
expired_order.action_close()
old_sale = self.env['sale.order'].create({
'partner_id': self.member_partner.id,
'group_order_id': expired_order.id,
'state': 'draft',
})
old_sale = self.env["sale.order"].create(
{
"partner_id": self.member_partner.id,
"group_order_id": expired_order.id,
"state": "draft",
}
)
# Should warn: order expired
self.assertEqual(expired_order.state, 'closed')
self.assertEqual(expired_order.state, "closed")

View file

@ -1,127 +1,158 @@
# Copyright 2025 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from datetime import datetime, timedelta
from datetime import datetime
from datetime import timedelta
from odoo.tests.common import TransactionCase
class TestEskaerShop(TransactionCase):
'''Test suite para la lógica de eskaera_shop (descubrimiento de productos).'''
"""Test suite para la lógica de eskaera_shop (descubrimiento de productos)."""
def setUp(self):
super().setUp()
# Crear un grupo (res.partner)
self.group = self.env['res.partner'].create({
'name': 'Grupo Test Eskaera',
'is_company': True,
'email': 'grupo@test.com',
})
self.group = self.env["res.partner"].create(
{
"name": "Grupo Test Eskaera",
"is_company": True,
"email": "grupo@test.com",
}
)
# Crear usuario miembro del grupo
user_partner = self.env['res.partner'].create({
'name': 'Usuario Test Partner',
'email': 'usuario_test@test.com',
})
user_partner = self.env["res.partner"].create(
{
"name": "Usuario Test Partner",
"email": "usuario_test@test.com",
}
)
self.user = self.env['res.users'].create({
'name': 'Usuario Test',
'login': 'usuario_test@test.com',
'email': 'usuario_test@test.com',
'partner_id': user_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Usuario Test",
"login": "usuario_test@test.com",
"email": "usuario_test@test.com",
"partner_id": user_partner.id,
}
)
# Añadir el partner del usuario como miembro del grupo
self.group.member_ids = [(4, user_partner.id)]
# Crear categorías de producto
self.category1 = self.env['product.category'].create({
'name': 'Categoría Test 1',
})
self.category1 = self.env["product.category"].create(
{
"name": "Categoría Test 1",
}
)
self.category2 = self.env['product.category'].create({
'name': 'Categoría Test 2',
})
self.category2 = self.env["product.category"].create(
{
"name": "Categoría Test 2",
}
)
# Crear proveedor
self.supplier = self.env['res.partner'].create({
'name': 'Proveedor Test',
'is_company': True,
'supplier_rank': 1,
'email': 'proveedor@test.com',
})
self.supplier = self.env["res.partner"].create(
{
"name": "Proveedor Test",
"is_company": True,
"supplier_rank": 1,
"email": "proveedor@test.com",
}
)
# Crear productos
self.product_cat1 = self.env['product.product'].create({
'name': 'Producto Categoría 1',
'type': 'consu',
'list_price': 10.0,
'categ_id': self.category1.id,
'active': True,
})
self.product_cat1.product_tmpl_id.write({
'is_published': True,
'sale_ok': True,
})
self.product_cat1 = self.env["product.product"].create(
{
"name": "Producto Categoría 1",
"type": "consu",
"list_price": 10.0,
"categ_id": self.category1.id,
"active": True,
}
)
self.product_cat1.product_tmpl_id.write(
{
"is_published": True,
"sale_ok": True,
}
)
self.product_cat2 = self.env['product.product'].create({
'name': 'Producto Categoría 2',
'type': 'consu',
'list_price': 20.0,
'categ_id': self.category2.id,
'active': True,
})
self.product_cat2.product_tmpl_id.write({
'is_published': True,
'sale_ok': True,
})
self.product_cat2 = self.env["product.product"].create(
{
"name": "Producto Categoría 2",
"type": "consu",
"list_price": 20.0,
"categ_id": self.category2.id,
"active": True,
}
)
self.product_cat2.product_tmpl_id.write(
{
"is_published": True,
"sale_ok": True,
}
)
# Crear producto con relación a proveedor
self.product_supplier_template = self.env['product.template'].create({
'name': 'Producto Proveedor',
'type': 'consu',
'list_price': 30.0,
'categ_id': self.category1.id,
'is_published': True,
'sale_ok': True,
})
self.product_supplier_template = self.env["product.template"].create(
{
"name": "Producto Proveedor",
"type": "consu",
"list_price": 30.0,
"categ_id": self.category1.id,
"is_published": True,
"sale_ok": True,
}
)
self.product_supplier = self.product_supplier_template.product_variant_ids[0]
self.product_supplier.active = True
# Crear relación con proveedor
self.env['product.supplierinfo'].create({
'product_tmpl_id': self.product_supplier_template.id,
'partner_id': self.supplier.id,
'min_qty': 1.0,
})
self.env["product.supplierinfo"].create(
{
"product_tmpl_id": self.product_supplier_template.id,
"partner_id": self.supplier.id,
"min_qty": 1.0,
}
)
self.product_direct = self.env['product.product'].create({
'name': 'Producto Directo',
'type': 'consu',
'list_price': 40.0,
'categ_id': self.category1.id,
'active': True,
})
self.product_direct.product_tmpl_id.write({
'is_published': True,
'sale_ok': True,
})
self.product_direct = self.env["product.product"].create(
{
"name": "Producto Directo",
"type": "consu",
"list_price": 40.0,
"categ_id": self.category1.id,
"active": True,
}
)
self.product_direct.product_tmpl_id.write(
{
"is_published": True,
"sale_ok": True,
}
)
def test_product_discovery_direct(self):
'''Test que los productos directos se descubren correctamente.'''
order = self.env['group.order'].create({
'name': 'Pedido Directo',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
'product_ids': [(6, 0, [self.product_direct.id])],
})
"""Test que los productos directos se descubren correctamente."""
order = self.env["group.order"].create(
{
"name": "Pedido Directo",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
"product_ids": [(6, 0, [self.product_direct.id])],
}
)
order.action_open()
@ -131,96 +162,124 @@ class TestEskaerShop(TransactionCase):
self.assertEqual(len(products), 1)
self.assertIn(self.product_direct, products)
products = self.env['product.product']._get_products_for_group_order(order.id)
self.assertIn(self.product_direct.product_tmpl_id, products.mapped('product_tmpl_id'))
products = self.env["product.product"]._get_products_for_group_order(order.id)
self.assertIn(
self.product_direct.product_tmpl_id, products.mapped("product_tmpl_id")
)
def test_product_discovery_by_category(self):
'''Test que los productos se descubren por categoría cuando no hay directos.'''
order = self.env['group.order'].create({
'name': 'Pedido por Categoría',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
'category_ids': [(6, 0, [self.category1.id])],
})
"""Test que los productos se descubren por categoría cuando no hay directos."""
order = self.env["group.order"].create(
{
"name": "Pedido por Categoría",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
"category_ids": [(6, 0, [self.category1.id])],
}
)
order.action_open()
# Simular lo que hace eskaera_shop (fallback a categorías)
products = order.product_ids
if not products:
products = self.env['product.product'].search([
('categ_id', 'in', order.category_ids.ids),
])
products = self.env["product.product"].search(
[
("categ_id", "in", order.category_ids.ids),
]
)
# Debe incluir todos los productos de la categoría 1
self.assertGreaterEqual(len(products), 2)
self.assertIn(self.product_cat1.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertIn(self.product_supplier.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertIn(self.product_direct.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertIn(
self.product_cat1.product_tmpl_id, products.mapped("product_tmpl_id")
)
self.assertIn(
self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
)
self.assertIn(
self.product_direct.product_tmpl_id, products.mapped("product_tmpl_id")
)
order.write({'category_ids': [(4, self.category1.id)]})
products = self.env['product.product']._get_products_for_group_order(order.id)
self.assertIn(self.product_cat1.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertNotIn(self.product_cat2.product_tmpl_id, products.mapped('product_tmpl_id'))
order.write({"category_ids": [(4, self.category1.id)]})
products = self.env["product.product"]._get_products_for_group_order(order.id)
self.assertIn(
self.product_cat1.product_tmpl_id, products.mapped("product_tmpl_id")
)
self.assertNotIn(
self.product_cat2.product_tmpl_id, products.mapped("product_tmpl_id")
)
def test_product_discovery_by_supplier(self):
'''Test que los productos se descubren por proveedor cuando no hay directos ni categorías.'''
order = self.env['group.order'].create({
'name': 'Pedido por Proveedor',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
'supplier_ids': [(6, 0, [self.supplier.id])],
})
"""Test que los productos se descubren por proveedor cuando no hay directos ni categorías."""
order = self.env["group.order"].create(
{
"name": "Pedido por Proveedor",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
"supplier_ids": [(6, 0, [self.supplier.id])],
}
)
order.action_open()
# Simular lo que hace eskaera_shop (fallback a proveedores)
products = order.product_ids
if not products and order.category_ids:
products = self.env['product.product'].search([
('categ_id', 'in', order.category_ids.ids),
])
products = self.env["product.product"].search(
[
("categ_id", "in", order.category_ids.ids),
]
)
if not products and order.supplier_ids:
# Buscar productos que tienen estos proveedores en seller_ids
product_templates = self.env['product.template'].search([
('seller_ids.partner_id', 'in', order.supplier_ids.ids),
])
products = product_templates.mapped('product_variant_ids')
product_templates = self.env["product.template"].search(
[
("seller_ids.partner_id", "in", order.supplier_ids.ids),
]
)
products = product_templates.mapped("product_variant_ids")
# Debe incluir el producto del proveedor
self.assertEqual(len(products), 1)
self.assertIn(self.product_supplier.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertIn(
self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
)
order.write({'supplier_ids': [(4, self.supplier.id)]})
products = self.env['product.product']._get_products_for_group_order(order.id)
self.assertIn(self.product_supplier.product_tmpl_id, products.mapped('product_tmpl_id'))
order.write({"supplier_ids": [(4, self.supplier.id)]})
products = self.env["product.product"]._get_products_for_group_order(order.id)
self.assertIn(
self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
)
def test_product_discovery_priority(self):
'''Test que la prioridad de descubrimiento es: directos > categorías > proveedores.'''
order = self.env['group.order'].create({
'name': 'Pedido con Todos',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
'product_ids': [(6, 0, [self.product_direct.id])],
'category_ids': [(6, 0, [self.category1.id, self.category2.id])],
'supplier_ids': [(6, 0, [self.supplier.id])],
})
"""Test que la prioridad de descubrimiento es: directos > categorías > proveedores."""
order = self.env["group.order"].create(
{
"name": "Pedido con Todos",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
"product_ids": [(6, 0, [self.product_direct.id])],
"category_ids": [(6, 0, [self.category1.id, self.category2.id])],
"supplier_ids": [(6, 0, [self.supplier.id])],
}
)
order.action_open()
@ -229,94 +288,122 @@ class TestEskaerShop(TransactionCase):
# Debe retornar los productos directos, no los de categoría/proveedor
self.assertEqual(len(products), 1)
self.assertIn(self.product_direct.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertNotIn(self.product_cat1.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertNotIn(self.product_cat2.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertNotIn(self.product_supplier.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertIn(
self.product_direct.product_tmpl_id, products.mapped("product_tmpl_id")
)
self.assertNotIn(
self.product_cat1.product_tmpl_id, products.mapped("product_tmpl_id")
)
self.assertNotIn(
self.product_cat2.product_tmpl_id, products.mapped("product_tmpl_id")
)
self.assertNotIn(
self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
)
# 2. The canonical helper now returns the UNION of all association
# sources (direct products, categories, suppliers). Assert all are
# present to reflect the new behaviour.
products = self.env['product.product']._get_products_for_group_order(order.id)
tmpl_ids = products.mapped('product_tmpl_id')
products = self.env["product.product"]._get_products_for_group_order(order.id)
tmpl_ids = products.mapped("product_tmpl_id")
self.assertIn(self.product_direct.product_tmpl_id, tmpl_ids)
self.assertIn(self.product_cat1.product_tmpl_id, tmpl_ids)
self.assertIn(self.product_supplier.product_tmpl_id, tmpl_ids)
def test_product_discovery_fallback_from_category_to_supplier(self):
'''Test que si no hay directos ni categorías, usa proveedores.'''
order = self.env['group.order'].create({
'name': 'Pedido Fallback',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
# Sin product_ids
# Sin category_ids
'supplier_ids': [(6, 0, [self.supplier.id])],
})
"""Test que si no hay directos ni categorías, usa proveedores."""
order = self.env["group.order"].create(
{
"name": "Pedido Fallback",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
# Sin product_ids
# Sin category_ids
"supplier_ids": [(6, 0, [self.supplier.id])],
}
)
order.action_open()
# Simular lo que hace eskaera_shop
products = order.product_ids
if not products and order.category_ids:
products = self.env['product.product'].search([
('categ_id', 'in', order.category_ids.ids),
])
products = self.env["product.product"].search(
[
("categ_id", "in", order.category_ids.ids),
]
)
if not products and order.supplier_ids:
# Buscar productos que tienen estos proveedores en seller_ids
product_templates = self.env['product.template'].search([
('seller_ids.partner_id', 'in', order.supplier_ids.ids),
])
products = product_templates.mapped('product_variant_ids')
product_templates = self.env["product.template"].search(
[
("seller_ids.partner_id", "in", order.supplier_ids.ids),
]
)
products = product_templates.mapped("product_variant_ids")
# Debe retornar productos del proveedor
self.assertEqual(len(products), 1)
self.assertIn(self.product_supplier.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertIn(
self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
)
# Clear categories so supplier-only fallback remains active
order.write({
'category_ids': [(5, 0, 0)],
'supplier_ids': [(4, self.supplier.id)],
})
products = self.env['product.product']._get_products_for_group_order(order.id)
self.assertIn(self.product_supplier.product_tmpl_id, products.mapped('product_tmpl_id'))
self.assertNotIn(self.product_direct.product_tmpl_id, products.mapped('product_tmpl_id'))
order.write(
{
"category_ids": [(5, 0, 0)],
"supplier_ids": [(4, self.supplier.id)],
}
)
products = self.env["product.product"]._get_products_for_group_order(order.id)
self.assertIn(
self.product_supplier.product_tmpl_id, products.mapped("product_tmpl_id")
)
self.assertNotIn(
self.product_direct.product_tmpl_id, products.mapped("product_tmpl_id")
)
def test_no_products_available(self):
'''Test que retorna vacío si no hay productos definidos de ninguna forma.'''
order = self.env['group.order'].create({
'name': 'Pedido Sin Productos',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
# Sin product_ids, category_ids, supplier_ids
})
"""Test que retorna vacío si no hay productos definidos de ninguna forma."""
order = self.env["group.order"].create(
{
"name": "Pedido Sin Productos",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
# Sin product_ids, category_ids, supplier_ids
}
)
order.action_open()
# Simular lo que hace eskaera_shop
products = order.product_ids
if not products and order.category_ids:
products = self.env['product.product'].search([
('categ_id', 'in', order.category_ids.ids),
])
products = self.env["product.product"].search(
[
("categ_id", "in", order.category_ids.ids),
]
)
if not products and order.supplier_ids:
# Buscar productos que tienen estos proveedores en seller_ids
product_templates = self.env['product.template'].search([
('seller_ids.partner_id', 'in', order.supplier_ids.ids),
])
products = product_templates.mapped('product_variant_ids')
product_templates = self.env["product.template"].search(
[
("seller_ids.partner_id", "in", order.supplier_ids.ids),
]
)
products = product_templates.mapped("product_variant_ids")
# Debe estar vacío
self.assertEqual(len(products), 0)

View file

@ -1,310 +1,354 @@
# Copyright 2025 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from datetime import datetime, timedelta
from datetime import datetime
from datetime import timedelta
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError
from psycopg2 import IntegrityError
from odoo import fields
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestGroupOrder(TransactionCase):
'''Test suite para el modelo group.order.'''
"""Test suite para el modelo group.order."""
def setUp(self):
super().setUp()
# Crear un grupo (res.partner)
self.group = self.env['res.partner'].create({
'name': 'Grupo Test',
'is_company': True,
'email': 'grupo@test.com',
})
self.group = self.env["res.partner"].create(
{
"name": "Grupo Test",
"is_company": True,
"email": "grupo@test.com",
}
)
# Crear productos
self.product1 = self.env['product.product'].create({
'name': 'Producto Test 1',
'type': 'consu',
'list_price': 10.0,
})
self.product1 = self.env["product.product"].create(
{
"name": "Producto Test 1",
"type": "consu",
"list_price": 10.0,
}
)
self.product2 = self.env['product.product'].create({
'name': 'Producto Test 2',
'type': 'consu',
'list_price': 20.0,
})
self.product2 = self.env["product.product"].create(
{
"name": "Producto Test 2",
"type": "consu",
"list_price": 20.0,
}
)
def test_create_group_order(self):
'''Test crear un pedido de grupo.'''
order = self.env['group.order'].create({
'name': 'Pedido Semanal Test',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
"""Test crear un pedido de grupo."""
order = self.env["group.order"].create(
{
"name": "Pedido Semanal Test",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
self.assertEqual(order.state, 'draft')
self.assertEqual(order.state, "draft")
self.assertIn(self.group, order.group_ids)
def test_group_order_dates_validation(self):
""" Test that start_date must be before end_date """
"""Test that start_date must be before end_date"""
with self.assertRaises(ValidationError):
self.env['group.order'].create({
'name': 'Pedido Invalid',
'start_date': fields.Date.today() + timedelta(days=7),
'end_date': fields.Date.today(),
})
self.env["group.order"].create(
{
"name": "Pedido Invalid",
"start_date": fields.Date.today() + timedelta(days=7),
"end_date": fields.Date.today(),
}
)
def test_group_order_state_transitions(self):
'''Test transiciones de estado.'''
order = self.env['group.order'].create({
'name': 'Pedido State Test',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
"""Test transiciones de estado."""
order = self.env["group.order"].create(
{
"name": "Pedido State Test",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
# Draft -> Open
order.action_open()
self.assertEqual(order.state, 'open')
self.assertEqual(order.state, "open")
# Open -> Closed
order.action_close()
self.assertEqual(order.state, 'closed')
self.assertEqual(order.state, "closed")
def test_group_order_action_cancel(self):
'''Test cancelar un pedido.'''
order = self.env['group.order'].create({
'name': 'Pedido Cancel Test',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
"""Test cancelar un pedido."""
order = self.env["group.order"].create(
{
"name": "Pedido Cancel Test",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
order.action_cancel()
self.assertEqual(order.state, 'cancelled')
self.assertEqual(order.state, "cancelled")
def test_get_active_orders_for_week(self):
'''Test obtener pedidos activos para la semana.'''
"""Test obtener pedidos activos para la semana."""
today = datetime.now().date()
week_start = today - timedelta(days=today.weekday())
week_end = week_start + timedelta(days=6)
# Crear pedido activo esta semana
active_order = self.env['group.order'].create({
'name': 'Pedido Activo',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': week_start,
'end_date': week_end,
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
'state': 'open',
})
active_order = self.env["group.order"].create(
{
"name": "Pedido Activo",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": week_start,
"end_date": week_end,
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
"state": "open",
}
)
# Crear pedido inactivo (futuro)
future_order = self.env['group.order'].create({
'name': 'Pedido Futuro',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': week_end + timedelta(days=1),
'end_date': week_end + timedelta(days=8),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
'state': 'open',
})
future_order = self.env["group.order"].create(
{
"name": "Pedido Futuro",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": week_end + timedelta(days=1),
"end_date": week_end + timedelta(days=8),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
"state": "open",
}
)
active_orders = self.env['group.order'].search([
('state', '=', 'open'),
'|',
('end_date', '>=', week_start),
('end_date', '=', False),
('start_date', '<=', week_end),
])
active_orders = self.env["group.order"].search(
[
("state", "=", "open"),
"|",
("end_date", ">=", week_start),
("end_date", "=", False),
("start_date", "<=", week_end),
]
)
self.assertIn(active_order, active_orders)
self.assertNotIn(future_order, active_orders)
def test_permanent_group_order(self):
'''Test crear un pedido permanente (sin end_date).'''
order = self.env['group.order'].create({
'name': 'Pedido Permanente',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': False,
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
"""Test crear un pedido permanente (sin end_date)."""
order = self.env["group.order"].create(
{
"name": "Pedido Permanente",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": False,
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
self.assertFalse(order.end_date)
def test_get_active_orders_excludes_draft(self):
'''Test que get_active_orders_for_week NO incluye pedidos en draft.'''
"""Test que get_active_orders_for_week NO incluye pedidos en draft."""
today = datetime.now().date()
# Crear pedido en draft (no abierto)
draft_order = self.env['group.order'].create({
'name': 'Pedido Draft',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': today,
'end_date': today + timedelta(days=7),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
'state': 'draft',
})
draft_order = self.env["group.order"].create(
{
"name": "Pedido Draft",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": today,
"end_date": today + timedelta(days=7),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
"state": "draft",
}
)
today = datetime.now().date()
week_start = today - timedelta(days=today.weekday())
week_end = week_start + timedelta(days=6)
active_orders = self.env['group.order'].search([
('state', '=', 'open'),
'|',
('end_date', '>=', week_start),
('end_date', '=', False),
('start_date', '<=', week_end),
])
active_orders = self.env["group.order"].search(
[
("state", "=", "open"),
"|",
("end_date", ">=", week_start),
("end_date", "=", False),
("start_date", "<=", week_end),
]
)
self.assertNotIn(draft_order, active_orders)
def test_get_active_orders_excludes_closed(self):
'''Test que get_active_orders_for_week NO incluye pedidos cerrados.'''
"""Test que get_active_orders_for_week NO incluye pedidos cerrados."""
today = datetime.now().date()
closed_order = self.env['group.order'].create({
'name': 'Pedido Cerrado',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': today,
'end_date': today + timedelta(days=7),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
'state': 'closed',
})
closed_order = self.env["group.order"].create(
{
"name": "Pedido Cerrado",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": today,
"end_date": today + timedelta(days=7),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
"state": "closed",
}
)
today = datetime.now().date()
week_start = today - timedelta(days=today.weekday())
week_end = week_start + timedelta(days=6)
active_orders = self.env['group.order'].search([
('state', '=', 'open'),
'|',
('end_date', '>=', week_start),
('end_date', '=', False),
('start_date', '<=', week_end),
])
active_orders = self.env["group.order"].search(
[
("state", "=", "open"),
"|",
("end_date", ">=", week_start),
("end_date", "=", False),
("start_date", "<=", week_end),
]
)
self.assertNotIn(closed_order, active_orders)
def test_get_active_orders_excludes_cancelled(self):
'''Test que get_active_orders_for_week NO incluye pedidos cancelados.'''
"""Test que get_active_orders_for_week NO incluye pedidos cancelados."""
today = datetime.now().date()
cancelled_order = self.env['group.order'].create({
'name': 'Pedido Cancelado',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': today,
'end_date': today + timedelta(days=7),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
'state': 'cancelled',
})
cancelled_order = self.env["group.order"].create(
{
"name": "Pedido Cancelado",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": today,
"end_date": today + timedelta(days=7),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
"state": "cancelled",
}
)
today = datetime.now().date()
week_start = today - timedelta(days=today.weekday())
week_end = week_start + timedelta(days=6)
active_orders = self.env['group.order'].search([
('state', '=', 'open'),
'|',
('end_date', '>=', week_start),
('end_date', '=', False),
('start_date', '<=', week_end),
])
active_orders = self.env["group.order"].search(
[
("state", "=", "open"),
"|",
("end_date", ">=", week_start),
("end_date", "=", False),
("start_date", "<=", week_end),
]
)
self.assertNotIn(cancelled_order, active_orders)
def test_state_transition_draft_to_open(self):
'''Test que un pedido pasa de draft a open.'''
order = self.env['group.order'].create({
'name': 'Pedido Estado Test',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': datetime.now().date() + timedelta(days=7),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
"""Test que un pedido pasa de draft a open."""
order = self.env["group.order"].create(
{
"name": "Pedido Estado Test",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": datetime.now().date() + timedelta(days=7),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
self.assertEqual(order.state, 'draft')
self.assertEqual(order.state, "draft")
order.action_open()
self.assertEqual(order.state, 'open')
self.assertEqual(order.state, "open")
def test_state_transition_open_to_closed(self):
'''Test transición válida open -> closed.'''
order = self.env['group.order'].create({
'name': 'Pedido Estado Test',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': datetime.now().date() + timedelta(days=7),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
"""Test transición válida open -> closed."""
order = self.env["group.order"].create(
{
"name": "Pedido Estado Test",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": datetime.now().date() + timedelta(days=7),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
order.action_open()
self.assertEqual(order.state, 'open')
self.assertEqual(order.state, "open")
order.action_close()
self.assertEqual(order.state, 'closed')
self.assertEqual(order.state, "closed")
def test_state_transition_any_to_cancelled(self):
'''Test cancelar desde cualquier estado.'''
order = self.env['group.order'].create({
'name': 'Pedido Estado Test',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': datetime.now().date() + timedelta(days=7),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
"""Test cancelar desde cualquier estado."""
order = self.env["group.order"].create(
{
"name": "Pedido Estado Test",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": datetime.now().date() + timedelta(days=7),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
# Desde draft
order.action_cancel()
self.assertEqual(order.state, 'cancelled')
self.assertEqual(order.state, "cancelled")
# Crear otro desde open
order2 = self.env['group.order'].create({
'name': 'Pedido Estado Test 2',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': datetime.now().date() + timedelta(days=7),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
order2 = self.env["group.order"].create(
{
"name": "Pedido Estado Test 2",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": datetime.now().date() + timedelta(days=7),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
order2.action_open()
order2.action_cancel()
self.assertEqual(order2.state, 'cancelled')
self.assertEqual(order2.state, "cancelled")

View file

@ -1,147 +1,178 @@
# Copyright 2025 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from datetime import datetime, timedelta
from datetime import datetime
from datetime import timedelta
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestMultiCompanyGroupOrder(TransactionCase):
'''Test suite para el soporte multicompañía en group.order.'''
"""Test suite para el soporte multicompañía en group.order."""
def setUp(self):
super().setUp()
# Crear dos compañías
self.company1 = self.env['res.company'].create({
'name': 'Company 1',
})
self.company2 = self.env['res.company'].create({
'name': 'Company 2',
})
self.company1 = self.env["res.company"].create(
{
"name": "Company 1",
}
)
self.company2 = self.env["res.company"].create(
{
"name": "Company 2",
}
)
# Crear grupos en diferentes compañías
self.group1 = self.env['res.partner'].create({
'name': 'Grupo Company 1',
'is_company': True,
'email': 'grupo1@test.com',
'company_id': self.company1.id,
})
self.group1 = self.env["res.partner"].create(
{
"name": "Grupo Company 1",
"is_company": True,
"email": "grupo1@test.com",
"company_id": self.company1.id,
}
)
self.group2 = self.env['res.partner'].create({
'name': 'Grupo Company 2',
'is_company': True,
'email': 'grupo2@test.com',
'company_id': self.company2.id,
})
self.group2 = self.env["res.partner"].create(
{
"name": "Grupo Company 2",
"is_company": True,
"email": "grupo2@test.com",
"company_id": self.company2.id,
}
)
# Crear productos en cada compañía
self.product1 = self.env['product.product'].create({
'name': 'Producto Company 1',
'type': 'consu',
'list_price': 10.0,
'company_id': self.company1.id,
})
self.product1 = self.env["product.product"].create(
{
"name": "Producto Company 1",
"type": "consu",
"list_price": 10.0,
"company_id": self.company1.id,
}
)
self.product2 = self.env['product.product'].create({
'name': 'Producto Company 2',
'type': 'consu',
'list_price': 20.0,
'company_id': self.company2.id,
})
self.product2 = self.env["product.product"].create(
{
"name": "Producto Company 2",
"type": "consu",
"list_price": 20.0,
"company_id": self.company2.id,
}
)
def test_group_order_has_company_id(self):
'''Test que group.order tenga el campo company_id.'''
order = self.env['group.order'].create({
'name': 'Pedido Company 1',
'group_ids': [(6, 0, [self.group1.id])],
'company_id': self.company1.id,
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
"""Test que group.order tenga el campo company_id."""
order = self.env["group.order"].create(
{
"name": "Pedido Company 1",
"group_ids": [(6, 0, [self.group1.id])],
"company_id": self.company1.id,
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
self.assertEqual(order.company_id, self.company1)
def test_group_order_default_company(self):
'''Test que company_id por defecto sea la compañía del usuario.'''
"""Test que company_id por defecto sea la compañía del usuario."""
# Crear usuario con compañía específica
user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser',
'password': 'test123',
'company_id': self.company1.id,
'company_ids': [(6, 0, [self.company1.id])],
})
user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser",
"password": "test123",
"company_id": self.company1.id,
"company_ids": [(6, 0, [self.company1.id])],
}
)
order = self.env['group.order'].with_user(user).create({
'name': 'Pedido Default Company',
'group_ids': [(6, 0, [self.group1.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
order = (
self.env["group.order"]
.with_user(user)
.create(
{
"name": "Pedido Default Company",
"group_ids": [(6, 0, [self.group1.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
)
# Verificar que se asignó la compañía del usuario
self.assertEqual(order.company_id, self.company1)
def test_group_order_company_constraint(self):
'''Test que solo grupos de la misma compañía se puedan asignar.'''
"""Test que solo grupos de la misma compañía se puedan asignar."""
# Intentar asignar un grupo de otra compañía
with self.assertRaises(ValidationError):
self.env['group.order'].create({
'name': 'Pedido Mixed Companies',
'group_ids': [(6, 0, [self.group1.id, self.group2.id])],
'company_id': self.company1.id,
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
self.env["group.order"].create(
{
"name": "Pedido Mixed Companies",
"group_ids": [(6, 0, [self.group1.id, self.group2.id])],
"company_id": self.company1.id,
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
def test_group_order_multi_company_filter(self):
'''Test que get_active_orders_for_week() respete company_id.'''
"""Test que get_active_orders_for_week() respete company_id."""
# Crear órdenes en diferentes compañías
order1 = self.env['group.order'].create({
'name': 'Pedido Company 1',
'group_ids': [(6, 0, [self.group1.id])],
'company_id': self.company1.id,
'type': 'regular',
'state': 'open',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
order1 = self.env["group.order"].create(
{
"name": "Pedido Company 1",
"group_ids": [(6, 0, [self.group1.id])],
"company_id": self.company1.id,
"type": "regular",
"state": "open",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
order2 = self.env['group.order'].create({
'name': 'Pedido Company 2',
'group_ids': [(6, 0, [self.group2.id])],
'company_id': self.company2.id,
'type': 'regular',
'state': 'open',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
order2 = self.env["group.order"].create(
{
"name": "Pedido Company 2",
"group_ids": [(6, 0, [self.group2.id])],
"company_id": self.company2.id,
"type": "regular",
"state": "open",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
# Obtener órdenes activas de company1
active_orders = self.env['group.order'].with_context(
allowed_company_ids=[self.company1.id]
).get_active_orders_for_week()
active_orders = (
self.env["group.order"]
.with_context(allowed_company_ids=[self.company1.id])
.get_active_orders_for_week()
)
# Debería contener solo order1
self.assertIn(order1, active_orders)
@ -149,24 +180,28 @@ class TestMultiCompanyGroupOrder(TransactionCase):
# el filtro de compañía correctamente
def test_product_company_isolation(self):
'''Test que los productos de diferentes compañías estén aislados.'''
"""Test que los productos de diferentes compañías estén aislados."""
# Crear categoría para products
category = self.env['product.category'].create({
'name': 'Test Category',
})
category = self.env["product.category"].create(
{
"name": "Test Category",
}
)
order = self.env['group.order'].create({
'name': 'Pedido con Categoría',
'group_ids': [(6, 0, [self.group1.id])],
'category_ids': [(6, 0, [category.id])],
'company_id': self.company1.id,
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Pedido con Categoría",
"group_ids": [(6, 0, [self.group1.id])],
"category_ids": [(6, 0, [category.id])],
"company_id": self.company1.id,
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
self.assertEqual(order.company_id, self.company1)

View file

@ -13,131 +13,166 @@ Coverage:
- Product price info structure in eskaera_shop
"""
import json
from odoo.tests.common import TransactionCase
from odoo.tests import tagged
from odoo.tests.common import TransactionCase
@tagged('post_install', '-at_install')
@tagged("post_install", "-at_install")
class TestPricingWithPricelist(TransactionCase):
"""Test pricing calculations using OCA product_get_price_helper addon."""
def setUp(self):
super().setUp()
# Create test company
self.company = self.env['res.company'].create({
'name': 'Test Company Pricing',
})
self.company = self.env["res.company"].create(
{
"name": "Test Company Pricing",
}
)
# Create test group
self.group = self.env['res.partner'].create({
'name': 'Test Group Pricing',
'is_company': True,
'company_id': self.company.id,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group Pricing",
"is_company": True,
"company_id": self.company.id,
}
)
# Create test user
self.user = self.env['res.users'].create({
'name': 'Test User Pricing',
'login': 'testpricing@example.com',
'company_id': self.company.id,
'company_ids': [(6, 0, [self.company.id])],
})
self.user = self.env["res.users"].create(
{
"name": "Test User Pricing",
"login": "testpricing@example.com",
"company_id": self.company.id,
"company_ids": [(6, 0, [self.company.id])],
}
)
# Get or create default tax group
tax_group = self.env['account.tax.group'].search([
('company_id', '=', self.company.id)
], limit=1)
tax_group = self.env["account.tax.group"].search(
[("company_id", "=", self.company.id)], limit=1
)
if not tax_group:
tax_group = self.env['account.tax.group'].create({
'name': 'IVA',
'company_id': self.company.id,
})
tax_group = self.env["account.tax.group"].create(
{
"name": "IVA",
"company_id": self.company.id,
}
)
# Get default country (Spain)
country_es = self.env.ref('base.es')
country_es = self.env.ref("base.es")
# Create tax (21% IVA)
self.tax_21 = self.env['account.tax'].create({
'name': 'IVA 21%',
'amount': 21.0,
'amount_type': 'percent',
'type_tax_use': 'sale',
'company_id': self.company.id,
'country_id': country_es.id,
'tax_group_id': tax_group.id,
})
self.tax_21 = self.env["account.tax"].create(
{
"name": "IVA 21%",
"amount": 21.0,
"amount_type": "percent",
"type_tax_use": "sale",
"company_id": self.company.id,
"country_id": country_es.id,
"tax_group_id": tax_group.id,
}
)
# Create tax (10% IVA reducido)
self.tax_10 = self.env['account.tax'].create({
'name': 'IVA 10%',
'amount': 10.0,
'amount_type': 'percent',
'type_tax_use': 'sale',
'company_id': self.company.id,
'country_id': country_es.id,
'tax_group_id': tax_group.id,
})
self.tax_10 = self.env["account.tax"].create(
{
"name": "IVA 10%",
"amount": 10.0,
"amount_type": "percent",
"type_tax_use": "sale",
"company_id": self.company.id,
"country_id": country_es.id,
"tax_group_id": tax_group.id,
}
)
# Create fiscal position (maps 21% to 10%)
self.fiscal_position = self.env['account.fiscal.position'].create({
'name': 'Test Fiscal Position',
'company_id': self.company.id,
})
self.env['account.fiscal.position.tax'].create({
'position_id': self.fiscal_position.id,
'tax_src_id': self.tax_21.id,
'tax_dest_id': self.tax_10.id,
})
self.fiscal_position = self.env["account.fiscal.position"].create(
{
"name": "Test Fiscal Position",
"company_id": self.company.id,
}
)
self.env["account.fiscal.position.tax"].create(
{
"position_id": self.fiscal_position.id,
"tax_src_id": self.tax_21.id,
"tax_dest_id": self.tax_10.id,
}
)
# Create product category
self.category = self.env['product.category'].create({
'name': 'Test Category Pricing',
})
self.category = self.env["product.category"].create(
{
"name": "Test Category Pricing",
}
)
# Create test products with different tax configurations
self.product_with_tax = self.env['product.product'].create({
'name': 'Product With 21% Tax',
'list_price': 100.0,
'categ_id': self.category.id,
'taxes_id': [(6, 0, [self.tax_21.id])],
'company_id': self.company.id,
})
self.product_without_tax = self.env['product.product'].create({
'name': 'Product Without Tax',
'list_price': 50.0,
'categ_id': self.category.id,
'taxes_id': False,
'company_id': self.company.id,
})
self.product_with_tax = self.env["product.product"].create(
{
"name": "Product With 21% Tax",
"list_price": 100.0,
"categ_id": self.category.id,
"taxes_id": [(6, 0, [self.tax_21.id])],
"company_id": self.company.id,
}
)
self.product_without_tax = self.env["product.product"].create(
{
"name": "Product Without Tax",
"list_price": 50.0,
"categ_id": self.category.id,
"taxes_id": False,
"company_id": self.company.id,
}
)
# Create pricelist with discount
self.pricelist_with_discount = self.env['product.pricelist'].create({
'name': 'Test Pricelist 10% Discount',
'company_id': self.company.id,
'item_ids': [(0, 0, {
'compute_price': 'percentage',
'percent_price': 10.0, # 10% discount
'applied_on': '3_global',
})],
})
self.pricelist_with_discount = self.env["product.pricelist"].create(
{
"name": "Test Pricelist 10% Discount",
"company_id": self.company.id,
"item_ids": [
(
0,
0,
{
"compute_price": "percentage",
"percent_price": 10.0, # 10% discount
"applied_on": "3_global",
},
)
],
}
)
# Create pricelist without discount
self.pricelist_no_discount = self.env['product.pricelist'].create({
'name': 'Test Pricelist No Discount',
'company_id': self.company.id,
})
self.pricelist_no_discount = self.env["product.pricelist"].create(
{
"name": "Test Pricelist No Discount",
"company_id": self.company.id,
}
)
# Create group order
self.group_order = self.env['group.order'].create({
'name': 'Test Order Pricing',
'state': 'open',
'group_ids': [(6, 0, [self.group.id])],
'product_ids': [(6, 0, [self.product_with_tax.id, self.product_without_tax.id])],
'company_id': self.company.id,
})
self.group_order = self.env["group.order"].create(
{
"name": "Test Order Pricing",
"state": "open",
"group_ids": [(6, 0, [self.group.id])],
"product_ids": [
(6, 0, [self.product_with_tax.id, self.product_without_tax.id])
],
"company_id": self.company.id,
}
)
def test_add_to_cart_basic_price_without_tax(self):
"""Test basic price calculation for product without taxes."""
@ -147,11 +182,15 @@ class TestPricingWithPricelist(TransactionCase):
pricelist=self.pricelist_no_discount,
fposition=False,
)
self.assertEqual(result['value'], 50.0,
"Product without tax should have price = list_price")
self.assertEqual(result.get('discount', 0), 0,
"No discount pricelist should have 0% discount")
self.assertEqual(
result["value"], 50.0, "Product without tax should have price = list_price"
)
self.assertEqual(
result.get("discount", 0),
0,
"No discount pricelist should have 0% discount",
)
def test_add_to_cart_with_pricelist_discount(self):
"""Test that discounted prices are calculated correctly."""
@ -161,14 +200,18 @@ class TestPricingWithPricelist(TransactionCase):
pricelist=self.pricelist_with_discount,
fposition=False,
)
# OCA addon returns price without taxes by default
expected_price = 100.0 * 0.9 # 90.0
self.assertIn('value', result, "Result must contain 'value' key")
self.assertIn('tax_included', result, "Result must contain 'tax_included' key")
self.assertAlmostEqual(result['value'], expected_price, places=2,
msg=f"Expected {expected_price}, got {result['value']}")
self.assertIn("value", result, "Result must contain 'value' key")
self.assertIn("tax_included", result, "Result must contain 'tax_included' key")
self.assertAlmostEqual(
result["value"],
expected_price,
places=2,
msg=f"Expected {expected_price}, got {result['value']}",
)
def test_add_to_cart_with_fiscal_position(self):
"""Test fiscal position maps taxes correctly (21% -> 10%)."""
@ -178,19 +221,19 @@ class TestPricingWithPricelist(TransactionCase):
pricelist=self.pricelist_no_discount,
fposition=False,
)
result_with_fp = self.product_with_tax._get_price(
qty=1.0,
pricelist=self.pricelist_no_discount,
fposition=self.fiscal_position,
)
# Both should return base price (100.0) without tax by default
# Tax mapping only affects tax calculation, not the base price returned
self.assertIn('value', result_without_fp, "Result must contain 'value'")
self.assertIn('value', result_with_fp, "Result must contain 'value'")
self.assertEqual(result_without_fp['value'], 100.0)
self.assertEqual(result_with_fp['value'], 100.0)
self.assertIn("value", result_without_fp, "Result must contain 'value'")
self.assertIn("value", result_with_fp, "Result must contain 'value'")
self.assertEqual(result_without_fp["value"], 100.0)
self.assertEqual(result_with_fp["value"], 100.0)
def test_add_to_cart_with_tax_included(self):
"""Test price calculation returns tax_included flag correctly."""
@ -200,43 +243,53 @@ class TestPricingWithPricelist(TransactionCase):
pricelist=self.pricelist_no_discount,
fposition=False,
)
# By default, tax is not included in price
self.assertIn('tax_included', result)
self.assertEqual(result['value'], 100.0, "Price should be base price without tax")
self.assertIn("tax_included", result)
self.assertEqual(
result["value"], 100.0, "Price should be base price without tax"
)
def test_add_to_cart_with_quantity_discount(self):
"""Test quantity-based discounts if applicable."""
# Create pricelist with quantity-based rule
pricelist_qty = self.env['product.pricelist'].create({
'name': 'Quantity Discount Pricelist',
'company_id': self.company.id,
'item_ids': [(0, 0, {
'compute_price': 'percentage',
'percent_price': 20.0, # 20% discount
'min_quantity': 5.0,
'applied_on': '3_global',
})],
})
pricelist_qty = self.env["product.pricelist"].create(
{
"name": "Quantity Discount Pricelist",
"company_id": self.company.id,
"item_ids": [
(
0,
0,
{
"compute_price": "percentage",
"percent_price": 20.0, # 20% discount
"min_quantity": 5.0,
"applied_on": "3_global",
},
)
],
}
)
# Quantity 1: No discount
result_qty_1 = self.product_with_tax._get_price(
qty=1.0,
pricelist=pricelist_qty,
fposition=False,
)
# Quantity 5: 20% discount
result_qty_5 = self.product_with_tax._get_price(
qty=5.0,
pricelist=pricelist_qty,
fposition=False,
)
# Qty 1: 100.0 (no discount, no tax in value)
# Qty 5: 100 * 0.8 = 80.0 (with 20% discount, no tax in value)
self.assertAlmostEqual(result_qty_1['value'], 100.0, places=2)
self.assertAlmostEqual(result_qty_5['value'], 80.0, places=2)
self.assertAlmostEqual(result_qty_1["value"], 100.0, places=2)
self.assertAlmostEqual(result_qty_5["value"], 80.0, places=2)
def test_add_to_cart_price_fallback_no_pricelist(self):
"""Test fallback to list_price when pricelist is not available."""
@ -247,35 +300,39 @@ class TestPricingWithPricelist(TransactionCase):
pricelist=False,
fposition=False,
)
# Should return list_price with taxes (fallback behavior)
# This depends on OCA addon implementation
self.assertIsNotNone(result, "Should not fail when pricelist is False")
self.assertIn('value', result, "Result should contain 'value' key")
self.assertIn("value", result, "Result should contain 'value' key")
def test_add_to_cart_price_fallback_no_variant(self):
"""Test handling when product has no variants."""
# Create product template without variants
product_template = self.env['product.template'].create({
'name': 'Product Without Variant',
'list_price': 75.0,
'categ_id': self.category.id,
'company_id': self.company.id,
})
product_template = self.env["product.template"].create(
{
"name": "Product Without Variant",
"list_price": 75.0,
"categ_id": self.category.id,
"company_id": self.company.id,
}
)
# Should have auto-created variant
self.assertTrue(product_template.product_variant_ids,
"Product template should have at least one variant")
self.assertTrue(
product_template.product_variant_ids,
"Product template should have at least one variant",
)
variant = product_template.product_variant_ids[0]
result = variant._get_price(
qty=1.0,
pricelist=self.pricelist_no_discount,
fposition=False,
)
self.assertIsNotNone(result, "Should handle product with auto-created variant")
self.assertAlmostEqual(result['value'], 75.0, places=2)
self.assertAlmostEqual(result["value"], 75.0, places=2)
def test_product_price_info_structure(self):
"""Test product_price_info dict structure returned by _get_price."""
@ -284,18 +341,19 @@ class TestPricingWithPricelist(TransactionCase):
pricelist=self.pricelist_with_discount,
fposition=False,
)
# Verify structure
self.assertIn('value', result, "Result must contain 'value' key")
self.assertIsInstance(result['value'], (int, float),
"Price value must be numeric")
self.assertIn("value", result, "Result must contain 'value' key")
self.assertIsInstance(
result["value"], (int, float), "Price value must be numeric"
)
# Optional keys (depends on OCA addon version)
if 'discount' in result:
self.assertIsInstance(result['discount'], (int, float))
if 'original_value' in result:
self.assertIsInstance(result['original_value'], (int, float))
if "discount" in result:
self.assertIsInstance(result["discount"], (int, float))
if "original_value" in result:
self.assertIsInstance(result["original_value"], (int, float))
def test_discounted_price_visual_comparison(self):
"""Test comparison of original vs discounted price for UI display."""
@ -304,71 +362,83 @@ class TestPricingWithPricelist(TransactionCase):
pricelist=self.pricelist_with_discount,
fposition=False,
)
# When there's a discount, original_value should be higher than value
if result.get('discount', 0) > 0:
original = result.get('original_value', result['value'])
discounted = result['value']
self.assertGreater(original, discounted,
"Original price should be higher than discounted price")
if result.get("discount", 0) > 0:
original = result.get("original_value", result["value"])
discounted = result["value"]
self.assertGreater(
original,
discounted,
"Original price should be higher than discounted price",
)
def test_price_calculation_with_multiple_taxes(self):
"""Test product with multiple taxes applied."""
# Get tax group and country from existing tax
tax_group = self.tax_21.tax_group_id
country = self.tax_21.country_id
# Create additional tax
tax_extra = self.env['account.tax'].create({
'name': 'Extra Tax 5%',
'amount': 5.0,
'amount_type': 'percent',
'type_tax_use': 'sale',
'company_id': self.company.id,
'country_id': country.id,
'tax_group_id': tax_group.id,
})
product_multi_tax = self.env['product.product'].create({
'name': 'Product With Multiple Taxes',
'list_price': 100.0,
'categ_id': self.category.id,
'taxes_id': [(6, 0, [self.tax_21.id, tax_extra.id])],
'company_id': self.company.id,
})
tax_extra = self.env["account.tax"].create(
{
"name": "Extra Tax 5%",
"amount": 5.0,
"amount_type": "percent",
"type_tax_use": "sale",
"company_id": self.company.id,
"country_id": country.id,
"tax_group_id": tax_group.id,
}
)
product_multi_tax = self.env["product.product"].create(
{
"name": "Product With Multiple Taxes",
"list_price": 100.0,
"categ_id": self.category.id,
"taxes_id": [(6, 0, [self.tax_21.id, tax_extra.id])],
"company_id": self.company.id,
}
)
result = product_multi_tax._get_price(
qty=1.0,
pricelist=self.pricelist_no_discount,
fposition=False,
)
# Base price 100.0 (taxes not included in value by default)
self.assertEqual(result['value'], 100.0,
msg="Should return base price (taxes applied separately)")
self.assertEqual(
result["value"],
100.0,
msg="Should return base price (taxes applied separately)",
)
def test_price_currency_handling(self):
"""Test price calculation with different currencies."""
# Get or use existing EUR currency
eur = self.env['res.currency'].search([('name', '=', 'EUR')], limit=1)
eur = self.env["res.currency"].search([("name", "=", "EUR")], limit=1)
if not eur:
self.skipTest("EUR currency not available in test database")
# Create pricelist with EUR
pricelist_eur = self.env['product.pricelist'].create({
'name': 'EUR Pricelist',
'currency_id': eur.id,
'company_id': self.company.id,
})
pricelist_eur = self.env["product.pricelist"].create(
{
"name": "EUR Pricelist",
"currency_id": eur.id,
"company_id": self.company.id,
}
)
result = self.product_with_tax._get_price(
qty=1.0,
pricelist=pricelist_eur,
fposition=False,
)
self.assertIsNotNone(result, "Should handle different currency pricelist")
self.assertIn('value', result)
self.assertIn("value", result)
def test_price_consistency_across_calls(self):
"""Test that multiple calls with same params return same price."""
@ -377,33 +447,37 @@ class TestPricingWithPricelist(TransactionCase):
pricelist=self.pricelist_with_discount,
fposition=False,
)
result2 = self.product_with_tax._get_price(
qty=1.0,
pricelist=self.pricelist_with_discount,
fposition=False,
)
self.assertEqual(result1['value'], result2['value'],
"Price calculation should be deterministic")
self.assertEqual(
result1["value"],
result2["value"],
"Price calculation should be deterministic",
)
def test_zero_price_product(self):
"""Test handling of free products (price = 0)."""
free_product = self.env['product.product'].create({
'name': 'Free Product',
'list_price': 0.0,
'categ_id': self.category.id,
'company_id': self.company.id,
})
free_product = self.env["product.product"].create(
{
"name": "Free Product",
"list_price": 0.0,
"categ_id": self.category.id,
"company_id": self.company.id,
}
)
result = free_product._get_price(
qty=1.0,
pricelist=self.pricelist_no_discount,
fposition=False,
)
self.assertEqual(result['value'], 0.0,
"Free product should have price = 0")
self.assertEqual(result["value"], 0.0, "Free product should have price = 0")
def test_negative_quantity_handling(self):
"""Test that negative quantities are handled properly."""

View file

@ -17,7 +17,8 @@ Coverage:
- Ordering and deduplication
"""
from datetime import datetime, timedelta
from datetime import datetime
from datetime import timedelta
from odoo.tests.common import TransactionCase
@ -27,81 +28,105 @@ class TestProductDiscoveryUnion(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
# Create a supplier
self.supplier = self.env['res.partner'].create({
'name': 'Test Supplier',
'is_supplier': True,
})
self.supplier = self.env["res.partner"].create(
{
"name": "Test Supplier",
"is_supplier": True,
}
)
# Create categories
self.category1 = self.env['product.category'].create({
'name': 'Category 1',
})
self.category1 = self.env["product.category"].create(
{
"name": "Category 1",
}
)
self.category2 = self.env['product.category'].create({
'name': 'Category 2',
})
self.category2 = self.env["product.category"].create(
{
"name": "Category 2",
}
)
# Create products
# Direct product
self.direct_product = self.env['product.product'].create({
'name': 'Direct Product',
'type': 'consu',
'list_price': 10.0,
'is_published': True,
'sale_ok': True,
})
self.direct_product = self.env["product.product"].create(
{
"name": "Direct Product",
"type": "consu",
"list_price": 10.0,
"is_published": True,
"sale_ok": True,
}
)
# Category 1 product
self.cat1_product = self.env['product.product'].create({
'name': 'Category 1 Product',
'type': 'consu',
'list_price': 20.0,
'categ_id': self.category1.id,
'is_published': True,
'sale_ok': True,
})
self.cat1_product = self.env["product.product"].create(
{
"name": "Category 1 Product",
"type": "consu",
"list_price": 20.0,
"categ_id": self.category1.id,
"is_published": True,
"sale_ok": True,
}
)
# Category 2 product
self.cat2_product = self.env['product.product'].create({
'name': 'Category 2 Product',
'type': 'consu',
'list_price': 30.0,
'categ_id': self.category2.id,
'is_published': True,
'sale_ok': True,
})
self.cat2_product = self.env["product.product"].create(
{
"name": "Category 2 Product",
"type": "consu",
"list_price": 30.0,
"categ_id": self.category2.id,
"is_published": True,
"sale_ok": True,
}
)
# Supplier product
self.supplier_product = self.env['product.product'].create({
'name': 'Supplier Product',
'type': 'consu',
'list_price': 40.0,
'categ_id': self.category1.id, # Also in category
'seller_ids': [(0, 0, {
'partner_id': self.supplier.id,
'product_name': 'Supplier Product',
})],
'is_published': True,
'sale_ok': True,
})
self.supplier_product = self.env["product.product"].create(
{
"name": "Supplier Product",
"type": "consu",
"list_price": 40.0,
"categ_id": self.category1.id, # Also in category
"seller_ids": [
(
0,
0,
{
"partner_id": self.supplier.id,
"product_name": "Supplier Product",
},
)
],
"is_published": True,
"sale_ok": True,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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",
}
)
def test_discovery_from_direct_products(self):
"""Test discovery returns directly linked products."""
@ -145,14 +170,16 @@ class TestProductDiscoveryUnion(TransactionCase):
def test_discovery_filters_unpublished(self):
"""Test that unpublished products are excluded from discovery."""
unpublished = self.env['product.product'].create({
'name': 'Unpublished Product',
'type': 'consu',
'list_price': 50.0,
'categ_id': self.category1.id,
'is_published': False,
'sale_ok': True,
})
unpublished = self.env["product.product"].create(
{
"name": "Unpublished Product",
"type": "consu",
"list_price": 50.0,
"categ_id": self.category1.id,
"is_published": False,
"sale_ok": True,
}
)
self.group_order.category_ids = [(4, self.category1.id)]
discovered = self.group_order.product_ids
@ -162,14 +189,16 @@ class TestProductDiscoveryUnion(TransactionCase):
def test_discovery_filters_not_for_sale(self):
"""Test that non-sellable products are excluded."""
not_for_sale = self.env['product.product'].create({
'name': 'Not For Sale',
'type': 'consu',
'list_price': 60.0,
'categ_id': self.category1.id,
'is_published': True,
'sale_ok': False,
})
not_for_sale = self.env["product.product"].create(
{
"name": "Not For Sale",
"type": "consu",
"list_price": 60.0,
"categ_id": self.category1.id,
"is_published": True,
"sale_ok": False,
}
)
self.group_order.category_ids = [(4, self.category1.id)]
discovered = self.group_order.product_ids
@ -183,76 +212,96 @@ class TestDeepCategoryHierarchies(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
# Create nested category structure:
# Root -> L1 -> L2 -> L3 -> L4
self.cat_l1 = self.env['product.category'].create({
'name': 'Level 1',
})
self.cat_l1 = self.env["product.category"].create(
{
"name": "Level 1",
}
)
self.cat_l2 = self.env['product.category'].create({
'name': 'Level 2',
'parent_id': self.cat_l1.id,
})
self.cat_l2 = self.env["product.category"].create(
{
"name": "Level 2",
"parent_id": self.cat_l1.id,
}
)
self.cat_l3 = self.env['product.category'].create({
'name': 'Level 3',
'parent_id': self.cat_l2.id,
})
self.cat_l3 = self.env["product.category"].create(
{
"name": "Level 3",
"parent_id": self.cat_l2.id,
}
)
self.cat_l4 = self.env['product.category'].create({
'name': 'Level 4',
'parent_id': self.cat_l3.id,
})
self.cat_l4 = self.env["product.category"].create(
{
"name": "Level 4",
"parent_id": self.cat_l3.id,
}
)
self.cat_l5 = self.env['product.category'].create({
'name': 'Level 5',
'parent_id': self.cat_l4.id,
})
self.cat_l5 = self.env["product.category"].create(
{
"name": "Level 5",
"parent_id": self.cat_l4.id,
}
)
# Create products at each level
self.product_l2 = self.env['product.product'].create({
'name': 'Product L2',
'type': 'consu',
'list_price': 10.0,
'categ_id': self.cat_l2.id,
'is_published': True,
'sale_ok': True,
})
self.product_l2 = self.env["product.product"].create(
{
"name": "Product L2",
"type": "consu",
"list_price": 10.0,
"categ_id": self.cat_l2.id,
"is_published": True,
"sale_ok": True,
}
)
self.product_l4 = self.env['product.product'].create({
'name': 'Product L4',
'type': 'consu',
'list_price': 20.0,
'categ_id': self.cat_l4.id,
'is_published': True,
'sale_ok': True,
})
self.product_l4 = self.env["product.product"].create(
{
"name": "Product L4",
"type": "consu",
"list_price": 20.0,
"categ_id": self.cat_l4.id,
"is_published": True,
"sale_ok": True,
}
)
self.product_l5 = self.env['product.product'].create({
'name': 'Product L5',
'type': 'consu',
'list_price': 30.0,
'categ_id': self.cat_l5.id,
'is_published': True,
'sale_ok': True,
})
self.product_l5 = self.env["product.product"].create(
{
"name": "Product L5",
"type": "consu",
"list_price": 30.0,
"categ_id": self.cat_l5.id,
"is_published": True,
"sale_ok": True,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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",
}
)
def test_discovery_root_category_includes_all_descendants(self):
"""Test that linking root category discovers all nested products."""
@ -307,33 +356,41 @@ class TestEmptySourcesDiscovery(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
self.category = self.env['product.category'].create({
'name': 'Empty Category',
})
self.category = self.env["product.category"].create(
{
"name": "Empty Category",
}
)
# No products in this category
self.supplier = self.env['res.partner'].create({
'name': 'Supplier No Products',
'is_supplier': True,
})
self.supplier = self.env["res.partner"].create(
{
"name": "Supplier No Products",
"is_supplier": True,
}
)
# No products from this supplier
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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",
}
)
def test_discovery_empty_category(self):
"""Test discovery from empty category."""
@ -371,39 +428,47 @@ class TestProductDiscoveryOrdering(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
self.category = self.env['product.category'].create({
'name': 'Test Category',
})
self.category = self.env["product.category"].create(
{
"name": "Test Category",
}
)
# Create products with specific names
self.products = []
for i in range(5):
product = self.env['product.product'].create({
'name': f'Product {chr(65 + i)}', # A, B, C, D, E
'type': 'consu',
'list_price': (i + 1) * 10.0,
'categ_id': self.category.id,
'is_published': True,
'sale_ok': True,
})
product = self.env["product.product"].create(
{
"name": f"Product {chr(65 + i)}", # A, B, C, D, E
"type": "consu",
"list_price": (i + 1) * 10.0,
"categ_id": self.category.id,
"is_published": True,
"sale_ok": True,
}
)
self.products.append(product)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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",
}
)
def test_discovery_consistent_ordering(self):
"""Test that repeated calls return same order."""
@ -413,10 +478,7 @@ class TestProductDiscoveryOrdering(TransactionCase):
discovered2 = list(self.group_order.product_ids)
# Order should be consistent
self.assertEqual(
[p.id for p in discovered1],
[p.id for p in discovered2]
)
self.assertEqual([p.id for p in discovered1], [p.id for p in discovered2])
def test_discovery_alphabetical_or_price_order(self):
"""Test that products are ordered predictably."""
@ -427,6 +489,6 @@ class TestProductDiscoveryOrdering(TransactionCase):
# Should be in some consistent order (name, price, ID, etc)
# Verify they're the same products, regardless of order
self.assertEqual(len(discovered), 5)
discovered_ids = set(p.id for p in discovered)
expected_ids = set(p.id for p in self.products)
discovered_ids = {p.id for p in discovered}
expected_ids = {p.id for p in self.products}
self.assertEqual(discovered_ids, expected_ids)

View file

@ -1,91 +1,106 @@
# Copyright 2025 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from datetime import datetime, timedelta
from odoo.tests.common import TransactionCase
class TestProductExtension(TransactionCase):
'''Test suite para las extensiones de product.template.'''
"""Test suite para las extensiones de product.template."""
def setUp(self):
super(TestProductExtension, self).setUp()
self.product = self.env['product.product'].create({
'name': 'Test Product',
})
self.order = self.env['group.order'].create({
'name': 'Test Order',
'product_ids': [(4, self.product.id)]
})
super().setUp()
self.product = self.env["product.product"].create(
{
"name": "Test Product",
}
)
self.order = self.env["group.order"].create(
{"name": "Test Order", "product_ids": [(4, self.product.id)]}
)
def test_product_template_group_order_ids_field_exists(self):
'''Test que el campo group_order_ids existe en product.template.'''
"""Test que el campo group_order_ids existe en product.template."""
product_template = self.product.product_tmpl_id
# El campo debe existir y ser readonly
self.assertTrue(hasattr(product_template, 'group_order_ids'))
self.assertTrue(hasattr(product_template, "group_order_ids"))
def test_product_group_order_ids_readonly(self):
""" Test that group_order_ids is a readonly field """
field = self.env['product.template']._fields['group_order_ids']
"""Test that group_order_ids is a readonly field"""
field = self.env["product.template"]._fields["group_order_ids"]
self.assertTrue(field.readonly)
def test_product_group_order_ids_reverse_lookup(self):
""" Test that adding a product to an order reflects in group_order_ids """
"""Test that adding a product to an order reflects in group_order_ids"""
related_orders = self.product.product_tmpl_id.group_order_ids
self.assertIn(self.order, related_orders)
def test_product_group_order_ids_empty_by_default(self):
""" Test that a new product has no group orders """
new_product = self.env['product.product'].create({'name': 'New Product'})
"""Test that a new product has no group orders"""
new_product = self.env["product.product"].create({"name": "New Product"})
self.assertFalse(new_product.product_tmpl_id.group_order_ids)
def test_product_group_order_ids_multiple_orders(self):
""" Test that group_order_ids can contain multiple orders """
order2 = self.env['group.order'].create({
'name': 'Test Order 2',
'product_ids': [(4, self.product.id)]
})
"""Test that group_order_ids can contain multiple orders"""
order2 = self.env["group.order"].create(
{"name": "Test Order 2", "product_ids": [(4, self.product.id)]}
)
self.assertIn(self.order, self.product.product_tmpl_id.group_order_ids)
self.assertIn(order2, self.product.product_tmpl_id.group_order_ids)
def test_product_group_order_ids_empty_after_remove_from_order(self):
""" Test that group_order_ids is empty after removing the product from all orders """
self.order.write({'product_ids': [(3, self.product.id)]})
"""Test that group_order_ids is empty after removing the product from all orders"""
self.order.write({"product_ids": [(3, self.product.id)]})
self.assertFalse(self.product.product_tmpl_id.group_order_ids)
def test_product_group_order_ids_with_multiple_products(self):
""" Test group_order_ids with multiple products in one order """
product2 = self.env['product.product'].create({'name': 'Test Product 2'})
self.order.write({'product_ids': [
(4, self.product.id),
(4, product2.id)
]})
"""Test group_order_ids with multiple products in one order"""
product2 = self.env["product.product"].create({"name": "Test Product 2"})
self.order.write({"product_ids": [(4, self.product.id), (4, product2.id)]})
self.assertIn(self.order, self.product.product_tmpl_id.group_order_ids)
self.assertIn(self.order, product2.product_tmpl_id.group_order_ids)
def test_product_with_variants_group_order_ids(self):
""" Test that group_order_ids works correctly with product variants """
"""Test that group_order_ids works correctly with product variants"""
# Create a product template with two variants
product_template = self.env['product.template'].create({
'name': 'Product with Variants',
'attribute_line_ids': [(0, 0, {
'attribute_id': self.env.ref('product.product_attribute_1').id,
'value_ids': [
(4, self.env.ref('product.product_attribute_value_1').id),
(4, self.env.ref('product.product_attribute_value_2').id)
]
})]
})
product_template = self.env["product.template"].create(
{
"name": "Product with Variants",
"attribute_line_ids": [
(
0,
0,
{
"attribute_id": self.env.ref(
"product.product_attribute_1"
).id,
"value_ids": [
(
4,
self.env.ref(
"product.product_attribute_value_1"
).id,
),
(
4,
self.env.ref(
"product.product_attribute_value_2"
).id,
),
],
},
)
],
}
)
variant1 = product_template.product_variant_ids[0]
variant2 = product_template.product_variant_ids[1]
# Add one variant to an order (store variant id, not template id)
order_with_variant = self.env['group.order'].create({
'name': 'Order with Variant',
'product_ids': [(4, variant1.id)]
})
order_with_variant = self.env["group.order"].create(
{"name": "Order with Variant", "product_ids": [(4, variant1.id)]}
)
# Check that the order appears in the group_order_ids of the template
self.assertIn(order_with_variant, product_template.group_order_ids)

View file

@ -1,145 +1,170 @@
# Copyright 2025 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from datetime import datetime, timedelta
from datetime import datetime
from datetime import timedelta
from odoo.tests.common import TransactionCase
from odoo.exceptions import AccessError
from odoo.tests.common import TransactionCase
class TestGroupOrderRecordRules(TransactionCase):
'''Test suite para record rules de multicompañía en group.order.'''
"""Test suite para record rules de multicompañía en group.order."""
def setUp(self):
super().setUp()
# Crear dos compañías
self.company1 = self.env['res.company'].create({
'name': 'Company 1',
})
self.company2 = self.env['res.company'].create({
'name': 'Company 2',
})
self.company1 = self.env["res.company"].create(
{
"name": "Company 1",
}
)
self.company2 = self.env["res.company"].create(
{
"name": "Company 2",
}
)
# Crear usuarios para cada compañía
self.user_company1 = self.env['res.users'].create({
'name': 'User Company 1',
'login': 'user_c1',
'password': 'pass123',
'company_id': self.company1.id,
'company_ids': [(6, 0, [self.company1.id])],
})
self.user_company1 = self.env["res.users"].create(
{
"name": "User Company 1",
"login": "user_c1",
"password": "pass123",
"company_id": self.company1.id,
"company_ids": [(6, 0, [self.company1.id])],
}
)
self.user_company2 = self.env['res.users'].create({
'name': 'User Company 2',
'login': 'user_c2',
'password': 'pass123',
'company_id': self.company2.id,
'company_ids': [(6, 0, [self.company2.id])],
})
self.user_company2 = self.env["res.users"].create(
{
"name": "User Company 2",
"login": "user_c2",
"password": "pass123",
"company_id": self.company2.id,
"company_ids": [(6, 0, [self.company2.id])],
}
)
# Crear admin con acceso a ambas compañías
self.admin_user = self.env['res.users'].create({
'name': 'Admin Both',
'login': 'admin_both',
'password': 'pass123',
'company_id': self.company1.id,
'company_ids': [(6, 0, [self.company1.id, self.company2.id])],
})
self.admin_user = self.env["res.users"].create(
{
"name": "Admin Both",
"login": "admin_both",
"password": "pass123",
"company_id": self.company1.id,
"company_ids": [(6, 0, [self.company1.id, self.company2.id])],
}
)
# Crear grupos en cada compañía
self.group1 = self.env['res.partner'].create({
'name': 'Grupo Company 1',
'is_company': True,
'email': 'grupo1@test.com',
'company_id': self.company1.id,
})
self.group1 = self.env["res.partner"].create(
{
"name": "Grupo Company 1",
"is_company": True,
"email": "grupo1@test.com",
"company_id": self.company1.id,
}
)
self.group2 = self.env['res.partner'].create({
'name': 'Grupo Company 2',
'is_company': True,
'email': 'grupo2@test.com',
'company_id': self.company2.id,
})
self.group2 = self.env["res.partner"].create(
{
"name": "Grupo Company 2",
"is_company": True,
"email": "grupo2@test.com",
"company_id": self.company2.id,
}
)
# Crear órdenes en cada compañía
self.order1 = self.env['group.order'].create({
'name': 'Pedido Company 1',
'group_ids': [(6, 0, [self.group1.id])],
'company_id': self.company1.id,
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
self.order1 = self.env["group.order"].create(
{
"name": "Pedido Company 1",
"group_ids": [(6, 0, [self.group1.id])],
"company_id": self.company1.id,
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
self.order2 = self.env['group.order'].create({
'name': 'Pedido Company 2',
'group_ids': [(6, 0, [self.group2.id])],
'company_id': self.company2.id,
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': (datetime.now() + timedelta(days=7)).date(),
'period': 'weekly',
'pickup_day': '5',
'cutoff_day': '0',
})
self.order2 = self.env["group.order"].create(
{
"name": "Pedido Company 2",
"group_ids": [(6, 0, [self.group2.id])],
"company_id": self.company2.id,
"type": "regular",
"start_date": datetime.now().date(),
"end_date": (datetime.now() + timedelta(days=7)).date(),
"period": "weekly",
"pickup_day": "5",
"cutoff_day": "0",
}
)
def test_user_company1_can_read_own_orders(self):
'''Test que usuario de Company 1 puede leer sus propias órdenes.'''
orders = self.env['group.order'].with_user(
self.user_company1
).search([('company_id', '=', self.company1.id)])
"""Test que usuario de Company 1 puede leer sus propias órdenes."""
orders = (
self.env["group.order"]
.with_user(self.user_company1)
.search([("company_id", "=", self.company1.id)])
)
self.assertIn(self.order1, orders)
def test_user_company1_cannot_read_company2_orders(self):
'''Test que usuario de Company 1 NO puede leer órdenes de Company 2.'''
orders = self.env['group.order'].with_user(
self.user_company1
).search([('company_id', '=', self.company2.id)])
"""Test que usuario de Company 1 NO puede leer órdenes de Company 2."""
orders = (
self.env["group.order"]
.with_user(self.user_company1)
.search([("company_id", "=", self.company2.id)])
)
self.assertNotIn(self.order2, orders)
self.assertEqual(len(orders), 0)
def test_admin_can_read_all_orders(self):
'''Test que admin con acceso a ambas compañías ve todas las órdenes.'''
orders = self.env['group.order'].with_user(
self.admin_user
).search([])
"""Test que admin con acceso a ambas compañías ve todas las órdenes."""
orders = self.env["group.order"].with_user(self.admin_user).search([])
self.assertIn(self.order1, orders)
self.assertIn(self.order2, orders)
def test_user_cannot_write_other_company_order(self):
'''Test que usuario no puede escribir en orden de otra compañía.'''
"""Test que usuario no puede escribir en orden de otra compañía."""
with self.assertRaises(AccessError):
self.order2.with_user(self.user_company1).write({
'name': 'Intentando cambiar nombre',
})
self.order2.with_user(self.user_company1).write(
{
"name": "Intentando cambiar nombre",
}
)
def test_record_rule_filters_search(self):
'''Test que búsqueda automáticamente filtra por record rule.'''
"""Test que búsqueda automáticamente filtra por record rule."""
# Usuario de Company 1 busca todas las órdenes
orders_c1 = self.env['group.order'].with_user(
self.user_company1
).search([('state', '=', 'draft')])
orders_c1 = (
self.env["group.order"]
.with_user(self.user_company1)
.search([("state", "=", "draft")])
)
# Solo debe ver su orden
self.assertEqual(len(orders_c1), 1)
self.assertEqual(orders_c1[0], self.order1)
def test_cross_company_access_denied(self):
'''Test que acceso entre compañías es denegado.'''
"""Test que acceso entre compañías es denegado."""
# Usuario company1 intenta acceder a orden de company2
with self.assertRaises(AccessError):
self.order2.with_user(self.user_company1).read()
def test_admin_can_bypass_company_restriction(self):
'''Test que admin puede acceder a órdenes de cualquier compañía.'''
"""Test que admin puede acceder a órdenes de cualquier compañía."""
# Admin lee orden de company2 sin problema
order2_admin = self.order2.with_user(self.admin_user)
self.assertEqual(order2_admin.name, 'Pedido Company 2')
self.assertEqual(order2_admin.name, "Pedido Company 2")
self.assertEqual(order2_admin.company_id, self.company2)

View file

@ -5,34 +5,40 @@ from odoo.tests.common import TransactionCase
class TestResPartnerExtension(TransactionCase):
'''Test suite para la extensión res.partner (user-group relationship).'''
"""Test suite para la extensión res.partner (user-group relationship)."""
def setUp(self):
super().setUp()
# Crear grupos (res.partner with is_company=True)
self.group1 = self.env['res.partner'].create({
'name': 'Grupo 1',
'is_company': True,
'email': 'grupo1@test.com',
})
self.group1 = self.env["res.partner"].create(
{
"name": "Grupo 1",
"is_company": True,
"email": "grupo1@test.com",
}
)
self.group2 = self.env['res.partner'].create({
'name': 'Grupo 2',
'is_company': True,
'email': 'grupo2@test.com',
})
self.group2 = self.env["res.partner"].create(
{
"name": "Grupo 2",
"is_company": True,
"email": "grupo2@test.com",
}
)
# Crear usuario
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'email': 'testuser@test.com',
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"email": "testuser@test.com",
}
)
def test_partner_can_belong_to_groups(self):
'''Test que un partner (usuario) puede pertenecer a múltiples grupos.'''
"""Test que un partner (usuario) puede pertenecer a múltiples grupos."""
partner = self.user.partner_id
# Agregar partner a grupos (usar campo member_ids)
partner.member_ids = [(6, 0, [self.group1.id, self.group2.id])]
@ -42,12 +48,14 @@ class TestResPartnerExtension(TransactionCase):
self.assertEqual(len(partner.member_ids), 2)
def test_group_can_have_multiple_users(self):
'''Test que un grupo puede tener múltiples usuarios.'''
user2 = self.env['res.users'].create({
'name': 'Test User 2',
'login': 'testuser2@test.com',
'email': 'testuser2@test.com',
})
"""Test que un grupo puede tener múltiples usuarios."""
user2 = self.env["res.users"].create(
{
"name": "Test User 2",
"login": "testuser2@test.com",
"email": "testuser2@test.com",
}
)
# Agregar usuarios al grupo
self.group1.user_ids = [(6, 0, [self.user.id, user2.id])]
@ -58,26 +66,28 @@ class TestResPartnerExtension(TransactionCase):
self.assertEqual(len(self.group1.user_ids), 2)
def test_user_group_relationship_is_bidirectional(self):
'''Test que se puede modificar la relación desde el lado del partner o el grupo.'''
"""Test que se puede modificar la relación desde el lado del partner o el grupo."""
partner = self.user.partner_id
# Opción 1: Agregar grupo al usuario (desde el lado del usuario/partner)
partner.member_ids = [(6, 0, [self.group1.id])]
self.assertIn(self.group1, partner.member_ids)
# Opción 2: Agregar usuario al grupo (desde el lado del grupo)
# Opción 2: Agregar usuario al grupo (desde el lado del grupo)
# Nota: Esto es una relación Many2many independiente
user2 = self.env['res.users'].create({
'name': 'Test User 2',
'login': 'testuser2@test.com',
'email': 'testuser2@test.com',
})
user2 = self.env["res.users"].create(
{
"name": "Test User 2",
"login": "testuser2@test.com",
"email": "testuser2@test.com",
}
)
self.group2.user_ids = [(6, 0, [user2.id])]
self.assertIn(user2, self.group2.user_ids)
def test_empty_group_ids(self):
'''Test que un partner sin grupos tiene group_ids vacío.'''
"""Test que un partner sin grupos tiene group_ids vacío."""
partner = self.user.partner_id
# Sin agregar a ningún grupo
self.assertEqual(len(partner.member_ids), 0)

View file

@ -11,7 +11,8 @@ draft sale orders.
See: website_sale_aplicoop/controllers/website_sale.py
"""
from datetime import datetime, timedelta
from datetime import datetime
from datetime import timedelta
from odoo.tests.common import TransactionCase
@ -23,60 +24,72 @@ class TestSaveOrderEndpoints(TransactionCase):
super().setUp()
# Create a consumer group
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
'email': 'group@test.com',
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
"email": "group@test.com",
}
)
# Create a group member (user partner)
self.member_partner = self.env['res.partner'].create({
'name': 'Group Member Partner',
'email': 'member@test.com',
})
self.member_partner = self.env["res.partner"].create(
{
"name": "Group Member Partner",
"email": "member@test.com",
}
)
# Add member to group
self.group.member_ids = [(4, self.member_partner.id)]
# Create test user
self.user = self.env['res.users'].create({
'name': 'Test User',
'login': 'testuser@test.com',
'email': 'testuser@test.com',
'partner_id': self.member_partner.id,
})
self.user = self.env["res.users"].create(
{
"name": "Test User",
"login": "testuser@test.com",
"email": "testuser@test.com",
"partner_id": self.member_partner.id,
}
)
# Create a group order
start_date = datetime.now().date()
end_date = start_date + timedelta(days=7)
self.group_order = self.env['group.order'].create({
'name': 'Test Group Order',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': start_date,
'end_date': end_date,
'period': 'weekly',
'pickup_day': '3', # Wednesday
'pickup_date': start_date + timedelta(days=3),
'home_delivery': False,
'cutoff_day': '0',
})
self.group_order = self.env["group.order"].create(
{
"name": "Test Group Order",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": start_date,
"end_date": end_date,
"period": "weekly",
"pickup_day": "3", # Wednesday
"pickup_date": start_date + timedelta(days=3),
"home_delivery": False,
"cutoff_day": "0",
}
)
# Open the group order
self.group_order.action_open()
# Create products for the order
self.category = self.env['product.category'].create({
'name': 'Test Category',
})
self.category = self.env["product.category"].create(
{
"name": "Test Category",
}
)
self.product = self.env['product.product'].create({
'name': 'Test Product',
'type': 'consu',
'list_price': 10.0,
'categ_id': self.category.id,
})
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"type": "consu",
"list_price": 10.0,
"categ_id": self.category.id,
}
)
# Associate product with group order
self.group_order.product_ids = [(4, self.product.id)]
@ -84,22 +97,22 @@ class TestSaveOrderEndpoints(TransactionCase):
def test_save_eskaera_draft_creates_order_with_group_order_id(self):
"""
Test that save_eskaera_draft() creates a sale.order with group_order_id.
This is the main fix: ensure that the /eskaera/save-order endpoint
correctly links the created sale.order to the group.order.
"""
# Simulate what the controller does: create order with group_order_id
order_vals = {
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'pickup_day': self.group_order.pickup_day,
'pickup_date': self.group_order.pickup_date,
'home_delivery': self.group_order.home_delivery,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"pickup_day": self.group_order.pickup_day,
"pickup_date": self.group_order.pickup_date,
"home_delivery": self.group_order.home_delivery,
"order_line": [],
"state": "draft",
}
sale_order = self.env['sale.order'].create(order_vals)
sale_order = self.env["sale.order"].create(order_vals)
# Verify the order was created with group_order_id
self.assertIsNotNone(sale_order.id)
@ -109,34 +122,34 @@ class TestSaveOrderEndpoints(TransactionCase):
def test_save_eskaera_draft_propagates_pickup_day(self):
"""Test that save_eskaera_draft() propagates pickup_day correctly."""
order_vals = {
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'pickup_day': self.group_order.pickup_day,
'pickup_date': self.group_order.pickup_date,
'home_delivery': self.group_order.home_delivery,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"pickup_day": self.group_order.pickup_day,
"pickup_date": self.group_order.pickup_date,
"home_delivery": self.group_order.home_delivery,
"order_line": [],
"state": "draft",
}
sale_order = self.env['sale.order'].create(order_vals)
sale_order = self.env["sale.order"].create(order_vals)
# Verify pickup_day was propagated
self.assertEqual(sale_order.pickup_day, '3')
self.assertEqual(sale_order.pickup_day, "3")
self.assertEqual(sale_order.pickup_day, self.group_order.pickup_day)
def test_save_eskaera_draft_propagates_pickup_date(self):
"""Test that save_eskaera_draft() propagates pickup_date correctly."""
order_vals = {
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'pickup_day': self.group_order.pickup_day,
'pickup_date': self.group_order.pickup_date,
'home_delivery': self.group_order.home_delivery,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"pickup_day": self.group_order.pickup_day,
"pickup_date": self.group_order.pickup_date,
"home_delivery": self.group_order.home_delivery,
"order_line": [],
"state": "draft",
}
sale_order = self.env['sale.order'].create(order_vals)
sale_order = self.env["sale.order"].create(order_vals)
# Verify pickup_date was propagated
self.assertEqual(sale_order.pickup_date, self.group_order.pickup_date)
@ -144,33 +157,35 @@ class TestSaveOrderEndpoints(TransactionCase):
def test_save_eskaera_draft_propagates_home_delivery(self):
"""Test that save_eskaera_draft() propagates home_delivery correctly."""
# Create a group order with home_delivery=True
group_order_home = self.env['group.order'].create({
'name': 'Test Group Order with Home Delivery',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date(),
'end_date': datetime.now().date() + timedelta(days=7),
'period': 'weekly',
'pickup_day': '3',
'pickup_date': datetime.now().date() + timedelta(days=3),
'home_delivery': True, # Enable home delivery
'cutoff_day': '0',
})
group_order_home = self.env["group.order"].create(
{
"name": "Test Group Order with Home Delivery",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date(),
"end_date": datetime.now().date() + timedelta(days=7),
"period": "weekly",
"pickup_day": "3",
"pickup_date": datetime.now().date() + timedelta(days=3),
"home_delivery": True, # Enable home delivery
"cutoff_day": "0",
}
)
group_order_home.action_open()
# Test with home_delivery=True
order_vals = {
'partner_id': self.member_partner.id,
'group_order_id': group_order_home.id,
'pickup_day': group_order_home.pickup_day,
'pickup_date': group_order_home.pickup_date,
'home_delivery': group_order_home.home_delivery,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"group_order_id": group_order_home.id,
"pickup_day": group_order_home.pickup_day,
"pickup_date": group_order_home.pickup_date,
"home_delivery": group_order_home.home_delivery,
"order_line": [],
"state": "draft",
}
sale_order = self.env['sale.order'].create(order_vals)
sale_order = self.env["sale.order"].create(order_vals)
# Verify home_delivery was propagated
self.assertTrue(sale_order.home_delivery)
@ -179,65 +194,65 @@ class TestSaveOrderEndpoints(TransactionCase):
def test_save_eskaera_draft_order_is_draft_state(self):
"""Test that save_eskaera_draft() creates order in draft state."""
order_vals = {
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'pickup_day': self.group_order.pickup_day,
'pickup_date': self.group_order.pickup_date,
'home_delivery': self.group_order.home_delivery,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"pickup_day": self.group_order.pickup_day,
"pickup_date": self.group_order.pickup_date,
"home_delivery": self.group_order.home_delivery,
"order_line": [],
"state": "draft",
}
sale_order = self.env['sale.order'].create(order_vals)
sale_order = self.env["sale.order"].create(order_vals)
# Verify order is in draft state
self.assertEqual(sale_order.state, 'draft')
self.assertEqual(sale_order.state, "draft")
def test_save_eskaera_draft_multiple_fields_together(self):
"""
Test that all fields are saved together correctly.
This test ensures that the fix didn't break any field and that
all group_order-related fields are propagated together.
"""
order_vals = {
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'pickup_day': self.group_order.pickup_day,
'pickup_date': self.group_order.pickup_date,
'home_delivery': self.group_order.home_delivery,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"pickup_day": self.group_order.pickup_day,
"pickup_date": self.group_order.pickup_date,
"home_delivery": self.group_order.home_delivery,
"order_line": [],
"state": "draft",
}
sale_order = self.env['sale.order'].create(order_vals)
sale_order = self.env["sale.order"].create(order_vals)
# Verify all fields together
self.assertEqual(sale_order.group_order_id.id, self.group_order.id)
self.assertEqual(sale_order.pickup_day, self.group_order.pickup_day)
self.assertEqual(sale_order.pickup_date, self.group_order.pickup_date)
self.assertEqual(sale_order.home_delivery, self.group_order.home_delivery)
self.assertEqual(sale_order.state, 'draft')
self.assertEqual(sale_order.state, "draft")
def test_save_cart_draft_also_saves_group_order_id(self):
"""
Test that save_cart_draft() (the working endpoint) also saves group_order_id.
This is a regression test to ensure that save_cart_draft() continues
to work correctly after the fix to save_eskaera_draft().
"""
# save_cart_draft should also include group_order_id
order_vals = {
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'pickup_day': self.group_order.pickup_day,
'pickup_date': self.group_order.pickup_date,
'home_delivery': self.group_order.home_delivery,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"pickup_day": self.group_order.pickup_day,
"pickup_date": self.group_order.pickup_date,
"home_delivery": self.group_order.home_delivery,
"order_line": [],
"state": "draft",
}
sale_order = self.env['sale.order'].create(order_vals)
sale_order = self.env["sale.order"].create(order_vals)
# Verify all fields
self.assertEqual(sale_order.group_order_id.id, self.group_order.id)
@ -247,18 +262,18 @@ class TestSaveOrderEndpoints(TransactionCase):
def test_save_draft_order_without_group_order_id_still_works(self):
"""
Test that creating a normal sale.order (without group_order_id) still works.
This ensures backward compatibility - you should still be able to create
sale orders without associating them to a group order.
"""
order_vals = {
'partner_id': self.member_partner.id,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"order_line": [],
"state": "draft",
# No group_order_id
}
sale_order = self.env['sale.order'].create(order_vals)
sale_order = self.env["sale.order"].create(order_vals)
# Verify order was created without group_order_id
self.assertIsNotNone(sale_order.id)
@ -267,62 +282,64 @@ class TestSaveOrderEndpoints(TransactionCase):
def test_group_order_id_field_exists_and_is_stored(self):
"""
Test that group_order_id field exists on sale.order and is stored correctly.
This is a sanity check to ensure the field is properly defined in the model.
"""
# Verify the field exists in the model
sale_order_model = self.env['sale.order']
self.assertIn('group_order_id', sale_order_model._fields)
sale_order_model = self.env["sale.order"]
self.assertIn("group_order_id", sale_order_model._fields)
# Verify it's a Many2one field
field = sale_order_model._fields['group_order_id']
self.assertEqual(field.type, 'many2one')
self.assertEqual(field.comodel_name, 'group.order')
field = sale_order_model._fields["group_order_id"]
self.assertEqual(field.type, "many2one")
self.assertEqual(field.comodel_name, "group.order")
def test_different_group_orders_map_to_different_sale_orders(self):
"""
Test that different group orders create separate sale orders.
This ensures that two users buying from different group orders
don't accidentally share the same sale.order.
"""
# Create a second group order
group_order_2 = self.env['group.order'].create({
'name': 'Test Group Order 2',
'group_ids': [(6, 0, [self.group.id])],
'type': 'regular',
'start_date': datetime.now().date() + timedelta(days=10),
'end_date': datetime.now().date() + timedelta(days=17),
'period': 'weekly',
'pickup_day': '5',
'pickup_date': datetime.now().date() + timedelta(days=12),
'home_delivery': True,
'cutoff_day': '0',
})
group_order_2 = self.env["group.order"].create(
{
"name": "Test Group Order 2",
"group_ids": [(6, 0, [self.group.id])],
"type": "regular",
"start_date": datetime.now().date() + timedelta(days=10),
"end_date": datetime.now().date() + timedelta(days=17),
"period": "weekly",
"pickup_day": "5",
"pickup_date": datetime.now().date() + timedelta(days=12),
"home_delivery": True,
"cutoff_day": "0",
}
)
group_order_2.action_open()
# Create order for first group order
order_vals_1 = {
'partner_id': self.member_partner.id,
'group_order_id': self.group_order.id,
'pickup_day': self.group_order.pickup_day,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"group_order_id": self.group_order.id,
"pickup_day": self.group_order.pickup_day,
"order_line": [],
"state": "draft",
}
sale_order_1 = self.env['sale.order'].create(order_vals_1)
sale_order_1 = self.env["sale.order"].create(order_vals_1)
# Create order for second group order
order_vals_2 = {
'partner_id': self.member_partner.id,
'group_order_id': group_order_2.id,
'pickup_day': group_order_2.pickup_day,
'order_line': [],
'state': 'draft',
"partner_id": self.member_partner.id,
"group_order_id": group_order_2.id,
"pickup_day": group_order_2.pickup_day,
"order_line": [],
"state": "draft",
}
sale_order_2 = self.env['sale.order'].create(order_vals_2)
sale_order_2 = self.env["sale.order"].create(order_vals_2)
# Verify they're different orders with different group_order_ids
self.assertNotEqual(sale_order_1.id, sale_order_2.id)

View file

@ -1,77 +1,90 @@
# Copyright 2025 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from datetime import date, timedelta
from odoo.tests.common import TransactionCase, tagged
from datetime import date
from datetime import timedelta
from odoo import _
from odoo.tests.common import TransactionCase
from odoo.tests.common import tagged
@tagged('post_install', '-at_install')
@tagged("post_install", "-at_install")
class TestTemplatesRendering(TransactionCase):
'''Test suite to verify QWeb templates work with day_names context.
"""Test suite to verify QWeb templates work with day_names context.
This test covers the fix for the issue where _() function calls
in QWeb t-value attributes caused TypeError: 'NoneType' object is not callable.
The fix moves day_names definition to Python controller and passes it as context.
'''
"""
def setUp(self):
'''Set up test data: create a test group order.'''
"""Set up test data: create a test group order."""
super().setUp()
# Create a test supplier
self.supplier = self.env['res.partner'].create({
'name': 'Test Supplier',
'is_company': True,
})
self.supplier = self.env["res.partner"].create(
{
"name": "Test Supplier",
"is_company": True,
}
)
# Create test products
self.product = self.env['product.product'].create({
'name': 'Test Product',
'type': 'consu', # consumable (consu), service, or storable
})
self.product = self.env["product.product"].create(
{
"name": "Test Product",
"type": "consu", # consumable (consu), service, or storable
}
)
# Create a test group
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
# Create a group order
self.group_order = self.env['group.order'].create({
'name': 'Test Order',
'state': 'open',
'supplier_ids': [(6, 0, [self.supplier.id])],
'product_ids': [(6, 0, [self.product.id])],
'group_ids': [(6, 0, [self.group.id])],
'start_date': date.today(),
'end_date': date.today() + timedelta(days=7),
'pickup_day': '5', # Saturday
'cutoff_day': '3', # Thursday
})
self.group_order = self.env["group.order"].create(
{
"name": "Test Order",
"state": "open",
"supplier_ids": [(6, 0, [self.supplier.id])],
"product_ids": [(6, 0, [self.product.id])],
"group_ids": [(6, 0, [self.group.id])],
"start_date": date.today(),
"end_date": date.today() + timedelta(days=7),
"pickup_day": "5", # Saturday
"cutoff_day": "3", # Thursday
}
)
def test_eskaera_page_template_exists(self):
'''Test that eskaera_page template compiles without errors.'''
template = self.env.ref('website_sale_aplicoop.eskaera_page')
"""Test that eskaera_page template compiles without errors."""
template = self.env.ref("website_sale_aplicoop.eskaera_page")
self.assertIsNotNone(template)
self.assertEqual(template.type, 'qweb')
self.assertEqual(template.type, "qweb")
def test_eskaera_shop_template_exists(self):
'''Test that eskaera_shop template compiles without errors.'''
template = self.env.ref('website_sale_aplicoop.eskaera_shop')
"""Test that eskaera_shop template compiles without errors."""
template = self.env.ref("website_sale_aplicoop.eskaera_shop")
self.assertIsNotNone(template)
self.assertEqual(template.type, 'qweb')
self.assertEqual(template.type, "qweb")
def test_eskaera_checkout_template_exists(self):
'''Test that eskaera_checkout template compiles without errors.'''
template = self.env.ref('website_sale_aplicoop.eskaera_checkout')
"""Test that eskaera_checkout template compiles without errors."""
template = self.env.ref("website_sale_aplicoop.eskaera_checkout")
self.assertIsNotNone(template)
self.assertEqual(template.type, 'qweb')
self.assertEqual(template.type, "qweb")
def test_day_names_context_is_provided(self):
'''Test that day_names context is provided by the controller method.'''
"""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 odoo.addons.website_sale_aplicoop.controllers.website_sale import (
AplicoopWebsiteSale,
)
controller = AplicoopWebsiteSale()
day_names = controller._get_day_names(env=self.env)
@ -86,45 +99,61 @@ class TestTemplatesRendering(TransactionCase):
self.assertGreater(len(day_name), 0, f"Day at index {i} is empty string")
def test_day_names_not_using_inline_underscore(self):
'''Test that day_names are defined in Python, not in t-value attributes.
"""Test that day_names are defined in Python, not in t-value attributes.
This test ensures the fix has been applied:
- day_names MUST be passed from controller context
- day_names MUST NOT be defined with _() inside t-value attributes
- Templates use day_names[index] from context, not t-set with _()
'''
template = self.env.ref('website_sale_aplicoop.eskaera_page')
"""
template = self.env.ref("website_sale_aplicoop.eskaera_page")
# Read the template source to verify it doesn't have inline _() in t-value
self.assertIn('day_names', template.arch_db,
"Template must reference day_names from context")
self.assertIn(
"day_names",
template.arch_db,
"Template must reference day_names from context",
)
# The fix ensures no <t t-set="day_names" t-value="[_(...)]"/> exists
# which was causing the NoneType error
def test_eskaera_checkout_summary_template_exists(self):
'''Test that eskaera_checkout_summary sub-template exists.'''
template = self.env.ref('website_sale_aplicoop.eskaera_checkout_summary')
"""Test that eskaera_checkout_summary sub-template exists."""
template = self.env.ref("website_sale_aplicoop.eskaera_checkout_summary")
self.assertIsNotNone(template)
self.assertEqual(template.type, 'qweb')
self.assertEqual(template.type, "qweb")
# Verify it has the expected structure
self.assertIn('checkout-summary-table', template.arch_db,
"Template must have checkout-summary-table id")
self.assertIn('Product', template.arch_db,
"Template must have Product label for translation")
self.assertIn('Quantity', template.arch_db,
"Template must have Quantity label for translation")
self.assertIn('Price', template.arch_db,
"Template must have Price label for translation")
self.assertIn('Subtotal', template.arch_db,
"Template must have Subtotal label for translation")
self.assertIn(
"checkout-summary-table",
template.arch_db,
"Template must have checkout-summary-table id",
)
self.assertIn(
"Product",
template.arch_db,
"Template must have Product label for translation",
)
self.assertIn(
"Quantity",
template.arch_db,
"Template must have Quantity label for translation",
)
self.assertIn(
"Price", template.arch_db, "Template must have Price label for translation"
)
self.assertIn(
"Subtotal",
template.arch_db,
"Template must have Subtotal label for translation",
)
def test_eskaera_checkout_summary_renders(self):
'''Test that eskaera_checkout_summary renders without errors.'''
template = self.env.ref('website_sale_aplicoop.eskaera_checkout_summary')
"""Test that eskaera_checkout_summary renders without errors."""
template = self.env.ref("website_sale_aplicoop.eskaera_checkout_summary")
# Render the template with empty context
html = template._render_template(template.xml_id, {})
# Should contain the basic table structure
self.assertIn('<table', html)
self.assertIn('checkout-summary-table', html)
self.assertIn('Product', html)
self.assertIn('Quantity', html)
self.assertIn("<table", html)
self.assertIn("checkout-summary-table", html)
self.assertIn("Product", html)
self.assertIn("Quantity", html)
self.assertIn("This order's cart is empty", html)

View file

@ -13,10 +13,12 @@ Coverage:
- group.order state transitions: illegal transitions
"""
from datetime import datetime, timedelta
from datetime import datetime
from datetime import timedelta
from odoo.exceptions import UserError
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError, UserError
class TestGroupOrderValidations(TransactionCase):
@ -25,87 +27,101 @@ class TestGroupOrderValidations(TransactionCase):
def setUp(self):
super().setUp()
self.company1 = self.env.company
self.company2 = self.env['res.company'].create({
'name': 'Company 2',
})
self.company2 = self.env["res.company"].create(
{
"name": "Company 2",
}
)
self.group_c1 = self.env['res.partner'].create({
'name': 'Group Company 1',
'is_company': True,
'company_id': self.company1.id,
})
self.group_c1 = self.env["res.partner"].create(
{
"name": "Group Company 1",
"is_company": True,
"company_id": self.company1.id,
}
)
self.group_c2 = self.env['res.partner'].create({
'name': 'Group Company 2',
'is_company': True,
'company_id': self.company2.id,
})
self.group_c2 = self.env["res.partner"].create(
{
"name": "Group Company 2",
"is_company": True,
"company_id": self.company2.id,
}
)
def test_group_order_same_company_constraint(self):
"""Test that all groups in an order must be from same company."""
start_date = datetime.now().date()
# Creating order with groups from different companies should fail
with self.assertRaises(ValidationError):
self.env['group.order'].create({
'name': 'Multi-Company Order',
'group_ids': [(6, 0, [self.group_c1.id, self.group_c2.id])],
'type': 'regular',
'start_date': start_date,
'end_date': start_date + timedelta(days=7),
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
self.env["group.order"].create(
{
"name": "Multi-Company Order",
"group_ids": [(6, 0, [self.group_c1.id, self.group_c2.id])],
"type": "regular",
"start_date": start_date,
"end_date": start_date + timedelta(days=7),
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
def test_group_order_same_company_mixed_single(self):
"""Test that single company group is valid."""
start_date = datetime.now().date()
# Single company should pass
order = self.env['group.order'].create({
'name': 'Single Company Order',
'group_ids': [(6, 0, [self.group_c1.id])],
'type': 'regular',
'start_date': start_date,
'end_date': start_date + timedelta(days=7),
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Single Company Order",
"group_ids": [(6, 0, [self.group_c1.id])],
"type": "regular",
"start_date": start_date,
"end_date": start_date + timedelta(days=7),
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
def test_group_order_date_validation_start_after_end(self):
"""Test that start_date must be before end_date."""
start_date = datetime.now().date()
end_date = start_date - timedelta(days=1) # End before start
with self.assertRaises(ValidationError):
self.env['group.order'].create({
'name': 'Bad Dates Order',
'group_ids': [(6, 0, [self.group_c1.id])],
'type': 'regular',
'start_date': start_date,
'end_date': end_date,
'period': 'weekly',
'pickup_day': '3',
'cutoff_day': '0',
})
self.env["group.order"].create(
{
"name": "Bad Dates Order",
"group_ids": [(6, 0, [self.group_c1.id])],
"type": "regular",
"start_date": start_date,
"end_date": end_date,
"period": "weekly",
"pickup_day": "3",
"cutoff_day": "0",
}
)
def test_group_order_date_validation_same_date(self):
"""Test that start_date == end_date is allowed (single-day order)."""
same_date = datetime.now().date()
order = self.env['group.order'].create({
'name': 'Same Day Order',
'group_ids': [(6, 0, [self.group_c1.id])],
'type': 'regular',
'start_date': same_date,
'end_date': same_date,
'period': 'once',
'pickup_day': '0',
'cutoff_day': '0',
})
order = self.env["group.order"].create(
{
"name": "Same Day Order",
"group_ids": [(6, 0, [self.group_c1.id])],
"type": "regular",
"start_date": same_date,
"end_date": same_date,
"period": "once",
"pickup_day": "0",
"cutoff_day": "0",
}
)
self.assertTrue(order.exists())
@ -114,43 +130,47 @@ class TestGroupOrderImageFallback(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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",
}
)
def test_image_fallback_order_image_first(self):
"""Test that order image takes priority over group image."""
# Set both order and group image
test_image = b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
test_image = b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
self.group_order.image_1920 = test_image
self.group.image_1920 = test_image
# Order image should be returned
computed_image = self.group_order.image_1920
self.assertEqual(computed_image, test_image)
def test_image_fallback_group_image_when_no_order_image(self):
"""Test fallback to group image when order has no image."""
test_image = b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
test_image = b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
# Only set group image
self.group_order.image_1920 = False
self.group.image_1920 = test_image
# Group image should be returned as fallback
# Note: This requires the computed field logic to be tested
# after field recalculation
@ -160,7 +180,7 @@ class TestGroupOrderImageFallback(TransactionCase):
# No images set
self.group_order.image_1920 = False
self.group.image_1920 = False
# Should be empty/False
computed_image = self.group_order.image_1920
self.assertFalse(computed_image)
@ -171,34 +191,42 @@ class TestGroupOrderProductCount(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
start_date = datetime.now().date()
self.group_order = self.env['group.order'].create({
'name': '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 = self.env["group.order"].create(
{
"name": "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.product1 = self.env['product.product'].create({
'name': 'Product 1',
'type': 'consu',
'list_price': 10.0,
})
self.product1 = self.env["product.product"].create(
{
"name": "Product 1",
"type": "consu",
"list_price": 10.0,
}
)
self.product2 = self.env['product.product'].create({
'name': 'Product 2',
'type': 'consu',
'list_price': 20.0,
})
self.product2 = self.env["product.product"].create(
{
"name": "Product 2",
"type": "consu",
"list_price": 20.0,
}
)
def test_product_count_initial_zero(self):
"""Test that new order has zero products."""
@ -232,28 +260,32 @@ class TestStateTransitions(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
start_date = datetime.now().date()
self.order = self.env['group.order'].create({
'name': '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.order = self.env["group.order"].create(
{
"name": "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",
}
)
def test_illegal_transition_draft_to_closed(self):
"""Test that Draft -> Closed transition is not allowed."""
# Should not allow skipping Open state
self.assertEqual(self.order.state, 'draft')
self.assertEqual(self.order.state, "draft")
# Calling action_close() without action_open() should fail
with self.assertRaises((ValidationError, UserError)):
self.order.action_close()
@ -261,36 +293,36 @@ class TestStateTransitions(TransactionCase):
def test_illegal_transition_cancelled_to_open(self):
"""Test that Cancelled -> Open transition is not allowed."""
self.order.action_cancel()
self.assertEqual(self.order.state, 'cancelled')
self.assertEqual(self.order.state, "cancelled")
# Should not allow re-opening cancelled order
with self.assertRaises((ValidationError, UserError)):
self.order.action_open()
def test_legal_transition_draft_open_closed(self):
"""Test that Draft -> Open -> Closed is allowed."""
self.assertEqual(self.order.state, 'draft')
self.assertEqual(self.order.state, "draft")
self.order.action_open()
self.assertEqual(self.order.state, 'open')
self.assertEqual(self.order.state, "open")
self.order.action_close()
self.assertEqual(self.order.state, 'closed')
self.assertEqual(self.order.state, "closed")
def test_transition_draft_to_cancelled(self):
"""Test that Draft -> Cancelled is allowed."""
self.assertEqual(self.order.state, 'draft')
self.assertEqual(self.order.state, "draft")
self.order.action_cancel()
self.assertEqual(self.order.state, 'cancelled')
self.assertEqual(self.order.state, "cancelled")
def test_transition_open_to_cancelled(self):
"""Test that Open -> Cancelled is allowed (emergency stop)."""
self.order.action_open()
self.assertEqual(self.order.state, 'open')
self.assertEqual(self.order.state, "open")
self.order.action_cancel()
self.assertEqual(self.order.state, 'cancelled')
self.assertEqual(self.order.state, "cancelled")
class TestUserPartnerValidation(TransactionCase):
@ -298,31 +330,37 @@ class TestUserPartnerValidation(TransactionCase):
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
# Create user without partner (edge case)
self.user_no_partner = self.env['res.users'].create({
'name': 'User No Partner',
'login': 'noparnter@test.com',
'partner_id': False, # Explicitly no partner
})
self.user_no_partner = self.env["res.users"].create(
{
"name": "User No Partner",
"login": "noparnter@test.com",
"partner_id": False, # Explicitly no partner
}
)
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({
'name': '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',
})
order = self.env["group.order"].create(
{
"name": "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",
}
)
# User without partner should not have access
# This should be validated in controller