From 74f5c26f74a978c996047194c8cd7250519a98a8 Mon Sep 17 00:00:00 2001 From: Ekaterina Volkova Date: Fri, 14 Aug 2026 06:48:19 +0000 Subject: [PATCH 1/2] Fill postal code from block-less re-query when dadata suggestion lacks it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dadata house-level suggestions for buildings with a block (к N) often return postal_code=null, leaving the required postcode field empty and blocking checkout. When that happens, re-query dadata without the block part — the building index is the same. --- components/order/AddressAutocomplete.vue | 26 ++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/components/order/AddressAutocomplete.vue b/components/order/AddressAutocomplete.vue index 88e47000..742ce16e 100644 --- a/components/order/AddressAutocomplete.vue +++ b/components/order/AddressAutocomplete.vue @@ -80,18 +80,40 @@ const onInput = () => { debounceTimer = setTimeout(() => fetchSuggestions(query.value), 300); }; -const applyDadataResult = (suggestion: DadataSuggestion) => { +const fetchPostcodeWithoutBlock = async (data: DadataAddressData): Promise => { + const parts = [data.city_with_type || data.settlement_with_type, data.street_with_type, data.house ? `д ${data.house}` : null].filter(Boolean); + if (parts.length < 3) return ''; + try { + const res = await $fetch<{ suggestions: DadataSuggestion[] }>( + 'https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/address', + { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'Authorization': `Token ${config.public.dadataKey}` }, + body: JSON.stringify({ query: parts.join(', '), count: 1 }), + } + ); + return res.suggestions?.[0]?.data.postal_code || ''; + } catch { + return ''; + } +}; + +const applyDadataResult = async (suggestion: DadataSuggestion) => { selected.value = true; const { data } = suggestion; query.value = suggestion.value; isOpen.value = false; const city = data.city_with_type || data.settlement_with_type || data.region_with_type || ''; - const postcode = data.postal_code || ''; const street = data.street_with_type || ''; const house = [data.house || null, data.block ? `к${data.block}` : null].filter(Boolean).join(' '); const room = data.flat ?? ''; + let postcode = data.postal_code || ''; + if (!postcode && data.block) { + postcode = await fetchPostcodeWithoutBlock(data); + } + emit('select', { city, postcode, street, house, room }); }; From a6ca280930084eeec3c581600c364cec41383fa8 Mon Sep 17 00:00:00 2001 From: Ekaterina Volkova Date: Fri, 14 Aug 2026 07:23:09 +0000 Subject: [PATCH 2/2] Validate block-less re-query result and dedupe dadata fetch calls Accept the fallback postcode only when the returned suggestion matches the selected street and house, so a fuzzy match can't inject a wrong index. Extract dadataSuggest() shared by all three call sites. --- components/order/AddressAutocomplete.vue | 44 +++++++++--------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/components/order/AddressAutocomplete.vue b/components/order/AddressAutocomplete.vue index 742ce16e..26e7cc99 100644 --- a/components/order/AddressAutocomplete.vue +++ b/components/order/AddressAutocomplete.vue @@ -51,6 +51,16 @@ const showRecent = () => { } }; +const dadataSuggest = (query: string, count: number) => + $fetch<{ suggestions: DadataSuggestion[] }>( + 'https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/address', + { + method: 'POST', + headers: { 'Authorization': `Token ${config.public.dadataKey}` }, + body: { query, count }, + } + ); + const fetchSuggestions = async (value: string) => { if (value.trim().length < 3) { suggestions.value = []; @@ -59,17 +69,7 @@ const fetchSuggestions = async (value: string) => { if (!value.trim()) showRecent(); return; } - const res = await $fetch<{ suggestions: DadataSuggestion[] }>( - 'https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/address', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Token ${config.public.dadataKey}`, - }, - body: JSON.stringify({ query: value, count: 6 }), - } - ); + const res = await dadataSuggest(value, 6); suggestions.value = res.suggestions ?? []; isOpen.value = suggestions.value.length > 0; emit('noResults', suggestions.value.length === 0); @@ -84,15 +84,10 @@ const fetchPostcodeWithoutBlock = async (data: DadataAddressData): Promise( - 'https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/address', - { - method: 'POST', - headers: { 'Content-Type': 'application/json', 'Authorization': `Token ${config.public.dadataKey}` }, - body: JSON.stringify({ query: parts.join(', '), count: 1 }), - } - ); - return res.suggestions?.[0]?.data.postal_code || ''; + const res = await dadataSuggest(parts.join(', '), 1); + const found = res.suggestions?.[0]?.data; + if (!found || found.house !== data.house || found.street_with_type !== data.street_with_type) return ''; + return found.postal_code || ''; } catch { return ''; } @@ -121,14 +116,7 @@ const onSelect = async (suggestion: DadataSuggestion) => { if (suggestion.isRecent) { query.value = suggestion.value; isOpen.value = false; - const res = await $fetch<{ suggestions: DadataSuggestion[] }>( - 'https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/address', - { - method: 'POST', - headers: { 'Content-Type': 'application/json', 'Authorization': `Token ${config.public.dadataKey}` }, - body: JSON.stringify({ query: suggestion.value, count: 1 }), - } - ); + const res = await dadataSuggest(suggestion.value, 1); if (res.suggestions?.[0]) applyDadataResult(res.suggestions[0]); else emit('noResults', true); return;