diff --git a/src/app/api/admin/import/furni/batch/route.ts b/src/app/api/admin/import/furni/batch/route.ts index 9cae964a..18dc1e84 100644 --- a/src/app/api/admin/import/furni/batch/route.ts +++ b/src/app/api/admin/import/furni/batch/route.ts @@ -13,6 +13,7 @@ import { buildLocalizedFurniDataFiles } from "@/lib/services/furni-data-i18n"; import { ensureDirectories, ensureFurniOwnership, + fixDatabaseConsistencyAfterImport, importSingleFurni, reconcileImportedOfferIds, syncAssetsToGamedataBundle, @@ -265,6 +266,9 @@ export const POST = withAdmin( ); } + // Fix database consistency (catalog_name + have_offer) after import + const dbFix = await fixDatabaseConsistencyAfterImport(); + send({ type: "batch_complete", succeeded, @@ -281,6 +285,8 @@ export const POST = withAdmin( offerRebuildFixed, spriteFixed, interactionFixed, + catalogNameFixed: dbFix.catalogNameFixed, + haveOfferFixed: dbFix.haveOfferFixed, languages, duration: Date.now() - startTime, }); diff --git a/src/app/api/admin/import/furni/route.ts b/src/app/api/admin/import/furni/route.ts index 370a0fcf..3b283346 100644 --- a/src/app/api/admin/import/furni/route.ts +++ b/src/app/api/admin/import/furni/route.ts @@ -27,6 +27,7 @@ import { downloadFile, ensureDirectories, ensureFurniOwnership, + fixDatabaseConsistencyAfterImport, IMPORTED_PAGE_CAPTION_SAVE, importSingleFurni, reconcileImportedOfferIds, @@ -480,6 +481,9 @@ export const POST = withAdmin( // Verify + fix interaction_modes_count once for the whole batch const verification = await verifyAndFixInteractionModesCount(); + // Fix database consistency (catalog_name + have_offer) after import + const dbFix = await fixDatabaseConsistencyAfterImport(); + // Rebuild all localized furnidata files (best effort) let languages: Awaited> = []; @@ -513,6 +517,8 @@ export const POST = withAdmin( spriteChecked: spriteVerify.checked, spriteFixed: spriteVerify.fixed, interactionFixed: verification.fixed, + catalogNameFixed: dbFix.catalogNameFixed, + haveOfferFixed: dbFix.haveOfferFixed, languages, }); } @@ -575,6 +581,9 @@ export const POST = withAdmin( // Verify the furnidata matches the DB ids const furniReconcile = await reconcileFurniDataWithItemsBase(); + // Fix database consistency (catalog_name + have_offer) after import + const dbFix = await fixDatabaseConsistencyAfterImport(); + // Rebuild every catalog offer_id from the furnidata const offerRebuild = await rebuildCatalogOfferIds(); @@ -632,6 +641,8 @@ export const POST = withAdmin( spriteChecked: spriteVerify.checked, spriteFixed: spriteVerify.fixed, interactionFixed: verification.fixed, + catalogNameFixed: dbFix.catalogNameFixed, + haveOfferFixed: dbFix.haveOfferFixed, languages: languagesPatch, spriteCount: result.spriteCount, warnings: result.warnings, diff --git a/src/lib/services/furni-import.ts b/src/lib/services/furni-import.ts index a5f75be7..fad3b450 100644 --- a/src/lib/services/furni-import.ts +++ b/src/lib/services/furni-import.ts @@ -1086,6 +1086,37 @@ async function realNitroModes(classname: string): Promise { } } +/** Fix database consistency after import: + * 1. Fill empty catalog_name from items_base.public_name + * 2. Set have_offer = '1' where it was '0' + * Returns { catalogNameFixed, haveOfferFixed } with counts. */ +export async function fixDatabaseConsistencyAfterImport(): Promise<{ + catalogNameFixed: number; + haveOfferFixed: number; +}> { + // 1. Fill empty catalog_name from items_base.public_name + const [nameResult] = (await db.execute(sql` + UPDATE catalog_items c + JOIN items_base i ON c.item_ids = i.id + SET c.catalog_name = CASE + WHEN i.public_name LIKE '%*%' THEN SUBSTRING_INDEX(i.public_name, '*', 1) + ELSE i.public_name + END + WHERE c.catalog_name IS NULL OR c.catalog_name = '' + `)) as unknown as [Record, unknown]; + const catalogNameFixed = Number(nameResult.affectedRows ?? 0); + + // 2. Set have_offer = '1' where it was '0' + const [offerResult] = (await db.execute(sql` + UPDATE catalog_items + SET have_offer = '1' + WHERE have_offer = '0' + `)) as unknown as [Record, unknown]; + const haveOfferFixed = Number(offerResult.affectedRows ?? 0); + + return { catalogNameFixed, haveOfferFixed }; +} + /** Verify and fix interaction values for ALL furniture in items_base. * Run after import to ensure every item's interaction_type, modes count and * sit/lay/stand flags match the real furniture data. Only items with