Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay;
|
||||
|
||||
use ApplicationCore;
|
||||
use GuzzleHttp\Client;
|
||||
use Xentral\Core\DependencyInjection\ContainerInterface;
|
||||
use Xentral\Modules\Ebay\Client\EbayRestApiClient;
|
||||
use Xentral\Modules\Ebay\Gateway\EbayListingGateway;
|
||||
use Xentral\Modules\Ebay\Gateway\EbayRestApiGateway;
|
||||
use Xentral\Modules\Ebay\Module\EbayRestApiModule;
|
||||
use Xentral\Modules\Ebay\Service\EbayListingService;
|
||||
use Xentral\Modules\Ebay\Service\EbayListingXmlSerializer;
|
||||
use Xentral\Modules\Ebay\Service\EbayRestApiService;
|
||||
use Xentral\Modules\Ebay\Service\EbayStockLoggingService;
|
||||
use Xentral\Modules\Ebay\Wrapper\StockCalculationWrapper;
|
||||
|
||||
final class Bootstrap
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function registerServices(): array
|
||||
{
|
||||
return [
|
||||
'EbayListingGateway' => 'onInitEbayListingGateway',
|
||||
'EbayListingService' => 'onInitEbayListingService',
|
||||
'EbayRestApiModule' => 'onInitEbayRestApiModule',
|
||||
'EbayStockLoggingService' => 'onInitEbayStockLoggingService',
|
||||
'EbayRestApiGateway' => 'onInitEbayRestApiGateway',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return EbayListingService
|
||||
*/
|
||||
public static function onInitEbayListingService(ContainerInterface $container): EbayListingService
|
||||
{
|
||||
return new EbayListingService(
|
||||
$container->get('EbayListingGateway'),
|
||||
$container->get('Database'),
|
||||
new EbayListingXmlSerializer(),
|
||||
self::onInitStockCalculationWrapper($container)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return StockCalculationWrapper
|
||||
*/
|
||||
private static function onInitStockCalculationWrapper(ContainerInterface $container): StockCalculationWrapper
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new StockCalculationWrapper($app->erp, $container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return EbayStockLoggingService
|
||||
*/
|
||||
public static function onInitEbayStockLoggingService(ContainerInterface $container): EbayStockLoggingService
|
||||
{
|
||||
return new EbayStockLoggingService($container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return EbayListingGateway
|
||||
*/
|
||||
public static function onInitEbayListingGateway(ContainerInterface $container): EbayListingGateway
|
||||
{
|
||||
return new EbayListingGateway($container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return EbayRestApiModule
|
||||
*/
|
||||
public static function onInitEbayRestApiModule(ContainerInterface $container): EbayRestApiModule
|
||||
{
|
||||
return new EbayRestApiModule(
|
||||
self::onInitEbayRestApiClient(),
|
||||
self::onInitEbayRestApiGateway($container),
|
||||
self::onInitEbayRestApiService($container)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return EbayRestApiGateway
|
||||
*/
|
||||
public static function onInitEbayRestApiGateway(ContainerInterface $container): EbayRestApiGateway
|
||||
{
|
||||
return new EbayRestApiGateway($container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EbayRestApiClient
|
||||
*/
|
||||
private static function onInitEbayRestApiClient(): EbayRestApiClient
|
||||
{
|
||||
return new EbayRestApiClient(new Client());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return EbayRestApiService
|
||||
*/
|
||||
private static function onInitEbayRestApiService(ContainerInterface $container): EbayRestApiService
|
||||
{
|
||||
return new EbayRestApiService($container->get('Database'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Client;
|
||||
|
||||
use DateTime;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use Xentral\Modules\Ebay\Data\AccountCredentialsData;
|
||||
use Xentral\Modules\Ebay\Data\TokenData;
|
||||
|
||||
class EbayRestApiClient
|
||||
{
|
||||
|
||||
public const TOKEN_TYPE_APPLICATION = 'Application Access Token';
|
||||
public const TOKEN_TYPE_USER = 'User Access Token';
|
||||
public const DEFAULT_ORDER_IMPORT_LIMIT = 50;
|
||||
|
||||
protected $client;
|
||||
|
||||
public function __construct($client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountCredentialsData $accountCredentialsData
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRestApiApplicationAccessTokenFromEbay(AccountCredentialsData $accountCredentialsData): array
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Authorization' => 'Basic ' . base64_encode(
|
||||
$accountCredentialsData->getClientId() . ':' . $accountCredentialsData->getClientSecret()
|
||||
),
|
||||
];
|
||||
|
||||
$scope = ['https://api.ebay.com/oauth/api_scope'];
|
||||
$body = [
|
||||
'grant_type' => 'client_credentials',
|
||||
'scope' => implode(' ', $scope),
|
||||
];
|
||||
$request = new Request(
|
||||
'POST',
|
||||
'https://api.ebay.com/identity/v1/oauth2/token',
|
||||
$headers,
|
||||
http_build_query($body)
|
||||
);
|
||||
|
||||
$response = $this->client->send($request);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
public function getRestApiUserAccessTokenFromEbay(AccountCredentialsData $accountCredentialsData, string $code): array
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Authorization' => 'Basic ' . base64_encode(
|
||||
$accountCredentialsData->getClientId() . ':' . $accountCredentialsData->getClientSecret()
|
||||
),
|
||||
];
|
||||
$body = [
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $code,
|
||||
'redirect_uri' => $accountCredentialsData->getRedirectUrl(),
|
||||
];
|
||||
$request = new Request(
|
||||
'POST',
|
||||
'https://api.ebay.com/identity/v1/oauth2/token',
|
||||
$headers,
|
||||
http_build_query($body)
|
||||
);
|
||||
|
||||
$response = $this->client->send($request);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $siteId
|
||||
* @param int $categoryId
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCategorySpecificProperties(int $siteId, int $categoryId, string $token): array
|
||||
{
|
||||
$headers = [
|
||||
'Authorization' => 'Bearer ' . $token,
|
||||
];
|
||||
|
||||
$url = sprintf(
|
||||
'https://api.ebay.com/commerce/taxonomy/v1_beta/category_tree/%d/get_item_aspects_for_category?category_id=%d',
|
||||
$siteId,
|
||||
$categoryId
|
||||
);
|
||||
|
||||
$request = new Request(
|
||||
'GET',
|
||||
$url,
|
||||
$headers
|
||||
);
|
||||
|
||||
$response = $this->client->send($request);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
public function getOrders(string $token, DateTime $dateFrom, int $offset, ?int $limit): array
|
||||
{
|
||||
$headers = [
|
||||
'Authorization' => 'Bearer ' . $token,
|
||||
];
|
||||
$dateFromString = $dateFrom->format('Y-m-d\TH:i:s');
|
||||
|
||||
$url = 'https://api.ebay.com/sell/fulfillment/v1/order?';
|
||||
$url .= http_build_query([
|
||||
'offset' => $offset,
|
||||
'fieldGroups' => 'TAX_BREAKDOWN',
|
||||
'limit' => ($limit ?: self::DEFAULT_ORDER_IMPORT_LIMIT),
|
||||
'filter' => "lastmodifieddate:[{$dateFromString}.000Z..],orderfulfillmentstatus:{NOT_STARTED|IN_PROGRESS}",
|
||||
]);
|
||||
$request = new Request(
|
||||
'GET',
|
||||
$url,
|
||||
$headers
|
||||
);
|
||||
$response = $this->client->send($request);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
public function renewToken(AccountCredentialsData $accountCredentialsData, TokenData $tokenData): array
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Authorization' => 'Basic ' . base64_encode(
|
||||
$accountCredentialsData->getClientId() . ':' . $accountCredentialsData->getClientSecret()
|
||||
),
|
||||
];
|
||||
|
||||
$scope = ['https://api.ebay.com/oauth/api_scope'];
|
||||
if ($tokenData->getType() === self::TOKEN_TYPE_USER) {
|
||||
$scope = $this->getCompleteScope();
|
||||
}
|
||||
|
||||
$body = [
|
||||
'grant_type' => 'refresh_token',
|
||||
'scope' => implode(' ', $scope),
|
||||
'refresh_token' => $tokenData->getRefreshToken(),
|
||||
];
|
||||
$request = new Request(
|
||||
'POST',
|
||||
'https://api.ebay.com/identity/v1/oauth2/token',
|
||||
$headers,
|
||||
http_build_query($body)
|
||||
);
|
||||
|
||||
$response = $this->client->send($request);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
public function getCompleteScope(): array
|
||||
{
|
||||
return [
|
||||
'https://api.ebay.com/oauth/api_scope',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.marketing.readonly',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.marketing',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.inventory.readonly',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.inventory',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.account.readonly',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.account',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.fulfillment',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.analytics.readonly',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.finances',
|
||||
'https://api.ebay.com/oauth/api_scope/sell.payment.dispute',
|
||||
'https://api.ebay.com/oauth/api_scope/commerce.identity.readonly',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Data;
|
||||
|
||||
final class AccountCredentialsData
|
||||
{
|
||||
/** @var string */
|
||||
private $clientId;
|
||||
/** @var string */
|
||||
private $clientSecret;
|
||||
/** @var string */
|
||||
private $redirectUrl;
|
||||
|
||||
/**
|
||||
* AccountCredentialsData constructor.
|
||||
*
|
||||
* @param string $clientId
|
||||
* @param string $clientSecret
|
||||
* @param string $redirectUrl
|
||||
*/
|
||||
public function __construct(string $clientId, string $clientSecret, string $redirectUrl)
|
||||
{
|
||||
$this->clientId = $clientId;
|
||||
$this->clientSecret = $clientSecret;
|
||||
$this->redirectUrl = $redirectUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClientId(): string
|
||||
{
|
||||
return $this->clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $clientId
|
||||
*
|
||||
* @return AccountCredentialsData
|
||||
*/
|
||||
public function setClientId(string $clientId): AccountCredentialsData
|
||||
{
|
||||
$this->clientId = $clientId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClientSecret(): string
|
||||
{
|
||||
return $this->clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $clientSecret
|
||||
*
|
||||
* @return AccountCredentialsData
|
||||
*/
|
||||
public function setClientSecret(string $clientSecret): AccountCredentialsData
|
||||
{
|
||||
$this->clientSecret = $clientSecret;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUrl(): string
|
||||
{
|
||||
return $this->redirectUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $redirectUrl
|
||||
*
|
||||
* @return AccountCredentialsData
|
||||
*/
|
||||
public function setRedirectUrl(string $redirectUrl): AccountCredentialsData
|
||||
{
|
||||
$this->redirectUrl = $redirectUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,724 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Data;
|
||||
|
||||
use Xentral\Modules\Ebay\Exception\InvalidArgumentException;
|
||||
|
||||
final class StagingListingData
|
||||
{
|
||||
/** @var int $id */
|
||||
private $id;
|
||||
|
||||
/** @var int $articleId */
|
||||
private $articleId = 0;
|
||||
|
||||
/** @var string $type */
|
||||
private $type = '';
|
||||
|
||||
/** @var string $status */
|
||||
private $status = '';
|
||||
|
||||
/** @var string $sku */
|
||||
private $sku = '';
|
||||
|
||||
/** @var string $title */
|
||||
private $title = '';
|
||||
|
||||
/** @var string $description */
|
||||
private $description = '';
|
||||
|
||||
/** @var string $primaryCategoryId */
|
||||
private $primaryCategoryId = '';
|
||||
|
||||
/** @var string $secondaryCategoryId */
|
||||
private $secondaryCategoryId = '';
|
||||
|
||||
/** @var string $primaryStoreCategoryId */
|
||||
private $primaryStoreCategoryId = '';
|
||||
|
||||
/** @var string $secondaryStoreCategoryId */
|
||||
private $secondaryStoreCategoryId = '';
|
||||
|
||||
/** @var string $shippingProfileId */
|
||||
private $shippingProfileId = '';
|
||||
|
||||
/** @var string $returnProfileId */
|
||||
private $returnProfileId = '';
|
||||
|
||||
/** @var string $paymentProfileId */
|
||||
private $paymentProfileId = '';
|
||||
|
||||
/** @var string $deliveryTime */
|
||||
private $deliveryTime = '';
|
||||
|
||||
/** @var string $itemId */
|
||||
private $itemId = '';
|
||||
|
||||
/** @var string $inventoryTrackingMethod */
|
||||
private $inventoryTrackingMethod = '';
|
||||
|
||||
/** @var string $conditionId */
|
||||
private $conditionId = '0';
|
||||
|
||||
/** @var string $conditionDisplayName */
|
||||
private $conditionDisplayName = '';
|
||||
|
||||
/** @var string $conditionDescription */
|
||||
private $conditionDescription = '';
|
||||
|
||||
/** @var string $listingDuration */
|
||||
private $listingDuration = '';
|
||||
|
||||
/** @var bool $ebayPlus */
|
||||
private $ebayPlus = false;
|
||||
|
||||
/** @var bool $privateListing */
|
||||
private $privateListing = false;
|
||||
|
||||
/** @var bool $priceSuggestion */
|
||||
private $priceSuggestion = false;
|
||||
|
||||
/** @var int $shopId */
|
||||
private $shopId;
|
||||
|
||||
/** @var int $templateId */
|
||||
private $templateId = 0;
|
||||
|
||||
/** @var array $variations */
|
||||
private $variations = [];
|
||||
|
||||
/** @var array $specifics */
|
||||
private $specifics = [];
|
||||
|
||||
/** @var array $pictures */
|
||||
private $pictures = [];
|
||||
|
||||
/**
|
||||
* StagingListing constructor.
|
||||
*
|
||||
* @param int $shopId
|
||||
* @param int $databaseId
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($shopId, $databaseId = 0)
|
||||
{
|
||||
if (empty($shopId)) {
|
||||
throw new InvalidArgumentException('Required argument "shopId" is empty.');
|
||||
}
|
||||
$this->shopId = (int)$shopId;
|
||||
$this->id = $databaseId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return StagingListingData
|
||||
*/
|
||||
public static function fromDbState($data): StagingListingData
|
||||
{
|
||||
$stagingListing = new StagingListingData($data['shop_id'], $data['id']);
|
||||
|
||||
$stagingListing->setArticleId($data['article_id']);
|
||||
$stagingListing->setType($data['type']);
|
||||
$stagingListing->setTitle($data['title']);
|
||||
$stagingListing->setStatus($data['status']);
|
||||
$stagingListing->setSku($data['sku']);
|
||||
$stagingListing->setDescription($data['description']);
|
||||
$stagingListing->setPrimaryCategoryId($data['ebay_primary_category_id_external']);
|
||||
$stagingListing->setSecondaryCategoryId($data['ebay_secondary_category_id_external']);
|
||||
$stagingListing->setShippingProfileId($data['ebay_shipping_profile_id_external']);
|
||||
$stagingListing->setPaymentProfileId($data['ebay_payment_profile_id_external']);
|
||||
$stagingListing->setReturnProfileId($data['ebay_return_profile_id_external']);
|
||||
$stagingListing->setPrivateListing(!empty($data['ebay_private_listing']));
|
||||
$stagingListing->setDeliveryTime($data['delivery_time']);
|
||||
$stagingListing->setInventoryTrackingMethod($data['inventory_tracking_method']);
|
||||
$stagingListing->setConditionId($data['condition_id_external']);
|
||||
$stagingListing->setConditionDisplayName($data['condition_display_name']);
|
||||
$stagingListing->setConditionDescription($data['condition_description']);
|
||||
$stagingListing->setListingDuration($data['listing_duration']);
|
||||
$stagingListing->setDeliveryTime($data['delivery_time']);
|
||||
$stagingListing->setEbayPlus((bool)$data['ebay_plus']);
|
||||
$stagingListing->setPriceSuggestion((bool)$data['ebay_price_suggestion']);
|
||||
$stagingListing->setItemId($data['item_id_external']);
|
||||
$stagingListing->setTemplateId((int)$data['template_id']);
|
||||
|
||||
return $stagingListing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $description
|
||||
*
|
||||
*/
|
||||
public function setDescription($description): void
|
||||
{
|
||||
$this->description = (string)$description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getShopId(): int
|
||||
{
|
||||
return $this->shopId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function listSpecifics(): array
|
||||
{
|
||||
return $this->specifics;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $specifics
|
||||
*/
|
||||
public function setSpecifics($specifics): void
|
||||
{
|
||||
$this->specifics = $specifics;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $specificName
|
||||
* @param string $specificValue
|
||||
*/
|
||||
public function addSpecific($specificName, $specificValue = ''): void
|
||||
{
|
||||
if (!empty($specificName)) {
|
||||
$this->specifics[$specificName] = $specificValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function listPictures(): array
|
||||
{
|
||||
return $this->pictures;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param StagingListingPicture $picture
|
||||
*/
|
||||
public function addPicture(StagingListingPicture $picture): void
|
||||
{
|
||||
$pictureExists = false;
|
||||
foreach ($this->pictures as $existingPicture) {
|
||||
if ($existingPicture->getUrl() === $picture->getUrl()) {
|
||||
$pictureExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$pictureExists) {
|
||||
$this->pictures[] = $picture;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPrimaryStoreCategoryId(): string
|
||||
{
|
||||
return $this->primaryStoreCategoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $primaryStoreCategoryId
|
||||
*/
|
||||
public function setPrimaryStoreCategoryId($primaryStoreCategoryId): void
|
||||
{
|
||||
$this->primaryStoreCategoryId = $primaryStoreCategoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSecondaryStoreCategoryId(): string
|
||||
{
|
||||
return $this->secondaryStoreCategoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $secondaryStoreCategoryId
|
||||
*/
|
||||
public function setSecondaryStoreCategoryId($secondaryStoreCategoryId): void
|
||||
{
|
||||
$this->secondaryStoreCategoryId = $secondaryStoreCategoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StagingListingVariationData $variation
|
||||
*/
|
||||
public function addVariation($variation): void
|
||||
{
|
||||
if (empty($variation->listSpecifics())) {
|
||||
return;
|
||||
}
|
||||
|
||||
$variationExists = false;
|
||||
foreach ($this->variations as $existingVariation) {
|
||||
$existingSpecifics = $existingVariation->listSpecifics();
|
||||
$variationExists = $this->identicalVariationExistsWithinListing($variation, $existingSpecifics);
|
||||
if ($variationExists) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$variationExists) {
|
||||
$this->variations[] = $variation;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StagingListingVariationData $variation
|
||||
* @param array $existingSpecifics
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function identicalVariationExistsWithinListing($variation, $existingSpecifics): bool
|
||||
{
|
||||
$variationExists = false;
|
||||
foreach ($variation->listSpecifics() as $propertyToCheck => $valueToCheck) {
|
||||
$variationExists = false;
|
||||
if (isset($existingSpecifics[$propertyToCheck]) && $existingSpecifics[$propertyToCheck] === $valueToCheck) {
|
||||
$variationExists = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $variationExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getVariations(): array
|
||||
{
|
||||
return $this->variations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $variations
|
||||
*/
|
||||
public function setVariations($variations): void
|
||||
{
|
||||
$this->variations = $variations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'article_id' => $this->getArticleId(),
|
||||
'type' => $this->getType(),
|
||||
'title' => $this->getTitle(),
|
||||
'status' => $this->getStatus(),
|
||||
'sku' => $this->getSku(),
|
||||
'ebay_primary_category_id_external' => $this->getPrimaryCategoryId(),
|
||||
'ebay_secondary_category_id_external' => $this->getSecondaryCategoryId(),
|
||||
'ebay_shipping_profile_id_external' => $this->getShippingProfileId(),
|
||||
'ebay_payment_profile_id_external' => $this->getPaymentProfileId(),
|
||||
'ebay_return_profile_id_external' => $this->getReturnProfileId(),
|
||||
'item_id_external' => $this->getItemId(),
|
||||
'delivery_time' => $this->getDeliveryTime(),
|
||||
'inventory_tracking_method' => $this->getInventoryTrackingMethod(),
|
||||
'condition_id_external' => $this->getConditionId(),
|
||||
'condition_display_name' => $this->getConditionDisplayName(),
|
||||
'condition_description' => $this->getConditionDescription(),
|
||||
'listing_duration' => $this->getListingDuration(),
|
||||
'ebay_plus' => $this->isEbayPlus(),
|
||||
'ebay_price_suggestion' => $this->isPriceSuggestion(),
|
||||
'ebay_private_listing' => $this->isPrivateListing(),
|
||||
'variations' => $this->getVariationsAsArray(),
|
||||
'template_id' => $this->getTemplateId(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getArticleId(): int
|
||||
{
|
||||
return $this->articleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
*/
|
||||
public function setArticleId($articleId): void
|
||||
{
|
||||
$this->articleId = (int)$articleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*/
|
||||
public function setType($type): void
|
||||
{
|
||||
$this->type = (string)$type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
*/
|
||||
public function setTitle($title): void
|
||||
{
|
||||
$this->title = (string)$title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getStatus(): string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $status
|
||||
*/
|
||||
public function setStatus($status): void
|
||||
{
|
||||
$this->status = (string)$status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSku(): string
|
||||
{
|
||||
return $this->sku;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sku
|
||||
*/
|
||||
public function setSku($sku): void
|
||||
{
|
||||
$this->sku = (string)$sku;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPrimaryCategoryId(): string
|
||||
{
|
||||
return $this->primaryCategoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $primaryCategoryId
|
||||
*/
|
||||
public function setPrimaryCategoryId($primaryCategoryId): void
|
||||
{
|
||||
$this->primaryCategoryId = (string)$primaryCategoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSecondaryCategoryId(): string
|
||||
{
|
||||
return $this->secondaryCategoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $secondaryCategoryId
|
||||
*/
|
||||
public function setSecondaryCategoryId($secondaryCategoryId): void
|
||||
{
|
||||
$this->secondaryCategoryId = (string)$secondaryCategoryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getShippingProfileId(): string
|
||||
{
|
||||
return $this->shippingProfileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $shippingProfileId
|
||||
*/
|
||||
public function setShippingProfileId($shippingProfileId): void
|
||||
{
|
||||
$this->shippingProfileId = (string)$shippingProfileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPaymentProfileId(): string
|
||||
{
|
||||
return $this->paymentProfileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $paymentProfileId
|
||||
*/
|
||||
public function setPaymentProfileId($paymentProfileId): void
|
||||
{
|
||||
$this->paymentProfileId = (string)$paymentProfileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getReturnProfileId(): string
|
||||
{
|
||||
return $this->returnProfileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $returnProfileId
|
||||
*/
|
||||
public function setReturnProfileId($returnProfileId): void
|
||||
{
|
||||
$this->returnProfileId = (string)$returnProfileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getItemId(): string
|
||||
{
|
||||
return $this->itemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $itemId
|
||||
*/
|
||||
public function setItemId($itemId): void
|
||||
{
|
||||
$this->itemId = (string)$itemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDeliveryTime(): string
|
||||
{
|
||||
return $this->deliveryTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $deliveryTime
|
||||
*/
|
||||
public function setDeliveryTime($deliveryTime): void
|
||||
{
|
||||
$this->deliveryTime = $deliveryTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getInventoryTrackingMethod(): string
|
||||
{
|
||||
return $this->inventoryTrackingMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $inventoryTrackingMethod
|
||||
*/
|
||||
public function setInventoryTrackingMethod($inventoryTrackingMethod): void
|
||||
{
|
||||
$this->inventoryTrackingMethod = $inventoryTrackingMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getConditionId(): string
|
||||
{
|
||||
return $this->conditionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $conditionId
|
||||
*/
|
||||
public function setConditionId(string $conditionId): void
|
||||
{
|
||||
$this->conditionId = $conditionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getConditionDisplayName(): string
|
||||
{
|
||||
return $this->conditionDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $conditionDisplayName
|
||||
*/
|
||||
public function setConditionDisplayName($conditionDisplayName): void
|
||||
{
|
||||
$this->conditionDisplayName = $conditionDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getConditionDescription(): string
|
||||
{
|
||||
return $this->conditionDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $conditionDescription
|
||||
*/
|
||||
public function setConditionDescription($conditionDescription): void
|
||||
{
|
||||
$this->conditionDescription = $conditionDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getListingDuration(): string
|
||||
{
|
||||
return $this->listingDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $listingDuration
|
||||
*/
|
||||
public function setListingDuration($listingDuration): void
|
||||
{
|
||||
$this->listingDuration = $listingDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isEbayPlus(): bool
|
||||
{
|
||||
return $this->ebayPlus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $ebayPlus
|
||||
*/
|
||||
public function setEbayPlus($ebayPlus): void
|
||||
{
|
||||
$this->ebayPlus = $ebayPlus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isPriceSuggestion(): bool
|
||||
{
|
||||
return $this->priceSuggestion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $priceSuggestion
|
||||
*/
|
||||
public function setPriceSuggestion($priceSuggestion): void
|
||||
{
|
||||
$this->priceSuggestion = $priceSuggestion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isPrivateListing(): bool
|
||||
{
|
||||
return $this->privateListing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $privateListing
|
||||
*/
|
||||
public function setPrivateListing(bool $privateListing): void
|
||||
{
|
||||
$this->privateListing = $privateListing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getVariationsAsArray(): array
|
||||
{
|
||||
$variations = [];
|
||||
foreach ($this->variations as $variation) {
|
||||
$variations[] = $variation->toArray();
|
||||
}
|
||||
|
||||
return $variations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTemplateId(): int
|
||||
{
|
||||
return $this->templateId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $templateId
|
||||
*/
|
||||
public function setTemplateId($templateId): void
|
||||
{
|
||||
$this->templateId = $templateId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function validate(): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
if ($this->shopId <= 0) {
|
||||
$errors['shop_id'][] = 'The "shopId" property must be greater than zero.';
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Data;
|
||||
|
||||
class StagingListingPicture
|
||||
{
|
||||
/**@var int $id */
|
||||
private $id;
|
||||
|
||||
/**@var int $stagingListingVariantId */
|
||||
private $stagingListingVariantId = 0;
|
||||
|
||||
/** @var int $fileId */
|
||||
private $fileId = 0;
|
||||
|
||||
/** @var int $stagingListingId */
|
||||
private $stagingListingId = 0;
|
||||
|
||||
/** @var string $url */
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*/
|
||||
public function __construct($url)
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getFileId(): int
|
||||
{
|
||||
return $this->fileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fileId
|
||||
*/
|
||||
public function setFileId(int $fileId): void
|
||||
{
|
||||
$this->fileId = $fileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getStagingListingId(): int
|
||||
{
|
||||
return $this->stagingListingId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $stagingListingId
|
||||
*/
|
||||
public function setStagingListingId(int $stagingListingId): void
|
||||
{
|
||||
$this->stagingListingId = $stagingListingId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getStagingListingVariantId(): int
|
||||
{
|
||||
return $this->stagingListingVariantId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $stagingListingVariantId
|
||||
*/
|
||||
public function setStagingListingVariantId(int $stagingListingVariantId): void
|
||||
{
|
||||
$this->stagingListingVariantId = $stagingListingVariantId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl(): string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*/
|
||||
public function setUrl(string $url): void
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Data;
|
||||
|
||||
final class StagingListingVariationData
|
||||
{
|
||||
/** @var int $articleId */
|
||||
private $articleId = 0;
|
||||
|
||||
/** @var string $sku */
|
||||
private $sku = '';
|
||||
|
||||
/** @var array $specifics */
|
||||
private $specifics = [];
|
||||
|
||||
/** @var array $pictures */
|
||||
private $pictures = [];
|
||||
|
||||
/** @var int $id */
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*/
|
||||
public function __construct(int $id = 0)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $specifics
|
||||
*
|
||||
* @return StagingListingVariationData
|
||||
*/
|
||||
public static function fromArray($data, $specifics): StagingListingVariationData
|
||||
{
|
||||
$stagingListing = new StagingListingVariationData($data['id']);
|
||||
|
||||
$stagingListing->setSku($data['sku']);
|
||||
$stagingListing->setSpecifics($specifics);
|
||||
$stagingListing->setArticleId($data['article_id']);
|
||||
|
||||
return $stagingListing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $specifics
|
||||
*/
|
||||
public function setSpecifics($specifics): void
|
||||
{
|
||||
$this->specifics = $specifics;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $property
|
||||
* @param string $value
|
||||
*/
|
||||
public function addSpecifics($property, $value): void
|
||||
{
|
||||
$this->specifics[$property] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'article_id' => $this->getArticleId(),
|
||||
'sku' => $this->getSku(),
|
||||
'specifics' => $this->listSpecifics(),
|
||||
'pictures' => $this->listPictures(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getArticleId(): int
|
||||
{
|
||||
return $this->articleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
*/
|
||||
public function setArticleId($articleId): void
|
||||
{
|
||||
$this->articleId = (int)$articleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSku(): string
|
||||
{
|
||||
return $this->sku;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sku
|
||||
*/
|
||||
public function setSku($sku): void
|
||||
{
|
||||
$this->sku = (string)$sku;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function listSpecifics(): array
|
||||
{
|
||||
return $this->specifics;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function listPictures(): array
|
||||
{
|
||||
return $this->pictures;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StagingListingPicture $picture
|
||||
*/
|
||||
public function addPicture(StagingListingPicture $picture): void
|
||||
{
|
||||
$pictureExists = false;
|
||||
foreach ($this->pictures as $existingPicture) {
|
||||
if ($existingPicture->getUrl() === $picture->getUrl()) {
|
||||
$pictureExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$pictureExists) {
|
||||
$this->pictures[] = $picture;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Ebay\Data;
|
||||
|
||||
class StockLoggingData
|
||||
{
|
||||
|
||||
/** @var string */
|
||||
protected $itemId;
|
||||
/** @var string */
|
||||
protected $sku;
|
||||
/** @var int */
|
||||
protected $quantity;
|
||||
/** @var string */
|
||||
protected $status;
|
||||
/** @var StockLogingVariationData[] */
|
||||
protected $variations = [];
|
||||
/** @var string[] */
|
||||
protected $errorMessages = [];
|
||||
|
||||
public function __construct(string $itemId)
|
||||
{
|
||||
$this->itemId = $itemId;
|
||||
}
|
||||
|
||||
public function getItemId(): string
|
||||
{
|
||||
return $this->itemId;
|
||||
}
|
||||
|
||||
public function setItemId(string $itemId): StockLoggingData
|
||||
{
|
||||
$this->itemId = $itemId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSku(): string
|
||||
{
|
||||
return $this->sku;
|
||||
}
|
||||
|
||||
public function setSku(string $sku): StockLoggingData
|
||||
{
|
||||
$this->sku = $sku;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getQuantity(): ?int
|
||||
{
|
||||
return $this->quantity;
|
||||
}
|
||||
|
||||
public function setQuantity(int $quantity): StockLoggingData
|
||||
{
|
||||
$this->quantity = $quantity;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStatus(): string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function setStatus(string $status): StockLoggingData
|
||||
{
|
||||
$this->status = $status;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVariations(): array
|
||||
{
|
||||
return $this->variations;
|
||||
}
|
||||
|
||||
public function setVariations(array $variations): StockLoggingData
|
||||
{
|
||||
$this->variations = $variations;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addVariation(StockLogingVariationData $variation): StockLoggingData
|
||||
{
|
||||
$this->variations[$variation->getSku()] = $variation;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasVariations(): bool
|
||||
{
|
||||
return !empty($this->variations);
|
||||
}
|
||||
|
||||
public function getVariation(string $sku): StockLoggingVariationData
|
||||
{
|
||||
return $this->variations[$sku];
|
||||
}
|
||||
|
||||
public function getErrorMessages(): array
|
||||
{
|
||||
return $this->errorMessages;
|
||||
}
|
||||
|
||||
public function setErrorMessages(array $errorMessages): StockLoggingData
|
||||
{
|
||||
$this->errorMessages = $errorMessages;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasErrorMessages(): bool
|
||||
{
|
||||
return !empty($this->errorMessages);
|
||||
}
|
||||
|
||||
public function addErrorMessage(string $type, string $errorMessage): StockLoggingData
|
||||
{
|
||||
$this->errorMessages[$errorMessage] = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Ebay\Data;
|
||||
|
||||
class StockLogingVariationData
|
||||
{
|
||||
|
||||
/** @var string */
|
||||
protected $sku;
|
||||
/** @var int */
|
||||
protected $quantity;
|
||||
|
||||
public function __construct(string $sku, int $quantity)
|
||||
{
|
||||
$this->sku = $sku;
|
||||
$this->quantity = $quantity;
|
||||
}
|
||||
|
||||
public function getSku(): string
|
||||
{
|
||||
return $this->sku;
|
||||
}
|
||||
|
||||
public function setSku(string $sku): StockLogingVariationData
|
||||
{
|
||||
$this->sku = $sku;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getQuantity(): int
|
||||
{
|
||||
return $this->quantity;
|
||||
}
|
||||
|
||||
public function setQuantity(int $quantity): StockLogingVariationData
|
||||
{
|
||||
$this->quantity = $quantity;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Data;
|
||||
|
||||
final class TokenData
|
||||
{
|
||||
/** @var string */
|
||||
protected $token;
|
||||
/** @var string */
|
||||
protected $refreshToken;
|
||||
/** @var string */
|
||||
protected $type;
|
||||
/** @var bool */
|
||||
protected $valid;
|
||||
|
||||
/**
|
||||
* TokenData constructor.
|
||||
*
|
||||
* @param string $token
|
||||
* @param string $refreshToken
|
||||
* @param string $type
|
||||
* @param bool $valid
|
||||
*/
|
||||
public function __construct(string $token, string $refreshToken, string $type, bool $valid)
|
||||
{
|
||||
$this->token = $token;
|
||||
$this->refreshToken = $refreshToken;
|
||||
$this->type = $type;
|
||||
$this->valid = $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getToken(): string
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
*
|
||||
* @return TokenData
|
||||
*/
|
||||
public function setToken(string $token): TokenData
|
||||
{
|
||||
$this->token = $token;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRefreshToken(): string
|
||||
{
|
||||
return $this->refreshToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @return TokenData
|
||||
*/
|
||||
public function setRefreshToken(string $refreshToken): TokenData
|
||||
{
|
||||
$this->refreshToken = $refreshToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return TokenData
|
||||
*/
|
||||
public function setType(string $type): TokenData
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid(): bool
|
||||
{
|
||||
return $this->valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $valid
|
||||
*
|
||||
* @return TokenData
|
||||
*/
|
||||
public function setValid(bool $valid): TokenData
|
||||
{
|
||||
$this->valid = $valid;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Ebay\Exception;
|
||||
|
||||
use Xentral\Core\Exception\ModuleExceptionInterface;
|
||||
|
||||
interface EbayExceptionInterface extends ModuleExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Ebay\Exception;
|
||||
|
||||
use InvalidArgumentException as SplInvalidArgumentException;
|
||||
|
||||
class InvalidArgumentException extends SplInvalidArgumentException implements EbayExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Ebay\Exception;
|
||||
|
||||
use UnexpectedValueException as SplUnexpectedValueException;
|
||||
|
||||
class MissingValueException extends SplUnexpectedValueException implements EbayExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Ebay\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
final class ValidationFailedException extends RuntimeException implements EbayExceptionInterface
|
||||
{
|
||||
/** @var array $errors */
|
||||
private $errors = [];
|
||||
|
||||
/**
|
||||
* @param array $errors
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromErrors(array $errors): self
|
||||
{
|
||||
$errorString = '';
|
||||
foreach ($errors as $propertyName => $propertyErrors) {
|
||||
$errorString .= implode("\r\n", $propertyErrors);
|
||||
}
|
||||
|
||||
$exception = new self('Validation failed with following errors: ' . "\n\n" . $errorString);
|
||||
$exception->errors = $errors;
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Ebay\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
class ValueNotFoundException extends SplRuntimeException implements EbayExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Gateway;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Ebay\Data\StagingListingData;
|
||||
use Xentral\Modules\Ebay\Data\StagingListingVariationData;
|
||||
use Xentral\Modules\Ebay\Exception\InvalidArgumentException;
|
||||
use Xentral\Modules\Ebay\Exception\ValidationFailedException;
|
||||
|
||||
final class EbayListingGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $database
|
||||
*/
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->db = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $itemId
|
||||
*
|
||||
* @throws ValidationFailedException
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function tryGetStagingListingIdByItemId($itemId): int
|
||||
{
|
||||
$sql = 'SELECT e.*
|
||||
FROM `ebay_staging_listing` AS `e`
|
||||
WHERE e.item_id_external = :item_id';
|
||||
$values = ['item_id' => $itemId];
|
||||
$stagingListingData = $this->db->fetchRow($sql, $values);
|
||||
|
||||
if (empty($stagingListingData)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $stagingListingData['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws ValidationFailedException
|
||||
*
|
||||
* @return StagingListingData
|
||||
*/
|
||||
public function getStagingListingByDatabaseId(int $id): StagingListingData
|
||||
{
|
||||
$sql = 'SELECT e.*
|
||||
FROM `ebay_staging_listing` AS `e`
|
||||
WHERE e.id = :listing_id';
|
||||
$values = ['listing_id' => $id];
|
||||
$stagingListingData = $this->db->fetchRow($sql, $values);
|
||||
|
||||
if (empty($stagingListingData)) {
|
||||
throw new InvalidArgumentException('Required argument "id" is empty or invalid.');
|
||||
}
|
||||
$stagingListing = StagingListingData::fromDbState($stagingListingData);
|
||||
$stagingListing->setVariations($this->getStagingListingVariations($stagingListing->getId()));
|
||||
|
||||
$validationErrors = $stagingListing->validate();
|
||||
if (!empty($validationErrors)) {
|
||||
throw ValidationFailedException::fromErrors($validationErrors);
|
||||
}
|
||||
|
||||
return $stagingListing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $stagingListingId
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @return array
|
||||
*/
|
||||
protected function getStagingListingVariations(int $stagingListingId): array
|
||||
{
|
||||
if (empty($stagingListingId)) {
|
||||
throw new InvalidArgumentException('Required argument "stagingListingId" is empty or invalid.');
|
||||
}
|
||||
|
||||
$variations = [];
|
||||
$sql = 'SELECT e.id, e.sku, e.ebay_staging_listing_id, e.article_id
|
||||
FROM `ebay_staging_listing_variant` AS `e`
|
||||
WHERE e.ebay_staging_listing_id = :listing_id';
|
||||
$values = ['listing_id' => $stagingListingId];
|
||||
$stagingListingVariations = $this->db->fetchAll($sql, $values);
|
||||
|
||||
if (empty($stagingListingVariations)) {
|
||||
return $variations;
|
||||
}
|
||||
|
||||
foreach ($stagingListingVariations as $variation) {
|
||||
$sql = 'SELECT e.property, e.value
|
||||
FROM ebay_staging_listing_variant_specific AS `e`
|
||||
WHERE e.ebay_staging_listing_variant_id = :variation_id';
|
||||
$values = ['variation_id' => $variation['id']];
|
||||
$allSpecificsInDatabase = $this->db->fetchAll($sql, $values);
|
||||
|
||||
$specifics = [];
|
||||
foreach ($allSpecificsInDatabase as $specificsInDatabase) {
|
||||
$specifics[$specificsInDatabase['property']] = $specificsInDatabase['value'];
|
||||
}
|
||||
$stagingListingVariation = StagingListingVariationData::fromArray($variation, $specifics);
|
||||
$variations[] = $stagingListingVariation;
|
||||
}
|
||||
|
||||
return $variations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPaymentBusinessPolicies($shopId): array
|
||||
{
|
||||
return $this->findBusinessPolicies($shopId, 'PAYMENT');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopId
|
||||
* @param string $type
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function findBusinessPolicies($shopId, $type): array
|
||||
{
|
||||
if (empty($shopId)) {
|
||||
throw new InvalidArgumentException('Required argument "shopId" is empty or invalid.');
|
||||
}
|
||||
if (empty($type)) {
|
||||
throw new InvalidArgumentException('Required argument "type" is empty.');
|
||||
}
|
||||
|
||||
$sql = 'SELECT
|
||||
e.id, e.aktiv AS active, e.profilid AS profile_id_external,
|
||||
e.profilname AS profile_name, e.profilsummary AS profile_summary
|
||||
FROM ebay_rahmenbedingungen AS `e`
|
||||
WHERE e.shop=:shopid AND e.profiltype=:profiltype';
|
||||
$values = [
|
||||
'shopid' => $shopId,
|
||||
'profiltype' => $type,
|
||||
];
|
||||
|
||||
return $this->db->fetchAll($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getShippingBusinessPolicies($shopId): array
|
||||
{
|
||||
return $this->findBusinessPolicies($shopId, 'SHIPPING');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getReturnBusinessPolicies($shopId): array
|
||||
{
|
||||
return $this->findBusinessPolicies($shopId, 'RETURN_POLICY');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTemplates(): array
|
||||
{
|
||||
$sql = 'SELECT e.id, e.bezeichnung AS template_name
|
||||
FROM `ebay_template` AS `e`
|
||||
WHERE e.aktiv = 1';
|
||||
|
||||
return $this->db->fetchAll($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopId
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @return array
|
||||
*/
|
||||
public function getStoreCategories(int $shopId): array
|
||||
{
|
||||
if ($shopId <= 0) {
|
||||
throw new InvalidArgumentException('Required argument "shopId" is invalid.');
|
||||
}
|
||||
|
||||
$sql = 'SELECT e.id, e.kategorie AS `category_id_external`, e.bezeichnung AS description
|
||||
FROM `ebay_storekategorien` AS `e`
|
||||
WHERE shop = :shop_id';
|
||||
$values = ['shop_id' => $shopId];
|
||||
|
||||
return $this->db->fetchAll($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StagingListingData $stagingListing
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function searchForMatchingArticleId(StagingListingData $stagingListing): int
|
||||
{
|
||||
if (!empty($stagingListing->getArticleId())) {
|
||||
return $stagingListing->getArticleId();
|
||||
}
|
||||
|
||||
//associate by listing id in foreign numbers
|
||||
$sql =
|
||||
"SELECT af.artikel
|
||||
FROM `artikelnummer_fremdnummern` AS `af`
|
||||
JOIN `artikel` AS `a` ON af.artikel = a.id
|
||||
WHERE af.shopid = :shop_id AND LOWER(af.bezeichnung) = 'ebaylisting' AND af.nummer = :article_number
|
||||
AND a.nummer <> 'DEL' AND a.geloescht = 0 AND a.intern_gesperrt = 0
|
||||
LIMIT 1";
|
||||
$values = [
|
||||
'shop_id' => $stagingListing->getShopId(),
|
||||
'article_number' => $stagingListing->getItemId(),
|
||||
];
|
||||
$articleId = $this->db->fetchValue($sql, $values);
|
||||
|
||||
if (empty($articleId)) {
|
||||
//associate by sku
|
||||
$sql = 'SELECT a.id
|
||||
FROM `artikel` AS `a`
|
||||
WHERE a.geloescht = 0 AND a.intern_gesperrt=0 AND a.nummer=:article_number';
|
||||
$values = ['article_number' => $stagingListing->getSku()];
|
||||
|
||||
$articleId = $this->db->fetchValue($sql, $values);
|
||||
}
|
||||
|
||||
if (empty($articleId)) {
|
||||
//associate by foreign number
|
||||
$sql = "SELECT a.id
|
||||
FROM `artikel` AS `a`
|
||||
JOIN `artikelnummer_fremdnummern` AS `af` ON af.artikel = a.id
|
||||
WHERE a.geloescht = 0 AND a.intern_gesperrt = 0 AND a.nummer <> ''
|
||||
AND af.aktiv = 1 AND (LOWER(af.bezeichnung) = 'sku' OR LOWER(af.bezeichnung) = 'bestandseinheit')
|
||||
AND af.nummer = :article_number AND (af.shopid = :shop_id OR af.shopid = 0)
|
||||
ORDER BY af.shopid DESC LIMIT 1";
|
||||
$values = [
|
||||
'article_number' => $stagingListing->getSku(),
|
||||
'shop_id' => $stagingListing->getShopId(),
|
||||
];
|
||||
$articleId = $this->db->fetchValue($sql, $values);
|
||||
}
|
||||
|
||||
return (int)$articleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StagingListingVariationData $variation
|
||||
* @param int $shopId
|
||||
* @param int $parentArticleId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function searchForMatchingArticleIdForVariation(
|
||||
StagingListingVariationData $variation,
|
||||
int $shopId,
|
||||
int $parentArticleId
|
||||
): int {
|
||||
if (!empty($variation->getArticleId())) {
|
||||
return $variation->getArticleId();
|
||||
}
|
||||
//associate by sku
|
||||
$sql = 'SELECT a.id
|
||||
FROM `artikel` AS a
|
||||
WHERE a.geloescht = 0 AND a.intern_gesperrt = 0 AND a.nummer = :article_number';
|
||||
$values = ['article_number' => $variation->getSku()];
|
||||
$articleId = $this->db->fetchValue($sql, $values);
|
||||
|
||||
if (empty($articleId)) {
|
||||
//associate by foreign number
|
||||
$sql = "SELECT a.id
|
||||
FROM `artikel` AS `a`
|
||||
JOIN `artikelnummer_fremdnummern` AS `af` ON af.artikel = a.id
|
||||
WHERE a.geloescht = 0 AND a.intern_gesperrt = 0 AND a.nummer <> ''
|
||||
AND af.aktiv = 1 AND (LOWER(af.bezeichnung) = 'sku' OR LOWER(af.bezeichnung) = 'bestandseinheit')
|
||||
AND af.nummer = :sku AND (af.shopid = :shop_id OR af.shopid = 0)
|
||||
ORDER BY af.shopid DESC LIMIT 1";
|
||||
$values = [
|
||||
'sku' => $variation->getSku(),
|
||||
'shop_id' => $shopId,
|
||||
];
|
||||
$articleId = $this->db->fetchValue($sql, $values);
|
||||
}
|
||||
|
||||
if (empty($articleId)) {
|
||||
//associate by matrix combination
|
||||
$specifics = [];
|
||||
foreach ($variation->listSpecifics() as $dimension => $value) {
|
||||
$specifics[] = sprintf('(ma.name = %s AND mea.name = %s)',
|
||||
$this->db->escapeString($dimension),
|
||||
$this->db->escapeString($value));
|
||||
}
|
||||
$query = sprintf(
|
||||
'
|
||||
SELECT x.artikel AS `artikelId`
|
||||
FROM (
|
||||
SELECT moza.artikel
|
||||
FROM `matrixprodukt_eigenschaftengruppen_artikel` AS `ma`
|
||||
JOIN `matrixprodukt_eigenschaftenoptionen_artikel` AS `mea` on ma.id = mea.gruppe
|
||||
JOIN `matrixprodukt_optionen_zu_artikel` AS `moza` ON moza.option_id = mea.id
|
||||
WHERE ma.artikel = %d AND (%s)
|
||||
) AS `x`
|
||||
GROUP BY x.artikel
|
||||
HAVING COUNT(x.artikel) = %d',
|
||||
$parentArticleId,
|
||||
implode(' OR ', $specifics),
|
||||
count($specifics)
|
||||
);
|
||||
$foundCombinations = $this->db->fetchAll($query);
|
||||
if (count($foundCombinations) === 1) {
|
||||
$articleId = $foundCombinations[0]['artikelId'];
|
||||
}
|
||||
}
|
||||
|
||||
return (int)$articleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @param int $shopId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function existsStagingListingsForArticleId(int $articleId, int $shopId): bool
|
||||
{
|
||||
$sql = "SELECT e.id
|
||||
FROM `ebay_staging_listing` AS `e`
|
||||
LEFT JOIN `ebay_staging_listing_variant` AS `v` ON e.id = v.ebay_staging_listing_id
|
||||
WHERE (e.article_id = :article_id or v.article_id = :article_id) AND e.shop_id = :shop_id AND e.status = 'Aktiv'";
|
||||
$values = [
|
||||
'article_id' => $articleId,
|
||||
'shop_id' => $shopId
|
||||
];
|
||||
$stagingId = $this->db->fetchValue($sql, $values);
|
||||
|
||||
return !empty($stagingId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Gateway;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Ebay\Client\EbayRestApiClient;
|
||||
use Xentral\Modules\Ebay\Data\AccountCredentialsData;
|
||||
use Xentral\Modules\Ebay\Data\TokenData;
|
||||
use Xentral\Modules\Ebay\Exception\ValueNotFoundException;
|
||||
|
||||
class EbayRestApiGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $database
|
||||
*/
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->db = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopexportId
|
||||
*
|
||||
* @throws ValueNotFoundException
|
||||
*
|
||||
* @return AccountCredentialsData
|
||||
*/
|
||||
public function getAccountCredentials(int $shopexportId): AccountCredentialsData
|
||||
{
|
||||
$settings = $this->getShopSettings($shopexportId);
|
||||
|
||||
return new AccountCredentialsData(
|
||||
(string)$settings['felder']['appID'],
|
||||
(string)$settings['felder']['certID'],
|
||||
(string)$settings['felder']['ruName']
|
||||
);
|
||||
}
|
||||
|
||||
protected function getShopSettings(int $shopexportId): array
|
||||
{
|
||||
$sql = 'SELECT `einstellungen_json` FROM `shopexport` WHERE `id` = :shopexport_id';
|
||||
$values = [
|
||||
'shopexport_id' => $shopexportId,
|
||||
];
|
||||
$encodedSettings = $this->db->fetchValue($sql, $values);
|
||||
|
||||
if (empty($encodedSettings)) {
|
||||
throw new ValueNotFoundException('No settings were found for given shopexport Id: ' . $shopexportId);
|
||||
}
|
||||
|
||||
return json_decode($encodedSettings, true);
|
||||
}
|
||||
|
||||
public function useRestApiForOrderImport(int $shopexportId): bool
|
||||
{
|
||||
$settings = $this->getShopSettings($shopexportId);
|
||||
|
||||
$userEnabledSetting = (bool)$settings['felder']['useRestApiOnOrderImport'];
|
||||
$restApiTokenExists = $this->tryGetRestApiAccessTokenFromDatabase(
|
||||
$shopexportId,
|
||||
EbayRestApiClient::TOKEN_TYPE_USER
|
||||
) !== null;
|
||||
|
||||
return $userEnabledSetting && $restApiTokenExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopexportId
|
||||
* @param string $type
|
||||
*
|
||||
* @return TokenData|null
|
||||
*/
|
||||
public function tryGetRestApiAccessTokenFromDatabase(int $shopexportId, string $type): ?TokenData
|
||||
{
|
||||
$sql = "SELECT e.token, e.type, e.refresh_token, (e.valid_until > NOW()) AS valid
|
||||
FROM `ebay_rest_token` AS `e`
|
||||
WHERE e.shopexport_id = :shopexport_id
|
||||
AND e.type = :type
|
||||
LIMIT 1";
|
||||
$values = [
|
||||
'shopexport_id' => $shopexportId,
|
||||
'type' => $type,
|
||||
];
|
||||
$data = $this->db->fetchAll($sql, $values);
|
||||
|
||||
$data = reset($data);
|
||||
if (empty($data['token'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TokenData(
|
||||
$data['token'],
|
||||
$data['refresh_token'],
|
||||
$data['type'],
|
||||
(bool)$data['valid']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopexportId
|
||||
*
|
||||
* @throws ValueNotFoundException
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSiteId(int $shopexportId): int
|
||||
{
|
||||
$sql = 'SELECT `einstellungen_json` FROM `shopexport` WHERE `id` = :shopexport_id';
|
||||
$values = [
|
||||
'shopexport_id' => $shopexportId,
|
||||
];
|
||||
$encodedSettings = $this->db->fetchValue($sql, $values);
|
||||
|
||||
if (empty($encodedSettings)) {
|
||||
throw new ValueNotFoundException('No settings were found for given shopexport Id: ' . $shopexportId);
|
||||
}
|
||||
$settings = json_decode($encodedSettings, true);
|
||||
|
||||
if (empty($settings['felder']['siteID'])) {
|
||||
throw new ValueNotFoundException('Site Id value missing for given shopexport Id:' . $shopexportId);
|
||||
}
|
||||
|
||||
return (int)$settings['felder']['siteID'];
|
||||
}
|
||||
|
||||
public function existsRestOrderInDatabase(string $orderId): bool
|
||||
{
|
||||
$sql = 'SELECT `id` FROM `ebay_rest_orders` WHERE `order_id` = :order_id';
|
||||
$values = [
|
||||
'order_id' => $orderId,
|
||||
];
|
||||
|
||||
return $this->db->fetchValue($sql, $values) > 0;
|
||||
}
|
||||
|
||||
public function countRestOrdersToImport(int $shopexportId): int
|
||||
{
|
||||
$sql = 'SELECT COUNT(id) FROM `ebay_rest_orders` WHERE `processed` = 0 AND `shopexport_id` = :shopexport_id';
|
||||
$values = [
|
||||
'shopexport_id' => $shopexportId,
|
||||
];
|
||||
|
||||
return (int)$this->db->fetchValue($sql, $values);
|
||||
}
|
||||
|
||||
public function getNextOrderToImport(int $shopexportId): string
|
||||
{
|
||||
$sql = 'SELECT `order_data` FROM `ebay_rest_orders`
|
||||
WHERE `processed` = 0 AND `shopexport_id` = :shopexport_id
|
||||
ORDER BY `date_of_order` ASC
|
||||
LIMIT 1';
|
||||
$values = [
|
||||
'shopexport_id' => $shopexportId,
|
||||
];
|
||||
|
||||
return (string)$this->db->fetchValue($sql, $values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Module;
|
||||
|
||||
use DateTime;
|
||||
use Xentral\Modules\Ebay\Client\EbayRestApiClient;
|
||||
use Xentral\Modules\Ebay\Data\AccountCredentialsData;
|
||||
use Xentral\Modules\Ebay\Data\TokenData;
|
||||
use Xentral\Modules\Ebay\Gateway\EbayRestApiGateway;
|
||||
use Xentral\Modules\Ebay\Service\EbayRestApiService;
|
||||
|
||||
final class EbayRestApiModule
|
||||
{
|
||||
/** @var EbayRestApiClient $client */
|
||||
private $client;
|
||||
/** @var EbayRestApiGateway $gateway */
|
||||
private $gateway;
|
||||
/** @var EbayRestApiService $service */
|
||||
private $service;
|
||||
|
||||
/**
|
||||
* @param EbayRestApiClient $client
|
||||
* @param EbayRestApiGateway $gateway
|
||||
* @param EbayRestApiService $service
|
||||
*/
|
||||
public function __construct(EbayRestApiClient $client, EbayRestApiGateway $gateway, EbayRestApiService $service)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->gateway = $gateway;
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopexportId
|
||||
* @param int $categoryId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCategorySpecificProperties(int $shopexportId, int $categoryId): array
|
||||
{
|
||||
$siteId = $this->gateway->getSiteId($shopexportId);
|
||||
|
||||
$token = $this->getRestApiApplicationAccessToken($shopexportId);
|
||||
|
||||
return $this->client->getCategorySpecificProperties($siteId, $categoryId, $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopexportId
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRestApiApplicationAccessToken(int $shopexportId): ?string
|
||||
{
|
||||
$credentials = $this->gateway->getAccountCredentials($shopexportId);
|
||||
$ebayResponse = $this->client->getRestApiApplicationAccessTokenFromEbay(
|
||||
$credentials
|
||||
);
|
||||
$this->service->saveRestApiAccessToken($shopexportId, $ebayResponse);
|
||||
|
||||
return $ebayResponse['access_token'];
|
||||
}
|
||||
|
||||
public function getOrders(int $shopexportId, DateTime $dateFrom, int $offset, int $limit = null): array
|
||||
{
|
||||
$token = $this->getRestApiUserAccessToken($shopexportId);
|
||||
|
||||
return $this->client->getOrders($token, $dateFrom, $offset, $limit);
|
||||
}
|
||||
|
||||
public function getRestApiUserAccessToken(int $shopexportId): string
|
||||
{
|
||||
$tokenData = $this->gateway->tryGetRestApiAccessTokenFromDatabase(
|
||||
$shopexportId,
|
||||
EbayRestApiClient::TOKEN_TYPE_USER
|
||||
);
|
||||
if ($tokenData === null) {
|
||||
//TODO EXCEPTION
|
||||
throw new \RuntimeException('Token Request Failure');
|
||||
}
|
||||
if ($tokenData->isValid()) {
|
||||
return $tokenData->getToken();
|
||||
}
|
||||
|
||||
$tokenData = $this->renewToken($shopexportId, $tokenData);
|
||||
|
||||
//TODO Exception
|
||||
return $tokenData->getToken();
|
||||
}
|
||||
|
||||
protected function renewToken(int $shopexportId, TokenData $tokenData): TokenData
|
||||
{
|
||||
$response = $this->client->renewToken(
|
||||
$this->gateway->getAccountCredentials($shopexportId),
|
||||
$tokenData
|
||||
);
|
||||
|
||||
$tokenData->setToken($response['access_token']);
|
||||
$this->service->renewToken($shopexportId, (int)$response['expires_in'], $tokenData);
|
||||
|
||||
return $tokenData;
|
||||
}
|
||||
|
||||
public function fetchRestApiUserAccessToken(int $shopexportId, string $requestCode): ?string
|
||||
{
|
||||
$credentials = $this->gateway->getAccountCredentials($shopexportId);
|
||||
$ebayResponse = $this->client->getRestApiUserAccessTokenFromEbay(
|
||||
$credentials,
|
||||
$requestCode
|
||||
);
|
||||
$this->service->saveRestApiAccessToken($shopexportId, $ebayResponse);
|
||||
|
||||
if (!isset($ebayResponse['access_token'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ebayResponse['access_token'];
|
||||
}
|
||||
|
||||
public function getCompleteApiScope(): array
|
||||
{
|
||||
return $this->client->getCompleteScope();
|
||||
}
|
||||
|
||||
public function getAccountCredentials($shopexportId): AccountCredentialsData
|
||||
{
|
||||
return $this->gateway->getAccountCredentials($shopexportId);
|
||||
}
|
||||
|
||||
public function useRestApiForOrderImport(int $shopexportId): bool
|
||||
{
|
||||
return $this->gateway->useRestApiForOrderImport($shopexportId);
|
||||
}
|
||||
|
||||
public function saveRestOrder(int $shopexportId, DateTime $orderDate, string $orderId, string $orderData): void
|
||||
{
|
||||
$this->service->saveRestOrder($shopexportId, $orderDate, $orderId, $orderData);
|
||||
}
|
||||
|
||||
public function countRestOrdersToImport(int $shopexportId): int
|
||||
{
|
||||
return $this->gateway->countRestOrdersToImport($shopexportId);
|
||||
}
|
||||
|
||||
public function getNextOrderToImport(int $shopexportId): string
|
||||
{
|
||||
return $this->gateway->getNextOrderToImport($shopexportId);
|
||||
}
|
||||
|
||||
public function setRestOrderToProcessed(string $orderId): void
|
||||
{
|
||||
$this->service->setRestOrderToProcessed($orderId);
|
||||
}
|
||||
|
||||
public function deleteRestOrderFromDatabase(string $orderId): void
|
||||
{
|
||||
$this->service->deleteRestOrderFromDatabase($orderId);
|
||||
}
|
||||
|
||||
public function existsRestOrderInDatabase(string $orderId): bool
|
||||
{
|
||||
return $this->gateway->existsRestOrderInDatabase($orderId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,448 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Ebay\Data\StagingListingData;
|
||||
use Xentral\Modules\Ebay\Data\StagingListingPicture;
|
||||
use Xentral\Modules\Ebay\Data\StagingListingVariationData;
|
||||
use Xentral\Modules\Ebay\Exception\InvalidArgumentException;
|
||||
use Xentral\Modules\Ebay\Exception\MissingValueException;
|
||||
use Xentral\Modules\Ebay\Gateway\EbayListingGateway;
|
||||
use Xentral\Modules\Ebay\Wrapper\EbayStockCalculationWrapperInterface;
|
||||
use Xentral\Modules\Ebay\Wrapper\StockCalculationWrapper;
|
||||
|
||||
final class EbayListingService
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/** @var EbayListingGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/** @var EbayListingXmlSerializer $serializer */
|
||||
private $serializer;
|
||||
|
||||
/** @var StockCalculationWrapper $stockCalculationWrapper */
|
||||
private $stockCalculationWrapper;
|
||||
|
||||
/**
|
||||
* @param EbayListingGateway $gateway
|
||||
* @param Database $database
|
||||
* @param EbayListingXmlSerializer $serializer
|
||||
* @param EbayStockCalculationWrapperInterface $wrapper
|
||||
*/
|
||||
public function __construct(
|
||||
EbayListingGateway $gateway,
|
||||
Database $database,
|
||||
EbayListingXmlSerializer $serializer,
|
||||
EbayStockCalculationWrapperInterface $wrapper
|
||||
) {
|
||||
$this->gateway = $gateway;
|
||||
$this->db = $database;
|
||||
$this->serializer = $serializer;
|
||||
$this->stockCalculationWrapper = $wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $stagingListingId
|
||||
*
|
||||
* @return StagingListingData
|
||||
*/
|
||||
public function associateStagingListing($stagingListingId): StagingListingData
|
||||
{
|
||||
$stagingListing = $this->gateway->getStagingListingByDatabaseId($stagingListingId);
|
||||
|
||||
$stagingListing = $this->associateArticle($stagingListing);
|
||||
|
||||
$stagingListing = $this->associateVariants($stagingListing);
|
||||
|
||||
$this->saveStagingListing($stagingListing);
|
||||
|
||||
return $stagingListing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StagingListingData $stagingListing
|
||||
*
|
||||
* @return StagingListingData
|
||||
*/
|
||||
private function associateArticle(StagingListingData $stagingListing): StagingListingData
|
||||
{
|
||||
$articleId = $this->gateway->searchForMatchingArticleId($stagingListing);
|
||||
$stagingListing->setArticleId($articleId);
|
||||
|
||||
return $stagingListing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StagingListingData $stagingListing
|
||||
*
|
||||
* @return StagingListingData
|
||||
*/
|
||||
private function associateVariants(StagingListingData $stagingListing): StagingListingData
|
||||
{
|
||||
if (empty($stagingListing->getArticleId()) || empty($stagingListing->getVariations())) {
|
||||
return $stagingListing;
|
||||
}
|
||||
foreach ($stagingListing->getVariations() as $variation) {
|
||||
$articleId = $this->gateway->searchForMatchingArticleIdForVariation(
|
||||
$variation,
|
||||
$stagingListing->getShopId(),
|
||||
$stagingListing->getArticleId()
|
||||
);
|
||||
$variation->setArticleId($articleId);
|
||||
}
|
||||
|
||||
return $stagingListing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StagingListingData $stagingListing
|
||||
*
|
||||
* @throws MissingValueException
|
||||
*
|
||||
* @return StagingListingData
|
||||
*/
|
||||
public function saveStagingListing($stagingListing): StagingListingData
|
||||
{
|
||||
$stagingListingId = $stagingListing->getId();
|
||||
|
||||
if (empty($stagingListingId)) {
|
||||
$query = sprintf(
|
||||
'INSERT INTO `ebay_staging_listing` (`shop_id`) VALUES (%d)',
|
||||
$stagingListing->getShopId()
|
||||
);
|
||||
$this->db->exec($query);
|
||||
$stagingListingId = $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
if(!empty($stagingListingId)){
|
||||
$sql = 'SELECT esl.id FROM `ebay_staging_listing` AS `esl` WHERE esl.id=:id';
|
||||
$stagingListingId = $this->db->fetchValue($sql,['id' => $stagingListingId]);
|
||||
}
|
||||
|
||||
if (empty($stagingListingId)) {
|
||||
throw new MissingValueException('ID for Staging Listing dataset could not be found or created.');
|
||||
}
|
||||
|
||||
$sql = 'UPDATE `ebay_staging_listing` SET
|
||||
`article_id` = :article_id,
|
||||
`type` = :listing_type,
|
||||
`title` = :title,
|
||||
`status` = :listing_status,
|
||||
`sku` = :sku,
|
||||
`description` = :description,
|
||||
`ebay_primary_category_id_external` = :primary_category,
|
||||
`ebay_secondary_category_id_external` = :secondary_category,
|
||||
`ebay_primary_store_category_id_external` = :primary_store_category,
|
||||
`ebay_secondary_store_category_id_external` = :secondary_store_category,
|
||||
`ebay_shipping_profile_id_external` = :shipping_profile,
|
||||
`ebay_payment_profile_id_external` = :payment_profile,
|
||||
`ebay_return_profile_id_external` = :return_profile,
|
||||
`ebay_plus` = :ebayplus,
|
||||
`ebay_price_suggestion` = :price_suggestion,
|
||||
`ebay_private_listing` = :private_listing,
|
||||
`condition_id_external` = :condition_id,
|
||||
`condition_display_name` = :condition_display_name,
|
||||
`condition_description` = :condition_description,
|
||||
`listing_duration` = :listing_duration,
|
||||
`inventory_tracking_method` = :inventory_tracking_method,
|
||||
`item_id_external` = :item_id,
|
||||
`delivery_time` = :delivery_time,
|
||||
`template_id` = :template_id
|
||||
WHERE id = :listing_id';
|
||||
$values = [
|
||||
'article_id' => $stagingListing->getArticleId(),
|
||||
'listing_type' => $stagingListing->getType(),
|
||||
'title' => $stagingListing->getTitle(),
|
||||
'listing_status' => $stagingListing->getStatus(),
|
||||
'sku' => $stagingListing->getSku(),
|
||||
'description' => $stagingListing->getDescription(),
|
||||
'primary_category' => $stagingListing->getPrimaryCategoryId(),
|
||||
'secondary_category' => $stagingListing->getSecondaryCategoryId(),
|
||||
'primary_store_category' => $stagingListing->getPrimaryStoreCategoryId(),
|
||||
'secondary_store_category' => $stagingListing->getSecondaryStoreCategoryId(),
|
||||
'shipping_profile' => $stagingListing->getShippingProfileId(),
|
||||
'payment_profile' => $stagingListing->getPaymentProfileId(),
|
||||
'return_profile' => $stagingListing->getReturnProfileId(),
|
||||
'ebayplus' => $stagingListing->isEbayPlus(),
|
||||
'price_suggestion' => $stagingListing->isPriceSuggestion(),
|
||||
'private_listing' => $stagingListing->isPrivateListing(),
|
||||
'condition_id' => $stagingListing->getConditionId(),
|
||||
'condition_display_name' => $stagingListing->getConditionDisplayName(),
|
||||
'condition_description' => $stagingListing->getConditionDescription(),
|
||||
'listing_duration' => $stagingListing->getListingDuration(),
|
||||
'inventory_tracking_method' => $stagingListing->getInventoryTrackingMethod(),
|
||||
'item_id' => $stagingListing->getItemId(),
|
||||
'delivery_time' => $stagingListing->getDeliveryTime(),
|
||||
'template_id' => $stagingListing->getTemplateId(),
|
||||
'listing_id' => $stagingListingId,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
|
||||
foreach ($stagingListing->listSpecifics() as $specificName => $specificValue) {
|
||||
$this->saveSpecific($stagingListingId, $specificName, $specificValue);
|
||||
}
|
||||
|
||||
if (!empty($stagingListing->getVariations())) {
|
||||
foreach ($stagingListing->getVariations() as $variation) {
|
||||
$this->saveStagingListingVariation($stagingListingId, $variation);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($stagingListing->listPictures())) {
|
||||
foreach ($stagingListing->listPictures() as $picture) {
|
||||
$picture->setStagingListingId($stagingListingId);
|
||||
$this->savePictureHostingServicePicture($picture);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->gateway->getStagingListingByDatabaseId($stagingListingId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $stagingListingId
|
||||
* @param string $specificName
|
||||
* @param string $specificValue
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function saveSpecific($stagingListingId, $specificName, $specificValue): void
|
||||
{
|
||||
if (empty($specificName)) {
|
||||
throw new InvalidArgumentException('Required argument "specificName" is empty or invalid.');
|
||||
}
|
||||
if (empty($stagingListingId)) {
|
||||
throw new InvalidArgumentException('Required argument "stagingListingId" is empty or invalid.');
|
||||
}
|
||||
|
||||
$sql = 'SELECT esls.id FROM `ebay_staging_listing_specific` AS `esls`
|
||||
WHERE `ebay_staging_listing_id` = :listing_id AND `property` = :specific_name';
|
||||
$values = [
|
||||
'listing_id' => $stagingListingId,
|
||||
'specific_name' => $specificName,
|
||||
];
|
||||
$specificId = $this->db->fetchValue($sql, $values);
|
||||
|
||||
$sql = 'UPDATE `ebay_staging_listing_specific` SET `value` = :value WHERE `id` = :specific_id';
|
||||
$values = [
|
||||
'value' => $specificValue,
|
||||
'specific_id' => $specificId,
|
||||
];
|
||||
|
||||
if (empty($specificId)) {
|
||||
$sql = 'INSERT INTO `ebay_staging_listing_specific`
|
||||
(`ebay_staging_listing_id`, `property`, `value`) VALUES (:listing_id, :specific_name, :value)';
|
||||
$values = [
|
||||
'listing_id' => $stagingListingId,
|
||||
'specific_name' => $specificName,
|
||||
'value' => $specificValue,
|
||||
];
|
||||
}
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $stagingListingId
|
||||
* @param StagingListingVariationData $variation
|
||||
*/
|
||||
private function saveStagingListingVariation($stagingListingId, $variation): void
|
||||
{
|
||||
$specifics = $variation->listSpecifics();
|
||||
$conditions = [];
|
||||
foreach ($specifics as $property => $value) {
|
||||
$conditions[] = sprintf(
|
||||
'(eslvs.property = %s AND eslvs.value = %s)',
|
||||
$this->db->escapeString($property),
|
||||
$this->db->escapeString($value)
|
||||
);
|
||||
}
|
||||
$condition = implode(' OR ', $conditions);
|
||||
if (empty($conditions)) {
|
||||
$condition = 0;
|
||||
}
|
||||
|
||||
$query = sprintf(
|
||||
'
|
||||
SELECT eslv.id
|
||||
FROM `ebay_staging_listing_variant_specific` AS `eslvs`
|
||||
JOIN `ebay_staging_listing_variant` AS `eslv` ON eslv.id = eslvs.ebay_staging_listing_variant_id
|
||||
WHERE eslv.ebay_staging_listing_id = %s AND (%s)
|
||||
GROUP BY eslv.id
|
||||
HAVING COUNT(eslv.id) = %d',
|
||||
$stagingListingId,
|
||||
$condition,
|
||||
count($conditions)
|
||||
);
|
||||
$stagingListingVariationId = $this->db->fetchValue($query);
|
||||
if (empty($stagingListingVariationId)) {
|
||||
$query = 'INSERT INTO `ebay_staging_listing_variant` () VALUES ()';
|
||||
$this->db->exec($query);
|
||||
$stagingListingVariationId = $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
$sql = 'UPDATE `ebay_staging_listing_variant` SET
|
||||
`article_id` = :article_id, `sku` = :sku, `ebay_staging_listing_id` = :listing_id
|
||||
WHERE id = :variation_id';
|
||||
$values = [
|
||||
'article_id' => $variation->getArticleId(),
|
||||
'sku' => $variation->getSku(),
|
||||
'listing_id' => $stagingListingId,
|
||||
'variation_id' => $stagingListingVariationId,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
|
||||
foreach ($specifics as $property => $value) {
|
||||
$sql = 'SELECT `id`
|
||||
FROM `ebay_staging_listing_variant_specific`
|
||||
WHERE `ebay_staging_listing_variant_id`=:variation_id AND `property`=:property AND `value`=:value';
|
||||
$values = [
|
||||
'variation_id' => $stagingListingVariationId,
|
||||
'property' => $property,
|
||||
'value' => $value,
|
||||
];
|
||||
$specificMissing = empty($this->db->fetchValue($sql, $values));
|
||||
|
||||
if ($specificMissing) {
|
||||
$sql = 'INSERT INTO `ebay_staging_listing_variant_specific`
|
||||
(`ebay_staging_listing_variant_id`, `property`, `value`)
|
||||
VALUES (:variation_id, :property, :value)';
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StagingListingPicture $picture
|
||||
*/
|
||||
private function savePictureHostingServicePicture(StagingListingPicture $picture): void
|
||||
{
|
||||
$sql = 'SELECT `id` FROM `ebay_picture_hosting_service`
|
||||
WHERE `url`=:url
|
||||
AND `ebay_staging_listing_id`=:listing_id
|
||||
AND `ebay_staging_listing_variation_id`=:variation_id';
|
||||
$values = [
|
||||
'url' => $picture->getUrl(),
|
||||
'listing_id' => $picture->getStagingListingId(),
|
||||
'variation_id' => $picture->getStagingListingVariantId(),
|
||||
];
|
||||
|
||||
$pictureId = $this->db->fetchValue($sql, $values);
|
||||
if (!empty($pictureId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sql = 'INSERT INTO `ebay_picture_hosting_service`
|
||||
(`ebay_staging_listing_id`, `ebay_staging_listing_variation_id`, `file_id`, `url`)
|
||||
VALUES
|
||||
(:listing_id,:variation_id,:file_id,:url)';
|
||||
$values = [
|
||||
'listing_id' => $picture->getStagingListingId(),
|
||||
'variation_id' => $picture->getStagingListingVariantId(),
|
||||
'file_id' => $picture->getFileId(),
|
||||
'url' => $picture->getUrl(),
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopId
|
||||
* @param object $item
|
||||
*
|
||||
* @return StagingListingData
|
||||
*/
|
||||
public function synchronizeItemData($shopId, $item): StagingListingData
|
||||
{
|
||||
$stagingListing = new StagingListingData($shopId);
|
||||
|
||||
$stagingListingId = $this->gateway->tryGetStagingListingIdByItemId((string)$item->ItemID);
|
||||
if (!empty($stagingListingId)) {
|
||||
$stagingListing = $this->gateway->getStagingListingByDatabaseId($stagingListingId);
|
||||
}
|
||||
|
||||
$listingStatus = 'Aktiv';
|
||||
if (!empty($item->ListingDetails->EndingReason)) {
|
||||
$listingStatus = 'Beendet';
|
||||
}
|
||||
$stagingListing->setType((string)$item->ListingType);
|
||||
$stagingListing->setTitle((string)$item->Title);
|
||||
$stagingListing->setSku((string)$item->SKU);
|
||||
$stagingListing->setDescription('');
|
||||
$stagingListing->setPrimaryCategoryId((string)$item->PrimaryCategory->CategoryID);
|
||||
$stagingListing->setPrimaryStoreCategoryId((string)$item->Storefront->StoreCategoryID);
|
||||
$stagingListing->setSecondaryStoreCategoryId((string)$item->Storefront->StoreCategoryID2);
|
||||
$stagingListing->setShippingProfileId((string)$item->SellerProfiles->SellerShippingProfile->ShippingProfileID);
|
||||
$stagingListing->setPaymentProfileId((string)$item->SellerProfiles->SellerPaymentProfile->PaymentProfileID);
|
||||
$stagingListing->setReturnProfileId((string)$item->SellerProfiles->SellerReturnProfile->ReturnProfileID);
|
||||
$stagingListing->setDeliveryTime((string)$item->DispatchTimeMax);
|
||||
$stagingListing->setItemId((string)$item->ItemID);
|
||||
$stagingListing->setInventoryTrackingMethod((string)$item->InventoryTrackingMethod);
|
||||
$stagingListing->setConditionId((string)$item->ConditionID);
|
||||
$stagingListing->setListingDuration((string)$item->ListingDuration);
|
||||
$stagingListing->setConditionDisplayName((string)$item->ConditionDisplayName);
|
||||
$stagingListing->setConditionDescription((string)$item->ConditionDescription);
|
||||
$stagingListing->setPrivateListing(strtolower((string)$item->PrivateListing) === 'true');
|
||||
$stagingListing->setEbayPlus(strtolower((string)$item->eBayPlus) === 'true');
|
||||
$stagingListing->setStatus($listingStatus);
|
||||
|
||||
if (!empty($item->ItemSpecifics->NameValueList)) {
|
||||
$stagingListing->setSpecifics([]);
|
||||
foreach ($item->ItemSpecifics->NameValueList as $itemSpecific) {
|
||||
$stagingListing->addSpecific((string)$itemSpecific->Name, (string)$itemSpecific->Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($item->PictureDetails->PictureURL)) {
|
||||
foreach ($item->PictureDetails->PictureURL as $pictureUrl) {
|
||||
$stagingListing->addPicture(
|
||||
new StagingListingPicture(
|
||||
str_replace('$_1.', '$_10.', (string)$pictureUrl)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($item->Variations)) {
|
||||
foreach ($item->Variations->Variation as $variation) {
|
||||
$stagingListingVariation = new StagingListingVariationData();
|
||||
$stagingListingVariation->setSku((string)$variation->SKU);
|
||||
foreach ($variation->VariationSpecifics->NameValueList as $specifics) {
|
||||
$stagingListingVariation->addSpecifics((string)$specifics->Name, (string)$specifics->Value);
|
||||
}
|
||||
$stagingListing->addVariation($stagingListingVariation);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->saveStagingListing($stagingListing);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $stagingId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getStockSyncBody($stagingId): string
|
||||
{
|
||||
$staging = $this->gateway->getStagingListingByDatabaseId($stagingId);
|
||||
|
||||
$stocksForArticles = [];
|
||||
|
||||
$stocksForArticles[$staging->getArticleId()] = $this->stockCalculationWrapper->calculateStock(
|
||||
$staging->getArticleId(),
|
||||
$staging->getShopId()
|
||||
);
|
||||
foreach ($staging->getVariations() as $variation) {
|
||||
if (!empty($variation->getArticleId()) && !isset($stocksForArticles[$variation->getArticleId()])) {
|
||||
$stocksForArticles[$variation->getArticleId()] = $this->stockCalculationWrapper->calculateStock(
|
||||
$variation->getArticleId(),
|
||||
$staging->getShopId()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->serializer->createStockSyncXmlString($staging, $stocksForArticles);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Ebay\Service;
|
||||
|
||||
use Xentral\Modules\Ebay\Data\StagingListingData;
|
||||
|
||||
final class EbayListingXmlSerializer
|
||||
{
|
||||
/**
|
||||
* @param StagingListingData $stagingListing
|
||||
* @param array $stocksForArticles
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function createStockSyncXmlString(StagingListingData $stagingListing, $stocksForArticles): string
|
||||
{
|
||||
$syncBody = '<ReviseFixedPriceItemRequest version="1.0" xmlns="urn:ebay:apis:eBLBaseComponents">';
|
||||
$syncBody .= '<Version>1137</Version>';
|
||||
$syncBody .= '<MessageID>' . $stagingListing->getSku() . '</MessageID>';
|
||||
$syncBody .= '<Item>
|
||||
<ItemID>' . $stagingListing->getItemId() . '</ItemID>';
|
||||
|
||||
if (!empty($stagingListing->getVariations())) {
|
||||
$syncBody .= '<Variations>';
|
||||
foreach ($stagingListing->getVariations() as $variation) {
|
||||
$quantity = 0;
|
||||
|
||||
if (!empty($variation->getArticleId()) && array_key_exists(
|
||||
$variation->getArticleId(),
|
||||
$stocksForArticles
|
||||
)) {
|
||||
$quantity = $stocksForArticles[$variation->getArticleId()];
|
||||
$syncBody .= '
|
||||
<Variation>';
|
||||
$syncBody .= '<Quantity>' . $quantity . '</Quantity><SKU>' . $variation->getSku() . '</SKU>';
|
||||
$syncBody .= '<VariationSpecifics>';
|
||||
foreach ($variation->listSpecifics() as $specificName => $specificValue) {
|
||||
$syncBody .= '
|
||||
<NameValueList>';
|
||||
$syncBody .= '<Name>' . $specificName . '</Name>';
|
||||
$syncBody .= '<Value>' . $specificValue . '</Value>';
|
||||
$syncBody .= '</NameValueList>';
|
||||
}
|
||||
$syncBody .= '</VariationSpecifics>';
|
||||
$syncBody .= '</Variation>';
|
||||
}
|
||||
}
|
||||
$syncBody .= '</Variations>';
|
||||
} else {
|
||||
$quantity = 0;
|
||||
if (!empty($stagingListing->getArticleId()) && array_key_exists(
|
||||
$stagingListing->getArticleId(),
|
||||
$stocksForArticles
|
||||
)) {
|
||||
$quantity = $stocksForArticles[$stagingListing->getArticleId()];
|
||||
}
|
||||
|
||||
$syncBody .= '<Quantity>' . $quantity . '</Quantity>';
|
||||
}
|
||||
|
||||
$syncBody .= '</Item></ReviseFixedPriceItemRequest>';
|
||||
|
||||
|
||||
return $syncBody;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Service;
|
||||
|
||||
use DateTime;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Ebay\Data\TokenData;
|
||||
use Xentral\Modules\Ebay\Exception\InvalidArgumentException;
|
||||
|
||||
class EbayRestApiService
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $database
|
||||
*/
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->db = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopexportId
|
||||
* @param array $ebayResponse
|
||||
*/
|
||||
public function saveRestApiAccessToken(int $shopexportId, array $ebayResponse): void
|
||||
{
|
||||
if (empty($shopexportId)) {
|
||||
throw new InvalidArgumentException('Value for shopexport Id must not be empty');
|
||||
}
|
||||
if (empty($ebayResponse)) {
|
||||
throw new InvalidArgumentException('eBay Response was empty');
|
||||
}
|
||||
$token = $ebayResponse['access_token'];
|
||||
$refreshToken = $ebayResponse['refresh_token'];
|
||||
$expiresInMinutes = $ebayResponse['expires_in'] / 60 - 5;
|
||||
$validUntil = new DateTime();
|
||||
$validUntil->modify(sprintf('+%d minutes', $expiresInMinutes));
|
||||
|
||||
if (empty($token)) {
|
||||
throw new InvalidArgumentException('Value for token must not be empty');
|
||||
}
|
||||
|
||||
$this->deleteRedundantToken($shopexportId, $ebayResponse['token_type']);
|
||||
|
||||
$query = sprintf(
|
||||
'INSERT INTO `ebay_rest_token` (`shopexport_id`, `token`, `refresh_token`,`type`, `scope`, `valid_until`)
|
||||
VALUES (%d, \'%s\', \'%s\', \'%s\', \'%s\',\'%s\')',
|
||||
$shopexportId,
|
||||
$token,
|
||||
$refreshToken,
|
||||
$ebayResponse['token_type'],
|
||||
'',
|
||||
$validUntil->format('Y-m-d H:i:s')
|
||||
|
||||
);
|
||||
$this->db->exec($query);
|
||||
}
|
||||
|
||||
public function deleteRedundantToken(int $shopexportId, string $type): void
|
||||
{
|
||||
$sql = 'DELETE FROM `ebay_rest_token` WHERE shopexport_id = :shopexport_id AND type = :type';
|
||||
$values = [
|
||||
'shopexport_id' => $shopexportId,
|
||||
'type' => $type,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
public function renewToken(int $shopexportId, int $expiresInSeconds, TokenData $tokenData): void
|
||||
{
|
||||
$expiresInMinutes = $expiresInSeconds / 60 - 5; // reduce the actual valid time by 5 minutes to avoid a very specific edge case in which the token runs out the second it gets used
|
||||
$validUntil = new DateTime();
|
||||
$validUntil->modify(sprintf('+%d minutes', $expiresInMinutes));
|
||||
|
||||
$sql = 'UPDATE `ebay_rest_token` SET `token` = :token, `valid_until` = :valid_until
|
||||
WHERE `shopexport_id` = :shopexport_id AND `type` = :type';
|
||||
$values = [
|
||||
'token' => $tokenData->getToken(),
|
||||
'valid_until' => $validUntil->format('Y-m-d H:i:s'),
|
||||
'shopexport_id' => $shopexportId,
|
||||
'type' => $tokenData->getType(),
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
public function saveRestOrder(int $shopexportId, DateTime $orderDate, string $orderId, string $orderData): void
|
||||
{
|
||||
$sql = 'INSERT INTO `ebay_rest_orders` (`date_of_order`, `order_data`, `shopexport_id`, `order_id`, `processed`)
|
||||
VALUES (:date_of_order, :order_data, :shopexport_id, :order_id, 0)';
|
||||
$values = [
|
||||
'date_of_order' => $orderDate->format('Y-m-d H:i:s'),
|
||||
'order_data' => $orderData,
|
||||
'shopexport_id' => $shopexportId,
|
||||
'order_id' => $orderId,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
public function setRestOrderToProcessed(string $orderId): void
|
||||
{
|
||||
$sql = 'UPDATE `ebay_rest_orders` SET `processed` = 1
|
||||
WHERE `order_id` = :order_id';
|
||||
$values = [
|
||||
'order_id' => $orderId,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
public function deleteRestOrderFromDatabase(string $orderId): void
|
||||
{
|
||||
$sql = 'DELETE FROM `ebay_rest_orders` WHERE `order_id` = :order_id';
|
||||
$values = [
|
||||
'order_id' => $orderId,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Ebay\Data\StockLoggingData;
|
||||
|
||||
final class EbayStockLoggingService
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $database
|
||||
*/
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->db = $database;
|
||||
}
|
||||
|
||||
public function saveStockLoggingInformation(
|
||||
int $shopId,
|
||||
string $jobIdExternal,
|
||||
StockLoggingData $stockLoggingData
|
||||
): void {
|
||||
$sql = 'INSERT INTO `ebay_stock_logging` (`shop_id`, `job_id_external`, `listing_id_external`,`sku`, `quantity`, `status`)
|
||||
VALUES (:shop_id, :job_id_external, :listing_id_external, :sku, :quantity, :status)';
|
||||
$values = [
|
||||
'shop_id' => $shopId,
|
||||
'job_id_external' => $jobIdExternal,
|
||||
'listing_id_external' => $stockLoggingData->getItemId(),
|
||||
'sku' => $stockLoggingData->getSku(),
|
||||
'quantity' => $stockLoggingData->getQuantity(),
|
||||
'status' => $stockLoggingData->getStatus(),
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
$stockLoggingDataId = $this->db->lastInsertId();
|
||||
|
||||
foreach ($stockLoggingData->getVariations() as $variation) {
|
||||
$sql = 'INSERT INTO `ebay_stock_logging_variations` (`ebay_stock_logging_id`, `sku`, `quantity`)
|
||||
VALUES (:ebay_stock_logging_id, :sku, :quantity)';
|
||||
$values = [
|
||||
'ebay_stock_logging_id' => $stockLoggingDataId,
|
||||
'sku' => $variation->getSku(),
|
||||
'quantity' => $variation->getQuantity(),
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
foreach ($stockLoggingData->getErrorMessages() as $errorMessage => $type) {
|
||||
$sql = 'INSERT INTO `ebay_stock_logging_errors` (`ebay_stock_logging_id`, `message`, `type`)
|
||||
VALUES (:ebay_stock_logging_id, :message, :type)';
|
||||
$values = [
|
||||
'ebay_stock_logging_id' => $stockLoggingDataId,
|
||||
'message' => $errorMessage,
|
||||
'type' => $type,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Wrapper;
|
||||
|
||||
interface EbayStockCalculationWrapperInterface
|
||||
{
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @param int $shopId
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function calculateStock($articleId, $shopId): float;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ebay\Wrapper;
|
||||
|
||||
use erpAPI;
|
||||
use Xentral\Components\Database\Database;
|
||||
|
||||
/**
|
||||
* Anti-Corruption-Layer für erpApi->ArtikelAnzahlVerkaufbar()
|
||||
*/
|
||||
final class StockCalculationWrapper implements EbayStockCalculationWrapperInterface
|
||||
{
|
||||
/** @var erpAPI $erp */
|
||||
private $erp;
|
||||
|
||||
/**
|
||||
* @var Database
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $maximumStockForShop = [];
|
||||
|
||||
/**
|
||||
* @param erpAPI $erp
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct($erp, $db)
|
||||
{
|
||||
$this->erp = $erp;
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @param int $shopId
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function calculateStock($articleId, $shopId): float
|
||||
{
|
||||
if(empty($articleId)){
|
||||
return 0;
|
||||
}
|
||||
|
||||
$pseudoStorage = trim($this->erp->GetArtikelShopEinstellung('pseudolager', $articleId, $shopId));
|
||||
|
||||
if($pseudoStorage === '' && $this->erp->ModulVorhanden('pseudostorage')){
|
||||
$values = ['shop_id' => $shopId];
|
||||
$sql = 'SELECT p.formula FROM `pseudostorage_shop` AS `p` WHERE p.shop_id = :shop_id';
|
||||
$pseudoStorage = trim($this->db->fetchValue($sql, $values));
|
||||
}
|
||||
|
||||
if(!empty($pseudoStorage)) {
|
||||
$this->erp->RunHook('remote_send_article_list_pseudostorage', 3, $shopId, $articleId, $pseudoStorage);
|
||||
}
|
||||
|
||||
if ($pseudoStorage !== '') {
|
||||
return $this->recalculateForMaximumStock($pseudoStorage > 0 ? floor($pseudoStorage) : 0, $shopId);
|
||||
}
|
||||
|
||||
$sql = 'SELECT s.lagergrundlage FROM `shopexport` AS `s` WHERE s.id = :shop_id';
|
||||
$values = ['shop_id' => $shopId];
|
||||
$lagergrundlage = $this->db->fetchValue($sql, $values);
|
||||
|
||||
$sql = 'SELECT p.projektlager
|
||||
FROM `projekt` AS `p`
|
||||
JOIN `artikel` AS `a` ON p.id = a.projekt
|
||||
WHERE a.id = :article_id';
|
||||
$values = ['article_id' => $articleId];
|
||||
$projektlager = $this->db->fetchValue($sql, $values);
|
||||
|
||||
$calculatedStock = (float)$this->erp->ArtikelAnzahlVerkaufbar(
|
||||
$articleId,
|
||||
0,
|
||||
$projektlager,
|
||||
$shopId,
|
||||
$lagergrundlage
|
||||
);
|
||||
|
||||
return $this->recalculateForMaximumStock($calculatedStock > 0 ? floor($calculatedStock) : 0, $shopId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $originalStock
|
||||
* @param int $shopId
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function recalculateForMaximumStock(float $originalStock, int $shopId): float
|
||||
{
|
||||
if (!isset($this->maximumStockForShop[$shopId])) {
|
||||
$this->getMaximumStockForShop($shopId);
|
||||
}
|
||||
|
||||
if ($this->maximumStockForShop[$shopId] > 0) {
|
||||
return $originalStock < $this->maximumStockForShop[$shopId]
|
||||
? $originalStock : $this->maximumStockForShop[$shopId];
|
||||
}
|
||||
|
||||
return $originalStock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopId
|
||||
*/
|
||||
private function getMaximumStockForShop(int $shopId): void
|
||||
{
|
||||
$sql = "SELECT s.einstellungen_json
|
||||
FROM `shopexport` AS `s`
|
||||
WHERE s.id = :shop_id
|
||||
LIMIT 1";
|
||||
|
||||
$values = ['shop_id' => $shopId];
|
||||
$importerSettings = $this->db->fetchValue($sql, $values);
|
||||
|
||||
$maximumStock = 0;
|
||||
if (!empty(json_decode($importerSettings, true))) {
|
||||
$importerSettings = json_decode($importerSettings, true);
|
||||
$maximumStock = $importerSettings['felder']['lagerbestandmaxmenge'];
|
||||
}
|
||||
|
||||
$this->maximumStockForShop[$shopId] = (float)$maximumStock;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
function loggingPositionsMoreData(){
|
||||
oMoreData1stocklogging = $('#show_errors_only').prop("checked")?1:0;
|
||||
var oTableL = $('#stocklogging').dataTable();
|
||||
oTableL.fnFilter('a');
|
||||
oTableL.fnFilter('');
|
||||
}
|
||||
Reference in New Issue
Block a user