<?php
// KONFIGURACJA INTEGRACJI
$shopName = 'test_shop';
$apiKey = '$2y$10$XCUXFm5gcunQ.tyqzNtfJLZ80.gbQwuzO7yvETu/z/xWebOy/kywExgnQOkB.';
$domain = 'arena.pl';
$shopEngineName = 'SuperShop v8.8';
$pluginName = 'CUSTOM INTEGRATION v1.2';
// KONFIGURACJA KONKRETNEGO ŻĄDANIA
$endpoint = 'categories/search';
$requestData = [
'filters' => [
[
'field' => 'id',
'conditions' => [
['operator' => '>=', 'value' => 3],
['operator' => '<', 'value' => 300],
],
],
[
'field' => 'name',
'conditions' => [
['operator' => 'NOT IN', 'value' => ['Berety', 'Rękawiczki']],
],
],
],
'perPage' => 2,
];
$guzzle = new \GuzzleHttp\Client([
'base_uri' => 'https://' . $domain . '/api/v4/',
\GuzzleHttp\RequestOptions::HEADERS => [
'User-Agent' => "{$shopEngineName} ({$pluginName})",
'Accept' => 'application/json',
],
\GuzzleHttp\RequestOptions::AUTH => [$shopName, $apiKey],
]);
$response = $guzzle->post($endpoint, [\GuzzleHttp\RequestOptions::JSON => $requestData]);
var_dump($response->getStatusCode());
$responseData = $response->getBody()->__toString();
if ($response->getStatusCode() === 200) {
var_dump(json_decode($responseData, true));
} else {
var_dump($responseData);
}
<?php
// KONFIGURACJA INTEGRACJI
$shopName = 'test_shop';
$apiKey = '$2y$10$XCUXFm5gcunQ.tyqzNtfJLZ80.gbQwuzO7yvETu/z/xWebOy/kywExgnQOkB.';
$domain = 'arena.pl';
$shopEngineName = 'SuperShop v8.8';
$pluginName = 'CUSTOM INTEGRATION v1.2';
// KONFIGURACJA KONKRETNEGO ŻĄDANIA
$endpoint = 'categories/search';
$requestData = [
'filters' => [
[
'field' => 'id',
'conditions' => [
['operator' => '>=', 'value' => 3],
['operator' => '<', 'value' => 300],
],
],
[
'field' => 'name',
'conditions' => [
['operator' => 'NOT IN', 'value' => ['Berety', 'Rękawiczki']],
],
],
],
'perPage' => 2,
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://{$domain}/api/v4/{$endpoint}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json', 'Accept: application/json']);
curl_setopt($ch, CURLOPT_USERAGENT, "{$shopEngineName} ({$pluginName})");
curl_setopt($ch, CURLOPT_USERPWD, $shopName . ':' . $apiKey);
curl_setopt($ch, CURLOPT_POST, 1);
// for patch you'll need curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$responseData = curl_exec($ch);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
var_dump($responseCode);
if ($responseCode === 200) {
var_dump(json_decode($responseData, true));
} else {
var_dump($responseData);
}
Authorization zgodny z Basic Auth,
tak jak w przykładach.
POST /api/v4/categories/search i paginować po 100 kategorii.
W każdej kategorii są wypisane dostępne w niej atrybuty.
Każda kategoria może mieć inne atrybuty, np. `Odzież damska → Koszule` i `Odzież męska → Koszule` mają
zupełnie oddzielnie zdefiniowane rozmiary.
PATCH aby ustawić produkt jako nieaktywny.products/deactivate/{timestamp-rozpoczęcia-aktualizacji}.id grupy wariantowejvariantGroupIdPATCH) grupę wariantowąinvalidationReason wynosi NULL)
invalidationReason wynosi NULL)
auto_{id_grupy_w_sklepie_sprzedawcy},
dzięki temu powinno był łatwiej odnajdywać się podczas synchonizacji danych.
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
use GuzzleHttp\RequestOptions;
// KONFIGURACJA INTEGRACJI
$shopName = 'test_shop';
$apiKey = '$2y$10$XCUXFm5gcunQ.tyqzNtfJLZ80.gbQwuzO7yvETu/z/xWebOy/kywExgnQOkB.';
$domain = 'arena.pl';
$shopEngineName = 'SuperShop v8.8';
$pluginName = 'CUSTOM INTEGRATION v1.2';
// PRZYGOTOWANIE KLIENTA HTTP
$guzzle = new Client([
'base_uri' => 'https://' . $domain . '/api/v4/',
RequestOptions::HEADERS => [
'User-Agent' => "{$shopEngineName} ({$pluginName})",
'Accept' => 'application/json',
],
RequestOptions::AUTH => [$shopName, $apiKey],
]);
// FUNKCJA WYKONUJĄCA TRZY PRÓBY WYSŁANIA REQUESTA, GDY DOSTANIEMY ODPOWIEDŹ 5xx
function wrapApiCall(callable $func)
{
$tries = 3;
for ($i = 1; $i <= $tries; $i++) {
try {
return $func();
} catch (ServerException $e) {
if ($i === $tries) {
throw $e;
}
sleep((5 ** ($i)) * 1000);
}
}
}
// FUNKCJA TWORZĄCA GRUPĘ WARIANTOWĄ
function createVariantGroup(string $name, array $parameters, Client $guzzle): int
{
$requestSearchData = [
"filters" => [
[
"field" => "name",
"conditions" => [
[
"operator" => "=",
"value" => $name,
],
],
],
],
];
$requestData = [
"name" => $name,
"parameters" => $parameters
];
$variantGroupId = null;
$response = wrapApiCall(function () use ($guzzle, $requestSearchData) {
return $guzzle->post("variantGroups/search", [RequestOptions::JSON => $requestSearchData]);
});
if (json_decode($response->getBody(), true)['results']) {
$variantGroupId = json_decode($response->getBody(), true)['results'][0]['id'];
$response = wrapApiCall(function () use ($guzzle, $variantGroupId, $requestData) {
return $guzzle->patch("variantGroups/{$variantGroupId}", [RequestOptions::JSON => $requestData]);
});
$variantGroupId = json_decode($response->getBody()->__toString(), true)['id'];
} else {
$response = wrapApiCall(function () use ($guzzle, $requestData) {
return $guzzle->post("variantGroups", [RequestOptions::JSON => $requestData]);
});
$variantGroupId = json_decode($response->getBody()->__toString(), true)['id'];
}
var_dump("Dodanie grupy wariantowej {$name} powiodło się.");
return $variantGroupId;
}
// FUNKCJA SPRAWDZAJĄCA POPRAWNOŚĆ GRUPY WARIANTOWEJ ORAZ AKTYWUJĄCA JĄ
function enableVariantGroupAndCheckIsValid(int $variantGroupId, Client $guzzle)
{
$response = wrapApiCall(function () use ($guzzle, $variantGroupId) {
return $guzzle->patch("variantGroups/{$variantGroupId}", [RequestOptions::JSON => [
"enabled" => true
]]);
});
$responseData = json_decode($response->getBody()->__toString(), true);
$invalidationReason = $responseData['invalidationReason'];
if ($response && is_null($invalidationReason)) {
var_dump("Aktywacja grupy {$responseData['name']} powiodła się");
} else {
var_dump($invalidationReason);
}
}
// FUNKCJA DODAJĄCA PRODUKT DO GRUPY WARIANTOWEJ
function addProductToVariantGroup(array $product, Client $guzzle)
{
try {
$response = wrapApiCall(function () use ($product, $guzzle) {
return $guzzle->patch(
"products/bySellerProductId/{$product['sellerProductId']}",
[RequestOptions::JSON => $product]
);
});
} catch (ClientException $e) {
if ($e->getResponse()->getStatusCode() !== 404) {
throw $e;
}
$response = wrapApiCall(function () use ($product, $guzzle) {
return $guzzle->post("products", [RequestOptions::JSON => $product]);
});
}
$responseData = $response->getBody()->__toString();
$productId = json_decode($responseData, true)['id'];
var_dump("Dodanie produktu o id {$productId} powiodło się");
}
// STWORZENIE PRODUKTU
function createProductData(
string $name,
string $sellerProductId,
string $imgageUrl,
int $variantThumbnail,
int $attribiuteValueId,
int $variantGroupId
): array {
return [
"sellerProductId" => $sellerProductId,
"name" => $name,
"availability" => 1,
"quantity" => 100,
"price" => 1250,
"productImages" => [
[
"url" => $imgageUrl,
"isThumbnail" => true,
"position" => 0,
],
],
"categoryId" => 8503, // BODY
"attributes" => [
[
"id" => 20191, // ROZMIAR
"valueId" => $attribiuteValueId,
],
],
"variantGroupId" => $variantGroupId,
"variantThumbnail" => $variantThumbnail,
];
}
// PARAMETRY GRUPY WARIANTOWEJ
$sellerProductId = "YY";
$parameters = [
[ // GRUPOWANIE PO OBRAZKU
"type" => "Thumbnail",
"attributeId" => null,
],
[ // GRUPOWANIE PO ROZMIARZE
"type" => "Attribute",
"attributeId" => 20191,
],
];
// DODANIE GRUPY WARIANTOWEJ
$variantGroupId = createVariantGroup("auto_{$sellerProductId}", $parameters, $guzzle);
// DODANIE PRODUKTÓW DO GRUPY WARIANTOWEJ
addProductToVariantGroup(createProductData(
"Body z samochodem. Niebieskie. Rozmiar - 56",
"{$sellerProductId}_1",
"https://e-kidi.pl/13014-medium_default/nicola-body-autko-dlugi-rekaw-11610-11-b-56-68.jpg",
1, // $variantThumbnail - identyfikator po, ktorym będą łączone zdjęcia. Gdy go brak tej wartości, to jest ona nadawana automatycznie na podstawie image url.
34309, // $attribiuteValueId - id rozmiaru 56
$variantGroupId
), $guzzle);
addProductToVariantGroup(createProductData(
"Body z samochodem. Niebieskie. Rozmiar - 68",
"{$sellerProductId}_2",
"https://e-kidi.pl/13015-medium_default/nicola-body-autko-dlugi-rekaw-11610-11-b-74-86.jpg",
1, // obrazek jest inny niż poprzedni, ale przedstawia ten sam produkt (mniejszy rozmiar, ma inne zapięcie)
34313, // rozmiar 68
$variantGroupId
), $guzzle);
addProductToVariantGroup(createProductData(
"Body z samochodem. Brązowe. Rozmiar - 74",
"{$sellerProductId}_3",
"https://e-kidi.pl/13019-medium_default/nicola-body-autko-dlugi-rekaw-11610-22-b-74-86.jpg",
2,
30209, // rozmiar 74
$variantGroupId
), $guzzle);
addProductToVariantGroup(createProductData(
"Body z samochodem. Brązowe. Rozmiar - 86",
"{$sellerProductId}_4",
"https://e-kidi.pl/13019-medium_default/nicola-body-autko-dlugi-rekaw-11610-22-b-74-86.jpg",
2,
33024,
$variantGroupId
), $guzzle);
addProductToVariantGroup(createProductData(
"Body z samochodem. Brązowe. Rozmiar - 62",
"{$sellerProductId}_6",
"https://e-kidi.pl/13018-medium_default/nicola-body-autko-dlugi-rekaw-11610-22-b-56-68.jpg",
2,
34311, // rozmair 62
$variantGroupId
), $guzzle);
addProductToVariantGroup(createProductData(
"Body z samochodem. Niebieskie. Rozmiar - 62",
"{$sellerProductId}_5",
"https://e-kidi.pl/13014-medium_default/nicola-body-autko-dlugi-rekaw-11610-11-b-56-68.jpg",
1,
34311, // rozmiar 62
$variantGroupId
), $guzzle);
// SPRAWDZENIE POPRAWNIOŚCI UTWORZONEJ GRUPY WARIANTOWEJ I JEJ AKTYWACJA
enableVariantGroupAndCheckIsValid($variantGroupId, $guzzle);
widok stworzonej grupy w panelu:
widok stworzonej grupy w serwisie:
GET /api/v4/categories/{id}, tak aby wysunęły się szczegóły danej akcji.
1 w pole Category IdPOST
orders/search.
Aktualnie NIE można polegać na polu updatedAt w modelu ORDER.
Błędy o kodzie z zakresu 500-599 to błędy po stronie serwera, w przypadku ich napotkania warto kilka razy jest powtórzyć request później.
Błąd 429 Too Many Requests oznacza, że wykonano zbyt wiele zapytań do API Arena.pl lub realizacja zapytań była zbyt czasochłonna.
Wtedy należy poczekać chwilę przed wykonaniem kolejnych żądań.
Ilość dozwolonych zapytań zmienia się w zależności od obciążenia serwisu.
W przypadku prostych requestów (np. GET/PATCH pojedynczego produktu) zalecany bezpieczny limit to 15 requestów na sekundę.
Inne błędy o kodzie z zakresu 400-499 to błędy związane z nieprawidłowym zapytaniem, np. problemy z autoryzacją lub formatem przesłanych pól - nie należy ich ponawiać, trzeba najpierw rozwiązać dany problem.
Warto zobaczyć przykład z grupami wariantowymi.
PUT zostały zastąpione metodami PATCH;perPage jest pisane zawsze przy użyciu camel-case;Product pole variantGroupId
przyjmuje id grupy wariantowej z serwisu ARENA.pl,
wcześniej to był id grypy wariantowej w sklepie sprzedawcy.
/products/bySellerProductId/{sellerProductId};