SuperSeller3000/src/Infrastructure/Channel/Ebay/EbayAdapter.php

153 lines
4.8 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace App\Infrastructure\Channel\Ebay;
use App\Application\Channel\ChannelAdapterInterface;
use App\Domain\Article\Article;
use App\Domain\Article\ArticleCondition;
use App\Domain\Order\Order;
final class EbayAdapter implements ChannelAdapterInterface
{
public function __construct(
private readonly EbayInventoryApiClient $apiClient,
) {
}
public function getType(): string
{
return 'ebay';
}
public function publishListing(Article $article): string
{
$sku = $article->getSku();
$this->apiClient->upsertInventoryItem($sku, [
'availability' => [
'shipToLocationAvailability' => [
'quantity' => $article->getStock(),
],
],
'condition' => $this->mapCondition($article->getCondition()),
'conditionDescription' => $article->getConditionNotes() ?? '',
'product' => [
'title' => $article->getEbayTitle() ?? $article->getSku(),
'description' => $article->getEbayDescription() ?? '',
'aspects' => $this->buildAspects($article),
],
]);
$offerId = $this->apiClient->createOffer([
'sku' => $sku,
'marketplaceId' => 'EBAY_DE',
'format' => 'FIXED_PRICE',
'availableQuantity' => $article->getStock(),
'pricingSummary' => [
'price' => [
'currency' => 'EUR',
'value' => number_format((float) ($article->getListingPrice() ?? '0'), 2, '.', ''),
],
],
'listingDescription' => $article->getEbayDescription() ?? '',
'categoryId' => $this->getCategoryId(),
]);
return $this->apiClient->publishOffer($offerId);
}
public function updateStock(Article $article, int $stock): void
{
$this->apiClient->bulkUpdateInventoryItems([
'requests' => [
[
'sku' => $article->getSku(),
'shipToLocationAvailability' => [
'quantity' => $stock,
],
],
],
]);
}
public function deactivateListing(Article $article): void
{
$listingId = $article->getEbayListingId();
if (null === $listingId) {
return;
}
$this->apiClient->withdrawOffer($listingId);
}
public function pushTracking(Order $order): void
{
if (null === $order->getTrackingNumber()) {
throw new \RuntimeException('Order has no tracking number');
}
$this->apiClient->addTrackingToOrder($order->getPlatformOrderId(), [
'lineItems' => [
['lineItemId' => $order->getPlatformOrderId(), 'quantity' => 1],
],
'shippingCarrierCode' => $order->getCarrier() ?? 'DHL',
'trackingNumber' => $order->getTrackingNumber(),
]);
}
private function mapCondition(ArticleCondition $condition): string
{
return match ($condition) {
ArticleCondition::New => 'NEW',
ArticleCondition::LikeNew => 'LIKE_NEW',
ArticleCondition::Good => 'GOOD',
ArticleCondition::Acceptable => 'ACCEPTABLE',
};
}
/** @return array<string, list<string>> */
private function buildAspects(Article $article): array
{
$aspects = [];
// Index attribute values by definition ID for O(1) lookup
$valuesByDefId = [];
foreach ($article->getAttributeValues() as $value) {
$valuesByDefId[$value->getAttributeDefinition()->getId()->toRfc4122()] = $value->getValue();
}
foreach ($article->getArticleType()->getEbayMappings() as $mapping) {
$ebayName = $mapping->getEbayAspectName();
if ($mapping->getSourceType() === \App\Domain\Article\ArticleTypeEbayMapping::SOURCE_ARTICLE_FIELD) {
$getter = 'get'.ucfirst((string) $mapping->getArticleFieldKey());
if (!method_exists($article, $getter)) {
continue;
}
$fieldValue = $article->$getter();
if (null !== $fieldValue && '' !== (string) $fieldValue) {
$aspects[$ebayName] = [(string) $fieldValue];
}
} else {
$def = $mapping->getAttributeDefinition();
if (null === $def) {
continue;
}
$val = $valuesByDefId[$def->getId()->toRfc4122()] ?? null;
if (null !== $val) {
$aspects[$ebayName] = [$val];
}
}
}
return $aspects;
}
private function getCategoryId(): string
{
return '177';
}
}