Saltearse al contenido

Portafolio

Portafolio es la oferta comercial del sitio: productos y servicios con precio, categoría, imágenes y variantes. Se usa para cargar lo que se vende, publicarlo y retirarlo cuando ya no. Ojo con el nombre: lo que antes era el módulo catalogo es hoy Portafolio, con clave portfolio.

  • Tres altitudes. La oferta base (offer_items) guarda precio, slug, categoría, activo, imágenes y descripción: es lo que cotización, pedido, POS y cobro referencian. Encima, un producto añade medida, norma, variantes, especificaciones y video; un servicio añade beneficios y no tiene existencias.
  • CRUD de oferta, árbol de categorías, atributos y vocabulario de búsqueda (sinónimos y equivalencias de medida).
  • El type decide qué se crea: un servicio nunca toca los campos exclusivos de producto.
  • is_active es el único interruptor de publicación: apagarlo saca la ficha del sitio, del listado, de las facetas y del conteo por categoría sin borrar la fila. Al encenderlo vuelve entera.
  • Para apagar sin panel: php artisan catalog:product-state <sitio|id> <slug> <on|off> [--dry]. En producción se dispara por la entrada product_state del despliegue, porque no hay SSH.
  • Categorías anidadas por parent_id, sin límite de profundidad, con guarda contra ciclos. Al borrar una categoría, las hijas suben a la abuela.
  • Es núcleo: viene en los cuatro planes y no se apaga desde el panel.
  • De la clave portfolio en los controladores de producto, categoría, atributo y vocabulario. Listar sin el módulo devuelve 200 con lista vacía; escribir devuelve 403 {"module":"portfolio"}.
  • Varios módulos lo leen sin importarlo —cotizaciones, pedidos, POS, inventario y la bitácora— por el contrato de núcleo CatalogQuery.

No se puede apagar desde el panel: es núcleo, y el interruptor responde 422. Si el sitio pierde el módulo, las escrituras dan 403 y los listados salen vacíos, pero los datos quedan intactos. Apagar una ficha con is_active no la borra: se retira del sitio y vuelve con el mismo slug y la misma URL.

No confundas eso con destroy, que borra de verdad y arrastra en cascada producto, servicio, variantes y especificaciones. No es la forma de retirar algo del catálogo.

  • El type se fija al crear. No hay endpoint para convertir un producto existente en servicio ni al revés.
  • Un servicio nunca mueve existencias: todo punto que toca stock filtra por stockableIdsForSite(), que solo devuelve productos. Ajustar stock sobre un servicio da 422.
  • La categoría de un plan de Merez no se puede borrar: corta con 409.
  • catalog:sync-plan-offers no tiene disparador automático. Cambiar el precio de un plan no actualiza su oferta espejo hasta la próxima corrida manual.
  • Los beneficios derivados del plan no se borran al editar los manuales, y al revés: los dos orígenes conviven en la misma ficha.
  • El contrato que leen cotizaciones y pedidos castea el precio a entero. Con precios que lleven centavos, trunca; no hay decisión escrita de que eso sea intencional.
  • Las ofertas espejo de los planes nunca salen en el catálogo público.