retailcrm / api-client-php

PHP client for RetailCRM API
http://www.retailcrm.ru
MIT License
60 stars 58 forks source link

Проблема формата выгрузки платежа #179

Closed fowork1 closed 10 months ago

fowork1 commented 10 months ago

Здравствуйте. Столкнулись с проблемой на сервере разработки, что перестала выгружаться информация о платежах в ЦРМ. Используем клиент версии 6.13.1 (но так же пробовали понизить до 6.12.5, результат такой же)

В логах ошибка выглядит так:

Errors in the entity format {"exception":"[object] (RetailCrm\\Api\\Exception\\Api\\ValidationException(code: 400): Errors in the entity format at /var/www/html/vendor/retailcrm/api-client-php/src/Factory/ApiExceptionFactory.php:62)
[stacktrace]
#0 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/ErrorResponseHandler.php(36): RetailCrm\\Api\\Factory\\ApiExceptionFactory->createException()
#1 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/AbstractResponseHandler.php(69): RetailCrm\\Api\\Handler\\Response\\ErrorResponseHandler->handleResponse()
#2 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/AbstractHandler.php(35): RetailCrm\\Api\\Handler\\Response\\AbstractResponseHandler->handle()
#3 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/AbstractResponseHandler.php(85): RetailCrm\\Api\\Handler\\AbstractHandler->handle()
#4 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/AccountNotFoundHandler.php(56): RetailCrm\\Api\\Handler\\Response\\AbstractResponseHandler->next()
#5 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/AbstractResponseHandler.php(69): RetailCrm\\Api\\Handler\\Response\\AccountNotFoundHandler->handleResponse()
#6 /var/www/html/vendor/retailcrm/api-client-php/src/Component/Transformer/ResponseTransformer.php(63): RetailCrm\\Api\\Handler\\Response\\AbstractResponseHandler->handle()
#7 /var/www/html/vendor/retailcrm/api-client-php/src/ResourceGroup/AbstractApiResourceGroup.php(133): RetailCrm\\Api\\Component\\Transformer\\ResponseTransformer->createResponse()
#8 /var/www/html/vendor/retailcrm/api-client-php/src/ResourceGroup/Orders.php(675): RetailCrm\\Api\\ResourceGroup\\AbstractApiResourceGroup->sendRequest()

Сам объект, который должен выгрузиться выглядит так:

"RetailCrm\Api\Model\Entity\Orders\SerializedPayment":{
      "id":null,
      "status":"paid",
      "type":"stripe",
      "externalId":1891,
      "amount":"58.90",
      "paidAt":{
         "date":"2023-11-07 15:39:41.000000",
         "timezone_type":3,
         "timezone":"UTC"
      },
      "comment":null,
      "order":{
         "id":null,
         "externalId":"4261",
         "number":null,
         "applyRound":null
      }
   }

Для выгрузки используем класс RetailCrm\Api\Model\Request\Orders\OrdersPaymentsCreateRequest и метод RetailCrm\Api\ResourceGroup\Orders::paymentsCreate

Пробовал убирать данные, оставляя только externalId и order.externalId. Результат не изменился и выглядит так же.

При этом всё то же самое (код, версия клиента, ключи и данные для выгрузки в ЦРМ) локально с моей машины работает корректно.

К сожалению, сообщение в ошибке не очень информативно. Скажите пожалуйста, в чём проблема и как её исправить?

Neur0toxine commented 10 months ago

В самом исключении есть подробности о том, с какими полями возникла проблема, но эту информацию можно получить при корректной обработке исключения (пример). Локально можно быстро определить в чем причина ошибки вот так:

try {
    // здесь код вашего запроса
} catch (ApiExceptionInterface | ClientExceptionInterface $exception) {
    echo $exception; // выведет подробности ошибки
}
fowork1 commented 10 months ago

В самом исключении есть подробности о том, с какими полями возникла проблема, но эту информацию можно получить при корректной обработке исключения (пример). Локально можно быстро определить в чем причина ошибки вот так:

try {
    // здесь код вашего запроса
} catch (ApiExceptionInterface | ClientExceptionInterface $exception) {
    echo $exception; // выведет подробности ошибки
}

Я добавил обработку классов исключений, о которых вы написали. Эта часть кода стала выглядеть так:

try {
        $retailCrmOrderPaymentRequest = $this->preparePaymentForExport->run($payment);
        $this->crmClient->orders->paymentsCreate($retailCrmOrderPaymentRequest);
        $exchangeStatus = ExchangeStatusDict::DONE;
} catch (ApiExceptionInterface | ClientExceptionInterface $e) {
        $exchangeStatus = ExchangeStatusDict::ERROR;
        Log::error(
            '[export:PaymentExportCreateAction] Ошибка создания платежа (' . $payment->id . ') в ЦРМ через API. ' . $e->getMessage(),
            ['full exception' => $e],
        );
} catch (Throwable $e) {
        $exchangeStatus = ExchangeStatusDict::ERROR;
        Log::error(
            '[export:PaymentExportCreateAction] Общая Ошибка создания платежа (' . $payment->id . ') в ЦРМ. ' . $e->getMessage(),
            ['exception' => $e],
        );
}

При проверке, информация об ошибке в логах не изменилась...


production.ERROR: [export:PaymentExportCreateAction] Ошибка создания платежа (1956) в ЦРМ через API. Errors in the entity format {"full exception":"[object] (RetailCrm\\Api\\Exception\\Api\\ValidationException(code: 400): Errors in the entity format at /var/www/html/vendor/retailcrm/api-client-php/src/Factory/ApiExceptionFactory.php:62)
[stacktrace]
#0 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/ErrorResponseHandler.php(36): RetailCrm\\Api\\Factory\\ApiExceptionFactory->createException()
#1 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/AbstractResponseHandler.php(69): RetailCrm\\Api\\Handler\\Response\\ErrorResponseHandler->handleResponse()
#2 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/AbstractHandler.php(35): RetailCrm\\Api\\Handler\\Response\\AbstractResponseHandler->handle()
#3 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/AbstractResponseHandler.php(85): RetailCrm\\Api\\Handler\\AbstractHandler->handle()
#4 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/AccountNotFoundHandler.php(56): RetailCrm\\Api\\Handler\\Response\\AbstractResponseHandler->next()
#5 /var/www/html/vendor/retailcrm/api-client-php/src/Handler/Response/AbstractResponseHandler.php(69): RetailCrm\\Api\\Handler\\Response\\AccountNotFoundHandler->handleResponse()
#6 /var/www/html/vendor/retailcrm/api-client-php/src/Component/Transformer/ResponseTransformer.php(63): RetailCrm\\Api\\Handler\\Response\\AbstractResponseHandler->handle()
#7 /var/www/html/vendor/retailcrm/api-client-php/src/ResourceGroup/AbstractApiResourceGroup.php(133): RetailCrm\\Api\\Component\\Transformer\\ResponseTransformer->createResponse()
#8 /var/www/html/vendor/retailcrm/api-client-php/src/ResourceGroup/Orders.php(675): RetailCrm\\Api\\ResourceGroup\\AbstractApiResourceGroup->sendRequest()
#9 /var/www/html/app/Containers/CrmIntegrationSection/RetailCrm/Actions/PaymentExportCreateAction.php(30): RetailCrm\\Api\\ResourceGroup\\Orders->paymentsCreate()
#10 /var/www/html/app/Containers/CrmIntegrationSection/RetailCrm/Jobs/CreatePaymentInRetailCrmJob.php(18): App\\Containers\\CrmIntegrationSection\\RetailCrm\\Actions\\PaymentExportCreateAction->run()
#11 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): App\\Containers\\CrmIntegrationSection\\RetailCrm\\Jobs\\CreatePaymentInRetailCrmJob->handle()
#12 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Util.php(41): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#13 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\\Container\\Util::unwrapIfClosure()
#14 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\\Container\\BoundMethod::callBoundMethod()
#15 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(661): Illuminate\\Container\\BoundMethod::call()
#16 /var/www/html/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(128): Illuminate\\Container\\Container->call()
#17 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Bus\\Dispatcher->Illuminate\\Bus\\{closure}()
#18 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#19 /var/www/html/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(132): Illuminate\\Pipeline\\Pipeline->then()
#20 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(124): Illuminate\\Bus\\Dispatcher->dispatchNow()
#21 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Queue\\CallQueuedHandler->Illuminate\\Queue\\{closure}()
#22 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#23 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(126): Illuminate\\Pipeline\\Pipeline->then()
#24 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(70): Illuminate\\Queue\\CallQueuedHandler->dispatchThroughMiddleware()
#25 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Jobs/Job.php(98): Illuminate\\Queue\\CallQueuedHandler->call()
#26 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(425): Illuminate\\Queue\\Jobs\\Job->fire()
#27 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(375): Illuminate\\Queue\\Worker->process()
#28 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(173): Illuminate\\Queue\\Worker->runJob()
#29 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(148): Illuminate\\Queue\\Worker->daemon()
#30 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(131): Illuminate\\Queue\\Console\\WorkCommand->runWorker()
#31 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Illuminate\\Queue\\Console\\WorkCommand->handle()
#32 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Util.php(41): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#33 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\\Container\\Util::unwrapIfClosure()
#34 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\\Container\\BoundMethod::callBoundMethod()
#35 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(661): Illuminate\\Container\\BoundMethod::call()
#36 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(183): Illuminate\\Container\\Container->call()
#37 /var/www/html/vendor/symfony/console/Command/Command.php(326): Illuminate\\Console\\Command->execute()
#38 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(153): Symfony\\Component\\Console\\Command\\Command->run()
#39 /var/www/html/vendor/symfony/console/Application.php(1063): Illuminate\\Console\\Command->run()
#40 /var/www/html/vendor/symfony/console/Application.php(320): Symfony\\Component\\Console\\Application->doRunCommand()
#41 /var/www/html/vendor/symfony/console/Application.php(174): Symfony\\Component\\Console\\Application->doRun()
#42 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Application.php(102): Symfony\\Component\\Console\\Application->run()
#43 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(155): Illuminate\\Console\\Application->run()
#44 /var/www/html/artisan(37): Illuminate\\Foundation\\Console\\Kernel->handle()
#45 {main}
"} ```
Neur0toxine commented 10 months ago

В данном вами коде обработки нет вывода информации о полях, которые не проходят валидацию на стороне API. Получить эту информацию можно обработав ошибку как указано в документации (ссылку я указывал ранее):

try {
   ...
} catch (ValidationException $exception) {
    echo 'Errors in fields:' . PHP_EOL;

    foreach ($exception->getErrorResponse()->errors as $field => $error) {
        printf(" - %s: %s\n", $field, $error);
    }

    exit(-1);
}

Этот блок catch должен быть первым. $exception->getErrorResponse()->errors в нем вы можете передавать в ваш логгер так же, как вы передаете ключ full exception.

Также вы можете временно инициализировать API-клиент следующим образом:

use RetailCrm\Api\Builder\ClientBuilder;
use RetailCrm\Api\Builder\FormEncoderBuilder;
use RetailCrm\Api\Handler\Request\HeaderAuthenticatorHandler;
use Psr\Log\AbstractLogger;

$client = (new ClientBuilder())
    ->setApiUrl('здесь URL системы')
    ->setAuthenticatorHandler(new HeaderAuthenticatorHandler('здесь API-ключ'))
    ->setFormEncoder((new FormEncoderBuilder())->build())
    ->setDebugLogger(new class extends AbstractLogger {
        public function log($level, $message, array $context = [])
        {
            printf('[%s] %s %s' . PHP_EOL, $level, $message, json_encode($context));
        }
    })
    ->build();

Инициализированный таким образом клиент выведет в stdout данные запроса и ответа. Эти данные помогут разобраться в чем проблема.

fowork1 commented 10 months ago

Да, так получилось добыть информацию об ошибке. Спасибо большое за ваш ответ )