Выдача оплаченных заказов через дистрибьютора
Задача
Часть товаров покупатель получает у дистрибьютора, а часть может приехать обычной доставкой. После оплаты заказ с самовывозом нельзя автоматически считать готовым к стандартной отгрузке: дистрибьютор должен найти его в своём кабинете и подтвердить фактическую выдачу. Ошибка здесь затрагивает сразу покупателя, дистрибьютора и учёт заказов: нельзя показывать чужой заказ по одному известному номеру, закрыть только часть предназначенных для выдачи позиций или отправить письмо о выдаче до изменения заказа.
Заказы хранятся на одном сайте WordPress-сети, кабинет дистрибьютора работает на другом. Эти сайты используют разные дочерние темы, поэтому сценарий должен проходить через API сайта с заказами, а не через прямой вызов классов соседней темы.
Роль и объём
Реализовал правила выдачи в WooCommerce и сценарий подтверждения между сайтами сети. На стороне заказа добавил снимок способа получения для каждой позиции, отдельное состояние после оплаты, поиск и завершение выдачи. На стороне кабинета — проверку доступа дистрибьютора, форму поиска, ограничение запросов, кэш ответа и уведомления после успешного подтверждения. Общий слой сети выполняет серверный запрос к сайту с заказами.
Ограничения
- В одном заказе могут быть позиции для выдачи и обычной доставки. Способ получения фиксируется на строке при создании заказа, чтобы последующая правка товара не меняла смысл уже оформленной покупки.
- Поиск требует номер заказа и почту плательщика. При завершении повторно передаются ID найденного заказа и та же почта; сайт с заказами снова сверяет её с заказом.
- Завершение должно охватывать весь набор позиций для выдачи. Список, присланный браузером, нельзя принимать как окончательный без сверки с заказом.
- Заказ может быть создан как обычным оформлением, так и через WooCommerce REST API. Во втором случае хук строк чекаута не вызывается, поэтому снимок способа получения нужно записать отдельно.
- Между кабинетом и сайтом с заказами есть сетевой вызов. Письма и отчёт не должны подменять фактическое состояние строк заказа.
Архитектура
Оформление заказа на сайте с WooCommerce
├── Каждая строка: выдача у дистрибьютора / доставка
└── Успешная оплата + строки для выдачи
└── Статус «ожидает выдачи»
│
▼
Кабинет дистрибьютора на другом сайте сети
├── Проверка роли и типа компании
├── Поиск: номер заказа + почта плательщика
├── Ограничение частоты и кэш найденного заказа
└── Подтверждение всех позиций для выдачи
│
▼
Серверный REST-запрос к сайту с заказами
├── Проверка почты, состояния заказа и состава строк
├── Кратковременная блокировка обработки
├── Отметка выдачи и исполнителя на строках
└── Дневной отчёт; ошибка записи — в серверный лог
│
▼
Успешный ответ → сброс кэша поиска → письма участникамСайт с заказами остаётся источником состояния выдачи. Кабинет показывает результат поиска и инициирует действие, но не записывает факт выдачи локально.
Реализация
При оформлении WooCommerce проверяет, разрешена ли выдача конкретного товара и доступен ли дистрибьютор для страны доставки. Вариация учитывает запрет, установленный у родительского товара. Для подходящих строк сохраняются тип получения и состояние ожидания; остальные строки остаются доставкой. Если заказ создаётся через REST, отдельная обработка заполняет тот же снимок. После успешной оплаты наличие строк для выдачи переводит заказ в специальный статус, в том числе при разных платёжных сценариях. Отменённые и неуспешные заказы в выдачу не переходят.
Кабинет сначала проверяет, что пользователь вошёл как представитель компании нужного типа. Поиск идёт по паре «номер заказа — почта плательщика». На сайте с заказами почта сравнивается с данными заказа, а отменённые, возвращённые и неуспешные заказы исключаются. Ошибка несовпадения не раскрывает постороннему детали заказа. Успешный ответ кэшируется на 30 минут по пользователю, номеру и нормализованной почте. Лимит в 30 поисков за минуту применяется до чтения кэша, поэтому повторные обращения тоже учитываются. Разбивка длинного списка на страницы выполняется в кабинете без нового запроса к заказам.
При подтверждении кабинет передаёт ID заказа, почту и список выбранных строк. Сайт с заказами снова проверяет почту и сравнивает список с полным набором строк для выдачи. Если все они уже помечены выданными, повтор получает отдельный отказ. Частота подтверждений ограничена 20 запросами пользователя за минуту. Для одновременных запросов предусмотрены короткие блокировки на обоих сайтах; после успешного ответа кэш найденного заказа сбрасывается. На каждой выданной строке сохраняются время, пользователь и компания, подтвердившие операцию.
После изменения заказа формируется запись в дневном CSV-отчёте. Добавление строк в файл выполняется под файловой блокировкой, чтобы параллельные выдачи не перезаписали друг друга. Только после успешного ответа сайта с заказами кабинет отправляет письма покупателю, сотруднику дистрибьютора и настроенному внутреннему списку.
Сбои и диагностика
Для поиска и подтверждения есть разные ответы на ожидаемые ситуации: заказ не найден, в нём нет позиций для выдачи, выбран не полный состав, выдача уже отмечена или операция временно занята. Неожиданные ошибки межсайтового запроса журналируются на стороне кабинета; клиенту возвращается общее сообщение без внутренних деталей.
Состояние строки заказа первично по отношению к отчёту и письмам. Если строка CSV не записалась, факт выдачи не отменяется, а в лог попадают номер заказа, исполнитель, компания, позиции и время для последующего разбора. Ошибка отправки письма тоже журналируется отдельно и не превращает состоявшуюся выдачу в неуспешную. Это позволяет отличить сбой уведомления или отчёта от самой операции.
границы решения
Кратковременные блокировки снижают вероятность двойной обработки, но не образуют транзакцию между двумя сайтами. На сайте с заказами блокировка через проверку и запись временного значения неатомарна; строгую гарантию для двух запросов, прошедших одновременно, из неё выводить нельзя. Последовательный повтор после сохранения строк отклоняется по их состоянию.
Кэш поиска может ненадолго показывать старое состояние, если заказ выдали из другого сеанса. Подтверждение не полагается на кэш: оно повторно читает заказ и его строки на сайте, где они хранятся.
Результат
Смешанный заказ сохраняет способ получения для каждой позиции, а после оплаты ожидает фактической выдачи там, где она нужна. Дистрибьютор работает через свой кабинет; окончательное решение принимается по данным заказа на другом сайте сети. Система различает повторное подтверждение, ошибку отчёта и сбой уведомления, сохраняя сведения о том, кто и когда отметил выдачу.
Стек
PHP · WordPress Multisite · WooCommerce · REST API · Transients · CSV
Есть похожая задача?
Расскажите о текущей системе и нужных изменениях — обсудим следующий шаг.
Следующий кейс: Импорт результатов голосовых кампаний в аналитическую базу