Skip to content

[Bug] Не удаётся связать способ оплаты со способом доставки (Failed to add payment to delivery) #628

Description

@Ibochkarev

Описание проблемы

При попытке связать способ оплаты со способом доставки через Vue-менеджер (вкладка «Способы оплаты» в форме доставки или вкладка «Способы доставки» в форме оплаты) API возвращает ошибку «Failed to add payment to delivery» / «Failed to add delivery to payment». Связь не сохраняется в таблице ms3_delivery_payments.

Проблема не связана с конкретным провайдером оплаты (bePaid): воспроизводится для любого нового способа оплаты. Связи из сида/миграций (прямой SQL INSERT) отображаются, но добавление новых через UI не работает.

Шаги воспроизведения

  1. Создать новый способ оплаты (например, «Картой в Telegram (bePaid)»).
  2. Открыть существующий способ доставки «Самовывоз».
  3. Перейти во вкладку «Способы оплаты».
  4. Включить новый способ оплаты ползунком.

Альтернативный путь: открыть способ оплаты → вкладка «Способы доставки» → включить доставку.

Ожидаемое поведение

Связь delivery_idpayment_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}/paymentsDeliveriesController::addPayment()addLink()
  • POST /api/mgr/payments/{id}/deliveriesPaymentsController::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»).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions