Saltar a contenido

RFC-002: Normalización de match_categories

Fecha: 2026-01-15 Estado: Pendiente de implementación Autor: Sistema / HQuintero Relacionado con: RFC-001 (Unificación de Categorías)


Resumen Ejecutivo

Este documento describe el plan para normalizar la tabla match_categories, estableciendo una regla clara donde category_a siempre corresponde a un Supplier y category_b siempre corresponde a un Partner.


Problema Actual

La tabla match_categories actualmente mezcla diferentes tipos de relaciones sin una estructura clara:

Estado Actual (162 matches)

Tipo de Relación Cantidad Problema
Supplier CL → Supplier Externo 115 Relación entre suppliers, no hacia partners
Partner TN → Supplier CL 37 Invertido (Partner en A, Supplier en B)
Huérfanos 10 category_a apunta a IDs inexistentes

Desglose de Supplier → Supplier (115)

Relación Cantidad
Supplier:1 (CL) → Supplier:2 (FX - Fastrax) 37
Supplier:1 (CL) → Supplier:999 (CPI - Compras Paraguai) 49
Supplier:1 (CL) → Supplier:888 (NGO) 25
Supplier:1 (CL) → Supplier:8 (TG - Todegol) 2
Supplier:1 (CL) → Supplier:3 (GT - Gametec) 1
Supplier:1 (CL) → Supplier:9 (JWE) 1

Matches Huérfanos (10)

Match ID category_a_id category_b (nombre)
84 870 (NO EXISTE) Cooler p/ Gabinete
83 870 (NO EXISTE) Memoria RAM para Notebook
86 870 (NO EXISTE) Memoria RAM para PC
82 870 (NO EXISTE) Notebooks
85 870 (NO EXISTE) Procesadores
80 871 (NO EXISTE) Celulares
79 877 (NO EXISTE) Auriculares
78 880 (NO EXISTE) Tablets
87 895 (NO EXISTE) Impresoras
81 934 (NO EXISTE) Aire Acondicionado

Propuesta de Solución

Nueva Regla

match_categories:
  category_a_id = SIEMPRE Supplier (cualquiera: CL, FX, NGO, CPI, etc.)
  category_b_id = SIEMPRE Partner (cualquiera: CL, TN, etc.)

Propósito

Sugerir categoría de Partner al confirmar un producto que viene de un Supplier.

Flujo Propuesto

┌─────────────────────────────────────────────────────────────────┐
│  ENTRADA                        SALIDA                          │
│                                                                  │
│  Category (Supplier FX)  ──match──►  Category (Partner CL)      │
│  Category (Supplier NGO) ──match──►  Category (Partner CL)      │
│  Category (Supplier CPI) ──match──►  Category (Partner CL)      │
│  Category (Supplier CL)  ──match──►  Category (Partner TN)      │
│  Category (Supplier CL)  ──match──►  Category (Partner CL)      │
│                                                                  │
│  + propagación: Si Supplier X → CL y CL → TN,                   │
│                 entonces crear Supplier X → TN                   │
└─────────────────────────────────────────────────────────────────┘

Transformaciones Requeridas

1. Matches Supplier CL → Supplier Externo (115 registros)

Lógica de transformación:

ANTES:
  Supplier CL (cat_a) → Supplier FX (cat_b)

DESPUÉS:
  1. Buscar Partner CL con mismo nombre que Supplier CL
  2. Crear: Supplier FX → Partner CL
  3. Si Supplier CL tiene match con Partner TN:
     Crear: Supplier FX → Partner TN
  4. Eliminar match original

Ejemplo concreto (verificado en base de datos 2026-01-15):

ANTES (estado actual):
  match_categories:
    | category_a_id | category_b_id |
    | 2 (Supplier CL: Accesorios p/ Notebook) | 110 (Supplier FX: Accesorios) |

  Y existe (invertido):
    | 1325 (Partner TN: Accesorios y Complementos) | 2 (Supplier CL: Accesorios p/ Notebook) |

DESPUÉS (normalizado):
  match_categories:
    | category_a_id | category_b_id |
    | 110 (Supplier FX: Accesorios) | 1875 (Partner CL: Accesorios p/ Notebook) |
    | 110 (Supplier FX: Accesorios) | 1325 (Partner TN: Accesorios y Complementos) |
    | 2 (Supplier CL: Accesorios p/ Notebook) | 1875 (Partner CL: Accesorios p/ Notebook) |
    | 2 (Supplier CL: Accesorios p/ Notebook) | 1325 (Partner TN: Accesorios y Complementos) |

IDs reales verificados: - Supplier CL "Accesorios p/ Notebook": ID 2 - Supplier FX "Accesorios": ID 110 - Partner CL "Accesorios p/ Notebook": ID 1875 - Partner TN "Accesorios y Complementos de Computadora": ID 1325

2. Matches Partner TN → Supplier CL (37 registros)

Lógica de transformación:

ANTES:
  Partner TN (cat_a) → Supplier CL (cat_b)

DESPUÉS:
  Supplier CL (cat_a) → Partner TN (cat_b)
  (simplemente invertir)

3. Nuevos matches Supplier CL → Partner CL

Lógica:

Para cada categoría de Supplier CL:
  1. Buscar categoría de Partner CL con mismo nombre
  2. Si existe: crear match Supplier CL → Partner CL
  3. Si no existe: no crear (no crear categorías faltantes)

Categorías de Supplier CL sin equivalente en Partner CL (9): - Celulares - Pantallas interactivas - Protector - Usados - Antishock - Servicios - NB USADAS - Test 1 - Test 2

Decisión: No crear estas categorías. Los matches no se crearán para ellas.

4. Eliminación de huérfanos (10 registros)

Eliminar matches con IDs: 78, 79, 80, 81, 82, 83, 84, 85, 86, 87


Resultado Esperado

Antes de la Migración

Tipo Cantidad
Supplier → Supplier 115
Partner → Supplier 37
Huérfanos 10
Total 162

Después de la Migración (estimado)

Tipo de Match Cantidad Estimada
Supplier CL → Partner CL ~94
Supplier CL → Partner TN 37
Supplier FX → Partner CL ~37
Supplier FX → Partner TN ~10-15
Supplier NGO → Partner CL ~25
Supplier NGO → Partner TN ~8-10
Supplier CPI → Partner CL ~49
Supplier CPI → Partner TN ~12-15
Otros suppliers → Partners ~4
Total estimado ~280-320

Validación del Modelo

Cambios en MatchCategory::add()

// ANTES: Validación parcial
if ($categoryA->categorizable_type == Supplier::class) {
    if ($categoryA->categorizable_id != SupplierConstants::CL) {
        return "Categoría A debe ser de CL";
    }
}

// DESPUÉS: Validación estricta
if ($categoryA->categorizable_type !== Supplier::class) {
    return "Categoría A debe ser de un Supplier";
}

if ($categoryB->categorizable_type !== Partner::class) {
    return "Categoría B debe ser de un Partner";
}

Dependencias

Servicios que usan match_categories

Servicio Archivo Uso
ProductService app/Services/ProductService.php getTNCategoriesIds(), getMatchesWithTN()
ProductTransformer app/Services/TiendaNaranja/Transformers/ProductTransformer.php getTNCategoriesFromProductItem()
MatchCategory Model app/Models/MatchCategory.php getMatches(), getMatchesWithTN()

Impacto en servicios

Después de la normalización, los métodos existentes seguirán funcionando porque: - getMatchesWithTN() busca matches donde alguna categoría sea de Partner TN - La lógica de búsqueda no cambia, solo la estructura de datos


Plan de Implementación

Fase 1: Preparación

  1. Backup de tabla match_categories
  2. Crear comando de diagnóstico (dry-run)

Fase 2: Ejecución

  1. Eliminar huérfanos (10 registros)
  2. Invertir matches Partner → Supplier (37 registros)
  3. Transformar matches Supplier CL → Supplier Externo (115 registros)
  4. Crear matches Supplier CL → Partner CL (~94 registros)

Fase 3: Validación

  1. Verificar que todos los matches cumplan la regla
  2. Actualizar validación en MatchCategory::add()
  3. Probar flujo de confirmación de productos

Comandos a Crear

# Diagnóstico (solo lectura)
php artisan match-categories:diagnose

# Migración (con backup automático)
php artisan match-categories:normalize

# Verificación post-migración
php artisan match-categories:verify

Riesgos y Mitigación

Riesgo Mitigación
Pérdida de datos Backup obligatorio antes de migración
Matches duplicados Verificar unicidad antes de insertar
Servicios afectados Los métodos existentes son compatibles con la nueva estructura

Verificación Técnica (2026-01-15)

Análisis del Código Actual

El método ProductService::getTNCategoriesIds() busca matches de forma bidireccional:

// Línea 129 de ProductService.php
$relatedCategoryId = $match->category_a_id == $categoryId
    ? $match->category_b_id
    : $match->category_a_id;

Esto significa que actualmente no importa en qué columna esté la categoría, el sistema busca la otra. Después de la normalización, esto seguirá funcionando porque la búsqueda es bidireccional.

Propósito Semántico Confirmado

La pregunta que responde el match es:

"Dado un producto con categoría X de Supplier Y, ¿a qué categoría de Partner Z debe asignarse?"

Por lo tanto: - category_a = Categoría de ENTRADA (Supplier - origen del producto) - category_b = Categoría de SALIDA (Partner - destino de asignación)

Datos Verificados en Base de Datos

Entidad Nombre ID
Supplier CL Accesorios p/ Notebook 2
Supplier FX Accesorios 110
Partner CL Accesorios p/ Notebook 1875
Partner TN Accesorios y Complementos de Computadora 1325

Compatibilidad Post-Migración

Los servicios existentes (ProductService, ProductTransformer) seguirán funcionando porque:

  1. getMatchesWithTN() busca matches donde alguna categoría sea de Partner TN
  2. getTNCategoriesIds() usa búsqueda bidireccional
  3. La lógica no asume una dirección específica

Notas Adicionales

  • Esta migración NO elimina la tabla match_categories, solo normaliza su contenido
  • La relación product_partner_categories (RFC-001) es independiente y complementaria
  • El match sirve para SUGERIR, la relación explícita en product_partner_categories es la definitiva

Aprobación

  • [ ] Revisado por: ___
  • [ ] Aprobado por: ___
  • [ ] Fecha de implementación: ___