From 83dc64e7ad70a8217333821730083444c20de1d1 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Sun, 5 Aug 2018 18:47:31 +0200 Subject: [PATCH 01/54] Render category description directives --- .../Model/Resolver/Categories.php | 1 + .../Category/CategoryHtmlAttribute.php | 73 +++++++++++++++++++ .../Products/DataProvider/CategoryTree.php | 1 + .../CatalogGraphQl/etc/schema.graphqls | 4 +- 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php index 378e7cb4c3673..cd28d32b4f2cc 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php @@ -110,6 +110,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $categories[$item->getId()] = $this->customAttributesFlattener ->flatten($categories[$item->getId()]); $categories[$item->getId()]['product_count'] = $item->getProductCount(); + $categories[$item->getId()]['model'] = $item; } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php new file mode 100644 index 0000000000000..17715344fad2e --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php @@ -0,0 +1,73 @@ +valueFactory = $valueFactory; + $this->outputHelper = $outputHelper; + } + + /** + * {@inheritdoc} + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ): Value { + if (!isset($value['model'])) { + $result = function () { + return null; + }; + return $this->valueFactory->create($result); + } + + /* @var $category Category */ + $category = $value['model']; + $fieldName = $field->getName(); + $renderedValue = $this->outputHelper->categoryAttribute($category, $category->getData($fieldName), $fieldName); + + $result = function () use ($renderedValue) { + return $renderedValue; + }; + + return $this->valueFactory->create($result); + } +} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php index d2fc174fb1ed5..13b8bf7523a11 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php @@ -119,6 +119,7 @@ private function processTree(\Iterator $iterator) : array $iterator->next(); $nextCategory = $iterator->current(); $tree[$category->getId()] = $this->hydrator->hydrateCategory($category); + $tree[$category->getId()]['model'] = $category; if ($nextCategory && (int) $nextCategory->getLevel() !== (int) $category->getLevel()) { $tree[$category->getId()]['children'] = $this->processTree($iterator); } diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 9235ec271a3c2..a0bada52cf964 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -364,7 +364,7 @@ interface CustomizableProductInterface @typeResolver(class: "Magento\\CatalogGra interface CategoryInterface @typeResolver(class: "Magento\\CatalogGraphQl\\Model\\CategoryInterfaceTypeResolver") @doc(description: "CategoryInterface contains the full set of attributes that can be returned in a category search") { id: Int @doc(description: "An ID that uniquely identifies the category") - description: String @doc(description: "An optional description of the category") + description: String @doc(description: "An optional description of the category") @resolver(class: "\\Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryHtmlAttribute") name: String @doc(description: "The display name of the category") path: String @doc(description: "Category Path") path_in_store: String @doc(description: "Category path in store") @@ -548,6 +548,6 @@ type SortField { } type SortFields @doc(description: "SortFields contains a default value for sort fields and all available sort fields") { - default: String @doc(description: "Default value of sort fields") + default: String @doc(description: "Default value of sort fields") options: [SortField] @doc(description: "Available sort fields") } From 665ec85a8aba7cc7916385cafd1520c67d1fb06a Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Wed, 8 Aug 2018 16:40:32 +0200 Subject: [PATCH 02/54] Api-functional test added --- .../CategoryWithDescriptionDirectivesTest.php | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryWithDescriptionDirectivesTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryWithDescriptionDirectivesTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryWithDescriptionDirectivesTest.php new file mode 100644 index 0000000000000..48496d4ca9fbc --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryWithDescriptionDirectivesTest.php @@ -0,0 +1,65 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/category.php + */ + public function testHtmlDirectivesRendered() + { + $categoryId = 333; + $mediaFilePath = '/path/to/mediafile'; + /** @var StoreManagerInterface $storeManager */ + $storeManager = ObjectManager::getInstance()->get(StoreManagerInterface::class); + $storeBaseUrl = $storeManager->getStore()->getBaseUrl(); + + /* Remove index.php from base URL */ + $storeBaseUrlParts = explode('/index.php', $storeBaseUrl); + $storeBaseUrl = $storeBaseUrlParts[0]; + + /** @var CategoryRepositoryInterface $categoryRepository */ + $categoryRepository = ObjectManager::getInstance()->get(CategoryRepositoryInterface::class); + /** @var CategoryInterface $category */ + $category = $categoryRepository->get($categoryId); + $category->setDescription('Test: {{media url="' . $mediaFilePath . '"}}'); + $categoryRepository->save($category); + + $query = <<graphQlQuery($query); + + self::assertNotContains('media url', $response['category']['description']); + self::assertContains($storeBaseUrl, $response['category']['description']); + } +} From 651ee47756eb8fb751b05030521c916adf359ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20der=20Linden?= Date: Thu, 6 Sep 2018 12:52:26 +0200 Subject: [PATCH 03/54] Improve pagination exception & add total pages to page_info --- .../Magento/CatalogGraphQl/Model/Resolver/Products.php | 9 +++++---- app/code/Magento/GraphQl/etc/schema.graphqls | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php index cc791ce780c14..e27018d3eb465 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php @@ -110,10 +110,10 @@ public function resolve( $currentPage = $searchCriteria->getCurrentPage(); if ($searchCriteria->getCurrentPage() > $maxPages && $searchResult->getTotalCount() > 0) { - $currentPage = new GraphQlInputException( + throw new GraphQlInputException( __( - 'currentPage value %1 specified is greater than the number of pages available.', - [$maxPages] + 'currentPage value %1 specified is greater than the %2 page(s) available.', + [$currentPage, $maxPages] ) ); } @@ -123,7 +123,8 @@ public function resolve( 'items' => $searchResult->getProductsSearchResult(), 'page_info' => [ 'page_size' => $searchCriteria->getPageSize(), - 'current_page' => $currentPage + 'current_page' => $currentPage, + 'total_pages' => $maxPages ], 'filters' => $this->filtersDataProvider->getData($layerType) ]; diff --git a/app/code/Magento/GraphQl/etc/schema.graphqls b/app/code/Magento/GraphQl/etc/schema.graphqls index c6651cdde0cb3..bafa76e6b4ab1 100644 --- a/app/code/Magento/GraphQl/etc/schema.graphqls +++ b/app/code/Magento/GraphQl/etc/schema.graphqls @@ -29,6 +29,7 @@ input FilterTypeInput @doc(description: "FilterTypeInput specifies which action type SearchResultPageInfo @doc(description: "SearchResultPageInfo provides navigation for the query response") { page_size: Int @doc(description: "Specifies the maximum number of items to return") current_page: Int @doc(description: "Specifies which page of results to return") + total_pages: Int @doc(description: "Total amount of pages") } enum SortEnum @doc(description: "This enumeration indicates whether to return results in ascending or descending order") { From 5f055721b2c0ee727e4c9ebeeefddcca7941a803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20der=20Linden?= Date: Fri, 7 Sep 2018 08:17:03 +0200 Subject: [PATCH 04/54] SearchResultPageInfo.total_pages description improvement --- app/code/Magento/GraphQl/etc/schema.graphqls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/GraphQl/etc/schema.graphqls b/app/code/Magento/GraphQl/etc/schema.graphqls index bafa76e6b4ab1..ce2166808b4de 100644 --- a/app/code/Magento/GraphQl/etc/schema.graphqls +++ b/app/code/Magento/GraphQl/etc/schema.graphqls @@ -29,7 +29,7 @@ input FilterTypeInput @doc(description: "FilterTypeInput specifies which action type SearchResultPageInfo @doc(description: "SearchResultPageInfo provides navigation for the query response") { page_size: Int @doc(description: "Specifies the maximum number of items to return") current_page: Int @doc(description: "Specifies which page of results to return") - total_pages: Int @doc(description: "Total amount of pages") + total_pages: Int @doc(description: "Total pages") } enum SortEnum @doc(description: "This enumeration indicates whether to return results in ascending or descending order") { From eea5cdd39cbd5f54c0660a696e27aecc8ba09d6c Mon Sep 17 00:00:00 2001 From: Roman Glushko Date: Fri, 7 Sep 2018 14:47:13 +0300 Subject: [PATCH 05/54] #141 Added add simple product to cart mutation to quote-graphql module --- .../Model/Product/Option/DateType.php | 59 +++++ .../Model/Hydrator/CartHydrator.php | 47 ++++ .../Resolver/Cart/AddSimpleProductsToCart.php | 226 +++++++++++++++++ .../Resolver/CartItem/CustomizableOptions.php | 235 ++++++++++++++++++ .../Model/Resolver/CartItemTypeResolver.php | 55 ++++ .../CartItemTypeResolverComposite.php | 55 ++++ .../Magento/QuoteGraphQl/etc/graphql/di.xml | 16 ++ .../Magento/QuoteGraphQl/etc/schema.graphqls | 38 ++- 8 files changed, 730 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php create mode 100644 app/code/Magento/QuoteGraphQl/etc/graphql/di.xml diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php new file mode 100644 index 0000000000000..8733b9a6b1d0e --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -0,0 +1,59 @@ +_dateExists() || $this->_timeExists()) { + return parent::validateUserValue($this->formatValues($values)); + } + + return $this; + } + + /** + * @param array $values + * @return array mixed + */ + protected function formatValues($values) + { + if (isset($values[$this->getOption()->getId()])) { + $value = $values[$this->getOption()->getId()]; + $dateTime = \DateTime::createFromFormat(DateTime::DATETIME_PHP_FORMAT, $value); + $values[$this->getOption()->getId()] = [ + 'date' => $value, + 'year' => $dateTime->format('Y'), + 'month' => $dateTime->format('m'), + 'day' => $dateTime->format('d'), + 'hour' => $dateTime->format('H'), + 'minute' => $dateTime->format('i'), + 'day_part' => $dateTime->format('a'), + ]; + } + + return $values; + } + + /** + * @return bool + */ + public function useCalendar() + { + return false; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php b/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php new file mode 100644 index 0000000000000..5f386134bcc9e --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php @@ -0,0 +1,47 @@ +getAllItems() as $cartItem) { + $productData = $cartItem->getProduct()->getData(); + $productData['model'] = $cartItem->getProduct(); + + $items[] = [ + 'id' => $cartItem->getItemId(), + 'qty' => $cartItem->getQty(), + 'product' => $productData, + 'model' => $cartItem, + ]; + } + + return [ + 'items' => $items, + ]; + } +} \ No newline at end of file diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php new file mode 100644 index 0000000000000..49bbcb1e43721 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php @@ -0,0 +1,226 @@ +valueFactory = $valueFactory; + $this->userContext = $userContext; + $this->arrayManager = $arrayManager; + $this->productRepository = $productRepository; + $this->cartHydrator = $cartHydrator; + $this->guestCartRepository = $guestCartRepository; + $this->dataObjectFactory = $dataObjectFactory; + $this->cartRepository = $cartRepository; + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + } + + /** + * {@inheritDoc} + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value + { + $cartHash = $this->arrayManager->get('input/cart_id', $args); + $cartItems = $this->arrayManager->get('input/cartItems', $args); + + if (!isset($cartHash)) { + throw new GraphQlInputException( + __('Missing key %1 in cart data', ['cart_id']) + ); + } + + if (!isset($cartItems)) { + throw new GraphQlInputException( + __('Missing key %1 in cart data', ['cartItems']) + ); + } + + $cart = $this->getCart((string) $cartHash); + + foreach ($cartItems as $cartItem) { + $sku = $this->arrayManager->get('details/sku', $cartItem); + $product = $this->productRepository->get($sku); + + $message = $cart->addProduct($product, $this->getBuyRequest($cartItem)); + + if (is_string($message)) { + throw new GraphQlInputException( + __('%1: %2', $sku, $message) + ); + } + + if ($cart->getData('has_error')) { + throw new GraphQlInputException( + __('%1: %2', $sku, $this->getCartErrors($cart)) + ); + } + } + + $this->cartRepository->save($cart); + + $result = function () use ($cart) { + return [ + 'cart' => $this->cartHydrator->hydrate($cart) + ]; + }; + + return $this->valueFactory->create($result); + } + + /** + * Format GraphQl input data to a shape that buy request has + * + * @param array $cartItem + * @return DataObject + */ + private function getBuyRequest($cartItem): DataObject + { + $customOptions = []; + $qty = $this->arrayManager->get('details/qty', $cartItem); + $customizableOptions = $this->arrayManager->get('customizable_options', $cartItem, []); + + foreach ($customizableOptions as $customizableOption) { + $customOptions[$customizableOption['id']] = $customizableOption['value']; + } + + return $this->dataObjectFactory->create([ + 'data' => [ + 'qty' => $qty, + 'options' => $customOptions + ] + ]); + } + + /** + * Collecting cart errors + * + * @param CartInterface|Quote $cart + * @return string + */ + private function getCartErrors($cart): string + { + $errorMessages = []; + + /** @var AbstractMessage $error */ + foreach ($cart->getErrors() as $error) { + $errorMessages[] = $error->getText(); + } + + return implode(PHP_EOL, $errorMessages); + } + + /** + * Retrieving quote mode based on customer authorization + * + * @param string $cartHash + * @return CartInterface|Quote + * @throws NoSuchEntityException + */ + private function getCart(string $cartHash): CartInterface + { + $customerId = $this->userContext->getUserId(); + + if (!$customerId) { + return $this->guestCartRepository->get($cartHash); + } + + $cartId = $this->maskedQuoteIdToQuoteId->execute((string) $cartHash); + return $this->cartRepository->get($cartId); + } +} \ No newline at end of file diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php new file mode 100644 index 0000000000000..871d152faa867 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php @@ -0,0 +1,235 @@ +valueFactory = $valueFactory; + $this->userContext = $userContext; + $this->storeManager = $storeManager; + } + + /** + * {@inheritDoc} + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value + { + if (!isset($value['model'])) { + return $this->valueFactory->create(function () { + return []; + }); + } + + /** @var QuoteItem $cartItem */ + $cartItem = $value['model']; + $optionIds = $cartItem->getOptionByCode('option_ids'); + + if (!$optionIds) { + return $this->valueFactory->create(function () { + return []; + }); + } + + $customOptions = []; + $customOptionIds = explode(',', $optionIds->getValue()); + + foreach ($customOptionIds as $optionId) { + $customOptionData = $this->getOptionData($cartItem, (int) $optionId); + + if (0 === count($customOptionData)) { + continue; + } + + $customOptions[] = $customOptionData; + } + + $result = function () use ($customOptions) { + return $customOptions; + }; + + return $this->valueFactory->create($result); + } + + /** + * @param QuoteItem $cartItem + * @param int $optionId + * @return array + * @throws NoSuchEntityException + * @throws LocalizedException + */ + private function getOptionData($cartItem, int $optionId): array + { + $product = $cartItem->getProduct(); + $option = $product->getOptionById($optionId); + + if (!$option) { + return []; + } + + $itemOption = $cartItem->getOptionByCode('option_' . $option->getId()); + + /** @var SelectOptionType|TextOptionType|DefaultOptionType $optionTypeGroup */ + $optionTypeGroup = $option->groupFactory($option->getType()) + ->setOption($option) + ->setConfigurationItem($cartItem) + ->setConfigurationItemOption($itemOption); + + if (ProductCustomOptionInterface::OPTION_GROUP_FILE == $option->getType()) { + $downloadParams = $cartItem->getFileDownloadParams(); + + if ($downloadParams) { + $url = $downloadParams->getUrl(); + if ($url) { + $optionTypeGroup->setCustomOptionDownloadUrl($url); + } + $urlParams = $downloadParams->getUrlParams(); + if ($urlParams) { + $optionTypeGroup->setCustomOptionUrlParams($urlParams); + } + } + } + + $selectedOptionValueData = [ + 'id' => $itemOption->getId(), + 'label' => $optionTypeGroup->getFormattedOptionValue($itemOption->getValue()), + ]; + + if (ProductCustomOptionInterface::OPTION_TYPE_DROP_DOWN == $option->getType() + || ProductCustomOptionInterface::OPTION_TYPE_RADIO == $option->getType() + || ProductCustomOptionInterface::OPTION_TYPE_CHECKBOX == $option->getType() + ) { + $optionValue = $option->getValueById($itemOption->getValue()); + $priceValueUnits = $this->getPriceValueUnits($optionValue->getPriceType()); + + $selectedOptionValueData['price'] = [ + 'type' => strtoupper($optionValue->getPriceType()), + 'units' => $priceValueUnits, + 'value' => $optionValue->getPrice(), + ]; + + $selectedOptionValueData = [$selectedOptionValueData]; + } + + if (ProductCustomOptionInterface::OPTION_TYPE_FIELD == $option->getType() + || ProductCustomOptionInterface::OPTION_TYPE_AREA == $option->getType() + || ProductCustomOptionInterface::OPTION_GROUP_DATE == $option->getType() + || ProductCustomOptionInterface::OPTION_TYPE_TIME == $option->getType() + ) { + $priceValueUnits = $this->getPriceValueUnits($option->getPriceType()); + + $selectedOptionValueData['price'] = [ + 'type' => strtoupper($option->getPriceType()), + 'units' => $priceValueUnits, + 'value' => $option->getPrice(), + ]; + + $selectedOptionValueData = [$selectedOptionValueData]; + } + + if (ProductCustomOptionInterface::OPTION_TYPE_MULTIPLE == $option->getType()) { + $selectedOptionValueData = []; + $optionIds = explode(',', $itemOption->getValue()); + + foreach ($optionIds as $optionId) { + $optionValue = $option->getValueById($optionId); + $priceValueUnits = $this->getPriceValueUnits($optionValue->getPriceType()); + + $selectedOptionValueData[] = [ + 'id' => $itemOption->getId(), + 'label' => $optionValue->getTitle(), + 'price' => [ + 'type' => strtoupper($optionValue->getPriceType()), + 'units' => $priceValueUnits, + 'value' => $optionValue->getPrice(), + ], + ]; + } + } + + return [ + 'id' => $option->getId(), + 'label' => $option->getTitle(), + 'type' => $option->getType(), + 'values' => $selectedOptionValueData, + 'sort_order' => $option->getSortOrder(), + ]; + } + + /** + * @param string $priceType + * @return string + * @throws NoSuchEntityException + */ + private function getPriceValueUnits(string $priceType): string + { + if (ProductPriceOptionsInterface::VALUE_PERCENT == $priceType) { + return '%'; + } + + return $this->getCurrencySymbol(); + } + + /** + * Get currency symbol + * @return string + * @throws NoSuchEntityException + */ + private function getCurrencySymbol(): string + { + /** @var Store|StoreInterface $store */ + $store = $this->storeManager->getStore(); + + return $store->getBaseCurrency()->getCurrencySymbol(); + } +} \ No newline at end of file diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php new file mode 100644 index 0000000000000..75232190b7361 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php @@ -0,0 +1,55 @@ +cartItemTypes = $cartItemTypes; + } + + /** + * {@inheritdoc} + * @throws GraphQlInputException + */ + public function resolveType(array $data) : string + { + if (!isset($data['product'])) { + return ''; + } + + $productData = $data['product']; + + if (!isset($productData['type_id'])) { + return ''; + } + + $productTypeId = $productData['type_id']; + + if (!isset($this->cartItemTypes[$productTypeId])) { + return ''; + } + + return $this->cartItemTypes[$productTypeId]; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php new file mode 100644 index 0000000000000..264887a66f621 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php @@ -0,0 +1,55 @@ +cartItemTypeResolvers = $cartItemTypeResolvers; + } + + /** + * {@inheritdoc} + * @throws GraphQlInputException + */ + public function resolveType(array $data) : string + { + if (!isset($data['product'])) { + throw new GraphQlInputException( + __('Missing key %1 in cart data', ['product']) + ); + } + + foreach ($this->cartItemTypeResolvers as $cartItemTypeResolver) { + $resolvedType = $cartItemTypeResolver->resolveType($data); + + if ($resolvedType) { + return $resolvedType; + } + } + + throw new GraphQlInputException( + __('Concrete type for %1 not implemented', ['CartItemInterface']) + ); + } +} diff --git a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml new file mode 100644 index 0000000000000..0a13f1ba34557 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml @@ -0,0 +1,16 @@ + + + + + + + Magento\QuoteGraphQl\Model\Resolver\CartItemTypeResolver + + + + diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 46d1b97d0aea2..8ee32e493c0da 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -2,5 +2,41 @@ # See COPYING.txt for license details. type Mutation { - createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") + createEmptyCart: String @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") } + +type Cart { + items: [CartItemInterface] +} + +input CartItemDetailsInput { + sku: String! + qty: Float! +} + +interface CartItemInterface @typeResolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\CartItemTypeResolverComposite") { + id: String! + qty: Float! + product: ProductInterface! +} + +type SelectedCustomizableOption { + id: Int! + label: String! + type: String! + values: [SelectedCustomizableOptionValue!]! + sort_order: Int! +} + +type SelectedCustomizableOptionValue { + id: Int + label: String! + price: CartItemSelectedOptionValuePrice! + sort_order: Int! +} + +type CartItemSelectedOptionValuePrice { + value: Float! + units: String! + type: PriceTypeEnum! +} \ No newline at end of file From 50a928c4c4192c8f85be46bbaaed14be7e7f0170 Mon Sep 17 00:00:00 2001 From: Roman Glushko Date: Fri, 7 Sep 2018 14:56:13 +0300 Subject: [PATCH 06/54] #141 Added required configurations --- .../Magento/QuoteGraphQl/etc/graphql/di.xml | 7 ++++++ .../Magento/QuoteGraphQl/etc/schema.graphqls | 24 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml index 0a13f1ba34557..8f29b2559a7a0 100644 --- a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml @@ -13,4 +13,11 @@ + + + + SimpleCartItem + + + diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 8ee32e493c0da..ab849ba569167 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -3,6 +3,30 @@ type Mutation { createEmptyCart: String @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") + addSimpleProductsToCart(input: AddSimpleProductsToCartInput): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\AddSimpleProductsToCart") +} + +input AddSimpleProductsToCartInput { + cart_id: String! + cartItems: [SimpleProductCartItemInput!]! +} + +input SimpleProductCartItemInput { + details: CartItemDetailsInput! + customizable_options:[CustomizableOptionInput!] +} + +input CustomizableOptionInput { + id: Int! + value: String! +} + +type AddSimpleProductsToCartOutput { + cart: Cart! +} + +type SimpleCartItem implements CartItemInterface @doc(description: "Simple Cart Item") { + customizable_options: [SelectedCustomizableOption] @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\CartItem\\CustomizableOptions") } type Cart { From 5105989b698c0fce1dec27b003225f9006b7a1c5 Mon Sep 17 00:00:00 2001 From: Roman Glushko Date: Fri, 7 Sep 2018 16:32:22 +0300 Subject: [PATCH 07/54] #141 Added hard dependencies --- app/code/Magento/QuoteGraphQl/composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/QuoteGraphQl/composer.json b/app/code/Magento/QuoteGraphQl/composer.json index 76ecfac373efc..9995e292e7842 100644 --- a/app/code/Magento/QuoteGraphQl/composer.json +++ b/app/code/Magento/QuoteGraphQl/composer.json @@ -6,7 +6,9 @@ "php": "~7.1.3||~7.2.0", "magento/framework": "*", "magento/module-authorization": "*", - "magento/module-quote": "*" + "magento/module-quote": "*", + "magento/module-catalog": "*", + "magento/module-store": "*" }, "suggest": { "magento/module-graph-ql": "*", From 1734dfca837e8031940f834e732543bb3ee350ac Mon Sep 17 00:00:00 2001 From: Roman Glushko Date: Fri, 7 Sep 2018 16:37:09 +0300 Subject: [PATCH 08/54] #141 Fixed issues from Travis --- .../Magento/CatalogGraphQl/Model/Product/Option/DateType.php | 1 + app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php | 2 +- .../Model/Resolver/Cart/AddSimpleProductsToCart.php | 2 +- .../Model/Resolver/CartItem/CustomizableOptions.php | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index 8733b9a6b1d0e..f3f74867128f5 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\CatalogGraphQl\Model\Product\Option; diff --git a/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php b/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php index 5f386134bcc9e..6dec379098863 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php +++ b/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php @@ -44,4 +44,4 @@ public function hydrate(CartInterface $cart): array 'items' => $items, ]; } -} \ No newline at end of file +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php index 49bbcb1e43721..cc44b1071b396 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php @@ -223,4 +223,4 @@ private function getCart(string $cartHash): CartInterface $cartId = $this->maskedQuoteIdToQuoteId->execute((string) $cartHash); return $this->cartRepository->get($cartId); } -} \ No newline at end of file +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php index 871d152faa867..67318be917c82 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php @@ -232,4 +232,4 @@ private function getCurrencySymbol(): string return $store->getBaseCurrency()->getCurrencySymbol(); } -} \ No newline at end of file +} From 7e7e82cd4e7cb59880ca079e5aa09434805a5dca Mon Sep 17 00:00:00 2001 From: Roman Glushko Date: Fri, 7 Sep 2018 18:34:15 +0300 Subject: [PATCH 09/54] #141 Running tests again --- app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php b/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php index 6dec379098863..1f3852aaf1e67 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php +++ b/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php @@ -18,7 +18,6 @@ class CartHydrator { /** * @param CartInterface|Quote $cart - * * @return array */ public function hydrate(CartInterface $cart): array From 316344ca83accb0680383c3692843af996d59d94 Mon Sep 17 00:00:00 2001 From: DmytroPaidych Date: Wed, 12 Sep 2018 11:01:23 +0300 Subject: [PATCH 10/54] MAGETWO-94889: Automate with MFTF Free Shipping is not available in Admin if "Minimum Order Amount" does not match Order total --- .../ConfigFlatRateMethodActionGroup.xml | 33 ++++++++++ .../ConfigFreeShippingMethodActionGroup.xml | 38 +++++++++++ .../Config/Test/Mftf/Page/AdminConfigPage.xml | 3 + .../Test/Mftf/Section/GeneralSection.xml | 2 +- .../Mftf/Section/ShippingMethodsSection.xml | 24 +++++++ .../AdminOrderDetailsMessagesSection.xml | 1 + .../Section/AdminOrderFormPaymentSection.xml | 1 + ...nimumOrderAmountNotMatchOrderTotalTest.xml | 64 +++++++++++++++++++ 8 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFlatRateMethodActionGroup.xml create mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFreeShippingMethodActionGroup.xml create mode 100644 app/code/Magento/Config/Test/Mftf/Section/ShippingMethodsSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminFreeShippingNotAvailableIfMinimumOrderAmountNotMatchOrderTotalTest.xml diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFlatRateMethodActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFlatRateMethodActionGroup.xml new file mode 100644 index 0000000000000..cbb2161a22e4b --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFlatRateMethodActionGroup.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFreeShippingMethodActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFreeShippingMethodActionGroup.xml new file mode 100644 index 0000000000000..b49d60cd2be43 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFreeShippingMethodActionGroup.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml b/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml index 7a62dfff8323b..2237b13005fb3 100644 --- a/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml +++ b/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml @@ -21,4 +21,7 @@
+ +
+ diff --git a/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml b/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml index 85035c6b56f9c..88532dc091f45 100644 --- a/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml +++ b/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml @@ -16,7 +16,7 @@ - +
diff --git a/app/code/Magento/Config/Test/Mftf/Section/ShippingMethodsSection.xml b/app/code/Magento/Config/Test/Mftf/Section/ShippingMethodsSection.xml new file mode 100644 index 0000000000000..db3128d70006d --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Section/ShippingMethodsSection.xml @@ -0,0 +1,24 @@ + + + + +
+ + + + + + + + + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsMessagesSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsMessagesSection.xml index 1bc3718467102..2dd515a28dc99 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsMessagesSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsMessagesSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml index e4d329bc85057..4350ffeb03373 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml @@ -13,5 +13,6 @@ +
\ No newline at end of file diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminFreeShippingNotAvailableIfMinimumOrderAmountNotMatchOrderTotalTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminFreeShippingNotAvailableIfMinimumOrderAmountNotMatchOrderTotalTest.xml new file mode 100644 index 0000000000000..8f5715ed69b45 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminFreeShippingNotAvailableIfMinimumOrderAmountNotMatchOrderTotalTest.xml @@ -0,0 +1,64 @@ + + + + + + + + + <description value="Admin should not be able place order with Free Shipping method if Minimum Order Amount does not match Order total"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-61001"/> + <group value="sales"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + <field key="price">100</field> + </createData> + <createData entity="Simple_US_Customer" stepKey="customer"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="DisableFlatRate" stepKey="disableFlatRate"/> + <actionGroup ref="EnableFreeShipping" stepKey="enableFreeShipping"> + <argument name="orderAmount" value="101"/> + </actionGroup> + <actionGroup ref="ClearCacheActionGroup" stepKey="clearCacheBefore"/> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="customer" stepKey="deleteCustomer"/> + <actionGroup ref="EnableFlatRate" stepKey="enableFlatRate"/> + <actionGroup ref="DisableFreeShipping" stepKey="disableFreeShipping"/> + <actionGroup ref="ClearCacheActionGroup" stepKey="clearCacheAfter"/> + <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + </after> + + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="goToCreateOrderPage"> + <argument name="customer" value="Simple_US_Customer"/> + </actionGroup> + + <!--Admin creates order--> + <actionGroup ref="addSimpleProductToOrder" stepKey="addProductToOrder"> + <argument name="product" value="SimpleProduct"/> + </actionGroup> + + <click selector="{{AdminOrderFormPaymentSection.header}}" stepKey="unfocus"/> + <waitForPageLoad stepKey="waitForJavascriptToFinish"/> + <click selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="clickShippingMethods"/> + <dontSeeElement selector="{{AdminOrderFormPaymentSection.freeShippingOption}}" stepKey="seeAbsentFreeShipping"/> + + <!--Submit Order and verify information--> + <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="clickSubmitOrder"/> + + <dontSeeElement selector="{{AdminOrderDetailsMessagesSection.successMessage}}" stepKey="seeSuccessMessage"/> + <seeElement selector="{{AdminOrderDetailsMessagesSection.errorMessage}}" stepKey="seeErrorMessage"/> + </test> +</tests> \ No newline at end of file From dfc6b0bf795f72e483deef703fd666cff43966b6 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Wed, 12 Sep 2018 15:30:07 +0300 Subject: [PATCH 11/54] MAGETWO-94939: State/Province field is empty on Company Grid --- .../Customer/Test/Mftf/Data/CustomerData.xml | 13 +++++++++++++ .../Magento/Customer/Test/Mftf/Data/RegionData.xml | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml b/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml index baf6772843894..6f5ade53e6790 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml @@ -89,4 +89,17 @@ <var key="id" entityKey="id" entityType="customer"/> <data key="firstname">Jane</data> </entity> + <entity name="Simple_US_CA_Customer" type="customer"> + <data key="group_id">1</data> + <data key="default_billing">true</data> + <data key="default_shipping">true</data> + <data key="email" unique="prefix">John.Doe@example.com</data> + <data key="firstname">John</data> + <data key="lastname">Doe</data> + <data key="fullname">John Doe</data> + <data key="password">pwdTest123!</data> + <data key="store_id">0</data> + <data key="website_id">0</data> + <requiredEntity type="address">US_Address_CA</requiredEntity> + </entity> </entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/RegionData.xml b/app/code/Magento/Customer/Test/Mftf/Data/RegionData.xml index 523a463e5dea2..b1da921f7ca59 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/RegionData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/RegionData.xml @@ -15,7 +15,7 @@ <entity name="RegionTX" type="region"> <data key="region">Texas</data> <data key="region_code">TX</data> - <data key="region_id">1</data> + <data key="region_id">57</data> </entity> <entity name="RegionCA" type="region"> <data key="region">California</data> From 5b40c2624dfc42b27c71563a303563f28c4ca9d6 Mon Sep 17 00:00:00 2001 From: Dmitriy Kogut <kogut.dmitriy@gmail.com> Date: Wed, 12 Sep 2018 16:25:36 +0300 Subject: [PATCH 12/54] MAGETWO-93830: Automate with MFTF Sort products grid after removing shared catalog --- ...AdminCreateApiBundleProductActionGroup.xml | 99 +++++++++++++++++++ .../Bundle/Test/Mftf/Data/ProductData.xml | 15 +++ ...reateApiConfigurableProductActionGroup.xml | 59 +++++++++++ .../Mftf/Data/ConfigurableProductData.xml | 11 +++ ...minCustomerGroupResetFilterActionGroup.xml | 19 ++++ ...inFilterCustomerGroupByNameActionGroup.xml | 20 ++++ .../Page/AdminCustomerGroupsIndexPage.xml | 15 +++ .../AdminCustomerGroupFiltersSection.xml | 20 ++++ .../AdminCustomerGroupGridActionsSection.xml | 15 +++ .../AdminCustomerGroupMainActionsSection.xml | 14 +++ 10 files changed, 287 insertions(+) create mode 100644 app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml create mode 100644 app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml new file mode 100644 index 0000000000000..5de75c976052f --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateApiDynamicBundleProductActionGroup"> + <!--Create 4 simple products--> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"> + <field key="price">4.99</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"> + <field key="price">2.89</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct3"> + <field key="price">7.33</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct4"> + <field key="price">18.25</field> + </createData> + <!-- Create the bundle product based --> + <createData entity="ApiBundleProduct" stepKey="createBundleProduct"/> + <createData entity="MultipleSelectOption" stepKey="createBundleOption1_1"> + <requiredEntity createDataKey="createBundleProduct"/> + <field key="required">false</field> + </createData> + <createData entity="CheckboxOption" stepKey="createBundleOption1_2"> + <requiredEntity createDataKey="createBundleProduct"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct1"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct2"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct2"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct3"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct3"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct4"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct4"/> + </createData> + </actionGroup> + <actionGroup name="AdminCreateApiFixedBundleProductActionGroup"> + <!--Create 4 simple products--> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"> + <field key="price">4.99</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"> + <field key="price">2.89</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct3"> + <field key="price">7.33</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct4"> + <field key="price">18.25</field> + </createData> + <!-- Create the bundle product based --> + <createData entity="ApiFixedBundleProduct" stepKey="createBundleProduct"/> + <createData entity="MultipleSelectOption" stepKey="createBundleOption1_1"> + <requiredEntity createDataKey="createBundleProduct"/> + <field key="required">false</field> + </createData> + <createData entity="CheckboxOption" stepKey="createBundleOption1_2"> + <requiredEntity createDataKey="createBundleProduct"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct1"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct2"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct2"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct3"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct3"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct4"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct4"/> + </createData> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml index f48810e0534fe..646ed673fd111 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml @@ -59,4 +59,19 @@ <requiredEntity type="custom_attribute">CustomAttributeDynamicPrice</requiredEntity> <requiredEntity type="custom_attribute">CustomAttributePriceViewRange</requiredEntity> </entity> + <entity name="ApiFixedBundleProduct" type="product2"> + <data key="name" unique="suffix">Api Fixed Bundle Product</data> + <data key="sku" unique="suffix">api-fixed-bundle-product</data> + <data key="type_id">bundle</data> + <data key="attribute_set_id">4</data> + <data key="price">1.23</data> + <data key="visibility">4</data> + <data key="status">1</data> + <data key="urlKey" unique="suffix">api-fixed-bundle-product</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute">ApiProductDescription</requiredEntity> + <requiredEntity type="custom_attribute">ApiProductShortDescription</requiredEntity> + <requiredEntity type="custom_attribute">CustomAttributeFixPrice</requiredEntity> + <requiredEntity type="custom_attribute">CustomAttributePriceView</requiredEntity> + </entity> </entities> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml new file mode 100644 index 0000000000000..b88c06762d49d --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateApiConfigurableProductActionGroup"> + <!-- Create the configurable product based on the data in the /data folder --> + <createData entity="ApiConfigurableProductWithOutCategory" stepKey="createConfigProduct"/> + + <!-- Make the configurable product have two options, that are children of the default attribute set --> + <createData entity="productAttributeWithTwoOptions" stepKey="createConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getConfigAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + + <!-- Create the 2 children that will be a part of the configurable product --> + <createData entity="ApiSimpleOne" stepKey="createConfigChildProduct1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + </createData> + <createData entity="ApiSimpleTwo" stepKey="createConfigChildProduct2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + + <!-- Assign the two products to the configurable product --> + <createData entity="ConfigurableProductTwoOptions" stepKey="createConfigProductOption"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild1"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigChildProduct1"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild2"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigChildProduct2"/> + </createData> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductData.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductData.xml index f92b388b46649..5bcbd59d148b6 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductData.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductData.xml @@ -34,6 +34,17 @@ <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> + <entity name="ApiConfigurableProductWithOutCategory" type="product"> + <data key="sku" unique="suffix">api-configurable-product-with-out-category</data> + <data key="type_id">configurable</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">API Configurable Product</data> + <data key="urlKey" unique="suffix">api-configurable-product</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + </entity> <entity name="ApiConfigurableProductWithDescription" type="product"> <data key="sku" unique="suffix">api-configurable-product</data> <data key="type_id">configurable</data> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml new file mode 100644 index 0000000000000..e6735dc87c4e3 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!--Reset the Customer Group grid to the default view--> + <actionGroup name="AdminCustomerGroupResetFilterActionGroup"> + <conditionalClick selector="{{AdminCustomerGroupFiltersSection.clearFilters}}" dependentSelector="{{AdminCustomerGroupFiltersSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> + <click selector="{{AdminCustomerGroupFiltersSection.viewDropdown}}" stepKey="openViewBookmarksTab"/> + <click selector="{{AdminCustomerGroupFiltersSection.viewBookmark('Default View')}}" stepKey="resetToDefaultGridView"/> + <waitForPageLoad stepKey="waitForProductGridLoad"/> + <see selector="{{AdminCustomerGroupFiltersSection.viewDropdown}}" userInput="Default View" stepKey="seeDefaultViewSelected"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml new file mode 100644 index 0000000000000..62aa1c4f155ea --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminFilterCustomerGroupByNameActionGroup"> + <arguments> + <argument name="customerGroupName" type="string"/> + </arguments> + <click selector="{{AdminCustomerGroupFiltersSection.filterButton}}" stepKey="openFiltersSectionOnCustomerGroupIndexPage"/> + <conditionalClick selector="{{AdminCustomerGroupFiltersSection.clearFiltersButton}}" dependentSelector="{{AdminCustomerGroupFiltersSection.clearFiltersButton}}" visible="true" stepKey="cleanFiltersIfTheySet"/> + <fillField userInput="{{customerGroupName}}" selector="{{AdminCustomerGroupFiltersSection.nameField}}" stepKey="fillNameFieldOnFiltersSection"/> + <click selector="{{AdminCustomerGroupFiltersSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml new file mode 100644 index 0000000000000..f375cfc4777aa --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminCustomerGroupsIndexPage" url="/customer/group/" area="admin" module="Magento_Customer"> + <section name="AdminCustomerGroupGridActionsSection"/> + <section name="AdminCustomerGroupFiltersSection"/> + </page> +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml new file mode 100644 index 0000000000000..ca85c35bea7b7 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCustomerGroupFiltersSection"> + <element name="filterButton" type="button" selector="//div[@class='data-grid-filters-action-wrap']/button" timeout="30"/> + <element name="clearFiltersButton" type="button" selector="//div[@class='admin__data-grid-header']//button[@class='action-tertiary action-clear']" timeout="10"/> + <element name="applyFilters" type="button" selector="button[data-action=grid-filter-apply]" timeout="30"/> + <element name="nameField" type="input" selector=".admin__data-grid-filters-wrap._show input[name='customer_group_code']" timeout="30"/> + <element name="clearFilters" type="button" selector=".admin__data-grid-header button[data-action='grid-filter-reset']" timeout="30"/> + <element name="viewDropdown" type="button" selector=".admin__data-grid-action-bookmarks button.admin__action-dropdown"/> + <element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml new file mode 100644 index 0000000000000..14737b1ef3eed --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCustomerGroupGridActionsSection"> + <element name="selectButton" type="button" selector="table.data-grid button.action-select" timeout="30"/> + <element name="selectButtonItem" type="text" selector="//ul[@class='action-menu _active']//a[contains(text(), '{{selectItem}}')]" timeout="30" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml new file mode 100644 index 0000000000000..a543ea15baec6 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCustomerGroupMainActionsSection"> + <element name="popupOkButton" type="button" selector="button.action-primary.action-accept" timeout="30"/> + </section> +</sections> From c09fe6df77b9d80a7cce943c8a3ae7b2f2f14174 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Thu, 13 Sep 2018 10:13:08 +0300 Subject: [PATCH 13/54] MAGETWO-94838: Automate with MFTF Ability to configure Advanced Prices from Shared Catalog Page for different type of products --- ...AdminCreateApiBundleProductActionGroup.xml | 99 +++++++++++++++++++ .../Bundle/Test/Mftf/Data/ProductData.xml | 15 +++ ...reateApiConfigurableProductActionGroup.xml | 59 +++++++++++ .../Mftf/Data/ConfigurableProductData.xml | 11 +++ ...minCustomerGroupResetFilterActionGroup.xml | 19 ++++ ...inFilterCustomerGroupByNameActionGroup.xml | 20 ++++ .../Page/AdminCustomerGroupsIndexPage.xml | 15 +++ .../AdminCustomerGroupFiltersSection.xml | 20 ++++ .../AdminCustomerGroupGridActionsSection.xml | 15 +++ .../AdminCustomerGroupMainActionsSection.xml | 14 +++ 10 files changed, 287 insertions(+) create mode 100644 app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml create mode 100644 app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml new file mode 100644 index 0000000000000..5de75c976052f --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateApiDynamicBundleProductActionGroup"> + <!--Create 4 simple products--> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"> + <field key="price">4.99</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"> + <field key="price">2.89</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct3"> + <field key="price">7.33</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct4"> + <field key="price">18.25</field> + </createData> + <!-- Create the bundle product based --> + <createData entity="ApiBundleProduct" stepKey="createBundleProduct"/> + <createData entity="MultipleSelectOption" stepKey="createBundleOption1_1"> + <requiredEntity createDataKey="createBundleProduct"/> + <field key="required">false</field> + </createData> + <createData entity="CheckboxOption" stepKey="createBundleOption1_2"> + <requiredEntity createDataKey="createBundleProduct"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct1"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct2"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct2"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct3"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct3"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct4"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct4"/> + </createData> + </actionGroup> + <actionGroup name="AdminCreateApiFixedBundleProductActionGroup"> + <!--Create 4 simple products--> + <createData entity="SimpleProduct2" stepKey="simpleProduct1"> + <field key="price">4.99</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct2"> + <field key="price">2.89</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct3"> + <field key="price">7.33</field> + </createData> + <createData entity="SimpleProduct2" stepKey="simpleProduct4"> + <field key="price">18.25</field> + </createData> + <!-- Create the bundle product based --> + <createData entity="ApiFixedBundleProduct" stepKey="createBundleProduct"/> + <createData entity="MultipleSelectOption" stepKey="createBundleOption1_1"> + <requiredEntity createDataKey="createBundleProduct"/> + <field key="required">false</field> + </createData> + <createData entity="CheckboxOption" stepKey="createBundleOption1_2"> + <requiredEntity createDataKey="createBundleProduct"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct1"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct2"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_1"/> + <requiredEntity createDataKey="simpleProduct2"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct3"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct3"/> + </createData> + <createData entity="ApiBundleLink" stepKey="linkOptionToProduct4"> + <requiredEntity createDataKey="createBundleProduct"/> + <requiredEntity createDataKey="createBundleOption1_2"/> + <requiredEntity createDataKey="simpleProduct4"/> + </createData> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml index af93200f946d2..9dc30e73228d3 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml @@ -60,4 +60,19 @@ <requiredEntity type="custom_attribute">CustomAttributeDynamicPrice</requiredEntity> <requiredEntity type="custom_attribute">CustomAttributePriceViewRange</requiredEntity> </entity> + <entity name="ApiFixedBundleProduct" type="product2"> + <data key="name" unique="suffix">Api Fixed Bundle Product</data> + <data key="sku" unique="suffix">api-fixed-bundle-product</data> + <data key="type_id">bundle</data> + <data key="attribute_set_id">4</data> + <data key="price">1.23</data> + <data key="visibility">4</data> + <data key="status">1</data> + <data key="urlKey" unique="suffix">api-fixed-bundle-product</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute">ApiProductDescription</requiredEntity> + <requiredEntity type="custom_attribute">ApiProductShortDescription</requiredEntity> + <requiredEntity type="custom_attribute">CustomAttributeFixPrice</requiredEntity> + <requiredEntity type="custom_attribute">CustomAttributePriceView</requiredEntity> + </entity> </entities> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml new file mode 100644 index 0000000000000..4db18bb4d5b4b --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateApiConfigurableProductActionGroup"> + <!-- Create the configurable product based on the data in the /data folder --> + <createData entity="ApiConfigurableProductWithOutCategory" stepKey="createConfigProduct"/> + + <!-- Make the configurable product have two options, that are children of the default attribute set --> + <createData entity="productAttributeWithTwoOptions" stepKey="createConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getConfigAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + + <!-- Create the 2 children that will be a part of the configurable product --> + <createData entity="ApiSimpleOne" stepKey="createConfigChildProduct1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + </createData> + <createData entity="ApiSimpleTwo" stepKey="createConfigChildProduct2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + + <!-- Assign the two products to the configurable product --> + <createData entity="ConfigurableProductTwoOptions" stepKey="createConfigProductOption"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild1"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigChildProduct1"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild2"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigChildProduct2"/> + </createData> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductData.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductData.xml index 2d42e12912cbb..e7d9d61491a32 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductData.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductData.xml @@ -36,6 +36,17 @@ <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> + <entity name="ApiConfigurableProductWithOutCategory" type="product"> + <data key="sku" unique="suffix">api-configurable-product-with-out-category</data> + <data key="type_id">configurable</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">API Configurable Product</data> + <data key="urlKey" unique="suffix">api-configurable-product</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + </entity> <entity name="ApiConfigurableProductWithDescription" type="product"> <data key="sku" unique="suffix">api-configurable-product</data> <data key="type_id">configurable</data> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml new file mode 100644 index 0000000000000..e6735dc87c4e3 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!--Reset the Customer Group grid to the default view--> + <actionGroup name="AdminCustomerGroupResetFilterActionGroup"> + <conditionalClick selector="{{AdminCustomerGroupFiltersSection.clearFilters}}" dependentSelector="{{AdminCustomerGroupFiltersSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> + <click selector="{{AdminCustomerGroupFiltersSection.viewDropdown}}" stepKey="openViewBookmarksTab"/> + <click selector="{{AdminCustomerGroupFiltersSection.viewBookmark('Default View')}}" stepKey="resetToDefaultGridView"/> + <waitForPageLoad stepKey="waitForProductGridLoad"/> + <see selector="{{AdminCustomerGroupFiltersSection.viewDropdown}}" userInput="Default View" stepKey="seeDefaultViewSelected"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml new file mode 100644 index 0000000000000..62aa1c4f155ea --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminFilterCustomerGroupByNameActionGroup"> + <arguments> + <argument name="customerGroupName" type="string"/> + </arguments> + <click selector="{{AdminCustomerGroupFiltersSection.filterButton}}" stepKey="openFiltersSectionOnCustomerGroupIndexPage"/> + <conditionalClick selector="{{AdminCustomerGroupFiltersSection.clearFiltersButton}}" dependentSelector="{{AdminCustomerGroupFiltersSection.clearFiltersButton}}" visible="true" stepKey="cleanFiltersIfTheySet"/> + <fillField userInput="{{customerGroupName}}" selector="{{AdminCustomerGroupFiltersSection.nameField}}" stepKey="fillNameFieldOnFiltersSection"/> + <click selector="{{AdminCustomerGroupFiltersSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml new file mode 100644 index 0000000000000..f375cfc4777aa --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminCustomerGroupsIndexPage" url="/customer/group/" area="admin" module="Magento_Customer"> + <section name="AdminCustomerGroupGridActionsSection"/> + <section name="AdminCustomerGroupFiltersSection"/> + </page> +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml new file mode 100644 index 0000000000000..ca85c35bea7b7 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCustomerGroupFiltersSection"> + <element name="filterButton" type="button" selector="//div[@class='data-grid-filters-action-wrap']/button" timeout="30"/> + <element name="clearFiltersButton" type="button" selector="//div[@class='admin__data-grid-header']//button[@class='action-tertiary action-clear']" timeout="10"/> + <element name="applyFilters" type="button" selector="button[data-action=grid-filter-apply]" timeout="30"/> + <element name="nameField" type="input" selector=".admin__data-grid-filters-wrap._show input[name='customer_group_code']" timeout="30"/> + <element name="clearFilters" type="button" selector=".admin__data-grid-header button[data-action='grid-filter-reset']" timeout="30"/> + <element name="viewDropdown" type="button" selector=".admin__data-grid-action-bookmarks button.admin__action-dropdown"/> + <element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml new file mode 100644 index 0000000000000..14737b1ef3eed --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCustomerGroupGridActionsSection"> + <element name="selectButton" type="button" selector="table.data-grid button.action-select" timeout="30"/> + <element name="selectButtonItem" type="text" selector="//ul[@class='action-menu _active']//a[contains(text(), '{{selectItem}}')]" timeout="30" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml new file mode 100644 index 0000000000000..a543ea15baec6 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCustomerGroupMainActionsSection"> + <element name="popupOkButton" type="button" selector="button.action-primary.action-accept" timeout="30"/> + </section> +</sections> From bf00d8376175395519ee40a742442116219291c6 Mon Sep 17 00:00:00 2001 From: Stas Puga <stas.puga@transoftgroup.com> Date: Thu, 13 Sep 2018 12:36:57 +0300 Subject: [PATCH 14/54] MAGETWO-94894: Reward Points functionality can be disabled/enabled on Storefront --- .../Mftf/Page/StorefrontCustomerDashboardPage.xml | 1 + .../Section/StorefrontCustomerSidebarSection.xml | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerSidebarSection.xml diff --git a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerDashboardPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerDashboardPage.xml index c4f03659c12af..eaca1c820e49e 100644 --- a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerDashboardPage.xml +++ b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerDashboardPage.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="StorefrontCustomerDashboardPage" url="/customer/account/" area="storefront" module="Magento_Customer"> <section name="StorefrontCustomerDashboardAccountInformationSection" /> + <section name="StorefrontCustomerSidebarSection"/> </page> </pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerSidebarSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerSidebarSection.xml new file mode 100644 index 0000000000000..7482193031091 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerSidebarSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="StorefrontCustomerSidebarSection"> + <element name="sidebarTab" type="text" selector="//div[@id='block-collapsible-nav']//a[text()='{{var1}}']" parameterized="true"/> + </section> +</sections> From c1893703e96aa4c4bcd2b07a50143c67f990f77b Mon Sep 17 00:00:00 2001 From: Dmitriy Kogut <kogut.dmitriy@gmail.com> Date: Thu, 13 Sep 2018 21:42:41 +0300 Subject: [PATCH 15/54] MAGETWO-93830: Automate with MFTF Sort products grid after removing shared catalog --- .../ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml | 2 +- .../ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml | 2 +- .../Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml | 2 +- .../Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml | 2 +- .../Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml | 2 +- .../Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml index e6735dc87c4e3..85e561d1f5750 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml @@ -7,7 +7,7 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <!--Reset the Customer Group grid to the default view--> <actionGroup name="AdminCustomerGroupResetFilterActionGroup"> <conditionalClick selector="{{AdminCustomerGroupFiltersSection.clearFilters}}" dependentSelector="{{AdminCustomerGroupFiltersSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml index 62aa1c4f155ea..df43290983770 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml @@ -7,7 +7,7 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminFilterCustomerGroupByNameActionGroup"> <arguments> <argument name="customerGroupName" type="string"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml index f375cfc4777aa..07d1b04dcb411 100644 --- a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml @@ -7,7 +7,7 @@ --> <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="AdminCustomerGroupsIndexPage" url="/customer/group/" area="admin" module="Magento_Customer"> <section name="AdminCustomerGroupGridActionsSection"/> <section name="AdminCustomerGroupFiltersSection"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml index ca85c35bea7b7..439ef1a5e7c57 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminCustomerGroupFiltersSection"> <element name="filterButton" type="button" selector="//div[@class='data-grid-filters-action-wrap']/button" timeout="30"/> <element name="clearFiltersButton" type="button" selector="//div[@class='admin__data-grid-header']//button[@class='action-tertiary action-clear']" timeout="10"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml index 14737b1ef3eed..bb2615483ed5c 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminCustomerGroupGridActionsSection"> <element name="selectButton" type="button" selector="table.data-grid button.action-select" timeout="30"/> <element name="selectButtonItem" type="text" selector="//ul[@class='action-menu _active']//a[contains(text(), '{{selectItem}}')]" timeout="30" parameterized="true"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml index a543ea15baec6..3f654c1c94c27 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminCustomerGroupMainActionsSection"> <element name="popupOkButton" type="button" selector="button.action-primary.action-accept" timeout="30"/> </section> From 4edafcf23aaf778aff5dd42e606b6c4500a78986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20der=20Linden?= <daniel.van.der.linden@guapa.nl> Date: Fri, 14 Sep 2018 10:30:09 +0200 Subject: [PATCH 16/54] Fix 2 api GQL API tests with expected exception messages --- .../Magento/GraphQl/Catalog/ProductSearchTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php index f1a79490b3dcf..264670f4159ae 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php @@ -381,13 +381,13 @@ public function testSearchWithFilterWithPageSizeEqualTotalCount() } QUERY; $this->expectException(\Exception::class); - $this->expectExceptionMessage('GraphQL response contains errors: currentPage value 1 specified is greater ' . - 'than the number of pages available.'); + $this->expectExceptionMessage('GraphQL response contains errors: currentPage value 2 specified is greater ' . + 'than the 1 page(s) available'); $this->graphQlQuery($query); } /** - * The query returns a total_count of 2 records; setting the pageSize = 1 and currentPage2 + * The query returns a total_count of 2 records; setting the pageSize = 1 and currentPage = 2 * Expected result is to get the second product on the list on the second page * * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php @@ -449,7 +449,7 @@ public function testSearchWithFilterPageSizeLessThanCurrentPage() * @var ProductRepositoryInterface $productRepository */ $productRepository = ObjectManager::getInstance()->get(ProductRepositoryInterface::class); - // when pagSize =1 and currentPage = 2, it should have simple2 on first page and simple1 on 2nd page + // when pageSize = 1 and currentPage = 2, it should have simple2 on first page and simple1 on 2nd page // since sorting is done on price in the DESC order $product = $productRepository->get('simple1'); $filteredProducts = [$product]; @@ -1132,8 +1132,8 @@ public function testQueryPageOutOfBoundException() QUERY; $this->expectException(\Exception::class); - $this->expectExceptionMessage('GraphQL response contains errors: currentPage value 1 specified is greater ' . - 'than the number of pages available.'); + $this->expectExceptionMessage('GraphQL response contains errors: currentPage value 2 specified is greater ' . + 'than the 1 page(s) available.'); $this->graphQlQuery($query); } From a39b4a76e2011941da810e60c49ec2e94a4e5ea2 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Fri, 14 Sep 2018 16:53:08 +0300 Subject: [PATCH 17/54] MAGETWO-94948: Can't delete an option from Fixed Product Tax --- .../Helper/ProcessTaxAttribute.php | 56 +++++++++++++++++ .../AdminProductAddFPTValueSection.xml | 1 + ...inRemoveProductWeeeAttributeOptionTest.xml | 61 +++++++++++++++++++ .../Product/Form/Modifier/Weee.php | 6 ++ app/code/Magento/Weee/etc/di.xml | 3 + 5 files changed, 127 insertions(+) create mode 100644 app/code/Magento/Weee/Plugin/Catalog/Controller/Adminhtml/Product/Initialization/Helper/ProcessTaxAttribute.php create mode 100644 app/code/Magento/Weee/Test/Mftf/Test/AdminRemoveProductWeeeAttributeOptionTest.xml diff --git a/app/code/Magento/Weee/Plugin/Catalog/Controller/Adminhtml/Product/Initialization/Helper/ProcessTaxAttribute.php b/app/code/Magento/Weee/Plugin/Catalog/Controller/Adminhtml/Product/Initialization/Helper/ProcessTaxAttribute.php new file mode 100644 index 0000000000000..011a1b3f9766b --- /dev/null +++ b/app/code/Magento/Weee/Plugin/Catalog/Controller/Adminhtml/Product/Initialization/Helper/ProcessTaxAttribute.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Weee\Plugin\Catalog\Controller\Adminhtml\Product\Initialization\Helper; + +use Magento\Catalog\Model\Product; +use Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper; +use Magento\Framework\App\RequestInterface; + +/** + * Handles product tax attributes data initialization. + */ +class ProcessTaxAttribute +{ + /** + * @var RequestInterface + */ + private $request; + + /** + * @param RequestInterface $request + */ + public function __construct(RequestInterface $request) + { + $this->request = $request; + } + + /** + * @param Helper $subject + * @param Product $result + * @param Product $product + * @param array $productData + * @return Product + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterInitializeFromData( + Helper $subject, + Product $result, + Product $product, + array $productData + ): Product { + $attributes = $result->getAttributes(); + if (!empty($attributes)) { + foreach ($attributes as $attribute) { + if ($attribute->getFrontendInput() == 'weee' && !isset($productData[$attribute->getAttributeCode()])) { + $result->setData($attribute->getAttributeCode(), []); + } + } + } + + return $result; + } +} diff --git a/app/code/Magento/Weee/Test/Mftf/Section/AdminProductAddFPTValueSection.xml b/app/code/Magento/Weee/Test/Mftf/Section/AdminProductAddFPTValueSection.xml index eee3f421910e1..ebf9f41047124 100644 --- a/app/code/Magento/Weee/Test/Mftf/Section/AdminProductAddFPTValueSection.xml +++ b/app/code/Magento/Weee/Test/Mftf/Section/AdminProductAddFPTValueSection.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminProductAddFPTValueSection"> <element name="addFPT" type="button" selector="[data-index='{{FPTAttributeCode}}'] [data-action='add_new_row']" parameterized="true"/> + <element name="removeRowByIndex" type="button" selector="[data-index='{{FPTAttributeCode}}'] [data-action='remove_row']:nth-of-type({{rowIndex}})" parameterized="true"/> <element name="selectCountryForFPT" type="select" selector="(//select[contains(@name, 'product[{{FPTAttributeCode}}]') and contains(@name, '[country]')])[last()]" parameterized="true"/> <element name="selectStateForFPT" type="select" selector="(//select[contains(@name, 'product[{{FPTAttributeCode}}]') and contains(@name, '[state]')])[last()]" parameterized="true"/> <element name="setTaxValueForFPT" type="text" selector="(//input[contains(@name, 'product[{{FPTAttributeCode}}]') and contains(@name, '[value]')])[last()]" parameterized="true"/> diff --git a/app/code/Magento/Weee/Test/Mftf/Test/AdminRemoveProductWeeeAttributeOptionTest.xml b/app/code/Magento/Weee/Test/Mftf/Test/AdminRemoveProductWeeeAttributeOptionTest.xml new file mode 100644 index 0000000000000..2e3467fe2c7c5 --- /dev/null +++ b/app/code/Magento/Weee/Test/Mftf/Test/AdminRemoveProductWeeeAttributeOptionTest.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminRemoveProductWeeeAttributeOptionTest"> + <annotations> + <features value="Weee attribute options can be removed in product page"/> + <title value="Weee attribute options can be removed in product page"/> + <description value="Weee attribute options can be removed in product page"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-95033"/> + <group value="weee"/> + </annotations> + <before> + <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> + <requiredEntity createDataKey="createProductFPTAttribute"/> + </createData> + <createData entity="SimpleProduct2" stepKey="createSimpleProduct"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProductInitial"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProductInitial"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="AdminProductAddFPTValueActionGroup" stepKey="addWeeeAttributeValue"> + <argument name="FPTAttributeCode" value="$$createProductFPTAttribute.attribute_code$$"/> + <argument name="stateForFPT" value="California"/> + <argument name="valueForFPT" value="10"/> + </actionGroup> + <actionGroup ref="saveProductForm" stepKey="saveProductInitial"/> + </before> + <after> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductListing"/> + <waitForPageLoad stepKey="waitForProductListingPageLoad"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetGridToDefaultKeywordSearch"/> + <actionGroup ref="logout" stepKey="logout"/> + <deleteData createDataKey="createProductFPTAttribute" stepKey="deleteProductFPTAttribute"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + </after> + <!-- Test Steps --> + <!-- Step 1: Open created product edit page --> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <!-- Step 2: Remove weee attribute options --> + <click selector="{{AdminProductAddFPTValueSection.removeRowByIndex('$$createProductFPTAttribute.attribute_code$$','1')}}" stepKey="removeAttributeOption"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + <!-- Assert weee attribute options are empty --> + <dontSeeElement selector="{{AdminProductAddFPTValueSection.removeRowByIndex('$$createProductFPTAttribute.attribute_code$$','1')}}" stepKey="dontSeeOptions"/> + </test> +</tests> diff --git a/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php b/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php index c96a7a0200334..87dea65a41dcf 100644 --- a/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php +++ b/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php @@ -180,6 +180,7 @@ protected function modifyAttributeConfig($attributeCode, array $attributeConfig) 'component' => 'Magento_Weee/js/fpt-group', 'visible' => true, 'label' => __('Country/State'), + 'showLabel' => false, ], ], ], @@ -197,6 +198,7 @@ protected function modifyAttributeConfig($attributeCode, array $attributeConfig) 'validation' => [ 'required-entry' => true, ], + 'showLabel' => false, ], ], ], @@ -216,6 +218,7 @@ protected function modifyAttributeConfig($attributeCode, array $attributeConfig) ], 'caption' => '*', 'visible' => true, + 'showLabel' => false, ], ], ], @@ -233,6 +236,7 @@ protected function modifyAttributeConfig($attributeCode, array $attributeConfig) 'validation' => [ 'validate-fpt-group' => true ], + 'showLabel' => false, ], ], ], @@ -252,6 +256,7 @@ protected function modifyAttributeConfig($attributeCode, array $attributeConfig) 'validation' => [ 'required-entry' => true ], + 'showLabel' => false, ], ], ], @@ -267,6 +272,7 @@ protected function modifyAttributeConfig($attributeCode, array $attributeConfig) 'label' => __('Website'), 'visible' => $this->websiteManager->isMultiWebsites(), 'options' => $this->websiteManager->getWebsites($product, $eavAttribute), + 'showLabel' => false, ], ], ], diff --git a/app/code/Magento/Weee/etc/di.xml b/app/code/Magento/Weee/etc/di.xml index e52aebd3af8b5..8b433163cad22 100644 --- a/app/code/Magento/Weee/etc/di.xml +++ b/app/code/Magento/Weee/etc/di.xml @@ -78,4 +78,7 @@ </argument> </arguments> </type> + <type name="Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper"> + <plugin name="weeeAttributeOptionsProcess" type="Magento\Weee\Plugin\Catalog\Controller\Adminhtml\Product\Initialization\Helper\ProcessTaxAttribute"/> + </type> </config> From 026346a4a32b6ffdf2909ba47607a39439eccf02 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Mon, 17 Sep 2018 08:11:38 +0300 Subject: [PATCH 18/54] MAGETWO-94948: Can't delete an option from Fixed Product Tax --- .../Product/Initialization/Helper/ProcessTaxAttribute.php | 4 ++++ .../Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Weee/Plugin/Catalog/Controller/Adminhtml/Product/Initialization/Helper/ProcessTaxAttribute.php b/app/code/Magento/Weee/Plugin/Catalog/Controller/Adminhtml/Product/Initialization/Helper/ProcessTaxAttribute.php index 011a1b3f9766b..4aa941cd13796 100644 --- a/app/code/Magento/Weee/Plugin/Catalog/Controller/Adminhtml/Product/Initialization/Helper/ProcessTaxAttribute.php +++ b/app/code/Magento/Weee/Plugin/Catalog/Controller/Adminhtml/Product/Initialization/Helper/ProcessTaxAttribute.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Weee\Plugin\Catalog\Controller\Adminhtml\Product\Initialization\Helper; use Magento\Catalog\Model\Product; @@ -28,6 +30,8 @@ public function __construct(RequestInterface $request) } /** + * Handles product tax attributes data initialization. + * * @param Helper $subject * @param Product $result * @param Product $product diff --git a/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php b/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php index 87dea65a41dcf..26f135b56d11f 100644 --- a/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php +++ b/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php @@ -85,7 +85,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function modifyData(array $data) { @@ -93,7 +93,7 @@ public function modifyData(array $data) } /** - * {@inheritdoc} + * @inheritdoc */ public function modifyMeta(array $meta) { From ef21c8811b3cd127dbdd53bb32a081e9b9c06cc6 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Mon, 17 Sep 2018 11:40:26 +0300 Subject: [PATCH 19/54] MAGETWO-94946: Tax isn't calculated for all type of virtual products if use PayPal checkout as payment method. --- app/code/Magento/Paypal/Model/Api/PayflowNvp.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/Paypal/Model/Api/PayflowNvp.php b/app/code/Magento/Paypal/Model/Api/PayflowNvp.php index 6373c6d99fb16..861d3ebcc9bc2 100644 --- a/app/code/Magento/Paypal/Model/Api/PayflowNvp.php +++ b/app/code/Magento/Paypal/Model/Api/PayflowNvp.php @@ -136,6 +136,9 @@ class PayflowNvp extends \Magento\Paypal\Model\Api\Nvp 'CVV2MATCH' => 'cvv2_check_result', 'USERSELECTEDFUNDINGSOURCE' => 'funding_source', + + 'NOSHIPPING' => 'suppress_shipping', + 'REQBILLINGADDRESS' => 'require_billing_address', ]; /** @@ -248,6 +251,8 @@ class PayflowNvp extends \Magento\Paypal\Model\Api\Nvp 'PAYFLOWCOLOR', 'LOCALECODE', 'USERSELECTEDFUNDINGSOURCE', + 'NOSHIPPING', + 'REQBILLINGADDRESS', ]; /** From 790d4359b41da0909a2a81350e079ec7fdad8a37 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Mon, 17 Sep 2018 12:40:42 +0300 Subject: [PATCH 20/54] MAGETWO-94946: Tax isn't calculated for all type of virtual products if use PayPal checkout as payment method. --- app/code/Magento/Paypal/Model/Api/PayflowNvp.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Paypal/Model/Api/PayflowNvp.php b/app/code/Magento/Paypal/Model/Api/PayflowNvp.php index 861d3ebcc9bc2..b769cbe43645e 100644 --- a/app/code/Magento/Paypal/Model/Api/PayflowNvp.php +++ b/app/code/Magento/Paypal/Model/Api/PayflowNvp.php @@ -732,6 +732,7 @@ protected function _prepareExpressCheckoutCallRequest(&$requestFields) /** * Additional response processing. + * * Hack to cut off length from API type response params. * * @param array $response @@ -789,7 +790,8 @@ protected function _exportLineItems(array &$request, $i = 0) } /** - * Set specific data when negative line item case + * Set specific data when negative line item case. + * * @return void */ protected function _setSpecificForNegativeLineItems() From 01404a02c0102e3dee9d649aa6baa46bc9e2d4a8 Mon Sep 17 00:00:00 2001 From: Roman Glushko <r.glushko@atwix.com> Date: Mon, 17 Sep 2018 22:31:23 +0300 Subject: [PATCH 21/54] #141 Added descriptions to classes and methods --- .../Model/Product/Option/DateType.php | 13 +++++++++++-- .../QuoteGraphQl/Model/Hydrator/CartHydrator.php | 5 +++++ .../Model/Resolver/Cart/AddSimpleProductsToCart.php | 5 ++++- .../Model/Resolver/CartItemTypeResolver.php | 4 ++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index f3f74867128f5..364df839479cd 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -8,6 +8,7 @@ namespace Magento\CatalogGraphQl\Model\Product\Option; use Magento\Catalog\Model\Product\Option\Type\Date as ProductDateOptionType; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Stdlib\DateTime; /** @@ -16,6 +17,8 @@ class DateType extends ProductDateOptionType { /** + * Make valid string as a value of date option type for GraphQl queries + * * {@inheritdoc} */ public function validateUserValue($values) @@ -28,8 +31,12 @@ public function validateUserValue($values) } /** - * @param array $values - * @return array mixed + * Format date value from string to date array + * + * @param [] $values + * + * @return [] + * @throws LocalizedException */ protected function formatValues($values) { @@ -51,6 +58,8 @@ protected function formatValues($values) } /** + * Check if calendar should be shown + * * @return bool */ public function useCalendar() diff --git a/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php b/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php index 1f3852aaf1e67..55ad50f9ca5d6 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php +++ b/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php @@ -12,12 +12,17 @@ use Magento\Quote\Model\Quote\Item as QuoteItem; /** + * Cart Hydrator class + * * {@inheritdoc} */ class CartHydrator { /** + * Hydrate cart to plain array + * * @param CartInterface|Quote $cart + * * @return array */ public function hydrate(CartInterface $cart): array diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php index cc44b1071b396..d7d4956675764 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php @@ -11,7 +11,6 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Framework\DataObject; use Magento\Framework\DataObjectFactory; -use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; @@ -29,6 +28,8 @@ use Magento\QuoteGraphQl\Model\Hydrator\CartHydrator; /** + * Add simple product to cart GraphQl resolver + * * {@inheritdoc} */ class AddSimpleProductsToCart implements ResolverInterface @@ -112,6 +113,8 @@ public function __construct( } /** + * Resolve adding simple product to cart for customers/guests + * * {@inheritDoc} */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php index 75232190b7361..583ef6e33c6d3 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php @@ -11,6 +11,8 @@ use Magento\Framework\GraphQl\Query\Resolver\TypeResolverInterface; /** + * Resolver for cart item types that vary by product types + * * {@inheritdoc} */ class CartItemTypeResolver implements TypeResolverInterface @@ -29,6 +31,8 @@ public function __construct(array $cartItemTypes = []) } /** + * Resolve GraphQl types to retrieve product type specific information about cart items + * * {@inheritdoc} * @throws GraphQlInputException */ From 78c22fd2ce26f80b5294ce9b672ece2fb9de2994 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Tue, 18 Sep 2018 13:13:22 +0300 Subject: [PATCH 22/54] MAGETWO-94838: Automate with MFTF Ability to configure Advanced Prices from Shared Catalog Page for different type of products --- ...reateApiConfigurableProductActionGroup.xml | 4 ++-- ...minCustomerGroupResetFilterActionGroup.xml | 19 ------------------ ...inFilterCustomerGroupByNameActionGroup.xml | 8 ++++---- .../Page/AdminCustomerGroupsIndexPage.xml | 1 - .../AdminCustomerGroupFiltersSection.xml | 20 ------------------- .../AdminCustomerGroupGridActionsSection.xml | 4 ++-- .../AdminCustomerGroupMainActionsSection.xml | 14 ------------- 7 files changed, 8 insertions(+), 62 deletions(-) delete mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml delete mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml delete mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml index 4db18bb4d5b4b..e0be4e76239f0 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml @@ -12,7 +12,7 @@ <!-- Create the configurable product based on the data in the /data folder --> <createData entity="ApiConfigurableProductWithOutCategory" stepKey="createConfigProduct"/> - <!-- Make the configurable product have two options, that are children of the default attribute set --> + <!-- Create attribute with 2 options to be used in children products --> <createData entity="productAttributeWithTwoOptions" stepKey="createConfigProductAttribute"/> <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption1"> <requiredEntity createDataKey="createConfigProductAttribute"/> @@ -20,7 +20,7 @@ <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOption2"> <requiredEntity createDataKey="createConfigProductAttribute"/> </createData> - <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <createData entity="AddToDefaultSet" stepKey="addAttributeToAttributeSet"> <requiredEntity createDataKey="createConfigProductAttribute"/> </createData> <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption1"> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml deleted file mode 100644 index e6735dc87c4e3..0000000000000 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <!--Reset the Customer Group grid to the default view--> - <actionGroup name="AdminCustomerGroupResetFilterActionGroup"> - <conditionalClick selector="{{AdminCustomerGroupFiltersSection.clearFilters}}" dependentSelector="{{AdminCustomerGroupFiltersSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> - <click selector="{{AdminCustomerGroupFiltersSection.viewDropdown}}" stepKey="openViewBookmarksTab"/> - <click selector="{{AdminCustomerGroupFiltersSection.viewBookmark('Default View')}}" stepKey="resetToDefaultGridView"/> - <waitForPageLoad stepKey="waitForProductGridLoad"/> - <see selector="{{AdminCustomerGroupFiltersSection.viewDropdown}}" userInput="Default View" stepKey="seeDefaultViewSelected"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml index 62aa1c4f155ea..a05139e4e1564 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml @@ -12,9 +12,9 @@ <arguments> <argument name="customerGroupName" type="string"/> </arguments> - <click selector="{{AdminCustomerGroupFiltersSection.filterButton}}" stepKey="openFiltersSectionOnCustomerGroupIndexPage"/> - <conditionalClick selector="{{AdminCustomerGroupFiltersSection.clearFiltersButton}}" dependentSelector="{{AdminCustomerGroupFiltersSection.clearFiltersButton}}" visible="true" stepKey="cleanFiltersIfTheySet"/> - <fillField userInput="{{customerGroupName}}" selector="{{AdminCustomerGroupFiltersSection.nameField}}" stepKey="fillNameFieldOnFiltersSection"/> - <click selector="{{AdminCustomerGroupFiltersSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openFiltersSectionOnCustomerGroupIndexPage"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="cleanFiltersIfTheySet"/> + <fillField userInput="{{customerGroupName}}" selector="{{AdminDataGridHeaderSection.filterFieldInput('customer_group_code')}}" stepKey="fillNameFieldOnFiltersSection"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml index f375cfc4777aa..61afa18d21404 100644 --- a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml @@ -10,6 +10,5 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> <page name="AdminCustomerGroupsIndexPage" url="/customer/group/" area="admin" module="Magento_Customer"> <section name="AdminCustomerGroupGridActionsSection"/> - <section name="AdminCustomerGroupFiltersSection"/> </page> </pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml deleted file mode 100644 index ca85c35bea7b7..0000000000000 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="AdminCustomerGroupFiltersSection"> - <element name="filterButton" type="button" selector="//div[@class='data-grid-filters-action-wrap']/button" timeout="30"/> - <element name="clearFiltersButton" type="button" selector="//div[@class='admin__data-grid-header']//button[@class='action-tertiary action-clear']" timeout="10"/> - <element name="applyFilters" type="button" selector="button[data-action=grid-filter-apply]" timeout="30"/> - <element name="nameField" type="input" selector=".admin__data-grid-filters-wrap._show input[name='customer_group_code']" timeout="30"/> - <element name="clearFilters" type="button" selector=".admin__data-grid-header button[data-action='grid-filter-reset']" timeout="30"/> - <element name="viewDropdown" type="button" selector=".admin__data-grid-action-bookmarks button.admin__action-dropdown"/> - <element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> - </section> -</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml index 14737b1ef3eed..2636555af88a3 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml @@ -9,7 +9,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminCustomerGroupGridActionsSection"> - <element name="selectButton" type="button" selector="table.data-grid button.action-select" timeout="30"/> - <element name="selectButtonItem" type="text" selector="//ul[@class='action-menu _active']//a[contains(text(), '{{selectItem}}')]" timeout="30" parameterized="true"/> + <element name="selectButton" type="button" selector="//div[text()='{{NAME_FIELD}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//button[text()='Select']" timeout="30" parameterized="true"/> + <element name="actionsMenuButton" type="text" selector="//div[text()='{{NAME_FIELD}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='{{selectItem}}']" timeout="30" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml deleted file mode 100644 index a543ea15baec6..0000000000000 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="AdminCustomerGroupMainActionsSection"> - <element name="popupOkButton" type="button" selector="button.action-primary.action-accept" timeout="30"/> - </section> -</sections> From 27043e9bc7bca9039e12f076dc1cb976fa4bdea4 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Tue, 18 Sep 2018 14:54:38 +0300 Subject: [PATCH 23/54] MAGETWO-94889: Automate with MFTF Free Shipping is not available in Admin if "Minimum Order Amount" does not match Order total --- .../ConfigFlatRateMethodActionGroup.xml | 33 --------------- .../ConfigFreeShippingMethodActionGroup.xml | 38 ----------------- .../Config/Test/Mftf/Page/AdminConfigPage.xml | 3 -- .../Mftf/Section/ShippingMethodsSection.xml | 24 ----------- .../AdminOrderDetailsMessagesSection.xml | 1 - ...nimumOrderAmountNotMatchOrderTotalTest.xml | 41 +++++++++---------- .../Mftf/Data/FlatRateShippingMethodData.xml | 7 ++++ .../Test/Mftf/Data/FreeShippingMethodData.xml | 14 +++++++ 8 files changed, 41 insertions(+), 120 deletions(-) delete mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFlatRateMethodActionGroup.xml delete mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFreeShippingMethodActionGroup.xml delete mode 100644 app/code/Magento/Config/Test/Mftf/Section/ShippingMethodsSection.xml diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFlatRateMethodActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFlatRateMethodActionGroup.xml deleted file mode 100644 index cbb2161a22e4b..0000000000000 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFlatRateMethodActionGroup.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="DisableFlatRate"> - <amOnPage url="{{AdminShippingMethodsPage.url}}" stepKey="navigateToShippingMethodsPageDisable"/> - <waitForPageLoad stepKey="waitForPageLoad"/> - <conditionalClick selector="{{ShippingMethodsSection.FlatRateTab}}" dependentSelector="{{ShippingMethodsSection.CheckIfFlatRateTabExpand}}" visible="true" stepKey="expandFlatRateTab"/> - <waitForElementVisible selector="{{ShippingMethodsSection.FlatRateEnabled}}" stepKey="seeFlatRate"/> - <uncheckOption selector="{{ShippingMethodsSection.EnableFlatRateEnabled}}" stepKey="uncheckUseSystemValue"/> - <selectOption selector="{{ShippingMethodsSection.FlatRateEnabled}}" userInput="No" stepKey="setDisable"/> - <click selector="{{ShippingMethodsSection.FlatRateTab}}" stepKey="collapseFlatRateTab"/> - <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfig" /> - <seeElement selector="{{AdminMessagesSection.success}}" stepKey="seeSuccessMessage"/> - </actionGroup> - <actionGroup name="EnableFlatRate"> - <amOnPage url="{{AdminShippingMethodsPage.url}}" stepKey="navigateToShippingMethodsPage"/> - <waitForPageLoad stepKey="waitForPageLoad2"/> - <conditionalClick selector="{{ShippingMethodsSection.FlatRateTab}}" dependentSelector="{{ShippingMethodsSection.CheckIfFlatRateTabExpand}}" visible="true" stepKey="openFlatRateTab"/> - <waitForElementVisible selector="{{ShippingMethodsSection.FlatRateEnabled}}" stepKey="seeFlatRate2"/> - <selectOption selector="{{ShippingMethodsSection.FlatRateEnabled}}" userInput="Yes" stepKey="enableFlatRate"/> - <checkOption selector="{{ShippingMethodsSection.EnableFlatRateEnabled}}" stepKey="useSystemValue"/> - <click selector="{{ShippingMethodsSection.FlatRateTab}}" stepKey="collapseFlatRateTab2"/> - <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfiguration"/> - <seeElement selector="{{AdminMessagesSection.success}}" stepKey="seeSuccessMessage"/> - </actionGroup> -</actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFreeShippingMethodActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFreeShippingMethodActionGroup.xml deleted file mode 100644 index b49d60cd2be43..0000000000000 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigFreeShippingMethodActionGroup.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="DisableFreeShipping"> - <amOnPage url="{{AdminShippingMethodsPage.url}}" stepKey="navigateToShippingMethodsPageDisable"/> - <waitForPageLoad stepKey="waitForPageLoad"/> - <conditionalClick selector="{{ShippingMethodsSection.FreeShippingTab}}" dependentSelector="{{ShippingMethodsSection.CheckIfFreeShippingTabExpand}}" visible="true" stepKey="expandFreeShippingTab"/> - <waitForElementVisible selector="{{ShippingMethodsSection.FreeShippingEnabled}}" stepKey="seeFreeShipping"/> - <selectOption selector="{{ShippingMethodsSection.FreeShippingEnabled}}" userInput="No" stepKey="setDisable"/> - <checkOption selector="{{ShippingMethodsSection.EnableFreeShippingEnabled}}" stepKey="useSystemValue"/> - <clearField selector="{{ShippingMethodsSection.MinimumOrderAmount}}" stepKey="deleteMinimumOrderAmount"/> - <click selector="{{ShippingMethodsSection.FreeShippingTab}}" stepKey="collapseFreeShippingTab"/> - <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfig" /> - <seeElement selector="{{AdminMessagesSection.success}}" stepKey="seeSuccessMessage"/> - </actionGroup> - <actionGroup name="EnableFreeShipping"> - <arguments> - <argument name="orderAmount" defaultValue="" type="string"/> - </arguments> - <amOnPage url="{{AdminShippingMethodsPage.url}}" stepKey="navigateToShippingMethodsPage"/> - <waitForPageLoad stepKey="waitForPageLoad"/> - <conditionalClick selector="{{ShippingMethodsSection.FreeShippingTab}}" dependentSelector="{{ShippingMethodsSection.CheckIfFreeShippingTabExpand}}" visible="true" stepKey="openFreeShippingTab"/> - <waitForElementVisible selector="{{ShippingMethodsSection.FreeShippingEnabled}}" stepKey="seeFreeShipping2"/> - <uncheckOption selector="{{ShippingMethodsSection.EnableFreeShippingEnabled}}" stepKey="uncheckUseSystemValue"/> - <selectOption selector="{{ShippingMethodsSection.FreeShippingEnabled}}" userInput="Yes" stepKey="enableFreeShipping"/> - <fillField selector="{{ShippingMethodsSection.MinimumOrderAmount}}" userInput="{{orderAmount}}" stepKey="enterMinimumOrderAmount"/> - <click selector="{{ShippingMethodsSection.FreeShippingTab}}" stepKey="collapseFreeShippingTab2"/> - <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfiguration"/> - <seeElement selector="{{AdminMessagesSection.success}}" stepKey="seeSuccessMessage"/> - </actionGroup> -</actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml b/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml index 2237b13005fb3..7a62dfff8323b 100644 --- a/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml +++ b/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml @@ -21,7 +21,4 @@ <page name="AdminConfigGeneralPage" url="admin/system_config/edit/section/general/" area="admin" module="Magento_Config"> <section name="GeneralSection"/> </page> - <page name="AdminShippingMethodsPage" url="admin/system_config/edit/section/carriers/" area="admin" module="Magento_Config"> - <section name="ShippingMethodsSection"/> - </page> </pages> diff --git a/app/code/Magento/Config/Test/Mftf/Section/ShippingMethodsSection.xml b/app/code/Magento/Config/Test/Mftf/Section/ShippingMethodsSection.xml deleted file mode 100644 index db3128d70006d..0000000000000 --- a/app/code/Magento/Config/Test/Mftf/Section/ShippingMethodsSection.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> - <section name="ShippingMethodsSection"> - <!--Flat Rate tab in Shipping Methods--> - <element name="FlatRateTab" type="button" selector="#carriers_flatrate-head"/> - <element name="CheckIfFlatRateTabExpand" type="button" selector="#carriers_flatrate-head:not(.open)"/> - <element name="FlatRateEnabled" type="button" selector="#carriers_flatrate_active"/> - <element name="EnableFlatRateEnabled" type="checkbox" selector="#carriers_flatrate_active_inherit"/> - <!--Free Shipping tab in Shipping Methods--> - <element name="FreeShippingTab" type="button" selector="#carriers_freeshipping-head"/> - <element name="CheckIfFreeShippingTabExpand" type="button" selector="#carriers_freeshipping-head:not(.open)"/> - <element name="FreeShippingEnabled" type="button" selector="#carriers_freeshipping_active"/> - <element name="EnableFreeShippingEnabled" type="checkbox" selector="#carriers_freeshipping_active_inherit"/> - <element name="MinimumOrderAmount" type="input" selector="#carriers_freeshipping_free_shipping_subtotal"/> - </section> -</sections> \ No newline at end of file diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsMessagesSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsMessagesSection.xml index 2dd515a28dc99..1bc3718467102 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsMessagesSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsMessagesSection.xml @@ -10,6 +10,5 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminOrderDetailsMessagesSection"> <element name="successMessage" type="text" selector="div.message-success"/> - <element name="errorMessage" type="text" selector="div.message-error"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminFreeShippingNotAvailableIfMinimumOrderAmountNotMatchOrderTotalTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminFreeShippingNotAvailableIfMinimumOrderAmountNotMatchOrderTotalTest.xml index 8f5715ed69b45..5f6ea0937b52a 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminFreeShippingNotAvailableIfMinimumOrderAmountNotMatchOrderTotalTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminFreeShippingNotAvailableIfMinimumOrderAmountNotMatchOrderTotalTest.xml @@ -23,42 +23,41 @@ <requiredEntity createDataKey="createCategory"/> <field key="price">100</field> </createData> - <createData entity="Simple_US_Customer" stepKey="customer"/> + <createData entity="Simple_US_Customer" stepKey="createCustomer"/> + <createData entity="DisableFlatRateShippingMethodConfig" stepKey="disableFlatRate"/> + <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShippingMethod"/> + <createData entity="setFreeShippingSubtotal" stepKey="setFreeShippingSubtotal"/> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> - <actionGroup ref="DisableFlatRate" stepKey="disableFlatRate"/> - <actionGroup ref="EnableFreeShipping" stepKey="enableFreeShipping"> - <argument name="orderAmount" value="101"/> - </actionGroup> - <actionGroup ref="ClearCacheActionGroup" stepKey="clearCacheBefore"/> + <magentoCLI command="cache:flush" stepKey="flushCache"/> </before> <after> <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> - <deleteData createDataKey="customer" stepKey="deleteCustomer"/> - <actionGroup ref="EnableFlatRate" stepKey="enableFlatRate"/> - <actionGroup ref="DisableFreeShipping" stepKey="disableFreeShipping"/> - <actionGroup ref="ClearCacheActionGroup" stepKey="clearCacheAfter"/> - <amOnPage url="{{AdminLogoutPage.url}}" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <createData entity="FlatRateShippingMethodConfig" stepKey="enableFlatRate"/> + <createData entity="FreeShippinMethodDefault" stepKey="disableFreeShippingMethod"/> + <createData entity="setFreeShippingSubtotalToDefault" stepKey="setFreeShippingSubtotalToDefault"/> + <actionGroup ref="logout" stepKey="logout"/> + <magentoCLI command="cache:flush" stepKey="flushCache2"/> </after> - + <!--Create new order with existing customer--> <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="goToCreateOrderPage"> - <argument name="customer" value="Simple_US_Customer"/> + <argument name="customer" value="$$createCustomer$$"/> </actionGroup> - - <!--Admin creates order--> + <!--Add product to order--> <actionGroup ref="addSimpleProductToOrder" stepKey="addProductToOrder"> - <argument name="product" value="SimpleProduct"/> + <argument name="product" value="$$createProduct$$"/> </actionGroup> <click selector="{{AdminOrderFormPaymentSection.header}}" stepKey="unfocus"/> <waitForPageLoad stepKey="waitForJavascriptToFinish"/> - <click selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="clickShippingMethods"/> + <!--Click *Get shipping methods and rates* and see that Free Shipping is absent--> + <click selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="clickGetShippingMehods"/> <dontSeeElement selector="{{AdminOrderFormPaymentSection.freeShippingOption}}" stepKey="seeAbsentFreeShipping"/> - - <!--Submit Order and verify information--> + <!--Submit Order and verify that Order isn't placed--> <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="clickSubmitOrder"/> - <dontSeeElement selector="{{AdminOrderDetailsMessagesSection.successMessage}}" stepKey="seeSuccessMessage"/> - <seeElement selector="{{AdminOrderDetailsMessagesSection.errorMessage}}" stepKey="seeErrorMessage"/> + <dontSeeElement selector="{{AdminMessagesSection.successMessage}}" stepKey="seeSuccessMessage"/> + <seeElement selector="{{AdminMessagesSection.errorMessage}}" stepKey="seeErrorMessage"/> </test> </tests> \ No newline at end of file diff --git a/app/code/Magento/Shipping/Test/Mftf/Data/FlatRateShippingMethodData.xml b/app/code/Magento/Shipping/Test/Mftf/Data/FlatRateShippingMethodData.xml index 6c7e5cf1b18e0..6d877dac5cbf4 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Data/FlatRateShippingMethodData.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Data/FlatRateShippingMethodData.xml @@ -13,6 +13,13 @@ <entity name="flatRateActiveEnable" type="active"> <data key="value">1</data> </entity> + <!-- Disable Flat Rate Shipping method config --> + <entity name="DisableFlatRateShippingMethodConfig" type="flat_rate_shipping_method"> + <requiredEntity type="active">flatRateActiveDisable</requiredEntity> + </entity> + <entity name="flatRateActiveDisable" type="active"> + <data key="value">0</data> + </entity> <!-- Flat Rate Shipping method default setup --> <entity name="FlatRateShippingMethodDefault" type="flat_rate_shipping_method"> <requiredEntity type="active">flatRateActiveDefault</requiredEntity> diff --git a/app/code/Magento/Shipping/Test/Mftf/Data/FreeShippingMethodData.xml b/app/code/Magento/Shipping/Test/Mftf/Data/FreeShippingMethodData.xml index 110795533468e..512ef8389bb7b 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Data/FreeShippingMethodData.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Data/FreeShippingMethodData.xml @@ -52,4 +52,18 @@ <entity name="freeSortOrderDefault" type="sort_order"> <data key="value" /> </entity> + <!--Set Free Shipping Subtotal to 101--> + <entity name="setFreeShippingSubtotal" type="free_shipping_method"> + <requiredEntity type="free_shipping_subtotal">freeShippingSubtotal</requiredEntity> + </entity> + <entity name="freeShippingSubtotal" type="free_shipping_subtotal"> + <data key="value">101</data> + </entity> + <!--Set to default Free Shipping Subtotal--> + <entity name="setFreeShippingSubtotalToDefault" type="free_shipping_method"> + <requiredEntity type="free_shipping_subtotal">freeShippingSubtotalDefault</requiredEntity> + </entity> + <entity name="freeShippingSubtotalDefault" type="free_shipping_subtotal"> + <data key="value">0</data> + </entity> </entities> From 10648548d66c0dc0696fcad2af0ec21db8269e05 Mon Sep 17 00:00:00 2001 From: Roman Glushko <r.glushko@atwix.com> Date: Tue, 18 Sep 2018 22:07:02 +0300 Subject: [PATCH 24/54] #141 Performed decoupling of the resolvers --- .../Model/Product/Option/DateType.php | 8 +- .../Cart/AddSimpleProductToCartProcessor.php | 120 ++++++++++++ .../Resolver/Cart/AddSimpleProductsToCart.php | 67 ++----- .../Resolver/CartItem/CustomizableOptions.php | 155 +--------------- .../DataProvider/Cart}/CartHydrator.php | 6 +- .../CartItem/CustomizableOption.php | 174 ++++++++++++++++++ 6 files changed, 318 insertions(+), 212 deletions(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php rename app/code/Magento/QuoteGraphQl/Model/{Hydrator => Resolver/DataProvider/Cart}/CartHydrator.php (92%) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index 364df839479cd..d9308cf606e1f 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -13,12 +13,12 @@ /** * Catalog product option date validator + * {@inheritdoc} */ class DateType extends ProductDateOptionType { /** * Make valid string as a value of date option type for GraphQl queries - * * {@inheritdoc} */ public function validateUserValue($values) @@ -32,9 +32,7 @@ public function validateUserValue($values) /** * Format date value from string to date array - * * @param [] $values - * * @return [] * @throws LocalizedException */ @@ -58,9 +56,7 @@ protected function formatValues($values) } /** - * Check if calendar should be shown - * - * @return bool + * @inheritdoc */ public function useCalendar() { diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php b/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php new file mode 100644 index 0000000000000..ff02f48ef6659 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php @@ -0,0 +1,120 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Cart; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\DataObject; +use Magento\Framework\DataObjectFactory; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Stdlib\ArrayManager; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\CartInterface; +use Magento\Quote\Api\GuestCartRepositoryInterface; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\Item as QuoteItem; + +/** + * Add simple product to cart process + */ +class AddSimpleProductToCartProcessor +{ + /** + * @var ArrayManager + */ + private $arrayManager; + + /** + * @var CartRepositoryInterface + */ + private $cartRepository; + + /** + * @var MaskedQuoteIdToQuoteIdInterface + */ + private $maskedQuoteIdToQuoteId; + + /** + * @var DataObjectFactory + */ + private $dataObjectFactory; + + /** + * @var GuestCartRepositoryInterface + */ + private $guestCartRepository; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @param ArrayManager $arrayManager + * @param DataObjectFactory $dataObjectFactory + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + * @param CartRepositoryInterface $cartRepository + * @param GuestCartRepositoryInterface $guestCartRepository + * @param ProductRepositoryInterface $productRepository + */ + public function __construct( + ArrayManager $arrayManager, + DataObjectFactory $dataObjectFactory, + MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, + CartRepositoryInterface $cartRepository, + GuestCartRepositoryInterface $guestCartRepository, + ProductRepositoryInterface $productRepository + ) { + $this->productRepository = $productRepository; + $this->guestCartRepository = $guestCartRepository; + $this->dataObjectFactory = $dataObjectFactory; + $this->cartRepository = $cartRepository; + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->arrayManager = $arrayManager; + } + + /** + * Resolve adding simple product to cart for customers/guests + * @param CartInterface|Quote $cart + * @param array $cartItemData + * @return QuoteItem|string + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function process($cart, array $cartItemData) + { + $sku = $this->arrayManager->get('details/sku', $cartItemData); + $product = $this->productRepository->get($sku); + + return $cart->addProduct($product, $this->getBuyRequest($cartItemData)); + } + + /** + * Format GraphQl input data to a shape that buy request has + * @param array $cartItem + * @return DataObject + */ + private function getBuyRequest(array $cartItem): DataObject + { + $customOptions = []; + $qty = $this->arrayManager->get('details/qty', $cartItem); + $customizableOptions = $this->arrayManager->get('customizable_options', $cartItem, []); + + foreach ($customizableOptions as $customizableOption) { + $customOptions[$customizableOption['id']] = $customizableOption['value']; + } + + return $this->dataObjectFactory->create([ + 'data' => [ + 'qty' => $qty, + 'options' => $customOptions + ] + ]); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php index d7d4956675764..845ae75918851 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php @@ -8,9 +8,6 @@ namespace Magento\QuoteGraphQl\Model\Resolver\Cart; use Magento\Authorization\Model\UserContextInterface; -use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Framework\DataObject; -use Magento\Framework\DataObjectFactory; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; @@ -25,15 +22,20 @@ use Magento\Quote\Api\GuestCartRepositoryInterface; use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Quote\Model\Quote; -use Magento\QuoteGraphQl\Model\Hydrator\CartHydrator; +use Magento\QuoteGraphQl\Model\Cart\AddSimpleProductToCartProcessor; +use Magento\QuoteGraphQl\Model\Resolver\DataProvider\Cart\CartHydrator; /** * Add simple product to cart GraphQl resolver - * * {@inheritdoc} */ class AddSimpleProductsToCart implements ResolverInterface { + /** + * @var AddSimpleProductToCartProcessor + */ + private $addSimpleProductToCartProcessor; + /** * @var CartRepositoryInterface */ @@ -44,21 +46,11 @@ class AddSimpleProductsToCart implements ResolverInterface */ private $maskedQuoteIdToQuoteId; - /** - * @var DataObjectFactory - */ - private $dataObjectFactory; - /** * @var GuestCartRepositoryInterface */ private $guestCartRepository; - /** - * @var ProductRepositoryInterface - */ - private $productRepository; - /** * @var CartHydrator */ @@ -80,42 +72,38 @@ class AddSimpleProductsToCart implements ResolverInterface private $userContext; /** - * @param DataObjectFactory $dataObjectFactory + * @param AddSimpleProductToCartProcessor $addSimpleProductToCartProcessor * @param CartHydrator $cartHydrator * @param ArrayManager $arrayManager * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId * @param CartRepositoryInterface $cartRepository * @param GuestCartRepositoryInterface $guestCartRepository - * @param ProductRepositoryInterface $productRepository * @param ValueFactory $valueFactory * @param UserContextInterface $userContext */ public function __construct( - DataObjectFactory $dataObjectFactory, + AddSimpleProductToCartProcessor $addSimpleProductToCartProcessor, CartHydrator $cartHydrator, ArrayManager $arrayManager, MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, CartRepositoryInterface $cartRepository, GuestCartRepositoryInterface $guestCartRepository, - ProductRepositoryInterface $productRepository, ValueFactory $valueFactory, UserContextInterface $userContext ) { $this->valueFactory = $valueFactory; $this->userContext = $userContext; $this->arrayManager = $arrayManager; - $this->productRepository = $productRepository; $this->cartHydrator = $cartHydrator; $this->guestCartRepository = $guestCartRepository; - $this->dataObjectFactory = $dataObjectFactory; $this->cartRepository = $cartRepository; $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->addSimpleProductToCartProcessor = $addSimpleProductToCartProcessor; } /** * Resolve adding simple product to cart for customers/guests - * - * {@inheritDoc} + * {@inheritdoc} */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value { @@ -136,11 +124,10 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $cart = $this->getCart((string) $cartHash); - foreach ($cartItems as $cartItem) { - $sku = $this->arrayManager->get('details/sku', $cartItem); - $product = $this->productRepository->get($sku); + foreach ($cartItems as $cartItemData) { + $sku = $this->arrayManager->get('details/sku', $cartItemData); - $message = $cart->addProduct($product, $this->getBuyRequest($cartItem)); + $message = $this->addSimpleProductToCartProcessor->process($cart, $cartItemData); if (is_string($message)) { throw new GraphQlInputException( @@ -166,33 +153,8 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value return $this->valueFactory->create($result); } - /** - * Format GraphQl input data to a shape that buy request has - * - * @param array $cartItem - * @return DataObject - */ - private function getBuyRequest($cartItem): DataObject - { - $customOptions = []; - $qty = $this->arrayManager->get('details/qty', $cartItem); - $customizableOptions = $this->arrayManager->get('customizable_options', $cartItem, []); - - foreach ($customizableOptions as $customizableOption) { - $customOptions[$customizableOption['id']] = $customizableOption['value']; - } - - return $this->dataObjectFactory->create([ - 'data' => [ - 'qty' => $qty, - 'options' => $customOptions - ] - ]); - } - /** * Collecting cart errors - * * @param CartInterface|Quote $cart * @return string */ @@ -210,7 +172,6 @@ private function getCartErrors($cart): string /** * Retrieving quote mode based on customer authorization - * * @param string $cartHash * @return CartInterface|Quote * @throws NoSuchEntityException diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php index 67318be917c82..8961fea3acb4d 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php @@ -8,22 +8,13 @@ namespace Magento\QuoteGraphQl\Model\Resolver\CartItem; use Magento\Authorization\Model\UserContextInterface; -use Magento\Catalog\Api\Data\ProductCustomOptionInterface; -use Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface; -use Magento\Catalog\Model\Product\Option\Type\DefaultType as DefaultOptionType; -use Magento\Catalog\Model\Product\Option\Type\Select as SelectOptionType; -use Magento\Catalog\Model\Product\Option\Type\Text as TextOptionType; -use Magento\Framework\Exception\LocalizedException; -use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Query\Resolver\Value; use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Quote\Model\Quote\Item as QuoteItem; -use Magento\Store\Api\Data\StoreInterface; -use Magento\Store\Model\Store; -use Magento\Store\Model\StoreManagerInterface; +use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomizableOption as CustomizableOptionDataProvider; /** * {@inheritdoc} @@ -31,9 +22,9 @@ class CustomizableOptions implements ResolverInterface { /** - * @var StoreManagerInterface + * @var CustomizableOptionDataProvider */ - private $storeManager; + private $customOptionDataProvider; /** * @var ValueFactory @@ -48,16 +39,16 @@ class CustomizableOptions implements ResolverInterface /** * @param ValueFactory $valueFactory * @param UserContextInterface $userContext - * @param StoreManagerInterface $storeManager + * @param CustomizableOptionDataProvider $customOptionDataProvider */ public function __construct( ValueFactory $valueFactory, UserContextInterface $userContext, - StoreManagerInterface $storeManager + CustomizableOptionDataProvider $customOptionDataProvider ) { $this->valueFactory = $valueFactory; $this->userContext = $userContext; - $this->storeManager = $storeManager; + $this->customOptionDataProvider = $customOptionDataProvider; } /** @@ -85,7 +76,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $customOptionIds = explode(',', $optionIds->getValue()); foreach ($customOptionIds as $optionId) { - $customOptionData = $this->getOptionData($cartItem, (int) $optionId); + $customOptionData = $this->customOptionDataProvider->getData($cartItem, (int) $optionId); if (0 === count($customOptionData)) { continue; @@ -100,136 +91,4 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value return $this->valueFactory->create($result); } - - /** - * @param QuoteItem $cartItem - * @param int $optionId - * @return array - * @throws NoSuchEntityException - * @throws LocalizedException - */ - private function getOptionData($cartItem, int $optionId): array - { - $product = $cartItem->getProduct(); - $option = $product->getOptionById($optionId); - - if (!$option) { - return []; - } - - $itemOption = $cartItem->getOptionByCode('option_' . $option->getId()); - - /** @var SelectOptionType|TextOptionType|DefaultOptionType $optionTypeGroup */ - $optionTypeGroup = $option->groupFactory($option->getType()) - ->setOption($option) - ->setConfigurationItem($cartItem) - ->setConfigurationItemOption($itemOption); - - if (ProductCustomOptionInterface::OPTION_GROUP_FILE == $option->getType()) { - $downloadParams = $cartItem->getFileDownloadParams(); - - if ($downloadParams) { - $url = $downloadParams->getUrl(); - if ($url) { - $optionTypeGroup->setCustomOptionDownloadUrl($url); - } - $urlParams = $downloadParams->getUrlParams(); - if ($urlParams) { - $optionTypeGroup->setCustomOptionUrlParams($urlParams); - } - } - } - - $selectedOptionValueData = [ - 'id' => $itemOption->getId(), - 'label' => $optionTypeGroup->getFormattedOptionValue($itemOption->getValue()), - ]; - - if (ProductCustomOptionInterface::OPTION_TYPE_DROP_DOWN == $option->getType() - || ProductCustomOptionInterface::OPTION_TYPE_RADIO == $option->getType() - || ProductCustomOptionInterface::OPTION_TYPE_CHECKBOX == $option->getType() - ) { - $optionValue = $option->getValueById($itemOption->getValue()); - $priceValueUnits = $this->getPriceValueUnits($optionValue->getPriceType()); - - $selectedOptionValueData['price'] = [ - 'type' => strtoupper($optionValue->getPriceType()), - 'units' => $priceValueUnits, - 'value' => $optionValue->getPrice(), - ]; - - $selectedOptionValueData = [$selectedOptionValueData]; - } - - if (ProductCustomOptionInterface::OPTION_TYPE_FIELD == $option->getType() - || ProductCustomOptionInterface::OPTION_TYPE_AREA == $option->getType() - || ProductCustomOptionInterface::OPTION_GROUP_DATE == $option->getType() - || ProductCustomOptionInterface::OPTION_TYPE_TIME == $option->getType() - ) { - $priceValueUnits = $this->getPriceValueUnits($option->getPriceType()); - - $selectedOptionValueData['price'] = [ - 'type' => strtoupper($option->getPriceType()), - 'units' => $priceValueUnits, - 'value' => $option->getPrice(), - ]; - - $selectedOptionValueData = [$selectedOptionValueData]; - } - - if (ProductCustomOptionInterface::OPTION_TYPE_MULTIPLE == $option->getType()) { - $selectedOptionValueData = []; - $optionIds = explode(',', $itemOption->getValue()); - - foreach ($optionIds as $optionId) { - $optionValue = $option->getValueById($optionId); - $priceValueUnits = $this->getPriceValueUnits($optionValue->getPriceType()); - - $selectedOptionValueData[] = [ - 'id' => $itemOption->getId(), - 'label' => $optionValue->getTitle(), - 'price' => [ - 'type' => strtoupper($optionValue->getPriceType()), - 'units' => $priceValueUnits, - 'value' => $optionValue->getPrice(), - ], - ]; - } - } - - return [ - 'id' => $option->getId(), - 'label' => $option->getTitle(), - 'type' => $option->getType(), - 'values' => $selectedOptionValueData, - 'sort_order' => $option->getSortOrder(), - ]; - } - - /** - * @param string $priceType - * @return string - * @throws NoSuchEntityException - */ - private function getPriceValueUnits(string $priceType): string - { - if (ProductPriceOptionsInterface::VALUE_PERCENT == $priceType) { - return '%'; - } - - return $this->getCurrencySymbol(); - } - - /** - * Get currency symbol - * @return string - * @throws NoSuchEntityException - */ - private function getCurrencySymbol(): string - { - /** @var Store|StoreInterface $store */ - $store = $this->storeManager->getStore(); - - return $store->getBaseCurrency()->getCurrencySymbol(); - } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/Cart/CartHydrator.php similarity index 92% rename from app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php rename to app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/Cart/CartHydrator.php index 55ad50f9ca5d6..6a0a5f26aa336 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Hydrator/CartHydrator.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/Cart/CartHydrator.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Hydrator; +namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\Cart; use Magento\Quote\Api\Data\CartInterface; use Magento\Quote\Model\Quote; @@ -13,16 +13,12 @@ /** * Cart Hydrator class - * - * {@inheritdoc} */ class CartHydrator { /** * Hydrate cart to plain array - * * @param CartInterface|Quote $cart - * * @return array */ public function hydrate(CartInterface $cart): array diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php new file mode 100644 index 0000000000000..0ea2cbb25d9da --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php @@ -0,0 +1,174 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem; + +use Magento\Catalog\Api\Data\ProductCustomOptionInterface; +use Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface; +use Magento\Catalog\Model\Product\Option\Type\DefaultType as DefaultOptionType; +use Magento\Catalog\Model\Product\Option\Type\Select as SelectOptionType; +use Magento\Catalog\Model\Product\Option\Type\Text as TextOptionType; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\Store; +use Magento\Store\Model\StoreManagerInterface; + +/** + * Custom Option Data provider + */ +class CustomizableOption +{ + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @param StoreManagerInterface $storeManager + */ + public function __construct( + StoreManagerInterface $storeManager + ) { + $this->storeManager = $storeManager; + } + + /** + * Retrieve custom option data + * @param QuoteItem $cartItem + * @param int $optionId + * @return array + * @throws NoSuchEntityException + * @throws LocalizedException + */ + public function getData(QuoteItem $cartItem, int $optionId): array + { + $product = $cartItem->getProduct(); + $option = $product->getOptionById($optionId); + + if (!$option) { + return []; + } + + $itemOption = $cartItem->getOptionByCode('option_' . $option->getId()); + + /** @var SelectOptionType|TextOptionType|DefaultOptionType $optionTypeGroup */ + $optionTypeGroup = $option->groupFactory($option->getType()) + ->setOption($option) + ->setConfigurationItem($cartItem) + ->setConfigurationItemOption($itemOption); + + if (ProductCustomOptionInterface::OPTION_GROUP_FILE == $option->getType()) { + $downloadParams = $cartItem->getFileDownloadParams(); + + if ($downloadParams) { + $url = $downloadParams->getUrl(); + if ($url) { + $optionTypeGroup->setCustomOptionDownloadUrl($url); + } + $urlParams = $downloadParams->getUrlParams(); + if ($urlParams) { + $optionTypeGroup->setCustomOptionUrlParams($urlParams); + } + } + } + + $selectedOptionValueData = [ + 'id' => $itemOption->getId(), + 'label' => $optionTypeGroup->getFormattedOptionValue($itemOption->getValue()), + ]; + + if (ProductCustomOptionInterface::OPTION_TYPE_DROP_DOWN == $option->getType() + || ProductCustomOptionInterface::OPTION_TYPE_RADIO == $option->getType() + || ProductCustomOptionInterface::OPTION_TYPE_CHECKBOX == $option->getType() + ) { + $optionValue = $option->getValueById($itemOption->getValue()); + $priceValueUnits = $this->getPriceValueUnits($optionValue->getPriceType()); + + $selectedOptionValueData['price'] = [ + 'type' => strtoupper($optionValue->getPriceType()), + 'units' => $priceValueUnits, + 'value' => $optionValue->getPrice(), + ]; + + $selectedOptionValueData = [$selectedOptionValueData]; + } + + if (ProductCustomOptionInterface::OPTION_TYPE_FIELD == $option->getType() + || ProductCustomOptionInterface::OPTION_TYPE_AREA == $option->getType() + || ProductCustomOptionInterface::OPTION_GROUP_DATE == $option->getType() + || ProductCustomOptionInterface::OPTION_TYPE_TIME == $option->getType() + ) { + $priceValueUnits = $this->getPriceValueUnits($option->getPriceType()); + + $selectedOptionValueData['price'] = [ + 'type' => strtoupper($option->getPriceType()), + 'units' => $priceValueUnits, + 'value' => $option->getPrice(), + ]; + + $selectedOptionValueData = [$selectedOptionValueData]; + } + + if (ProductCustomOptionInterface::OPTION_TYPE_MULTIPLE == $option->getType()) { + $selectedOptionValueData = []; + $optionIds = explode(',', $itemOption->getValue()); + + foreach ($optionIds as $optionId) { + $optionValue = $option->getValueById($optionId); + $priceValueUnits = $this->getPriceValueUnits($optionValue->getPriceType()); + + $selectedOptionValueData[] = [ + 'id' => $itemOption->getId(), + 'label' => $optionValue->getTitle(), + 'price' => [ + 'type' => strtoupper($optionValue->getPriceType()), + 'units' => $priceValueUnits, + 'value' => $optionValue->getPrice(), + ], + ]; + } + } + + return [ + 'id' => $option->getId(), + 'label' => $option->getTitle(), + 'type' => $option->getType(), + 'values' => $selectedOptionValueData, + 'sort_order' => $option->getSortOrder(), + ]; + } + + /** + * Retrieve price value unit + * @param string $priceType + * @return string + * @throws NoSuchEntityException + */ + private function getPriceValueUnits(string $priceType): string + { + if (ProductPriceOptionsInterface::VALUE_PERCENT == $priceType) { + return '%'; + } + + return $this->getCurrencySymbol(); + } + + /** + * Get currency symbol + * @return string + * @throws NoSuchEntityException + */ + private function getCurrencySymbol(): string + { + /** @var Store|StoreInterface $store */ + $store = $this->storeManager->getStore(); + + return $store->getBaseCurrency()->getCurrencySymbol(); + } +} From f66d9c4703ac3d16daacce77c69258c5958cf6c7 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 19 Sep 2018 10:22:15 +0300 Subject: [PATCH 25/54] MAGETWO-94948: Can't delete an option from Fixed Product Tax --- .../Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php b/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php index 26f135b56d11f..d05b8c2168936 100644 --- a/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php +++ b/app/code/Magento/Weee/Ui/DataProvider/Product/Form/Modifier/Weee.php @@ -155,6 +155,7 @@ protected function modifyAttributeConfig($attributeCode, array $attributeConfig) 'dndConfig' => [ 'enabled' => false, ], + 'required' => (bool)$attributeConfig['arguments']['data']['config']['required'], ], ], ], From 0456a9fb557b9608df2efed2e7956a74138801d2 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Wed, 19 Sep 2018 12:41:43 +0300 Subject: [PATCH 26/54] MAGETWO-94838: Automate with MFTF Ability to configure Advanced Prices from Shared Catalog Page for different type of products --- .../AdminDeleteCustomerGroupActionGroup.xml | 20 +++++++++++++++++++ .../AdminCustomerGroupGridActionsSection.xml | 5 +++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml new file mode 100644 index 0000000000000..9b06caa5a6d4a --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminDeleteCustomerGroupActionGroup"> + <arguments> + <argument name="customerGroupName" type="string"/> + </arguments> + <click selector="{{AdminCustomerGroupGridActionsSection.selectButton('customerGroupName')}}" stepKey="clickSelectButton"/> + <click selector="{{AdminCustomerGroupGridActionsSection.deleteAction('customerGroupName')}}" stepKey="clickOnDeleteItem"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmDeleteCustomerGroup"/> + <seeElement selector="{{AdminMessagesSection.success}}" stepKey="seeSuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml index 2636555af88a3..aa6def4849f78 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml @@ -9,7 +9,8 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminCustomerGroupGridActionsSection"> - <element name="selectButton" type="button" selector="//div[text()='{{NAME_FIELD}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//button[text()='Select']" timeout="30" parameterized="true"/> - <element name="actionsMenuButton" type="text" selector="//div[text()='{{NAME_FIELD}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='{{selectItem}}']" timeout="30" parameterized="true"/> + <element name="selectButton" type="button" selector="//div[text()='{{groupName}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//button[text()='Select']" timeout="30" parameterized="true"/> + <element name="deleteAction" type="button" selector="//div[text()='{{groupName}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='Delete']" timeout="30" parameterized="true"/> + <element name="actionsMenuButton" type="text" selector="//div[text()='{{groupName}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='{{selectItem}}']" timeout="30" parameterized="true"/> </section> </sections> From a3b979f9b33be8f82ac5b680fe86bcf6554cbade Mon Sep 17 00:00:00 2001 From: Dmitriy Kogut <kogut.dmitriy@gmail.com> Date: Wed, 19 Sep 2018 13:09:54 +0300 Subject: [PATCH 27/54] MAGETWO-93830: Automate with MFTF Sort products grid after removing shared catalog --- ...reateApiConfigurableProductActionGroup.xml | 6 +++--- ...minCustomerGroupResetFilterActionGroup.xml | 19 ------------------ .../AdminDeleteCustomerGroupActionGroup.xml | 20 +++++++++++++++++++ ...inFilterCustomerGroupByNameActionGroup.xml | 8 ++++---- .../AdminCustomerGroupFiltersSection.xml | 20 ------------------- .../AdminCustomerGroupGridActionsSection.xml | 5 +++-- .../AdminCustomerGroupMainActionsSection.xml | 14 ------------- 7 files changed, 30 insertions(+), 62 deletions(-) delete mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml delete mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml delete mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml index b88c06762d49d..e0be4e76239f0 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml @@ -10,9 +10,9 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminCreateApiConfigurableProductActionGroup"> <!-- Create the configurable product based on the data in the /data folder --> - <createData entity="ApiConfigurableProductWithOutCategory" stepKey="createConfigProduct"/> + <createData entity="ApiConfigurableProductWithOutCategory" stepKey="createConfigProduct"/> - <!-- Make the configurable product have two options, that are children of the default attribute set --> + <!-- Create attribute with 2 options to be used in children products --> <createData entity="productAttributeWithTwoOptions" stepKey="createConfigProductAttribute"/> <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption1"> <requiredEntity createDataKey="createConfigProductAttribute"/> @@ -20,7 +20,7 @@ <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOption2"> <requiredEntity createDataKey="createConfigProductAttribute"/> </createData> - <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <createData entity="AddToDefaultSet" stepKey="addAttributeToAttributeSet"> <requiredEntity createDataKey="createConfigProductAttribute"/> </createData> <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption1"> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml deleted file mode 100644 index 85e561d1f5750..0000000000000 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCustomerGroupResetFilterActionGroup.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <!--Reset the Customer Group grid to the default view--> - <actionGroup name="AdminCustomerGroupResetFilterActionGroup"> - <conditionalClick selector="{{AdminCustomerGroupFiltersSection.clearFilters}}" dependentSelector="{{AdminCustomerGroupFiltersSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> - <click selector="{{AdminCustomerGroupFiltersSection.viewDropdown}}" stepKey="openViewBookmarksTab"/> - <click selector="{{AdminCustomerGroupFiltersSection.viewBookmark('Default View')}}" stepKey="resetToDefaultGridView"/> - <waitForPageLoad stepKey="waitForProductGridLoad"/> - <see selector="{{AdminCustomerGroupFiltersSection.viewDropdown}}" userInput="Default View" stepKey="seeDefaultViewSelected"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml new file mode 100644 index 0000000000000..9b06caa5a6d4a --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminDeleteCustomerGroupActionGroup"> + <arguments> + <argument name="customerGroupName" type="string"/> + </arguments> + <click selector="{{AdminCustomerGroupGridActionsSection.selectButton('customerGroupName')}}" stepKey="clickSelectButton"/> + <click selector="{{AdminCustomerGroupGridActionsSection.deleteAction('customerGroupName')}}" stepKey="clickOnDeleteItem"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmDeleteCustomerGroup"/> + <seeElement selector="{{AdminMessagesSection.success}}" stepKey="seeSuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml index df43290983770..1681a8e850ca2 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminFilterCustomerGroupByNameActionGroup.xml @@ -12,9 +12,9 @@ <arguments> <argument name="customerGroupName" type="string"/> </arguments> - <click selector="{{AdminCustomerGroupFiltersSection.filterButton}}" stepKey="openFiltersSectionOnCustomerGroupIndexPage"/> - <conditionalClick selector="{{AdminCustomerGroupFiltersSection.clearFiltersButton}}" dependentSelector="{{AdminCustomerGroupFiltersSection.clearFiltersButton}}" visible="true" stepKey="cleanFiltersIfTheySet"/> - <fillField userInput="{{customerGroupName}}" selector="{{AdminCustomerGroupFiltersSection.nameField}}" stepKey="fillNameFieldOnFiltersSection"/> - <click selector="{{AdminCustomerGroupFiltersSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openFiltersSectionOnCustomerGroupIndexPage"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="cleanFiltersIfTheySet"/> + <fillField userInput="{{customerGroupName}}" selector="{{AdminDataGridHeaderSection.filterFieldInput('customer_group_code')}}" stepKey="fillNameFieldOnFiltersSection"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml deleted file mode 100644 index 439ef1a5e7c57..0000000000000 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupFiltersSection.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> - <section name="AdminCustomerGroupFiltersSection"> - <element name="filterButton" type="button" selector="//div[@class='data-grid-filters-action-wrap']/button" timeout="30"/> - <element name="clearFiltersButton" type="button" selector="//div[@class='admin__data-grid-header']//button[@class='action-tertiary action-clear']" timeout="10"/> - <element name="applyFilters" type="button" selector="button[data-action=grid-filter-apply]" timeout="30"/> - <element name="nameField" type="input" selector=".admin__data-grid-filters-wrap._show input[name='customer_group_code']" timeout="30"/> - <element name="clearFilters" type="button" selector=".admin__data-grid-header button[data-action='grid-filter-reset']" timeout="30"/> - <element name="viewDropdown" type="button" selector=".admin__data-grid-action-bookmarks button.admin__action-dropdown"/> - <element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> - </section> -</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml index bb2615483ed5c..391292ca7fa31 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupGridActionsSection.xml @@ -9,7 +9,8 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminCustomerGroupGridActionsSection"> - <element name="selectButton" type="button" selector="table.data-grid button.action-select" timeout="30"/> - <element name="selectButtonItem" type="text" selector="//ul[@class='action-menu _active']//a[contains(text(), '{{selectItem}}')]" timeout="30" parameterized="true"/> + <element name="selectButton" type="button" selector="//div[text()='{{groupName}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//button[text()='Select']" timeout="30" parameterized="true"/> + <element name="deleteAction" type="button" selector="//div[text()='{{groupName}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='Delete']" timeout="30" parameterized="true"/> + <element name="actionsMenuButton" type="text" selector="//div[text()='{{groupName}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='{{selectItem}}']" timeout="30" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml deleted file mode 100644 index 3f654c1c94c27..0000000000000 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainActionsSection.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> - <section name="AdminCustomerGroupMainActionsSection"> - <element name="popupOkButton" type="button" selector="button.action-primary.action-accept" timeout="30"/> - </section> -</sections> From d0231e8e891ef88703089f06f6b7e7799485c782 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 19 Sep 2018 17:52:07 +0300 Subject: [PATCH 28/54] GraphQL-175: Improve graphql product pagination -- fix static tests --- .../Magento/CatalogGraphQl/Model/Resolver/Products.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php index e27018d3eb465..aaf8473a50758 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products.php @@ -7,6 +7,7 @@ namespace Magento\CatalogGraphQl\Model\Resolver; +use Magento\CatalogGraphQl\Model\Resolver\Layer\DataProvider\Filters; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\CatalogGraphQl\Model\Resolver\Products\Query\Filter; use Magento\CatalogGraphQl\Model\Resolver\Products\Query\Search; @@ -58,7 +59,9 @@ class Products implements ResolverInterface * @param Builder $searchCriteriaBuilder * @param Search $searchQuery * @param Filter $filterQuery + * @param SearchFilter $searchFilter * @param ValueFactory $valueFactory + * @param Filters $filtersDataProvider */ public function __construct( Builder $searchCriteriaBuilder, @@ -66,7 +69,7 @@ public function __construct( Filter $filterQuery, SearchFilter $searchFilter, ValueFactory $valueFactory, - \Magento\CatalogGraphQl\Model\Resolver\Layer\DataProvider\Filters $filtersDataProvider + Filters $filtersDataProvider ) { $this->searchCriteriaBuilder = $searchCriteriaBuilder; $this->searchQuery = $searchQuery; @@ -77,7 +80,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function resolve( Field $field, From 34e010632ada4fbc6d22a302e8f5a390c37a282c Mon Sep 17 00:00:00 2001 From: Roman Glushko <r.glushko@atwix.com> Date: Wed, 19 Sep 2018 22:22:15 +0300 Subject: [PATCH 29/54] #141 Added missed lines in phpdocs --- .../Magento/CatalogGraphQl/Model/Product/Option/DateType.php | 1 + .../Model/Cart/AddSimpleProductToCartProcessor.php | 2 ++ .../Model/Resolver/Cart/AddSimpleProductsToCart.php | 2 ++ .../QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php | 2 +- .../Model/Resolver/CartItemTypeResolverComposite.php | 1 + .../Resolver/DataProvider/CartItem/CustomizableOption.php | 3 +++ 6 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index d9308cf606e1f..db03b1712612d 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -32,6 +32,7 @@ public function validateUserValue($values) /** * Format date value from string to date array + * * @param [] $values * @return [] * @throws LocalizedException diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php b/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php index ff02f48ef6659..3b6e1801c5f1f 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php @@ -81,6 +81,7 @@ public function __construct( /** * Resolve adding simple product to cart for customers/guests + * * @param CartInterface|Quote $cart * @param array $cartItemData * @return QuoteItem|string @@ -97,6 +98,7 @@ public function process($cart, array $cartItemData) /** * Format GraphQl input data to a shape that buy request has + * * @param array $cartItem * @return DataObject */ diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php index 845ae75918851..d5b0b862d23d2 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php @@ -155,6 +155,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value /** * Collecting cart errors + * * @param CartInterface|Quote $cart * @return string */ @@ -172,6 +173,7 @@ private function getCartErrors($cart): string /** * Retrieving quote mode based on customer authorization + * * @param string $cartHash * @return CartInterface|Quote * @throws NoSuchEntityException diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php index 583ef6e33c6d3..b8b197b45039a 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php @@ -32,8 +32,8 @@ public function __construct(array $cartItemTypes = []) /** * Resolve GraphQl types to retrieve product type specific information about cart items - * * {@inheritdoc} + * * @throws GraphQlInputException */ public function resolveType(array $data) : string diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php index 264887a66f621..901f177ced98e 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php @@ -30,6 +30,7 @@ public function __construct(array $cartItemTypeResolvers = []) /** * {@inheritdoc} + * * @throws GraphQlInputException */ public function resolveType(array $data) : string diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php index 0ea2cbb25d9da..909867c0457d8 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php @@ -40,6 +40,7 @@ public function __construct( /** * Retrieve custom option data + * * @param QuoteItem $cartItem * @param int $optionId * @return array @@ -146,6 +147,7 @@ public function getData(QuoteItem $cartItem, int $optionId): array /** * Retrieve price value unit + * * @param string $priceType * @return string * @throws NoSuchEntityException @@ -161,6 +163,7 @@ private function getPriceValueUnits(string $priceType): string /** * Get currency symbol + * * @return string * @throws NoSuchEntityException */ From e8011a8d05c77f9586c12a94ad63b057aee4204e Mon Sep 17 00:00:00 2001 From: Roman Glushko <r.glushko@atwix.com> Date: Wed, 19 Sep 2018 23:40:57 +0300 Subject: [PATCH 30/54] #141 Removed redundant dependency --- .../Resolver/Cart/AddSimpleProductsToCart.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php index d5b0b862d23d2..80aa42b4365d7 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php @@ -19,7 +19,6 @@ use Magento\Framework\Stdlib\ArrayManager; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\CartInterface; -use Magento\Quote\Api\GuestCartRepositoryInterface; use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Quote\Model\Quote; use Magento\QuoteGraphQl\Model\Cart\AddSimpleProductToCartProcessor; @@ -46,11 +45,6 @@ class AddSimpleProductsToCart implements ResolverInterface */ private $maskedQuoteIdToQuoteId; - /** - * @var GuestCartRepositoryInterface - */ - private $guestCartRepository; - /** * @var CartHydrator */ @@ -77,7 +71,6 @@ class AddSimpleProductsToCart implements ResolverInterface * @param ArrayManager $arrayManager * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId * @param CartRepositoryInterface $cartRepository - * @param GuestCartRepositoryInterface $guestCartRepository * @param ValueFactory $valueFactory * @param UserContextInterface $userContext */ @@ -87,7 +80,6 @@ public function __construct( ArrayManager $arrayManager, MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, CartRepositoryInterface $cartRepository, - GuestCartRepositoryInterface $guestCartRepository, ValueFactory $valueFactory, UserContextInterface $userContext ) { @@ -95,7 +87,6 @@ public function __construct( $this->userContext = $userContext; $this->arrayManager = $arrayManager; $this->cartHydrator = $cartHydrator; - $this->guestCartRepository = $guestCartRepository; $this->cartRepository = $cartRepository; $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; $this->addSimpleProductToCartProcessor = $addSimpleProductToCartProcessor; @@ -180,13 +171,8 @@ private function getCartErrors($cart): string */ private function getCart(string $cartHash): CartInterface { - $customerId = $this->userContext->getUserId(); - - if (!$customerId) { - return $this->guestCartRepository->get($cartHash); - } - $cartId = $this->maskedQuoteIdToQuoteId->execute((string) $cartHash); + return $this->cartRepository->get($cartId); } } From 5048832bcf927f9eb21d141b9c7d29d04009a84d Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Thu, 20 Sep 2018 12:01:25 +0300 Subject: [PATCH 31/54] MAGETWO-94838: Automate with MFTF Ability to configure Advanced Prices from Shared Catalog Page for different type of products --- .../AdminCreateApiBundleProductActionGroup.xml | 14 ++++++++++++-- ...dminCreateApiConfigurableProductActionGroup.xml | 8 +++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml index 5de75c976052f..ad9a8253e910c 100644 --- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml +++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml @@ -9,6 +9,9 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminCreateApiDynamicBundleProductActionGroup"> + <arguments> + <argument name="productName" defaultValue="Api Dynamic Bundle Product" type="string"/> + </arguments> <!--Create 4 simple products--> <createData entity="SimpleProduct2" stepKey="simpleProduct1"> <field key="price">4.99</field> @@ -23,7 +26,9 @@ <field key="price">18.25</field> </createData> <!-- Create the bundle product based --> - <createData entity="ApiBundleProduct" stepKey="createBundleProduct"/> + <createData entity="ApiBundleProduct" stepKey="createBundleProduct"> + <field key="name">{{productName}}</field> + </createData> <createData entity="MultipleSelectOption" stepKey="createBundleOption1_1"> <requiredEntity createDataKey="createBundleProduct"/> <field key="required">false</field> @@ -53,6 +58,9 @@ </createData> </actionGroup> <actionGroup name="AdminCreateApiFixedBundleProductActionGroup"> + <arguments> + <argument name="productName" defaultValue="Api Fixed Bundle Product" type="string"/> + </arguments> <!--Create 4 simple products--> <createData entity="SimpleProduct2" stepKey="simpleProduct1"> <field key="price">4.99</field> @@ -67,7 +75,9 @@ <field key="price">18.25</field> </createData> <!-- Create the bundle product based --> - <createData entity="ApiFixedBundleProduct" stepKey="createBundleProduct"/> + <createData entity="ApiFixedBundleProduct" stepKey="createBundleProduct"> + <field key="name">{{productName}}</field> + </createData> <createData entity="MultipleSelectOption" stepKey="createBundleOption1_1"> <requiredEntity createDataKey="createBundleProduct"/> <field key="required">false</field> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml index e0be4e76239f0..033e6757c3bf9 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml @@ -9,8 +9,14 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminCreateApiConfigurableProductActionGroup"> + <arguments> + <argument name="productName" defaultValue="ApiConfigurableProductWithOutCategory" type="string"/> + </arguments> + <!-- Create the configurable product based on the data in the /data folder --> - <createData entity="ApiConfigurableProductWithOutCategory" stepKey="createConfigProduct"/> + <createData entity="ApiConfigurableProductWithOutCategory" stepKey="createConfigProduct"> + <field key="name">{{productName}}</field> + </createData> <!-- Create attribute with 2 options to be used in children products --> <createData entity="productAttributeWithTwoOptions" stepKey="createConfigProductAttribute"/> From f9dba750788db923609dfe4aa9762f2a3fbdca43 Mon Sep 17 00:00:00 2001 From: Stas Puga <stas.puga@transoftgroup.com> Date: Thu, 20 Sep 2018 16:17:58 +0300 Subject: [PATCH 32/54] MAGETWO-94843: Automate with MFTF Auto generated coupon code for Cart Price Rules considers "Uses per Coupon" and "Uses per Customer" options --- .../Section/StorefrontMessagesSection.xml | 1 + .../ApplyCartRuleOnStorefrontActionGroup.xml | 20 +-- .../Test/Mftf/Data/SalesRuleData.xml | 28 +++ .../StorefrontAutoGeneratedCouponCodeTest.xml | 162 ++++++++++++++++++ 4 files changed, 199 insertions(+), 12 deletions(-) create mode 100644 app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontMessagesSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontMessagesSection.xml index dea1b2a5af752..54b289a89c705 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontMessagesSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontMessagesSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="StorefrontMessagesSection"> <element name="success" type="text" selector="div.message-success.success.message"/> + <element name="error" type="text" selector="div.message-error.error.message"/> </section> </sections> diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/ApplyCartRuleOnStorefrontActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/ApplyCartRuleOnStorefrontActionGroup.xml index 55b2e9c10fd64..37e171823b11a 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/ApplyCartRuleOnStorefrontActionGroup.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/ApplyCartRuleOnStorefrontActionGroup.xml @@ -9,20 +9,16 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="ApplyCartRuleOnStorefrontActionGroup"> <arguments> - <argument name="Product" defaultValue="_defaultProduct"/> - <argument name="Coupon" defaultValue="SimpleSalesRuleCoupon"/> + <argument name="product"/> + <argument name="couponCode" type="string"/> </arguments> - <amOnPage url="{{Product.name}}.html" stepKey="navigateToProductPage"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addToCart" /> - <waitForText userInput="You added {{Product.name}} to your shopping cart." stepKey="waitForAddedBtn"/> - <amOnPage url="/checkout/cart/" stepKey="onPageShoppingCart"/> - <waitForPageLoad stepKey="waitForPageLoad2"/> - <click selector="{{DiscountSection.DiscountTab}}" stepKey="scrollToDiscountTab" /> - <fillField selector="{{DiscountSection.CouponInput}}" userInput="{{Coupon.code}}" stepKey="fillCouponCode" /> + <waitForText userInput="You added {{product.name}} to your shopping cart." stepKey="waitForText"/> + <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCheckoutPage"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <click selector="{{DiscountSection.DiscountTab}}" stepKey="clickToDiscountTab" /> + <fillField selector="{{DiscountSection.CouponInput}}" userInput="{{couponCode}}" stepKey="fillCouponCode"/> <click selector="{{DiscountSection.ApplyCodeBtn}}" stepKey="applyCode"/> - <waitForPageLoad stepKey="waitForPageLoad3"/> - <waitForText userInput="You used coupon code" stepKey="waitForText"/> - <see userInput="You used coupon code" stepKey="assertText"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml index 6ebc78a677149..dbca35d6432cc 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml @@ -60,4 +60,32 @@ <data key="apply">Percent of product price discount</data> <data key="discountAmount">50</data> </entity> + <entity name="SalesRuleSpecificCoupon" type="SalesRule"> + <data key="name" unique="suffix">SimpleSalesRule</data> + <data key="description">Sales Rule Descritpion</data> + <array key="website_ids"> + <item>1</item> + </array> + <array key="customer_group_ids"> + <item>0</item> + <item>1</item> + <item>3</item> + </array> + <data key="uses_per_customer">1</data> + <data key="is_active">true</data> + <data key="stop_rules_processing">false</data> + <data key="is_advanced">true</data> + <data key="sort_order">2</data> + <data key="simple_action">by_percent</data> + <data key="discount_amount">10</data> + <data key="discount_qty">1</data> + <data key="discount_step">0</data> + <data key="apply_to_shipping">false</data> + <data key="times_used">1</data> + <data key="is_rss">false</data> + <data key="coupon_type">SPECIFIC_COUPON</data> + <data key="use_auto_generation">true</data> + <data key="uses_per_coupon">2</data> + <data key="simple_free_shipping">1</data> + </entity> </entities> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml new file mode 100644 index 0000000000000..6250e1abba732 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -0,0 +1,162 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontAutoGeneratedCouponCodeTest"> + <annotations> + <features value="SalesRule"/> + <stories value="Create cart price rule"/> + <title value="[Cart Price Rule] Auto generated coupon code considers 'Uses per Coupon' and 'Uses per Customer' options"/> + <description + value="[Cart Price Rule] Auto generated coupon code considers 'Uses per Coupon' and 'Uses per Customer' options"/> + <severity value="AVERAGE"/> + <testCaseId value="MAGETWO-59323"/> + <group value="test"/> + <!--<group value="salesRule"/>--> + </annotations> + + <before> + <!-- Create customer --> + <createData entity="Simple_US_Customer" stepKey="createCustomer"/> + <!-- Create simple product--> + <createData entity="SimpleProduct2" stepKey="createSimpleProduct"/> + <!-- Create a cart price rule --> + <createData entity="SalesRuleSpecificCoupon" stepKey="createSalesRule"/> + </before> + + <after> + <!-- Delete the cart price rule we made during the test --> + <deleteData createDataKey="createSalesRule" stepKey="deleteSalesRule"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!-- Login as Admin --> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + + <!-- Search Cart Price Rule and go to edit Cart Price Rule --> + <amOnPage url="{{AdminCartPriceRulesPage.url}}" stepKey="amOnCartPriceList"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <fillField selector="{{AdminCartPriceRulesSection.filterByNameInput}}" userInput="$$createSalesRule.name$$" + stepKey="fillFieldFilterByName"/> + <click selector="{{AdminCartPriceRulesSection.searchButton}}" stepKey="clickSearchButton"/> + <see selector="{{AdminCartPriceRulesSection.nameColumns}}" userInput="$$createSalesRule.name$$" + stepKey="seeRuleName"/> + <click selector="{{AdminCartPriceRulesSection.rowContainingText($$createSalesRule.name$$)}}" + stepKey="goToEditRule"/> + + <!-- Step 3-4. Navigate to Manage Coupon Codes section to generate 1 coupon code --> + <conditionalClick selector="{{AdminCartPriceRulesFormSection.manageCouponCodesHeader}}" + dependentSelector="{{AdminCartPriceRulesFormSection.manageCouponCodesHeader}}" visible="true" + stepKey="clickManageCouponCodes"/> + <fillField selector="{{AdminCartPriceRulesFormSection.couponQty}}" userInput="1" stepKey="fillFieldCouponQty"/> + <click selector="{{AdminCartPriceRulesFormSection.generateCouponsButton}}" stepKey="clickGenerateCoupon"/> + <see selector="{{AdminCartPriceRulesFormSection.successMessage}}" userInput="1 coupon(s) have been generated." + stepKey="seeSuccessMessage"/> + <grabTextFrom selector="{{AdminCartPriceRulesFormSection.generatedCouponByIndex('1')}}" + stepKey="couponCode"/> + + <!-- Step: 5. Login to storefront as previously created customer --> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginAsCustomer"> + <argument name="Customer" value="$$createCustomer$$"/> + </actionGroup> + + <!-- Step: 6-7. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartPriceRule"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="couponCode" value="{$couponCode}"/> + </actionGroup> + <waitForText userInput='You used coupon code "{$couponCode}"' stepKey="waitForText"/> + <see selector="{{StorefrontMessagesSection.success}}" userInput='You used coupon code "{$couponCode}"' + stepKey="seeSuccessMessage1"/> + <waitForElementVisible selector="{{CheckoutCartSummarySection.discountAmount}}" time="30" + stepKey="waitForElementDiscountVisible"/> + + <!-- Step 8. Go to Checkout and Click Place Order button --> + <click selector="{{CheckoutCartSummarySection.proceedToCheckout}}" stepKey="clickProceedToCheckout"/> + <click selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" + stepKey="selectFlatShippingMethod"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> + <waitForElement selector="{{CheckoutShippingMethodsSection.next}}" time="30" stepKey="waitForNextButton"/> + <click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="clickNext"/> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" + stepKey="waitForPaymentSectionLoaded"/> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <waitForElement selector="{{CheckoutSuccessMainSection.success}}" time="30" stepKey="waitForLoadSuccessPage"/> + + <!-- Step: 9-10. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage1"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartPriceRule1"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="couponCode" value="{$couponCode}"/> + </actionGroup> + <waitForText userInput='The coupon code "{$couponCode}" is not valid.' stepKey="waitForText1"/> + <see selector="{{StorefrontMessagesSection.error}}" userInput='The coupon code "{$couponCode}" is not valid.' + stepKey="seeErrorMessages"/> + <waitForElementNotVisible selector="{{CheckoutCartSummarySection.discountAmount}}" time="30" + stepKey="waitForElementNotDiscountVisible"/> + + <!-- Step 11. Log out from storefront --> + <actionGroup ref="StorefrontSignOutActionGroup" stepKey="storefrontSignOut"/> + + <!-- Step: 12-13. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage2"/> + <waitForPageLoad stepKey="waitForPageLoad4"/> + <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartPriceRule2"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="couponCode" value="{$couponCode}"/> + </actionGroup> + <waitForText userInput='You used coupon code "{$couponCode}"' stepKey="waitForText2"/> + <see selector="{{StorefrontMessagesSection.success}}" userInput='You used coupon code "{$couponCode}"' + stepKey="seeSuccessMessage2"/> + <waitForElementVisible selector="{{CheckoutCartSummarySection.discountAmount}}" time="30" + stepKey="waitForElementDiscountVisible1"/> + + <!-- Step 14. Go to Checkout and Click Place Order button --> + <click selector="{{CheckoutCartSummarySection.proceedToCheckout}}" stepKey="clickProceedToCheckout1"/> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShippingSection"> + <argument name="customerVar" value="CustomerEntityOne"/> + <argument name="customerAddressVar" value="CustomerAddressSimple"/> + </actionGroup> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder1"/> + <waitForElement selector="{{CheckoutSuccessMainSection.success}}" time="30" stepKey="waitForLoadSuccessPage1"/> + + <!-- Step; 15-16. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage3"/> + <waitForPageLoad stepKey="waitForPageLoad5"/> + <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartPriceRule3"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="couponCode" value="{$couponCode}"/> + </actionGroup> + <waitForText userInput='The coupon code "{$couponCode}" is not valid.' stepKey="waitForText3"/> + <see selector="{{StorefrontMessagesSection.error}}" userInput='The coupon code "{$couponCode}" is not valid.' + stepKey="seeErrorMessages1"/> + <waitForElementNotVisible selector="{{CheckoutCartSummarySection.discountAmount}}" time="30" + stepKey="waitForElementNotDiscountVisible1"/> + + <!-- Step: 17. Open another browser Reset Cookie --> + <resetCookie userInput="PHPSESSID" stepKey="resetCookie"/> + + <!-- Step: 18-19. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage4"/> + <waitForPageLoad stepKey="waitForPageLoad6"/> + <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartPriceRule4"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="couponCode" value="{$couponCode}"/> + </actionGroup> + <waitForText userInput='The coupon code "{$couponCode}" is not valid.' stepKey="waitForText4"/> + <see selector="{{StorefrontMessagesSection.error}}" userInput='The coupon code "{$couponCode}" is not valid.' + stepKey="seeErrorMessages2"/> + <waitForElementNotVisible selector="{{CheckoutCartSummarySection.discountAmount}}" time="30" + stepKey="waitForElementNotDiscountVisible2"/> + </test> +</tests> From 042de5d08d0de641168a2d3f3bf68fb9c581a526 Mon Sep 17 00:00:00 2001 From: Dmitriy Kogut <kogut.dmitriy@gmail.com> Date: Thu, 20 Sep 2018 16:23:56 +0300 Subject: [PATCH 33/54] MAGETWO-93830: Automate with MFTF Sort products grid after removing shared catalog --- .../ActionGroup/AdminDeleteCustomerGroupActionGroup.xml | 6 ++++++ .../Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml index 9b06caa5a6d4a..b62a647ebdf62 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -12,6 +12,12 @@ <arguments> <argument name="customerGroupName" type="string"/> </arguments> + <amOnPage url="{{AdminCustomerGroupsIndexPage.url}}" stepKey="goToAdminCustomerGroupIndexPage"/> + <waitForPageLoad time="30" stepKey="waitForCustomerGroupIndexPageLoad"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openFiltersSectionOnCustomerGroupIndexPage"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="cleanFiltersIfTheySet"/> + <fillField userInput="{{customerGroupName}}" selector="{{AdminDataGridHeaderSection.filterFieldInput('customer_group_code')}}" stepKey="fillNameFieldOnFiltersSection"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> <click selector="{{AdminCustomerGroupGridActionsSection.selectButton('customerGroupName')}}" stepKey="clickSelectButton"/> <click selector="{{AdminCustomerGroupGridActionsSection.deleteAction('customerGroupName')}}" stepKey="clickOnDeleteItem"/> <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmDeleteCustomerGroup"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml index 07d1b04dcb411..5981fb7c907c3 100644 --- a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupsIndexPage.xml @@ -10,6 +10,5 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="AdminCustomerGroupsIndexPage" url="/customer/group/" area="admin" module="Magento_Customer"> <section name="AdminCustomerGroupGridActionsSection"/> - <section name="AdminCustomerGroupFiltersSection"/> </page> </pages> From d8064f9f8589d65cc19efa70a862f3c4c6aedfa8 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Thu, 20 Sep 2018 16:40:02 +0300 Subject: [PATCH 34/54] MAGETWO-94838: Automate with MFTF Ability to configure Advanced Prices from Shared Catalog Page for different type of products --- .../ActionGroup/AdminDeleteCustomerGroupActionGroup.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml index 9b06caa5a6d4a..b62a647ebdf62 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -12,6 +12,12 @@ <arguments> <argument name="customerGroupName" type="string"/> </arguments> + <amOnPage url="{{AdminCustomerGroupsIndexPage.url}}" stepKey="goToAdminCustomerGroupIndexPage"/> + <waitForPageLoad time="30" stepKey="waitForCustomerGroupIndexPageLoad"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openFiltersSectionOnCustomerGroupIndexPage"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="cleanFiltersIfTheySet"/> + <fillField userInput="{{customerGroupName}}" selector="{{AdminDataGridHeaderSection.filterFieldInput('customer_group_code')}}" stepKey="fillNameFieldOnFiltersSection"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> <click selector="{{AdminCustomerGroupGridActionsSection.selectButton('customerGroupName')}}" stepKey="clickSelectButton"/> <click selector="{{AdminCustomerGroupGridActionsSection.deleteAction('customerGroupName')}}" stepKey="clickOnDeleteItem"/> <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmDeleteCustomerGroup"/> From 436dee71b71162e70d5166c3c39cbc561247222d Mon Sep 17 00:00:00 2001 From: Roman Glushko <r.glushko@atwix.com> Date: Thu, 20 Sep 2018 21:10:17 +0300 Subject: [PATCH 35/54] #141 Restored config after patching the branch --- app/code/Magento/CatalogGraphQl/etc/graphql/di.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml index 68a292ede6b4a..7e18ac34f0fcc 100644 --- a/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml +++ b/app/code/Magento/CatalogGraphQl/etc/graphql/di.xml @@ -6,6 +6,7 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <preference for="Magento\Catalog\Model\Product\Option\Type\Date" type="Magento\CatalogGraphQl\Model\Product\Option\DateType" /> <type name="Magento\CatalogGraphQl\Model\ProductInterfaceTypeResolverComposite"> <arguments> <argument name="productTypeNameResolvers" xsi:type="array"> From 4942c6f202b097256c31fd8c32959a8867ae459a Mon Sep 17 00:00:00 2001 From: Roman Glushko <r.glushko@atwix.com> Date: Thu, 20 Sep 2018 21:11:08 +0300 Subject: [PATCH 36/54] #141 Decoupling the CustomOption data provider --- .../CartItemTypeResolverComposite.php | 2 +- .../CartItem/CustomOptionPriceUnitLabel.php | 64 +++++++++ .../CustomOptionValueInterface.php | 35 +++++ .../DropdownCustomOptionValue.php | 64 +++++++++ .../MultipleCustomOptionValue.php | 71 +++++++++ .../TextCustomOptionValue.php | 61 ++++++++ .../CartItem/CustomOptionValueComposite.php | 68 +++++++++ .../CartItem/CustomizableOption.php | 136 ++---------------- app/code/Magento/QuoteGraphQl/etc/di.xml | 24 ++++ 9 files changed, 401 insertions(+), 124 deletions(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionPriceUnitLabel.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/CustomOptionValueInterface.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/DropdownCustomOptionValue.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/MultipleCustomOptionValue.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/TextCustomOptionValue.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValueComposite.php create mode 100644 app/code/Magento/QuoteGraphQl/etc/di.xml diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php index 901f177ced98e..5af5217562044 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php @@ -30,7 +30,7 @@ public function __construct(array $cartItemTypeResolvers = []) /** * {@inheritdoc} - * + * * @throws GraphQlInputException */ public function resolveType(array $data) : string diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionPriceUnitLabel.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionPriceUnitLabel.php new file mode 100644 index 0000000000000..f80b2994cc874 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionPriceUnitLabel.php @@ -0,0 +1,64 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem; + +use Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\Store; +use Magento\Store\Model\StoreManagerInterface; + +/** + * Custom Option Data provider + */ +class CustomOptionPriceUnitLabel +{ + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @param StoreManagerInterface $storeManager + */ + public function __construct( + StoreManagerInterface $storeManager + ) { + $this->storeManager = $storeManager; + } + + /** + * Retrieve price value unit + * + * @param string $priceType + * @return string + * @throws NoSuchEntityException + */ + public function getData(string $priceType): string + { + if (ProductPriceOptionsInterface::VALUE_PERCENT == $priceType) { + return '%'; + } + + return $this->getCurrencySymbol(); + } + + /** + * Get currency symbol + * + * @return string + * @throws NoSuchEntityException + */ + private function getCurrencySymbol(): string + { + /** @var Store|StoreInterface $store */ + $store = $this->storeManager->getStore(); + + return $store->getBaseCurrency()->getCurrencySymbol(); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/CustomOptionValueInterface.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/CustomOptionValueInterface.php new file mode 100644 index 0000000000000..700362ceea0e6 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/CustomOptionValueInterface.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue; + +use Magento\Catalog\Model\Product\Option; +use Magento\Catalog\Model\Product\Option\Type\DefaultType; +use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\Quote\Model\Quote\Item\Option as SelectedOption; + +/** + * Custom Option Value Data provider + */ +interface CustomOptionValueInterface +{ + /** + * Custom Option Type Data Provider + * + * @param QuoteItem $cartItem + * @param Option $option + * @param SelectedOption $selectedOption + * @param DefaultType $optionTypeRenderer + * @return array + */ + public function getData( + QuoteItem $cartItem, + Option $option, + SelectedOption $selectedOption, + DefaultType $optionTypeRenderer + ): array; +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/DropdownCustomOptionValue.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/DropdownCustomOptionValue.php new file mode 100644 index 0000000000000..f56dacca23ca4 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/DropdownCustomOptionValue.php @@ -0,0 +1,64 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue; + +use Magento\Catalog\Model\Product\Option; +use Magento\Catalog\Model\Product\Option\Type\DefaultType as DefaultOptionType; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\Quote\Model\Quote\Item\Option as SelectedOption; +use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionPriceUnitLabel; + +/** + * Dropdown Custom Option Value Data provider + */ +class DropdownCustomOptionValue implements CustomOptionValueInterface +{ + /** + * @var CustomOptionPriceUnitLabel + */ + private $customOptionPriceUnitLabel; + + /** + * @param CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + */ + public function __construct( + CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + ) { + $this->customOptionPriceUnitLabel = $customOptionPriceUnitLabel; + } + + /** + * {@inheritdoc} + * + * @throws NoSuchEntityException + */ + public function getData( + QuoteItem $cartItem, + Option $option, + SelectedOption $selectedOption, + DefaultOptionType $optionTypeRenderer + ): array { + $selectedValue = $selectedOption->getValue(); + $optionValue = $option->getValueById($selectedValue); + $optionPriceType = (string) $optionValue->getPriceType(); + $priceValueUnits = $this->customOptionPriceUnitLabel->getData($optionPriceType); + + $selectedOptionValueData = [ + 'id' => $selectedOption->getId(), + 'label' => $optionTypeRenderer->getFormattedOptionValue($selectedValue), + 'price' => [ + 'type' => strtoupper($optionPriceType), + 'units' => $priceValueUnits, + 'value' => $optionValue->getPrice(), + ] + ]; + + return [$selectedOptionValueData]; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/MultipleCustomOptionValue.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/MultipleCustomOptionValue.php new file mode 100644 index 0000000000000..87ee56f56100c --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/MultipleCustomOptionValue.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue; + +use Magento\Catalog\Model\Product\Option; +use Magento\Catalog\Model\Product\Option\Type\DefaultType; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\Quote\Model\Quote\Item\Option as SelectedOption; +use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionPriceUnitLabel; + +/** + * Multiple Option Value Data provider + */ +class MultipleCustomOptionValue implements CustomOptionValueInterface +{ + /** + * @var CustomOptionPriceUnitLabel + */ + private $customOptionPriceUnitLabel; + + /** + * @param CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + */ + public function __construct( + CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + ) { + $this->customOptionPriceUnitLabel = $customOptionPriceUnitLabel; + } + + /** + * {@inheritdoc} + * + * @throws NoSuchEntityException + */ + public function getData( + QuoteItem $cartItem, + Option $option, + SelectedOption $selectedOption, + DefaultType $optionTypeRenderer + ): array { + $selectedOptionValueData = []; + $optionIds = explode(',', $selectedOption->getValue()); + + if (0 === count($optionIds)) { + return $selectedOptionValueData; + } + + foreach ($optionIds as $optionId) { + $optionValue = $option->getValueById($optionId); + $priceValueUnits = $this->customOptionPriceUnitLabel->getData($optionValue->getPriceType()); + + $selectedOptionValueData[] = [ + 'id' => $selectedOption->getId(), + 'label' => $optionValue->getTitle(), + 'price' => [ + 'type' => strtoupper($optionValue->getPriceType()), + 'units' => $priceValueUnits, + 'value' => $optionValue->getPrice(), + ], + ]; + } + + return $selectedOptionValueData; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/TextCustomOptionValue.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/TextCustomOptionValue.php new file mode 100644 index 0000000000000..78657603ff3e2 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/TextCustomOptionValue.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue; + +use Magento\Catalog\Model\Product\Option; +use Magento\Catalog\Model\Product\Option\Type\DefaultType; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\Quote\Model\Quote\Item\Option as SelectedOption; +use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionPriceUnitLabel; + +/** + * Text Custom Option Value Data provider + */ +class TextCustomOptionValue implements CustomOptionValueInterface +{ + /** + * @var CustomOptionPriceUnitLabel + */ + private $customOptionPriceUnitLabel; + + /** + * @param CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + */ + public function __construct( + CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + ) { + $this->customOptionPriceUnitLabel = $customOptionPriceUnitLabel; + } + + /** + * {@inheritdoc} + * + * @throws NoSuchEntityException + */ + public function getData( + QuoteItem $cartItem, + Option $option, + SelectedOption $selectedOption, + DefaultType $optionTypeRenderer + ): array { + $priceValueUnits = $this->customOptionPriceUnitLabel->getData($option->getPriceType()); + + $selectedOptionValueData = [ + 'id' => $selectedOption->getId(), + 'label' => $optionTypeRenderer->getFormattedOptionValue($selectedOption->getValue()), + 'price' => [ + 'type' => strtoupper($option->getPriceType()), + 'units' => $priceValueUnits, + 'value' => $option->getPrice(), + ] + ]; + + return [$selectedOptionValueData]; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValueComposite.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValueComposite.php new file mode 100644 index 0000000000000..4234753d11631 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValueComposite.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem; + +use Magento\Catalog\Model\Product\Option; +use Magento\Catalog\Model\Product\Option\Type\DefaultType as DefaultOptionType; +use Magento\Catalog\Model\Product\Option\Type\Select as SelectOptionType; +use Magento\Catalog\Model\Product\Option\Type\Text as TextOptionType; +use Magento\Framework\Exception\LocalizedException; +use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\Quote\Model\Quote\Item\Option as SelectedOption; +use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\CustomOptionValueInterface; + +/** + * Custom Option Value Composite Data provider + */ +class CustomOptionValueComposite +{ + /** + * @var CustomOptionValueInterface[] + */ + private $customOptionValueTypeProviders; + + /** + * @param array $customOptionValueTypeProviders + */ + public function __construct( + array $customOptionValueTypeProviders + ) { + $this->customOptionValueTypeProviders = $customOptionValueTypeProviders; + } + + /** + * Retrieve custom option values data + * + * @param string $optionType + * @param $cartItem + * @param $option + * @param $selectedOption + * @return array + * @throws LocalizedException + */ + public function getData( + string $optionType, + QuoteItem $cartItem, + Option $option, + SelectedOption $selectedOption + ): array { + if (!array_key_exists($optionType, $this->customOptionValueTypeProviders)) { + throw new LocalizedException(__('Option type "%1" is not supported', $optionType)); + } + + /** @var SelectOptionType|TextOptionType|DefaultOptionType $optionTypeRenderer */ + $optionTypeRenderer = $option->groupFactory($optionType) + ->setOption($option) + ->setConfigurationItem($cartItem) + ->setConfigurationItemOption($selectedOption); + + $customOptionValueTypeProvider = $this->customOptionValueTypeProviders[$optionType]; + + return $customOptionValueTypeProvider->getData($cartItem, $option, $selectedOption, $optionTypeRenderer); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php index 909867c0457d8..d40cad0242249 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php @@ -7,17 +7,8 @@ namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem; -use Magento\Catalog\Api\Data\ProductCustomOptionInterface; -use Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface; -use Magento\Catalog\Model\Product\Option\Type\DefaultType as DefaultOptionType; -use Magento\Catalog\Model\Product\Option\Type\Select as SelectOptionType; -use Magento\Catalog\Model\Product\Option\Type\Text as TextOptionType; use Magento\Framework\Exception\LocalizedException; -use Magento\Framework\Exception\NoSuchEntityException; use Magento\Quote\Model\Quote\Item as QuoteItem; -use Magento\Store\Api\Data\StoreInterface; -use Magento\Store\Model\Store; -use Magento\Store\Model\StoreManagerInterface; /** * Custom Option Data provider @@ -25,17 +16,17 @@ class CustomizableOption { /** - * @var StoreManagerInterface + * @var CustomOptionValueComposite */ - private $storeManager; + private $customOptionValueDataProvider; /** - * @param StoreManagerInterface $storeManager + * @param CustomOptionValueComposite $customOptionValueDataProvider */ public function __construct( - StoreManagerInterface $storeManager + CustomOptionValueComposite $customOptionValueDataProvider ) { - $this->storeManager = $storeManager; + $this->customOptionValueDataProvider = $customOptionValueDataProvider; } /** @@ -44,97 +35,26 @@ public function __construct( * @param QuoteItem $cartItem * @param int $optionId * @return array - * @throws NoSuchEntityException * @throws LocalizedException */ public function getData(QuoteItem $cartItem, int $optionId): array { $product = $cartItem->getProduct(); $option = $product->getOptionById($optionId); + $optionType = $option->getType(); if (!$option) { return []; } - $itemOption = $cartItem->getOptionByCode('option_' . $option->getId()); + $selectedOption = $cartItem->getOptionByCode('option_' . $option->getId()); - /** @var SelectOptionType|TextOptionType|DefaultOptionType $optionTypeGroup */ - $optionTypeGroup = $option->groupFactory($option->getType()) - ->setOption($option) - ->setConfigurationItem($cartItem) - ->setConfigurationItemOption($itemOption); - - if (ProductCustomOptionInterface::OPTION_GROUP_FILE == $option->getType()) { - $downloadParams = $cartItem->getFileDownloadParams(); - - if ($downloadParams) { - $url = $downloadParams->getUrl(); - if ($url) { - $optionTypeGroup->setCustomOptionDownloadUrl($url); - } - $urlParams = $downloadParams->getUrlParams(); - if ($urlParams) { - $optionTypeGroup->setCustomOptionUrlParams($urlParams); - } - } - } - - $selectedOptionValueData = [ - 'id' => $itemOption->getId(), - 'label' => $optionTypeGroup->getFormattedOptionValue($itemOption->getValue()), - ]; - - if (ProductCustomOptionInterface::OPTION_TYPE_DROP_DOWN == $option->getType() - || ProductCustomOptionInterface::OPTION_TYPE_RADIO == $option->getType() - || ProductCustomOptionInterface::OPTION_TYPE_CHECKBOX == $option->getType() - ) { - $optionValue = $option->getValueById($itemOption->getValue()); - $priceValueUnits = $this->getPriceValueUnits($optionValue->getPriceType()); - - $selectedOptionValueData['price'] = [ - 'type' => strtoupper($optionValue->getPriceType()), - 'units' => $priceValueUnits, - 'value' => $optionValue->getPrice(), - ]; - - $selectedOptionValueData = [$selectedOptionValueData]; - } - - if (ProductCustomOptionInterface::OPTION_TYPE_FIELD == $option->getType() - || ProductCustomOptionInterface::OPTION_TYPE_AREA == $option->getType() - || ProductCustomOptionInterface::OPTION_GROUP_DATE == $option->getType() - || ProductCustomOptionInterface::OPTION_TYPE_TIME == $option->getType() - ) { - $priceValueUnits = $this->getPriceValueUnits($option->getPriceType()); - - $selectedOptionValueData['price'] = [ - 'type' => strtoupper($option->getPriceType()), - 'units' => $priceValueUnits, - 'value' => $option->getPrice(), - ]; - - $selectedOptionValueData = [$selectedOptionValueData]; - } - - if (ProductCustomOptionInterface::OPTION_TYPE_MULTIPLE == $option->getType()) { - $selectedOptionValueData = []; - $optionIds = explode(',', $itemOption->getValue()); - - foreach ($optionIds as $optionId) { - $optionValue = $option->getValueById($optionId); - $priceValueUnits = $this->getPriceValueUnits($optionValue->getPriceType()); - - $selectedOptionValueData[] = [ - 'id' => $itemOption->getId(), - 'label' => $optionValue->getTitle(), - 'price' => [ - 'type' => strtoupper($optionValue->getPriceType()), - 'units' => $priceValueUnits, - 'value' => $optionValue->getPrice(), - ], - ]; - } - } + $selectedOptionValueData = $this->customOptionValueDataProvider->getData( + $optionType, + $cartItem, + $option, + $selectedOption + ); return [ 'id' => $option->getId(), @@ -144,34 +64,4 @@ public function getData(QuoteItem $cartItem, int $optionId): array 'sort_order' => $option->getSortOrder(), ]; } - - /** - * Retrieve price value unit - * - * @param string $priceType - * @return string - * @throws NoSuchEntityException - */ - private function getPriceValueUnits(string $priceType): string - { - if (ProductPriceOptionsInterface::VALUE_PERCENT == $priceType) { - return '%'; - } - - return $this->getCurrencySymbol(); - } - - /** - * Get currency symbol - * - * @return string - * @throws NoSuchEntityException - */ - private function getCurrencySymbol(): string - { - /** @var Store|StoreInterface $store */ - $store = $this->storeManager->getStore(); - - return $store->getBaseCurrency()->getCurrencySymbol(); - } } diff --git a/app/code/Magento/QuoteGraphQl/etc/di.xml b/app/code/Magento/QuoteGraphQl/etc/di.xml new file mode 100644 index 0000000000000..276049cb61deb --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/etc/di.xml @@ -0,0 +1,24 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValueComposite"> + <arguments> + <argument name="customOptionValueTypeProviders" xsi:type="array"> + <item name="drop_down" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\DropdownCustomOptionValue</item> + <item name="radio" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\DropdownCustomOptionValue</item> + <item name="checkbox" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\DropdownCustomOptionValue</item> + <item name="field" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> + <item name="area" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> + <item name="date" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> + <item name="time" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> + <item name="date_time" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> + <item name="multiple" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\MultipleCustomOptionValue</item> + </argument> + </arguments> + </type> +</config> From 13a57736e503637984f2a4552e892e4a080ebab4 Mon Sep 17 00:00:00 2001 From: Stas Puga <stas.puga@transoftgroup.com> Date: Fri, 21 Sep 2018 07:42:24 +0300 Subject: [PATCH 37/54] MAGETWO-94843: Automate with MFTF Auto generated coupon code for Cart Price Rules considers "Uses per Coupon" and "Uses per Customer" options --- .../Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml index 6250e1abba732..caa9094d5901f 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -143,7 +143,7 @@ <waitForElementNotVisible selector="{{CheckoutCartSummarySection.discountAmount}}" time="30" stepKey="waitForElementNotDiscountVisible1"/> - <!-- Step: 17. Open another browser Reset Cookie --> + <!-- Step: 17. Reset Cookie --> <resetCookie userInput="PHPSESSID" stepKey="resetCookie"/> <!-- Step: 18-19. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> From bd16304e80f5fc772e42d73662336af450c8ab1e Mon Sep 17 00:00:00 2001 From: Stas Puga <stas.puga@transoftgroup.com> Date: Fri, 21 Sep 2018 12:47:37 +0300 Subject: [PATCH 38/54] MAGETWO-94843: Automate with MFTF Auto generated coupon code for Cart Price Rules considers "Uses per Coupon" and "Uses per Customer" options --- .../Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml index caa9094d5901f..6f9474278bf45 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -17,8 +17,7 @@ value="[Cart Price Rule] Auto generated coupon code considers 'Uses per Coupon' and 'Uses per Customer' options"/> <severity value="AVERAGE"/> <testCaseId value="MAGETWO-59323"/> - <group value="test"/> - <!--<group value="salesRule"/>--> + <group value="salesRule"/> </annotations> <before> From 101716c2ab584a6cdc923afc903c76b212825bc5 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Wed, 26 Sep 2018 14:46:48 +0200 Subject: [PATCH 39/54] Fixed methods DocBlock comments --- app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php | 2 +- .../Model/Resolver/Category/CategoryHtmlAttribute.php | 2 +- .../GraphQl/Catalog/CategoryWithDescriptionDirectivesTest.php | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php index 4fc3ab4705055..e2998438bd74c 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php @@ -79,7 +79,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php index 17715344fad2e..55c90425c2f5f 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php @@ -43,7 +43,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function resolve( Field $field, diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryWithDescriptionDirectivesTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryWithDescriptionDirectivesTest.php index 48496d4ca9fbc..c115f7124c9fc 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryWithDescriptionDirectivesTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryWithDescriptionDirectivesTest.php @@ -23,6 +23,9 @@ class CategoryWithDescriptionDirectivesTest extends GraphQlAbstract */ private $objectManager; + /** + * @inheritdoc + */ protected function setUp() { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); From 7990b83d7d27efdaa89d60292e37058d5b78c79f Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 26 Sep 2018 19:05:52 +0300 Subject: [PATCH 40/54] GraphQL-141: [Mutations] Cart Operations > Add simple product to Cart --- .../Model/Cart/AddProductsToCart.php | 136 +++++++++++++ .../Model/Cart/AddSimpleProductToCart.php | 149 +++++++++++++++ .../Cart/AddSimpleProductToCartProcessor.php | 122 ------------ .../ExtractDataFromCart.php} | 14 +- .../DataProvider}/CustomizableOption.php | 17 +- .../CustomizableOptionValue/Composite.php | 68 +++++++ .../CustomizableOptionValue/Dropdown.php} | 39 ++-- .../CustomizableOptionValue/Multiple.php} | 26 ++- .../PriceUnitLabel.php} | 5 +- .../CustomizableOptionValue/Text.php | 59 ++++++ .../CustomizableOptionValueInterface.php} | 13 +- .../Resolver/AddSimpleProductsToCart.php | 77 ++++++++ .../{Coupon => }/ApplyCouponToCart.php | 2 +- .../Resolver/Cart/AddSimpleProductsToCart.php | 178 ------------------ .../Resolver/CartItem/CustomizableOptions.php | 94 --------- .../Model/Resolver/CartItemTypeResolver.php | 34 ++-- .../CartItemTypeResolverComposite.php | 56 ------ .../Resolver/{Cart => }/CreateEmptyCart.php | 2 +- .../Model/Resolver/CustomizableOptions.php | 65 +++++++ .../TextCustomOptionValue.php | 61 ------ .../CartItem/CustomOptionValueComposite.php | 68 ------- .../{Coupon => }/RemoveCouponFromCart.php | 2 +- app/code/Magento/QuoteGraphQl/etc/di.xml | 30 +-- .../Magento/QuoteGraphQl/etc/graphql/di.xml | 23 --- .../Magento/QuoteGraphQl/etc/schema.graphqls | 19 +- 25 files changed, 655 insertions(+), 704 deletions(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php create mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCart.php delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php rename app/code/Magento/QuoteGraphQl/Model/{Resolver/DataProvider/Cart/CartHydrator.php => Cart/ExtractDataFromCart.php} (74%) rename app/code/Magento/QuoteGraphQl/Model/{Resolver/DataProvider/CartItem => CartItem/DataProvider}/CustomizableOption.php (70%) create mode 100644 app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Composite.php rename app/code/Magento/QuoteGraphQl/Model/{Resolver/DataProvider/CartItem/CustomOptionValue/DropdownCustomOptionValue.php => CartItem/DataProvider/CustomizableOptionValue/Dropdown.php} (50%) rename app/code/Magento/QuoteGraphQl/Model/{Resolver/DataProvider/CartItem/CustomOptionValue/MultipleCustomOptionValue.php => CartItem/DataProvider/CustomizableOptionValue/Multiple.php} (61%) rename app/code/Magento/QuoteGraphQl/Model/{Resolver/DataProvider/CartItem/CustomOptionPriceUnitLabel.php => CartItem/DataProvider/CustomizableOptionValue/PriceUnitLabel.php} (90%) create mode 100644 app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Text.php rename app/code/Magento/QuoteGraphQl/Model/{Resolver/DataProvider/CartItem/CustomOptionValue/CustomOptionValueInterface.php => CartItem/DataProvider/CustomizableOptionValueInterface.php} (58%) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/AddSimpleProductsToCart.php rename app/code/Magento/QuoteGraphQl/Model/Resolver/{Coupon => }/ApplyCouponToCart.php (98%) delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php rename app/code/Magento/QuoteGraphQl/Model/Resolver/{Cart => }/CreateEmptyCart.php (98%) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/CustomizableOptions.php delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/TextCustomOptionValue.php delete mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValueComposite.php rename app/code/Magento/QuoteGraphQl/Model/Resolver/{Coupon => }/RemoveCouponFromCart.php (98%) delete mode 100644 app/code/Magento/QuoteGraphQl/etc/graphql/di.xml diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php new file mode 100644 index 0000000000000..87be72f1df1f2 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php @@ -0,0 +1,136 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Cart; + +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; +use Magento\Framework\Message\AbstractMessage; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +use Magento\Quote\Model\Quote; +use Magento\QuoteGraphQl\Model\Authorization\IsCartMutationAllowedForCurrentUser; + +/** + * Add products to cart + */ +class AddProductsToCart +{ + /** + * @var MaskedQuoteIdToQuoteIdInterface + */ + private $maskedQuoteIdToQuoteId; + + /** + * @var CartRepositoryInterface + */ + private $cartRepository; + + /** + * @var IsCartMutationAllowedForCurrentUser + */ + private $isCartMutationAllowedForCurrentUser; + + /** + * @var AddSimpleProductToCart + */ + private $addProductToCart; + + /** + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + * @param CartRepositoryInterface $cartRepository + * @param IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser + * @param AddSimpleProductToCart $addProductToCart + */ + public function __construct( + MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, + CartRepositoryInterface $cartRepository, + IsCartMutationAllowedForCurrentUser $isCartMutationAllowedForCurrentUser, + AddSimpleProductToCart $addProductToCart + ) { + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->cartRepository = $cartRepository; + $this->isCartMutationAllowedForCurrentUser = $isCartMutationAllowedForCurrentUser; + $this->addProductToCart = $addProductToCart; + } + + /** + * Add products to cart + * + * @param string $cartHash + * @param array $cartItems + * @return Quote + * @throws GraphQlInputException + */ + public function execute(string $cartHash, array $cartItems): Quote + { + $cart = $this->getCart($cartHash); + + foreach ($cartItems as $cartItemData) { + $this->addProductToCart->execute($cart, $cartItemData); + } + + if ($cart->getData('has_error')) { + throw new GraphQlInputException( + __('Shopping cart error: %message', ['message' => $this->getCartErrors($cart)]) + ); + } + + $this->cartRepository->save($cart); + return $cart; + } + + /** + * @param string $cartHash + * @return Quote + * @throws GraphQlNoSuchEntityException + * @throws GraphQlAuthorizationException + */ + private function getCart(string $cartHash): Quote + { + try { + $cartId = $this->maskedQuoteIdToQuoteId->execute($cartHash); + $cart = $this->cartRepository->get($cartId); + } catch (NoSuchEntityException $e) { + throw new GraphQlNoSuchEntityException( + __('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $cartHash]) + ); + } + + if (false === $this->isCartMutationAllowedForCurrentUser->execute($cartId)) { + throw new GraphQlAuthorizationException( + __( + 'The current user cannot perform operations on cart "%masked_cart_id"', + ['masked_cart_id' => $cartHash] + ) + ); + } + + /** @var Quote $cart */ + return $cart; + } + + /** + * Collecting cart errors + * + * @param Quote $cart + * @return string + */ + private function getCartErrors(Quote $cart): string + { + $errorMessages = []; + + /** @var AbstractMessage $error */ + foreach ($cart->getErrors() as $error) { + $errorMessages[] = $error->getText(); + } + + return implode(PHP_EOL, $errorMessages); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCart.php new file mode 100644 index 0000000000000..6b13c6c0af72e --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCart.php @@ -0,0 +1,149 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Cart; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\DataObject; +use Magento\Framework\DataObjectFactory; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; +use Magento\Framework\Stdlib\ArrayManager; +use Magento\Quote\Model\Quote; + +/** + * Add simple product to cart + * + * TODO: should be replaced for different types resolver + */ +class AddSimpleProductToCart +{ + /** + * @var ArrayManager + */ + private $arrayManager; + + /** + * @var DataObjectFactory + */ + private $dataObjectFactory; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @param ArrayManager $arrayManager + * @param DataObjectFactory $dataObjectFactory + * @param ProductRepositoryInterface $productRepository + */ + public function __construct( + ArrayManager $arrayManager, + DataObjectFactory $dataObjectFactory, + ProductRepositoryInterface $productRepository + ) { + $this->arrayManager = $arrayManager; + $this->dataObjectFactory = $dataObjectFactory; + $this->productRepository = $productRepository; + } + + /** + * Add simple product to cart + * + * @param Quote $cart + * @param array $cartItemData + * @return void + * @throws GraphQlNoSuchEntityException + * @throws GraphQlInputException + */ + public function execute(Quote $cart, array $cartItemData): void + { + $sku = $this->extractSku($cartItemData); + $qty = $this->extractQty($cartItemData); + $customizableOptions = $this->extractCustomizableOptions($cartItemData); + + try { + $product = $this->productRepository->get($sku); + } catch (NoSuchEntityException $e) { + throw new GraphQlNoSuchEntityException(__('Could not find a product with SKU "%sku"', ['sku' => $sku])); + } + + $result = $cart->addProduct($product, $this->createBuyRequest($qty, $customizableOptions)); + + if (is_string($result)) { + throw new GraphQlInputException(__($result)); + } + } + + /** + * Extract SKU from cart item data + * + * @param array $cartItemData + * @return string + * @throws GraphQlInputException + */ + private function extractSku(array $cartItemData): string + { + $sku = $this->arrayManager->get('data/sku', $cartItemData); + if (!isset($sku)) { + throw new GraphQlInputException( __('Missing key "sku" in cart item data')); + } + return (string)$sku; + } + + /** + * Extract Qty from cart item data + * + * @param array $cartItemData + * @return float + * @throws GraphQlInputException + */ + private function extractQty(array $cartItemData): float + { + $qty = $this->arrayManager->get('data/qty', $cartItemData); + if (!isset($qty)) { + throw new GraphQlInputException( __('Missing key "qty" in cart item data')); + } + return (float)$qty; + } + + /** + * Extract Customizable Options from cart item data + * + * @param array $cartItemData + * @return array + */ + private function extractCustomizableOptions(array $cartItemData): array + { + $customizableOptions = $this->arrayManager->get('customizable_options', $cartItemData, []); + + $customizableOptionsData = []; + foreach ($customizableOptions as $customizableOption) { + $customizableOptionsData[$customizableOption['id']] = $customizableOption['value']; + } + return $customizableOptionsData; + } + + /** + * Format GraphQl input data to a shape that buy request has + * + * @param float $qty + * @param array $customOptions + * @return DataObject + */ + private function createBuyRequest(float $qty, array $customOptions): DataObject + { + return $this->dataObjectFactory->create([ + 'data' => [ + 'qty' => $qty, + 'options' => $customOptions, + ], + ]); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php b/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php deleted file mode 100644 index 3b6e1801c5f1f..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCartProcessor.php +++ /dev/null @@ -1,122 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Cart; - -use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Framework\DataObject; -use Magento\Framework\DataObjectFactory; -use Magento\Framework\Exception\LocalizedException; -use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Framework\Stdlib\ArrayManager; -use Magento\Quote\Api\CartRepositoryInterface; -use Magento\Quote\Api\Data\CartInterface; -use Magento\Quote\Api\GuestCartRepositoryInterface; -use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; -use Magento\Quote\Model\Quote; -use Magento\Quote\Model\Quote\Item as QuoteItem; - -/** - * Add simple product to cart process - */ -class AddSimpleProductToCartProcessor -{ - /** - * @var ArrayManager - */ - private $arrayManager; - - /** - * @var CartRepositoryInterface - */ - private $cartRepository; - - /** - * @var MaskedQuoteIdToQuoteIdInterface - */ - private $maskedQuoteIdToQuoteId; - - /** - * @var DataObjectFactory - */ - private $dataObjectFactory; - - /** - * @var GuestCartRepositoryInterface - */ - private $guestCartRepository; - - /** - * @var ProductRepositoryInterface - */ - private $productRepository; - - /** - * @param ArrayManager $arrayManager - * @param DataObjectFactory $dataObjectFactory - * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId - * @param CartRepositoryInterface $cartRepository - * @param GuestCartRepositoryInterface $guestCartRepository - * @param ProductRepositoryInterface $productRepository - */ - public function __construct( - ArrayManager $arrayManager, - DataObjectFactory $dataObjectFactory, - MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, - CartRepositoryInterface $cartRepository, - GuestCartRepositoryInterface $guestCartRepository, - ProductRepositoryInterface $productRepository - ) { - $this->productRepository = $productRepository; - $this->guestCartRepository = $guestCartRepository; - $this->dataObjectFactory = $dataObjectFactory; - $this->cartRepository = $cartRepository; - $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; - $this->arrayManager = $arrayManager; - } - - /** - * Resolve adding simple product to cart for customers/guests - * - * @param CartInterface|Quote $cart - * @param array $cartItemData - * @return QuoteItem|string - * @throws LocalizedException - * @throws NoSuchEntityException - */ - public function process($cart, array $cartItemData) - { - $sku = $this->arrayManager->get('details/sku', $cartItemData); - $product = $this->productRepository->get($sku); - - return $cart->addProduct($product, $this->getBuyRequest($cartItemData)); - } - - /** - * Format GraphQl input data to a shape that buy request has - * - * @param array $cartItem - * @return DataObject - */ - private function getBuyRequest(array $cartItem): DataObject - { - $customOptions = []; - $qty = $this->arrayManager->get('details/qty', $cartItem); - $customizableOptions = $this->arrayManager->get('customizable_options', $cartItem, []); - - foreach ($customizableOptions as $customizableOption) { - $customOptions[$customizableOption['id']] = $customizableOption['value']; - } - - return $this->dataObjectFactory->create([ - 'data' => [ - 'qty' => $qty, - 'options' => $customOptions - ] - ]); - } -} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/Cart/CartHydrator.php b/app/code/Magento/QuoteGraphQl/Model/Cart/ExtractDataFromCart.php similarity index 74% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/Cart/CartHydrator.php rename to app/code/Magento/QuoteGraphQl/Model/Cart/ExtractDataFromCart.php index 6a0a5f26aa336..faefa686606e2 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/Cart/CartHydrator.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/ExtractDataFromCart.php @@ -5,23 +5,23 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\Cart; +namespace Magento\QuoteGraphQl\Model\Cart; -use Magento\Quote\Api\Data\CartInterface; use Magento\Quote\Model\Quote; use Magento\Quote\Model\Quote\Item as QuoteItem; /** - * Cart Hydrator class + * Extract data from cart */ -class CartHydrator +class ExtractDataFromCart { /** - * Hydrate cart to plain array - * @param CartInterface|Quote $cart + * Extract data from cart + * + * @param Quote $cart * @return array */ - public function hydrate(CartInterface $cart): array + public function execute(Quote $cart): array { $items = []; diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOption.php similarity index 70% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php rename to app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOption.php index d40cad0242249..3199668060ea5 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomizableOption.php +++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOption.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem; +namespace Magento\QuoteGraphQl\Model\CartItem\DataProvider; use Magento\Framework\Exception\LocalizedException; use Magento\Quote\Model\Quote\Item as QuoteItem; @@ -16,17 +16,17 @@ class CustomizableOption { /** - * @var CustomOptionValueComposite + * @var CustomizableOptionValueInterface */ - private $customOptionValueDataProvider; + private $customizableOptionValue; /** - * @param CustomOptionValueComposite $customOptionValueDataProvider + * @param CustomizableOptionValueInterface $customOptionValueDataProvider */ public function __construct( - CustomOptionValueComposite $customOptionValueDataProvider + CustomizableOptionValueInterface $customOptionValueDataProvider ) { - $this->customOptionValueDataProvider = $customOptionValueDataProvider; + $this->customizableOptionValue = $customOptionValueDataProvider; } /** @@ -41,7 +41,6 @@ public function getData(QuoteItem $cartItem, int $optionId): array { $product = $cartItem->getProduct(); $option = $product->getOptionById($optionId); - $optionType = $option->getType(); if (!$option) { return []; @@ -49,8 +48,7 @@ public function getData(QuoteItem $cartItem, int $optionId): array $selectedOption = $cartItem->getOptionByCode('option_' . $option->getId()); - $selectedOptionValueData = $this->customOptionValueDataProvider->getData( - $optionType, + $selectedOptionValueData = $this->customizableOptionValue->getData( $cartItem, $option, $selectedOption @@ -62,6 +60,7 @@ public function getData(QuoteItem $cartItem, int $optionId): array 'type' => $option->getType(), 'values' => $selectedOptionValueData, 'sort_order' => $option->getSortOrder(), + 'is_required' => $option->getIsRequire(), ]; } } diff --git a/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Composite.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Composite.php new file mode 100644 index 0000000000000..5297845125300 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Composite.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue; + +use Magento\Catalog\Model\Product\Option; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\ObjectManagerInterface; +use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\Quote\Model\Quote\Item\Option as SelectedOption; +use Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValueInterface; + +/** + * @inheritdoc + */ +class Composite implements CustomizableOptionValueInterface +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var CustomizableOptionValueInterface[] + */ + private $customizableOptionValues; + + /** + * @param ObjectManagerInterface $objectManager + * @param CustomizableOptionValueInterface[] $customizableOptionValues + */ + public function __construct( + ObjectManagerInterface $objectManager, + array $customizableOptionValues = [] + ) { + $this->objectManager = $objectManager; + $this->customizableOptionValues = $customizableOptionValues; + } + + /** + * @inheritdoc + */ + public function getData( + QuoteItem $cartItem, + Option $option, + SelectedOption $selectedOption + ): array { + $optionType = $option->getType(); + + if (!array_key_exists($optionType, $this->customizableOptionValues)) { + throw new GraphQlInputException(__('Option type "%1" is not supported', $optionType)); + } + $customizableOptionValueClassName = $this->customizableOptionValues[$optionType]; + + $customizableOptionValue = $this->objectManager->get($customizableOptionValueClassName); + if (!$customizableOptionValue instanceof CustomizableOptionValueInterface) { + throw new LocalizedException( + __('%1 doesn\'t implement CustomizableOptionValueInterface', $customizableOptionValueClassName) + ); + } + return $customizableOptionValue->getData($cartItem, $option, $selectedOption); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/DropdownCustomOptionValue.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Dropdown.php similarity index 50% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/DropdownCustomOptionValue.php rename to app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Dropdown.php index f56dacca23ca4..74ed403465009 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/DropdownCustomOptionValue.php +++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Dropdown.php @@ -5,60 +5,61 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue; +namespace Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue; use Magento\Catalog\Model\Product\Option; -use Magento\Catalog\Model\Product\Option\Type\DefaultType as DefaultOptionType; -use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Catalog\Model\Product\Option\Type\Select as SelectOptionType; use Magento\Quote\Model\Quote\Item as QuoteItem; use Magento\Quote\Model\Quote\Item\Option as SelectedOption; -use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionPriceUnitLabel; +use Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValueInterface; /** - * Dropdown Custom Option Value Data provider + * @inheritdoc */ -class DropdownCustomOptionValue implements CustomOptionValueInterface +class Dropdown implements CustomizableOptionValueInterface { /** - * @var CustomOptionPriceUnitLabel + * @var PriceUnitLabel */ - private $customOptionPriceUnitLabel; + private $priceUnitLabel; /** - * @param CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + * @param PriceUnitLabel $priceUnitLabel */ public function __construct( - CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + PriceUnitLabel $priceUnitLabel ) { - $this->customOptionPriceUnitLabel = $customOptionPriceUnitLabel; + $this->priceUnitLabel = $priceUnitLabel; } /** - * {@inheritdoc} - * - * @throws NoSuchEntityException + * @inheritdoc */ public function getData( QuoteItem $cartItem, Option $option, - SelectedOption $selectedOption, - DefaultOptionType $optionTypeRenderer + SelectedOption $selectedOption ): array { + /** @var SelectOptionType $optionTypeRenderer */ + $optionTypeRenderer = $option->groupFactory($option->getType()) + ->setOption($option) + ->setConfigurationItemOption($selectedOption); + $selectedValue = $selectedOption->getValue(); $optionValue = $option->getValueById($selectedValue); - $optionPriceType = (string) $optionValue->getPriceType(); - $priceValueUnits = $this->customOptionPriceUnitLabel->getData($optionPriceType); + $optionPriceType = (string)$optionValue->getPriceType(); + $priceValueUnits = $this->priceUnitLabel->getData($optionPriceType); $selectedOptionValueData = [ 'id' => $selectedOption->getId(), 'label' => $optionTypeRenderer->getFormattedOptionValue($selectedValue), + 'value' => $selectedValue, 'price' => [ 'type' => strtoupper($optionPriceType), 'units' => $priceValueUnits, 'value' => $optionValue->getPrice(), ] ]; - return [$selectedOptionValueData]; } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/MultipleCustomOptionValue.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Multiple.php similarity index 61% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/MultipleCustomOptionValue.php rename to app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Multiple.php index 87ee56f56100c..619e84568a545 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/MultipleCustomOptionValue.php +++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Multiple.php @@ -5,44 +5,40 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue; +namespace Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue; use Magento\Catalog\Model\Product\Option; use Magento\Catalog\Model\Product\Option\Type\DefaultType; -use Magento\Framework\Exception\NoSuchEntityException; use Magento\Quote\Model\Quote\Item as QuoteItem; use Magento\Quote\Model\Quote\Item\Option as SelectedOption; -use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionPriceUnitLabel; +use Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValueInterface; /** * Multiple Option Value Data provider */ -class MultipleCustomOptionValue implements CustomOptionValueInterface +class Multiple implements CustomizableOptionValueInterface { /** - * @var CustomOptionPriceUnitLabel + * @var PriceUnitLabel */ - private $customOptionPriceUnitLabel; + private $priceUnitLabel; /** - * @param CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + * @param PriceUnitLabel $priceUnitLabel */ public function __construct( - CustomOptionPriceUnitLabel $customOptionPriceUnitLabel + PriceUnitLabel $priceUnitLabel ) { - $this->customOptionPriceUnitLabel = $customOptionPriceUnitLabel; + $this->priceUnitLabel = $priceUnitLabel; } /** - * {@inheritdoc} - * - * @throws NoSuchEntityException + * @inheritdoc */ public function getData( QuoteItem $cartItem, Option $option, - SelectedOption $selectedOption, - DefaultType $optionTypeRenderer + SelectedOption $selectedOption ): array { $selectedOptionValueData = []; $optionIds = explode(',', $selectedOption->getValue()); @@ -53,7 +49,7 @@ public function getData( foreach ($optionIds as $optionId) { $optionValue = $option->getValueById($optionId); - $priceValueUnits = $this->customOptionPriceUnitLabel->getData($optionValue->getPriceType()); + $priceValueUnits = $this->priceUnitLabel->getData($optionValue->getPriceType()); $selectedOptionValueData[] = [ 'id' => $selectedOption->getId(), diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionPriceUnitLabel.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/PriceUnitLabel.php similarity index 90% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionPriceUnitLabel.php rename to app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/PriceUnitLabel.php index f80b2994cc874..bee2e54ed5f40 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionPriceUnitLabel.php +++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/PriceUnitLabel.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem; +namespace Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue; use Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface; use Magento\Framework\Exception\NoSuchEntityException; @@ -16,7 +16,7 @@ /** * Custom Option Data provider */ -class CustomOptionPriceUnitLabel +class PriceUnitLabel { /** * @var StoreManagerInterface @@ -37,7 +37,6 @@ public function __construct( * * @param string $priceType * @return string - * @throws NoSuchEntityException */ public function getData(string $priceType): string { diff --git a/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Text.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Text.php new file mode 100644 index 0000000000000..4b29eb6a4a663 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValue/Text.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue; + +use Magento\Catalog\Model\Product\Option; +use Magento\Catalog\Model\Product\Option\Type\Text as TextOptionType; +use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\Quote\Model\Quote\Item\Option as SelectedOption; +use Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValueInterface; + +/** + * @inheritdoc + */ +class Text implements CustomizableOptionValueInterface +{ + /** + * @var PriceUnitLabel + */ + private $priceUnitLabel; + + /** + * @param PriceUnitLabel $priceUnitLabel + */ + public function __construct( + PriceUnitLabel $priceUnitLabel + ) { + $this->priceUnitLabel = $priceUnitLabel; + } + + /** + * @inheritdoc + */ + public function getData( + QuoteItem $cartItem, + Option $option, + SelectedOption $selectedOption + ): array { + /** @var TextOptionType $optionTypeRenderer */ + $optionTypeRenderer = $option->groupFactory($option->getType()); + $priceValueUnits = $this->priceUnitLabel->getData($option->getPriceType()); + + $selectedOptionValueData = [ + 'id' => $selectedOption->getId(), + 'label' => '', + 'value' => $optionTypeRenderer->getFormattedOptionValue($selectedOption->getValue()), + 'price' => [ + 'type' => strtoupper($option->getPriceType()), + 'units' => $priceValueUnits, + 'value' => $option->getPrice(), + ], + ]; + return [$selectedOptionValueData]; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/CustomOptionValueInterface.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValueInterface.php similarity index 58% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/CustomOptionValueInterface.php rename to app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValueInterface.php index 700362ceea0e6..fce8b80f6d476 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/CustomOptionValueInterface.php +++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/CustomizableOptionValueInterface.php @@ -5,31 +5,28 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue; +namespace Magento\QuoteGraphQl\Model\CartItem\DataProvider; use Magento\Catalog\Model\Product\Option; -use Magento\Catalog\Model\Product\Option\Type\DefaultType; use Magento\Quote\Model\Quote\Item as QuoteItem; use Magento\Quote\Model\Quote\Item\Option as SelectedOption; /** - * Custom Option Value Data provider + * Customizable Option Value Data provider */ -interface CustomOptionValueInterface +interface CustomizableOptionValueInterface { /** - * Custom Option Type Data Provider + * Customizable Option Value Data Provider * * @param QuoteItem $cartItem * @param Option $option * @param SelectedOption $selectedOption - * @param DefaultType $optionTypeRenderer * @return array */ public function getData( QuoteItem $cartItem, Option $option, - SelectedOption $selectedOption, - DefaultType $optionTypeRenderer + SelectedOption $selectedOption ): array; } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/AddSimpleProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/AddSimpleProductsToCart.php new file mode 100644 index 0000000000000..31a0b3d02e44a --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/AddSimpleProductsToCart.php @@ -0,0 +1,77 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Framework\Stdlib\ArrayManager; +use Magento\QuoteGraphQl\Model\Cart\AddProductsToCart; +use Magento\QuoteGraphQl\Model\Cart\ExtractDataFromCart; + +/** + * Add simple products to cart GraphQl resolver + * {@inheritdoc} + */ +class AddSimpleProductsToCart implements ResolverInterface +{ + /** + * @var ArrayManager + */ + private $arrayManager; + + /** + * @var AddProductsToCart + */ + private $addProductsToCart; + + /** + * @var ExtractDataFromCart + */ + private $extractDataFromCart; + + /** + * @param ArrayManager $arrayManager + * @param AddProductsToCart $addProductsToCart + * @param ExtractDataFromCart $extractDataFromCart + */ + public function __construct( + ArrayManager $arrayManager, + AddProductsToCart $addProductsToCart, + ExtractDataFromCart $extractDataFromCart + ) { + $this->arrayManager = $arrayManager; + $this->addProductsToCart = $addProductsToCart; + $this->extractDataFromCart = $extractDataFromCart; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + $cartHash = $this->arrayManager->get('input/cart_id', $args); + $cartItems = $this->arrayManager->get('input/cartItems', $args); + + if (!isset($cartHash)) { + throw new GraphQlInputException(__('Missing key "cart_id" in cart data')); + } + + if (!isset($cartItems) || !is_array($cartItems) || empty($cartItems)) { + throw new GraphQlInputException(__('Missing key "cartItems" in cart data')); + } + + $cart = $this->addProductsToCart->execute((string)$cartHash, $cartItems); + $cartData = $this->extractDataFromCart->execute($cart); + + return [ + 'cart' => $cartData, + ]; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Coupon/ApplyCouponToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/ApplyCouponToCart.php similarity index 98% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/Coupon/ApplyCouponToCart.php rename to app/code/Magento/QuoteGraphQl/Model/Resolver/ApplyCouponToCart.php index ab57b8ff499c6..ac5cb38326bc0 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Coupon/ApplyCouponToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/ApplyCouponToCart.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\Coupon; +namespace Magento\QuoteGraphQl\Model\Resolver; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\NoSuchEntityException; diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php deleted file mode 100644 index 80aa42b4365d7..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/AddSimpleProductsToCart.php +++ /dev/null @@ -1,178 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Resolver\Cart; - -use Magento\Authorization\Model\UserContextInterface; -use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Query\Resolver\Value; -use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; -use Magento\Framework\GraphQl\Query\ResolverInterface; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Framework\Message\AbstractMessage; -use Magento\Framework\Stdlib\ArrayManager; -use Magento\Quote\Api\CartRepositoryInterface; -use Magento\Quote\Api\Data\CartInterface; -use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; -use Magento\Quote\Model\Quote; -use Magento\QuoteGraphQl\Model\Cart\AddSimpleProductToCartProcessor; -use Magento\QuoteGraphQl\Model\Resolver\DataProvider\Cart\CartHydrator; - -/** - * Add simple product to cart GraphQl resolver - * {@inheritdoc} - */ -class AddSimpleProductsToCart implements ResolverInterface -{ - /** - * @var AddSimpleProductToCartProcessor - */ - private $addSimpleProductToCartProcessor; - - /** - * @var CartRepositoryInterface - */ - private $cartRepository; - - /** - * @var MaskedQuoteIdToQuoteIdInterface - */ - private $maskedQuoteIdToQuoteId; - - /** - * @var CartHydrator - */ - private $cartHydrator; - - /** - * @var ArrayManager - */ - private $arrayManager; - - /** - * @var ValueFactory - */ - private $valueFactory; - - /** - * @var UserContextInterface - */ - private $userContext; - - /** - * @param AddSimpleProductToCartProcessor $addSimpleProductToCartProcessor - * @param CartHydrator $cartHydrator - * @param ArrayManager $arrayManager - * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId - * @param CartRepositoryInterface $cartRepository - * @param ValueFactory $valueFactory - * @param UserContextInterface $userContext - */ - public function __construct( - AddSimpleProductToCartProcessor $addSimpleProductToCartProcessor, - CartHydrator $cartHydrator, - ArrayManager $arrayManager, - MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, - CartRepositoryInterface $cartRepository, - ValueFactory $valueFactory, - UserContextInterface $userContext - ) { - $this->valueFactory = $valueFactory; - $this->userContext = $userContext; - $this->arrayManager = $arrayManager; - $this->cartHydrator = $cartHydrator; - $this->cartRepository = $cartRepository; - $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; - $this->addSimpleProductToCartProcessor = $addSimpleProductToCartProcessor; - } - - /** - * Resolve adding simple product to cart for customers/guests - * {@inheritdoc} - */ - public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value - { - $cartHash = $this->arrayManager->get('input/cart_id', $args); - $cartItems = $this->arrayManager->get('input/cartItems', $args); - - if (!isset($cartHash)) { - throw new GraphQlInputException( - __('Missing key %1 in cart data', ['cart_id']) - ); - } - - if (!isset($cartItems)) { - throw new GraphQlInputException( - __('Missing key %1 in cart data', ['cartItems']) - ); - } - - $cart = $this->getCart((string) $cartHash); - - foreach ($cartItems as $cartItemData) { - $sku = $this->arrayManager->get('details/sku', $cartItemData); - - $message = $this->addSimpleProductToCartProcessor->process($cart, $cartItemData); - - if (is_string($message)) { - throw new GraphQlInputException( - __('%1: %2', $sku, $message) - ); - } - - if ($cart->getData('has_error')) { - throw new GraphQlInputException( - __('%1: %2', $sku, $this->getCartErrors($cart)) - ); - } - } - - $this->cartRepository->save($cart); - - $result = function () use ($cart) { - return [ - 'cart' => $this->cartHydrator->hydrate($cart) - ]; - }; - - return $this->valueFactory->create($result); - } - - /** - * Collecting cart errors - * - * @param CartInterface|Quote $cart - * @return string - */ - private function getCartErrors($cart): string - { - $errorMessages = []; - - /** @var AbstractMessage $error */ - foreach ($cart->getErrors() as $error) { - $errorMessages[] = $error->getText(); - } - - return implode(PHP_EOL, $errorMessages); - } - - /** - * Retrieving quote mode based on customer authorization - * - * @param string $cartHash - * @return CartInterface|Quote - * @throws NoSuchEntityException - */ - private function getCart(string $cartHash): CartInterface - { - $cartId = $this->maskedQuoteIdToQuoteId->execute((string) $cartHash); - - return $this->cartRepository->get($cartId); - } -} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php deleted file mode 100644 index 8961fea3acb4d..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItem/CustomizableOptions.php +++ /dev/null @@ -1,94 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Resolver\CartItem; - -use Magento\Authorization\Model\UserContextInterface; -use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Query\Resolver\Value; -use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; -use Magento\Framework\GraphQl\Query\ResolverInterface; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Quote\Model\Quote\Item as QuoteItem; -use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomizableOption as CustomizableOptionDataProvider; - -/** - * {@inheritdoc} - */ -class CustomizableOptions implements ResolverInterface -{ - /** - * @var CustomizableOptionDataProvider - */ - private $customOptionDataProvider; - - /** - * @var ValueFactory - */ - private $valueFactory; - - /** - * @var UserContextInterface - */ - private $userContext; - - /** - * @param ValueFactory $valueFactory - * @param UserContextInterface $userContext - * @param CustomizableOptionDataProvider $customOptionDataProvider - */ - public function __construct( - ValueFactory $valueFactory, - UserContextInterface $userContext, - CustomizableOptionDataProvider $customOptionDataProvider - ) { - $this->valueFactory = $valueFactory; - $this->userContext = $userContext; - $this->customOptionDataProvider = $customOptionDataProvider; - } - - /** - * {@inheritDoc} - */ - public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value - { - if (!isset($value['model'])) { - return $this->valueFactory->create(function () { - return []; - }); - } - - /** @var QuoteItem $cartItem */ - $cartItem = $value['model']; - $optionIds = $cartItem->getOptionByCode('option_ids'); - - if (!$optionIds) { - return $this->valueFactory->create(function () { - return []; - }); - } - - $customOptions = []; - $customOptionIds = explode(',', $optionIds->getValue()); - - foreach ($customOptionIds as $optionId) { - $customOptionData = $this->customOptionDataProvider->getData($cartItem, (int) $optionId); - - if (0 === count($customOptionData)) { - continue; - } - - $customOptions[] = $customOptionData; - } - - $result = function () use ($customOptions) { - return $customOptions; - }; - - return $this->valueFactory->create($result); - } -} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php index b8b197b45039a..88db93c177f7a 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php @@ -7,53 +7,49 @@ namespace Magento\QuoteGraphQl\Model\Resolver; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Query\Resolver\TypeResolverInterface; /** - * Resolver for cart item types that vary by product types - * - * {@inheritdoc} + * @inheritdoc */ class CartItemTypeResolver implements TypeResolverInterface { /** - * @var string[] + * @var array */ - private $cartItemTypes = []; + private $supportedTypes = []; /** - * @param TypeResolverInterface[] $cartItemTypes + * @param array $supportedTypes */ - public function __construct(array $cartItemTypes = []) + public function __construct(array $supportedTypes = []) { - $this->cartItemTypes = $cartItemTypes; + $this->supportedTypes = $supportedTypes; } /** - * Resolve GraphQl types to retrieve product type specific information about cart items * {@inheritdoc} * - * @throws GraphQlInputException + * @throws LocalizedException */ public function resolveType(array $data) : string { if (!isset($data['product'])) { - return ''; + throw new LocalizedException(__('Missing key "product" in cart data')); } - $productData = $data['product']; if (!isset($productData['type_id'])) { - return ''; + throw new LocalizedException(__('Missing key "type_id" in product data')); } - $productTypeId = $productData['type_id']; - if (!isset($this->cartItemTypes[$productTypeId])) { - return ''; + if (!isset($this->supportedTypes[$productTypeId])) { + throw new LocalizedException( + __('Product "%product_type" type is not supported', ['product_type' => $productTypeId]) + ); } - - return $this->cartItemTypes[$productTypeId]; + return $this->supportedTypes[$productTypeId]; } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php deleted file mode 100644 index 5af5217562044..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolverComposite.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Resolver; - -use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\GraphQl\Query\Resolver\TypeResolverInterface; - -/** - * {@inheritdoc} - */ -class CartItemTypeResolverComposite implements TypeResolverInterface -{ - /** - * TypeResolverInterface[] - */ - private $cartItemTypeResolvers = []; - - /** - * @param TypeResolverInterface[] $cartItemTypeResolvers - */ - public function __construct(array $cartItemTypeResolvers = []) - { - $this->cartItemTypeResolvers = $cartItemTypeResolvers; - } - - /** - * {@inheritdoc} - * - * @throws GraphQlInputException - */ - public function resolveType(array $data) : string - { - if (!isset($data['product'])) { - throw new GraphQlInputException( - __('Missing key %1 in cart data', ['product']) - ); - } - - foreach ($this->cartItemTypeResolvers as $cartItemTypeResolver) { - $resolvedType = $cartItemTypeResolver->resolveType($data); - - if ($resolvedType) { - return $resolvedType; - } - } - - throw new GraphQlInputException( - __('Concrete type for %1 not implemented', ['CartItemInterface']) - ); - } -} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/CreateEmptyCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php similarity index 98% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/CreateEmptyCart.php rename to app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php index 78f9638313293..1ccc2fda58e56 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Cart/CreateEmptyCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\Cart; +namespace Magento\QuoteGraphQl\Model\Resolver; use Magento\Authorization\Model\UserContextInterface; use Magento\Framework\GraphQl\Config\Element\Field; diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CustomizableOptions.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CustomizableOptions.php new file mode 100644 index 0000000000000..a681b2ca0d004 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CustomizableOptions.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\QuoteGraphQl\Model\Resolver; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Quote\Model\Quote\Item as QuoteItem; +use Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOption; + +/** + * @inheritdoc + */ +class CustomizableOptions implements ResolverInterface +{ + /** + * @var CustomizableOption + */ + private $customizableOption; + + /** + * @param CustomizableOption $customizableOption + */ + public function __construct( + CustomizableOption $customizableOption + ) { + $this->customizableOption = $customizableOption; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (!isset($value['model'])) { + throw new LocalizedException(__('"model" value should be specified')); + } + + /** @var QuoteItem $cartItem */ + $cartItem = $value['model']; + $quoteItemOption = $cartItem->getOptionByCode('option_ids'); + + if (null === $quoteItemOption) { + return []; + } + + $customizableOptionsData = []; + $customizableOptionIds = explode(',', $quoteItemOption->getValue()); + + foreach ($customizableOptionIds as $customizableOptionId) { + $customizableOption = $this->customizableOption->getData( + $cartItem, + (int)$customizableOptionId + ); + $customizableOptionsData[] = $customizableOption; + } + return $customizableOptionsData; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/TextCustomOptionValue.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/TextCustomOptionValue.php deleted file mode 100644 index 78657603ff3e2..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValue/TextCustomOptionValue.php +++ /dev/null @@ -1,61 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue; - -use Magento\Catalog\Model\Product\Option; -use Magento\Catalog\Model\Product\Option\Type\DefaultType; -use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Quote\Model\Quote\Item as QuoteItem; -use Magento\Quote\Model\Quote\Item\Option as SelectedOption; -use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionPriceUnitLabel; - -/** - * Text Custom Option Value Data provider - */ -class TextCustomOptionValue implements CustomOptionValueInterface -{ - /** - * @var CustomOptionPriceUnitLabel - */ - private $customOptionPriceUnitLabel; - - /** - * @param CustomOptionPriceUnitLabel $customOptionPriceUnitLabel - */ - public function __construct( - CustomOptionPriceUnitLabel $customOptionPriceUnitLabel - ) { - $this->customOptionPriceUnitLabel = $customOptionPriceUnitLabel; - } - - /** - * {@inheritdoc} - * - * @throws NoSuchEntityException - */ - public function getData( - QuoteItem $cartItem, - Option $option, - SelectedOption $selectedOption, - DefaultType $optionTypeRenderer - ): array { - $priceValueUnits = $this->customOptionPriceUnitLabel->getData($option->getPriceType()); - - $selectedOptionValueData = [ - 'id' => $selectedOption->getId(), - 'label' => $optionTypeRenderer->getFormattedOptionValue($selectedOption->getValue()), - 'price' => [ - 'type' => strtoupper($option->getPriceType()), - 'units' => $priceValueUnits, - 'value' => $option->getPrice(), - ] - ]; - - return [$selectedOptionValueData]; - } -} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValueComposite.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValueComposite.php deleted file mode 100644 index 4234753d11631..0000000000000 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/DataProvider/CartItem/CustomOptionValueComposite.php +++ /dev/null @@ -1,68 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem; - -use Magento\Catalog\Model\Product\Option; -use Magento\Catalog\Model\Product\Option\Type\DefaultType as DefaultOptionType; -use Magento\Catalog\Model\Product\Option\Type\Select as SelectOptionType; -use Magento\Catalog\Model\Product\Option\Type\Text as TextOptionType; -use Magento\Framework\Exception\LocalizedException; -use Magento\Quote\Model\Quote\Item as QuoteItem; -use Magento\Quote\Model\Quote\Item\Option as SelectedOption; -use Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\CustomOptionValueInterface; - -/** - * Custom Option Value Composite Data provider - */ -class CustomOptionValueComposite -{ - /** - * @var CustomOptionValueInterface[] - */ - private $customOptionValueTypeProviders; - - /** - * @param array $customOptionValueTypeProviders - */ - public function __construct( - array $customOptionValueTypeProviders - ) { - $this->customOptionValueTypeProviders = $customOptionValueTypeProviders; - } - - /** - * Retrieve custom option values data - * - * @param string $optionType - * @param $cartItem - * @param $option - * @param $selectedOption - * @return array - * @throws LocalizedException - */ - public function getData( - string $optionType, - QuoteItem $cartItem, - Option $option, - SelectedOption $selectedOption - ): array { - if (!array_key_exists($optionType, $this->customOptionValueTypeProviders)) { - throw new LocalizedException(__('Option type "%1" is not supported', $optionType)); - } - - /** @var SelectOptionType|TextOptionType|DefaultOptionType $optionTypeRenderer */ - $optionTypeRenderer = $option->groupFactory($optionType) - ->setOption($option) - ->setConfigurationItem($cartItem) - ->setConfigurationItemOption($selectedOption); - - $customOptionValueTypeProvider = $this->customOptionValueTypeProviders[$optionType]; - - return $customOptionValueTypeProvider->getData($cartItem, $option, $selectedOption, $optionTypeRenderer); - } -} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/Coupon/RemoveCouponFromCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php similarity index 98% rename from app/code/Magento/QuoteGraphQl/Model/Resolver/Coupon/RemoveCouponFromCart.php rename to app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php index abb5a0b57519b..40175cc589954 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/Coupon/RemoveCouponFromCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\QuoteGraphQl\Model\Resolver\Coupon; +namespace Magento\QuoteGraphQl\Model\Resolver; use Magento\Framework\Exception\CouldNotDeleteException; use Magento\Framework\Exception\NoSuchEntityException; diff --git a/app/code/Magento/QuoteGraphQl/etc/di.xml b/app/code/Magento/QuoteGraphQl/etc/di.xml index 276049cb61deb..63ad9e193b955 100644 --- a/app/code/Magento/QuoteGraphQl/etc/di.xml +++ b/app/code/Magento/QuoteGraphQl/etc/di.xml @@ -6,18 +6,26 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <type name="Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValueComposite"> + <preference for="Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValueInterface" type="Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Composite" /> + <type name="Magento\QuoteGraphQl\Model\Resolver\CartItemTypeResolver"> <arguments> - <argument name="customOptionValueTypeProviders" xsi:type="array"> - <item name="drop_down" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\DropdownCustomOptionValue</item> - <item name="radio" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\DropdownCustomOptionValue</item> - <item name="checkbox" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\DropdownCustomOptionValue</item> - <item name="field" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> - <item name="area" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> - <item name="date" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> - <item name="time" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> - <item name="date_time" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\TextCustomOptionValue</item> - <item name="multiple" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\DataProvider\CartItem\CustomOptionValue\MultipleCustomOptionValue</item> + <argument name="supportedTypes" xsi:type="array"> + <item name="simple" xsi:type="string">SimpleCartItem</item> + </argument> + </arguments> + </type> + <type name="Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Composite"> + <arguments> + <argument name="customizableOptionValues" xsi:type="array"> + <item name="field" xsi:type="string">Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Text</item> + <item name="date" xsi:type="string">Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Text</item> + <item name="time" xsi:type="string">Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Text</item> + <item name="date_time" xsi:type="string">Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Text</item> + <item name="area" xsi:type="string">Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Text</item> + <item name="drop_down" xsi:type="string">Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Dropdown</item> + <item name="radio" xsi:type="string">Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Dropdown</item> + <item name="checkbox" xsi:type="string">Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Dropdown</item> + <item name="multiple" xsi:type="string">Magento\QuoteGraphQl\Model\CartItem\DataProvider\CustomizableOptionValue\Multiple</item> </argument> </arguments> </type> diff --git a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml b/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml deleted file mode 100644 index 8f29b2559a7a0..0000000000000 --- a/app/code/Magento/QuoteGraphQl/etc/graphql/di.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <type name="Magento\QuoteGraphQl\Model\Resolver\CartItemTypeResolverComposite"> - <arguments> - <argument name="cartItemTypeResolvers" xsi:type="array"> - <item name="cart_item_type_resolver" xsi:type="object">Magento\QuoteGraphQl\Model\Resolver\CartItemTypeResolver</item> - </argument> - </arguments> - </type> - <type name="Magento\QuoteGraphQl\Model\Resolver\CartItemTypeResolver"> - <arguments> - <argument name="cartItemTypes" xsi:type="array"> - <item name="simple" xsi:type="string">SimpleCartItem</item> - </argument> - </arguments> - </type> -</config> diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 7be066e125c11..17527612caa76 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -2,10 +2,10 @@ # See COPYING.txt for license details. type Mutation { - createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") - applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\ApplyCouponToCart") - removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\RemoveCouponFromCart") - addSimpleProductsToCart(input: AddSimpleProductsToCartInput): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\AddSimpleProductsToCart") + createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") + applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart") + removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\RemoveCouponFromCart") + addSimpleProductsToCart(input: AddSimpleProductsToCartInput): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") } input ApplyCouponToCartInput { @@ -18,6 +18,7 @@ type ApplyCouponToCartOutput { } type Cart { + items: [CartItemInterface] applied_coupon: AppliedCoupon } @@ -43,7 +44,7 @@ input AddSimpleProductsToCartInput { } input SimpleProductCartItemInput { - details: CartItemDetailsInput! + data: CartItemInput! customizable_options:[CustomizableOptionInput!] } @@ -57,15 +58,15 @@ type AddSimpleProductsToCartOutput { } type SimpleCartItem implements CartItemInterface @doc(description: "Simple Cart Item") { - customizable_options: [SelectedCustomizableOption] @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\CartItem\\CustomizableOptions") + customizable_options: [SelectedCustomizableOption] @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\CustomizableOptions") } -input CartItemDetailsInput { +input CartItemInput { sku: String! qty: Float! } -interface CartItemInterface @typeResolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\CartItemTypeResolverComposite") { +interface CartItemInterface @typeResolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\CartItemTypeResolver") { id: String! qty: Float! product: ProductInterface! @@ -75,6 +76,7 @@ type SelectedCustomizableOption { id: Int! label: String! type: String! + is_required: Int! values: [SelectedCustomizableOptionValue!]! sort_order: Int! } @@ -82,6 +84,7 @@ type SelectedCustomizableOption { type SelectedCustomizableOptionValue { id: Int label: String! + value: String! price: CartItemSelectedOptionValuePrice! sort_order: Int! } From ada51dc5fe9f3e52f78253874627de21bb345f68 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 26 Sep 2018 19:14:27 +0300 Subject: [PATCH 41/54] GraphQL-141: [Mutations] Cart Operations > Add simple product to Cart --- app/code/Magento/QuoteGraphQl/etc/schema.graphqls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 17527612caa76..f692aa57b2180 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -82,7 +82,7 @@ type SelectedCustomizableOption { } type SelectedCustomizableOptionValue { - id: Int + id: Int! label: String! value: String! price: CartItemSelectedOptionValuePrice! From 484c65c2088cc4bdce6a59c94d13dfb3760f2662 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 26 Sep 2018 19:53:11 +0300 Subject: [PATCH 42/54] GraphQL-141: [Mutations] Cart Operations > Add simple product to Cart -- fix static builds --- .../Magento/CatalogGraphQl/Model/Product/Option/DateType.php | 5 +++++ .../Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php | 2 ++ .../QuoteGraphQl/Model/Cart/AddSimpleProductToCart.php | 4 ++-- .../QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php | 4 ++++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index db03b1712612d..b26d1fae376fa 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -13,13 +13,18 @@ /** * Catalog product option date validator + * * {@inheritdoc} */ class DateType extends ProductDateOptionType { /** * Make valid string as a value of date option type for GraphQl queries + * * {@inheritdoc} + * + * @param array $values All product option values, i.e. array (option_id => mixed, option_id => mixed...) + * @return $this */ public function validateUserValue($values) { diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php index 87be72f1df1f2..daec9411307f8 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php @@ -87,6 +87,8 @@ public function execute(string $cartHash, array $cartItems): Quote } /** + * Get cart + * * @param string $cartHash * @return Quote * @throws GraphQlNoSuchEntityException diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCart.php index 6b13c6c0af72e..aa5b41daebdc3 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/AddSimpleProductToCart.php @@ -92,7 +92,7 @@ private function extractSku(array $cartItemData): string { $sku = $this->arrayManager->get('data/sku', $cartItemData); if (!isset($sku)) { - throw new GraphQlInputException( __('Missing key "sku" in cart item data')); + throw new GraphQlInputException(__('Missing key "sku" in cart item data')); } return (string)$sku; } @@ -108,7 +108,7 @@ private function extractQty(array $cartItemData): float { $qty = $this->arrayManager->get('data/qty', $cartItemData); if (!isset($qty)) { - throw new GraphQlInputException( __('Missing key "qty" in cart item data')); + throw new GraphQlInputException(__('Missing key "qty" in cart item data')); } return (float)$qty; } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php index 88db93c177f7a..a4d0a890eaf37 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php @@ -8,6 +8,7 @@ namespace Magento\QuoteGraphQl\Model\Resolver; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\Resolver\TypeResolverInterface; /** @@ -31,6 +32,9 @@ public function __construct(array $supportedTypes = []) /** * {@inheritdoc} * + * @param array $data + * @return string + * @throws GraphQlInputException * @throws LocalizedException */ public function resolveType(array $data) : string From 6b7300a16b0474ce8e31168d44190b55dcccad11 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 26 Sep 2018 19:54:27 +0300 Subject: [PATCH 43/54] GraphQL-141: [Mutations] Cart Operations > Add simple product to Cart -- fix static builds --- .../Magento/CatalogGraphQl/Model/Product/Option/DateType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index b26d1fae376fa..14b2d17781a57 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -24,7 +24,7 @@ class DateType extends ProductDateOptionType * {@inheritdoc} * * @param array $values All product option values, i.e. array (option_id => mixed, option_id => mixed...) - * @return $this + * @return ProductDateOptionType */ public function validateUserValue($values) { From c21a016ac581fab5404f3ae03f24aca1f8fd8cb9 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 26 Sep 2018 20:03:33 +0300 Subject: [PATCH 44/54] GraphQL-141: [Mutations] Cart Operations > Add simple product to Cart -- fix static tests --- .../CatalogGraphQl/Model/Product/Option/DateType.php | 4 ++-- .../QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index 14b2d17781a57..1506f0f745ed3 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -19,10 +19,10 @@ class DateType extends ProductDateOptionType { /** - * Make valid string as a value of date option type for GraphQl queries - * * {@inheritdoc} * + * Make valid string as a value of date option type for GraphQl queries + * * @param array $values All product option values, i.e. array (option_id => mixed, option_id => mixed...) * @return ProductDateOptionType */ diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php index a4d0a890eaf37..962463860a592 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartItemTypeResolver.php @@ -30,12 +30,7 @@ public function __construct(array $supportedTypes = []) } /** - * {@inheritdoc} - * - * @param array $data - * @return string - * @throws GraphQlInputException - * @throws LocalizedException + * @inheritdoc */ public function resolveType(array $data) : string { From d39230e634e50c248300efce12c794097ba196bd Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Wed, 26 Sep 2018 20:37:20 +0300 Subject: [PATCH 45/54] GraphQL-141: [Mutations] Cart Operations > Add simple product to Cart -- fix static tests --- .../Magento/CatalogGraphQl/Model/Product/Option/DateType.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index 1506f0f745ed3..e0c665fe8035a 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -19,8 +19,6 @@ class DateType extends ProductDateOptionType { /** - * {@inheritdoc} - * * Make valid string as a value of date option type for GraphQl queries * * @param array $values All product option values, i.e. array (option_id => mixed, option_id => mixed...) From accac0b81338f166d86c0cf2ca07ee9e27e60c37 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Thu, 27 Sep 2018 11:21:43 +0200 Subject: [PATCH 46/54] Added methods descriptions to CategoryTree --- .../Model/Resolver/Products/DataProvider/CategoryTree.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php index ab39e33bddb95..e532a30c98772 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php @@ -83,9 +83,12 @@ public function __construct( } /** + * Returns categories tree starting from parent $rootCategoryId + * * @param ResolveInfo $resolveInfo * @param int $rootCategoryId * @return array + * @throws \Exception */ public function getTree(ResolveInfo $resolveInfo, int $rootCategoryId) : array { @@ -107,6 +110,8 @@ public function getTree(ResolveInfo $resolveInfo, int $rootCategoryId) : array } /** + * Iterates through category tree + * * @param \Iterator $iterator * @return array */ @@ -129,6 +134,8 @@ private function processTree(\Iterator $iterator) : array } /** + * Joins EAV attributes recursively + * * @param Collection $collection * @param FieldNode $fieldNode * @return void From 8e9b1eb911753eb8a3fe23adc07cab5578e2b0fb Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza <enarc@atwix.com> Date: Fri, 28 Sep 2018 13:34:58 +0200 Subject: [PATCH 47/54] Reducing the number of dependencies --- .../Model/Resolver/Products/DataProvider/CategoryTree.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php index e532a30c98772..07d8996838e9f 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/DataProvider/CategoryTree.php @@ -88,7 +88,6 @@ public function __construct( * @param ResolveInfo $resolveInfo * @param int $rootCategoryId * @return array - * @throws \Exception */ public function getTree(ResolveInfo $resolveInfo, int $rootCategoryId) : array { From d43164b5edc26e5f092a094a60f2f121b2223587 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 1 Oct 2018 12:48:01 +0300 Subject: [PATCH 48/54] GraphQL-141: [Mutations] Cart Operations > Add simple product to Cart -- fix static tests --- .../Magento/CatalogGraphQl/Model/Product/Option/DateType.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index e0c665fe8035a..76bc0abaeb025 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -12,9 +12,7 @@ use Magento\Framework\Stdlib\DateTime; /** - * Catalog product option date validator - * - * {@inheritdoc} + * @inheritdoc */ class DateType extends ProductDateOptionType { From cb7a755d8851e15c5cfbbefd4950c668b1ea3e4e Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 1 Oct 2018 13:11:01 +0300 Subject: [PATCH 49/54] GraphQL-135: GraphQL API returns rendered content for category --- .../Category/CategoryHtmlAttribute.php | 24 ++++--------------- .../Model/Resolver/Product/Image.php | 3 ++- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php index 55c90425c2f5f..7ccb46c3a293f 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryHtmlAttribute.php @@ -8,9 +8,8 @@ namespace Magento\CatalogGraphQl\Model\Resolver\Category; use Magento\Catalog\Model\Category; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Query\Resolver\Value; -use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Catalog\Helper\Output as OutputHelper; @@ -20,25 +19,17 @@ */ class CategoryHtmlAttribute implements ResolverInterface { - /** - * @var ValueFactory - */ - private $valueFactory; - /** * @var OutputHelper */ private $outputHelper; /** - * @param ValueFactory $valueFactory * @param OutputHelper $outputHelper */ public function __construct( - ValueFactory $valueFactory, OutputHelper $outputHelper ) { - $this->valueFactory = $valueFactory; $this->outputHelper = $outputHelper; } @@ -51,12 +42,9 @@ public function resolve( ResolveInfo $info, array $value = null, array $args = null - ): Value { + ) { if (!isset($value['model'])) { - $result = function () { - return null; - }; - return $this->valueFactory->create($result); + throw new LocalizedException(__('"model" value should be specified')); } /* @var $category Category */ @@ -64,10 +52,6 @@ public function resolve( $fieldName = $field->getName(); $renderedValue = $this->outputHelper->categoryAttribute($category, $category->getData($fieldName), $fieldName); - $result = function () use ($renderedValue) { - return $renderedValue; - }; - - return $this->valueFactory->create($result); + return $renderedValue; } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/Image.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/Image.php index 49617c442eebd..6830aecb78f10 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/Image.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/Image.php @@ -9,6 +9,7 @@ use Magento\Catalog\Model\Product; use Magento\Catalog\Model\Product\ImageFactory; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; @@ -45,7 +46,7 @@ public function resolve( array $args = null ): array { if (!isset($value['model'])) { - throw new \LogicException(__('"model" value should be specified')); + throw new LocalizedException(__('"model" value should be specified')); } /** @var Product $product */ $product = $value['model']; From 9ad5a2c71414132a5754b28f81bb37f897580de7 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 1 Oct 2018 16:02:37 +0300 Subject: [PATCH 50/54] GraphQL-175: Improve graphql product pagination -- Update API-functional tests --- .../GraphQl/Catalog/ProductSearchTest.php | 48 +++++++------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php index 264670f4159ae..459101f432e37 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php @@ -552,7 +552,6 @@ public function testQueryProductsInCurrentPageSortedByPriceASC() * Verify the items in the second page is correct after sorting their name in ASC order * * @magentoApiDataFixture Magento/Catalog/_files/multiple_mixed_products_2.php - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function testFilterProductsInNextPageSortedByNameASC() { @@ -562,44 +561,27 @@ public function testFilterProductsInNextPageSortedByNameASC() products( filter: { - price:{gt: "5", lt: "50"} - or: - { - sku:{eq:"simple1"} - name:{like:"configurable%"} - } + sku:{in:["simple2", "simple1"]} } - pageSize:4 + pageSize:1 currentPage:2 sort: { - name:ASC + name:ASC } ) { items { sku - price { - minimalPrice { - amount { - value - currency - } - } - } name - type_id - ... on PhysicalProductInterface { - weight - } - attribute_set_id - } - total_count - page_info - { + } + total_count + page_info + { page_size - } + current_page + } } } QUERY; @@ -607,13 +589,15 @@ public function testFilterProductsInNextPageSortedByNameASC() * @var ProductRepositoryInterface $productRepository */ $productRepository = ObjectManager::getInstance()->get(ProductRepositoryInterface::class); - $product = $productRepository->get('simple1'); - $filteredProducts = [$product]; + $product = $productRepository->get('simple2'); $response = $this->graphQlQuery($query); - $this->assertEquals(1, $response['products']['total_count']); - $this->assertProductItems($filteredProducts, $response); - $this->assertEquals(4, $response['products']['page_info']['page_size']); + $this->assertEquals(2, $response['products']['total_count']); + $this->assertEquals(['page_size' => 1, 'current_page' => 2], $response['products']['page_info']); + $this->assertEquals( + [['sku' => $product->getSku(), 'name' => $product->getName()]], + $response['products']['items'] + ); } /** From 541098b83940008a817d6fad832e765e7fa32c29 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 1 Oct 2018 17:18:49 +0300 Subject: [PATCH 51/54] GraphQL-175: Improve graphql product pagination -- Remove API-functional tests due to sort order and pagination functionality is covered by testFilterProductsByNameASC --- .../GraphQl/Catalog/ProductSearchTest.php | 77 +------------------ 1 file changed, 2 insertions(+), 75 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php index 459101f432e37..e9d7fb549a6f9 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php @@ -386,79 +386,6 @@ public function testSearchWithFilterWithPageSizeEqualTotalCount() $this->graphQlQuery($query); } - /** - * The query returns a total_count of 2 records; setting the pageSize = 1 and currentPage = 2 - * Expected result is to get the second product on the list on the second page - * - * @magentoApiDataFixture Magento/Catalog/_files/multiple_products.php - */ - public function testSearchWithFilterPageSizeLessThanCurrentPage() - { - - $query - = <<<QUERY -{ - products( - search : "simple" - filter: - { - special_price:{neq:"null"} - price:{lt:"60"} - or: - { - sku:{like:"%simple%"} - name:{like:"%configurable%"} - } - weight:{eq:"1"} - } - pageSize:1 - currentPage:2 - sort: - { - price:DESC - } - ) - { - items - { - sku - price { - minimalPrice { - amount { - value - currency - } - } - } - name - ... on PhysicalProductInterface { - weight - } - type_id - attribute_set_id - } - total_count - page_info - { - page_size - } - } -} -QUERY; - /** - * @var ProductRepositoryInterface $productRepository - */ - $productRepository = ObjectManager::getInstance()->get(ProductRepositoryInterface::class); - // when pageSize = 1 and currentPage = 2, it should have simple2 on first page and simple1 on 2nd page - // since sorting is done on price in the DESC order - $product = $productRepository->get('simple1'); - $filteredProducts = [$product]; - - $response = $this->graphQlQuery($query); - $this->assertEquals(1, $response['products']['total_count']); - $this->assertProductItems($filteredProducts, $response); - } - /** * Requesting for items that match a specific SKU or NAME within a certain price range sorted by Price in ASC order * @@ -549,11 +476,11 @@ public function testQueryProductsInCurrentPageSortedByPriceASC() } /** - * Verify the items in the second page is correct after sorting their name in ASC order + * Verify the items is correct after sorting their name in ASC order * * @magentoApiDataFixture Magento/Catalog/_files/multiple_mixed_products_2.php */ - public function testFilterProductsInNextPageSortedByNameASC() + public function testFilterProductsByNameASC() { $query = <<<QUERY From 2296d844ee0c34172ed07b2d4b981a3267d588af Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Mon, 1 Oct 2018 17:19:49 +0300 Subject: [PATCH 52/54] GraphQL-175: Improve graphql product pagination -- Remove API-functional tests due to sort order and pagination functionality is covered by testQueryProductsSortedByNameASC --- .../testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php index e9d7fb549a6f9..99de6088b19a7 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php @@ -480,7 +480,7 @@ public function testQueryProductsInCurrentPageSortedByPriceASC() * * @magentoApiDataFixture Magento/Catalog/_files/multiple_mixed_products_2.php */ - public function testFilterProductsByNameASC() + public function testQueryProductsSortedByNameASC() { $query = <<<QUERY From c78b9938228c991dcc669ba174f2fced9b7ba66d Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Tue, 2 Oct 2018 13:29:10 +0300 Subject: [PATCH 53/54] GraphQL-141: [Mutations] Cart Operations > Add simple product to Cart -- fix static tests --- .../Magento/CatalogGraphQl/Model/Product/Option/DateType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php index 76bc0abaeb025..e1106a3f696e4 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php +++ b/app/code/Magento/CatalogGraphQl/Model/Product/Option/DateType.php @@ -38,7 +38,7 @@ public function validateUserValue($values) * @return [] * @throws LocalizedException */ - protected function formatValues($values) + private function formatValues($values) { if (isset($values[$this->getOption()->getId()])) { $value = $values[$this->getOption()->getId()]; From 7e3c023a20b499ff671c09acbbc2c5e67b2f9196 Mon Sep 17 00:00:00 2001 From: Valeriy Nayda <vnayda@magento.com> Date: Tue, 2 Oct 2018 13:43:34 +0300 Subject: [PATCH 54/54] GraphQL-141: [Mutations] Cart Operations > Add simple product to Cart -- fix static tests --- app/code/Magento/QuoteGraphQl/composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/composer.json b/app/code/Magento/QuoteGraphQl/composer.json index 9995e292e7842..bed9157c4de59 100644 --- a/app/code/Magento/QuoteGraphQl/composer.json +++ b/app/code/Magento/QuoteGraphQl/composer.json @@ -11,8 +11,7 @@ "magento/module-store": "*" }, "suggest": { - "magento/module-graph-ql": "*", - "magento/module-catalog-graph-ql": "*" + "magento/module-graph-ql": "*" }, "license": [ "OSL-3.0",