diff --git a/app/code/Magento/InventoryInStorePickup/Model/ResourceModel/OrderPickupLocation/GetPickupLocationByOrderId.php b/app/code/Magento/InventoryInStorePickup/Model/ResourceModel/OrderPickupLocation/GetPickupLocationByOrderId.php new file mode 100644 index 000000000000..307b0bc7fe7b --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/Model/ResourceModel/OrderPickupLocation/GetPickupLocationByOrderId.php @@ -0,0 +1,56 @@ +connection = $connection; + } + + /** + * Fetch pickup location identifier by order identifier. + * + * @param int $orderId + * + * @return string|null + */ + public function execute(int $orderId): ?string + { + $connection = $this->connection->getConnection(); + $table = $this->connection->getTableName('inventory_pickup_location_order'); + + $select = $connection->select() + ->from($table, [self::PICKUP_LOCATION_CODE => self::PICKUP_LOCATION_CODE]) + ->where(self::ORDER_ID . '= ?', $orderId) + ->limit(1); + + $id = $connection->fetchOne($select); + + return $id ?: null; + } +} diff --git a/app/code/Magento/InventoryInStorePickup/Model/ResourceModel/OrderPickupLocation/SaveOrderPickupLocation.php b/app/code/Magento/InventoryInStorePickup/Model/ResourceModel/OrderPickupLocation/SaveOrderPickupLocation.php new file mode 100644 index 000000000000..15b07555f4e1 --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/Model/ResourceModel/OrderPickupLocation/SaveOrderPickupLocation.php @@ -0,0 +1,56 @@ +connection = $connection; + } + + /** + * Fetch pickup location identifier by order identifier. + * + * @param int $orderId + * @param string $pickupLocationCode + * + * @return void + */ + public function execute(int $orderId, string $pickupLocationCode): void + { + $connection = $this->connection->getConnection(); + $table = $this->connection->getTableName('inventory_pickup_location_order'); + + $data = [ + self::ORDER_ID => $orderId, + self::PICKUP_LOCATION_CODE => $pickupLocationCode + ]; + + $connection->insertOnDuplicate($table, $data); + } +} diff --git a/app/code/Magento/InventoryInStorePickup/Plugin/Sales/Order/GetPickupLocationForOrderPlugin.php b/app/code/Magento/InventoryInStorePickup/Plugin/Sales/Order/GetPickupLocationForOrderPlugin.php new file mode 100644 index 000000000000..fa34698bcebc --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/Plugin/Sales/Order/GetPickupLocationForOrderPlugin.php @@ -0,0 +1,73 @@ +orderExtensionFactory = $orderExtensionFactory; + $this->getPickupLocationByOrderId = $getPickupLocationByOrderId; + } + + /** + * Add Pickup Location Code extension attribute when loading Order with OrderRepository. + * + * @param OrderRepositoryInterface $orderRepository + * @param OrderInterface $order + * + * @return OrderInterface + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGet(OrderRepositoryInterface $orderRepository, OrderInterface $order): OrderInterface + { + $extension = $order->getExtensionAttributes(); + + if (empty($extension)) { + $extension = $this->orderExtensionFactory->create(); + } + + if ($extension->getPickupLocationCode()) { + return $order; + } + + $pickupLocationCode = $this->getPickupLocationByOrderId->execute((int)$order->getEntityId()); + + if ($pickupLocationCode) { + $extension->setPickupLocationCode($pickupLocationCode); + } + + $order->setExtensionAttributes($extension); + + return $order; + } +} diff --git a/app/code/Magento/InventoryInStorePickup/Plugin/Sales/Order/SavePickupLocationForOrderPlugin.php b/app/code/Magento/InventoryInStorePickup/Plugin/Sales/Order/SavePickupLocationForOrderPlugin.php new file mode 100644 index 000000000000..a0c163d4631c --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/Plugin/Sales/Order/SavePickupLocationForOrderPlugin.php @@ -0,0 +1,55 @@ +saveOrderPickupLocation = $saveOrderPickupLocation; + } + + /** + * Save Order to Pickup Location relation when saving the order. + * + * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository + * @param \Magento\Sales\Api\Data\OrderInterface $result + * @param \Magento\Sales\Api\Data\OrderInterface $entity + * + * @return \Magento\Sales\Api\Data\OrderInterface + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterSave( + OrderRepositoryInterface $orderRepository, + OrderInterface $result, + OrderInterface $entity + ) { + $extension = $result->getExtensionAttributes(); + + if (!empty($extension) && $extension->getPickupLocationCode()) { + $this->saveOrderPickupLocation->execute((int)$result->getEntityId(), $extension->getPickupLocationCode()); + } + + return $result; + } +} diff --git a/app/code/Magento/InventoryInStorePickup/Test/Integration/PickupLocationOrderTest.php b/app/code/Magento/InventoryInStorePickup/Test/Integration/PickupLocationOrderTest.php new file mode 100644 index 000000000000..ef2321e737d9 --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/Test/Integration/PickupLocationOrderTest.php @@ -0,0 +1,85 @@ +objectManager = Bootstrap::getObjectManager(); + + $this->orderRepository = $this->objectManager->get(OrderRepositoryInterface::class); + $this->searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $this->orderExtensionFactory = $this->objectManager->get(OrderExtensionFactory::class); + } + + /** + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/products.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/sources.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/stocks.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/stock_source_links.php + * @magentoDataFixture ../../../../app/code/Magento/InventorySalesApi/Test/_files/websites_with_stores.php + * @magentoDataFixture ../../../../app/code/Magento/InventorySalesApi/Test/_files/stock_website_sales_channels.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/source_items.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryIndexer/Test/_files/reindex_inventory.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryInStorePickup/Test/_files/create_in_store_pickup_quote_on_eu_website.php + * @magentoDataFixture ../../../../app/code/Magento/InventoryInStorePickup/Test/_files/place_order.php + * + * @magentoDbIsolation disabled + */ + public function testPickupLocationSaveWithOrder() + { + $sourceId = 'eu-1'; + + $searchCriteria = $this->searchCriteriaBuilder + ->addFilter('increment_id', 'in_store_pickup_test_order') + ->create(); + /** @var OrderInterface $createdOrder */ + $createdOrder = current($this->orderRepository->getList($searchCriteria)->getItems()); + $orderId = $createdOrder->getEntityId(); + + $extension = $createdOrder->getExtensionAttributes(); + + if (empty($extension)) { + /** @var \Magento\Sales\Api\Data\OrderExtensionInterface $extension */ + $extension = $this->orderExtensionFactory->create(); + } + + $extension->setPickupLocationCode($sourceId); + $createdOrder->setExtensionAttributes($extension); + + $this->orderRepository->save($createdOrder); + + // Remove value to re-load from DB during 'get'. + $extension->setPickupLocationCode(null); + + $order = $this->orderRepository->get($orderId); + + $this->assertEquals($order->getExtensionAttributes()->getPickupLocationCode(), $sourceId); + } +} diff --git a/app/code/Magento/InventoryInStorePickup/Test/_files/create_in_store_pickup_quote_on_eu_website.php b/app/code/Magento/InventoryInStorePickup/Test/_files/create_in_store_pickup_quote_on_eu_website.php new file mode 100644 index 000000000000..fa289d7dbb02 --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/Test/_files/create_in_store_pickup_quote_on_eu_website.php @@ -0,0 +1,59 @@ +get(CartRepositoryInterface::class); +/** @var CartManagementInterface $cartManagement */ +$cartManagement = Bootstrap::getObjectManager()->get(CartManagementInterface::class); +/** @var AddressInterfaceFactory $addressFactory */ +$addressFactory = Bootstrap::getObjectManager()->get(AddressInterfaceFactory::class); +/** @var StoreRepositoryInterface $storeRepository */ +$storeRepository = Bootstrap::getObjectManager()->get(StoreRepositoryInterface::class); +/** @var StoreManagerInterface\ $storeManager */ +$storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class); + +$cartId = $cartManagement->createEmptyCart(); +$cart = $cartRepository->get($cartId); +$cart->setCustomerEmail('admin@example.com'); +$cart->setCustomerIsGuest(true); +$store = $storeRepository->get('store_for_eu_website'); +$cart->setStoreId($store->getId()); +$storeManager->setCurrentStore($store->getCode()); + +/** @var AddressInterface $address */ +$address = $addressFactory->create( + [ + 'data' => [ + AddressInterface::KEY_COUNTRY_ID => 'US', + AddressInterface::KEY_REGION_ID => 15, + AddressInterface::KEY_LASTNAME => 'Doe', + AddressInterface::KEY_FIRSTNAME => 'John', + AddressInterface::KEY_STREET => 'example street', + AddressInterface::KEY_EMAIL => 'customer@example.com', + AddressInterface::KEY_CITY => 'Los Angeles', + AddressInterface::KEY_TELEPHONE => '937 99 92', + AddressInterface::KEY_POSTCODE => 12345 + ] + ] +); +$cart->setReservedOrderId('in_store_pickup_test_order'); +$cart->setBillingAddress($address); +$cart->setShippingAddress($address); +$cart->getPayment()->setMethod('checkmo'); +/** Will be replaced with 'In Store Pickup' delivery method */ +$cart->getShippingAddress()->setShippingMethod('flatrate_flatrate'); +$cart->getShippingAddress()->setCollectShippingRates(true); +$cart->getShippingAddress()->collectShippingRates(); +$cartRepository->save($cart); diff --git a/app/code/Magento/InventoryInStorePickup/Test/_files/create_in_store_pickup_quote_on_eu_website_rollback.php b/app/code/Magento/InventoryInStorePickup/Test/_files/create_in_store_pickup_quote_on_eu_website_rollback.php new file mode 100644 index 000000000000..0ac614eb443d --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/Test/_files/create_in_store_pickup_quote_on_eu_website_rollback.php @@ -0,0 +1,40 @@ +get(Registry::class); + +/** @var CartRepositoryInterface $cartRepository */ +$cartRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class); +/** @var SearchCriteriaBuilder $searchCriteriaBuilder */ +$searchCriteriaBuilder = Bootstrap::getObjectManager()->get(SearchCriteriaBuilder::class); + +$searchCriteria = $searchCriteriaBuilder + ->addFilter('reserved_order_id', 'in_store_pickup_test_order') + ->create(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var CartInterface[] $order */ +$carts = $cartRepository->getList($searchCriteria)->getItems(); +foreach ($carts as $cart) { + $cartRepository->delete($cart); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +/* Refresh stores memory cache */ +Bootstrap::getObjectManager()->get(StoreManagerInterface::class)->reinitStores(); diff --git a/app/code/Magento/InventoryInStorePickup/Test/_files/place_order.php b/app/code/Magento/InventoryInStorePickup/Test/_files/place_order.php new file mode 100644 index 000000000000..8e5a39c7e3ea --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/Test/_files/place_order.php @@ -0,0 +1,37 @@ +get(SearchCriteriaBuilder::class); +/** @var CartRepositoryInterface $cartRepository */ +$cartRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); +/** @var CartManagementInterface $cartManagement */ +$cartManagement = Bootstrap::getObjectManager()->get(CartManagementInterface::class); + +$searchCriteria = $searchCriteriaBuilder + ->addFilter('reserved_order_id', 'in_store_pickup_test_order') + ->create(); +$cart = current($cartRepository->getList($searchCriteria)->getItems()); + +$product = $productRepository->get('SKU-1'); +$requestData = [ + 'product' => $product->getProductId(), + 'qty' => 3.5 +]; +$request = new \Magento\Framework\DataObject($requestData); +$cart->addProduct($product, $request); + +$cartRepository->save($cart); +$cartManagement->placeOrder($cart->getId()); diff --git a/app/code/Magento/InventoryInStorePickup/Test/_files/place_order_rollback.php b/app/code/Magento/InventoryInStorePickup/Test/_files/place_order_rollback.php new file mode 100644 index 000000000000..194465bb9eaa --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/Test/_files/place_order_rollback.php @@ -0,0 +1,41 @@ +get(Registry::class); + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = Bootstrap::getObjectManager()->get(OrderRepositoryInterface::class); +/** @var OrderManagementInterface $orderManagement */ +$orderManagement = Bootstrap::getObjectManager()->get(OrderManagementInterface::class); +/** @var SearchCriteriaBuilder $searchCriteriaBuilder */ +$searchCriteriaBuilder = Bootstrap::getObjectManager()->get(SearchCriteriaBuilder::class); + +$searchCriteria = $searchCriteriaBuilder + ->addFilter('increment_id', 'in_store_pickup_test_order') + ->create(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var OrderInterface $order */ +$order = current($orderRepository->getList($searchCriteria)->getItems()); +if ($order) { + $orderManagement->cancel($order->getEntityId()); + $orderRepository->delete($order); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/app/code/Magento/InventoryInStorePickup/composer.json b/app/code/Magento/InventoryInStorePickup/composer.json index 5938a3b3e082..caa00eafee06 100644 --- a/app/code/Magento/InventoryInStorePickup/composer.json +++ b/app/code/Magento/InventoryInStorePickup/composer.json @@ -5,7 +5,8 @@ "php": "~7.1.3||~7.2.0", "magento/framework": "*", "magento/module-inventory-in-store-pickup-api": "*", - "magento/module-inventory-api": "*" + "magento/module-inventory-api": "*", + "magento/module-sales": "*" }, "type": "magento2-module", "license": [ diff --git a/app/code/Magento/InventoryInStorePickup/etc/db_schema.xml b/app/code/Magento/InventoryInStorePickup/etc/db_schema.xml new file mode 100644 index 000000000000..ce0351a1aba0 --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/etc/db_schema.xml @@ -0,0 +1,18 @@ + + + + + + + + + + +
+
diff --git a/app/code/Magento/InventoryInStorePickup/etc/db_schema_whitelist.json b/app/code/Magento/InventoryInStorePickup/etc/db_schema_whitelist.json new file mode 100644 index 000000000000..6577e0903af9 --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/etc/db_schema_whitelist.json @@ -0,0 +1,12 @@ +{ + "inventory_pickup_location_order": { + "column": { + "order_id": true, + "pickup_location_code": true + }, + "constraint": { + "PRIMARY": true, + "INVENTORY_PICKUP_LOCATION_ORDER_ORDER_ID_SALES_ORDER_ENTITY_ID": true + } + } +} diff --git a/app/code/Magento/InventoryInStorePickup/etc/di.xml b/app/code/Magento/InventoryInStorePickup/etc/di.xml index eed5311a30ee..a7d9095347de 100644 --- a/app/code/Magento/InventoryInStorePickup/etc/di.xml +++ b/app/code/Magento/InventoryInStorePickup/etc/di.xml @@ -5,10 +5,13 @@ * See COPYING.txt for license details. */ --> - + + + + + + type="Magento\InventoryInStorePickup\Model\GetNearbySourcesByPostcode"/> diff --git a/app/code/Magento/InventoryInStorePickup/etc/extension_attributes.xml b/app/code/Magento/InventoryInStorePickup/etc/extension_attributes.xml new file mode 100644 index 000000000000..9658b9c75e5e --- /dev/null +++ b/app/code/Magento/InventoryInStorePickup/etc/extension_attributes.xml @@ -0,0 +1,16 @@ + + + + + + + pickup_location_code + + + + diff --git a/app/code/Magento/InventoryInStorePickup/etc/module.xml b/app/code/Magento/InventoryInStorePickup/etc/module.xml index 850ca9e9c6a7..224ec751bd77 100644 --- a/app/code/Magento/InventoryInStorePickup/etc/module.xml +++ b/app/code/Magento/InventoryInStorePickup/etc/module.xml @@ -6,5 +6,9 @@ */ --> - + + + + +