DistanceBasedAlgorithm.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\InventoryDistanceBasedSourceSelection\Model\Algorithms;
  8. use Magento\Framework\Exception\LocalizedException;
  9. use Magento\InventoryApi\Api\GetSourcesAssignedToStockOrderedByPriorityInterface;
  10. use Magento\InventoryApi\Api\Data\SourceInterface;
  11. use Magento\InventoryDistanceBasedSourceSelection\Model\DistanceProvider\GetDistanceFromSourceToAddress;
  12. use Magento\InventorySourceSelectionApi\Api\Data\AddressInterface;
  13. use Magento\InventorySourceSelectionApi\Model\Algorithms\Result\GetDefaultSortedSourcesResult;
  14. use Magento\InventorySourceSelectionApi\Api\Data\InventoryRequestInterface;
  15. use Magento\InventorySourceSelectionApi\Api\Data\SourceSelectionResultInterface;
  16. use Magento\InventorySourceSelectionApi\Model\SourceSelectionInterface;
  17. /**
  18. * {@inheritdoc}
  19. * This shipping algorithm just iterates over all the sources one by one in distance order
  20. */
  21. class DistanceBasedAlgorithm implements SourceSelectionInterface
  22. {
  23. /**
  24. * @var GetSourcesAssignedToStockOrderedByPriorityInterface
  25. */
  26. private $getSourcesAssignedToStockOrderedByPriority;
  27. /**
  28. * @var GetDefaultSortedSourcesResult
  29. */
  30. private $getDefaultSortedSourcesResult;
  31. /**
  32. * @var GetDistanceFromSourceToAddress
  33. */
  34. private $getDistanceFromSourceToAddress;
  35. /**
  36. * DistanceBasedAlgorithm constructor.
  37. *
  38. * @param GetSourcesAssignedToStockOrderedByPriorityInterface $getSourcesAssignedToStockOrderedByPriority
  39. * @param GetDefaultSortedSourcesResult $getDefaultSortedSourcesResult
  40. * @param GetDistanceFromSourceToAddress $getDistanceFromSourceToAddress
  41. */
  42. public function __construct(
  43. GetSourcesAssignedToStockOrderedByPriorityInterface $getSourcesAssignedToStockOrderedByPriority,
  44. GetDefaultSortedSourcesResult $getDefaultSortedSourcesResult,
  45. GetDistanceFromSourceToAddress $getDistanceFromSourceToAddress
  46. ) {
  47. $this->getSourcesAssignedToStockOrderedByPriority = $getSourcesAssignedToStockOrderedByPriority;
  48. $this->getDefaultSortedSourcesResult = $getDefaultSortedSourcesResult;
  49. $this->getDistanceFromSourceToAddress = $getDistanceFromSourceToAddress;
  50. }
  51. /**
  52. * @inheritdoc
  53. * @throws LocalizedException
  54. */
  55. public function execute(InventoryRequestInterface $inventoryRequest): SourceSelectionResultInterface
  56. {
  57. $destinationAddress = $inventoryRequest->getExtensionAttributes()->getDestinationAddress();
  58. if ($destinationAddress === null) {
  59. throw new LocalizedException(__('No destination address was provided in the request'));
  60. }
  61. $stockId = $inventoryRequest->getStockId();
  62. $sortedSources = $this->getEnabledSourcesOrderedByDistanceByStockId(
  63. $stockId,
  64. $destinationAddress
  65. );
  66. return $this->getDefaultSortedSourcesResult->execute($inventoryRequest, $sortedSources);
  67. }
  68. /**
  69. * Get enabled sources ordered by priority by $stockId
  70. *
  71. * @param int $stockId
  72. * @param AddressInterface $address
  73. * @return array
  74. *
  75. * @throws \Magento\Framework\Exception\InputException
  76. * @throws \Magento\Framework\Exception\LocalizedException
  77. */
  78. private function getEnabledSourcesOrderedByDistanceByStockId(
  79. int $stockId,
  80. AddressInterface $address
  81. ): array {
  82. // We keep priority order as computational base
  83. $sources = $this->getSourcesAssignedToStockOrderedByPriority->execute($stockId);
  84. $sources = array_filter($sources, function (SourceInterface $source) {
  85. return $source->isEnabled();
  86. });
  87. $distanceBySourceCode = $sortSources = $sourcesWithoutDistance = [];
  88. foreach ($sources as $source) {
  89. try {
  90. $distanceBySourceCode[$source->getSourceCode()] = $this->getDistanceFromSourceToAddress->execute(
  91. $source,
  92. $address
  93. );
  94. $sortSources[] = $source;
  95. } catch (LocalizedException $e) {
  96. $sourcesWithoutDistance[] = $source;
  97. }
  98. }
  99. // Sort sources by distance
  100. uasort(
  101. $sortSources,
  102. function (SourceInterface $a, SourceInterface $b) use ($distanceBySourceCode) {
  103. $distanceFromA = $distanceBySourceCode[$a->getSourceCode()];
  104. $distanceFromB = $distanceBySourceCode[$b->getSourceCode()];
  105. return ($distanceFromA < $distanceFromB) ? -1 : 1;
  106. }
  107. );
  108. return array_merge($sortSources, $sourcesWithoutDistance);
  109. }
  110. }