OpenXE/classes/Modules/Ebay/Service/EbayListingService.php

449 lines
18 KiB
PHP
Raw Normal View History

2021-05-21 08:49:41 +02:00
<?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);
}
}