# Документация — qwelp.location

## О модуле

## Начало работы

- Установите решение через Marketplace. На шаге установки выберите сайты. Демо-города добавляйте только для знакомства.
- Откройте «Квэлп → Местоположения → Города», выберите сайт и добавьте города.
- Добавьте активные города с уникальными кодами и выберите город по умолчанию.
- Разместите кнопку выбора города и компонент контактов по примерам в документации.

Требуются PHP 8.2 и main 24.300.0+, модуль «Информационные блоки». Цены и склады используют «Торговый каталог», свойства заказа — «Интернет-магазин». Эти возможности доступны при наличии соответствующих модулей. Интерфейс выбора города работает самостоятельно.

**Куда устанавливаются файлы**

Общий модуль — /bitrix/modules/qwelp.location/, компоненты — /bitrix/components/qwelp/location.contacts/, ресурсы — /bitrix/js/qwelp/location/. У каждого сайта может быть свой /local/ или его может не быть. Пользовательские переопределения установщик сохраняет.

## Города и сайты

- Откройте «Квэлп → Местоположения → Города» и выберите сайт.

- Нажмите «Добавить город». Заполните название, уникальный код и включите активность.

- На вкладках карточки укажите контакты, координаты, местоположение доставки, тип цены и склады. Сохраните.

- В списке выберите «Город по умолчанию» и нажмите «Выбрать для сайта».

Список показывает активные и отключённые города. Чтобы временно убрать город с витрины, отключите его в карточке. Данные сохранятся. Настройки карты и оформления заказа находятся в пункте «Настройки» левого меню модуля.

Хранилище и совместимость

Данные городов остаются в инфоблоке. Карточка сохраняет дополнительные свойства клиента и неизменённые изображения. Выбор города по умолчанию хранится отдельно для сайта и имеет приоритет над прежним признаком в инфоблоке. Пока явного выбора нет, используется активный город с прежним признаком, затем первый доступный.

Адреса магазинов и складские остатки остаются в штатном каталоге Битрикса. В карточке выбираются привязки; ссылка рядом открывает список складов. Домен, часовой пояс, минимальная сумма, валюта и SEO доступны через API и сами по себе не включают редиректы, ограничения или пересчёт цен.



## Диагностика городов

В пункте «Диагностика» выберите сайт. В колонке «Что заполнить» у каждого активного города показаны недостающие тип цены, склады и координаты. Нажмите название города, заполните данные в карточке и сохраните. Если отметок нет, показано «Заполнено». Под таблицей доступны номера страниц, стрелки и выбор 10, 25, 50 или 100 городов на странице. Сводные счётчики учитывают все доступные активные города выбранного сайта, включая города на других страницах.

## Выбор города

Добавьте этот вызов в шаблон сайта в месте расположения кнопки:

```php
if (\Bitrix\Main\Loader::includeModule('qwelp.location')) {
    \Qwelp\Location\Helper\RenderHelper::renderCityButton('modal');
}
```

Доступны варианты `modal`, `dropdown`, `center_grid`. Если аргумент не передан, используется настройка модуля. Поиск работает по активным городам модуля. При ошибке загрузки посетитель может повторить запрос.

**Кеш и Композит**

Ресурсы регистрируются до выполнения компонентов, а обработчики сохраняют работоспособность после замены динамического фрагмента. Собственный кеш родительского компонента, включающий название города или региональные данные, должен включать код текущего города в ключ кеша. Не сохраняйте персональные данные в общем кешe. После изменения интеграции очистите прежний кеш компонента и Композита.

## Контакты и карта

Пример страницы контактов с отключённой отправкой сообщений:

```php
$APPLICATION->IncludeComponent('qwelp:location.contacts', '.default', [
    'CONTACTS_LAYOUT' => 'default',
    'SHOW_FEEDBACK_FORM' => 'N',
    'SHOW_CITY_FILTER' => 'Y',
    'PAGE_TITLE' => '',
    'CACHE_TYPE' => 'A',
    'CACHE_TIME' => '36000000',
]);
```

Для списка магазинов выберите шаблон `stores` и параметр `CONTACTS_LAYOUT=stores`. Настройки компонента доступны в визуальном редакторе Bitrix.

- Добавьте склады с адресами и координатами и привяжите их к городам.
- Для карты укажите собственный ключ JavaScript API Яндекс Карт. Рядом с полем API-ключа в «Настройках» есть ссылка «Получить ключ»: она открывает кабинет разработчика Яндекса в новой вкладке. Выберите JavaScript API, скопируйте ключ в поле и сохраните настройки. Если ключ не настроен, в пункте «Диагностика» левого меню нажмите «Настроить» в строке «API-ключ Яндекс.Карт»: откроется поле ключа в настройках выбранного сайта.
- Разрешите внешние запросы в настройках модуля после выполнения требований сервиса и вашего сайта к согласию посетителей.

При выключенных внешних запросах адреса остаются доступны списком. Карта загружается только при разрешённом обращении к сервису. Обратная связь использует штатный bitrix:main.feedback и его почтовые шаблоны. Проверьте настройки почты до включения формы.

## Региональные цены

Модуль рассчитывает региональные цены через API. Чтобы они появились в разделе каталога, детальной карточке, рекомендациях или своём блоке, подключите расчёт в шаблоне каждого такого места. Установка модуля сама по себе не заменяет цену в произвольной вёрстке. Эти шаги выполняет разработчик шаблона.

### 1. Настройте типы цен и города

1. В Битриксе создайте нужные типы цен, заполните цены товаров и торговых предложений. Разрешите нужным группам пользователей просмотр и покупку по этим типам.
2. В «Квэлп → Местоположения → Города» выберите сайт. В карточке города на вкладке «Цены и склады» выберите тип цены и склады; сохраните. Укажите город по умолчанию.
3. Подключите выбор города по разделу справки «Выбор города». Цена определяется городом текущего посетителя на текущем сайте, а не сайтом, выбранным в админке.

### Где размещать код

| Место | Шаблон и данные |
| --- | --- |
| Раздел каталога, подборка, рекомендации | bitrix:catalog.section → result_modifier.php → $arResult['ITEMS'] |
| Детальная карточка товара | bitrix:catalog.element → result_modifier.php → $arResult |
| Отдельная карточка списка | bitrix:catalog.item → result_modifier.php → $arResult['ITEM'] |
| Свой блок цены по ID | После подключения пролога Bitrix, перед выводом HTML → RegionalPriceService::resolve() |

Работайте в копии шаблона сайта: /local/templates/<шаблон_сайта>/components/bitrix/catalog.section/<шаблон_компонента>/result_modifier.php; для детальной страницы замените catalog.section на catalog.element. Если файла нет, создайте его с <?php и проверкой B_PROLOG_INCLUDED. В существующем файле добавляйте фрагмент внутрь PHP. Сохраняйте штатную подготовку данных и пользовательские правки; ядро /bitrix/components/ не редактируйте.

### 2. Передайте регион в параметры и кеш компонента

До существующего вызова $APPLICATION->IncludeComponent вынесите его текущий массив параметров в $catalogParams. Добавьте фрагмент ниже и передайте $catalogParams третьим аргументом того же вызова. Имя компонента, имя шаблона, инфоблок, фильтр и остальные аргументы сохраняются. Для современного шаблона нужен COMPATIBLE_MODE=N; старый шаблон с полем PRICES требует отдельной адаптации.

```php
if (\Bitrix\Main\Loader::includeModule('qwelp.location')) {
    $catalogParams['PRICE_CODE'] =
        \Qwelp\Location\Service\LocationService::getComponentPriceTypeCodeArray();
    $catalogParams['QWELP_LOCATION_CACHE_CONTEXT'] =
        \Qwelp\Location\Service\LocationService::getCatalogCacheContext();
    $catalogParams['CACHE_GROUPS'] = 'Y';
    $catalogParams['COMPATIBLE_MODE'] = 'N';
}
```

PRICE_CODE ограничивает исходную выборку типом цены города. QWELP_LOCATION_CACHE_CONTEXT — дополнительный параметр вашей интеграции: штатный кеш компонента учитывает параметры, в том числе город, склады, группы и версию настроек. Заполняйте его до начала кеширования, а не в result_modifier.php. Для собственного кеша добавьте тот же контекст к его ключу.

#### Если используется комплексный bitrix:catalog

В его шаблоне section.php и element.php передайте контекст дальше в параметры вложенных catalog.section и catalog.element. В этом фрагменте $catalogParams — существующие параметры дочернего вызова, а $arParams — параметры родителя после предыдущего шага. Аналогично поступите с кешируемыми рекомендациями и другими родительскими блоками.

```php
$catalogParams['PRICE_CODE'] = $arParams['PRICE_CODE'];
$catalogParams['QWELP_LOCATION_CACHE_CONTEXT'] =
    $arParams['QWELP_LOCATION_CACHE_CONTEXT'];
$catalogParams['CACHE_GROUPS'] = 'Y';
$catalogParams['COMPATIBLE_MODE'] = 'N';
```

### 3. Карточки товаров в разделе и подборках

В result_modifier.php шаблона catalog.section добавьте код после штатной подготовки ITEMS и OFFERS, перед формированием своих копий цены и JS-данных. Сервис меняет массив на месте; присваивать результат enrichItems() нельзя — метод возвращает void. Для catalog.top применяйте к реальному массиву ITEMS, в том числе внутри каждого блока ROWS, если шаблон группирует товары.

```php
if (!empty($arResult['ITEMS'])
    && \Bitrix\Main\Loader::includeModule('qwelp.location')) {
    $regionalCatalog = \Bitrix\Main\DI\ServiceLocator::getInstance()->get(
        \Qwelp\Location\Service\RegionalCatalogService::class
    );
    $regionalCatalog->enrichItems(
        $arResult['ITEMS'],
        quantity: 1.0,
        siteId: SITE_ID,
        vatInclude: ($arParams['PRICE_VAT_INCLUDE'] ?? 'Y') !== 'N',
        currency: ($arParams['CONVERT_CURRENCY'] ?? 'N') === 'Y'
            ? (trim((string)($arParams['CURRENCY_ID'] ?? '')) ?: null)
            : null
    );
}
```

### 4. Детальная карточка товара

В result_modifier.php шаблона catalog.element после штатной подготовки товара и предложений используйте enrichItem(). Он обрабатывает один товар вместе с уже загруженными OFFERS и JS_OFFERS. Если шаблон заранее сохранил цену в своих переменных, пересоздайте их после этого вызова.

```php
if (!empty($arResult['ID'])
    && \Bitrix\Main\Loader::includeModule('qwelp.location')) {
    $regionalCatalog = \Bitrix\Main\DI\ServiceLocator::getInstance()->get(
        \Qwelp\Location\Service\RegionalCatalogService::class
    );
    $regionalCatalog->enrichItem(
        $arResult,
        quantity: 1.0,
        siteId: SITE_ID,
        vatInclude: ($arParams['PRICE_VAT_INCLUDE'] ?? 'Y') !== 'N',
        currency: ($arParams['CONVERT_CURRENCY'] ?? 'N') === 'Y'
            ? (trim((string)($arParams['CURRENCY_ID'] ?? '')) ?: null)
            : null
    );
}
```

Если карточка выводится отдельным catalog.item, передавайте $arResult['ITEM'] вместо $arResult и проверяйте его ID. Достаточно обработать товар в одном выбранном месте: обычно удобнее весь список в catalog.section. Параметр quantity — количество для расчёта, PRICE_VAT_INCLUDE и CONVERT_CURRENCY/CURRENCY_ID берутся из текущего компонента.

### 5. Как вывести полученную цену

В template.php внутри цикла товаров используйте пример ниже: $item — текущий товар из уже обработанного ITEMS. Для детальной страницы замените первую строку на $regionalItem = $arResult;, для catalog.item — на $regionalItem = $arResult['ITEM'];. Штатный современный шаблон обычно уже читает ITEM_PRICES, поэтому отдельный второй ценник ему не нужен. Пример показывает сумму с кодом валюты.

```php
<?php
$regionalItem = $item;
if (!empty($regionalItem['OFFERS'])) {
    $offerIndex = $regionalItem['OFFERS_SELECTED'] ?? null;
    $regionalItem = $offerIndex !== null
        ? ($regionalItem['OFFERS'][$offerIndex] ?? [])
        : [];
}
$priceIndex = $regionalItem['ITEM_PRICE_SELECTED'] ?? null;
$regionalPrice = $priceIndex !== null
    ? ($regionalItem['ITEM_PRICES'][$priceIndex] ?? null)
    : null;
?>
<?php if (is_array($regionalPrice)): ?>
    <span class="product-price"><?=
        \Bitrix\Main\Text\HtmlFilter::encode(
            number_format((float)$regionalPrice['PRICE'], 2, ',', ' ')
            . ' ' . (string)$regionalPrice['CURRENCY']
        )
    ?></span>
<?php endif; ?>
```

| Поле | Назначение |
| --- | --- |
| ITEM_PRICES[ITEM_PRICE_SELECTED] | Цена выбранного товара/предложения и количества; PRICE — со скидкой, BASE_PRICE — до скидки, CURRENCY — валюта. |
| OFFERS и JS_OFFERS | Цена каждого предложения. При смене размера/цвета ваш JS должен брать цену выбранного предложения из обновлённых данных. |
| MIN_PRICE | Минимальная цена «от» для товара с предложениями; не подменяет цену выбранного SKU в детальной карточке. |
| CAN_BUY, MAX_QUANTITY | Доступность и ограничение количества после RegionalCatalogService; цена сама по себе не означает возможность покупки. |

Если ITEM_PRICES пуст, не показывайте 0 и не возвращайте прежний BASE или CATALOG_PRICE_1: это может быть недоступная региональная цена. Покажите предусмотренное вашим шаблоном состояние без цены. Кнопка покупки должна учитывать CAN_BUY. На сервере корзины и заказа также проверяются цена и допустимое количество; изменение одного HTML-ценника этих проверок не заменяет.

### 6. Цена в произвольном блоке по ID

После пролога Bitrix задайте $productId ID простого товара или конкретного выбранного торгового предложения из данных вашего блока. Код ниже получает только цену, без расчёта складской доступности. Затем используйте предыдущий фрагмент вывода с $item. Для списка передайте все ID одним вызовом resolve(), а не вызывайте сервис в цикле для каждого товара.

```php
$regionalPrices = [];
if ($productId > 0 && \Bitrix\Main\Loader::includeModule('qwelp.location')) {
    $regionalPrices = \Bitrix\Main\DI\ServiceLocator::getInstance()
        ->get(\Qwelp\Location\Service\RegionalPriceService::class)
        ->resolve([$productId], quantity: 1.0, siteId: SITE_ID);
}
$item = $regionalPrices[$productId] ?? [];
```

Для минимальной цены родителя с предложениями у resolve() есть includeSkuOffers: true. Результат индексирован ID товара; OFFERS содержит цены предложений, SOURCE_PRODUCT_ID — источник минимальной цены. Это расчёт цены, а не выбор доступного на региональном складе SKU. Для готового товарного массива с остатками используйте RegionalCatalogService.

### Кеш, Композит и проверка подключения

- Один result_modifier.php не решает общий кеш: при попадании в кеш он не запускается. Регион должен входить в ключ компонента и каждого кешируемого родителя до получения результата.
- Кеш компонента и полный HTML-кеш Композита — разные уровни. Региональный/персональный ценник нельзя оставлять в общей статической части страницы; используйте динамическую область или подходящий сессионный режим вашей интеграции. Пустая заглушка не должна показывать цену другого города.
- getCatalogCacheContext() не является полным ключом для всех персональных скидок и купонов. Такие цены требуют контекста посетителя либо динамического вывода; не включайте личные данные в общий кеш.
- После смены города обновите затронутые блоки или страницу. Для AJAX передавайте текущий контекст сайта, используйте тот же серверный расчёт; не читайте HttpOnly cookie города из JavaScript.
- После подключения проверьте один товар в двух городах с разными ценами: раздел, детальную карточку, смену SKU и повторное открытие страницы с прогретым кешем. Это проверка вашей интеграции, а не подтверждение, что шаблон изменился автоматически.

**Город без настроек**

Если у города не задан или не найден тип цены, модуль использует тип цены города по умолчанию, затем базовый тип Битрикса. Опция PRICE_FALLBACK добавляет базовый тип как запасной, когда у товара нет цены выбранного типа. Опция GLOBAL_STOCK_FALLBACK разрешает общий остаток, если региональные склады не заданы. Обе опции по умолчанию выключены.

OTHER_CITIES_STOCK_FALLBACK (по умолчанию N) разрешает при отсутствии свободного остатка в выбранном городе проверить активные склады всех активных городов текущего сайта. Резервы вычитаются, чужие непривязанные склады не участвуют. Если местный остаток есть, используется только он; фолбек не расширяет его при запросе большего количества. Правила цены и запрета покупки сохраняются. Корзина и оформление должны использовать STORE_IDS и STORES из результата для конкретного товара; самовывоз проверяется отдельно по выбранному складу. Ошибка чтения региональных остатков не должна разрешать покупку.

**Особые правила продажи**

Для товаров под заказ или услуг передавайте явные параметры IS_MADE_TO_ORDER, IS_SERVICE, REQUIRED или BYPASS в массиве с ключом RegionalStockService::OPTIONS_KEY. Для комплектов доступен SET_COMPONENT_STATES. Политика конкретного шаблона сайта не определяется автоматически.

## Обслуживание

- После изменения городов проверьте выбор, контакты, цены и склады на каждом сайте.
- Права R разрешают просмотр админки, W — изменение настроек и очистку кеша; установка и удаление доступны администратору.
- При удалении выберите, сохранять ли данные. Повторная установка использует сохранённые собственные данные.
- Удаление данных затрагивает только подтверждённо созданные модулем инфоблоки и файлы. Изменённые стороной файлы блокируют удаление до разбора конфликта.

При переходе с внутренней версии с файлами в /local/ сначала сохраните настройки и переопределения. Автоматического удаления клиентского /local/ нет. Старые интеграционные настройки сторонних модулей сохраняются; перенесите используемые значения в настройки этого модуля.

**События интеграции**

OnAfterCatalogCacheClear сообщает об очистке регионального каталога; OnAfterDiscountBoundaryChange — о переходе границы скидок. Источник обоих событий — qwelp.location. OnBeforeRegionalCatalogStock вызывается после расчёта цен, перед остатками; OnBeforeRegionalStockEnrich — перед обогащением остатков. В них items содержит товары, siteId — сайт, а во втором событии productSetComponents содержит состав комплектов. Для изменения данных верните EventResult::SUCCESS с массивом items, сохранив ключи и ID товаров; EventResult::ERROR прерывает расчёт. Обработчик второго события может вернуть EventResult::ERROR, чтобы повторить попытку позже. Детали исключений записываются в штатный журнал Bitrix.

Поддержка: [qwelp.ru](https://qwelp.ru).



## Оформление заказа

Выбранный на сайте город может автоматически заполнять пустое поле доставки стандартного компонента bitrix:sale.order.ajax. Правка ядра и копирование шаблона заказа не нужны.

- В Битриксе откройте «Магазин → Настройки → Местоположения» и загрузите местоположения, если справочник пуст.

- Откройте «Квэлп → Местоположения → Города». В карточке каждого города на вкладке «Карта и оформление заказа» найдите «Местоположение для доставки» через поиск и сохраните.

- В свойствах заказа для каждого используемого типа плательщика проверьте активное свойство типа «Местоположение» с признаком использования для расчёта доставки. Оно не должно быть служебным. Используется первое такое свойство по сортировке.

- В «Местоположения → Настройки» включите «Подставлять выбранный город в стандартное оформление заказа».

- В параметрах существующего компонента оформления отключите «Определять местоположение покупателя по IP» (SPOT_LOCATION_BY_GEOIP = N), чтобы встроенное определение по IP не заполнило поле раньше выбранного города.

- Добавьте кнопку выбора города в шаблон сайта, например в шапку. Если кнопка уже есть, повторно добавлять её не нужно.



```php
if (\Bitrix\Main\Loader::includeModule('qwelp.location')) {
    \Qwelp\Location\Helper\RenderHelper::renderCityButton('modal');
}
```

Вставляйте пример внутри PHP-блока. Для кнопки непосредственно на странице оформления вызовите его после подключения шапки и перед существующим $APPLICATION->IncludeComponent('bitrix:sale.order.ajax', ...). Остальные параметры своего компонента сохраните. В его массиве параметров измените:

```php
'SPOT_LOCATION_BY_GEOIP' => 'N',
```

Когда выполняется подстановка

Только при первом открытии страницы методом GET и только в пустое поле доставки. Адрес из профиля, последнее местоположение, значение по умолчанию свойства, результат включённого GeoIP и ручной выбор сохраняют приоритет. AJAX-пересчёт, смена доставки и отправка заказа не перезаписывают адрес. Переключатель города сайта не заменяет уже заполненный адрес доставки и не синхронизирует его в обратную сторону.

Если город не связан с местоположением или оно удалено, оформление работает как обычно. Собственные формы заказа, не вызывающие штатное событие, требуют отдельной интеграции.

Отключить для одной страницы

Добавьте в массив параметров существующего bitrix:sale.order.ajax:



```php
'QWELP_LOCATION_PREFILL' => 'N',
```

Для всех страниц сайта выключите настройку модуля.

Проверка и устранение проблем

- В новом приватном окне выберите связанный город, добавьте товар и перейдите к оформлению: пустое поле доставки должно заполниться.

- Вручную измените город в оформлении, затем доставку: ручной выбор должен сохраниться.

- Повторите для каждого типа плательщика и сайта.

- Если город не появился, проверьте связь в карточке, настройку нужного сайта и признаки свойства заказа. Заполненное профилем поле намеренно не изменяется.

Штатная установка сама регистрирует OnSaleComponentOrderProperties. Дополнительный обработчик в init.php не нужен. Копирование файлов не заменяет установку модуля.




### Значения фолбеков в рамках запроса

Событие `qwelp.location:OnResolveBooleanOption` позволяет явной интеграции сайта переопределить `PRICE_FALLBACK` и `OTHER_CITIES_STOCK_FALLBACK` только для текущего запроса. Параметры: `name`, `value` (bool), `siteId`. Для переопределения обработчик возвращает `EventResult::SUCCESS` с `value` строго типа bool; `UNDEFINED` сохраняет значение модуля. Чтение не записывает опции. Интеграция обязана ограничить значение нужным сайтом и сессией; эффективные флаги входят в контекст кеша каталога.


## Корзина и остатки

Региональная цена стандартной корзины рассчитывается сервером через обработчик модуля. Копировать шаблоны `sale.basket.basket` и `sale.order.ajax` только ради цены не нужно. В каталоге сначала выполните раздел «Региональные цены».

### Подключение по шагам

1. Создайте типы цен в «Магазин → Настройки → Цены → Типы цен». В самом типе разрешите нужным группам просмотр и покупку; для открытого магазина проверьте группу «Все пользователи». Заполните цены именно у торговых предложений, если товар имеет размеры или цвета.
1. В карточках городов выберите тип цены и склады. Заполните остатки товаров и предложений на этих складах. Для ограничиваемых остатков у товара включите количественный учёт и запрет покупки при отсутствии.
1. Откройте «Квэлп → Местоположения → Настройки», выберите сайт и включите «Проверять региональные остатки в корзине и заказе». Сохраните. До назначения складов эта настройка по умолчанию выключена.
1. Добавьте кнопку города в общую шапку либо перед существующими компонентами корзины и оформления. Не добавляйте повторно, если кнопка уже есть.

```php
if (\Bitrix\Main\Loader::includeModule('qwelp.location')) {
    \Qwelp\Location\Helper\RenderHelper::renderCityButton('modal');
}
```

### Что проверяется

- При добавлении и увеличении количества сервер проверяет остаток выбранного города. Количество одинакового товара в нескольких строках суммируется.
- При смене города цены пересчитываются. Если оставшегося количества недостаточно, корзина показывает сообщение. Уменьшите количество, удалите товар или вернитесь в другой город.
- Оформление повторно проверяет остаток до сохранения нового заказа. Товары без количественного учёта и товары с разрешённой покупкой при нулевом остатке сохраняют штатные правила.
- Ручной адрес доставки не меняет город цен магазина. Кнопка города и поле местоположения заказа решают разные задачи; подстановка адреса описана в разделе «Оформление заказа».

**Границы интеграции**

Используются штатные события корзины и заказа Битрикса. Собственная корзина, которая не вызывает эти события, требует серверной проверки через API. Административное редактирование уже созданных заказов и фоновые операции без контекста посетителя не используют текущий город браузера. Проверка остатка не заменяет штатное резервирование и не назначает склад отгрузки.

Если склады города не заданы, поведение зависит от «Использовать общий остаток…». При выключенной опции товар с контролем количества нельзя купить. Ошибка чтения остатка не разрешает оформление. Индивидуальные правила услуг, комплектов и товаров под заказ согласуйте с серверной интеграцией; одного изменения `CAN_BUY` в шаблоне недостаточно.

### Проверка перед запуском

1. В новом приватном окне выберите два города с разными ценами. Сравните один товар в разделе, детальной карточке, корзине и заказе.
1. Для товара с предложениями переключите размер или цвет, добавьте выбранное предложение и проверьте его цену.
1. Проверьте товар, доступный только в одном городе, и попытку заказать больше местного остатка.
1. Переключите город с заполненной корзиной, уменьшите количество после предупреждения и убедитесь, что оформление снова доступно.
1. Повторите чтение прогретых страниц и проверку на каждом используемом сайте. Не подменяйте эти проверки постоянной очисткой всего кеша.

**Стандартный шаблон bootstrap_v4: точные места подключения**

1. Скопируйте целиком шаблоны комплексного catalog, catalog.section и catalog.element в пользовательские папки, например `/local/templates/.default/components/bitrix/catalog/qwelp_location/`, `catalog.section/qwelp_location/` и `catalog.element/qwelp_location/`. Одного нового result_modifier.php без template.php недостаточно.
1. В существующем вызове catalog выберите имя шаблона `qwelp_location`. В его копии измените имена шаблонов дочерних catalog.section и catalog.element на это же имя.
1. В bootstrap_v4 параметры списка находятся в `section_vertical.php` и `section_horizontal.php`, а детальной карточки — в `element.php`. Передайте региональный контекст в реально выполняемые вложенные вызовы, включая подборки.
1. В обоих result_modifier.php сохраните штатный `$arParams = $component->applyTemplateModifications();` и добавьте обогащение ниже. Проверьте не только первый ценник, но и смену SKU.

Для штатного блока «Наличие на складах» передайте `LocationService::getCurrentStoreIds()` в параметр `STORES` существующего catalog.store.amount через комплексный каталог. Папка `.default` позволяет подключить свою копию компонента без создания неполного шаблона сайта и без правки ядра.

<strong>Если вместо выбранного города всегда Москва:</strong> откройте свойство заказа «Местоположение» для нужного типа плательщика и очистите «Значение по умолчанию», если хотите подставлять город магазина. Проверьте в новом приватном окне: адрес из профиля или предыдущего оформления намеренно имеет приоритет. Сделайте это отдельно для каждого используемого типа плательщика.


Рабочие параметры доступны в разделе «Квэлп → Квэлп: Местоположения → Настройки». В штатном разделе «Настройки → Настройки модулей» находится только вкладка «Доступ» для прав групп. API-ключ Яндекс.Карт при новой установке пустой; сохранённый ключ сайта не переносится в архив.
