diff --git a/apps/importer/src/shopee/__tests__/open-core-intelligence.test.ts b/apps/importer/src/shopee/__tests__/open-core-intelligence.test.ts index 56ab53c1..c43fa200 100644 --- a/apps/importer/src/shopee/__tests__/open-core-intelligence.test.ts +++ b/apps/importer/src/shopee/__tests__/open-core-intelligence.test.ts @@ -486,6 +486,19 @@ async function runSuite() { ['iPad Air 11 năm 2024 M2 128GB', 'apple:ipad-air-m2-11:128gb'], ['iPad Pro 12.9 năm 2022 M2 128GB', 'apple:ipad-pro-m2-129:128gb'], ['MacBook Air M2 13 năm', 'apple:macbook-air-m2:unknown'], + // Any word or year form after "năm" keeps the size (DOS/Rate#1333). + ['iPad Pro 11 năm sx 2022', 'apple:ipad-pro-11:unknown'], + ['iPad Pro 12.9 năm sản xuất 2022', 'apple:ipad-pro-129:unknown'], + ['MacBook Air 13 năm ra mắt 2022', 'apple:macbook-air-13:unknown'], + ['iPad Pro 11 năm: 2022', 'apple:ipad-pro-11:unknown'], + ['iPad Pro 11 năm 22', 'apple:ipad-pro-11:unknown'], + // A shop's age is no size: the gift's size stands in. + ['iPad Pro M4 256GB - Shop 13 năm kinh nghiệm - tặng ốp 11 inch', 'apple:ipad-pro-m4-11:256gb'], + [ + 'MacBook Air M2 256GB - Shop 14 năm kinh nghiệm - tặng túi 13 inch', + 'apple:macbook-air-m2-13:256gb', + ], + ['iPad Pro M4 256GB 11 năm bảo hành tặng ốp 13 inch', 'apple:ipad-pro-m4-11:256gb'], // A date ("11/11"), RAM or SSD, a macOS name, a duration or an amount is no // size, so the gift's size still stands in. ['iPad Pro M4 Sale 11/11 tặng ốp 13 inch', 'apple:ipad-pro-m4-13:unknown'], @@ -764,6 +777,8 @@ async function runSuite() { ['Apple Watch Series 10 GPS 46 tặng ốp 42mm', 'apple:watch-series-10:64gb'], ['Apple Watch Series 10 GPS giảm 40% tặng ốp 46mm', 'apple:watch-series-10-46mm:64gb'], ['Apple Watch Series 10 giảm 44 nghìn tặng ốp 46mm', 'apple:watch-series-10-46mm:64gb'], + // A bare size equal to the gift's is the same size (DOS/Rate#1333). + ['Apple Watch Series 10 tặng ốp 42mm 42 GPS', 'apple:watch-series-10-42mm:64gb'], // A size listed right after the box's is a list, not the watch's own case. ['Apple Watch Series 10 kèm hộp 46mm | 42mm', 'apple:watch-series-10-46mm:64gb'], // "size 46" beats a box's size; a band's "size 42" is not the watch's. diff --git a/apps/importer/src/shopee/product-normalizer.ts b/apps/importer/src/shopee/product-normalizer.ts index 9980b6fe..0b38aa03 100644 --- a/apps/importer/src/shopee/product-normalizer.ts +++ b/apps/importer/src/shopee/product-normalizer.ts @@ -1256,11 +1256,13 @@ function isProductCodeToken(token: string): boolean { // js/polynomial-redos). A unit ends where a letter does, Vietnamese ones included: "13 // tặng" or "13 hãng" is a bare 13, not "13 t(b)" or "13 h"; "15 tháng" (warranty), "10%" // or "15 gói" is no size (DOS/Rate#1291). +// "năm" is a duration at the end, before a separator or a shop's age ("13 năm", "Shop +// 13 năm kinh nghiệm"); any other word or a year after it keeps the size (DOS/Rate#1333). // "16 RAM 512" is the RAM; "13 RAM 8GB" (a RAM size follows) is the screen's 13 // (DOS/Rate#1317). const UNIT_END = String.raw`(?![\p{L}\p{M}\d])`; const SIZE_NOT_PRECEDED_BY = String.raw`(? + [...ownPart.matchAll(new RegExp(bare.source, 'giu'))].some( + m => m[0].replace(',', '.') !== giftSize + ); const namesSize = family === 'watch' - ? WATCH_SIZE.test(withoutGift) || WATCH_BARE_SIZE.test(ownPart) - : APPLE_SIZE_PATTERNS[family]!.some(re => re.test(ownPart)) || SCREEN_BARE_SIZE.test(ownPart); + ? WATCH_SIZE.test(withoutGift) || namesOtherBare(WATCH_BARE_SIZE) + : APPLE_SIZE_PATTERNS[family]!.some(re => re.test(ownPart)) || + namesOtherBare(SCREEN_BARE_SIZE); return namesSize || withoutGift === productPart || giftSizes.size !== 1 ? '' : readFamilySize(family, productPart);