diff --git a/src/features/product/repositories/product.repository.ts b/src/features/product/repositories/product.repository.ts index 43a7df09..89ad152f 100644 --- a/src/features/product/repositories/product.repository.ts +++ b/src/features/product/repositories/product.repository.ts @@ -882,6 +882,7 @@ export class ProductRepository { }, include: { text_tokens: { + where: activeWhere, orderBy: { sort_order: 'asc' }, }, }, @@ -922,6 +923,7 @@ export class ProductRepository { }, include: { text_tokens: { + where: activeWhere, orderBy: { sort_order: 'asc' }, }, }, diff --git a/src/features/product/services/product-seller-custom-template.service.spec.ts b/src/features/product/services/product-seller-custom-template.service.spec.ts index 0eb77fbc..b8368f90 100644 --- a/src/features/product/services/product-seller-custom-template.service.spec.ts +++ b/src/features/product/services/product-seller-custom-template.service.spec.ts @@ -63,6 +63,22 @@ describe('SellerCustomTemplateService (real DB)', () => { }); } + /** 활성 슬롯 A + soft-delete된 슬롯 B. */ + async function createTokensWithDeleted(templateId: bigint) { + const live = await prisma.productCustomTextToken.create({ + data: { template_id: templateId, token_key: 'A', default_text: 'a' }, + }); + await prisma.productCustomTextToken.create({ + data: { + template_id: templateId, + token_key: 'B', + default_text: 'b', + deleted_at: new Date(), + }, + }); + return live; + } + describe('sellerUpsertProductCustomTemplate', () => { it('없는 productId면 404', async () => { const { accountId } = await setupSellerWithProduct(); @@ -100,6 +116,22 @@ describe('SellerCustomTemplateService (real DB)', () => { }); expect(templates).toHaveLength(1); }); + + it('응답 textTokens에서 soft-delete된 슬롯은 제외한다', async () => { + const { accountId, product } = await setupSellerWithProduct(); + const tpl = await createTemplate(product.id); + const live = await createTokensWithDeleted(tpl.id); + + const result = await service.sellerUpsertProductCustomTemplate( + accountId, + { + productId: product.id.toString(), + baseImageUrl: ownedUploadUrl('PRODUCT_IMAGE', accountId, 'b.png'), + }, + ); + + expect(result.textTokens.map((t) => t.id)).toEqual([live.id.toString()]); + }); }); describe('sellerSetProductCustomTemplateActive', () => { @@ -145,6 +177,19 @@ describe('SellerCustomTemplateService (real DB)', () => { }); expect(auditLogs).toHaveLength(1); }); + + it('응답 textTokens에서 soft-delete된 슬롯은 제외한다', async () => { + const { accountId, product } = await setupSellerWithProduct(); + const tpl = await createTemplate(product.id); + const live = await createTokensWithDeleted(tpl.id); + + const result = await service.sellerSetProductCustomTemplateActive( + accountId, + { templateId: tpl.id.toString(), isActive: false }, + ); + + expect(result.textTokens.map((t) => t.id)).toEqual([live.id.toString()]); + }); }); describe('sellerUpsertProductCustomTextToken', () => {