From ea36a7da3d60514aa6454378ffb7a3bdb6dee100 Mon Sep 17 00:00:00 2001 From: Wender Lima Date: Thu, 25 Jun 2026 15:02:24 -0300 Subject: [PATCH 1/2] Fixing scenario where false unavailable items are show on ReviewBlock --- CHANGELOG.md | 4 + node/yarn.lock | 6 +- react/components/ReviewBlock.tsx | 271 ++++++++++++++++++++++--------- 3 files changed, 200 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02f2a46e..b0330401 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Fixed + +- Fix `ReviewBlock` seller resolution to use sellers returned by `skuFromRefIds` instead of the autocomplete restriction map, preventing false "Restricted Item" errors and missing seller dropdowns when multiple sellers are available for the active sales channel (including marketplace sellers with non-numeric IDs) + ## [3.16.7] - 2026-03-06 ### Changed diff --git a/node/yarn.lock b/node/yarn.lock index 28617a0f..63f39b8c 100644 --- a/node/yarn.lock +++ b/node/yarn.lock @@ -6759,9 +6759,9 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"stats-lite@github:vtex/node-stats-lite#dist": - version "2.2.0" - resolved "https://codeload.github.com/vtex/node-stats-lite/tar.gz/1b0d39cc41ef7aaecfd541191f877887a2044797" +stats-lite@vtex/node-stats-lite#dist: + version "2.2.1" + resolved "https://codeload.github.com/vtex/node-stats-lite/tar.gz/a0b5ee91861f31b6ec845146b4906faf5172c430" dependencies: isnumber "~1.0.0" diff --git a/react/components/ReviewBlock.tsx b/react/components/ReviewBlock.tsx index 91286ed3..195ebf82 100644 --- a/react/components/ReviewBlock.tsx +++ b/react/components/ReviewBlock.tsx @@ -21,7 +21,6 @@ import { reviewMessages as messages } from '../utils/messages' import { ParseText, GetText } from '../utils' import getRefIdTranslation from '../queries/refids.gql' import OrderFormQuery from '../queries/orderForm.gql' -import autocomplete from '../queries/autocomplete.gql' const remove = @@ -46,27 +45,6 @@ const ReviewBlock: FunctionComponent = ({ skip: !!orderFormId, }) - const checkRestriction = async (sku: any) => { - return client.query({ - query: autocomplete, - variables: { inputValue: sku }, - }) - } - - const setRestriction = async (data: any) => { - const promises = data.map((item: any) => - checkRestriction(item.refid).then((res: any) => { - const foundSku = res?.data?.productSuggestions?.products[0]?.items.find( - (suggestedItem) => suggestedItem.itemId === item.sku - ) - - return foundSku ? item : null - }) - ) - - return Promise.all(promises) - } - const [state, setReviewState] = useState({ reviewItems: reviewedItems.map((item: any, index: number) => { @@ -161,22 +139,6 @@ const ReviewBlock: FunctionComponent = ({ }) : [] - const mappedRefId = {} - - if (refidData?.skuFromRefIds?.items) { - const restrictedData = await setRestriction( - refidData.skuFromRefIds.items - ).then((data) => - data.filter((item: any) => { - return item != null - }) - ) - - restrictedData.forEach((item: any) => { - mappedRefId[item.refid] = item - }) - } - const errorMsg = (item: any, sellerWithStock: string) => { const { sku } = item @@ -222,6 +184,22 @@ const ReviewBlock: FunctionComponent = ({ ? 'store/quickorder.limited' : null + if (itemRestricted && foundHasStock) { + console.log( + '[quickorder:ReviewBlock] "Restricted Item" shown despite API reporting stock', + { + refId: sku, + sellerWithStock, + foundHasStock, + foundSellers: found?.sellers?.map((s: any) => ({ + id: s.id, + name: s.name, + availability: s.availability, + })), + } + ) + } + // Final return return notfound ? 'store/quickorder.skuNotFound' @@ -232,36 +210,126 @@ const ReviewBlock: FunctionComponent = ({ error = true } + const refIdApiMap: Record = {} + + refIdFound.forEach((apiItem: any) => { + refIdApiMap[apiItem.refid] = apiItem + }) + + const findFirstSellerWithStock = (sellers: any[] = []) => + sellers.find( + (seller: any) => + seller.availability === 'available' || + seller.availability === 'partiallyAvailable' + ) + const items = reviewed.map((item: any) => { + const refIdDataItem = refIdApiMap[item.sku] + const rowSellers = refIdDataItem?.sellers ?? [] + const sellerWithStock = item.seller ? item.seller - : item.sku && mappedRefId[item.sku]?.sellers?.length - ? mappedRefId[item.sku]?.sellers.find( - (seller: any) => - seller.availability === 'available' || - seller.availability === 'partiallyAvailable' - )?.id ?? '' - : '' - - const sellerUnitMultiplier = - item.sku && mappedRefId[item.sku]?.sellers?.length - ? mappedRefId[item.sku]?.sellers.find( - (seller: any) => seller.id === sellerWithStock - )?.unitMultiplier ?? '1' - : '1' - - const sellerAvailableQuantity = - item.sku && mappedRefId[item.sku]?.sellers?.length - ? mappedRefId[item.sku]?.sellers.find( - (seller: any) => seller.id === sellerWithStock - )?.availableQuantity - : null + : findFirstSellerWithStock(rowSellers)?.id ?? '' + + const selectedSeller = rowSellers.find( + (seller: any) => seller.id === sellerWithStock + ) + + const availableSellersFromApi = + rowSellers.filter( + (seller: any) => + seller.availability === 'available' || + seller.availability === 'partiallyAvailable' + ) + + if ( + !sellerWithStock && + availableSellersFromApi.length > 0 + ) { + console.log( + '[quickorder:ReviewBlock] Restricted Item scenario — stock exists but no seller resolved', + { + refId: item.sku, + vtexSku: refIdDataItem?.sku, + itemSeller: item.seller, + resolvedSellerWithStock: sellerWithStock, + apiSellers: rowSellers, + availableSellersFromApi: availableSellersFromApi.map( + (s: any) => ({ id: s.id, name: s.name, availability: s.availability }) + ), + } + ) + } + + if ( + sellerWithStock && + selectedSeller && + selectedSeller.availability === 'withoutStock' && + availableSellersFromApi.some((s: any) => s.id !== sellerWithStock) + ) { + console.log( + '[quickorder:ReviewBlock] Selected seller has no stock but other sellers are available', + { + refId: item.sku, + vtexSku: refIdDataItem?.sku, + selectedSellerId: sellerWithStock, + selectedSellerAvailability: selectedSeller.availability, + otherAvailableSellers: availableSellersFromApi + .filter((s: any) => s.id !== sellerWithStock) + .map((s: any) => ({ + id: s.id, + name: s.name, + availability: s.availability, + })), + } + ) + } + + const sellerUnitMultiplier = selectedSeller?.unitMultiplier ?? '1' + const sellerAvailableQuantity = selectedSeller?.availableQuantity ?? null + + const dropdownOptions = rowSellers.filter( + (seller: any) => seller?.availability !== 'withoutStock' + ) + const hasStockInRowSellers = rowSellers.find( + (seller: any) => seller?.availability !== 'withoutStock' + ) + const willShowDropdown = rowSellers.length > 1 + const sellerDisplayMode = willShowDropdown + ? 'dropdown' + : rowSellers.length && hasStockInRowSellers + ? 'singleName' + : 'empty' + + console.log( + '[quickorder:ReviewBlock] Seller column display resolution', + { + refId: item.sku, + vtexSku: refIdDataItem?.sku, + displayMode: sellerDisplayMode, + willShowDropdown, + dropdownCondition: 'rowData.sellers.length > 1', + rowSellersCount: rowSellers.length, + rowSellers: rowSellers.map((s: any) => ({ + id: s.id, + name: s.name, + availability: s.availability, + availableQuantity: s.availableQuantity, + })), + dropdownOptions: dropdownOptions.map((s: any) => ({ + id: s.id, + name: s.name, + availability: s.availability, + })), + selectedSeller: sellerWithStock, + } + ) return { ...item, - sellers: item.sku ? mappedRefId[item.sku]?.sellers : [], + sellers: rowSellers, seller: sellerWithStock, - vtexSku: item.sku ? mappedRefId[item.sku]?.sku : '1', + vtexSku: refIdDataItem?.sku ?? item.vtexSku, unitMultiplier: sellerUnitMultiplier, totalQuantity: sellerUnitMultiplier ? sellerUnitMultiplier * item.quantity @@ -318,6 +386,20 @@ const ReviewBlock: FunctionComponent = ({ try { const { data } = await client.query(query) + console.log('[quickorder:ReviewBlock] skuFromRefIds response', { + refIdSellerMap, + items: data?.skuFromRefIds?.items?.map((item: any) => ({ + refid: item.refid, + sku: item.sku, + sellers: item.sellers?.map((s: any) => ({ + id: s.id, + name: s.name, + availability: s.availability, + availableQuantity: s.availableQuantity, + })), + })), + }) + await validateRefids(data, reviewed) onRefidLoading(false) } catch (err) { @@ -340,6 +422,13 @@ const ReviewBlock: FunctionComponent = ({ return item.sku }) + console.log('[quickorder:ReviewBlock] convertRefIds — initial refIdSellerMap', { + refIdSellerMap, + orderFormId, + note: + 'Seller "1" is hardcoded; backend may return marketplace sellers (e.g. "cromosolsc1") for the active sales channel', + }) + getRefIds(refids, items, refIdSellerMap) } @@ -525,18 +614,51 @@ const ReviewBlock: FunctionComponent = ({ id: 'store/quickorder.review.label.seller', }), cellRenderer: ({ rowData }: any) => { - if (rowData?.sellers?.length > 1) { + const sellers = rowData?.sellers ?? [] + const dropdownOptions = sellers.filter( + (seller: { availability?: string }) => + seller?.availability !== 'withoutStock' + ) + const willShowDropdown = sellers.length > 1 + const hasStock = sellers.find( + (seller?: { availability: string; [key: string]: unknown }) => + seller?.availability !== 'withoutStock' + ) + const displayMode = willShowDropdown + ? 'dropdown' + : sellers.length && hasStock + ? 'singleName' + : 'empty' + + if (!refidLoading) { + console.log( + '[quickorder:ReviewBlock] Seller cell render', + { + refId: rowData.sku, + lineIndex: rowData.index, + displayMode, + willShowDropdown, + sellersCount: sellers.length, + availableSellers: dropdownOptions.map((s: any) => ({ + id: s.id, + name: s.name, + availability: s.availability, + })), + selectedSeller: rowData.seller, + } + ) + } + + if (willShowDropdown) { return (
seller?.availability !== 'withoutStock') - .map((item: any) => { - return { - label: item.name, - value: item.id, - } - })} + options={dropdownOptions.map((item: any) => { + return { + label: item.name, + value: item.id, + } + })} value={rowData.seller} onChange={(_: any, v: any) => { updateLineSeller(rowData.index, v) @@ -546,14 +668,7 @@ const ReviewBlock: FunctionComponent = ({ ) } - const hasStock = rowData?.sellers?.find( - (seller?: { availability: string; [key: string]: unknown }) => - seller?.availability !== 'withoutStock' - ) - - return rowData?.sellers?.length && hasStock - ? rowData.sellers[0].name - : '' + return sellers.length && hasStock ? sellers[0].name : '' }, } } From 25cfca7067fd284f4d455553b4b58df14509fa8a Mon Sep 17 00:00:00 2001 From: Wender Lima Date: Thu, 25 Jun 2026 15:10:00 -0300 Subject: [PATCH 2/2] [B2BTEAM-3293] Removing console.logs --- react/components/ReviewBlock.tsx | 156 +------------------------------ 1 file changed, 4 insertions(+), 152 deletions(-) diff --git a/react/components/ReviewBlock.tsx b/react/components/ReviewBlock.tsx index 195ebf82..7d07c0fb 100644 --- a/react/components/ReviewBlock.tsx +++ b/react/components/ReviewBlock.tsx @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable vtex/prefer-early-return */ import type { FunctionComponent } from 'react' @@ -184,26 +183,10 @@ const ReviewBlock: FunctionComponent = ({ ? 'store/quickorder.limited' : null - if (itemRestricted && foundHasStock) { - console.log( - '[quickorder:ReviewBlock] "Restricted Item" shown despite API reporting stock', - { - refId: sku, - sellerWithStock, - foundHasStock, - foundSellers: found?.sellers?.map((s: any) => ({ - id: s.id, - name: s.name, - availability: s.availability, - })), - } - ) - } - // Final return return notfound ? 'store/quickorder.skuNotFound' - : availabilityError ?? itemRestricted + : (availabilityError ?? itemRestricted) } if (refIdNotFound.length || refNotAvailable.length) { @@ -229,101 +212,15 @@ const ReviewBlock: FunctionComponent = ({ const sellerWithStock = item.seller ? item.seller - : findFirstSellerWithStock(rowSellers)?.id ?? '' + : (findFirstSellerWithStock(rowSellers)?.id ?? '') const selectedSeller = rowSellers.find( (seller: any) => seller.id === sellerWithStock ) - const availableSellersFromApi = - rowSellers.filter( - (seller: any) => - seller.availability === 'available' || - seller.availability === 'partiallyAvailable' - ) - - if ( - !sellerWithStock && - availableSellersFromApi.length > 0 - ) { - console.log( - '[quickorder:ReviewBlock] Restricted Item scenario — stock exists but no seller resolved', - { - refId: item.sku, - vtexSku: refIdDataItem?.sku, - itemSeller: item.seller, - resolvedSellerWithStock: sellerWithStock, - apiSellers: rowSellers, - availableSellersFromApi: availableSellersFromApi.map( - (s: any) => ({ id: s.id, name: s.name, availability: s.availability }) - ), - } - ) - } - - if ( - sellerWithStock && - selectedSeller && - selectedSeller.availability === 'withoutStock' && - availableSellersFromApi.some((s: any) => s.id !== sellerWithStock) - ) { - console.log( - '[quickorder:ReviewBlock] Selected seller has no stock but other sellers are available', - { - refId: item.sku, - vtexSku: refIdDataItem?.sku, - selectedSellerId: sellerWithStock, - selectedSellerAvailability: selectedSeller.availability, - otherAvailableSellers: availableSellersFromApi - .filter((s: any) => s.id !== sellerWithStock) - .map((s: any) => ({ - id: s.id, - name: s.name, - availability: s.availability, - })), - } - ) - } - const sellerUnitMultiplier = selectedSeller?.unitMultiplier ?? '1' - const sellerAvailableQuantity = selectedSeller?.availableQuantity ?? null - - const dropdownOptions = rowSellers.filter( - (seller: any) => seller?.availability !== 'withoutStock' - ) - const hasStockInRowSellers = rowSellers.find( - (seller: any) => seller?.availability !== 'withoutStock' - ) - const willShowDropdown = rowSellers.length > 1 - const sellerDisplayMode = willShowDropdown - ? 'dropdown' - : rowSellers.length && hasStockInRowSellers - ? 'singleName' - : 'empty' - - console.log( - '[quickorder:ReviewBlock] Seller column display resolution', - { - refId: item.sku, - vtexSku: refIdDataItem?.sku, - displayMode: sellerDisplayMode, - willShowDropdown, - dropdownCondition: 'rowData.sellers.length > 1', - rowSellersCount: rowSellers.length, - rowSellers: rowSellers.map((s: any) => ({ - id: s.id, - name: s.name, - availability: s.availability, - availableQuantity: s.availableQuantity, - })), - dropdownOptions: dropdownOptions.map((s: any) => ({ - id: s.id, - name: s.name, - availability: s.availability, - })), - selectedSeller: sellerWithStock, - } - ) + const sellerAvailableQuantity = + selectedSeller?.availableQuantity ?? null return { ...item, @@ -386,20 +283,6 @@ const ReviewBlock: FunctionComponent = ({ try { const { data } = await client.query(query) - console.log('[quickorder:ReviewBlock] skuFromRefIds response', { - refIdSellerMap, - items: data?.skuFromRefIds?.items?.map((item: any) => ({ - refid: item.refid, - sku: item.sku, - sellers: item.sellers?.map((s: any) => ({ - id: s.id, - name: s.name, - availability: s.availability, - availableQuantity: s.availableQuantity, - })), - })), - }) - await validateRefids(data, reviewed) onRefidLoading(false) } catch (err) { @@ -422,13 +305,6 @@ const ReviewBlock: FunctionComponent = ({ return item.sku }) - console.log('[quickorder:ReviewBlock] convertRefIds — initial refIdSellerMap', { - refIdSellerMap, - orderFormId, - note: - 'Seller "1" is hardcoded; backend may return marketplace sellers (e.g. "cromosolsc1") for the active sales channel', - }) - getRefIds(refids, items, refIdSellerMap) } @@ -624,30 +500,6 @@ const ReviewBlock: FunctionComponent = ({ (seller?: { availability: string; [key: string]: unknown }) => seller?.availability !== 'withoutStock' ) - const displayMode = willShowDropdown - ? 'dropdown' - : sellers.length && hasStock - ? 'singleName' - : 'empty' - - if (!refidLoading) { - console.log( - '[quickorder:ReviewBlock] Seller cell render', - { - refId: rowData.sku, - lineIndex: rowData.index, - displayMode, - willShowDropdown, - sellersCount: sellers.length, - availableSellers: dropdownOptions.map((s: any) => ({ - id: s.id, - name: s.name, - availability: s.availability, - })), - selectedSeller: rowData.seller, - } - ) - } if (willShowDropdown) { return (