1010use Magento \CatalogInventory \Api \RegisterProductSaleInterface ;
1111use Magento \Framework \Exception \LocalizedException ;
1212use Magento \InventoryCatalog \Model \GetSkusByProductIdsInterface ;
13- use Magento \InventoryReservations \Model \ReservationBuilderInterface ;
14- use Magento \InventoryReservationsApi \Api \AppendReservationsInterface ;
15- use Magento \InventorySalesApi \Api \Data \ItemToSellInterface ;
16- use Magento \InventorySalesApi \Api \Data \ItemToSellInterfaceFactory ;
17- use Magento \InventorySalesApi \Api \Data \SalesChannelInterface ;
18- use Magento \InventorySalesApi \Api \Data \SalesChannelInterfaceFactory ;
19- use Magento \InventorySalesApi \Api \Data \SalesEventInterface ;
20- use Magento \InventorySalesApi \Api \Data \SalesEventInterfaceFactory ;
2113use Magento \InventorySalesApi \Api \IsProductSalableForRequestedQtyInterface ;
22- use Magento \InventorySalesApi \Api \RegisterSalesEventInterface ;
2314use Magento \Store \Api \WebsiteRepositoryInterface ;
15+ use Magento \InventorySalesApi \Api \StockResolverInterface ;
16+ use Magento \InventoryCatalog \Model \GetProductTypesBySkusInterface ;
17+ use Magento \InventoryConfiguration \Model \IsSourceItemsAllowedForProductTypeInterface ;
18+ use Magento \InventorySalesApi \Api \Data \SalesChannelInterface ;
19+ use Magento \InventorySalesApi \Api \Data \ProductSalabilityErrorInterface ;
20+ use Magento \InventorySalesApi \Api \Data \ProductSalableResultInterface ;
2421
2522/**
2623 * Class provides around Plugin on RegisterProductSaleInterface::registerProductsSale
@@ -32,73 +29,53 @@ class ProcessRegisterProductsSalePlugin
3229 */
3330 private $ getSkusByProductIds ;
3431
35- /**
36- * @var ReservationBuilderInterface
37- */
38- private $ reservationBuilder ;
39-
40- /**
41- * @var AppendReservationsInterface
42- */
43- private $ appendReservations ;
44-
4532 /**
4633 * @var IsProductSalableForRequestedQtyInterface
4734 */
4835 private $ isProductSalableForRequestedQty ;
4936
50- /**
51- * @var RegisterSalesEventInterface
52- */
53- private $ registerSalesEvent ;
54-
55- /**
56- * @var SalesChannelInterfaceFactory
57- */
58- private $ salesChannelFactory ;
59-
6037 /**
6138 * @var WebsiteRepositoryInterface
6239 */
6340 private $ websiteRepository ;
6441
6542 /**
66- * @var SalesEventInterfaceFactory
43+ * @var StockResolverInterface
6744 */
68- private $ salesEventFactory ;
45+ private $ stockResolver ;
46+
47+ /*
48+ * @var GetProductTypesBySkusInterface
49+ */
50+ private $ getProductTypesBySkus ;
6951
7052 /**
71- * @var ItemToSellInterfaceFactory
53+ * @var IsSourceItemsAllowedForProductTypeInterface
7254 */
73- private $ itemToSellFactory ;
55+ private $ isSourceItemsAllowedForProductType ;
7456
7557 public function __construct (
7658 GetSkusByProductIdsInterface $ getSkusByProductIds ,
77- ReservationBuilderInterface $ reservationBuilder ,
78- AppendReservationsInterface $ appendReservations ,
7959 IsProductSalableForRequestedQtyInterface $ isProductSalableForRequestedQty ,
80- RegisterSalesEventInterface $ registerSalesEvent ,
81- SalesChannelInterfaceFactory $ salesChannelFactory ,
8260 WebsiteRepositoryInterface $ websiteRepository ,
83- SalesEventInterfaceFactory $ salesEventFactory ,
84- ItemToSellInterfaceFactory $ itemToSellFactory
61+ StockResolverInterface $ stockResolver ,
62+ GetProductTypesBySkusInterface $ getProductTypesBySkus ,
63+ IsSourceItemsAllowedForProductTypeInterface $ isSourceItemsAllowedForProductType
8564 ) {
8665 $ this ->getSkusByProductIds = $ getSkusByProductIds ;
87- $ this ->reservationBuilder = $ reservationBuilder ;
88- $ this ->appendReservations = $ appendReservations ;
8966 $ this ->isProductSalableForRequestedQty = $ isProductSalableForRequestedQty ;
90- $ this ->registerSalesEvent = $ registerSalesEvent ;
91- $ this ->salesChannelFactory = $ salesChannelFactory ;
9267 $ this ->websiteRepository = $ websiteRepository ;
93- $ this ->salesEventFactory = $ salesEventFactory ;
94- $ this ->itemToSellFactory = $ itemToSellFactory ;
68+ $ this ->stockResolver = $ stockResolver ;
69+ $ this ->getProductTypesBySkus = $ getProductTypesBySkus ;
70+ $ this ->isSourceItemsAllowedForProductType = $ isSourceItemsAllowedForProductType ;
9571 }
9672
9773 /**
9874 * @param RegisterProductSaleInterface $subject
9975 * @param callable $proceed
10076 * @param float[] $items
10177 * @param int|null $websiteId
78+ *
10279 * @return []
10380 * @throws LocalizedException
10481 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
@@ -107,45 +84,46 @@ public function aroundRegisterProductsSale(
10784 RegisterProductSaleInterface $ subject ,
10885 callable $ proceed ,
10986 $ items ,
110- $ websiteId = null ,
111- $ quoteId = null
87+ $ websiteId = null
11288 ) {
11389 if (empty ($ items )) {
11490 return [];
11591 }
11692 if (null === $ websiteId ) {
11793 throw new LocalizedException (__ ('$websiteId parameter is required ' ));
11894 }
119-
120- $ salesEventType = SalesEventInterface::TYPE_ORDER_PLACED ;
121- $ salesEventObjectType = SalesEventInterface::OBJECT_TYPE_QUOTE ;
122- $ salesEventObjectId = $ quoteId ;
123- if (null === $ quoteId ) {
124- $ salesEventType = 'none ' ;
125- $ salesEventObjectType = 'none ' ;
126- $ salesEventObjectId = 'none ' ;
127- }
128- /** @var SalesEventInterface $salesEvent */
129- $ salesEvent = $ this ->salesEventFactory ->create ([
130- 'type ' => $ salesEventType ,
131- 'objectType ' => $ salesEventObjectType ,
132- 'objectId ' => $ salesEventObjectId
133- ]);
134-
13595 $ productSkus = $ this ->getSkusByProductIds ->execute (array_keys ($ items ));
136- /** @var ItemToSellInterface[] $itemsToSell */
137- $ itemsToSell = [];
96+ $ itemsBySku = [];
13897 foreach ($ productSkus as $ productId => $ sku ) {
139- $ itemsToSell [] = $ this -> itemToSellFactory -> create ([ ' sku ' => $ sku , ' qty ' => $ items [$ productId ]]) ;
98+ $ itemsBySku [ $ sku] = $ items [$ productId ];
14099 }
141-
142100 $ websiteCode = $ this ->websiteRepository ->getById ($ websiteId )->getCode ();
143- $ salesChannel = $ this ->salesChannelFactory ->create ();
144- $ salesChannel ->setCode ($ websiteCode );
145- $ salesChannel ->setType (SalesChannelInterface::TYPE_WEBSITE );
146-
147- $ this ->registerSalesEvent ->execute ($ itemsToSell , $ salesChannel , $ salesEvent );
148-
101+ $ stockId = (int )$ this ->stockResolver ->get (SalesChannelInterface::TYPE_WEBSITE , $ websiteCode )->getStockId ();
102+ $ productTypes = $ this ->getProductTypesBySkus ->execute (array_keys ($ itemsBySku ));
103+ $ this ->checkItemsQuantity ($ itemsBySku , $ productTypes , $ stockId );
149104 return [];
150105 }
106+
107+ /**
108+ * Check whether all items salable
109+ *
110+ * @return void
111+ * @throws LocalizedException
112+ */
113+ private function checkItemsQuantity (array $ items , array $ productTypes , int $ stockId )
114+ {
115+ foreach ($ items as $ sku => $ qty ) {
116+ if (false === $ this ->isSourceItemsAllowedForProductType ->execute ($ productTypes [$ sku ])) {
117+ continue ;
118+ }
119+ /** @var ProductSalableResultInterface $isSalable */
120+ $ isSalable = $ this ->isProductSalableForRequestedQty ->execute ($ sku , $ stockId , $ qty );
121+ if (false === $ isSalable ->isSalable ()) {
122+ $ errors = $ isSalable ->getErrors ();
123+ /** @var ProductSalabilityErrorInterface $errorMessage */
124+ $ errorMessage = array_pop ($ errors );
125+ throw new LocalizedException (__ ($ errorMessage ->getMessage ()));
126+ }
127+ }
128+ }
151129}
0 commit comments