
- MODX 3
- PHP 8.2
- miniShop3


Дата релиза: 4 ноября 2026
Минорный релиз: багфиксы корзины, security-слой API, централизованная тема PrimeVue через VueTools.
Повышены минимальные требования. Package Manager теперь откажет на установке, если какая-то из зависимостей старее. Ранее ошибка всплывала только в рантайме.
| Пакет | Было | Стало |
|---|---|---|
| PHP | ≥ 8.2 | ≥ 8.2 |
| MODX | ≥ 3.0.0 | ≥ 3.0.0 |
| MiniShop3 | не декларировалась | ≥ 1.13.0-beta1 |
| pdoTools | не декларировалась | ≥ 3.0.0 |
| VueTools | не декларировалась | ≥ 1.2.0 |
Vue-админка перешла на тему из VueTools. Тема больше не прошита: preset берётся из системной настройки vuetools.theme (aura или modx). PrimeVue, Vue и Pinia идут через Import Map VueTools — шарятся с MS3 и остальными Vue-компонентами. Бандл админки упал с ~1040 КБ до ~65 КБ (gzip 22 КБ). Переименования PrimeVue 4.5: Dropdown → Select, Chips → InputChips.
Двойная скидка при смене количества позиции. Инвариант snapshot'а из 1.0.1-beta1 (live_price + discount_amount / count ≈ original_price) ломался при смене количества: MiniShop3 оставляет цену за единицу (уже со скидкой) и пересчитывает только cost. Snapshot признавался устаревшим, и syncAfterCartChange() накладывал скидку второй раз. Теперь snapshot хранит цену, которую поставил сам apply (discounted_price), и проверяется по ней — смена количества её не меняет.
min_order_amount сверялся с суммой уже со скидкой. ValidationService::validateForOrder() брал msOrder.cart_cost черновика, а там после apply сумма со скидкой. Теперь apply() и validate() передают сумму позиций по исходным ценам.
Analytics-процессор GetLog возвращал всегда пустой журнал. SELECT ссылался на Order.status — колонка называется status_id. SQL молча падал, API отдавал {success: true, total: N, results: []}. KPI-карточки показывали число, журнал был пуст.
Резолвер статистики установки не подключался в сборку. Файл был в репозитории с первого релиза, но в массив $resolvers в build.php не входил — ни одна установка не отправляла метрики на metrics.modx.pro. Заодно резолвер приведён к эталону: правильный префикс ms3_ на install_type / previous_version, package_version из подписи транспорта, поддержка metrics_optout, reconnect к БД.
JS API: destroy() не очищал локальные подписки через on(). Объект listeners жил в замыкании модуля — в SPA при цикле destroy → init обработчики накапливались.
JS API: remove() и validate() молчали при не-success ответе. apply() эмитил error, две соседние функции — только из catch (сетевой сбой). Для validate() дополнительно учитывается бизнес-ответ {valid: false, reason, message} — теперь эмитится отдельная ветка error с code = data.reason.
CodesView confirm-диалог вводил в заблуждение. Диалог обещал, что удаление кода не затронет историю применений. По факту composites с owner='local' в модели msPromoCode даёт cascade delete всех msPromoCodeUsage. Текст предупреждения исправлен; корневая смена семантики (SET NULL или disallow delete) оставлена в бэклоге.
CORS, rate limiting и проверка доступности сервиса теперь действуют для /api/v1/promo/*. Группа роутов имела только TokenMiddleware: OPTIONS preflight возвращал 405 (SPA с другого origin не работал), /apply можно было долбить без ограничения. Стек приведён к паттерну MS3: cors → rateLimit → serviceCheck → token. ServiceCheckMiddleware возвращает 503 Service unavailable, если фасад MS3 не зарегистрирован — иначе PromoCodeController падал необработанным исключением.
vuetools/theme, админка покажет модальное окно MODX с сообщением «требуется VueTools >= 1.2.0» вместо немой ошибки ES-модуля в консоли.filemtime для JS и CSS Vue-админки. Без него браузер держал старый бандл после пересборки под той же версией пакета.ms3PromoCodeForm, headless JS API, web API) не менялась — свои чанки и override-ассеты продолжат работать.