custom/plugins/DreiwmBrandstetterPlugin/src/Subscriber/CheckoutSubscriber.php line 192

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace DreiwmBrandstetterPlugin\Subscriber;
  3. use DateTime;
  4. use DateTimeZone;
  5. use DreiwmBrandstetterPlugin\Core\Checkout\Cart\Custom\Error\CustomerTooLateForPackstationError;
  6. use DreiwmBrandstetterPlugin\DreiwmBrandstetterPlugin;
  7. use DreiwmBrandstetterPlugin\Service\DateValidator;
  8. use DreiwmBrandstetterPlugin\Service\PackingStationService;
  9. use DreiwmBrandstetterPlugin\Service\RadbotenService;
  10. use Exception;
  11. use Prophecy\Prophecy\Revealer;
  12. use Psr\Log\LoggerInterface;
  13. use Shopware\Core\Checkout\Cart\Delivery\Struct\Delivery;
  14. use Shopware\Core\Checkout\Cart\Event\CartSavedEvent;
  15. use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
  16. use Shopware\Core\Checkout\Cart\Order\CartConvertedEvent;
  17. use Shopware\Core\Checkout\Order\OrderEntity;
  18. use Shopware\Core\Framework\Context;
  19. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  20. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  21. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  22. use Shopware\Core\Framework\Log\LoggerFactory;
  23. use Shopware\Core\System\Snippet\SnippetService;
  24. use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
  25. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  26. use Symfony\Component\HttpFoundation\RequestStack;
  27. class CheckoutSubscriber implements EventSubscriberInterface
  28. {
  29.     private RequestStack $requestStack;
  30.     private EntityRepository $packstationRepository;
  31.     private DateValidator $dateValidator;
  32.     private EntityRepository $tagRepository;
  33.     private EntityRepository $orderRepository;
  34.     private RadbotenService $radbotenService;
  35.     private SnippetService $snippetService;
  36.     private PackingStationService $packingStationService;
  37.     private LoggerInterface $logger;
  38.     public function __construct(
  39.         RequestStack $requestStack,
  40.         EntityRepository $packsatationRepository,
  41.         DateValidator $dateValidator,
  42.         EntityRepository $tagRepository,
  43.         EntityRepository $orderRepository,
  44.         RadbotenService $radbotenService,
  45.         SnippetService $snippetService,
  46.         PackingStationService $packingStationService,
  47.         LoggerFactory $loggerFactory
  48.     ) {
  49.         $this->requestStack $requestStack;
  50.         $this->packstationRepository $packsatationRepository;
  51.         $this->dateValidator $dateValidator;
  52.         $this->tagRepository $tagRepository;
  53.         $this->orderRepository $orderRepository;
  54.         $this->radbotenService $radbotenService;
  55.         $this->snippetService $snippetService;
  56.         $this->packingStationService $packingStationService;
  57.         $this->logger $loggerFactory->createRotating('dreiwm_brandstetter_checkout_subscriber'7);
  58.     }
  59.     public static function getSubscribedEvents(): array
  60.     {
  61.         return [
  62.             CartConvertedEvent::class => 'processCheckout',
  63.             CheckoutOrderPlacedEvent::class => 'onOrderPlaced',
  64.         ];
  65.     }
  66.     /**
  67.      * Setzt den Tag "BestelldatumGleichLieferdatum" in die Bestellung, wenn das Bestelldatum gleich dem gewünschten Lieferdatum ist
  68.      * Setzt den Tag "BestelldatumIstNextDayKontingent" in die Bestellung, wenn das Bestelldatum größer als das gewünschte Lieferdatum ist
  69.      * @param CheckoutOrderPlacedEvent $event
  70.      * @throws Exception
  71.      */
  72.     public function onOrderPlaced(CheckoutOrderPlacedEvent $event): void
  73.     {
  74.         // Hole das gewünschte Lieferdatum aus den customFields
  75.         $orderCustomFields $event->getOrder()->getCustomFields();
  76.         if ($orderCustomFields === null || !array_key_exists('brandstetter_orders_desired_delivery_date',
  77.                 $orderCustomFields)) {
  78.             return;
  79.         }
  80.         $desiredDeliveryDate $orderCustomFields['brandstetter_orders_desired_delivery_date'];
  81.         // Erstelle ein DateTime-Objekt aus dem gewünschten Lieferdatum
  82.         $desiredDeliveryDate = new DateTime($desiredDeliveryDate, new DateTimeZone('Europe/Berlin'));
  83.         // Erstelle ein DateTime-Objekt für das heutige Datum
  84.         $today $this->dateValidator->getServerDateAndTime();
  85.         // Prüfe, ob das Bestelldatum heute ist
  86.         if ($desiredDeliveryDate->format('Y-m-d') == $today->format('Y-m-d')) {
  87.             // Setze den Tag "BestelldatumGleichLieferdatum" in die Bestellung
  88.             $this->setTagToOrder($event->getOrder(), 'BestelldatumGleichLieferdatum');
  89.         } elseif ($desiredDeliveryDate->format('Y-m-d') > $today->format('Y-m-d')) {
  90.             $lineItems $event->getOrder()->getLineItems();
  91.             $stdOptionFound false;
  92.             foreach ($lineItems as $lineItem) {
  93.                 if ($lineItem->getType() === 'product' && $lineItem->getPayload()['options'] !== null) {
  94.                     $options $lineItem->getPayload()['options'];
  95.                     // Gehe durch alle Optionen
  96.                     foreach ($options as $option) {
  97.                         if ($option['option'] === 'std') {
  98.                             $stdOptionFound true;
  99.                             break 2// Breche beide Schleifen ab, da "std" vorhanden ist
  100.                         }
  101.                     }
  102.                 }
  103.             }
  104.             if (!$stdOptionFound) {
  105.                 $this->setTagToOrder($event->getOrder(), 'BestelldatumIstNextDayKontingent');
  106.             }
  107.         }
  108.     }
  109.     /**
  110.      * Setzt den Tag in die Bestellung
  111.      * @param $order OrderEntity
  112.      * @param $tagName string
  113.      * @return void
  114.      */
  115.     private function setTagToOrder(OrderEntity $orderstring $tagName): void
  116.     {
  117.         // Erstelle ein Context-Objekt
  118.         $context Context::createDefaultContext();
  119.         // Hole das OrderRepository
  120.         $orderRepository $this->orderRepository;
  121.         // Erstelle ein neues Order-Array mit den erforderlichen Daten
  122.         $orderData = [
  123.             [
  124.                 'id' => $order->getId(),
  125.                 'orderNumber' => $order->getOrderNumber(),
  126.                 'tags' => [
  127.                     [
  128.                         'id' => $this->getTagId($tagName)
  129.                     ]
  130.                 ],
  131.             ]
  132.         ];
  133.         try {
  134.             // Speichere die Bestellung
  135.             $orderRepository->upsert($orderData$context);
  136.         } catch (Exception $e) {
  137.             // Fehlermeldung ausgeben
  138.             $this->logger->error('Fehler beim Setzen des Tags in die Bestellung: ' $e->getMessage()) . 'Bestellnummer:' $order->getOrderNumber();
  139.         }
  140.     }
  141.     /**
  142.      * Gibt die ID des Tags anhand des Tag-Namens zurück
  143.      * @param $tagName string
  144.      * @return mixed
  145.      */
  146.     public function getTagId(string $tagName): mixed
  147.     {
  148.         $criteria = new Criteria();
  149.         $criteria->addFilter(new EqualsFilter('name'$tagName));
  150.         $context Context::createDefaultContext();
  151.         $result $this->tagRepository->search($criteria$context)->first();
  152.         return $result->getId();
  153.     }
  154.     public function onCheckoutConfirmPageLoaded(CheckoutConfirmPageLoadedEvent $event): void
  155.     {
  156.         // Lieferart Paketstation holen
  157.         /** @var $shippingMethod Delivery */
  158.         $shippingMethod $event->getPage()->getCart()->getDeliveries()->first();
  159.         $shippingMethodId $shippingMethod->getShippingMethod()->getId();
  160.         // wenn Paketstation gewählt wurde
  161.         if ($shippingMethodId == DreiwmBrandstetterPlugin::PAKETSTATION_ID) {
  162.         }
  163.     }
  164.     /**
  165.      *
  166.      * @param CartConvertedEvent $event
  167.      * @throws Exception
  168.      */
  169.     public function processCheckout(CartConvertedEvent $event): void
  170.     {
  171.         $request $this->requestStack->getCurrentRequest();
  172.         // Wenn kein Request vorhanden ist, dann abbrechen
  173.         if ($request === null) {
  174.             return;
  175.         }
  176.         // Hole das '_routeScope'-Attribut
  177.         $routeScope $request->attributes->get('_routeScope');
  178.         // Wenn $routeScope von api kommt, dann ist es nicht aus dem Frontend, daher abbrechen
  179.         if ($routeScope !== null && in_array('api'$routeScope->getScopes())) {
  180.             return;
  181.         }
  182.         $orderData $event->getConvertedCart();
  183.         // bei Post nichts machen, da dort kein Datum übergeben wird
  184.         if ($orderData['deliveries'][0]['shippingMethodId'] == DreiwmBrandstetterPlugin::POST_ID) {
  185.             return;
  186.         }
  187.         $lo_serverDateAndTime = new DateTime('now', new DateTimeZone('Europe/Berlin'));
  188.         // muss ohne Zeitzone sein, da Shopware nur UTC akzeptiert im CustomField
  189.         $desiredDeliveryDateTime = new DateTime($this->requestStack->getCurrentRequest()->cookies->get("customerSelectedDate"));
  190.         // Prüfe, ob eine gewünschte Uhrzeit für die Radbotenlieferung übergeben wurde
  191.         // kann nur gewählt werden, wenn die Lieferart "Radboten" gewählt wurde
  192.         $ls_desiredRadbotenTimeRange $this->requestStack->getCurrentRequest()->request->get('BrandstetterDesiredRadbotenTimeRange');
  193.         if ($ls_desiredRadbotenTimeRange !== null) {
  194.             // $ls_desiredRadbotenTimeRange in den customFields des convertedCart speichern
  195.             $orderData['customFields']['brandstetter_orders_desired_delivery_timeRange_radboten'] = $ls_desiredRadbotenTimeRange;
  196.             // convertedCart mit den neuen Daten zurückgeben
  197.             $event->setConvertedCart($orderData);
  198.         }
  199.         // Abstellort für Radbotenlieferung
  200.         $ls_desiredDropOffLocation $this->requestStack->getCurrentRequest()->request->get('BrandstetterDropOffLocation');
  201.         if ($ls_desiredDropOffLocation !== null) {
  202.             // $ls_desiredDropOffLocation in den customFields des convertedCart speichern
  203.             $orderData['customFields']['brandstetter_orders_desired_dropoff_location'] = $ls_desiredDropOffLocation;
  204.             // convertedCart mit den neuen Daten zurückgeben
  205.             $event->setConvertedCart($orderData);
  206.         }
  207.         // prüfe ob Packstation gewählt wurde
  208.         $shippingMethodId $event->getConvertedCart()['deliveries'][0]['shippingMethodId'];
  209.         if ($shippingMethodId == DreiwmBrandstetterPlugin::PAKETSTATION_ID) {
  210.             $cartToken $event->getCart()->getToken();
  211.             $this->logger->info('Packstation gewählt für Warenkorb ' $cartToken);
  212.             // hole das Cart-Token
  213.             // suche nach dem Cart-Token in der Tabelle dreiwm_free_locker
  214.             $packstationRepository $this->packstationRepository;
  215.             $criteria = new Criteria();
  216.             $criteria->addFilter(new EqualsFilter('cartToken'$cartToken));
  217.             $context Context::createDefaultContext();
  218.             $packstationResult $packstationRepository->search($criteria$context)->first();
  219.             // wenn das Cart-Token gefunden wurde, dann speichere den CustomerPin und MerchantPin in den customFields des convertedCart
  220.             if ($packstationResult !== null) {
  221.                 // customerPin und merchantPin und box_name in den customFields des convertedCart speichern
  222.                 if ($packstationResult->getCustomerPin() !== null && $packstationResult->getMerchantPin() !== null && $packstationResult->getBoxName() !== null) {
  223.                     // kann immer noch empty sein
  224.                     $this->logger->info('Eintrag in dreiwm_free_locker für Warenkorb ' $cartToken, [
  225.                         'customerPin' => $packstationResult->getCustomerPin(),
  226.                         'merchantPin' => $packstationResult->getMerchantPin(),
  227.                         'boxName' => $packstationResult->getBoxName()
  228.                     ]);
  229.                 }
  230.                 $orderData['customFields']['brandstetter_orders_customer_pin'] = $packstationResult->getCustomerPin();
  231.                 $orderData['customFields']['brandstetter_orders_merchant_pin'] = $packstationResult->getMerchantPin();
  232.                 $orderData['customFields']['brandstetter_orders_box_name'] = $packstationResult->getBoxName();
  233.                 // convertedCart mit den neuen Daten zurückgeben
  234.             } else {
  235.                 $this->logger->info('Kein Eintrag in dreiwm_free_locker für Warenkorb ' $cartToken);
  236.                 // Fallback => wir versuchen ein weiteres Fach zu reservieren und holen die PINS
  237.                 // Copy, weil in reservePaketinLockerOnDate das Objekt verändert wird, weiter unten aber unverändert benötigt wird
  238.                 $desiredDeliveryDateTimeCopy = clone $desiredDeliveryDateTime;
  239.                 $reservedLockerData $this->packingStationService->reservePaketinLockerOnDate($desiredDeliveryDateTimeCopy$cartToken);
  240.                 if ($reservedLockerData != null) {
  241.                     $this->logger->info('Fallback generiert für Warenkorb ' $cartToken, [
  242.                         'customerPin' => $reservedLockerData['customerPin'],
  243.                         'merchantPin' => $reservedLockerData['merchantPin'],
  244.                         'boxName' => $reservedLockerData['boxName']
  245.                     ]);
  246.                     $orderData['customFields']['brandstetter_orders_customer_pin'] = $reservedLockerData['customerPin'];
  247.                     $orderData['customFields']['brandstetter_orders_merchant_pin'] = $reservedLockerData['merchantPin'];
  248.                     $orderData['customFields']['brandstetter_orders_box_name'] = $reservedLockerData['boxName'];
  249.                     // speichere das Cart-Token in 3wmfreelocker
  250.                     $packstationRepository->upsert([
  251.                         [
  252.                             'cartToken' => $event->getCart()->getToken(),
  253.                             'boxId' => $reservedLockerData['boxId'],
  254.                             'boxName' => $reservedLockerData['boxName'],
  255.                             'merchantPin' => $reservedLockerData['merchantPin'],
  256.                             'customerPin' => $reservedLockerData['customerPin'],
  257.                             'date' => $desiredDeliveryDateTime->format('Y-m-d'),
  258.                             'freeLocker' => 1,
  259.                         ]
  260.                     ], $context);
  261.                 } else {
  262.                     // Fehlermeldung CustomerTooLateForPackstationError
  263.                     $event->getCart()->addErrors(new CustomerTooLateForPackstationError());
  264.                     $this->logger->info('Kein weiteres Fach verfügbar für Warenkorb ' $cartToken);
  265.                 }
  266.             }
  267.             $event->setConvertedCart($orderData);
  268.             // convertedCart holen
  269.             $orderData $event->getConvertedCart();
  270.             // token aus dem Cart holen
  271.             $cartToken $event->getCart()->getToken();
  272.             // token in dreiwm_free_locker speichern
  273.             $this->packingStationService->markCartTokenAsUsedInFreeLockerRepo($cartToken);
  274.         }
  275.         $orderData['customFields']['brandstetter_orders_desired_delivery_date'] = $desiredDeliveryDateTime;
  276.         // ist die Shipping-Methode "Radboten" gewählt?
  277.         if ($this->dateValidator->isRadbotenShippingMethod($shippingMethodId)) {
  278.             // desiredDeliveryDate aus dem Cookie holen
  279.             $desiredDeliveryDate $this->requestStack->getCurrentRequest()->cookies->get("customerSelectedDate");
  280.             // desiredDeliveryDate in den customFields des convertedCart speichern
  281.             $orderData['customFields']['brandstetter_orders_desired_delivery_date'] = $desiredDeliveryDate;
  282.             // convertedCart mit den neuen Daten zurückgeben
  283.             $event->setConvertedCart($orderData);
  284.         }
  285.         // convertedCart mit den neuen Daten zurückgeben
  286.         $event->setConvertedCart($orderData);
  287.     }
  288.     public function checkFreeLocker($desiredDeliveryDate)
  289.     {
  290.         $desiredDeliveryDate $desiredDeliveryDate->format('Y-m-d');
  291.         // durchsuche das dreiwm_free_locker repository nach dem $desiredDeliveryDateParam
  292.         $packsatationRepository $this->packstationRepository;
  293.         $criteria = new Criteria();
  294.         $criteria->addFilter(new EqualsFilter('date'$desiredDeliveryDate));
  295.         $context Context::createDefaultContext();
  296.         // desiredDeliveryDate in der Tabelle suchen
  297.         $packstationResult $packsatationRepository->search($criteria$context)->first();
  298.         if ($packstationResult) {
  299. //            $this->saveOrderToPaketin();
  300.             $free_locker $packstationResult->getFreeLocker();
  301.             // Wenn das Datum gefunden wurde, dann schaue ob, free_locker größer als 0 ist
  302.             if ($free_locker) {
  303.                 // free_locker um 1 verringern
  304.                 $free_locker--;
  305.                 // free_locker in der Tabelle aktualisieren
  306.                 $packsatationRepository->update([
  307.                     [
  308.                         'id' => $packstationResult->getId(),
  309.                         'free_locker' => $free_locker
  310.                     ]
  311.                 ], $context);
  312.                 //@TODO: Datensatz in PAKETIN speichern
  313.             } else {
  314.                 // convertedCart zurückgeben mit Fehlermeldung dass Fach schon voll ist
  315. //                $event->setConvertedCart($orderData);
  316.             }
  317.         } // Wenn das Datum nicht gefunden wurde, dann erstelle das Datum in der Tabelle
  318.         else {
  319.             // free_locker in der Tabelle aktualisieren
  320.             $packsatationRepository->create([
  321.                 [
  322.                     'date' => $desiredDeliveryDate,
  323.                     'free_locker' => DreiwmBrandstetterPlugin::MAXIMUM_FREE_LOCKER 1
  324.                 ]
  325.             ], $context);
  326.             //TODO: Datensatz in PAKETIN speichern
  327.         }
  328.     }
  329. }