diff --git a/src/app/api/creation/execute/route.ts b/src/app/api/creation/execute/route.ts index f4e7022..b1daf6f 100644 --- a/src/app/api/creation/execute/route.ts +++ b/src/app/api/creation/execute/route.ts @@ -5,7 +5,7 @@ import { fetchPendingProducts } from '@/lib/creationSheets' import { generateDescriptions } from '@/lib/openaiClient' import { ensureMetafieldDefinition, setProductMetafield } from '@/lib/shopifyMetafields' import { addProductToCollection } from '@/lib/shopifyCollections' -import { createShopifyProduct } from '@/lib/shopifySync' +import { createShopifyProduct, fetchAllShopifyProducts } from '@/lib/shopifySync' import { prisma } from '@/lib/prisma' import type { MetafieldResolution, CreationStreamEvent } from '@/types/creation' @@ -28,13 +28,17 @@ export async function POST(req: NextRequest) { async start(controller) { const send = (event: CreationStreamEvent) => controller.enqueue(encode(event)) try { - const existing = await prisma.productCreation.findMany({ select: { sheetTab: true, sheetRow: true } }) - const alreadyCreated = new Set(existing.map(e => `${e.sheetTab}:${e.sheetRow}`)) + const [existingRows, shopifyProducts] = await Promise.all([ + prisma.productCreation.findMany({ select: { sheetTab: true, sheetRow: true } }), + fetchAllShopifyProducts(), + ]) + const alreadyCreated = new Set(existingRows.map(e => `${e.sheetTab}:${e.sheetRow}`)) + const shopifyRefs = new Set(shopifyProducts.map(p => p.ref.trim().toLowerCase())) const pending = await fetchPendingProducts(alreadyCreated) const total = pending.length if (total === 0) { - send({ type: 'done', summary: { created: 0, errors: 0, status: 'success' } }) + send({ type: 'done', summary: { created: 0, skipped: 0, errors: 0, status: 'success' } }) controller.close() return } @@ -45,10 +49,19 @@ export async function POST(req: NextRequest) { } let created = 0 + let skipped = 0 let errors = 0 for (let i = 0; i < pending.length; i++) { const product = pending[i] + + // Vérifier si le produit existe déjà dans Shopify par SKU + if (shopifyRefs.has(product.sku.trim().toLowerCase())) { + send({ type: 'skipped', title: product.title, sku: product.sku }) + skipped++ + continue + } + send({ type: 'progress', current: i + 1, total, tab: product.tab, title: product.title, step: 'Génération descriptions…' }) try { const { longDesc } = await generateDescriptions({ @@ -90,10 +103,10 @@ export async function POST(req: NextRequest) { } } const status = errors === 0 ? 'success' : created === 0 ? 'error' : 'partial' - send({ type: 'done', summary: { created, errors, status } }) + send({ type: 'done', summary: { created, skipped, errors, status } }) } catch (err) { const message = err instanceof Error ? err.message : 'Erreur inconnue' - send({ type: 'done', summary: { created: 0, errors: 1, status: 'error' } }) + send({ type: 'done', summary: { created: 0, skipped: 0, errors: 1, status: 'error' } }) console.error('[creation/execute]', message) } finally { controller.close() diff --git a/src/components/creation/CreationProgress.tsx b/src/components/creation/CreationProgress.tsx index 2e1c378..2fb1337 100644 --- a/src/components/creation/CreationProgress.tsx +++ b/src/components/creation/CreationProgress.tsx @@ -10,6 +10,7 @@ export function CreationProgress({ events, done }: Props) { const lastProgress = [...events].reverse().find(e => e.type === 'progress') as Extract | undefined const doneEvent = events.find(e => e.type === 'done') as Extract | undefined const errors = events.filter(e => e.type === 'error') as Array> + const skipped = events.filter(e => e.type === 'skipped') as Array> return (
@@ -26,6 +27,17 @@ export function CreationProgress({ events, done }: Props) {

{lastProgress.tab} — {lastProgress.title}

)} + {skipped.length > 0 && ( +
+ {skipped.map((e, i) => ( +
+ ⚠️ + {e.title} + — SKU {e.sku} déjà présent dans Shopify, ignoré +
+ ))} +
+ )} {errors.length > 0 && (
{errors.map((e, i) => ( @@ -43,6 +55,7 @@ export function CreationProgress({ events, done }: Props) {

{doneEvent.summary.created} créé{doneEvent.summary.created > 1 ? 's' : ''} + {doneEvent.summary.skipped > 0 && ` — ${doneEvent.summary.skipped} déjà existant${doneEvent.summary.skipped > 1 ? 's' : ''} (ignorés)`} {doneEvent.summary.errors > 0 && ` — ${doneEvent.summary.errors} erreur${doneEvent.summary.errors > 1 ? 's' : ''}`}

diff --git a/src/types/creation.ts b/src/types/creation.ts index 2e10825..53e95c1 100644 --- a/src/types/creation.ts +++ b/src/types/creation.ts @@ -41,7 +41,8 @@ export interface MetafieldResolution { export type CreationStreamEvent = | { type: 'progress'; current: number; total: number; tab: string; title: string; step: string } | { type: 'error'; title: string; message: string } - | { type: 'done'; summary: { created: number; errors: number; status: 'success' | 'partial' | 'error' } } + | { type: 'skipped'; title: string; sku: string } + | { type: 'done'; summary: { created: number; skipped: number; errors: number; status: 'success' | 'partial' | 'error' } } /** Résumé d'une création (stocké en DB) */ export interface CreationRecord {