Skip to content

Commit

Permalink
Merge pull request magento#921 from magento-engcom/822-source-deducti…
Browse files Browse the repository at this point in the history
…on-for-virtual

MSI#822 Source deduction for virtual and downloadable products
  • Loading branch information
maghamed authored May 3, 2018
2 parents 46a2be5 + 8c40777 commit 8ffcf0a
Show file tree
Hide file tree
Showing 18 changed files with 1,544 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface SalesEventInterface
const EVENT_ORDER_PLACED = 'order_placed';
const EVENT_ORDER_CANCELED = 'order_canceled';
const EVENT_SHIPMENT_CREATED = 'shipment_created';
const EVENT_INVOICE_CREATED = 'invoice_created';
/**#@-*/

/**#@+
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,37 @@
*/
declare(strict_types=1);

use Magento\Framework\Event\ManagerInterface;
use Magento\Store\Api\Data\GroupInterface;
use Magento\Store\Api\Data\StoreInterface;
use Magento\Store\Model\Store;
use Magento\Store\Model\Website;
use Magento\TestFramework\Db\Sequence;
use Magento\TestFramework\Helper\Bootstrap;

$websiteCodes = ['eu_website', 'us_website', 'global_website'];

$store = Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class);
$objectManager = Bootstrap::getObjectManager();
/** @var ManagerInterface $eventManager */
$eventManager = $objectManager->create(ManagerInterface::class);
/** @var Sequence $sequence */
$sequence = $objectManager->create(Sequence::class);
/** @var StoreInterface $store */
$store = $objectManager->create(Store::class);
$store->load('default');
$rootCategoryId = $store->getRootCategoryId();

foreach ($websiteCodes as $key => $websiteCode) {
/** @var Website $website */
$website = Bootstrap::getObjectManager()->create(Website::class);
$website = $objectManager->create(Website::class);
$website->setData([
'code' => $websiteCode,
'name' => 'Test Website ' . $websiteCode,
'is_default' => '0',
]);
$website->save();

$store = Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class);
$store = $objectManager->create(Store::class);
$store->setCode(
'store_for_' . $websiteCode
)->setWebsiteId(
Expand All @@ -39,7 +49,7 @@
);

/** @var GroupInterface $group */
$group = Bootstrap::getObjectManager()->create(GroupInterface::class);
$group = $objectManager->create(GroupInterface::class);
$group->setName('store_view_' . $websiteCode);
$group->setCode('store_view_' . $websiteCode);
$group->setWebsiteId($website->getId());
Expand All @@ -51,8 +61,14 @@
$website->save();
$store->setGroupId($group->getId());
$store->save();
$eventManager->dispatch('store_add', ['store' => $store]);
}

$objectManager = Bootstrap::getObjectManager();
/**
* \Magento\TestFramework\Application by default generates 10 Sequence tables of each kind
* with indexes form 0 to 9, but last created Store id is greater than 9.
*/
$sequence->generateSequences($store->getId());

/* Refresh stores memory cache */
$objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->reinitStores();
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryShipping\Model;

use Magento\Framework\Exception\InputException;
use Magento\InventoryCatalog\Model\GetSkusByProductIdsInterface;
use Magento\InventorySales\Model\StockByWebsiteIdResolver;
use Magento\InventorySourceSelectionApi\Api\Data\InventoryRequestInterface;
use Magento\InventorySourceSelectionApi\Api\Data\InventoryRequestInterfaceFactory;
use Magento\InventorySourceSelectionApi\Api\Data\ItemRequestInterfaceFactory;
use Magento\Sales\Api\Data\InvoiceInterface;
use Magento\Sales\Api\Data\InvoiceItemInterface;
use Magento\Sales\Api\Data\OrderItemInterface;
use Traversable;

/**
* Creates instance of InventoryRequestInterface by given InvoiceInterface object.
* Only virtual type items will be used.
*/
class InventoryRequestFromInvoiceFactory
{
/**
* @var GetSkusByProductIdsInterface
*/
private $getSkusByProductIds;

/**
* @var ItemRequestInterfaceFactory
*/
private $itemRequestFactory;

/**
* @var InventoryRequestInterfaceFactory
*/
private $inventoryRequestFactory;

/**
* @var StockByWebsiteIdResolver
*/
private $stockByWebsiteIdResolver;

/**
* @param GetSkusByProductIdsInterface $getSkusByProductIds
* @param ItemRequestInterfaceFactory $itemRequestFactory
* @param StockByWebsiteIdResolver $stockByWebsiteIdResolver
* @param InventoryRequestInterfaceFactory $inventoryRequestFactory
*/
public function __construct(
GetSkusByProductIdsInterface $getSkusByProductIds,
ItemRequestInterfaceFactory $itemRequestFactory,
StockByWebsiteIdResolver $stockByWebsiteIdResolver,
InventoryRequestInterfaceFactory $inventoryRequestFactory
) {
$this->getSkusByProductIds = $getSkusByProductIds;
$this->itemRequestFactory = $itemRequestFactory;
$this->inventoryRequestFactory = $inventoryRequestFactory;
$this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver;
}

/**
* @param InvoiceInterface $invoice
* @return InventoryRequestInterface
* @throws InputException
*/
public function create(InvoiceInterface $invoice): InventoryRequestInterface
{
$order = $invoice->getOrder();
$websiteId = $order->getStore()->getWebsiteId();
$stockId = (int)$this->stockByWebsiteIdResolver->get((int)$websiteId)->getStockId();

/** @var InventoryRequestInterface $inventoryRequest */
return $this->inventoryRequestFactory->create([
'stockId' => $stockId,
'items' => $this->getSelectionRequestItems($invoice->getItems())
]);
}

/**
* @param InvoiceItemInterface[]|Traversable $invoiceItems
* @return array
* @throws InputException
*/
private function getSelectionRequestItems(Traversable $invoiceItems): array
{
$selectionRequestItems = [];
foreach ($invoiceItems as $invoiceItem) {
if (!$invoiceItem->getOrderItem()->getIsVirtual()) {
continue;
}

$itemSku = $invoiceItem->getSku() ?: $this->getSkusByProductIds->execute(
[$invoiceItem->getProductId()]
)[$invoiceItem->getProductId()];
$qty = $this->castQty($invoiceItem->getOrderItem(), $invoiceItem->getQty());

$selectionRequestItems[] = $this->itemRequestFactory->create([
'sku' => $itemSku,
'qty' => $qty,
]);
}
return $selectionRequestItems;
}

/**
* @param OrderItemInterface $item
* @param string|int|float $qty
* @return float|int
*/
private function castQty(OrderItemInterface $item, $qty)
{
if ($item->getIsQtyDecimal()) {
$qty = (double)$qty;
} else {
$qty = (int)$qty;
}

return $qty > 0 ? $qty : 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\InventoryShipping\Model;

use Magento\InventorySalesApi\Api\Data\SalesEventInterface;
use Magento\InventoryShipping\Model\SourceDeduction\Request\ItemToDeductInterface;
use Magento\InventoryShipping\Model\SourceDeduction\Request\ItemToDeductInterfaceFactory;
use Magento\InventoryShipping\Model\SourceDeduction\Request\SourceDeductionRequestInterface;
use Magento\InventoryShipping\Model\SourceDeduction\Request\SourceDeductionRequestInterfaceFactory;
use Magento\InventorySourceSelectionApi\Api\Data\SourceSelectionItemInterface;
use Magento\InventorySourceSelectionApi\Api\Data\SourceSelectionResultInterface;

class SourceDeductionRequestsFromSourceSelectionFactory
{
/**
* @var SourceDeductionRequestInterfaceFactory
*/
private $sourceDeductionRequestFactory;

/**
* @var ItemToDeductInterfaceFactory
*/
private $itemToDeductFactory;

/**
* @param SourceDeductionRequestInterfaceFactory $sourceDeductionRequestFactory
* @param ItemToDeductInterfaceFactory $itemToDeductFactory
*/
public function __construct(
SourceDeductionRequestInterfaceFactory $sourceDeductionRequestFactory,
ItemToDeductInterfaceFactory $itemToDeductFactory
) {
$this->sourceDeductionRequestFactory = $sourceDeductionRequestFactory;
$this->itemToDeductFactory = $itemToDeductFactory;
}

/**
* @param SourceSelectionResultInterface $sourceSelectionResult
* @param SalesEventInterface $salesEvent
* @param int $websiteId
* @return SourceDeductionRequestInterface[]
*/
public function create(
SourceSelectionResultInterface $sourceSelectionResult,
SalesEventInterface $salesEvent,
int $websiteId
): array {
$sourceDeductionRequests = [];
foreach ($this->getItemsPerSource($sourceSelectionResult->getSourceSelectionItems()) as $sourceCode => $items) {
/** @var SourceDeductionRequestInterface[] $sourceDeductionRequests */
$sourceDeductionRequests[] = $this->sourceDeductionRequestFactory->create([
'websiteId' => $websiteId,
'sourceCode' => $sourceCode,
'items' => $items,
'salesEvent' => $salesEvent
]);
}
return $sourceDeductionRequests;
}

/**
* @param SourceSelectionItemInterface[] $sourceSelectionItems
* @return ItemToDeductInterface[]
*/
private function getItemsPerSource(array $sourceSelectionItems)
{
$itemsPerSource = [];
foreach ($sourceSelectionItems as $sourceSelectionItem) {
if (!isset($itemsPerSource[$sourceSelectionItem->getSourceCode()])) {
$itemsPerSource[$sourceSelectionItem->getSourceCode()] = [];
}
$itemsPerSource[$sourceSelectionItem->getSourceCode()][] = $this->itemToDeductFactory->create([
'sku' => $sourceSelectionItem->getSku(),
'qty' => $sourceSelectionItem->getQtyToDeduct(),
]);
}
return $itemsPerSource;
}
}
Loading

0 comments on commit 8ffcf0a

Please sign in to comment.