El importador de commerce-backend definia normalizeTitleForMatch (colapsa
guion largo/comillas tipograficas) pero nunca la usaba en el matching de
producto/categoria/coleccion -- seguia comparando con toLowerCase().trim()
plano, por eso un re-import de "Toy Story 5 - Woody" con guion largo pegado
desde Excel volvio a crear un duplicado en vez de actualizar el existente.
En el storefront, cualquier slug de producto inexistente devolvia HTTP 200
en vez de 404 (confirmado con un slug inventado): el Suspense del navbar
hace que el layout empiece a stream-ear la respuesta con status 200 antes
de que notFound() se ejecute dentro de la pagina. Se mueve la verificacion
a generateMetadata, que se resuelve completo antes de iniciar el stream.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Re-subir la misma fila de CSV (ej. para agregar más fotos o actualizar
la descripción de un producto ya cargado) creaba un producto nuevo con
handle distinto -- confirmado en vivo re-importando "Hello Kitty &
Friends" para sumar fotos: quedaron dos productos con el mismo título
en la tienda.
Ahora, si el título coincide (case-insensitive/trim) con un producto ya
importado, se actualiza ese producto en vez de crear uno: las fotos
nuevas se agregan a las que ya tenía (no se reemplazan) y la
descripción se actualiza si la fila trae una. No toca
precio/cantidad/categoría/colección del producto existente.
El duplicado ya creado se fusionó en vivo (fotos movidas al original,
duplicado borrado) sin esperar este deploy.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
El importador solo enlazaba categoría/colección cuando el nombre del CSV
matcheaba exacto (case-insensitive) una ya existente -- si no había match,
category_ids/collection_id quedaban undefined sin ningún error. Así quedó
el producto "Hello Kitty & Friends" importado sin colección: la colección
nunca existió en la tienda, el importador nunca la creó ni avisó.
Ahora, si el nombre no matchea, se crea la categoría/colección nueva
(createProductCategoriesWorkflow / createCollectionsWorkflow) con el mismo
slugify() ASCII-safe que ya usa el handle del producto, por la misma razón:
el default de Medusa no quita tildes/eñes y rompe la ruta pública.
El producto ya importado se corrigió en caliente vía Admin API (colección
creada + enlazada + handle corregido de "hello-kitty-&-friends" a
"hello-kitty-friends"), sin esperar este deploy.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
3 productos importados con título acentuado (ñ/tildes) quedaron con handle
no-ASCII y daban 404 real al entrar por shop.cruzcloud.net -- el tunel/
ingress público rompe rutas con UTF-8 no-ASCII en el path, confirmado en
vivo comparando el mismo request directo al servicio (200 OK) contra el
dominio público (404). Se genera el handle explícito (slugify propio,
sin dependencia nueva) con sufijo único por fila para evitar colisiones
entre títulos parecidos. Los 3 productos ya publicados con handle roto
se corrigieron en caliente vía Admin API, sin esperar este deploy.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01SEsGCsCmxkyXi9XctNdrT1
El S3 file provider de Medusa descarta cualquier subcarpeta del
filename (usa solo path.parse().name + ulid, confirmado leyendo
@medusajs/file-s3/dist/services/s3-file.js) -- no existe una carpeta
import-products/ separada como decia el comentario original. El bucket
(ari-products) es plano, igual para todas las fotos del catalogo.
Confirmado en vivo con una importacion real de 3 productos.
listProductCategories({})/listProductCollections({}) sin select
explicito devolvian name/title undefined (a diferencia de la capa HTTP
del Admin API, que si los trae completos por defecto) -- causaba un 500
"Cannot read properties of undefined (reading 'toLowerCase')" en
cualquier import real. Confirmado en vivo con una prueba de importacion
de 3 productos antes de este fix.
De paso, se agrega un filtro defensivo antes del .map() para que una
categoria/coleccion sin nombre no tumbe el import entero.
Nueva pagina "Importacion" en Medusa Admin para cargar varios productos
de una sola vez (comprados en Amazon/eBay/etc, no dropshipping
automatizado -- se evaluo y descarto raspar catalogos de terceros sin
autorizacion por riesgo de copyright/ToS).
src/api/admin/product-import/route.ts: GET sirve la plantilla CSV
descargable, POST procesa fila por fila (una foto rota o categoria mal
escrita no tumba el resto del archivo). Cada foto se descarga del origen
y se re-aloja en el mismo MinIO/S3 del NAS que ya usa el catalogo
(prefijo import-products/, separado de ari-products/), se crea el
registro de inventario con la cantidad indicada y el producto queda
vinculado con el mismo patron "Presentacion"/"Estandar" que usa el resto
del catalogo -- el storefront no necesita cambios.
src/lib/csv.ts: parser CSV propio (RFC4180), sin sumar dependencia nueva.
Workflows y servicios de modulo (uploadFilesWorkflow,
createInventoryItemsWorkflow, createProductsWorkflow, stock-location/
fulfillment/sales-channel/product module services) verificados contra
los .d.ts reales instalados, no solo contra documentacion.
TS2769: la anotacion explicita {location_id: string} no calzaba con el
tipo Maybe<InventoryLevel> que infiere query.graph para location_levels.
Se quita la anotacion y se deja inferir, con optional chaining.
Nueva pestana "Inventario" en el sidebar del Admin (src/admin/routes/
inventario), pensada para un usuario no tecnico: una fila por producto
(catalogo real confirmado 1 variante por producto), switch para activar
seguimiento de stock, input de cantidad que guarda solo, badge de stock
bajo (<=5 unidades) y activacion/desactivacion en bloque por seleccion.
No reemplaza la vista nativa de Inventory de Medusa, es un atajo.
Backend: src/api/admin/inventory-panel/route.ts + workflow propio
src/workflows/attach-inventory-item-to-variant.ts para vincular un
InventoryItem nuevo a una variante existente (Medusa no lo hace solo al
togglear manage_inventory en un producto ya creado -- confirmado en vivo
contra un producto [DEMO] antes de escribir el codigo).
Nombres de campos y workflows verificados contra los .d.ts reales
instalados en el pod (no solo contra la documentacion, que no cubre bien
este flujo de vincular inventario a una variante existente).