Aplicoop desde el repo de kidekoop

This commit is contained in:
snt 2026-02-11 15:32:11 +01:00
parent 69917d1ec2
commit 7cff89e418
93 changed files with 313992 additions and 0 deletions

View file

@ -0,0 +1,432 @@
# Copyright 2025 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
"""
Test suite for product discovery logic in website_sale_aplicoop.
The discovery mechanism uses 3 sources:
1. product_ids: Directly linked products
2. category_ids: Products from linked categories (recursive)
3. supplier_ids: Products from linked suppliers
Coverage:
- Correct union of all 3 sources (no duplicates)
- Deep category hierarchies (nested categories)
- Empty sources (empty categories/suppliers)
- Product filters (is_published, sale_ok)
- Ordering and deduplication
"""
from datetime import datetime, timedelta
from odoo.tests.common import TransactionCase
class TestProductDiscoveryUnion(TransactionCase):
"""Test that product discovery returns correct union of 3 sources."""
def setUp(self):
super().setUp()
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,
})
# Create categories
self.category1 = self.env['product.category'].create({
'name': 'Category 1',
})
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,
})
# 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,
})
# 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,
})
# 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,
})
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',
})
def test_discovery_from_direct_products(self):
"""Test discovery returns directly linked products."""
self.group_order.product_ids = [(4, self.direct_product.id)]
discovered = self.group_order.product_ids
self.assertIn(self.direct_product, discovered)
def test_discovery_from_categories(self):
"""Test discovery includes products from linked categories."""
self.group_order.category_ids = [(4, self.category1.id)]
discovered = self.group_order.product_ids # Computed
# Should include cat1_product and supplier_product (both in category1)
# Note: depends on how discovery is computed
def test_discovery_from_suppliers(self):
"""Test discovery includes products from linked suppliers."""
self.group_order.supplier_ids = [(4, self.supplier.id)]
# Should include supplier_product
# Note: depends on how supplier link is implemented
def test_discovery_union_no_duplicates(self):
"""Test that union doesn't include same product twice."""
# Add supplier_product via:
# 1. Direct link
# 2. Category link (cat1)
# 3. Supplier link
self.group_order.product_ids = [(4, self.supplier_product.id)]
self.group_order.category_ids = [(4, self.category1.id)]
self.group_order.supplier_ids = [(4, self.supplier.id)]
discovered = self.group_order.product_ids
# Count occurrences of supplier_product
count = sum(1 for p in discovered if p == self.supplier_product)
# Should appear only once
self.assertEqual(count, 1)
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,
})
self.group_order.category_ids = [(4, self.category1.id)]
discovered = self.group_order.product_ids
# Unpublished should not be in discovered
self.assertNotIn(unpublished, discovered)
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,
})
self.group_order.category_ids = [(4, self.category1.id)]
discovered = self.group_order.product_ids
# Not for sale should not be in discovered
self.assertNotIn(not_for_sale, discovered)
class TestDeepCategoryHierarchies(TransactionCase):
"""Test product discovery with nested category structures."""
def setUp(self):
super().setUp()
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_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_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,
})
# 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_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,
})
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',
})
def test_discovery_root_category_includes_all_descendants(self):
"""Test that linking root category discovers all nested products."""
self.group_order.category_ids = [(4, self.cat_l1.id)]
discovered = self.group_order.product_ids
# Should include products from L2, L4, L5 (all descendants)
self.assertIn(self.product_l2, discovered)
self.assertIn(self.product_l4, discovered)
self.assertIn(self.product_l5, discovered)
def test_discovery_mid_level_category_includes_descendants(self):
"""Test discovery from middle of hierarchy."""
self.group_order.category_ids = [(4, self.cat_l3.id)]
discovered = self.group_order.product_ids
# Should include L4 and L5 (descendants of L3)
self.assertIn(self.product_l4, discovered)
self.assertIn(self.product_l5, discovered)
# Should not include L2 (ancestor)
self.assertNotIn(self.product_l2, discovered)
def test_discovery_leaf_category_only_own_products(self):
"""Test discovery from leaf (deepest) category."""
self.group_order.category_ids = [(4, self.cat_l5.id)]
discovered = self.group_order.product_ids
# Should only include products directly in L5
self.assertIn(self.product_l5, discovered)
self.assertNotIn(self.product_l4, discovered)
def test_discovery_circular_category_reference(self):
"""Test handling of circular category references (edge case)."""
# Create circular reference (if allowed): L1 -> L2 -> L1
# This should be prevented by Odoo constraints
# or handled gracefully in discovery logic
# Attempt to create circular ref may fail
try:
self.cat_l1.parent_id = self.cat_l5.id # Creates loop
except:
# Expected: Odoo should prevent circular refs
pass
class TestEmptySourcesDiscovery(TransactionCase):
"""Test discovery behavior with empty/null sources."""
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
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,
})
# 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',
})
def test_discovery_empty_category(self):
"""Test discovery from empty category."""
self.group_order.category_ids = [(4, self.category.id)]
discovered = self.group_order.product_ids
# Should return empty list
self.assertEqual(len(discovered), 0)
def test_discovery_empty_supplier(self):
"""Test discovery from supplier with no products."""
self.group_order.supplier_ids = [(4, self.supplier.id)]
discovered = self.group_order.product_ids
# Should return empty list
self.assertEqual(len(discovered), 0)
def test_discovery_all_sources_empty(self):
"""Test when all 3 sources are empty."""
# No direct products, empty category, empty supplier
self.group_order.product_ids = [(6, 0, [])]
self.group_order.category_ids = [(4, self.category.id)]
self.group_order.supplier_ids = [(4, self.supplier.id)]
discovered = self.group_order.product_ids
# Should return empty
self.assertEqual(len(discovered), 0)
class TestProductDiscoveryOrdering(TransactionCase):
"""Test that discovered products are returned in consistent order."""
def setUp(self):
super().setUp()
self.group = self.env['res.partner'].create({
'name': 'Test Group',
'is_company': True,
})
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,
})
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',
})
def test_discovery_consistent_ordering(self):
"""Test that repeated calls return same order."""
self.group_order.category_ids = [(4, self.category.id)]
discovered1 = list(self.group_order.product_ids)
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]
)
def test_discovery_alphabetical_or_price_order(self):
"""Test that products are ordered predictably."""
self.group_order.category_ids = [(4, self.category.id)]
discovered = list(self.group_order.product_ids)
# 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)
self.assertEqual(discovered_ids, expected_ids)