custom/plugins/ProcLiveOrderHistory/src/Subscriber/LiveOrderHistorySubscriber.php line 112

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Proc\ProcLiveOrderHistory\Subscriber;
  3. use Proc\ProcFoundation\Helper\ErrorHandler;
  4. use Proc\ProcFoundation\Helper\RequestHandler;
  5. use Proc\ProcFoundation\Service\ProcFoundationService;
  6. use Proc\ProcLiveOrderHistory\Helper\OrderHistoryStruct;
  7. use Proc\ProcLiveOrderHistory\Helper\BuildRequestHelper;
  8. use Shopware\Storefront\Page\Account\Order\AccountOrderPageLoadedEvent;
  9. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  13. use DateTime;
  14. use Exception;
  15. /**
  16.  * Class LiveOrderHistorySubscriber
  17.  * @package Proc\ProcLiveOrderHistory\Subscriber
  18.  */
  19. class LiveOrderHistorySubscriber implements EventSubscriberInterface
  20. {
  21.     private const PATH_HEADLIST '/iman/order-history-headlist';
  22.     private const PATH_DETAILS '/iman/order-history-details';
  23.     /**
  24.      * @todo
  25.      * Richtig muss es '/iman/order-history-document' heißen. Dies muss aber noch im iMan angepasst werden.
  26.      */
  27.     private const PATH_DOCUMENTS '/iman/order-history-documents';
  28. //     private const PATH_DOCUMENTS = '/iman/order-history-document';
  29.     /**
  30.      * @var RequestHandler
  31.      */
  32.     private $requestHandler;
  33.     /**
  34.      * @var ErrorHandler
  35.      */
  36.     private $errorHandler;
  37.     /**
  38.      * @var string
  39.      */
  40.     private $host,
  41.             $port,
  42.             $customerNumber,
  43.             $fromDate,
  44.             $toDate;
  45.     private $error null;
  46.     /**
  47.      * @var ProcFoundationService
  48.      */
  49.     private $foundationService;
  50.     /**
  51.      * @var AccountOrderPageLoadedEvent
  52.      */
  53.     private $event;
  54.     /**
  55.      * @var int
  56.      */
  57.     private $elementsPerPage,
  58.             $page;
  59.     /**
  60.      * @var EntityRepositoryInterface
  61.      */
  62.     private $productRepository;
  63.     /**
  64.      * @var Context
  65.      */
  66.     private $context;
  67.     /**
  68.      * @inheritDoc
  69.      */
  70.     public static function getSubscribedEvents()
  71.     {
  72.         return [
  73.             AccountOrderPageLoadedEvent::class => ['onAccountOrderPageLoaded' ,1]
  74.         ];
  75.     }
  76.     /**
  77.      * LiveOrderHistorySubscriber constructor.
  78.      * @param ProcFoundationService $foundationService
  79.      * @param RequestHandler $requestHandler
  80.      * @param ErrorHandler $errorHandler
  81.      * @throws Exception
  82.      */
  83.     public function __construct(ProcFoundationService $foundationServiceRequestHandler $requestHandlerErrorHandler $errorHandlerEntityRepositoryInterface  $productRepository)
  84.     {
  85.         $this->foundationService $foundationService;
  86.         $this->requestHandler $requestHandler;
  87.         $this->errorHandler $errorHandler;
  88.         $this->productRepository $productRepository;
  89.     }
  90.     /**
  91.      * @param AccountOrderPageLoadedEvent $event
  92.      */
  93.     public function onAccountOrderPageLoaded(AccountOrderPageLoadedEvent $event)
  94.     {
  95.         $this->event $event;
  96.         /**
  97.          * Prüfung ob Benutzer angemeldet ist, sonst keine Live-Abfrage.
  98.          */
  99.         if (!($this->checkLogin()) || !($this->checkConfig()))
  100.         {
  101.             $orderNotComplete['fromDate'] = (new DateTime())->format('Y-m-d');
  102.             $orderNotComplete['toDate'] = (new DateTime())->format('Y-m-d');
  103.             $orderNotComplete['numElements'] = 0;
  104.             $orderNotComplete['order-history-list'] = '';
  105.             $orderNotCompleteStruct = new OrderHistoryStruct();
  106.             $orderNotCompleteStruct->setOrderHistory($orderNotComplete);
  107.             $this->event->getPage()->addExtension('order_history'$orderNotCompleteStruct);
  108.             return;
  109.         }
  110.         $this->handleOrderHistory();
  111.     }
  112.     private function checkLogin()
  113.     {   
  114.         $this->customerNumber $this->foundationService->checkLogin($this->event->getSalesChannelContext(), (string)get_class($this));
  115.         $this->context $this->event->getSalesChannelContext()->getContext();
  116.         if (!($this->customerNumber)) return false;
  117.         return true;
  118.     }
  119.     /**
  120.      * Hauptfunktion welche das einlesen der OrderHistory primär steuert.
  121.      * Die OrderHistory wird anhand vorhandener Daten eingelesen. Wird kein Datum ermittelt werden alle Order von 1.1.2021 bis zum aktuellen Datum vom iMan geholt.
  122.      * Standard Anzahl der Elemente pro Seite ist bei 10, kann aber über das Menü der OrderHistory auch anders ausgewählt werden.
  123.      */
  124.     public function handleOrderHistory()
  125.     {
  126.         $request $this->event->getRequest();
  127.       
  128.         if ($request->getQueryString() == '') {
  129.             $orderNotComplete['fromDate'] = (new DateTime())->modify('-1 month')->format('Y-m-d');
  130.             $orderNotComplete['toDate'] = (new DateTime())->format('Y-m-d');
  131.             $orderNotComplete['numElements'] = 10;
  132.             $orderNotComplete['order-history-list'] = '';
  133.         }
  134.         $fromDate           $request->get('fromDate') ?? (new DateTime())->modify('-1 month')->format('Y-m-d');;
  135.         $toDate             $request->get('toDate') ?? (new DateTime())->format('Y-m-d');;
  136.         $this->elementsPerPage    $request->get('numElements') ? (int)$request->get('numElements') : null ?? 10;
  137.         $this->page               $request->get('page') ? (int)$request->get('page') : null ?? 1;
  138.         $orderHistory $this->getOrderHistory($fromDate$toDate);
  139.         if ($orderHistory['head']['status'] === 'NOK') {
  140.             $this->error $this->errorHandler->error($this->errorHandler::SAP_RESPONSE_ERRORget_class($this), 'SAP Status Fehler.' print_r($orderHistorytrue));
  141.             $this->errorHandler->writeErrorLog($this->error);
  142.             $orderNotComplete['fromDate'] = $request->get('fromDate');
  143.             $orderNotComplete['toDate'] = $request->get('toDate');
  144.             $orderNotComplete['numElements'] = 0;
  145.             $orderNotComplete['order-history-list'] = '';
  146.             $orderComplete['currentPage'] = $this->page;
  147.             $orderNotCompleteStruct = new OrderHistoryStruct();
  148.             $orderNotCompleteStruct->setOrderHistory($orderNotComplete);
  149.             $this->event->getPage()->addExtension('order_history'$orderNotCompleteStruct);
  150.         } else {
  151.             $orderHistory $this->formatOrderHistory($orderHistory);
  152.             $pageOrders $this->getOrdersPerPage($orderHistory);
  153.             $orderComplete $this->getOrderDetails($pageOrders);
  154.             // $numElements = count($orderComplete['order-history-list']['order']);
  155.             $numElements $this->elementsPerPage;
  156.             $orderComplete['numElements'] = $numElements;
  157.             if (null !== $qs $this->event->getRequest()->getQueryString()) {
  158.                 $qs '?'.$qs;
  159.             }
  160.             $orderComplete['baseUri'] = $this->event->getSalesChannelContext()->getSalesChannel()->getDomains()->first()->getUrl() .$this->event->getRequest()->getPathInfo().$qs;
  161.             $orderComplete['fromDate'] = $this->fromDate;
  162.             $orderComplete['toDate'] = $this->toDate;
  163.             $orderComplete['currentPage'] = $this->page;
  164.             $orderCompleteStruct = new OrderHistoryStruct();
  165.             $orderCompleteStruct->setOrderHistory($orderComplete);
  166.             $this->event->getPage()->addExtension('order_history'$orderCompleteStruct);
  167.         }
  168.     }
  169.     /**
  170.      * Nimm die Liste der OrderHistory-Elemente für die Zeit von-bis, wie beim Aufruf der getOrderHistory definiert
  171.      * schneidet" die Elemente für die gewünschte Seite aus und gibt das gekürzte Array zurück.
  172.      * @param $orderHistory
  173.      * @return array
  174.      */
  175.     protected function getOrdersPerPage($orderHistory) : array
  176.     {
  177.         $numElements count($orderHistory['order-history-list']['order']);
  178.         if ($this->page === '' || $this->elementsPerPage === '' || $this->elementsPerPage === null) {
  179.             $this->page 1;
  180.             $this->elementsPerPage 10;
  181.         }
  182.         if ($numElements <= $this->elementsPerPage) {
  183.             return $orderHistory;
  184.         }
  185.         $start = ($this->page 1) * $this->elementsPerPage;
  186.         $end = ($this->page $this->elementsPerPage) - 1;
  187.         $resultArray['head'] = $orderHistory['head'];
  188.         $resultArray['order-history-list']['order'] = array_slice($orderHistory['order-history-list']['order'], $start$this->elementsPerPage);
  189.         $resultArray['numPages'] = (int)ceil($numElements $this->elementsPerPage);
  190.         $resultArray['currentPage'] = $this->page;
  191.         return $resultArray;
  192.     }
  193.     /**
  194.      * Liest die OrderHistory aus und die hinterlegten Dokumente
  195.      * füllte das Basis-Array mit diesen Daten und gibt das angereicherte Array zurück.
  196.      * @param array $iterationArray
  197.      * @param int $shopInstance
  198.      * @param string $language
  199.      * @return array
  200.      */
  201.     protected function getOrderDetails(array $iterationArrayint $shopInstance 1string $language 'DE') : array
  202.     {
  203.         foreach ($iterationArray['order-history-list']['order'] as $key => $orderElement)
  204.         {
  205.             $params = [
  206.                 'shop-instance' => $shopInstance,
  207.                 'sap-order-id'  => $orderElement['sap-order-id'],
  208.                 'language'      => $language
  209.             ];
  210.             $buildRequestHelper = new BuildRequestHelper($params'details'$this->errorHandler);
  211.             /**
  212.              * @var string $request
  213.              */
  214.             $request $this->requestHandler->buildRequest($buildRequestHelper, (string)get_class($this));
  215.             if ($request !== '') {
  216.                 /**
  217.                  * @var string $detailResult
  218.                  */
  219.                 $detailResult $this->requestHandler->sendRequest($this->host$this->portself::PATH_DETAILS$request);
  220.             } else {
  221.                 $this->error $this->errorHandler->error($this->errorHandler::UNKNOWN_REQUESTget_class($this), 'Fehler im Aufbau des Request');
  222.                 $this->errorHandler->writeErrorLog($this->error);
  223.                 continue;
  224.             }
  225.             $detailArray RequestHandler::parseResult($detailResult);
  226.             if ($detailArray['head']['status'] === 'NOK' || count($detailArray) === 0) {
  227.                 continue;
  228.             }
  229.             /**
  230.              * Holen der Dokumente zu den einzelnen Orders
  231.              * @todo Deaktiviert, da SAP noch keine Dokumente liefern kann. Muss noch getestet werden, sobald SAP Dokumente liefern kan.
  232.              */
  233.             if (array_key_exists('sap-order-id'$detailArray['document-list']['document'])) {
  234.                 $detailIterationArray['head'] = $detailArray['head'];
  235.                 $detailIterationArray['document-list']['document'][0] = $detailArray['document-list']['document'];
  236.             } else {
  237.                 $detailIterationArray $detailArray;
  238.             }
  239.             /**
  240.              * @todo Die Foreach war für  um nur Rechunungen heraus zu filtern. Hier sollte es konfigurierbar gemacht werden.
  241.              */
  242.             foreach ($detailIterationArray['document-list']['document'] as $key2 => $documentElement)
  243.             {
  244.                 if (($documentElement['document-type-code'] != 'M') && ($documentElement['document-type-code'] != 'C'))
  245.                 {
  246.                     unset($detailIterationArray['document-list']['document'][$key2]);
  247.                 }
  248.             }
  249. //             $detailCompleteArray = $this->getOrderDocuments($detailIterationArray);
  250.             $iterationArray['order-history-list']['order'][$key]['document-list'] = $detailIterationArray['document-list'];
  251.             $iterationArray['order-history-list']['order'][$key]['head'] = $detailArray['head'];
  252.             if ($iterationArray['order-history-list']['order'][$key]['customer-order-id'] === []) {
  253.                 $iterationArray['order-history-list']['order'][$key]['customer-order-id'] = 'keine Kunden-Bestellnummer';
  254.             }
  255.             $totalAmount 0;
  256.             //check if an array of $detailArray['articles']['article'] is assocciative
  257.             if(array_key_exists('number'$detailArray['articles']['article'])) {
  258.                 //means that the order have only one article
  259.                 $additionaDataFromSW $this->fetchProductByReferenceNumber($detailArray['articles']['article']['number'], $detailArray['articles']['article']['short-text']);
  260.                 if($additionaDataFromSW ) {
  261.                     $detailArray['articles']['article'] = array_merge$detailArray['articles']['article'],$additionaDataFromSW);
  262.                 }
  263.                 $iterationArray['order-history-list']['order'][$key]['articles'][] = $detailArray['articles']['article'];
  264.                 $iterationArray['order-history-list']['order'][$key]['totalAmount'] = $detailArray['articles']['article']['net-position-sum'];
  265.             } else {
  266.                 foreach($detailArray['articles']['article'] as $lineItemKey => $lineItem) {
  267.                     $additionaDataFromSW $this->fetchProductByReferenceNumber($lineItem['number'], $lineItem['short-text']);
  268.                     if($additionaDataFromSW ) {
  269.                         $detailArray['articles']['article'][$lineItemKey] = array_merge$lineItem$additionaDataFromSW);
  270.                     }
  271.                     $totalAmount += $lineItem['net-position-sum'];
  272.                 }
  273.                 $iterationArray['order-history-list']['order'][$key]['articles'] = $detailArray['articles']['article'];
  274.                 $iterationArray['order-history-list']['order'][$key]['totalAmount'] = $totalAmount;
  275.             }
  276.             // @fts - Add discounts to array
  277.             $iterationArray['order-history-list']['order'][$key]['discounts'] = $detailArray['discounts'] ?? [];
  278.         }
  279.         return $iterationArray;
  280.     }
  281.     /**
  282.      * Liest die OrderDetails aus und die hinterlegten Dokumente
  283.      * füllte das Details-Array mit den Dokumenten und gibt das angereicherte Array zurück.
  284.      * @param array $detailsArray
  285.      * @param int$shopInstance
  286.      * @return array
  287.      * @todo In Controller auslagern, um die document.php im Plugin zu halten
  288.      */
  289.     public function getOrderDocuments(array $detailsArrayint $shopInstance 1)
  290.     {
  291.         foreach ($detailsArray['document-list']['document'] as $key => $documentElement)
  292.         {
  293.             /**
  294.              * @todo
  295.              * Hier muss noch wegen der Dokumententypen angepasst werden.
  296.              */
  297. //             if ($documentElement['document-type-code'] == 'M') {
  298.             if (true) {
  299.                 $params = [
  300.                     'shop-instance' => $shopInstance,
  301.                     'customer' => $this->customerNumber,
  302.                     'document-number' => $documentElement['document-number'],
  303.                     'document-type-code' => $documentElement['document-type-code']
  304.                 ];
  305.                 $buildRequestHelper = new BuildRequestHelper($params'documents'$this->errorHandler);
  306.                 /**
  307.                  * @var string $request
  308.                  */
  309.                 $request $this->requestHandler->buildRequest($buildRequestHelper, (string)get_class($this));
  310.                 if ($request !== '') {
  311.                     /**
  312.                      * @var string $documentResult
  313.                      */
  314.                     $documentResult $this->requestHandler->sendRequest($this->host$this->portself::PATH_DOCUMENTS$request);
  315.                 } else {
  316.                     $this->error $this->errorHandler->error($this->errorHandler::UNKNOWN_REQUESTget_class($this), 'Fehler im Aufbau des Request');
  317.                     $this->errorHandler->writeErrorLog($this->error);
  318.                     continue;
  319.                 }
  320.                 $documentArray RequestHandler::parseResult($documentResult);
  321.                 if ($documentArray['head']['status'] === 'NOK' || count($documentArray) === 0) {
  322.                     continue;
  323.                 }
  324.                 if (array_key_exists('data'$documentArray['head'])) {
  325.                     $documentIterationArray['data'] = $documentArray['head']['data'];
  326.                 } else {
  327.                     $documentIterationArray['data'] = $documentArray['head']['status'];
  328.                 }
  329.                 $detailsArray['document-list']['document'][$key]['document-data'] = $documentIterationArray['data'];
  330.             /**
  331.              * @todo Hier werden alle nicht Rechnungen entfernt. Muss raus genommen werden, wenn andere Dokumente gehen
  332.              */
  333.             } else {
  334.                 unset($detailsArray['document-list']['document'][$key]);
  335.             }
  336.         }
  337.         return $detailsArray;
  338.     }
  339.     /**
  340.      * Bereitet mit dem Requesthandler die Request auf und holt die Daten vom iMan
  341.      *
  342.      * @param string|null $fromDate
  343.      * @param string|null $toDate
  344.      * @param int $shopInstance
  345.      * @param string $language
  346.      * @return array
  347.      */
  348.     protected function getOrderHistory(string $fromDate null,
  349.                                        string $toDate null,
  350.                                        int $shopInstance 1,
  351.                                        string $language 'DE') : array
  352.     {
  353.         if ($fromDate !== null && $toDate !== null) {
  354.             $this->checkDateRange($fromDate$toDate);
  355.         }
  356.         if ($fromDate === null) {
  357.             $fromDate '2021-01-01';
  358.         }
  359.         if ($toDate === null) {
  360.             $toDate = (new DateTime())->format('Y-m-d');
  361.         }
  362.         $this->fromDate $fromDate;
  363.         $this->toDate $toDate;
  364.         $params = [
  365.             'shop-instance' => $shopInstance,
  366.             'customer'      => $this->customerNumber,
  367.             'date-from'     => $this->fromDate,
  368.             'date-to'       => $this->toDate,
  369.             'language'      => $language
  370.         ];
  371.         $buildRequestHelper = new BuildRequestHelper($params'headlist'$this->errorHandler);
  372.         /**
  373.          * @var string $request
  374.          */
  375.         $request $this->requestHandler->buildRequest($buildRequestHelper, (string)get_class($this));
  376.         if ($request !== '') {
  377.             /**
  378.              * @var string $result
  379.              */
  380.             $result $this->requestHandler->sendRequest($this->host$this->portself::PATH_HEADLIST$request);
  381.             $this->error $this->errorHandler->error($this->errorHandler::UNKNOWN_REQUESTget_class($this), 'Result: ' print_r($resulttrue));
  382.             $this->errorHandler->writeErrorLog($this->error);
  383.         } else {
  384.             /**
  385.              * @todo Fehlerbehandlung
  386.              */
  387.             Return array();
  388.         }
  389.         return $this->requestHandler->parseResult($result);
  390.     }
  391.     /**
  392.      * Prüft die übergebenen Daten auf ihren Wert und bei vertauschte Angabe werden diese ausgewechselt.
  393.      *
  394.      * @param string|null $fromDate
  395.      * @param string|null $toDate
  396.      */
  397.     protected function checkDateRange(string &$fromDatestring &$toDate) : void
  398.     {
  399.         try {
  400.             $startDate = new DateTime($fromDate);
  401.             $endDate = new DateTime($toDate);
  402.         } catch (Exception $e) {
  403.             $this->error $this->errorHandler->error($this->errorHandler::GENERAL_ERRORget_class($this), 'Eine Datumsangabe entspricht nicht dem vorgegeben Format. - ' $e->getCode() . ' - ' $e->getMessage());
  404.             $this->errorHandler->writeErrorLog($this->error);
  405.             $fromDate '';
  406.             $toDate '';
  407.         }
  408.         if ($endDate $startDate)
  409.         {
  410.             $fromDate   $endDate->format('Y-m-d');
  411.             $toDate     $startDate->format('Y-m-d');
  412.         }
  413.     }
  414.     /**
  415.      * Array des Response wird in ein einheitliches Format gebracht zur Vereinfachung der weiteren Handhabung
  416.      * @param array $orderHistory
  417.      * @return array
  418.      */
  419.     protected function formatOrderHistory(array $orderHistory) : array
  420.     {
  421.         if (array_key_exists('sap-order-id'$orderHistory['order-history-list']['order'])) {
  422.             $iterationArray['head'] = $orderHistory['head'];
  423.             $iterationArray['order-history-list']['order'][0] = $orderHistory['order-history-list']['order'];
  424.         } else {
  425.             $iterationArray $orderHistory;
  426.         }
  427.         if (empty($iterationArray['head']['customer']) || is_array($iterationArray['head']['customer'])) {
  428.             $iterationArray['head']['customer'] = $this->customerNumber;
  429.         }
  430.         return $iterationArray;
  431.     }
  432.     /**
  433.      * @return bool
  434.      */
  435.     private function checkConfig() : bool
  436.     {
  437.         if ($this->foundationService->getConfigStatus()) {
  438.             $this->host $this->foundationService->getHost();
  439.             $this->port $this->foundationService->getPort();
  440.             return true;
  441.         }
  442.         $this->error $this->errorHandler->error($this->errorHandler::CONFIG_NOT_VALIDget_class($this), 'Konnte die Konfiguration nicht ermitteln');
  443.         $this->errorHandler->writeErrorLog($this->error);
  444.         return false;
  445.     }
  446.     public function fetchProductByReferenceNumber(string $referenceNumberstring $orginalName)
  447.     {
  448.         $criteria = new Criteria();
  449.         $criteria->addFilter(new EqualsFilter('product.productNumber'$referenceNumber));
  450.         $product $this->productRepository->search($criteria$this->context)->first();
  451.         /** @var ProductEntity $product */
  452.         if (!$product) {
  453.             // throw new NotFoundException("Product with reference number {$referenceNumber} not found.");
  454.             return ['name' => $orginalName];
  455.         }
  456.         $result = [
  457.             'identifier' => $product->getId(),
  458.             'name' => $product->getTranslated()['name']
  459.         ];
  460.         return $result;
  461.     }
  462. }