Описание проблемы
При попытке связать способ оплаты со способом доставки через Vue-менеджер (вкладка «Способы оплаты» в форме доставки или вкладка «Способы доставки» в форме оплаты) API возвращает ошибку «Failed to add payment to delivery» / «Failed to add delivery to payment». Связь не сохраняется в таблице ms3_delivery_payments.
Проблема не связана с конкретным провайдером оплаты (bePaid): воспроизводится для любого нового способа оплаты. Связи из сида/миграций (прямой SQL INSERT) отображаются, но добавление новых через UI не работает.
Шаги воспроизведения
- Создать новый способ оплаты (например, «Картой в Telegram (bePaid)»).
- Открыть существующий способ доставки «Самовывоз».
- Перейти во вкладку «Способы оплаты».
- Включить новый способ оплаты ползунком.
Альтернативный путь: открыть способ оплаты → вкладка «Способы доставки» → включить доставку.
Ожидаемое поведение
Связь delivery_id ↔ payment_id сохраняется в ms3_delivery_payments, ползунок остаётся включённым, ошибка не показывается.
Фактическое поведение
Сразу после включения появляется toast с ошибкой «Failed to add payment to delivery». Ползунок возвращается в выключенное состояние. В БД новая строка не появляется.
Скриншоты
Скриншот с ошибкой в интерфейсе настроек MiniShop3 (toast «Ошибка» / «Failed to add payment to delivery»).
Окружение
- MiniShop3: 1.13.0-beta1 и актуальный
main (проверено в коде)
- MODX: 3.x
- PHP: 8.2+
- Браузер: любой (ошибка на стороне API)
Логи ошибок
Логи из core/cache/logs/error.log
При save() xPDO может писать SQL-ошибку (INSERT без PK или duplicate empty row). Типичный случай: INSERT в ms3_delivery_payments без delivery_id/payment_id.
Дополнительный контекст
Причина (root cause)
В Ms3ReferenceCrudService::addLink() при создании msDeliveryMember используется fromArray() без setPrimaryKeys = true:
$member = $this->modx->newObject(msDeliveryMember::class);
$member->fromArray($criteria); // delivery_id и payment_id не попадают в объект
if (!$member->save()) { // save() → false
return Response::error(
"Failed to add {$this->peerLabelLower()} to {$this->labelLower()}",
...
);
}
Файл: core/components/minishop3/src/Services/Reference/Ms3ReferenceCrudService.php (метод addLink, ~строки 317–324).
Для таблиц с составным первичным ключом xPDO fromArray() по умолчанию пропускает поля PK (см. комментарий и фикс в ProductLinkService::addLink() — там используется $object->set() для link, master, slave).
В том же сервисе метод replaceLinks() уже корректно использует set():
$member->set($this->config->memberOwnFk, $ownId);
$member->set($this->config->memberPeerFk, $peerId);
$member->save();
Затронутые эндпойнты
POST /api/mgr/deliveries/{id}/payments → DeliveriesController::addPayment() → addLink()
POST /api/mgr/payments/{id}/deliveries → PaymentsController::addDelivery() → addLink()
Фронт: vueManager/src/components/DeliveriesGrid.vue (togglePayment), PaymentsGrid.vue (toggleDelivery).
Предлагаемое исправление
Заменить fromArray($criteria) на явный set() (как в replaceLinks() и ProductLinkService) или вызвать fromArray($criteria, '', true).
Тест
Добавить unit/integration тест по аналогии с ProductLinkServiceCreateTest («composite PK must persist via set(), not fromArray without setPrimaryKeys»).
Описание проблемы
При попытке связать способ оплаты со способом доставки через Vue-менеджер (вкладка «Способы оплаты» в форме доставки или вкладка «Способы доставки» в форме оплаты) API возвращает ошибку «Failed to add payment to delivery» / «Failed to add delivery to payment». Связь не сохраняется в таблице
ms3_delivery_payments.Проблема не связана с конкретным провайдером оплаты (bePaid): воспроизводится для любого нового способа оплаты. Связи из сида/миграций (прямой SQL INSERT) отображаются, но добавление новых через UI не работает.
Шаги воспроизведения
Альтернативный путь: открыть способ оплаты → вкладка «Способы доставки» → включить доставку.
Ожидаемое поведение
Связь
delivery_id↔payment_idсохраняется вms3_delivery_payments, ползунок остаётся включённым, ошибка не показывается.Фактическое поведение
Сразу после включения появляется toast с ошибкой «Failed to add payment to delivery». Ползунок возвращается в выключенное состояние. В БД новая строка не появляется.
Скриншоты
Скриншот с ошибкой в интерфейсе настроек MiniShop3 (toast «Ошибка» / «Failed to add payment to delivery»).
Окружение
main(проверено в коде)Логи ошибок
Логи из core/cache/logs/error.log
Дополнительный контекст
Причина (root cause)
В
Ms3ReferenceCrudService::addLink()при созданииmsDeliveryMemberиспользуетсяfromArray()безsetPrimaryKeys = true:Файл:
core/components/minishop3/src/Services/Reference/Ms3ReferenceCrudService.php(методaddLink, ~строки 317–324).Для таблиц с составным первичным ключом xPDO
fromArray()по умолчанию пропускает поля PK (см. комментарий и фикс вProductLinkService::addLink()— там используется$object->set()дляlink,master,slave).В том же сервисе метод
replaceLinks()уже корректно используетset():Затронутые эндпойнты
POST /api/mgr/deliveries/{id}/payments→DeliveriesController::addPayment()→addLink()POST /api/mgr/payments/{id}/deliveries→PaymentsController::addDelivery()→addLink()Фронт:
vueManager/src/components/DeliveriesGrid.vue(togglePayment),PaymentsGrid.vue(toggleDelivery).Предлагаемое исправление
Заменить
fromArray($criteria)на явныйset()(как вreplaceLinks()иProductLinkService) или вызватьfromArray($criteria, '', true).Тест
Добавить unit/integration тест по аналогии с
ProductLinkServiceCreateTest(«composite PK must persist via set(), not fromArray without setPrimaryKeys»).