<?php
namespace CnhProductExporter\Services\Transport;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Throwable;
class CnhApiClient
{
const GET_TOKEN_LINK = 'api-backend/Authenticate/GetToken';
const PRODUCT_UPSERT_LINK = '/api-backend/Product/CreateOrUpdateProduct';
const ORDER_STATUS_UPDATE = '/api-backend/OrderProcessing/ShipOrder';
const ORDER_CANCELLED_LINK = '/api-backend/OrderProcessing/CancelOrder/%s?notifyCustomer=false';
private ?string $token = null;
private array $pluginConfig;
/**
* @var \GuzzleHttp\Client
*/
protected Client $httpClient;
/**
* @var \Psr\Log\LoggerInterface
*/
private LoggerInterface $logger;
/**
* @param array $storeConfigs
*/
public function __construct(
SystemConfigService $pluginConfig,
LoggerInterface $logger
) {
$this->pluginConfig = $pluginConfig->get('CnhProductExporter.config');
$this->logger = $logger;
$this->httpClient = new Client(
['base_uri' => $this->getApiHost(), "headers" => ['Content-Type' => 'application/json']]
);
}
public function sendOrder(string $orderJson)
{
$this->logger->info('Cancelling order: ' . $orderJson);
return $this->call(self::ORDER_STATUS_UPDATE, [
'body' => $orderJson
], Request::METHOD_POST);
}
public function sendProduct(string $productData, string $productNumber): ?ResponseInterface
{
$this->logger->info('Sending product ' . $productNumber);
$productArray = json_decode($productData, true);
// Überprüfen Sie, ob das Produkt gelöscht werden soll
if (isset($productArray['customFields']['delete_on_chn']) && $productArray['customFields']['delete_on_chn']) {
$productArray['to_be_deleted'] = true;
} else {
$productArray['to_be_deleted'] = false;
}
$this->logger->info('Product data: ' . json_encode($productArray));
$options = [
'body' => json_encode($productArray)
];
$response = $this->call(self::PRODUCT_UPSERT_LINK, $options, Request::METHOD_POST);
return $response;
}
// Produktlöschung__________________________________________________________________________________________________
public function sendProductString(string $productData, string $productNumber): ?ResponseInterface
{
$this->logger->info('Sending product ' . $productNumber);
// Produktdaten vom JSON-String in ein Array konvertieren
$productArray = json_decode($productData, true);
// Überprüfen Sie, ob das Produkt gelöscht werden soll
if (isset($productArray['customFields']['delete_on_chn']) && $productArray['customFields']['delete_on_chn']) {
$productArray['to_be_deleted'] = true;
} else {
$productArray['to_be_deleted'] = false;
}
$options = [
'body' => json_encode($productArray)
];
$response = $this->call(self::PRODUCT_UPSERT_LINK, $options, Request::METHOD_POST);
return $response;
}
//______________________________________________________________________________________________________________________
public function call(string $uri, array $options, string $method = Request::METHOD_GET): ?ResponseInterface
{
$maxRetryCount = 3;
$currentTry = 1;
$latestError = "";
if (!$this->token) {
$this->loadToken();
}
$response = null;
while ($currentTry < $maxRetryCount) {
try {
$options = array_merge(
[
'headers' => [
'Authorization' => 'Bearer ' . $this->token,
],
],
$options
);
$response = $this->httpClient->request($method, $uri, $options);
} catch (Throwable $exception) {
if ($exception instanceof ClientException) {
$response = $exception->getResponse();
} else {
$latestError = $exception->getMessage();
$this->logger->alert(
sprintf('Catched Error. Retrying %d time out of %d ', $currentTry, $maxRetryCount - 1)
);
}
}
if ($response) {
switch ($response->getStatusCode()) {
case 200:
return $response;
case 204:
return $response;
case 401:
$currentTry++;
$this->loadToken();
break;
default:
$latestError = $response->getBody()->getContents();
}
}
$this->logger->alert(sprintf('Trying %d time out of %d ', $currentTry, $maxRetryCount - 1));
$currentTry++;
}
$this->logger->error(sprintf('Transport failed. Sent: %s Received:%s', json_encode($options), $latestError));
return $response;
}
private function loadToken(): void
{
$loginData = [
"email" => $this->getEmail(),
"password" => $this->getPassword(),
];
$result = $this->httpClient->post(self::GET_TOKEN_LINK, [
'body' => json_encode(
$loginData
)
]);
if ($result->getStatusCode() !== Response::HTTP_OK) {
$this->logger->critical(sprintf('Get Token failed: %', $result->getBody()->getContents()));
}
$res = json_decode($result->getBody()->getContents(), true);
if (!array_key_exists('token', $res)) {
$this->logger->critical('Token aquirement failed');
}
$this->token = $res['token'];
}
private function getEmail()
{
return $this->pluginConfig['apiEmail'] ?? "";
}
private function getPassword()
{
return $this->pluginConfig['apiPassword'] ?? "";
}
private function getApiHost(): string
{
return $this->pluginConfig['apiHost'] ?? "";
}
public function cancelOrder(string $orderId): ResponseInterface
{
$this->logger->info('Canceling order: ' . $orderId);
return $this->call(
sprintf(self::ORDER_CANCELLED_LINK, $orderId), []
);
}
}