# 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 TestEskaerShop(TransactionCase): '''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', }) # Crear usuario miembro del grupo 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, }) # 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.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', }) # 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_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 = 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.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])], }) order.action_open() # Simular lo que hace eskaera_shop products = order.product_ids 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')) 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])], }) 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), ]) # 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')) 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])], }) 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), ]) 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') # Debe incluir el producto del proveedor self.assertEqual(len(products), 1) 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])], }) order.action_open() # Simular lo que hace eskaera_shop con prioridad products = order.product_ids # 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')) # 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') 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])], }) 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), ]) 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') # Debe retornar productos del proveedor self.assertEqual(len(products), 1) 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')) 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 }) 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), ]) 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') # Debe estar vacío self.assertEqual(len(products), 0)