Merge branch 'fix/categorias-sin-tildes-match'
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 27s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 15m24s
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 37s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 19m58s

This commit is contained in:
devops committed 2026-09-27 14:29:53 +00:00
commit ca10ef6e9a
2 files changed
+26 -8

No files matched your search

@@ -115,6 +115,15 @@ function normalizeTitleForMatch(title: string): string {
.toLowerCase();
}
// Categorias/colecciones: ademas de lo anterior, ignora tildes y eñes
// ("Figuras de accion" == "Figuras de acción"). Desde 2026-09-27 los
// nombres reales en Medusa llevan tildes; sin esto, un CSV escrito sin
// tildes (o viejo) crearia una categoria DUPLICADA en vez de reusar la
// existente. Los titulos de producto siguen con normalizeTitleForMatch.
function normalizeNameForMatch(name: string): string {
return normalizeTitleForMatch(name).normalize("NFD").replace(/[\u0300-\u036f]/g, "");
}
function slugify(title: string, uniquePart: string): string {
const base = title
.normalize("NFD")
@@ -166,7 +175,7 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
// ofrece descargar y lo que realmente se procesa.
const header = "titulo,descripcion,precio,categoria,coleccion,cantidad,fotos";
const example =
'"Muñeco Buzz Lightyear","Figura articulada de 30cm, edición coleccionista.",89900,"Figuras de accion","Toy Story",3,"https://ejemplo.com/foto1.jpg;https://ejemplo.com/foto2.jpg"';
'"Muñeco Buzz Lightyear","Figura articulada de 30cm, edición coleccionista.",89900,"Figuras de acción","Toy Story",3,"https://ejemplo.com/foto1.jpg;https://ejemplo.com/foto2.jpg"';
const csv = `${header}\n${example}\n`;
res.setHeader("Content-Type", "text/csv; charset=utf-8");
res.setHeader("Content-Disposition", 'attachment; filename="plantilla-importacion.csv"');
@@ -217,10 +226,10 @@ export async function POST(req: MedusaRequest<{ csv: string }>, res: MedusaRespo
}
const categoryByName = new Map(
categories.filter((c) => c.name).map((c) => [normalizeTitleForMatch(c.name), c.id]),
categories.filter((c) => c.name).map((c) => [normalizeNameForMatch(c.name), c.id]),
);
const collectionByName = new Map(
collections.filter((c) => c.title).map((c) => [normalizeTitleForMatch(c.title), c.id]),
collections.filter((c) => c.title).map((c) => [normalizeNameForMatch(c.title), c.id]),
);
const productByTitle = new Map(
existingProducts.filter((p) => p.title).map((p) => [normalizeTitleForMatch(p.title), p]),
@@ -289,7 +298,7 @@ export async function POST(req: MedusaRequest<{ csv: string }>, res: MedusaRespo
if (!inventoryItemId) throw new Error("No se pudo crear el registro de inventario");
const categoryName = row.categoria?.trim();
let categoryId = categoryName ? categoryByName.get(normalizeTitleForMatch(categoryName)) : undefined;
let categoryId = categoryName ? categoryByName.get(normalizeNameForMatch(categoryName)) : undefined;
if (categoryName && !categoryId) {
const { result: createdCategories } = await createProductCategoriesWorkflow(req.scope).run({
input: {
@@ -299,11 +308,11 @@ export async function POST(req: MedusaRequest<{ csv: string }>, res: MedusaRespo
},
});
categoryId = createdCategories[0].id;
categoryByName.set(normalizeTitleForMatch(categoryName), categoryId);
categoryByName.set(normalizeNameForMatch(categoryName), categoryId);
}
const collectionName = row.coleccion?.trim();
let collectionId = collectionName ? collectionByName.get(normalizeTitleForMatch(collectionName)) : undefined;
let collectionId = collectionName ? collectionByName.get(normalizeNameForMatch(collectionName)) : undefined;
if (collectionName && !collectionId) {
const { result: createdCollections } = await createCollectionsWorkflow(req.scope).run({
input: {
@@ -313,7 +322,7 @@ export async function POST(req: MedusaRequest<{ csv: string }>, res: MedusaRespo
},
});
collectionId = createdCollections[0].id;
collectionByName.set(normalizeTitleForMatch(collectionName), collectionId);
collectionByName.set(normalizeNameForMatch(collectionName), collectionId);
}
await createProductsWorkflow(req.scope).run({
+10 -1
View File
@@ -11,6 +11,13 @@ type CatalogPageProps = {
searchParams: Promise<Record<string, string | string[] | undefined>>;
};
// Sin tildes/eñes ni mayusculas: los links viejos (o escritos a mano)
// como ?category=Munecas y peluches siguen llevando a la categoria real
// "Muñecas y peluches" (renombrada con tildes el 2026-09-27).
function normalizeName(value: string): string {
return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").trim().toLowerCase();
}
function single(value: string | string[] | undefined): string {
return Array.isArray(value) ? value[0] ?? "" : value ?? "";
}
@@ -19,7 +26,9 @@ export default async function CatalogPage({ searchParams }: CatalogPageProps) {
const params = await searchParams;
const [products, categories] = await Promise.all([getProducts(), getCategories()]);
const category = single(params.category) || "Todos";
const requestedCategory = single(params.category) || "Todos";
const category =
categories.find((node) => normalizeName(node.name) === normalizeName(requestedCategory))?.name ?? requestedCategory;
const collection = single(params.collection);
const query = single(params.q);
const taxonomy = {