[ADD] website_sale_aplicoop: Supplier blacklist feature for group orders

- Add excluded_supplier_ids field for supplier exclusion
- Filter products by main_seller_id (from product_main_seller addon)
- Blacklist has absolute priority over all inclusion sources
- Products with blacklisted main supplier never appear in orders
- Update _get_products_for_group_order() with supplier blacklist logic
- Add excluded_supplier_ids to 'Productos Excluidos' section in form view
- Add comprehensive test suite (TestSupplierBlacklist class with 9 tests):
  * Test exclusion by main_seller_id
  * Test multiple supplier exclusion
  * Test products without main seller not affected
  * Test blacklist with direct product inclusion
  * Test blacklist priority over supplier inclusion
  * Test combined product and supplier blacklist
  * Test available_products_count with supplier blacklist
- Add Spanish and Euskera translations
- Update available_products_count computation to include excluded_supplier_ids
- Version bump to 18.0.1.5.0

Use case: Exclude all products from specific supplier (e.g., temporary unavailability)
Example: Category with 100 products, exclude supplier X → all products from X excluded
Workflow: Bulk inclusion via categories + supplier-level exclusion + product-level exclusion
This commit is contained in:
snt 2026-02-22 21:35:40 +01:00
parent 75ebb7b907
commit d90f2cdc61
7 changed files with 371 additions and 4 deletions

View file

@ -733,3 +733,269 @@ class TestProductBlacklist(TransactionCase):
# Count should decrease by 1
new_count = self.group_order.available_products_count
self.assertEqual(new_count, initial_count - 1)
class TestSupplierBlacklist(TransactionCase):
"""Test supplier blacklist (excluded_supplier_ids) functionality.
The supplier blacklist filters out products whose main_seller_id
(from product_main_seller addon) is in the excluded suppliers list.
Blacklist has absolute priority over inclusion sources.
"""
def setUp(self):
super().setUp()
self.group = self.env["res.partner"].create(
{
"name": "Test Group",
"is_company": True,
}
)
# Create suppliers
self.supplier_A = self.env["res.partner"].create(
{
"name": "Supplier A",
"is_company": True,
"supplier_rank": 1,
}
)
self.supplier_B = self.env["res.partner"].create(
{
"name": "Supplier B",
"is_company": True,
"supplier_rank": 1,
}
)
self.supplier_C = self.env["res.partner"].create(
{
"name": "Supplier C",
"is_company": True,
"supplier_rank": 1,
}
)
# Create category
self.category = self.env["product.category"].create(
{
"name": "Test Category",
}
)
# Create products with different main sellers
# Product 1: main seller = Supplier A
tmpl_1 = self.env["product.template"].create(
{
"name": "Product from Supplier A",
"type": "consu",
"list_price": 10.0,
"categ_id": self.category.id,
"is_published": True,
"sale_ok": True,
"main_seller_id": self.supplier_A.id,
}
)
self.product_A = tmpl_1.product_variant_ids[0]
# Product 2: main seller = Supplier B
tmpl_2 = self.env["product.template"].create(
{
"name": "Product from Supplier B",
"type": "consu",
"list_price": 20.0,
"categ_id": self.category.id,
"is_published": True,
"sale_ok": True,
"main_seller_id": self.supplier_B.id,
}
)
self.product_B = tmpl_2.product_variant_ids[0]
# Product 3: main seller = Supplier C
tmpl_3 = self.env["product.template"].create(
{
"name": "Product from Supplier C",
"type": "consu",
"list_price": 30.0,
"categ_id": self.category.id,
"is_published": True,
"sale_ok": True,
"main_seller_id": self.supplier_C.id,
}
)
self.product_C = tmpl_3.product_variant_ids[0]
# Product 4: no main seller
tmpl_4 = self.env["product.template"].create(
{
"name": "Product without main seller",
"type": "consu",
"list_price": 40.0,
"categ_id": self.category.id,
"is_published": True,
"sale_ok": True,
}
)
self.product_no_seller = tmpl_4.product_variant_ids[0]
start_date = datetime.now().date()
self.group_order = self.env["group.order"].create(
{
"name": "Test Supplier Blacklist 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_supplier_blacklist_excludes_by_main_seller(self):
"""Test that supplier blacklist excludes products by main_seller_id."""
# Add all products via category
self.group_order.category_ids = [(4, self.category.id)]
# All products should be discoverable initially
products = self.group_order._get_products_for_group_order(self.group_order.id)
self.assertIn(self.product_A, products)
self.assertIn(self.product_B, products)
self.assertIn(self.product_C, products)
self.assertIn(self.product_no_seller, products)
# Exclude Supplier A
self.group_order.excluded_supplier_ids = [(4, self.supplier_A.id)]
# Product A should NOT be discoverable anymore
products = self.group_order._get_products_for_group_order(self.group_order.id)
self.assertNotIn(self.product_A, products)
self.assertIn(self.product_B, products)
self.assertIn(self.product_C, products)
self.assertIn(self.product_no_seller, products)
def test_supplier_blacklist_multiple_suppliers(self):
"""Test excluding multiple suppliers at once."""
# Add all products via category
self.group_order.category_ids = [(4, self.category.id)]
# Exclude Suppliers A and B
self.group_order.excluded_supplier_ids = [
(4, self.supplier_A.id),
(4, self.supplier_B.id),
]
products = self.group_order._get_products_for_group_order(self.group_order.id)
# Products A and B should NOT be in results
self.assertNotIn(self.product_A, products)
self.assertNotIn(self.product_B, products)
# But product C and no-seller product should be there
self.assertIn(self.product_C, products)
self.assertIn(self.product_no_seller, products)
def test_supplier_blacklist_does_not_affect_no_main_seller(self):
"""Test that products without main_seller_id are not affected by supplier blacklist."""
# Add all products via category
self.group_order.category_ids = [(4, self.category.id)]
# Exclude all suppliers
self.group_order.excluded_supplier_ids = [
(4, self.supplier_A.id),
(4, self.supplier_B.id),
(4, self.supplier_C.id),
]
products = self.group_order._get_products_for_group_order(self.group_order.id)
# Products with main sellers should NOT be in results
self.assertNotIn(self.product_A, products)
self.assertNotIn(self.product_B, products)
self.assertNotIn(self.product_C, products)
# But product without main seller should still be there
self.assertIn(self.product_no_seller, products)
def test_supplier_blacklist_with_direct_product_inclusion(self):
"""Test that supplier blacklist affects even directly included products."""
# Add product A directly
self.group_order.product_ids = [(4, self.product_A.id)]
# Product should be discoverable
products = self.group_order._get_products_for_group_order(self.group_order.id)
self.assertIn(self.product_A, products)
# Exclude Supplier A
self.group_order.excluded_supplier_ids = [(4, self.supplier_A.id)]
# Product A should NOT be discoverable anymore, even though directly included
products = self.group_order._get_products_for_group_order(self.group_order.id)
self.assertNotIn(self.product_A, products)
def test_supplier_blacklist_with_supplier_inclusion(self):
"""Test that supplier blacklist has priority over supplier inclusion."""
# Add Supplier A to included suppliers
self.group_order.supplier_ids = [(4, self.supplier_A.id)]
# Also add Supplier A to excluded suppliers (blacklist has priority)
self.group_order.excluded_supplier_ids = [(4, self.supplier_A.id)]
products = self.group_order._get_products_for_group_order(self.group_order.id)
# Product A should NOT be discoverable (blacklist wins)
self.assertNotIn(self.product_A, products)
def test_empty_supplier_blacklist_no_effect(self):
"""Test that empty excluded_supplier_ids doesn't affect discovery."""
# Add products via category
self.group_order.category_ids = [(4, self.category.id)]
# All products should be discoverable
products = self.group_order._get_products_for_group_order(self.group_order.id)
self.assertIn(self.product_A, products)
self.assertIn(self.product_B, products)
self.assertIn(self.product_C, products)
# Excluded supplier list is empty - should have no effect
self.assertEqual(len(self.group_order.excluded_supplier_ids), 0)
def test_supplier_and_product_blacklist_combined(self):
"""Test that both product and supplier blacklists work together."""
# Add all products via category
self.group_order.category_ids = [(4, self.category.id)]
# Exclude Supplier A (affects product_A)
self.group_order.excluded_supplier_ids = [(4, self.supplier_A.id)]
# Exclude product B directly
self.group_order.excluded_product_ids = [(4, self.product_B.id)]
products = self.group_order._get_products_for_group_order(self.group_order.id)
# Products A and B should NOT be in results
self.assertNotIn(self.product_A, products)
self.assertNotIn(self.product_B, products)
# But products C and no-seller should be there
self.assertIn(self.product_C, products)
self.assertIn(self.product_no_seller, products)
def test_supplier_blacklist_available_products_count(self):
"""Test that available_products_count reflects supplier blacklist."""
# Add products
self.group_order.category_ids = [(4, self.category.id)]
# Count should include all 4 products
initial_count = self.group_order.available_products_count
self.assertEqual(initial_count, 4)
# Exclude Supplier A
self.group_order.excluded_supplier_ids = [(4, self.supplier_A.id)]
# Count should decrease by 1 (product_A excluded)
new_count = self.group_order.available_products_count
self.assertEqual(new_count, 3)