custom/plugins/AsbsStockWatcher/src/Subscriber/StockChangeSubscriber.php line 30

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Asbs\StockWatcher\Subscriber;
  3. use Psr\Log\LoggerInterface;
  4. use Shopware\Core\Framework\Context;
  5. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  7. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  8. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9. class StockChangeSubscriber implements EventSubscriberInterface
  10. {
  11.     private EntityRepository $productRepository;
  12.     private LoggerInterface $logger;
  13.     public function __construct(EntityRepository $productRepositoryLoggerInterface $logger)
  14.     {
  15.         $this->productRepository $productRepository;
  16.         $this->logger $logger;
  17.     }
  18.     public static function getSubscribedEvents(): array
  19.     {
  20.         return [
  21.             'product.written' => 'onProductWritten',
  22.         ];
  23.     }
  24.     public function onProductWritten(EntityWrittenEvent $event): void
  25.     {
  26.         $payloads $event->getPayloads();
  27.         $context $event->getContext();
  28.         foreach ($payloads as $payload) {
  29.             if (isset($payload['stock'])) {
  30.                 try {
  31.                     $this->logger->info('AsbsStockWatcher: Processing stock change', [
  32.                         'productId' => $payload['id'],
  33.                         'newStock' => $payload['stock']
  34.                     ]);
  35.                     
  36.                     $this->updateAvailablePseudo($payload['id'], $payload['stock'], $context);
  37.                 } catch (\Exception $e) {
  38.                     $this->logger->error('AsbsStockWatcher: Error updating pseudo sales', [
  39.                         'productId' => $payload['id'],
  40.                         'error' => $e->getMessage(),
  41.                         'trace' => $e->getTraceAsString()
  42.                     ]);
  43.                 }
  44.             }
  45.         }
  46.     }
  47.     private function updateAvailablePseudo(string $productIdint $stockContext $context): void
  48.     {
  49.         // Lade das Produkt mit seinen Custom Fields (ohne Parent-Association)
  50.         $criteria = new Criteria([$productId]);
  51.         $criteria->addAssociation('customFields');
  52.         
  53.         $product $this->productRepository->search($criteria$context)->first();
  54.         
  55.         if (!$product) {
  56.             return;
  57.         }
  58.         $customFields $product->getCustomFields() ?? [];
  59.         $parentCustomFields = [];
  60.         
  61.         // Wenn das Produkt ein Parent hat, lade es separat
  62.         if ($product->getParentId()) {
  63.             $parentCriteria = new Criteria([$product->getParentId()]);
  64.             $parentCriteria->addAssociation('customFields');
  65.             
  66.             $parent $this->productRepository->search($parentCriteria$context)->first();
  67.             if ($parent) {
  68.                 $parentCustomFields $parent->getCustomFields() ?? [];
  69.             }
  70.         }
  71.         
  72.         $this->logger->info('AsbsStockWatcher: Product data loaded', [
  73.             'productId' => $productId,
  74.             'hasParent' => $product->getParentId() !== null,
  75.             'parentId' => $product->getParentId(),
  76.             'productCustomFields' => $customFields,
  77.             'parentCustomFields' => $parentCustomFields
  78.         ]);
  79.         
  80.         // Shopware Vererbungslogik: Erst das Produkt selbst prüfen, dann Parent
  81.         $pseudoSales null;
  82.         
  83.         // Prüfe zuerst die Custom Fields des Produkts (dort sind auch vererbte Werte)
  84.         if (isset($customFields['pseudoSales']) && $customFields['pseudoSales'] !== null && $customFields['pseudoSales'] !== '') {
  85.             $pseudoSales $customFields['pseudoSales'];
  86.             $this->logger->info('AsbsStockWatcher: Using product own pseudoSales', [
  87.                 'productId' => $productId,
  88.                 'ownPseudoSales' => $pseudoSales
  89.             ]);
  90.         }
  91.         // Wenn nicht vorhanden und Parent Custom Fields geladen wurden
  92.         elseif (!empty($parentCustomFields)) {
  93.             $pseudoSales $parentCustomFields['pseudoSales'] ?? 0;
  94.             $this->logger->info('AsbsStockWatcher: Using parent pseudoSales', [
  95.                 'productId' => $productId,
  96.                 'parentId' => $product->getParentId(),
  97.                 'inheritedPseudoSales' => $pseudoSales
  98.             ]);
  99.         }
  100.         else {
  101.             $pseudoSales 0;
  102.             $this->logger->info('AsbsStockWatcher: No pseudoSales found, using default', [
  103.                 'productId' => $productId,
  104.                 'defaultPseudoSales' => $pseudoSales
  105.             ]);
  106.         }
  107.         
  108.         // Berechne neuen Wert für doncarne_available_pseudo
  109.         $doncarneAvailablePseudo $stock 10000 $pseudoSales $pseudoSales;
  110.         
  111.         // Update nur wenn sich der Wert geändert hat
  112.         if (($customFields['doncarne_available_pseudo'] ?? 0) !== $doncarneAvailablePseudo) {
  113.             $this->logger->info('AsbsStockWatcher: Updating doncarne_available_pseudo', [
  114.                 'productId' => $productId,
  115.                 'oldValue' => $customFields['doncarne_available_pseudo'] ?? 0,
  116.                 'newValue' => $doncarneAvailablePseudo,
  117.                 'pseudoSales' => $pseudoSales,
  118.                 'stock' => $stock
  119.             ]);
  120.             
  121.             // Nur das doncarne_available_pseudo Feld updaten
  122.             $updateData = [
  123.                 'id' => $productId,
  124.                 'customFields' => array_merge($customFields, [
  125.                     'doncarne_available_pseudo' => $doncarneAvailablePseudo
  126.                 ])
  127.             ];
  128.             
  129.             // Erstelle einen neuen Context ohne Validierung für interne Updates
  130.             $updateContext = clone $context;
  131.             $updateContext->addState(Context::SKIP_TRIGGER_FLOW);
  132.             
  133.             $this->productRepository->update([$updateData], $updateContext);
  134.         }
  135.     }
  136. }