🔄 Sincronización Automática de Productos a Shopify
📋 Descripción
Sistema de sincronización automática que replica productos y variantes creados desde ThreeTrackr hacia Shopify cuando la integración está activa y configurada para sincronizar inventario.
🏗️ Arquitectura Implementada
📦 Archivos Creados/Modificados
✅ Eventos
events/product-events.ts- Eventos para creación de productos y variantes
✅ Listeners
listeners/shopify-product.listener.ts- Maneja eventos de productos y sincroniza a Shopify
✅ Adapters (Extendido)
adapters/shopify-adapter.ts- Métodos para crear productos/variantes en Shopify
✅ Servicios (Modificado)
tenant/services/tenant-product-variant.service.ts- Emite eventos al crear variantes
✅ Resolvers (Modificado)
tenant/resolvers/tenant-product-variant.resolver.ts- Pasa organizationId al servicio
✅ Módulos (Actualizado)
integrations/integrations.module.ts- Incluye el nuevo listener
🔄 Flujo de Sincronización
1. **Creación de Variante en ThreeTrackr**
Usuario crea variante → TenantProductVariantResolver → TenantProductVariantService
2. **Emisión de Evento**
TenantProductVariantService.create() → EventEmitter.emit('tenant.product-variant.created')
3. **Procesamiento del Evento**
ShopifyProductListener.handleProductVariantCreated()
4. **Validaciones**
- ✅ Integración de Shopify activa (
status: "ACTIVE") - ✅ Integración configurada (
isConfigured: true) - ✅ Sincronización de inventario habilitada (
settings.syncInventory: true)
5. **Sincronización a Shopify**
CREATE:
Si producto existe:
ShopifyAdapter.addVariantToExistingProduct() → REST API de Shopify
Si producto NO existe:
ShopifyAdapter.createProductInShopify() → GraphQL + REST API de Shopify
UPDATE:
ShopifyAdapter.updateVariantInShopify() → REST API de Shopify
Si variante no existe: ShopifyAdapter.createVariantInShopifyProduct() → REST API de Shopify
DELETE:
ShopifyAdapter.deleteVariantFromShopify() → REST API de Shopify
⚙️ Configuración Requerida
🔧 Integración de Shopify
En el panel de integraciones, la integración de Shopify debe tener:
{
"status": "ACTIVE",
"isConfigured": true,
"storeUrl": "store.myshopify.com",
"apiKey": "shpat_xxxxx",
"apiVersion": "2025-07",
"settings": "{\"syncInventory\": true}"
}
📋 Campo settings (JSON)
{
"syncInventory": true, // ← Checkbox de sincronización de inventario
"syncOrders": true, // Para órdenes (ya implementado)
"syncCustomers": false // Para clientes (futuro)
}
🚀 Funcionalidades Implementadas
✅ Creación de Productos Completos
- Producto principal con metadatos (nombre, descripción, vendor, etc.)
- Variantes con opciones (talla, color, material)
- Inventario inicial por sucursal
- Imágenes y SEO
✅ Gestión de Opciones
- Option1 Talla (automático)
- Option2 Color (si existe)
- Option3 Material (si existe)
✅ Mapeo de Inventario
- Suma de inventario disponible de todas las sucursales
- Configuración automática de tracking de inventario
- Política de inventario (deny por defecto)
✅ Manejo de Errores
- Logging detallado de errores
- Continuación del flujo aunque falle la sincronización
- Actualización de
lastUsedAten integraciones exitosas
📊 Datos Sincronizados
🛍️ Producto
{
title: string, // Nombre del producto
descriptionHtml: string, // Descripción
vendor: string, // Proveedor
productType: string, // Tipo de producto
tags: string[], // Etiquetas
status: "ACTIVE"|"DRAFT",// Estado
handle: string, // URL slug
seo: { title, description },
images: [{ src: url }], // Imágenes
options: [{ name, values }], // Opciones (talla, color, etc.)
variants: [...] // Variantes
}
🏷️ Variante
{
sku: string,
barcode: string,
price: string,
compareAtPrice?: string,
weight?: number,
weightUnit: "KG"|"G"|"LB"|"OZ",
inventoryQuantities: [{
availableQuantity: number,
locationId: string
}],
inventoryItem: {
tracked: true,
requiresShipping: true
},
inventoryPolicy: "DENY",
options: [option1, option2, option3]
}
🔍 Logging y Monitoreo
📝 Logs Implementados
- ✅ Eventos de productos creados
- ✅ Validación de integraciones activas
- ✅ Estado de sincronización de inventario
- ✅ Éxitos y errores de API Shopify
- ✅ Mapeo de datos de productos
📊 Métricas Actualizadas
lastUsedAtÚltima sincronización exitosausageThisMonthContador de uso (futuro)lastErrorAtÚltimo error (si ocurre)
🛠️ Extensibilidad
🔌 Patrón Adapter
El sistema está diseñado para agregar fácilmente más plataformas:
- MercadoLibre
- Falabella
- WordPress/WooCommerce
- Amazon
🎯 Próximos Pasos
- Actualización de Productos - Sincronizar cambios de productos existentes
- Actualización de Inventario - Sincronizar cambios de stock
- Eliminación de Productos - Manejar productos eliminados
- Mapeo Bidireccional - Tabla de mapeo ThreeTrackr ↔ Shopify
- Sincronización Manual - Botón para sincronizar productos existentes
🧪 Testing
✅ Flujo de Prueba
- Configurar integración de Shopify con
syncInventory: true - Crear producto en ThreeTrackr con variantes
- Verificar logs de sincronización
- Comprobar producto creado en Shopify
- Validar inventario sincronizado
🔧 Debug
Para debuggear, revisar logs del ShopifyProductListener y ShopifyAdapter:
# Filtrar logs de sincronización de productos
grep -i "shopify.*product" logs/api.log
⚠️ Limitaciones Actuales
- Solo Creación Por ahora solo sincroniza productos nuevos, no actualizaciones
- Sin Mapeo Persistente No guarda relación ThreeTrackr ID ↔ Shopify ID
- Location Fija Usa location por defecto de Shopify
- Sin Rollback Si falla, no revierte la creación en ThreeTrackr
🎯 Beneficios
- ✅ Automático No requiere intervención manual
- ✅ Condicional Solo sincroniza si está configurado
- ✅ Robusto Maneja errores sin afectar el flujo principal
- ✅ Extensible Fácil agregar más plataformas
- ✅ Completo Sincroniza productos, variantes e inventario
- ✅ Siguiendo Patrones Usa la arquitectura existente de eventos
📋 Eventos del Sistema
tenant.product.created
new ProductCreatedFromTenantEvent(
organizationId: string,
productData: {
id: string;
name: string;
description?: string;
vendor?: string;
productType?: string;
tags?: string;
status: string;
handle?: string;
imageUrl?: string;
images?: string[];
seoTitle?: string;
seoDescription?: string;
}
)
tenant.product-variant.created
new ProductVariantCreatedFromTenantEvent(
organizationId: string,
variantData: {
id: string;
productId: string;
sku: string;
barcode: string;
title: string;
option1: string;
option2?: string;
option3?: string;
price: number;
compareAtPrice?: number;
costPerItem?: number;
weight?: number;
weightUnit: string;
imageUrl?: string;
images?: string[];
status: string;
inventoryItems?: Array<{
branchId: string;
available: number;
committed: number;
onHand: number;
}>;
},
productData: {
name: string;
description?: string;
vendor?: string;
productType?: string;
tags?: string;
handle?: string;
imageUrl?: string;
images?: string[];
}
)
📝 Notas Técnicas
API Utilizada
- Productos GraphQL API (
productCreate) - Para metadatos básicos - Variantes REST API (
/products/{id}/variants.json) - Más estable y confiable - Inventario REST API (
/inventory_levels/set.json) - Configuración por ubicación - Búsqueda GraphQL API (
productsquery) - Para encontrar productos existentes - Opciones REST API (
/products/{id}.jsonPUT) - Para actualizar opciones del producto
Razón del Enfoque Mixto
La API GraphQL de Shopify ha tenido cambios recientes:
- v2024-04+ Campo
variantsremovido deProductInput - v2024-07+ Mutación
productVariantCreateno disponible en todas las versiones
Por esto, se usa:
- GraphQL para crear productos (más eficiente para metadatos)
- REST para crear variantes (más estable y compatible)
🔧 Correcciones Implementadas
Problema: Creación de Productos Duplicados
- Antes Cada variante creaba un producto nuevo
- Solución Búsqueda de productos existentes por nombre antes de crear
Problema: Error de Opciones "Unknown option(s)"
- Antes Enviaba opciones sin definir en el producto
- Solución Actualización automática de opciones del producto antes de crear variantes
Problema: Campos Incompletos
- Antes No pasaba todos los campos necesarios
- Solución Mapeo completo de datos de ThreeTrackr a Shopify
Problema: Handles Duplicados
- Antes Error "Handle already in use" al crear productos
- Solución Generación automática de handles únicos con verificación
Problema: Búsqueda de Productos Ineficiente
- Antes Búsqueda simple que no encontraba productos existentes
- Solución Múltiples estrategias de búsqueda (título exacto, parcial, handle)
Problema: Sincronización Incompleta
- Antes Solo sincronizaba creación de variantes
- Solución Sincronización completa CREATE, UPDATE, DELETE
Problema: Eliminación No Funcionaba
- Antes Las variantes no se eliminaban de la DB del tenant
- Solución Emisión de eventos en métodos update/delete + listeners correspondientes
Problema: Update Fallaba si Variante No Existía
- Antes Error "Variant not found" al actualizar variantes inexistentes
- Solución Lógica inteligente: intenta UPDATE, si falla hace CREATE
Problema: Eventos No Se Emitían (DELETE)
- Antes El módulo tenant no tenía EventEmitterModule importado
- Solución Agregar EventEmitterModule.forRoot() al TenantModule
Problema: Foreign Key Constraint en Eliminación
- Antes Error "Foreign key constraint violated on InventoryItem_variantId_fkey"
- Solución Eliminar primero los registros de inventario antes de eliminar la variante
✅ Funcionalidades Implementadas
- [x] Sincronización CREATE Crear productos y variantes en Shopify
- [x] Sincronización UPDATE Actualizar variantes existentes en Shopify (con fallback a CREATE)
- [x] Sincronización DELETE Eliminar variantes de Shopify
- [x] Búsqueda inteligente Encontrar productos existentes por múltiples criterios
- [x] Handles únicos Generación automática de handles sin duplicados
- [x] Inventario Configuración automática de inventario por ubicación
- [x] Opciones de producto Actualización automática de opciones (talla, color, material)
🚀 Próximos Pasos
- [ ] Implementar sincronización de actualizaciones de productos (no solo variantes)
- [ ] Agregar soporte para imágenes de productos
- [ ] Implementar sincronización bidireccional (Shopify → ThreeTrackr)
- [ ] Agregar mapeo de categorías de productos
- [ ] Implementar sincronización de precios dinámicos