vendor/ezsystems/ezcommerce-shop/src/Silversolutions/Bundle/EshopBundle/Services/WebConnectorErpService.php line 49

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4.  * @license For full copyright and license information view LICENSE file distributed with this source code.
  5.  */
  6. namespace Silversolutions\Bundle\EshopBundle\Services;
  7. use eZ\Publish\Core\MVC\ConfigResolverInterface;
  8. use Monolog\Logger;
  9. use Silversolutions\Bundle\EshopBundle\Api\TemplateDebitorServiceInterface;
  10. use Silversolutions\Bundle\EshopBundle\Content\FieldInterface;
  11. use Silversolutions\Bundle\EshopBundle\Entities\Messages\CreateSalesOrderMessage;
  12. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\Contact;
  13. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\ItemTransfer;
  14. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\Order;
  15. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\Party;
  16. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\PartyPartyIdentification;
  17. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\StringObject;
  18. use Silversolutions\Bundle\EshopBundle\Entities\Messages\ItemtransferMessage;
  19. use Ibexa\Platform\Bundle\Commerce\Checkout\Entity\Basket;
  20. use Ibexa\Platform\Bundle\Commerce\Checkout\Entity\BasketLine;
  21. use Silversolutions\Bundle\EshopBundle\Event\Erp\ErpEvents;
  22. use Silversolutions\Bundle\EshopBundle\Event\Erp\OrderFailedEvent;
  23. use Silversolutions\Bundle\EshopBundle\Event\Erp\PreSubmitOrderEvent;
  24. use Silversolutions\Bundle\EshopBundle\Model\Price\PriceLine;
  25. use Silversolutions\Bundle\EshopBundle\Model\Price\PriceRequest;
  26. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\BuyerCustomerParty;
  27. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\BuyerCustomerPartyPartyPartyIdentification;
  28. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\ContactResponse;
  29. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\CustomerResponse;
  30. use Silversolutions\Bundle\EshopBundle\Entities\Messages\SelectContactMessage;
  31. use Silversolutions\Bundle\EshopBundle\Entities\Messages\SelectCustomerMessage;
  32. use Silversolutions\Bundle\EshopBundle\Exceptions\MessageInquiryException;
  33. use Silversolutions\Bundle\EshopBundle\Message\CalculateSalesPriceMessage;
  34. use Silversolutions\Bundle\EshopBundle\Services\Factory\SelectCustomerFactoryListener;
  35. use Silversolutions\Bundle\EshopBundle\Services\Factory\ItemtransferFactoryListener;
  36. use Silversolutions\Bundle\EshopBundle\Services\Transport\AbstractMessageTransport;
  37. use Siso\Bundle\PriceBundle\Model\Price;
  38. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\OrderOrderLine;
  39. use Silversolutions\Bundle\EshopBundle\Entities\Messages\Document\OrderResponse;
  40. use Siso\Bundle\VoucherBundle\Service\VoucherManager;
  41. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  42. /**
  43.  * This class is the interface to the Web-Connector communication. It provides
  44.  * the standard operations of the Web-Connector's webservice.
  45.  */
  46. class WebConnectorErpService extends AbstractErpService
  47. {
  48.     const DEFAULT_VARIANT_HANDLING self::VARIANT_HANDLING_SKU_ONLY;
  49.     const VARIANT_HANDLING_SKU_ONLY 'SKU_ONLY';
  50.     const VARIANT_HANDLING_SKU_AND_VARIANT 'SKU_AND_VARIANT';
  51.     /**
  52.      * @var MessageInquiryService
  53.      */
  54.     protected $messageInquiry;
  55.     /**
  56.      * @var AbstractMessageTransport
  57.      */
  58.     protected $transport;
  59.     /**
  60.      * @var EventDispatcherInterface
  61.      */
  62.     protected $eventDispatcher;
  63.     /**
  64.      * @var Logger
  65.      */
  66.     protected $logger;
  67.     /**
  68.      * @var ConfigResolverInterface
  69.      */
  70.     protected $configResolver;
  71.     /**
  72.      * @var string
  73.      */
  74.     protected $variantHandling;
  75.     /**
  76.      * true if the template debitor customer number should be used.
  77.      *
  78.      * @var bool
  79.      */
  80.     private $useTemplateDebitorCustomerNumber;
  81.     /**
  82.      * true if the template debitor contact number should be used.
  83.      *
  84.      * @var bool
  85.      */
  86.     private $useTemplateDebitorContactNumber;
  87.     /**
  88.      * @var TemplateDebitorServiceInterface
  89.      */
  90.     private $templateDebitorService;
  91.     /**
  92.      * The constructor. Initializes dependencies.
  93.      *
  94.      * @param MessageInquiryService $messageInquiry
  95.      * @param AbstractMessageTransport $transport
  96.      * @param ConfigResolverInterface $configResolver
  97.      * @param EventDispatcherInterface $eventDispatcher
  98.      * @param Logger $logger
  99.      * @param TemplateDebitorServiceInterface $templateDebitorService
  100.      */
  101.     public function __construct(
  102.         MessageInquiryService $messageInquiry,
  103.         AbstractMessageTransport $transport,
  104.         ConfigResolverInterface $configResolver,
  105.         EventDispatcherInterface $eventDispatcher,
  106.         Logger $logger,
  107.         TemplateDebitorServiceInterface $templateDebitorService
  108.     ) {
  109.         $this->messageInquiry $messageInquiry;
  110.         $this->transport $transport;
  111.         $this->logger $logger;
  112.         $this->eventDispatcher $eventDispatcher;
  113.         $this->configResolver $configResolver;
  114.         $this->templateDebitorService $templateDebitorService;
  115.         // set variant handling by configuration (see silver.eshop.yml, "silver_eshop.default.erp.variant_handling")
  116.         $this->variantHandling $this->configResolver->hasParameter('erp.variant_handling''silver_eshop')
  117.              ? $this->configResolver->getParameter('erp.variant_handling''silver_eshop')
  118.              : self::DEFAULT_VARIANT_HANDLING;
  119.     }
  120.     /**
  121.      * Sets properties.
  122.      */
  123.     public function setProperties()
  124.     {
  125.         $this->useTemplateDebitorCustomerNumber =
  126.             $this->configResolver->getParameter('use_template_debitor_customer_number''siso_core');
  127.         $this->useTemplateDebitorContactNumber =
  128.             $this->configResolver->getParameter('use_template_debitor_contact_number''siso_core');
  129.     }
  130.     /**
  131.      * This method will transform the price request into an ERP message object,
  132.      * request the price date from the ERP system and return the ERP response.
  133.      *
  134.      * @param PriceRequest $priceRequest
  135.      *
  136.      * @return OrderResponse|null
  137.      */
  138.     public function calculatePrices(PriceRequest $priceRequest)
  139.     {
  140.         // try to get the message instance
  141.         try {
  142.             /** @var CalculateSalesPriceMessage $calcPriceMessage */
  143.             $calcPriceMessage $this->messageInquiry->inquireMessage(
  144.                 StandardMessageFactoryListener::CALCULATEPRICE
  145.             );
  146.         } catch (MessageInquiryException $messageException) {
  147.             $this->exceptionLog($messageException);
  148.             return null;
  149.         }
  150.         // initialize request values and send message
  151.         if (!$calcPriceMessage instanceof CalculateSalesPriceMessage) {
  152.             $context = ['message' => $calcPriceMessage];
  153.             $this->logger->error('The created message is not of type: "CalculateSalesPriceMessage"'$context);
  154.             return null;
  155.         }
  156.         /** @var Order $orderDocument */
  157.         $orderDocument $calcPriceMessage->getRequestDocument();
  158.         $extendedData $priceRequest->getExtendedData();
  159.         //clone the parties in order not to change data in basket
  160.         /** @var Party $buyerParty */
  161.         $buyerParty = clone $priceRequest->getBuyerParty();
  162.         /** @var Party $invoiceParty */
  163.         $invoiceParty = clone $priceRequest->getInvoiceParty();
  164.         /** @var Party $deliveryParty */
  165.         $deliveryParty = clone $priceRequest->getDeliveryParty();
  166.         if ($buyerParty instanceof Party) {
  167.             $orderDocument->BuyerCustomerParty->Party $buyerParty;
  168.         } elseif ($invoiceParty instanceof Party) {
  169.             $orderDocument->BuyerCustomerParty->Party $invoiceParty;
  170.         }
  171.         // Initialize remaining data from PriceRequest
  172.         $calcPriceMessage->setCustomerId($priceRequest->getCustomerNumber());
  173.         $orderDocument->SesExtension->value['ContactNumber'] = $priceRequest->getContactNumber();
  174.         $orderDocument->AccountingCustomerParty->Party $invoiceParty;
  175.         $orderDocument->Delivery->DeliveryParty $deliveryParty;
  176.         $orderDocument->SesExtension->value['ShippingMethodCode'] = $priceRequest->getShippingMethod();
  177.         $orderDocument->PaymentMeans->PaymentMeansCode->value $priceRequest->getPaymentMethod();
  178.         $now = new \DateTime();
  179.         $orderDocument->IssueDate->value substr($now->format(\DateTime::ISO8601), 010);
  180.         foreach ($extendedData as $key => $value) {
  181.             if (!is_object($value)) {
  182.                 if (isset($orderDocument->SesExtension->value[$key])) {
  183.                     $this->logger->warning(
  184.                         'ErpPriceCalculation: Key conflict in SesExtension field. "'
  185.                         $key '" from PriceRequest\'s extendedData is already set in message.'
  186.                     );
  187.                 }
  188.                 $orderDocument->SesExtension->value[$key] = $value;
  189.             } else {
  190.                 $this->logger->warning(
  191.                     'ErpPriceCalculation: Object value in PriceRequest extendedData field: "'
  192.                     $key '". Objects can not be passed to SesExtension in ERP message.'
  193.                 );
  194.             }
  195.         }
  196.         // Initialize item lines from PriceRequest
  197.         $priceLines $priceRequest->getLines();
  198.         $variantSkuMap = [];
  199.         /** @var PriceLine $priceLine */
  200.         foreach ($priceLines as $priceLine) {
  201.             $sku $priceLine->getSku();
  202.             $qty $priceLine->getQuantity();
  203.             $variantCode $priceLine->getVariantCode();
  204.             if ($this->variantHandling === self::VARIANT_HANDLING_SKU_ONLY && !empty($variantCode)) {
  205.                 // Remember the sku since the ERP may not return the original sku in SKU_ONLY mode
  206.                 $variantSkuMap[$variantCode] = $sku;
  207.                 // In SKU_ONLY mode, the variant code is the actual SKU within the ERP system
  208.                 $sku $variantCode;
  209.                 $variantCode null;
  210.             }
  211.             $orderLine $calcPriceMessage->addRequestItemLine($sku$qty$variantCode);
  212.             $extendedData $priceLine->getExtendedData();
  213.             foreach ($extendedData as $key => $value) {
  214.                 if (!is_object($value)) {
  215.                     if (isset($orderLine->SesExtension->value[$key])) {
  216.                         $this->logger->warning(
  217.                             'ErpPriceCalculation: Key conflict in SesExtension field. "'
  218.                             $key '" from request PriceLine\'s extendedData is already set in message.'
  219.                         );
  220.                     }
  221.                     $orderLine->SesExtension->value[$key] = $value;
  222.                 } elseif ($value instanceof FieldInterface) {
  223.                     $orderLine->SesExtension->value[$key] = $value->toString();
  224.                 } else {
  225.                     $this->logger->warning(
  226.                         'ErpPriceCalculation: Object value in request PriceLine\'s extendedData field: "'
  227.                         $key '". Objects can not be passed to SesExtension in ERP message.'
  228.                     );
  229.                 }
  230.             }
  231.         }
  232.         try {
  233.             /** @var OrderResponse $response */
  234.             $response $this->transport->sendMessage($calcPriceMessage)
  235.                 ->getResponseDocument();
  236.             if (!$response instanceof OrderResponse) {
  237.                 $context = ['response' => $response];
  238.                 $this->logger->error('The response of the ERP transport is not valid.'$context);
  239.                 return null;
  240.             }
  241.             // Restore SKUs from the request as they got lost during the process in SKU_ONLY mode.
  242.             if ($this->variantHandling === self::VARIANT_HANDLING_SKU_ONLY) {
  243.                 foreach ($response->OrderLine as $responseOrderLine) {
  244.                     $sku $responseOrderLine->LineItem->Item->SellersItemIdentification->ID->value;
  245.                     // If the returned item was not stored in the map, it's not a variant or an additional line
  246.                     if (isset($variantSkuMap[$sku])) {
  247.                         $responseOrderLine->LineItem->Item->SellersItemIdentification->ExtendedID->value $sku;
  248.                         $responseOrderLine->LineItem->Item
  249.                             ->SellersItemIdentification->ID->value $variantSkuMap[$sku];
  250.                     }
  251.                 }
  252.             }
  253.         } catch (\RuntimeException $rtException) {
  254.             $this->exceptionLog($rtException);
  255.             return null;
  256.         }
  257.         return $response;
  258.     }
  259.     /**
  260.      * {@inheritdoc}
  261.      *
  262.      * The BuyerCustomerParty is set to the invoice party of the basket if no
  263.      * buyer party is available.
  264.      *
  265.      * The event ErpEvents::ORDER_FAILED is dispatched if an error occurs.
  266.      *
  267.      * @param Basket $basket
  268.      *
  269.      * @return OrderResponse|null
  270.      */
  271.     public function submitOrder(Basket $basket, array $params = [])
  272.     {
  273.         // try to get message instance
  274.         try {
  275.             /** @var CreateSalesOrderMessage $createSalesOrder */
  276.             $createSalesOrder $this->messageInquiry->inquireMessage(
  277.                 StandardMessageFactoryListener::CREATEORDER
  278.             );
  279.         } catch (MessageInquiryException $messageException) {
  280.             $this->exceptionLog($messageException);
  281.             return null;
  282.         }
  283.         // initialize request values and send message
  284.         if (!$createSalesOrder instanceof CreateSalesOrderMessage) {
  285.             $context = ['message' => $createSalesOrder];
  286.             $this->logger->error('The created message is not of type: "CreateSalesOrderMessage"'$context);
  287.             return null;
  288.         }
  289.         try {
  290.             //dispatch event before order is submitted
  291.             $preEvent = new PreSubmitOrderEvent();
  292.             $preEvent->setBasket($basket);
  293.             $this->eventDispatcher->dispatch($preEventErpEvents::PRE_SUBMIT_ORDER);
  294.             //if status is failed, order must be treated as lost order
  295.             if ($preEvent->getStatus() === PreSubmitOrderEvent::STATUS_FAILED) {
  296.                 $createSalesOrder->setResponseError($preEvent->getErrorMessage());
  297.                 throw new \RuntimeException($preEvent->getErrorMessage());
  298.             }
  299.             /** @var Order $request */
  300.             $request $createSalesOrder->getRequestDocument();
  301.             //clone the parties in order not to change data in basket
  302.             /** @var Party $buyerParty */
  303.             $buyerParty = clone $basket->getBuyerParty();
  304.             /** @var Party $invoiceParty */
  305.             $invoiceParty = clone $basket->getInvoiceParty();
  306.             /** @var Party $deliveryParty */
  307.             $deliveryParty = clone $basket->getDeliveryParty();
  308.             //check if buyer party is empty
  309.             if ($buyerParty instanceof Party
  310.                 && (count($buyerParty->PartyName) === 0
  311.                     || $buyerParty->PartyName[0]->Name->value === ''
  312.                     || $buyerParty->PartyName[0]->Name->value === null
  313.                 )
  314.             ) {
  315.                 $buyerParty = clone $invoiceParty;
  316.             }
  317.             $this->setProperCustomerAndContactNumber($buyerParty$invoiceParty$deliveryParty);
  318.             if ($buyerParty instanceof Party) {
  319.                 $request->BuyerCustomerParty->Party $buyerParty;
  320.             } elseif ($invoiceParty instanceof Party) {
  321.                 $request->BuyerCustomerParty->Party $invoiceParty;
  322.             } else {
  323.                 $this->logger->warning(
  324.                     'Neither buyer nor invoice party are given for order submission',
  325.                     ['basket_id' => $basket->getBasketId()]
  326.                 );
  327.             }
  328.             $request->BuyerCustomerParty->SupplierAssignedAccountID->value $basket->getUserId();
  329.             $request->AccountingCustomerParty->Party $invoiceParty;
  330.             $request->Delivery->DeliveryParty $deliveryParty;
  331.             $request->IssueDate->value substr($basket->getDateLastModified()->format(\DateTime::ISO8601), 010);
  332.             $request->DocumentCurrencyCode->value $basket->getTotalsSum()->getCurrency();
  333.             $request->UUID->value $basket->getGuid();
  334.             $request->CustomerReference->value $basket->getDataMap()['customerReference'];
  335.             // The comment is stored in "getRemark". It should be spllitted in 20 characters for the mapping
  336.             $newRemark wordwrap($basket->getRemark(), 20'||'true);
  337.             $request->SesExtension->value['Remark'] = $newRemark;
  338.             //$request->Delivery->RequestedDeliveryPeriod->EndDate->value = '';
  339.             $request->PaymentMeans->PaymentMeansCode->value $basket->getPaymentMethod();
  340.             $request->PaymentMeans->InstructionID->value $basket->getPaymentTransactionId();
  341.             //$request->TransactionConditions->ID->value = '';
  342.             $request->SesExtension->value['ShippingMethodCode'] = $basket->getShippingMethod();
  343.             //sets order lines
  344.             $this->setOrderLines($request$basket);
  345.             $dataMap $basket->getDataMap();
  346.             if (is_array($dataMap)) {
  347.                 foreach ($dataMap as $key => $value) {
  348.                     if (!is_object($value)) {
  349.                         //voucher identifier
  350.                         if (strpos($keyVoucherManager::VOUCHER_DATA_MAP_PREFIX) !== false) {
  351.                             $request->SesExtension->value[$key] = $value;
  352.                         } else {
  353.                             $request->SesExtension->value['BasketDataMap'][$key] = $value;
  354.                         }
  355.                     }
  356.                 }
  357.             }
  358.             /** @var OrderResponse $response */
  359.             $response $this->transport->sendMessage($createSalesOrder)
  360.                 ->getResponseDocument();
  361.             if (!$response instanceof OrderResponse) {
  362.                 $context = ['response' => $response];
  363.                 $this->logger->error('The response of the ERP transport is not valid.'$context);
  364.                 throw new \RuntimeException('submitOrder() failed!');
  365.             } else {
  366.                 return $response;
  367.             }
  368.         } catch (\RuntimeException $rtException) {
  369.             // Dispatch order failed event for additional custom processing
  370.             $orderFailedEvent = new OrderFailedEvent();
  371.             $orderFailedEvent->setBasket($basket);
  372.             $orderFailedEvent->setErpMessage($createSalesOrder);
  373.             $orderFailedEvent->setMaxCount(null);
  374.             $this->eventDispatcher->dispatch($orderFailedEventErpEvents::ORDER_FAILED);
  375.             $this->exceptionLog($rtException);
  376.             return null;
  377.         }
  378.     }
  379.     /**
  380.      * Sets the proper customer and contact number to the buyer and invoice party
  381.      * If no customer- and contact number are set, they are taken from the BuyerParty.
  382.      * If no customer- and contact number are set in the BuyerParty, the
  383.      * TemplateDebitorService is used to get the fallback customer- and
  384.      * contact number.
  385.      *
  386.      * @param Party $buyerParty
  387.      * @param Party $invoiceParty
  388.      * @param Party $deliveryParty
  389.      */
  390.     protected function setProperCustomerAndContactNumber(Party $buyerPartyParty $invoicePartyParty $deliveryParty)
  391.     {
  392.         $buyerCustomerNumber '';
  393.         $buyerContactNumber '';
  394.         if (isset($buyerParty->PartyIdentification[0])
  395.             && $buyerParty->PartyIdentification[0] instanceof PartyPartyIdentification
  396.         ) {
  397.             $buyerCustomerNumber $buyerParty->PartyIdentification[0]->ID->value;
  398.             $buyerContactNumber $buyerParty->Contact->ID->value;
  399.         }
  400.         if (empty($buyerCustomerNumber) && empty($buyerContactNumber)) {
  401.             if ($this->useTemplateDebitorCustomerNumber) {
  402.                 $fallbackCustomerNumber $this->templateDebitorService->getTemplateCustomerNumber(
  403.                     $buyerParty,
  404.                     $invoiceParty,
  405.                     $deliveryParty
  406.                 );
  407.                 $partyIdentification = new PartyPartyIdentification();
  408.                 $partyIdentification->ID->value = (string)$fallbackCustomerNumber;
  409.                 $buyerParty->PartyIdentification[] = $partyIdentification;
  410.                 $invoiceCustomerNumber null;
  411.                 if (!empty($invoiceParty->PartyIdentification)) {
  412.                     $invoiceCustomerNumber $invoiceParty->PartyIdentification[0]->ID->value;
  413.                 }
  414.                 if (empty($invoiceCustomerNumber)) {
  415.                     $invoiceParty->PartyIdentification[] = $partyIdentification;
  416.                 }
  417.             }
  418.             if ($this->useTemplateDebitorContactNumber) {
  419.                 $fallbackContactNumber $this->templateDebitorService->getTemplateContactNumber(
  420.                     $buyerParty,
  421.                     $invoiceParty,
  422.                     $deliveryParty
  423.                 );
  424.                 $buyerParty->Contact->ID->value $fallbackContactNumber;
  425.             }
  426.         }
  427.     }
  428.     /**
  429.      * sets order lines in order.
  430.      *
  431.      * @param Order $request
  432.      * @param Basket $basket
  433.      */
  434.     protected function setOrderLines(Order $requestBasket $basket)
  435.     {
  436.         $entityLines $basket->getLines();
  437.         $index 10;
  438.         foreach ($entityLines as $key => $entityLine) {
  439.             /** @var BasketLine $entityLine */
  440.             $orderLine = new OrderOrderLine();
  441.             $orderLine->Note[0] = new StringObject();
  442.             $orderLine->Note[0]->value $entityLine->getRemark();
  443.             $orderLine->LineItem->Item->SellersItemIdentification->ID->value $entityLine->getSku();
  444.             $orderLine->LineItem->Item->SellersItemIdentification->ExtendedID->value $entityLine->getVariantCode();
  445.             $orderLine->LineItem->Quantity->value $entityLine->getQuantity();
  446.             $orderLine->LineItem->Price->PriceAmount->value $entityLine->getLinePriceAmountNet();
  447.             $orderLine->LineItem->ID->value $index;
  448.             $orderLine->SesExtension->value['UnitOfMeasureCode'] = $entityLine->getUnit();
  449.             $orderLine->SesExtension->value['AmountInclVat'] = $entityLine->getLinePriceAmountGross();
  450.             //$orderLine->SesExtension->value['LineDiscountPercent'] = '';
  451.             $orderLine->SesExtension->value['LineRemark'] = $entityLine->getRemark();
  452.             $extendedData $entityLine->getRemoteDataMap();
  453.             foreach ($extendedData as $extendedDataKey => $value) {
  454.                 if (!is_object($value)) {
  455.                     if (isset($orderLine->SesExtension->value[$extendedDataKey])) {
  456.                         $this->logger->warning(
  457.                             'ErpPriceCalculation: Key conflict in SesExtension field. "'
  458.                             $extendedDataKey '" from request PriceLine\'s extendedData is already set in message.'
  459.                         );
  460.                     }
  461.                     $orderLine->SesExtension->value[$extendedDataKey] = $value;
  462.                 } elseif ($value instanceof FieldInterface) {
  463.                     $orderLine->SesExtension->value[$key] = $value->toString();
  464.                 } else {
  465.                     $this->logger->warning(
  466.                         'ErpPriceCalculation: Object value in request PriceLine\'s extendedData field: "'
  467.                         $extendedDataKey '". Objects can not be passed to SesExtension in ERP message.'
  468.                     );
  469.                 }
  470.             }
  471.             $request->OrderLine[] = $orderLine;
  472.             $index += 10;
  473.         }
  474.     }
  475.     /**
  476.      * {@inheritdoc}
  477.      *
  478.      * This implementation calls the select customer operation of the
  479.      * Web-Connector's webservice.
  480.      *
  481.      * $customerNumber may be a complete unique ID or a EPP specific wildcard
  482.      * query (12.. (NAV) requests all customer numbers starting with 12).
  483.      *
  484.      * @param string    $customerNumber
  485.      * @param int       $maxCount
  486.      * @param array     $params
  487.      *
  488.      * @return CustomerResponse
  489.      */
  490.     public function selectCustomer($customerNumber$maxCount 1, array $params = [])
  491.     {
  492.         // try to get message instance
  493.         try {
  494.             /** @var SelectCustomerMessage $selectCustomerMessage */
  495.             $selectCustomerMessage $this->messageInquiry->inquireMessage(
  496.                 SelectCustomerFactoryListener::SELECTCUSTOMER
  497.             );
  498.         } catch (MessageInquiryException $messageException) {
  499.             $this->exceptionLog($messageException);
  500.             return null;
  501.         }
  502.         // initialize request values and send message
  503.         if (!$selectCustomerMessage instanceof SelectCustomerMessage) {
  504.             $context = ['message' => $selectCustomerMessage];
  505.             $this->logger->error('The created message is not of type: "SelectCustomerMessage"'$context);
  506.             return null;
  507.         }
  508.         $selectCustomerMessage->setCustomerNumber($customerNumber);
  509.         try {
  510.             $response $this->transport->sendMessage($selectCustomerMessage)->getResponseDocument();
  511.             if (!$response instanceof CustomerResponse) {
  512.                 $context = ['response' => $response];
  513.                 $this->logger->error('The response of the ERP transport is not valid.'$context);
  514.                 return null;
  515.             }
  516.         } catch (\RuntimeException $rtException) {
  517.             $this->exceptionLog($rtException);
  518.             return null;
  519.         }
  520.         return $response;
  521.     }
  522.     /**
  523.      * Fetches contact data from ERP.
  524.      *
  525.      * @param $customerNumber
  526.      *
  527.      * @return object|null
  528.      */
  529.     private function fetchSelectContactResponse($customerNumber)
  530.     {
  531.         // try to get message instance
  532.         try {
  533.             /** @var SelectContactMessage $selectContactMessage */
  534.             $selectContactMessage $this->messageInquiry->inquireMessage(
  535.                 StandardMessageFactoryListener::SELECTCONTACT
  536.             );
  537.         } catch (MessageInquiryException $messageException) {
  538.             $this->exceptionLog($messageException);
  539.             return null;
  540.         }
  541.         // initialize request values and send message
  542.         if (!$selectContactMessage instanceof SelectContactMessage) {
  543.             $context = ['message' => $selectContactMessage];
  544.             $this->logger->error('The created message is not of type: "SelectContactMessage"'$context);
  545.             return null;
  546.         }
  547.         /** @var BuyerCustomerParty $selectContactRequest */
  548.         $selectContactRequest $selectContactMessage->getRequestDocument();
  549.         $partyIdentification = new BuyerCustomerPartyPartyPartyIdentification();
  550.         $partyIdentification->ID $customerNumber;
  551.         $selectContactRequest->Party->PartyIdentification[] = $partyIdentification;
  552.         try {
  553.             return $this->transport->sendMessage($selectContactMessage)->getResponseDocument();
  554.         } catch (\RuntimeException $rtException) {
  555.             $this->exceptionLog($rtException);
  556.             return null;
  557.         }
  558.         return null;
  559.     }
  560.     /**
  561.      * {@inheritdoc}
  562.      */
  563.     public function selectContact($customerNumber$contactNumber '', array $params = [])
  564.     {
  565.         $response $this->fetchSelectContactResponse($customerNumber);
  566.         if (!$response instanceof ContactResponse) {
  567.             return null;
  568.         }
  569.         // loop over all Contact objects in list, find correct Contact by its Contact->ID
  570.         foreach ($response->ErpContact->Contact as $contact) {
  571.             if ($contact->ID->value == $contactNumber) {
  572.                 return $contact;
  573.             }
  574.         }
  575.         return null;
  576.     }
  577.     /**
  578.      * Fetches contacts from the ERP.
  579.      *
  580.      * @param string $customerNumber
  581.      * @param array $params
  582.      *
  583.      * @return Contact[]
  584.      */
  585.     public function selectContacts($customerNumber, array $params = [])
  586.     {
  587.         $response $this->fetchSelectContactResponse($customerNumber);
  588.         if (!$response instanceof ContactResponse) {
  589.             return null;
  590.         }
  591.         if (is_array($response->ErpContact->Contact)) {
  592.             return $response->ErpContact->Contact;
  593.         }
  594.         return [];
  595.     }
  596.     /**
  597.      * Gets items from NAV.
  598.      *
  599.      * @param $itemNumber
  600.      * @param int $maxCount
  601.      *
  602.      * @return object
  603.      */
  604.     public function selectItem($itemNumber$maxCount 10)
  605.     {
  606.         /** @var ItemtransferMessage $selectItemMessage */
  607.         $selectItemMessage $this->messageInquiry->inquireMessage(ItemtransferFactoryListener::ITEMTRANSFER);
  608.         /** @var ItemTransfer $selectItemRequest */
  609.         $selectItemRequest $selectItemMessage->getRequestDocument();
  610.         $selectItemRequest->ITEM_MAXCOUNT->value $maxCount;
  611.         $selectItemRequest->ITEM_NO $itemNumber;
  612.         $response $this->transport->sendMessage($selectItemMessage)->getResponseDocument();
  613.         return $response;
  614.     }
  615.     /**
  616.      * Standard logging for exceptions in this class.
  617.      *
  618.      * @param \Exception $exception
  619.      */
  620.     protected function exceptionLog($exception)
  621.     {
  622.         $context = [
  623.             'exception' => $exception,
  624.         ];
  625.         $this->logger->debug(
  626.             'Exception: ' $exception->getMessage() . PHP_EOL $exception->getTraceAsString(),
  627.             $context
  628.         );
  629.     }
  630. }