Skip to content
ms3PromoCode
Промо-коды для MiniShop3 с гибкими правилами, генерацией по маске и интеграцией в позиции заказа
  1. Компоненты
  2. ms3PromoCode
  3. Интеграции
  4. MiniShop3

MiniShop3

ms3PromoCode — глубоко интегрированный плагин MS3. Эта страница объясняет, как именно компонент встраивается в жизненный цикл заказа и почему сделан именно так.

Учёт скидки в позициях

Главное архитектурное решение: при применении кода скидка распределяется по подпадающим позициям и записывается в msOrderProduct.price (а оригинальная цена сохраняется в properties.ms3promocode.original_price).

Что это даёт

ЧтоКак работает
Чек 54-ФЗОФД-агенты формируют чек по позициям, считывая msOrderProduct.price — суммы автоматически совпадают с оплаченной
Email-уведомленияСтандартные email-шаблоны MS3 показывают price каждой позиции — после применения кода они уценённые
Личный кабинетАналогично — без правок шаблонов покупатель видит реальные оплаченные цены
Аналитика MS3msOrder.cart_cost вычисляется как SUM(msOrderProduct.cost) — и в submit, и в finalize заказа

Альтернатива, которую мы НЕ выбрали

Можно было бы выводить скидку отдельной строкой в итогах:

Товары:           5000 ₽
Скидка SALE10:   −500 ₽
Итого:            4500 ₽

Так делают крупные маркетплейсы (Ozon, WB, Я.Маркет) — но у них своя фискализация, и расхождение между «общая сумма позиций» и «оплачено» не вызывает проблем.

Для типичного MS3-магазина такой подход потребовал бы:

  • Доработки email-шаблонов (показать строку скидки).
  • Доработки шаблонов личного кабинета.
  • Кастомизации формирования чека ОФД (отдельная позиция-скидка).

Подход «уценка позиций» решает все эти проблемы автоматически, без правки шаблонов.

Точки интеграции

События MS3, на которые подписан плагин

См. Развёрнутый список событий.

Lifecycle применения кода

1. Покупатель заходит в корзину
   └─→ Сниппет ms3PromoCodeForm рендерит SSR-форму

2. Покупатель применяет код
   └─→ POST /api/v1/promo/apply
       └─→ ApplicationService::apply()
           ├─ ValidationService::validateCode → lifecycle OK
           ├─ ValidationService::validateForOrder → min_order OK
           ├─ findMatchingItems (по rules)
           ├─ DiscountCalculator::calculate → breakdown
           ├─ applyToLineItems (уценка позиций + properties)
           ├─ saveToOrder (msOrder.properties.promo_code)
           └─ recalculateOrderTotals (cart_cost, cost)

3. Покупатель меняет состав корзины
   └─→ msOnAdd/Change/RemoveFromCart
       └─→ syncAfterCartChange
           ├─ restoreLineItems (восстановить оригиналы)
           ├─ findMatchingItems (на новом составе)
           ├─ DiscountCalculator (новый breakdown)
           └─ applyToLineItems  (или remove если стало невалидно)

4. Покупатель оформляет заказ
   └─→ msOnCreateOrder
       └─→ UsageTracker::recordApplication
           ├─ INSERT в ms3_promo_code_usages
           └─ UPDATE ms3_promo_codes.used_count + 1

5. Менеджер переводит заказ в "Отменён"
   └─→ msOnChangeOrderStatus
       └─→ UsageTracker::cancelApplication
           ├─ UPDATE usage SET cancelled_at = NOW()
           └─ UPDATE ms3_promo_codes.used_count - 1

Менеджер изменяет состав уже созданного заказа

Vue-админка MS3 не вызывает MODX-процессоры при изменении позиций (см. issue #207). Поэтому события msOnCreateOrderProduct / msOnUpdateOrderProduct / msOnRemoveOrderProduct, на которые подписан наш плагин, не срабатывают.

Решение

В order-tab.js установлен JS-перехватчик window.fetch:

  1. Перехватывает каждый успешный POST/PUT/DELETE к /api/mgr/orders/{id}/products*.
  2. До возврата response клиенту дёргает Mgr/Order/Resync процессор.
  3. Vue-админка получает ответ только после нашего await resync(...) — и затем перезапрашивает данные заказа, видя уже пересчитанные цены.

После мерджа PR в MS3 этот обходной механизм можно убрать — встроенные подписки на события заработают.

Что НЕ модифицирует ms3PromoCode

Чтобы не конфликтовать с другими плагинами и оставаться прозрачным:

  • Не модифицирует msProduct (карточка товара в каталоге остаётся нетронутой).
  • Не модифицирует msOrderProduct.options, weight, name — только price и связанные cost.
  • Не модифицирует настройки доставки и оплаты.
  • Не подписан на msOnGetProductPrice — скидки не применяются на уровне отдельного товара вне контекста корзины.
  • Не подписан на msOnGetCartCost — это бы дало двойную скидку при модели «уценка позиций».

Совместимость с версиями MS3

Версия MS3Поддержка ms3PromoCode
1.10+Полная — фронтенд, новая Vue-админка, манагерская вкладка работают
1.8 – 1.9Не тестировалось, но скорее всего работает (минорные изменения схемы)
< 1.8Не поддерживается

Для 1.10+ требуется применение PR на события msOn*OrderProduct (#207) для полноценной работы манагерского редактирования заказа без JS-перехватчика. Без PR — работает через JS-перехватчик.