From 1d256379261cdbe4f4a8a0c27e1ae27067336e22 Mon Sep 17 00:00:00 2001 From: hmmhmmhm Date: Mon, 5 Oct 2026 20:15:59 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=84=B8=EB=B8=90=EC=9D=BC=EB=A0=88?= =?UTF-8?q?=EB=B8=90=20=EC=A4=91=EB=B3=B5=20=EC=83=81=ED=92=88=EC=9D=98=20?= =?UTF-8?q?=EB=A7=A4=EC=9E=A5=20=EC=8B=9D=EB=B3=84=EC=9E=90=20=EB=B3=B4?= =?UTF-8?q?=EC=A1=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/seveneleven-product-pagination.md | 4 +++- src/api/routes/sevenelevenRoutes.ts | 2 +- src/services/seveneleven/client.ts | 12 +++++++----- tests/services/seveneleven/pagination.test.ts | 16 ++++++++++++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/docs/seveneleven-product-pagination.md b/docs/seveneleven-product-pagination.md index e29c10ff..b0985f0e 100644 --- a/docs/seveneleven-product-pagination.md +++ b/docs/seveneleven-product-pagination.md @@ -20,6 +20,8 @@ 부하를 제한하기 위해 요청당 컬렉션별 100행, 검색어당 최대 5페이지와 원본 합계 500행, 보정 검색 전체 최대 10요청을 허용합니다. 범위가 이 제한을 넘거나 페이지가 반복·누락되면 불완전한 목록을 정상 결과로 반환하지 않습니다. REST는 오류 응답, MCP는 명시적인 `degraded` 응답을 반환합니다. 넓은 검색은 상품명을 더 구체적으로 입력해야 합니다. -Mac 중계는 구형 본문과 공식 본문을 함께 허용합니다. 중계를 먼저 반영한 뒤 Worker를 배포합니다. 중계 인증·GS25 세션·호출 원장은 교체하거나 초기화하지 않습니다. REST 검색 캐시 namespace는 `seveneleven-products-v3`로 갱신했습니다. +Mac 중계는 구형 본문과 공식 본문을 함께 허용합니다. 중계를 먼저 반영한 뒤 Worker를 배포합니다. 중계 인증·GS25 세션·호출 원장은 교체하거나 초기화하지 않습니다. REST 검색 캐시 namespace는 `seveneleven-products-v4`로 갱신했습니다. 확인한 공식 소스: [검색 화면 번들](https://static.7-elevenapp.co.kr/k7app/_nuxt/DH1pJlb5.js), [검색 API 번들](https://static.7-elevenapp.co.kr/k7app/_nuxt/BqIULyu_.js). + +같은 상품 코드의 매장 상품과 교환권은 서로 다른 상품 번호를 가질 수 있습니다. 중복 제거는 먼저 확인한 매장 상품 정보를 보존하며, 뒤쪽 교환권의 상품 번호로 덮어쓰지 않습니다. diff --git a/src/api/routes/sevenelevenRoutes.ts b/src/api/routes/sevenelevenRoutes.ts index c4c3af3f..89d604fd 100644 --- a/src/api/routes/sevenelevenRoutes.ts +++ b/src/api/routes/sevenelevenRoutes.ts @@ -20,7 +20,7 @@ export function registerSevenElevenRoutes(app: Hono<{ Bindings: AppBindings }>): { ttlSeconds: 60 * 3, staleWhileRevalidateSeconds: 60, - keyPrefix: 'seveneleven-products-v3', + keyPrefix: 'seveneleven-products-v4', }, () => handleSevenElevenSearchProducts(c), ), diff --git a/src/services/seveneleven/client.ts b/src/services/seveneleven/client.ts index a8ff2e62..c6d489ba 100644 --- a/src/services/seveneleven/client.ts +++ b/src/services/seveneleven/client.ts @@ -206,11 +206,13 @@ export async function fetchSevenElevenProductSearchResults( const rows = normalizeProducts( pagination.documents.length ? pagination.documents : Array.isArray(data.content) ? data.content : [], ); - const products = [ - ...new Map( - rows.map((product) => [product.itemCode || product.productNo || product.itemName, product]), - ).values(), - ]; + const uniqueProducts = new Map(); + for (const product of rows) { + const key = product.itemCode || product.productNo || product.itemName; + // 뒤쪽 교환권 행이 먼저 확인한 매장 상품 정보를 덮어쓰지 않습니다. + if (!uniqueProducts.has(key)) uniqueProducts.set(key, product); + } + const products = [...uniqueProducts.values()]; return { query: data.SearchQueryResult?.query || query, totalCount: products.length, diff --git a/tests/services/seveneleven/pagination.test.ts b/tests/services/seveneleven/pagination.test.ts index 6e1dd9ef..28092b87 100644 --- a/tests/services/seveneleven/pagination.test.ts +++ b/tests/services/seveneleven/pagination.test.ts @@ -214,3 +214,19 @@ it('초기 레거시 목록도 전체 500개 제한을 적용한다', async () = ); await expect(searchSevenElevenProducts({ query: '커피' })).rejects.toThrow('최대 500개 제한'); }); + +it('교환권 컬렉션의 같은 상품 코드가 먼저 확인한 매장 상품 번호를 덮어쓰지 않는다', async () => { + mockFetch.mockResolvedValueOnce(Response.json({ + data: { SearchQueryResult: { Collection: [ + { CollectionId: 'pickup', Documentset: { totalCount: 1, Document: [ + { field: { itemCd: '8809415436006', prdNo: '3047966', itemOnm: '커피', itemGbnNm: '당일픽업', onlinePrice: '2000' } }, + ] } }, + { CollectionId: 'coupon', Documentset: { totalCount: 1, Document: [ + { field: { itemCd: '8809415436006', prdNo: '21441', itemOnm: '커피', itemGbnNm: '교환권', onlinePrice: '2000' } }, + ] } }, + ] } }, + })); + const result = await searchSevenElevenProducts({ query: '커피' }); + expect(result.totalCount).toBe(1); + expect(result.products[0]).toMatchObject({ productNo: '3047966', itemType: '당일픽업', salePrice: 2000 }); +});