diff --git a/app/code/Magento/CatalogRule/Model/Config/CatalogRule.php b/app/code/Magento/CatalogRule/Model/Config/CatalogRule.php
deleted file mode 100644
index 4a87a8a851d7..000000000000
--- a/app/code/Magento/CatalogRule/Model/Config/CatalogRule.php
+++ /dev/null
@@ -1,46 +0,0 @@
-scopeConfig->isSetFlag(self::XML_PATH_SHARE_ALL_CATALOG_RULES);
- }
-
- /**
- * Is 'share_applied_catalog_rules' config enabled
- *
- * @return bool
- */
- public function isShareAppliedCatalogRulesEnabled(): bool
- {
- return $this->scopeConfig->isSetFlag(self::XML_PATH_SHARE_APPLIED_CATALOG_RULES);
- }
-}
diff --git a/app/code/Magento/CatalogRule/Model/ResourceModel/GetAllCatalogRules.php b/app/code/Magento/CatalogRule/Model/ResourceModel/GetAllCatalogRules.php
deleted file mode 100644
index b9f7744f6201..000000000000
--- a/app/code/Magento/CatalogRule/Model/ResourceModel/GetAllCatalogRules.php
+++ /dev/null
@@ -1,56 +0,0 @@
-resourceConnection->getConnection();
- $linkField = $this->metadataPool->getMetadata(RuleInterface::class)->getLinkField();
-
- return $connection->fetchAll(
- $connection->select()
- ->from(
- ['cr' => $this->resourceConnection->getTableName('catalogrule')],
- ['name']
- )
- ->join(
- ['crw' => $this->resourceConnection->getTableName('catalogrule_website')],
- "cr.rule_id = crw.$linkField",
- )
- ->reset('columns')
- ->columns(['name'])
- ->distinct(true)
- ->where('cr.is_active = ?', 1)
- ->where('crw.website_id = ?', $websiteId)
- ) ?? [];
- }
-}
diff --git a/app/code/Magento/CatalogRule/Model/ResourceModel/GetAppliedCatalogRules.php b/app/code/Magento/CatalogRule/Model/ResourceModel/GetAppliedCatalogRules.php
deleted file mode 100644
index aa12a1a66de4..000000000000
--- a/app/code/Magento/CatalogRule/Model/ResourceModel/GetAppliedCatalogRules.php
+++ /dev/null
@@ -1,62 +0,0 @@
-resourceConnection->getConnection();
- $linkField = $this->metadataPool->getMetadata(RuleInterface::class)->getLinkField();
-
- return $connection->fetchAll(
- $connection->select()
- ->from(
- ['cr' => $this->resourceConnection->getTableName('catalogrule')],
- ['name']
- )
- ->join(
- ['crp' => $this->resourceConnection->getTableName('catalogrule_product')],
- 'crp.rule_id = cr.rule_id',
- )
- ->join(
- ['crw' => $this->resourceConnection->getTableName('catalogrule_website')],
- "cr.rule_id = crw.$linkField",
- )
- ->reset('columns')
- ->columns(['name'])
- ->distinct(true)
- ->where('cr.is_active = ?', 1)
- ->where('crp.product_id = ?', $productId)
- ->where('crw.website_id = ?', $websiteId)
- ) ?? [];
- }
-}
diff --git a/app/code/Magento/CatalogRule/etc/adminhtml/system.xml b/app/code/Magento/CatalogRule/etc/adminhtml/system.xml
deleted file mode 100644
index 5a14982e44d8..000000000000
--- a/app/code/Magento/CatalogRule/etc/adminhtml/system.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
- Magento\Config\Model\Config\Source\Yesno
- Option to disable providing Catalog Rules details via GraphQl
-
-
-
- Magento\Config\Model\Config\Source\Yesno
- Option to disable providing Applied Catalog Rules details via GraphQl
-
-
-
-
-
diff --git a/app/code/Magento/CatalogRule/etc/config.xml b/app/code/Magento/CatalogRule/etc/config.xml
deleted file mode 100644
index 0a4b6167ba10..000000000000
--- a/app/code/Magento/CatalogRule/etc/config.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
- 0
- 1
-
-
-
-
diff --git a/app/code/Magento/CatalogRuleGraphQl/Model/Resolver/AllCatalogRules.php b/app/code/Magento/CatalogRuleGraphQl/Model/Resolver/AllCatalogRules.php
deleted file mode 100644
index 2032d0fd1d99..000000000000
--- a/app/code/Magento/CatalogRuleGraphQl/Model/Resolver/AllCatalogRules.php
+++ /dev/null
@@ -1,55 +0,0 @@
-config->isShareAllCatalogRulesEnabled()) {
- throw new GraphQlInputException(__('Sharing catalog rules information is disabled or not configured.'));
- }
-
- return array_map(
- fn ($rule) => ['name' => $rule['name']],
- $this->getAllCatalogRules->execute(
- (int)$context->getExtensionAttributes()->getStore()->getWebsiteId()
- )
- );
- }
-}
diff --git a/app/code/Magento/CatalogRuleGraphQl/Model/Resolver/AppliedCatalogRules.php b/app/code/Magento/CatalogRuleGraphQl/Model/Resolver/AppliedCatalogRules.php
deleted file mode 100644
index aee83683af0e..000000000000
--- a/app/code/Magento/CatalogRuleGraphQl/Model/Resolver/AppliedCatalogRules.php
+++ /dev/null
@@ -1,60 +0,0 @@
-config->isShareAppliedCatalogRulesEnabled()) {
- return null; //Returning `null` to ensure that the entire product response remains intact.
- }
-
- return array_map(
- fn ($rule) => ['name' => $rule['name']],
- $this->getAppliedCatalogRules->execute(
- (int)$value['model']->getId(),
- (int)$context->getExtensionAttributes()->getStore()->getWebsiteId()
- )
- );
- }
-}
diff --git a/app/code/Magento/CatalogRuleGraphQl/etc/graphql/di.xml b/app/code/Magento/CatalogRuleGraphQl/etc/graphql/di.xml
index 1781e71feeee..40290d33789a 100644
--- a/app/code/Magento/CatalogRuleGraphQl/etc/graphql/di.xml
+++ b/app/code/Magento/CatalogRuleGraphQl/etc/graphql/di.xml
@@ -9,12 +9,4 @@
-
-
-
- - catalog/rule/share_all_catalog_rules
- - catalog/rule/share_applied_catalog_rules
-
-
-
diff --git a/app/code/Magento/CatalogRuleGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogRuleGraphQl/etc/schema.graphqls
deleted file mode 100644
index fd445c5e2736..000000000000
--- a/app/code/Magento/CatalogRuleGraphQl/etc/schema.graphqls
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2025 Adobe
-# All Rights Reserved.
-
-type StoreConfig {
- share_all_catalog_rules: Boolean! @doc(description: "Configuration data from catalog/rule/share_all_catalog_rules")
- share_applied_catalog_rules: Boolean! @doc(description: "Configuration data from catalog/rule/share_applied_catalog_rules")
-}
-
-type Query {
- allCatalogRules: [CatalogRule!] @doc(description: "Provides all active catalog rules in the store.") @resolver(class: "Magento\\CatalogRuleGraphQl\\Model\\Resolver\\AllCatalogRules")
-}
-
-interface ProductInterface {
- rules: [CatalogRule!] @doc(description: "Provides applied catalog rules in the current active cart") @resolver(class: "Magento\\CatalogRuleGraphQl\\Model\\Resolver\\AppliedCatalogRules")
-}
-
-type CatalogRule {
- name: String! @doc(description: "Name of the catalog rule")
-}
diff --git a/app/code/Magento/Customer/Model/Config/AccountInformation.php b/app/code/Magento/Customer/Model/Config/AccountInformation.php
index 3120a3123a55..2f6a21f62334 100644
--- a/app/code/Magento/Customer/Model/Config/AccountInformation.php
+++ b/app/code/Magento/Customer/Model/Config/AccountInformation.php
@@ -11,7 +11,6 @@
class AccountInformation
{
- private const XML_PATH_SHARE_ALL_CUSTOMER_GROUPS = 'customer/account_information/graphql_share_all_customer_groups';
private const XML_PATH_SHARE_CUSTOMER_GROUP = 'customer/account_information/graphql_share_customer_group';
/**
@@ -24,16 +23,6 @@ public function __construct(
) {
}
- /**
- * Is 'graphql_share_all_customer_groups' config enabled
- *
- * @return bool
- */
- public function isShareAllCustomerGroupsEnabled(): bool
- {
- return $this->scopeConfig->isSetFlag(self::XML_PATH_SHARE_ALL_CUSTOMER_GROUPS);
- }
-
/**
* Is 'graphql_share_customer_group' config enabled
*
diff --git a/app/code/Magento/Customer/etc/adminhtml/system.xml b/app/code/Magento/Customer/etc/adminhtml/system.xml
index c260cb6572ac..df9d7fbc4918 100644
--- a/app/code/Magento/Customer/etc/adminhtml/system.xml
+++ b/app/code/Magento/Customer/etc/adminhtml/system.xml
@@ -197,15 +197,10 @@
Magento\Config\Model\Config\Source\Yesno
-
-
- Magento\Config\Model\Config\Source\Yesno
- Option to disable providing all customer group details via GraphQl
-
-
+
Magento\Config\Model\Config\Source\Yesno
- Option to disable providing customer group details via GraphQl for a customer
+ Option to disable providing customer group details via GraphQl
diff --git a/app/code/Magento/Customer/etc/config.xml b/app/code/Magento/Customer/etc/config.xml
index ca7d4f1c3cea..8b385133298b 100644
--- a/app/code/Magento/Customer/etc/config.xml
+++ b/app/code/Magento/Customer/etc/config.xml
@@ -33,8 +33,7 @@
customer_account_information_change_email_template
customer_account_information_change_email_and_password_template
0
- 0
- 0
+ 1
support
diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/AllCustomerGroups.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/AllCustomerGroups.php
deleted file mode 100644
index 2d44c2071666..000000000000
--- a/app/code/Magento/CustomerGraphQl/Model/Resolver/AllCustomerGroups.php
+++ /dev/null
@@ -1,71 +0,0 @@
-config->isShareAllCustomerGroupsEnabled()) {
- throw new GraphQlInputException(__('Sharing customer group information is disabled or not configured.'));
- }
-
- try {
- $customerGroups = $this->groupRepository->getList(
- $this->searchCriteriaBuilder->create()
- )->getItems();
- } catch (Exception $e) {
- throw new GraphQlInputException(__('Unable to retrieve customer groups.'));
- }
-
- return array_map(
- fn ($group) => ['name' => $group->getCode()],
- array_filter(
- $customerGroups,
- fn ($group) => !in_array(
- (int)$context->getExtensionAttributes()->getStore()->getWebsiteId(),
- $group->getExtensionAttributes()->getExcludeWebsiteIds() ?? []
- )
- )
- );
- }
-}
diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/CustomerGroup.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/CustomerGroup.php
index 007de18ba9b1..e1ddd04e2044 100644
--- a/app/code/Magento/CustomerGraphQl/Model/Resolver/CustomerGroup.php
+++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/CustomerGroup.php
@@ -7,28 +7,24 @@
namespace Magento\CustomerGraphQl\Model\Resolver;
-use Magento\Customer\Api\Data\CustomerInterface;
use Magento\Customer\Model\Config\AccountInformation;
-use Magento\CustomerGraphQl\Model\GetCustomerGroupName;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
+use Magento\Framework\GraphQl\Query\Uid;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
-/**
- * Provides data for customer.group.name
- */
class CustomerGroup implements ResolverInterface
{
/**
* CustomerGroup Constructor
*
* @param AccountInformation $config
- * @param GetCustomerGroupName $getCustomerGroup
+ * @param Uid $idEncoder
*/
public function __construct(
- private readonly AccountInformation $config,
- private readonly GetCustomerGroupName $getCustomerGroup
+ private readonly AccountInformation $config,
+ private readonly Uid $idEncoder
) {
}
@@ -42,14 +38,16 @@ public function resolve(
?array $value = null,
?array $args = null
): ?array {
- if (!($value['model'] ?? null) instanceof CustomerInterface) {
+ if (!isset($value['model'])) {
throw new LocalizedException(__('"model" value should be specified'));
}
- return !$this->config->isShareCustomerGroupEnabled() ? null :
- $this->getCustomerGroup->execute(
- (int) $value['model']->getGroupId(),
- (int) $context->getExtensionAttributes()->getStore()->getWebsiteId()
- );
+ if (!$this->config->isShareCustomerGroupEnabled()) {
+ return null;
+ }
+
+ return [
+ 'uid' => $this->idEncoder->encode((string)$value['model']->getGroupId())
+ ];
}
}
diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/GetCustomerGroup.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/Visitor.php
similarity index 58%
rename from app/code/Magento/CustomerGraphQl/Model/Resolver/GetCustomerGroup.php
rename to app/code/Magento/CustomerGraphQl/Model/Resolver/Visitor.php
index f84bbb1abe5a..236fa4677c4d 100644
--- a/app/code/Magento/CustomerGraphQl/Model/Resolver/GetCustomerGroup.php
+++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/Visitor.php
@@ -7,30 +7,27 @@
namespace Magento\CustomerGraphQl\Model\Resolver;
-use Magento\CatalogCustomerGraphQl\Model\Resolver\Customer\GetCustomerGroup as CustomerGroup;
+use Magento\CatalogCustomerGraphQl\Model\Resolver\Customer\GetCustomerGroup;
use Magento\Customer\Model\Config\AccountInformation;
-use Magento\CustomerGraphQl\Model\GetCustomerGroupName;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
+use Magento\Framework\GraphQl\Query\Uid;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
-/**
- * Provides data for customerGroup.name
- */
-class GetCustomerGroup implements ResolverInterface
+class Visitor implements ResolverInterface
{
/**
- * GetCustomerGroup Constructor
+ * Visitor Constructor
*
* @param AccountInformation $config
- * @param CustomerGroup $customerGroup
- * @param GetCustomerGroupName $getCustomerGroup
+ * @param GetCustomerGroup $getCustomerGroup
+ * @param Uid $idEncoder
*/
public function __construct(
- private readonly AccountInformation $config,
- private readonly CustomerGroup $customerGroup,
- private readonly GetCustomerGroupName $getCustomerGroup
+ private readonly AccountInformation $config,
+ private readonly GetCustomerGroup $getCustomerGroup,
+ private readonly Uid $idEncoder
) {
}
@@ -44,13 +41,13 @@ public function resolve(
?array $value = null,
?array $args = null
): array {
+
if (!$this->config->isShareCustomerGroupEnabled()) {
throw new GraphQlInputException(__('Sharing customer group information is disabled or not configured.'));
}
- return $this->getCustomerGroup->execute(
- $this->customerGroup->execute($context->getUserId()),
- (int)$context->getExtensionAttributes()->getStore()->getWebsiteId()
- );
+ return [
+ 'uid' => $this->idEncoder->encode((string)$this->getCustomerGroup->execute($context->getUserId()))
+ ];
}
}
diff --git a/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml b/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml
index d8db12736124..779ccc4b91fd 100644
--- a/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml
+++ b/app/code/Magento/CustomerGraphQl/etc/graphql/di.xml
@@ -38,7 +38,6 @@
- customer/password/minimum_password_length
- customer/password/autocomplete_on_storefront
- customer/create_account/confirm
- - customer/account_information/graphql_share_all_customer_groups
- customer/account_information/graphql_share_customer_group
diff --git a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls
index abb8c968b6d1..667eecbfe9d3 100644
--- a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls
+++ b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls
@@ -6,8 +6,7 @@ type StoreConfig {
minimum_password_length : String @doc(description: "The minimum number of characters required for a valid password.")
autocomplete_on_storefront : Boolean @doc(description: "Indicates whether to enable autocomplete on login and forgot password forms.")
create_account_confirmation: Boolean @doc(description: "Indicates if the new accounts need confirmation.")
- graphql_share_all_customer_groups: Boolean! @doc(description: "Configuration data from customer/account_information/graphql_share_all_customer_groups")
- graphql_share_customer_group: Boolean! @doc(description: "Configuration data from customer/account_information/graphql_share_customer_group")
+ graphql_share_customer_group: Boolean @doc(description: "Configuration data from customer/account_information/graphql_share_customer_group")
}
type Query {
@@ -15,8 +14,7 @@ type Query {
isEmailAvailable (
email: String! @doc(description: "The email address to check.")
): IsEmailAvailableOutput @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\IsEmailAvailable") @doc(description: "Check whether the specified email has already been used to create a customer account.")
- allCustomerGroups: [CustomerGroup!] @doc(description: "An array containing a list of all Customer Groups available.") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\AllCustomerGroups")
- customerGroup: CustomerGroup! @doc(description: "Provides name of the Customer Group assigned to the Customer or Guest.") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\GetCustomerGroup")
+ customerGroup: CustomerGroupStorefront! @doc(description: "Provides Customer Group assigned to the Customer or Guest.") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\Visitor")
}
type Mutation {
@@ -157,7 +155,7 @@ type Customer @doc(description: "Defines the customer name, addresses, and other
gender: Int @doc(description: "The customer's gender (Male - 1, Female - 2).")
custom_attributes(attributeCodes: [ID!]): [AttributeValueInterface] @doc(description: "Customer's custom attributes.") @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\CustomAttributeFilter")
confirmation_status: ConfirmationStatusEnum! @doc(description: "The customer's confirmation status.") @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\ConfirmationStatus")
- group: CustomerGroup @doc(description: "Name of the customer group assigned to the customer") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\CustomerGroup")
+ group: CustomerGroupStorefront @doc(description: "Customer group assigned to the customer") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\CustomerGroup")
}
type CustomerAddresses {
@@ -497,6 +495,6 @@ enum ConfirmationStatusEnum @doc(description: "List of account confirmation stat
ACCOUNT_CONFIRMATION_NOT_REQUIRED @doc(description: "Account confirmation not required")
}
-type CustomerGroup @doc(description: "Data of customer group.") {
- name: String @doc(description: "The name of customer group.")
+type CustomerGroupStorefront @doc(description: "Data of customer group.") {
+ uid: ID! @doc(description: "The unique ID for a `CustomerGroup` object.")
}
diff --git a/app/code/Magento/Quote/etc/di.xml b/app/code/Magento/Quote/etc/di.xml
index e53ce4c7c0ec..ee17a1b8dd5b 100644
--- a/app/code/Magento/Quote/etc/di.xml
+++ b/app/code/Magento/Quote/etc/di.xml
@@ -182,6 +182,7 @@
- INSUFFICIENT_STOCK
- INSUFFICIENT_STOCK
- INSUFFICIENT_STOCK
+ - REQUIRED_PARAMETER_MISSING
diff --git a/app/code/Magento/QuoteGraphQl/Model/CartItem/ProductStock.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/ProductStock.php
index bd3eba6cdda2..4854675629d9 100644
--- a/app/code/Magento/QuoteGraphQl/Model/CartItem/ProductStock.php
+++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/ProductStock.php
@@ -9,6 +9,7 @@
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\CatalogInventory\Api\Data\StockStatusInterface;
use Magento\CatalogInventory\Api\StockRegistryInterface;
use Magento\CatalogInventory\Model\Configuration;
use Magento\CatalogInventory\Model\StockState;
@@ -18,7 +19,7 @@
use Magento\Store\Model\ScopeInterface;
/**
- * Product Stock class to check availability of product
+ * Product Stock class to check the availability of product
*/
class ProductStock
{
@@ -33,7 +34,7 @@ class ProductStock
private const PRODUCT_TYPE_CONFIGURABLE = "configurable";
/**
- * ProductStock constructor
+ * ProductStock Constructor
*
* @param ProductRepositoryInterface $productRepositoryInterface
* @param StockState $stockState
@@ -57,8 +58,8 @@ public function __construct(
*/
public function isProductAvailable(Item $cartItem): bool
{
- $requestedQty = $cartItem->getQtyToAdd() ?? $cartItem->getQty();
- $previousQty = $cartItem->getPreviousQty() ?? 0;
+ $requestedQty = (float)($cartItem->getQtyToAdd() ?? $cartItem->getQty());
+ $previousQty = (int)$cartItem->getPreviousQty() ?? 0;
if ($cartItem->getProductType() === self::PRODUCT_TYPE_BUNDLE) {
return $this->isStockAvailableBundle($cartItem, $previousQty, $requestedQty);
@@ -98,7 +99,7 @@ public function isStockAvailableBundle(Item $cartItem, int $previousQty, $reques
$qtyOptions = $cartItem->getQtyOptions();
$totalRequestedQty = $previousQty + $requestedQty;
foreach ($qtyOptions as $qtyOption) {
- $requiredItemQty = $qtyOption->getValue();
+ $requiredItemQty = (float)$qtyOption->getValue();
if ($totalRequestedQty) {
$requiredItemQty = $requiredItemQty * $totalRequestedQty;
}
@@ -176,16 +177,16 @@ private function isStockQtyAvailable(
float $requiredQuantity,
float $prevQty
): bool {
- $scopeId = $cartItem->getStore()->getId();
- $stockStatus = $this->stockState->checkQuoteItemQty(
+ $this->stockState->checkQuoteItemQty(
$product->getId(),
$itemQty,
$requiredQuantity,
$prevQty,
- $scopeId
+ $cartItem->getStore()->getId()
);
- return ((bool) $stockStatus->getHasError()) === false;
+ return ($this->getProductStockStatus($product)->getStockStatus() &&
+ $this->getAvailableStock($product) >= $itemQty);
}
/**
@@ -196,7 +197,7 @@ private function isStockQtyAvailable(
*/
private function getAvailableStock(ProductInterface $product): float
{
- return $this->stockState->getStockQty($product->getId());
+ return (float) $this->getProductStockStatus($product)->getQty();
}
/**
@@ -293,4 +294,18 @@ public function getSaleableQty(ProductInterface $product, ?float $thresholdQty):
return ($stockQty >= 0 && $stockLeft <= $thresholdQty) ? $stockQty : 0.0;
}
+
+ /**
+ * Returns the stock status of a product
+ *
+ * @param ProductInterface $product
+ * @return StockStatusInterface
+ */
+ private function getProductStockStatus(ProductInterface $product): StockStatusInterface
+ {
+ return $this->stockRegistry->getStockStatus(
+ $product->getId(),
+ $product->getStore()->getWebsiteId()
+ );
+ }
}
diff --git a/app/code/Magento/QuoteGraphQl/Test/Unit/Model/CartItem/ProductStockTest.php b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/CartItem/ProductStockTest.php
index 2b6737943f4e..6b7bc3335b83 100644
--- a/app/code/Magento/QuoteGraphQl/Test/Unit/Model/CartItem/ProductStockTest.php
+++ b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/CartItem/ProductStockTest.php
@@ -70,6 +70,16 @@ class ProductStockTest extends TestCase
*/
private $stockStatusMock;
+ /**
+ * @var ProductInterface|MockObject
+ */
+ private $optionProductMock;
+
+ /**
+ * @var Option|MockObject
+ */
+ private $qtyOptionMock;
+
/**
* Set up mocks and initialize the ProductStock class
*/
@@ -87,15 +97,25 @@ protected function setUp(): void
);
$this->stockStatusMock = $this->getMockBuilder(StockStatusInterface::class)
->disableOriginalConstructor()
- ->addMethods(['getHasError'])
+ ->onlyMethods(['getQty', 'getStockStatus'])
->getMockForAbstractClass();
$this->cartItemMock = $this->getMockBuilder(Item::class)
->addMethods(['getQtyToAdd', 'getPreviousQty'])
->onlyMethods(['getStore', 'getProductType', 'getProduct', 'getChildren', 'getQtyOptions'])
->disableOriginalConstructor()
->getMock();
- $this->productMock = $this->createMock(ProductInterface::class);
+ $this->productMock = $this->getMockBuilder(ProductInterface::class)
+ ->onlyMethods(['getId'])
+ ->addMethods(['getStore'])
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->optionProductMock = $this->getMockBuilder(ProductInterface::class)
+ ->onlyMethods(['getId'])
+ ->addMethods(['getStore'])
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
$this->storeMock = $this->createMock(StoreInterface::class);
+ $this->qtyOptionMock = $this->createMock(Option::class);
}
/**
@@ -121,16 +141,25 @@ public function testIsProductAvailableForSimpleProductWithStock(): void
$this->storeMock->expects($this->once())
->method('getId')
->willReturn(1);
- $this->productMock->expects($this->once())
+ $this->productMock->expects($this->exactly(3))
->method('getId')
->willReturn(123);
+ $this->productMock->expects($this->exactly(2))
+ ->method('getStore')
+ ->willReturn($this->storeMock);
$this->stockStatusMock->expects($this->once())
- ->method('getHasError')
- ->willReturn(false);
+ ->method('getStockStatus')
+ ->willReturn(true);
+ $this->stockStatusMock->expects($this->once())
+ ->method('getQty')
+ ->willReturn(10);
$this->stockStateMock->expects($this->once())
->method('checkQuoteItemQty')
->with(123, 2.0, 3.0, 1.0, 1)
->willReturn($this->stockStatusMock);
+ $this->stockRegistryMock->expects($this->exactly(2))
+ ->method('getStockStatus')
+ ->willReturn($this->stockStatusMock);
$this->cartItemMock->expects($this->never())->method('getChildren');
$result = $this->productStock->isProductAvailable($this->cartItemMock);
$this->assertTrue($result);
@@ -159,16 +188,22 @@ public function testIsProductAvailableForSimpleProductWithoutStock()
$this->storeMock->expects($this->once())
->method('getId')
->willReturn(1);
- $this->productMock->expects($this->once())
+ $this->productMock->expects($this->exactly(2))
->method('getId')
->willReturn(123);
+ $this->productMock->expects($this->once())
+ ->method('getStore')
+ ->willReturn($this->storeMock);
$this->stockStateMock->expects($this->once())
->method('checkQuoteItemQty')
->with(123, 2.0, 3.0, 1.0, 1)
->willReturn($this->stockStatusMock);
$this->stockStatusMock->expects($this->once())
- ->method('getHasError')
- ->willReturn(true);
+ ->method('getStockStatus')
+ ->willReturn(false);
+ $this->stockRegistryMock->expects($this->once())
+ ->method('getStockStatus')
+ ->willReturn($this->stockStatusMock);
$this->cartItemMock->expects($this->never())->method('getChildren');
$result = $this->productStock->isProductAvailable($this->cartItemMock);
$this->assertFalse($result);
@@ -179,33 +214,40 @@ public function testIsProductAvailableForSimpleProductWithoutStock()
*/
public function testIsStockAvailableBundleStockAvailable()
{
- $qtyOptionMock = $this->createMock(Option::class);
- $qtyOptionMock->expects($this->once())
+ $this->qtyOptionMock->expects($this->once())
->method('getValue')
- ->willReturn(2.0);
- $optionProductMock = $this->createMock(ProductInterface::class);
- $qtyOptionMock->expects($this->once())
+ ->willReturn(1.0);
+ $this->qtyOptionMock->expects($this->once())
->method('getProduct')
- ->willReturn($optionProductMock);
+ ->willReturn($this->optionProductMock);
$this->cartItemMock->expects($this->once())
->method('getQtyOptions')
- ->willReturn([$qtyOptionMock]);
+ ->willReturn([$this->qtyOptionMock]);
$this->cartItemMock->expects($this->once())
->method('getStore')
->willReturn($this->storeMock);
$this->storeMock->expects($this->once())
->method('getId')
->willReturn(1);
- $optionProductMock->expects($this->once())
+ $this->optionProductMock->expects($this->exactly(3))
->method('getId')
->willReturn(789);
- $this->stockStatusMock->expects($this->once())
- ->method('getHasError')
- ->willReturn(false);
+ $this->optionProductMock->expects($this->exactly(2))
+ ->method('getStore')
+ ->willReturn($this->storeMock);
$this->stockStateMock->expects($this->once())
->method('checkQuoteItemQty')
- ->with(789, 2.0, 6.0, 1.0, 1)
+ ->with(789, 2.0, 3.0, 1.0, 1)
->willReturn($this->stockStatusMock);
+ $this->stockStatusMock->expects($this->once())
+ ->method('getStockStatus')
+ ->willReturn(true);
+ $this->stockRegistryMock->expects($this->exactly(2))
+ ->method('getStockStatus')
+ ->willReturn($this->stockStatusMock);
+ $this->stockStatusMock->expects($this->once())
+ ->method('getQty')
+ ->willReturn(10);
$result = $this->productStock->isStockAvailableBundle($this->cartItemMock, 1, 2.0);
$this->assertTrue($result);
}
@@ -215,33 +257,37 @@ public function testIsStockAvailableBundleStockAvailable()
*/
public function testIsStockAvailableBundleStockNotAvailable()
{
- $qtyOptionMock = $this->createMock(\Magento\Quote\Model\Quote\Item\Option::class);
- $qtyOptionMock->expects($this->once())
+ $this->qtyOptionMock->expects($this->once())
->method('getValue')
->willReturn(2.0);
- $optionProductMock = $this->createMock(ProductInterface::class);
- $qtyOptionMock->expects($this->once())
+ $this->qtyOptionMock->expects($this->once())
->method('getProduct')
- ->willReturn($optionProductMock);
+ ->willReturn($this->optionProductMock);
$this->cartItemMock->expects($this->once())
->method('getQtyOptions')
- ->willReturn([$qtyOptionMock]);
+ ->willReturn([$this->qtyOptionMock]);
$this->cartItemMock->expects($this->once())
->method('getStore')
->willReturn($this->storeMock);
$this->storeMock->expects($this->once())
->method('getId')
->willReturn(1);
- $this->stockStatusMock->expects($this->once())
- ->method('getHasError')
- ->willReturn(true);
- $optionProductMock->expects($this->once())
+ $this->optionProductMock->expects($this->exactly(2))
->method('getId')
->willReturn(789);
+ $this->optionProductMock->expects($this->once())
+ ->method('getStore')
+ ->willReturn($this->storeMock);
$this->stockStateMock->expects($this->once())
->method('checkQuoteItemQty')
->with(789, 2.0, 6.0, 1.0, 1)
->willReturn($this->stockStatusMock);
+ $this->stockStatusMock->expects($this->once())
+ ->method('getStockStatus')
+ ->willReturn(false);
+ $this->stockRegistryMock->expects($this->once())
+ ->method('getStockStatus')
+ ->willReturn($this->stockStatusMock);
$result = $this->productStock->isStockAvailableBundle($this->cartItemMock, 1, 2.0);
$this->assertFalse($result);
}
diff --git a/app/code/Magento/SalesGraphQl/Model/Resolver/OrderTotal.php b/app/code/Magento/SalesGraphQl/Model/Resolver/OrderTotal.php
index ca6ddf804f0d..6c281e50d96a 100644
--- a/app/code/Magento/SalesGraphQl/Model/Resolver/OrderTotal.php
+++ b/app/code/Magento/SalesGraphQl/Model/Resolver/OrderTotal.php
@@ -55,6 +55,7 @@ public function resolve(
'currency' => $order->getBaseCurrencyCode()
],
'grand_total' => ['value' => $order->getGrandTotal(), 'currency' => $currency],
+ 'grand_total_excl_tax' => ['value' => $this->getGrandTotalExclTax($order), 'currency' => $currency],
'subtotal' => ['value' => $order->getSubtotal(), 'currency' => $currency],
'subtotal_incl_tax' => ['value' => $order->getSubtotalInclTax(), 'currency' => $currency],
'subtotal_excl_tax' => ['value' => $order->getSubtotal(), 'currency' => $currency],
@@ -217,4 +218,17 @@ private function getShippingDiscountDetails(OrderInterface $order): array
}
return $shippingDiscounts;
}
+
+ /**
+ * Get grand total excluding tax
+ *
+ * @param OrderInterface $order
+ * @return float
+ */
+ private function getGrandTotalExclTax(OrderInterface $order): float
+ {
+ return (float) ($order->getSubtotal()
+ + $order->getShippingAmount()
+ - abs((float)$order->getDiscountAmount()));
+ }
}
diff --git a/app/code/Magento/SalesGraphQl/Model/Resolver/ProductResolver.php b/app/code/Magento/SalesGraphQl/Model/Resolver/ProductResolver.php
index 665d4d917cb4..1d10e3a6756e 100644
--- a/app/code/Magento/SalesGraphQl/Model/Resolver/ProductResolver.php
+++ b/app/code/Magento/SalesGraphQl/Model/Resolver/ProductResolver.php
@@ -7,12 +7,12 @@
namespace Magento\SalesGraphQl\Model\Resolver;
-use Magento\Catalog\Model\Product;
use Magento\CatalogGraphQl\Model\ProductDataProvider;
+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\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
+use Magento\Sales\Api\Data\OrderItemInterface;
/**
* Fetches the Product data according to the GraphQL schema
@@ -39,14 +39,10 @@ public function resolve(
?array $value = null,
?array $args = null
) {
- if (!isset($value['associatedProduct'])) {
- throw new GraphQlNoSuchEntityException(
- __("This product is currently out of stock or not available.")
- );
+ if (!(($value['model'] ?? null) instanceof OrderItemInterface)) {
+ throw new LocalizedException(__('"model" value should be specified'));
}
- /** @var Product $product */
- $product = $value['associatedProduct'];
- return $this->productDataProvider->getProductDataById((int)$product->getId());
+ return $this->productDataProvider->getProductDataById((int)$value['model']->getProductId());
}
}
diff --git a/app/code/Magento/SalesGraphQl/etc/schema.graphqls b/app/code/Magento/SalesGraphQl/etc/schema.graphqls
index ec33e4986d59..58c62b2814c0 100644
--- a/app/code/Magento/SalesGraphQl/etc/schema.graphqls
+++ b/app/code/Magento/SalesGraphQl/etc/schema.graphqls
@@ -3,7 +3,7 @@
type Query {
customerOrders: CustomerOrders @resolver(class: "Magento\\SalesGraphQl\\Model\\Resolver\\Orders") @deprecated(reason: "Use the `customer` query instead.") @cache(cacheable: false)
- guestOrder(input: OrderInformationInput!): CustomerOrder! @doc(description:"Retrieve guest order details based on number, email and billing last name.") @resolver(class: "Magento\\SalesGraphQl\\Model\\Resolver\\GuestOrder") @cache(cacheable: false)
+ guestOrder(input: GuestOrderInformationInput!): CustomerOrder! @doc(description:"Retrieve guest order details based on number, email and billing last name.") @resolver(class: "Magento\\SalesGraphQl\\Model\\Resolver\\GuestOrder") @cache(cacheable: false)
guestOrderByToken(input: OrderTokenInput!): CustomerOrder! @doc(description:"Retrieve guest order details based on token.") @resolver(class: "Magento\\SalesGraphQl\\Model\\Resolver\\GuestOrder") @cache(cacheable: false)
}
@@ -170,6 +170,7 @@ type OrderTotal @doc(description: "Contains details about the sales total amount
shipping_handling: ShippingHandling @doc(description: "Details about the shipping and handling costs for the order.")
subtotal_incl_tax: Money! @doc(description: "The subtotal of the order, including taxes.")
subtotal_excl_tax: Money! @doc(description: "The subtotal of the order, excluding taxes.")
+ grand_total_excl_tax: Money! @doc(description: "The grand total of the order, excluding taxes.")
}
type Invoice @doc(description: "Contains invoice details.") {
@@ -309,7 +310,14 @@ input OrderTokenInput @doc(description: "Input to retrieve an order based on tok
token: String! @doc(description: "Order token.")
}
-input OrderInformationInput @doc(description: "Input to retrieve an order based on details.") {
+input OrderInformationInput @deprecated(reason: "Use `GuestOrderInformationInput` instead of OrderInformationInput.") @doc(description: "Input to retrieve an order based on details.") {
+ number: String! @doc(description: "Order number.")
+ email: String! @doc(description: "Order billing address email.")
+ lastname: String! @doc(description: "Order billing address lastname.")
+ postcode: String @deprecated(reason: "Use lastname instead of postcode") @doc(description: "Order billing address postcode")
+}
+
+input GuestOrderInformationInput @doc(description: "Input to retrieve an order based on details.") {
number: String! @doc(description: "Order number.")
email: String! @doc(description: "Order billing address email.")
lastname: String! @doc(description: "Order billing address lastname.")
diff --git a/app/code/Magento/SalesRule/Model/Config.php b/app/code/Magento/SalesRule/Model/Config.php
new file mode 100644
index 000000000000..59994bdf0574
--- /dev/null
+++ b/app/code/Magento/SalesRule/Model/Config.php
@@ -0,0 +1,36 @@
+scopeConfig->isSetFlag(self::SHARE_APPLIED_CART_RULES, ScopeInterface::SCOPE_STORE);
+ }
+}
diff --git a/app/code/Magento/SalesRule/Model/Config/Coupon.php b/app/code/Magento/SalesRule/Model/Config/Coupon.php
deleted file mode 100644
index c3f0b9dbf843..000000000000
--- a/app/code/Magento/SalesRule/Model/Config/Coupon.php
+++ /dev/null
@@ -1,53 +0,0 @@
-scopeConfig->isSetFlag(
- self::XML_PATH_PROMO_GRAPHQL_SHARE_ALL_RULES,
- ScopeInterface::SCOPE_STORE
- );
- }
-
- /**
- * Get share currently applied sales rule flag value
- *
- * @return bool
- */
- public function isShareAppliedSalesRulesEnabled(): bool
- {
- return $this->scopeConfig->isSetFlag(
- self::XML_PATH_PROMO_GRAPHQL_SHARE_APPLIED_RULES,
- ScopeInterface::SCOPE_STORE
- );
- }
-}
diff --git a/app/code/Magento/SalesRule/Model/ResourceModel/GetAllCartRules.php b/app/code/Magento/SalesRule/Model/ResourceModel/GetAllCartRules.php
deleted file mode 100644
index 36472aebc01b..000000000000
--- a/app/code/Magento/SalesRule/Model/ResourceModel/GetAllCartRules.php
+++ /dev/null
@@ -1,59 +0,0 @@
-resourceConnection->getConnection();
- $linkField = $this->metadataPool->getMetadata(RuleInterface::class)->getLinkField();
-
- return $connection->fetchAll(
- $connection->select()
- ->from(['sr' => $this->resourceConnection->getTableName('salesrule')])
- ->reset('columns')
- ->columns(['name'])
- ->join(
- ['srw' => $this->resourceConnection->getTableName('salesrule_website')],
- "sr.rule_id = srw.$linkField",
- []
- )
- ->where('sr.is_active = ?', 1)
- ->where(
- 'srw.website_id = ?',
- (int)$context->getExtensionAttributes()->getStore()->getWebsiteId()
- )
- ) ?? [];
- }
-}
diff --git a/app/code/Magento/SalesRule/Model/ResourceModel/GetAppliedCartRules.php b/app/code/Magento/SalesRule/Model/ResourceModel/GetAppliedCartRules.php
deleted file mode 100644
index ac28257b1400..000000000000
--- a/app/code/Magento/SalesRule/Model/ResourceModel/GetAppliedCartRules.php
+++ /dev/null
@@ -1,61 +0,0 @@
-resourceConnection->getConnection();
- $linkField = $this->metadataPool->getMetadata(RuleInterface::class)->getLinkField();
-
- return $connection->fetchAll(
- $connection->select()
- ->from(['sr' => $this->resourceConnection->getTableName('salesrule')])
- ->reset('columns')
- ->columns(['name'])
- ->join(
- ['srw' => $this->resourceConnection->getTableName('salesrule_website')],
- "sr.rule_id = srw.$linkField",
- []
- )
- ->where('sr.is_active = ?', 1)
- ->where('sr.rule_id IN (?)', explode(',', $ruleIds))
- ->where(
- 'srw.website_id = ?',
- (int)$context->getExtensionAttributes()->getStore()->getWebsiteId()
- )
- ) ?? [];
- }
-}
diff --git a/app/code/Magento/SalesRule/etc/adminhtml/system.xml b/app/code/Magento/SalesRule/etc/adminhtml/system.xml
index 7dc6e1f9278d..cdfa56565158 100755
--- a/app/code/Magento/SalesRule/etc/adminhtml/system.xml
+++ b/app/code/Magento/SalesRule/etc/adminhtml/system.xml
@@ -40,17 +40,12 @@
validate-digits
-
+
-
-
+
+
Magento\Config\Model\Config\Source\Yesno
- Configuration to allow to disable providing all cart rules via GraphQL
-
-
-
- Magento\Config\Model\Config\Source\Yesno
- Configuration to allow to disable currently applied sales rules for cart via GraphQL
+ Allow to retrieve applied cart rules via GraphQL API
diff --git a/app/code/Magento/SalesRule/etc/config.xml b/app/code/Magento/SalesRule/etc/config.xml
index aa1c453ef398..c3593558e3b8 100755
--- a/app/code/Magento/SalesRule/etc/config.xml
+++ b/app/code/Magento/SalesRule/etc/config.xml
@@ -14,8 +14,7 @@
1
- 0
- 1
+ 1
diff --git a/app/code/Magento/SalesRuleGraphQl/Model/Resolver/AllCartRules.php b/app/code/Magento/SalesRuleGraphQl/Model/Resolver/AllCartRules.php
deleted file mode 100644
index 6ae43d35c556..000000000000
--- a/app/code/Magento/SalesRuleGraphQl/Model/Resolver/AllCartRules.php
+++ /dev/null
@@ -1,50 +0,0 @@
-config->isShareAllSalesRulesEnabled()) {
- throw new GraphQlInputException(__('Sharing Cart Rules information is disabled or not configured.'));
- }
-
- return array_map(
- static fn ($rule) => ['name' => $rule['name']],
- $this->getAllCartRules->execute($context)
- );
- }
-}
diff --git a/app/code/Magento/SalesRuleGraphQl/Model/Resolver/AppliedCartRules.php b/app/code/Magento/SalesRuleGraphQl/Model/Resolver/AppliedCartRules.php
index 106e77f4cf3f..eca77dd20998 100644
--- a/app/code/Magento/SalesRuleGraphQl/Model/Resolver/AppliedCartRules.php
+++ b/app/code/Magento/SalesRuleGraphQl/Model/Resolver/AppliedCartRules.php
@@ -10,22 +10,24 @@
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
+use Magento\Framework\GraphQl\Query\Uid;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
-use Magento\Quote\Api\Data\CartInterface;
-use Magento\SalesRule\Model\Config\Coupon;
-use Magento\SalesRule\Model\ResourceModel\GetAppliedCartRules;
+use Magento\SalesRule\Model\Config;
+/**
+ * Resolver class for providing All applied cart rules
+ */
class AppliedCartRules implements ResolverInterface
{
/**
* AppliedCartRules Constructor
*
- * @param Coupon $config
- * @param GetAppliedCartRules $getAppliedCartRules
+ * @param Config $config
+ * @param Uid $idEncoder
*/
public function __construct(
- private readonly Coupon $config,
- private readonly GetAppliedCartRules $getAppliedCartRules
+ private readonly Config $config,
+ private readonly Uid $idEncoder
) {
}
@@ -38,20 +40,20 @@ public function resolve(
ResolveInfo $info,
?array $value = null,
?array $args = null
- ) {
- if (!(($value['model'] ?? null) instanceof CartInterface)) {
+ ): ?array {
+ if (empty($value['model'])) {
throw new LocalizedException(__('"model" value should be specified'));
}
- if (!$this->config->isShareAppliedSalesRulesEnabled()) {
- return null; //returning null so that whole cart response is not broken
+ if (!$this->config->isShareAppliedCartRulesEnabled()) {
+ return null;
}
$ruleIds = $value['model']->getAppliedRuleIds();
return $ruleIds ? array_map(
- fn ($rule) => ['name' => $rule['name']],
- $this->getAppliedCartRules->execute($ruleIds, $context)
+ fn ($rule) => ['uid' => $this->idEncoder->encode($rule)],
+ explode(",", $ruleIds)
) : [];
}
}
diff --git a/app/code/Magento/SalesRuleGraphQl/composer.json b/app/code/Magento/SalesRuleGraphQl/composer.json
index 8f5ba0cb0743..f566b5f84e2f 100644
--- a/app/code/Magento/SalesRuleGraphQl/composer.json
+++ b/app/code/Magento/SalesRuleGraphQl/composer.json
@@ -7,8 +7,7 @@
"require": {
"php": "~8.2.0||~8.3.0||~8.4.0",
"magento/framework": "*",
- "magento/module-sales-rule": "*",
- "magento/module-quote": "*"
+ "magento/module-sales-rule": "*"
},
"type": "magento2-module",
"license": [
diff --git a/app/code/Magento/SalesRuleGraphQl/etc/graphql/di.xml b/app/code/Magento/SalesRuleGraphQl/etc/graphql/di.xml
index 066640e3e463..e55b13dec937 100644
--- a/app/code/Magento/SalesRuleGraphQl/etc/graphql/di.xml
+++ b/app/code/Magento/SalesRuleGraphQl/etc/graphql/di.xml
@@ -9,8 +9,7 @@
- - promo/graphql/share_all_sales_rule
- - promo/graphql/share_applied_sales_rule
+ - promo/graphql/share_applied_cart_rule
diff --git a/app/code/Magento/SalesRuleGraphQl/etc/schema.graphqls b/app/code/Magento/SalesRuleGraphQl/etc/schema.graphqls
index 6bac9c7767c1..ea83f4aad0c4 100644
--- a/app/code/Magento/SalesRuleGraphQl/etc/schema.graphqls
+++ b/app/code/Magento/SalesRuleGraphQl/etc/schema.graphqls
@@ -1,24 +1,18 @@
# Copyright 2024 Adobe
# All Rights Reserved.
-
type Discount {
coupon: AppliedCoupon @resolver(class: "Magento\\SalesRuleGraphQl\\Model\\Resolver\\Coupon") @doc(description:"The coupon related to the discount.")
}
type StoreConfig {
- share_all_sales_rule: Boolean! @doc(description: "Configuration data from promo/graphql/share_all_sales_rule")
- share_applied_sales_rule: Boolean! @doc(description: "Configuration data from promo/graphql/share_applied_sales_rule")
-}
-
-type Query {
- allCartRules: [CartRule!] @doc(description: "Provides all active cart rules in the store.") @resolver(class: "Magento\\SalesRuleGraphQl\\Model\\Resolver\\AllCartRules")
+ share_applied_cart_rule: Boolean @doc(description: "Configuration data from promo/graphql/share_applied_cart_rule")
}
type Cart {
- rules: [CartRule!] @doc(description: "Provides applied cart rules in the current active cart") @resolver(class: "Magento\\SalesRuleGraphQl\\Model\\Resolver\\AppliedCartRules")
+ rules: [CartRuleStorefront!] @doc(description: "Provides applied cart rules in the current active cart") @resolver(class: "Magento\\SalesRuleGraphQl\\Model\\Resolver\\AppliedCartRules")
}
-type CartRule {
- name: String! @doc(description: "Name of the cart price rule")
+type CartRuleStorefront {
+ uid: ID! @doc(description: "The unique ID for a `CartRule` object.")
}
diff --git a/app/code/Magento/Tax/Test/Fixture/TaxRate.php b/app/code/Magento/Tax/Test/Fixture/TaxRate.php
index f79e2ba2a28a..d086abe80c06 100644
--- a/app/code/Magento/Tax/Test/Fixture/TaxRate.php
+++ b/app/code/Magento/Tax/Test/Fixture/TaxRate.php
@@ -1,7 +1,7 @@
null,
'zip_from' => null,
'zip_to' => null,
- 'titles' => [],
+ 'titles' => []
];
/**
- * @var ServiceFactory
- */
- private ServiceFactory $serviceFactory;
-
- /**
+ * TaxRate Constructor
+ *
* @param ServiceFactory $serviceFactory
+ * @param DataMerger $dataMerger
*/
- public function __construct(ServiceFactory $serviceFactory)
- {
- $this->serviceFactory = $serviceFactory;
+ public function __construct(
+ private readonly ServiceFactory $serviceFactory,
+ private readonly DataMerger $dataMerger
+ ) {
}
/**
@@ -46,10 +46,13 @@ public function __construct(ServiceFactory $serviceFactory)
public function apply(array $data = []): ?DataObject
{
$service = $this->serviceFactory->create(TaxRateRepositoryInterface::class, 'save');
+ $data = $this->dataMerger->merge(
+ self::DEFAULT_DATA,
+ $data
+ );
+ $data['code'] = str_replace('%uniqid%', uniqid(), $data['code']);
- return $service->execute([
- 'taxRate' => array_merge(self::DEFAULT_DATA, $data),
- ]);
+ return $service->execute(['taxRate' => $data]);
}
/**
diff --git a/app/code/Magento/WishlistGraphQl/etc/schema.graphqls b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls
index 8ff70de7d6ba..dcf49a1679d3 100644
--- a/app/code/Magento/WishlistGraphQl/etc/schema.graphqls
+++ b/app/code/Magento/WishlistGraphQl/etc/schema.graphqls
@@ -82,6 +82,7 @@ type WishlistCartUserInputError @doc(description: "Contains details about errors
enum WishlistCartUserInputErrorType @doc(description: "A list of possible error types.") {
PRODUCT_NOT_FOUND
+ REQUIRED_PARAMETER_MISSING
NOT_SALABLE
INSUFFICIENT_STOCK
UNDEFINED
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogRule/CatalogRuleStoreConfigTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogRule/CatalogRuleStoreConfigTest.php
deleted file mode 100644
index 5d9c0dd427c0..000000000000
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogRule/CatalogRuleStoreConfigTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-assertEquals(
- [
- 'storeConfig' => [
- 'share_all_catalog_rules' => 1,
- 'share_applied_catalog_rules' => 1
- ]
- ],
- $this->graphQlQuery($this->getStoreConfigQuery())
- );
- }
-
- /**
- * Generates storeConfig query with newly added configurations
- *
- * @return string
- */
- private function getStoreConfigQuery(): string
- {
- return <<fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
- }
-
- /**
- * Test to retrieve all catalog rules when catalog/rule/share_all_catalog_rules is enabled.
- *
- * @throws Exception
- */
- #[
- Config('catalog/rule/share_all_catalog_rules', 1),
- DataFixture(CatalogRuleFixture::class, as: 'catalogrule1'),
- DataFixture(CatalogRuleFixture::class, as: 'catalogrule2'),
- DataFixture(CatalogRuleFixture::class, as: 'catalogrule3'),
- DataFixture(CatalogRuleFixture::class, ['is_active' => 0], as: 'catalogrule4')
- ]
- public function testGetAllCatalogRules(): void
- {
- $this->assertEmpty(
- array_diff(
- array_column($this->graphQlQuery($this->getAllCatalogRulesQuery()), 'name'),
- array_column($this->fetchAllCatalogRules(), 'name')
- )
- );
- }
-
- /**
- * Test to retrieve catalog rules when catalog/rule/share_all_catalog_rules is enabled.
- *
- * @throws Exception
- */
- #[
- Config('catalog/rule/share_all_catalog_rules', 1)
- ]
- public function testGetAllCatalogRulesWithZeroResult(): void
- {
- $response = $this->graphQlQuery($this->getAllCatalogRulesQuery());
- $this->assertEmpty($response['allCatalogRules']);
- }
-
- /**
- * Test to retrieve all catalog rules when catalog/rule/share_all_catalog_rules is disabled.
- *
- * @throws Exception
- */
- #[
- Config('catalog/rule/share_all_catalog_rules', 0)
- ]
- public function testGetAllCatalogRulesWhenConfigDisabled(): void
- {
- $this->expectException(ResponseContainsErrorsException::class);
- $this->expectExceptionMessage(
- "Sharing catalog rules information is disabled or not configured."
- );
- $this->graphQlQuery($this->getAllCatalogRulesQuery());
- }
-
- /**
- * Get all catalog rules
- *
- * @return array[]
- */
- private function fetchAllCatalogRules(): array
- {
- return [
- 'allCatalogRules' => [
- ['name' => $this->fixtures->get('catalogrule1')->getName()],
- ['name' => $this->fixtures->get('catalogrule2')->getName()],
- ['name' => $this->fixtures->get('catalogrule3')->getName()]
- ]
- ];
- }
-
- /**
- * Get all catalog rules query
- *
- * @return string
- */
- private function getAllCatalogRulesQuery(): string
- {
- return <<fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
- }
-
- /**
- * Test to retrieve applied catalog rules when catalog/rule/share_applied_catalog_rules is enabled.
- *
- * @throws Exception
- */
- #[
- Config('catalog/rule/share_applied_catalog_rules', 1),
- DataFixture(ProductFixture::class, as: 'product'),
- DataFixture(CatalogRuleFixture::class, as: 'catalogrule1')
- ]
- public function testGetAppliedCatalogRules(): void
- {
- $response = $this->graphQlQuery($this->getAppliedCatalogRulesQuery());
- $this->assertContains(
- $this->fixtures->get('catalogrule1')->getName(),
- array_column($response['products']['items'][0]['rules'], 'name')
- );
- }
-
- /**
- * Test to retrieve applied catalog rules when catalog/rule/share_applied_catalog_rules is enabled.
- *
- * @throws Exception
- */
- #[
- Config('catalog/rule/share_applied_catalog_rules', 1),
- DataFixture(ProductFixture::class, as: 'product')
- ]
- public function testGetAppliedCatalogRulesWithZeroResult(): void
- {
- $response = $this->graphQlQuery($this->getAppliedCatalogRulesQuery());
- $this->assertEmpty($response['products']['items'][0]['rules']);
- }
-
- /**
- * Test to retrieve applied catalog rules when catalog/rule/share_applied_catalog_rules is disabled.
- *
- * @throws Exception
- */
- #[
- Config('catalog/rule/share_applied_catalog_rules', 0),
- DataFixture(ProductFixture::class, as: 'product')
- ]
- public function testGetAppliedCatalogRulesWhenConfigDisabled(): void
- {
- self::assertEquals(
- [
- 'products' => [
- 'items' => [
- '0' => [
- 'rules' => null
- ]
- ]
- ]
- ],
- $this->graphQlQuery($this->getAppliedCatalogRulesQuery())
- );
- }
-
- /**
- * Get applied catalog rules query
- *
- * @return string
- */
- private function getAppliedCatalogRulesQuery(): string
- {
- return <<fixtures->get('product')->getSku()}" } }){
- items {
- rules {
- name
- }
- }
- }
- }
- QUERY;
- }
-}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CustomerStoreConfigTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CustomerStoreConfigTest.php
index 4f6afcc90f25..cc6c98df5084 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CustomerStoreConfigTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CustomerStoreConfigTest.php
@@ -7,7 +7,6 @@
namespace Magento\GraphQl\Customer;
-use Exception;
use Magento\TestFramework\Fixture\Config;
use Magento\TestFramework\TestCase\GraphQlAbstract;
@@ -16,20 +15,30 @@
*/
class CustomerStoreConfigTest extends GraphQlAbstract
{
- /**
- * @throws Exception
- */
#[
- Config('customer/account_information/graphql_share_all_customer_groups', 1),
- Config('customer/account_information/graphql_share_customer_group', 1)
+ Config('customer/account_information/graphql_share_customer_group', true)
]
public function testCustomerGroupsGraphQlStoreConfig(): void
{
$this->assertEquals(
[
'storeConfig' => [
- 'graphql_share_all_customer_groups' => 1,
- 'graphql_share_customer_group' => 1
+ 'graphql_share_customer_group' => true
+ ]
+ ],
+ $this->graphQlQuery($this->getStoreConfigQuery())
+ );
+ }
+
+ #[
+ Config('customer/account_information/graphql_share_customer_group', false)
+ ]
+ public function testCustomerGroupsGraphQlStoreConfigDisabled(): void
+ {
+ $this->assertEquals(
+ [
+ 'storeConfig' => [
+ 'graphql_share_customer_group' => false
]
],
$this->graphQlQuery($this->getStoreConfigQuery())
@@ -46,7 +55,6 @@ private function getStoreConfigQuery(): string
return << $this->fetchAllCustomerGroups()
- ],
- $this->graphQlQuery($this->getAllCustomerGroupsQuery())
- );
- }
-
- /**
- * Test to retrieve all customer groups when graphql_share_all_customer_groups is disabled.
- *
- * @throws Exception
- */
- #[
- Config('customer/account_information/graphql_share_all_customer_groups', 0)
- ]
- public function testGetAllCustomerGroupsWhenConfigDisabled(): void
- {
- $this->expectException(ResponseContainsErrorsException::class);
- $this->expectExceptionMessage(
- "Sharing customer group information is disabled or not configured."
- );
- $this->graphQlQuery($this->getAllCustomerGroupsQuery());
- }
-
- /**
- * Fetch all customer groups
- *
- * @return array|array[]
- * @throws LocalizedException
- */
- public function fetchAllCustomerGroups(): array
- {
- $groupRepository = Bootstrap::getObjectManager()->get(GroupRepositoryInterface::class);
- $searchCriteria = Bootstrap::getObjectManager()->get(SearchCriteriaBuilder::class)->create();
-
- $customerGroups = $groupRepository->getList($searchCriteria)->getItems();
-
- return array_map(
- static fn ($group) => ['name' => $group->getCode()],
- $customerGroups
- );
- }
-
- /**
- * Get all customer groups query
- *
- * @return string
- */
- private function getAllCustomerGroupsQuery(): string
- {
- return <<customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class);
$this->fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
- $this->groupRepository = Bootstrap::getObjectManager()->get(GroupRepositoryInterface::class);
+ $this->idEncoder = Bootstrap::getObjectManager()->get(Uid::class);
}
/**
* Test to retrieve customer group when graphql_share_customer_group is enabled.
@@ -61,7 +51,7 @@ protected function setUp(): void
* @throws Exception
*/
#[
- Config('customer/account_information/graphql_share_customer_group', 1),
+ Config('customer/account_information/graphql_share_customer_group', true),
DataFixture(CustomerFixture::class, as: 'customer')
]
public function testGetCustomerGroupForLoggedInCustomer(): void
@@ -72,7 +62,7 @@ public function testGetCustomerGroupForLoggedInCustomer(): void
[
'customer' => [
'group' => [
- 'name' => $this->groupRepository->getById($customer->getGroupId())->getCode()
+ 'uid' => $this->idEncoder->encode($customer->getGroupId())
]
]
],
@@ -86,12 +76,12 @@ public function testGetCustomerGroupForLoggedInCustomer(): void
}
/**
- * Test to retrieve customer group when graphql_share_customer_group is disabled.
+ * Test to retrieve customer group when graphql_share_customer_group is disabled.
*
* @throws Exception
*/
#[
- Config('customer/account_information/graphql_share_customer_group', 0),
+ Config('customer/account_information/graphql_share_customer_group', false),
DataFixture(CustomerFixture::class, as: 'customer')
]
public function testGetCustomerGroupForLoggedInCustomerWhenConfigDisabled(): void
@@ -111,11 +101,8 @@ public function testGetCustomerGroupForLoggedInCustomerWhenConfigDisabled(): voi
);
}
- /**
- * @throws Exception
- */
#[
- Config('customer/account_information/graphql_share_customer_group', 1),
+ Config('customer/account_information/graphql_share_customer_group', true),
DataFixture(CustomerFixture::class, as: 'customer')
]
public function testGetCustomerGroup(): void
@@ -125,7 +112,7 @@ public function testGetCustomerGroup(): void
self::assertEquals(
[
'customerGroup' => [
- 'name' => $this->groupRepository->getById($customer->getGroupId())->getCode()
+ 'uid' => $this->idEncoder->encode($customer->getGroupId())
]
],
$this->graphQlQuery(
@@ -141,53 +128,7 @@ public function testGetCustomerGroup(): void
* @throws Exception
*/
#[
- Config('customer/account_information/graphql_share_customer_group', 1),
- DataFixture(CustomerGroupFixture::class, as: 'group')
- ]
- public function testGetCustomerGroupWhenItsExcluded(): void
- {
- $customer = Bootstrap::getObjectManager()->get(Customer::class);
- $customerGroup = Bootstrap::getObjectManager()->get(Group::class);
-
- // Load Customer Group
- $customerGroup->load($this->fixtures->get('group')->getCode(), 'customer_group_code');
-
- // Ensure extension attributes exist
- $extensionAttributes = $customerGroup->getExtensionAttributes();
- if (!$extensionAttributes) {
- $extensionAttributes = Bootstrap::getObjectManager()->get(GroupExtension::class);
- $customerGroup->setExtensionAttributes($extensionAttributes);
- }
-
- // Set excluded website ID
- $extensionAttributes->setExcludeWebsiteIds([1]); // Website ID 1 is excluded
- $customerGroup->setExtensionAttributes($extensionAttributes);
- $customerGroup->save();
-
- //set customer
- $customer->setWebsiteId(1);
- $customer->setGroupId($customerGroup->getId());
- $customer->setEmail('excluded_customer@example.com');
- $customer->setFirstname('Excluded');
- $customer->setLastname('User');
- $customer->setPassword('password');
- $customer->save();
-
- $response = $this->graphQlQuery(
- $this->getCustomerGroupQuery(),
- [],
- '',
- $this->getCustomerAuthHeaders('excluded_customer@example.com')
- );
-
- self::assertNotEquals($customer->getCustomerGroup(), $response['customerGroup']['name']);
- }
-
- /**
- * @throws Exception
- */
- #[
- Config('customer/account_information/graphql_share_customer_group', 0),
+ Config('customer/account_information/graphql_share_customer_group', false),
DataFixture(CustomerFixture::class, as: 'customer')
]
public function testGetCustomerGroupWhenConfigDisabled(): void
@@ -208,14 +149,14 @@ public function testGetCustomerGroupWhenConfigDisabled(): void
* @throws Exception
*/
#[
- Config('customer/account_information/graphql_share_customer_group', 1)
+ Config('customer/account_information/graphql_share_customer_group', true)
]
public function testGetCustomerGroupForGuest(): void
{
self::assertEquals(
[
'customerGroup' => [
- 'name' => self::GUEST_CUSTOMER_GROUP
+ 'uid' => $this->idEncoder->encode('0')
]
],
$this->graphQlQuery($this->getCustomerGroupQuery())
@@ -226,7 +167,7 @@ public function testGetCustomerGroupForGuest(): void
* @throws Exception
*/
#[
- Config('customer/account_information/graphql_share_customer_group', 0)
+ Config('customer/account_information/graphql_share_customer_group', false)
]
public function testGetCustomerGroupForGuestWhenConfigDisabled(): void
{
@@ -247,7 +188,7 @@ private function getCustomerGroupQuery(): string
return <<fixtures = DataFixtureStorageManager::getStorage();
+ $this->customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class);
+ }
+
+ #[
+ DataFixture(AttributeFixture::class, [
+ 'frontend_input' => 'select',
+ 'options' => ['40', '42'],
+ 'is_configurable' => true,
+ 'is_global' => true
+ ], as: 'attribute'),
+ DataFixture(
+ ProductFixture::class,
+ [
+ 'price' => 100,
+ 'custom_attributes' => [
+ ['attribute_code' => '$attribute.attribute_code$', 'value' => '40']
+ ]
+ ],
+ as: 'product1'
+ ),
+ DataFixture(
+ ProductFixture::class,
+ [
+ 'price' => 100,
+ 'custom_attributes' => [
+ ['attribute_code' => '$attribute.attribute_code$', 'value' => '42']
+ ]
+ ],
+ as: 'product2'
+ ),
+ DataFixture(
+ ConfigurableProductFixture::class,
+ [
+ '_options' => ['$attribute$'],
+ '_links' => ['$product1$', '$product2$'],
+ 'custom_attributes' => [
+ ['attribute_code' => '$attribute.attribute_code$', 'value' => '40']
+ ]
+ ],
+ 'configurable_product'
+ ),
+ DataFixture(Customer::class, as: 'customer'),
+ DataFixture(CustomerCart::class, ['customer_id' => '$customer.id$'], as: 'customerCart'),
+ DataFixture(QuoteIdMask::class, ['cart_id' => '$customerCart.id$'], 'quoteIdMask'),
+ ]
+ public function testAddToCartForConfigurableProductWithoutOptions(): void
+ {
+ $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
+
+ $this->assertEquals(
+ [
+ 'addProductsToCart' => [
+ 'cart' => [
+ 'id' => $maskedQuoteId,
+ 'itemsV2' => [
+ 'items' => []
+ ]
+ ],
+ 'user_errors' => [
+ [
+ 'code' => 'REQUIRED_PARAMETER_MISSING',
+ 'message' => 'You need to choose options for your item.'
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlMutation(
+ $this->getAddToCartMutation(
+ $maskedQuoteId,
+ $this->fixtures->get('configurable_product')->getSku(),
+ 2
+ ),
+ [],
+ "",
+ $this->getCustomerAuthHeaders($this->fixtures->get('customer')->getEmail())
+ )
+ );
+ }
+
+ /**
+ * Get addToCart mutation for a configurable product without specifying options
+ *
+ * @param string $cartId
+ * @param string $sku
+ * @param int $quantity
+ * @return string
+ */
+ private function getAddToCartMutation(string $cartId, string $sku, int $quantity): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($email, 'password');
+ return ['Authorization' => 'Bearer ' . $customerToken];
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/CartItemAvailabilityTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/CartItemAvailabilityTest.php
new file mode 100644
index 000000000000..16f841b53106
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/CartItemAvailabilityTest.php
@@ -0,0 +1,119 @@
+fixtures = DataFixtureStorageManager::getStorage();
+ }
+
+ #[
+ Config('cataloginventory/options/not_available_message', 1),
+ DbIsolation(false),
+ AppIsolation(true),
+ DataFixture(SourceFixture::class, as: 'source2'),
+ DataFixture(StockFixture::class, as: 'stock2'),
+ DataFixture(
+ StockSourceLinksFixture::class,
+ [
+ ['stock_id' => '$stock2.stock_id$', 'source_code' => '$source2.source_code$'],
+ ]
+ ),
+ DataFixture(
+ StockSalesChannelsFixture::class,
+ ['stock_id' => '$stock2.stock_id$', 'sales_channels' => ['base']]
+ ),
+
+ DataFixture(ProductFixture::class, ['sku' => 'simple1'], 'p1'),
+ DataFixture(
+ SourceItemsFixture::class,
+ [
+ ['sku' => '$p1.sku$', 'source_code' => 'default', 'quantity' => 0],
+ ['sku' => '$p1.sku$', 'source_code' => '$source2.source_code$', 'quantity' => 100],
+ ]
+ ),
+ DataFixture(GuestCartFixture::class, as: 'cart'),
+ DataFixture(AddProductToCart::class, ['cart_id' => '$cart.id$', 'product_id' => '$p1.id$']),
+ DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask')
+ ]
+ public function testCartItemAvailabilityWithMSI(): void
+ {
+ $this->assertEquals(
+ [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'not_available_message' => null,
+ 'is_available' => true,
+ 'product' => [
+ 'quantity' => 100,
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ $this->graphQlQuery($this->getCartQuery(
+ $this->fixtures->get('quoteIdMask')->getMaskedId()
+ ))
+ );
+ }
+
+ /**
+ * Return cart query with is_available & not_available_message fields
+ *
+ * @param string $cartId
+ * @return string
+ */
+ private function getCartQuery(string $cartId): string
+ {
+ return <<fixtures = DataFixtureStorageManager::getStorage();
+ }
+
+ #[
+ ConfigFixture('cataloginventory/options/enable_inventory_check', false, "store", "default"),
+ ConfigFixture('cataloginventory/options/not_available_message', true, "store", "default"),
+ DataFixture(ProductFixture::class, as: 'product'),
+ DataFixture(GuestCart::class, as: 'cart'),
+ DataFixture(QuoteIdMask::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
+ DataFixture(
+ AddProductToCartFixture::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$product.id$',
+ 'qty' => 1
+ ]
+ )
+ ]
+ public function testNotAvailableMessageWithoutInventoryCheck(): void
+ {
+ $this->assertCartResponse();
+ }
+
+ #[
+ ConfigFixture('cataloginventory/options/enable_inventory_check', true, "store", "default"),
+ ConfigFixture('cataloginventory/options/not_available_message', true, "store", "default"),
+ DataFixture(ProductFixture::class, as: 'product'),
+ DataFixture(GuestCart::class, as: 'cart'),
+ DataFixture(QuoteIdMask::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
+ DataFixture(
+ AddProductToCartFixture::class,
+ [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$product.id$',
+ 'qty' => 1
+ ]
+ )
+ ]
+ public function testNotAvailableMessageWithInventoryCheck(): void
+ {
+ $this->assertCartResponse();
+ }
+
+ private function assertCartResponse(): void
+ {
+ $this->assertEquals(
+ [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'not_available_message' => null,
+ ]
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlQuery(
+ $this->getCartQuery($this->fixtures->get('quoteIdMask')->getMaskedId())
+ )
+ );
+ }
+
+ /**
+ * Get cart query with not available message
+ *
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getCartQuery(string $maskedQuoteId): string
+ {
+ return <<fixtures = DataFixtureStorageManager::getStorage();
$this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class);
+ $this->stockRegistry = Bootstrap::getObjectManager()->get(StockRegistryInterface::class);
}
#[
Config('cataloginventory/options/not_available_message', 0),
- DataFixture(ProductFixture::class, ['price' => 100.00], as: 'product'),
+ DataFixture(ProductFixture::class, as: 'product'),
DataFixture(GuestCartFixture::class, as: 'cart'),
DataFixture(AddProductToCart::class, ['cart_id' => '$cart.id$', 'product_id' => '$product.id$', 'qty' => 100]),
- DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 90], 'prodStock')
+ DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask')
]
public function testStockStatusUnavailableSimpleProduct(): void
{
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->getQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
- $responseDataObject = new DataObject($response);
+ $this->updateProductStock();
- self::assertFalse(
- $responseDataObject->getData('cart/itemsV2/items/0/is_available')
- );
- self::assertEquals(
- 'Not enough items for sale',
- $responseDataObject->getData('cart/itemsV2/items/0/not_available_message')
+ $this->assertEquals(
+ [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'is_available' => false,
+ 'not_available_message' => 'Not enough items for sale',
+ 'product' => [
+ 'sku' => $this->fixtures->get('product')->getSku(),
+ 'only_x_left_in_stock' => null,
+ ],
+ 'quantity' => 100,
+ ]
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlQuery(
+ $this->getCartQuery($this->fixtures->get('quoteIdMask')->getMaskedId())
+ )
);
}
@@ -94,65 +108,100 @@ public function testStockStatusUnavailableSimpleProduct(): void
]
public function testStockStatusAvailableSimpleProduct(): void
{
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->getQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
- $responseDataObject = new DataObject($response);
-
- self::assertTrue(
- $responseDataObject->getData('cart/itemsV2/items/0/is_available')
- );
- self::assertNull(
- $responseDataObject->getData('cart/itemsV2/items/0/not_available_message')
+ $this->assertEquals(
+ [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'is_available' => true,
+ 'not_available_message' => null,
+ 'product' => [
+ 'sku' => $this->fixtures->get('product')->getSku(),
+ 'only_x_left_in_stock' => 100,
+ ],
+ 'quantity' => 100
+ ]
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlQuery(
+ $this->getCartQuery($this->fixtures->get('quoteIdMask')->getMaskedId())
+ )
);
}
#[
Config('cataloginventory/options/not_available_message', 1),
Config('cataloginventory/options/stock_threshold_qty', 100),
- DataFixture(ProductFixture::class, ['price' => 100.00], as: 'product'),
+ DataFixture(ProductFixture::class, as: 'product'),
DataFixture(GuestCartFixture::class, as: 'cart'),
- DataFixture(AddProductToCart::class, ['cart_id' => '$cart.id$', 'product_id' => '$product.id$', 'qty' => 20]),
- DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 10], 'prodStock')
+ DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask')
]
public function testStockStatusUnavailableSimpleProductOption1(): void
{
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->getQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
- $responseDataObject = new DataObject($response);
+ $this->updateProductStock(10, true);
- self::assertFalse(
- $responseDataObject->getData('cart/itemsV2/items/0/is_available')
- );
- self::assertEquals(10, $responseDataObject->getData('cart/itemsV2/items/0/product/only_x_left_in_stock'));
- self::assertEquals(
- 'Only 10 of 20 available',
- $responseDataObject->getData('cart/itemsV2/items/0/not_available_message')
+ $this->assertEquals(
+ [
+ 'addProductsToCart' => [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [],
+ ],
+ ],
+ 'user_errors' => [
+ [
+ 'code' => 'INSUFFICIENT_STOCK',
+ 'message' => 'Only 10 of 20 available',
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlMutation(
+ $this->addToCartMutation(
+ $this->fixtures->get('quoteIdMask')->getMaskedId(),
+ $this->fixtures->get('product')->getSku(),
+ 20
+ )
+ )
);
}
#[
Config('cataloginventory/options/not_available_message', 1),
Config('cataloginventory/options/stock_threshold_qty', 100),
- DataFixture(ProductFixture::class, ['sku' => self::SKU, 'price' => 100.00], as: 'product'),
+ DataFixture(ProductFixture::class, as: 'product'),
DataFixture(GuestCartFixture::class, as: 'cart'),
DataFixture(AddProductToCart::class, ['cart_id' => '$cart.id$', 'product_id' => '$product.id$', 'qty' => 99]),
DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask')
]
public function testStockStatusAddSimpleProduct(): void
{
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->mutationAddSimpleProduct($maskedQuoteId, self::SKU, 1);
- $response = $this->graphQlMutation($query);
- $responseDataObject = new DataObject($response);
-
- self::assertTrue(
- $responseDataObject->getData('addProductsToCart/cart/itemsV2/items/0/is_available')
- );
- self::assertNull(
- $responseDataObject->getData('addProductsToCart/cart/itemsV2/items/0/not_available_message')
+ $this->assertEquals(
+ [
+ 'addProductsToCart' => [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'not_available_message' => null,
+ 'quantity' => 100,
+ 'is_available' => true,
+ ]
+ ]
+ ]
+ ],
+ 'user_errors' => [],
+ ],
+ ],
+ $this->graphQlMutation(
+ $this->addToCartMutation(
+ $this->fixtures->get('quoteIdMask')->getMaskedId(),
+ $this->fixtures->get('product')->getSku()
+ )
+ )
);
}
@@ -183,79 +232,40 @@ public function testStockStatusAddSimpleProduct(): void
'qty' => 100
],
),
- DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 90], 'prodStock')
+ DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask')
]
public function testStockStatusUnavailableBundleProduct(): void
{
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->getQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
- $responseDataObject = new DataObject($response);
+ $this->updateProductStock();
- self::assertFalse(
- $responseDataObject->getData('cart/itemsV2/items/0/is_available')
- );
- self::assertEquals(
- 'Not enough items for sale',
- $responseDataObject->getData('cart/itemsV2/items/0/not_available_message')
- );
- }
-
- #[
- Config('cataloginventory/options/not_available_message', 1),
- Config('cataloginventory/options/stock_threshold_qty', 100),
- DataFixture(ProductFixture::class, ['price' => 100.00], as: 'product'),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 100], 'prodStock'),
- DataFixture(
- BundleSelectionFixture::class,
+ $this->assertEquals(
[
- 'sku' => '$product.sku$', 'price' => 100, 'price_type' => 0
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'is_available' => null,
+ 'not_available_message' => 'Not enough items for sale',
+ 'quantity' => 100,
+ 'product' => [
+ 'sku' => $this->fixtures->get('bundleProduct')->getSku(),
+ 'only_x_left_in_stock' => null,
+ ]
+ ]
+ ]
+ ]
+ ]
],
- as:'link'
- ),
- DataFixture(BundleOptionFixture::class, ['title' => 'Checkbox Options', 'type' => 'checkbox',
- 'required' => 1,'product_links' => ['$link$']], 'option'),
- DataFixture(
- BundleProductFixture::class,
- ['price' => 90, '_options' => ['$option$']],
- as:'bundleProduct'
- ),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$bundleProduct.id$', 'prod_qty' => 100], 'prodStock'),
- DataFixture(GuestCartFixture::class, as: 'cart'),
- DataFixture(
- AddBundleProductToCart::class,
- [
- 'cart_id' => '$cart.id$',
- 'product_id' => '$bundleProduct.id$',
- 'selections' => [['$product.id$']],
- 'qty' => 100
- ],
- ),
- DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 90], 'prodStock')
- ]
- public function testStockStatusUnavailableBundleProductOption1(): void
- {
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->getQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
- $responseDataObject = new DataObject($response);
-
- self::assertFalse(
- $responseDataObject->getData('cart/itemsV2/items/0/is_available')
- );
- self::assertEquals(
- 'Only 90 of 100 available',
- $responseDataObject->getData('cart/itemsV2/items/0/not_available_message')
+ $this->graphQlQuery(
+ $this->getCartQuery($this->fixtures->get('quoteIdMask')->getMaskedId())
+ )
);
}
#[
Config('cataloginventory/options/not_available_message', 1),
Config('cataloginventory/options/stock_threshold_qty', 100),
- DataFixture(ProductFixture::class, ['price' => 100.00], as: 'product'),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 100], 'prodStock'),
+ DataFixture(ProductFixture::class, as: 'product'),
DataFixture(
BundleSelectionFixture::class,
[
@@ -307,21 +317,38 @@ public function testStockStatusAddBundleProduct(): void
$option = $typeInstance->getOptionsCollection($product)->getFirstItem();
/** @var \Magento\Catalog\Model\Product $selection */
$selection = $typeInstance->getSelectionsCollection([$option->getId()], $product)->getFirstItem();
- $optionId = $option->getId();
- $selectionId = $selection->getSelectionId();
-
- $bundleOptionIdV2 = $this->generateBundleOptionIdV2((int) $optionId, (int) $selectionId, 1);
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->mutationAddBundleProduct($maskedQuoteId, self::PARENT_SKU_BUNDLE, $bundleOptionIdV2);
- $response = $this->graphQlMutation($query);
- $responseDataObject = new DataObject($response);
-
- self::assertTrue(
- $responseDataObject->getData('addProductsToCart/cart/itemsV2/items/0/is_available')
+ $bundleOptionIdV2 = $this->generateBundleOptionIdV2(
+ (int) $option->getId(),
+ (int) $selection->getSelectionId(),
+ 1
);
- self::assertNull(
- $responseDataObject->getData('addProductsToCart/cart/itemsV2/items/0/not_available_message')
+
+ $this->assertEquals(
+ [
+ 'addProductsToCart' => [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'is_available' => true,
+ 'not_available_message' => null,
+ 'product' => [
+ 'sku' => self::PARENT_SKU_BUNDLE,
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlMutation(
+ $this->mutationAddBundleProduct(
+ $this->fixtures->get('quoteIdMask')->getMaskedId(),
+ self::PARENT_SKU_BUNDLE,
+ $bundleOptionIdV2
+ )
+ )
);
}
@@ -344,64 +371,32 @@ public function testStockStatusAddBundleProduct(): void
'child_product_id' => '$product.id$',
'qty' => 100
],
- ),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 90], 'prodStock')
+ )
]
public function testStockStatusUnavailableConfigurableProduct(): void
{
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->getQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
- $responseDataObject = new DataObject($response);
-
- self::assertFalse(
- $responseDataObject->getData('cart/itemsV2/items/0/is_available')
- );
- self::assertEquals(
- 'Not enough items for sale',
- $responseDataObject->getData('cart/itemsV2/items/0/not_available_message')
- );
- }
-
- #[
- Config('cataloginventory/options/not_available_message', 1),
- Config('cataloginventory/options/stock_threshold_qty', 100),
- DataFixture(ProductFixture::class, as: 'product'),
- DataFixture(AttributeFixture::class, as: 'attribute'),
- DataFixture(
- ConfigurableProductFixture::class,
- ['_options' => ['$attribute$'], '_links' => ['$product$']],
- 'configurable_product'
- ),
- DataFixture(GuestCartFixture::class, as: 'cart'),
- DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
- DataFixture(
- AddConfigurableProductToCartFixture::class,
+ $this->updateProductStock();
+ $this->assertEquals(
[
- 'cart_id' => '$cart.id$',
- 'product_id' => '$configurable_product.id$',
- 'child_product_id' => '$product.id$',
- 'qty' => 100
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'is_available' => false,
+ 'not_available_message' => 'Not enough items for sale',
+ 'quantity' => 100,
+ 'product' => [
+ 'sku' => $this->fixtures->get('configurable_product')->getSku(),
+ 'only_x_left_in_stock' => null,
+ ]
+ ]
+ ]
+ ]
+ ]
],
- ),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 90], 'prodStock')
- ]
- public function testStockStatusUnavailableConfigurableProductOption1(): void
- {
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->getQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
- $responseDataObject = new DataObject($response);
-
- self::assertFalse(
- $responseDataObject->getData('cart/itemsV2/items/0/is_available')
- );
-
- self::assertEquals(90, $responseDataObject->getData('cart/itemsV2/items/0/product/only_x_left_in_stock'));
-
- self::assertEquals(
- 'Only 90 of 100 available',
- $responseDataObject->getData('cart/itemsV2/items/0/not_available_message')
+ $this->graphQlQuery(
+ $this->getCartQuery($this->fixtures->get('quoteIdMask')->getMaskedId())
+ )
);
}
@@ -417,7 +412,6 @@ public function testStockStatusUnavailableConfigurableProductOption1(): void
),
DataFixture(GuestCartFixture::class, as: 'cart'),
DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 100], 'prodStock'),
DataFixture(
AddConfigurableProductToCartFixture::class,
[
@@ -430,17 +424,27 @@ public function testStockStatusUnavailableConfigurableProductOption1(): void
]
public function testStockStatusAvailableConfigurableProduct(): void
{
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->getQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
- $responseDataObject = new DataObject($response);
-
- self::assertTrue(
- $responseDataObject->getData('cart/itemsV2/items/0/is_available')
- );
-
- self::assertNull(
- $responseDataObject->getData('cart/itemsV2/items/0/not_available_message')
+ $this->assertEquals(
+ [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'is_available' => true,
+ 'not_available_message' => null,
+ 'quantity' => 90,
+ 'product' => [
+ 'sku' => $this->fixtures->get('configurable_product')->getSku(),
+ 'only_x_left_in_stock' => 100,
+ ]
+ ]
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlQuery(
+ $this->getCartQuery($this->fixtures->get('quoteIdMask')->getMaskedId())
+ )
);
}
@@ -480,7 +484,7 @@ public function testStockStatusAvailableConfigurableProduct(): void
DataFixture(
ProductStockFixture::class,
[
- 'prod_id' => 'product_variant_1.id$',
+ 'prod_id' => '$product_variant_1.id$',
'prod_qty' => 100
],
'productVariantStock1'
@@ -488,7 +492,7 @@ public function testStockStatusAvailableConfigurableProduct(): void
DataFixture(
ProductStockFixture::class,
[
- 'prod_id' => 'product_variant_2.id$',
+ 'prod_id' => '$product_variant_2.id$',
'prod_qty' => 100
],
'productVariantStock2'
@@ -499,191 +503,270 @@ public function testStockStatusAvailableConfigurableProduct(): void
]
public function testStockStatusAddConfigurableProduct(): void
{
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
$productVariant1 = $this->fixtures->get('product_variant_1');
/** @var AttributeInterface $attribute */
$attribute = $this->fixtures->get('attribute');
/** @var AttributeOptionInterface $option */
$option = $attribute->getOptions()[1];
$selectedOption = base64_encode("configurable/{$attribute->getAttributeId()}/{$option->getValue()}");
- $query = $this->mutationAddConfigurableProduct(
- $maskedQuoteId,
- $productVariant1->getData('sku'),
- $selectedOption,
- 100
- );
-
- $response = $this->graphQlMutation($query);
- $responseDataObject = new DataObject($response);
- self::assertTrue(
- $responseDataObject->getData('addProductsToCart/cart/itemsV2/items/0/is_available')
- );
-
- self::assertNull(
- $responseDataObject->getData('addProductsToCart/cart/itemsV2/items/0/not_available_message')
+ $this->assertEquals(
+ [
+ 'addProductsToCart' => [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [
+ [
+ 'quantity' => 100,
+ 'is_available' => 1,
+ 'not_available_message' => '',
+ 'product' => [
+ 'sku' => 'product_variant_1',
+ 'only_x_left_in_stock' => 100,
+ ]
+ ]
+ ]
+ ]
+ ],
+ 'user_errors' => [],
+ ],
+ ],
+ $this->graphQlMutation(
+ $this->mutationAddConfigurableProduct(
+ $this->fixtures->get('quoteIdMask')->getMaskedId(),
+ $productVariant1->getData('sku'),
+ $selectedOption,
+ 100
+ )
+ )
);
}
#[
Config('cataloginventory/options/not_available_message', 1),
Config('cataloginventory/options/stock_threshold_qty', 100),
- DataFixture(ProductFixture::class, ['price' => 100.00], as: 'product'),
+ DataFixture(ProductFixture::class, as: 'product'),
DataFixture(GuestCartFixture::class, as: 'cart'),
- DataFixture(AddProductToCart::class, ['cart_id' => '$cart.id$', 'product_id' => '$product.id$', 'qty' => 100]),
- DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
- DataFixture(ProductStockFixture::class, ['prod_id' => '$product.id$', 'prod_qty' => 90], 'prodStock')
+ DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask')
]
public function testNotAvailableMessageOption1(): void
{
- $maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $query = $this->getQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
- $responseDataObject = new DataObject($response);
-
- self::assertFalse(
- $responseDataObject->getData('cart/itemsV2/items/0/is_available')
- );
-
- self::assertEquals(90, $responseDataObject->getData('cart/itemsV2/items/0/product/only_x_left_in_stock'));
-
- self::assertEquals(
- 'Only 90 of 100 available',
- $responseDataObject->getData('cart/itemsV2/items/0/not_available_message')
+ $this->updateProductStock(90, true);
+ $this->assertEquals(
+ [
+ 'addProductsToCart' => [
+ 'cart' => [
+ 'itemsV2' => [
+ 'items' => [],
+ ],
+ ],
+ 'user_errors' => [
+ [
+ 'code' => 'INSUFFICIENT_STOCK',
+ 'message' => 'Only 90 of 100 available',
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlMutation(
+ $this->addToCartMutation(
+ $this->fixtures->get('quoteIdMask')->getMaskedId(),
+ $this->fixtures->get('product')->getSku(),
+ 100
+ )
+ )
);
}
/**
+ * Generate GraphQL query to get cart items with availability status
+ *
* @param string $cartId
* @return string
*/
- private function getQuery(string $cartId): string
+ private function getCartQuery(string $cartId): string
{
return <<fixtures->get('product');
+ $stockItem = $this->stockRegistry->getStockItem($product->getId());
+ $stockItem->setData(StockItemInterface::IS_IN_STOCK, $isInStock);
+ $stockItem->setData(StockItemInterface::QTY, $qty);
+ $stockItem->setData(StockItemInterface::MANAGE_STOCK, true);
+ $stockItem->save();
+ }
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/CustomerOrderItemProductTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/CustomerOrderItemProductTest.php
new file mode 100644
index 000000000000..5d5ea35f51de
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/CustomerOrderItemProductTest.php
@@ -0,0 +1,155 @@
+customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class);
+ $this->fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
+ $this->stockRegistry = Bootstrap::getObjectManager()->get(StockRegistryInterface::class);
+ }
+
+ #[
+ DataFixture(ProductFixture::class, as: 'product'),
+ DataFixture(CustomerFixture::class, as: 'customer'),
+ DataFixture(
+ CustomerCartFixture::class,
+ ['customer_id' => '$customer.id$', 'reserved_order_id' => 'test_order_with_simple_product'],
+ as: 'cart'
+ ),
+ DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart.id$', 'product_id' => '$product.id$']),
+ DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$cart.id$']),
+ DataFixture(SetShippingAddressFixture::class, ['cart_id' => '$cart.id$']),
+ DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$cart.id$']),
+ DataFixture(SetPaymentMethodFixture::class, ['cart_id' => '$cart.id$']),
+ DataFixture(PlaceOrderFixture::class, ['cart_id' => '$cart.id$'], 'order')
+ ]
+ public function testOrderItemProductWhenOutOfStock(): void
+ {
+ $this->updateProductStock();
+
+ $this->assertEquals(
+ [
+ 'customer' => [
+ 'orders' => [
+ 'items' => [
+ [
+ 'number' => $this->fixtures->get('order')->getIncrementId(),
+ 'items' => [
+ [
+ 'product' => [
+ 'sku' => $this->fixtures->get('product')->getSku(),
+ 'stock_status' => 'OUT_OF_STOCK'
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlQuery(
+ $this->getCustomerOrdersQuery(),
+ [],
+ '',
+ $this->getCustomerAuthHeaders($this->fixtures->get('customer')->getEmail())
+ )
+ );
+ }
+
+ /**
+ * Update product stock to out of stock
+ *
+ * @throws Exception
+ */
+ private function updateProductStock(): void
+ {
+ /** @var ProductInterface $product */
+ $product = $this->fixtures->get('product');
+ $stockItem = $this->stockRegistry->getStockItem($product->getId());
+ $stockItem->setData(StockItemInterface::IS_IN_STOCK, false);
+ $stockItem->setData(StockItemInterface::QTY, 0);
+ $stockItem->setData(StockItemInterface::MANAGE_STOCK, true);
+ $stockItem->save();
+ }
+
+ /**
+ * Returns the GraphQL query to fetch customer orders.
+ *
+ * @return string
+ */
+ private function getCustomerOrdersQuery(): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($email, 'password');
+ return ['Authorization' => 'Bearer ' . $customerToken];
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrderTotalGrandTotalExclTaxTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrderTotalGrandTotalExclTaxTest.php
new file mode 100644
index 000000000000..9f78a09a7403
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/OrderTotalGrandTotalExclTaxTest.php
@@ -0,0 +1,332 @@
+customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class);
+ $this->fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
+ }
+
+ #[
+ Config('tax/calculation/apply_after_discount', false, "store", "default"),
+ DataFixture(
+ AddressConditionFixture::class,
+ [
+ 'attribute' => 'total_qty',
+ 'operator' => '>=',
+ 'value' => 1
+ ],
+ 'condition'
+ ),
+ DataFixture(
+ SalesRuleFixture::class,
+ [
+ 'store_labels' => [1 => self::DISCOUNT_LABEL],
+ 'coupon_type' => SalesRule::COUPON_TYPE_SPECIFIC,
+ 'simple_action' => SalesRule::BY_PERCENT_ACTION,
+ 'discount_amount' => 100,
+ 'coupon_code' => self::COUPON_CODE,
+ 'conditions' => ['$condition$'],
+ 'uses_per_customer' => 10,
+ 'apply_to_shipping' => true,
+ 'stop_rules_processing' => true
+ ],
+ as: 'rule'
+ ),
+ DataFixture(ProductTaxClassFixture::class, as: 'product_tax_class'),
+ DataFixture(TaxRateFixture::class, as: 'rate'),
+ DataFixture(
+ TaxRuleFixture::class,
+ [
+ 'customer_tax_class_ids' => [3],
+ 'product_tax_class_ids' => ['$product_tax_class.classId$'],
+ 'tax_rate_ids' => ['$rate.id$']
+ ],
+ 'rule'
+ ),
+ DataFixture(ProductFixture::class, [
+ 'price' => self::PRODUCT_PRICE,
+ 'custom_attributes' => ['tax_class_id' => '$product_tax_class.classId$']
+ ], as: 'product'),
+ DataFixture(CustomerFixture::class, as: 'customer'),
+ DataFixture(CustomerCartFixture::class, ['customer_id' => '$customer.id$'], as: 'quote'),
+ DataFixture(
+ AddProductToCartFixture::class,
+ [
+ 'cart_id' => '$quote.id$',
+ 'product_id' => '$product.id$',
+ 'qty' => self::TOTAL_QTY
+ ]
+ ),
+ DataFixture(
+ ApplyCouponFixture::class,
+ [
+ 'cart_id' => '$quote.id$',
+ 'coupon_codes' => [self::COUPON_CODE]
+ ]
+ ),
+ DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(SetShippingAddressFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(SetPaymentMethodFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(PlaceOrderFixture::class, ['cart_id' => '$quote.id$'], 'order')
+ ]
+ public function testGrandTotalExclTaxWithTaxAppliedBeforeDiscount(): void
+ {
+ $this->assertOrderResponse();
+ }
+
+ #[
+ Config('tax/calculation/apply_after_discount', true, "store", "default"),
+ DataFixture(
+ AddressConditionFixture::class,
+ [
+ 'attribute' => 'total_qty',
+ 'operator' => '>=',
+ 'value' => 1
+ ],
+ 'condition'
+ ),
+ DataFixture(
+ SalesRuleFixture::class,
+ [
+ 'store_labels' => [1 => self::DISCOUNT_LABEL],
+ 'coupon_type' => SalesRule::COUPON_TYPE_SPECIFIC,
+ 'simple_action' => SalesRule::BY_PERCENT_ACTION,
+ 'discount_amount' => 100,
+ 'coupon_code' => self::COUPON_CODE,
+ 'conditions' => ['$condition$'],
+ 'uses_per_customer' => 10,
+ 'apply_to_shipping' => true,
+ 'stop_rules_processing' => true
+ ],
+ as: 'rule'
+ ),
+ DataFixture(ProductTaxClassFixture::class, as: 'product_tax_class'),
+ DataFixture(TaxRateFixture::class, as: 'rate'),
+ DataFixture(
+ TaxRuleFixture::class,
+ [
+ 'customer_tax_class_ids' => [3],
+ 'product_tax_class_ids' => ['$product_tax_class.classId$'],
+ 'tax_rate_ids' => ['$rate.id$']
+ ],
+ 'rule'
+ ),
+ DataFixture(ProductFixture::class, [
+ 'price' => self::PRODUCT_PRICE,
+ 'custom_attributes' => ['tax_class_id' => '$product_tax_class.classId$']
+ ], as: 'product'),
+ DataFixture(CustomerFixture::class, as: 'customer'),
+ DataFixture(CustomerCartFixture::class, ['customer_id' => '$customer.id$'], as: 'quote'),
+ DataFixture(
+ AddProductToCartFixture::class,
+ [
+ 'cart_id' => '$quote.id$',
+ 'product_id' => '$product.id$',
+ 'qty' => self::TOTAL_QTY
+ ]
+ ),
+ DataFixture(
+ ApplyCouponFixture::class,
+ [
+ 'cart_id' => '$quote.id$',
+ 'coupon_codes' => [self::COUPON_CODE]
+ ]
+ ),
+ DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(SetShippingAddressFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(SetPaymentMethodFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(PlaceOrderFixture::class, ['cart_id' => '$quote.id$'], 'order')
+ ]
+ public function testGrandTotalExclTaxWithTaxAppliedAfterDiscount(): void
+ {
+ $this->assertOrderResponse();
+ }
+
+ #[
+ Config('tax/calculation/apply_after_discount', false, "store", "default"),
+ DataFixture(ProductTaxClassFixture::class, as: 'product_tax_class'),
+ DataFixture(TaxRateFixture::class, as: 'rate'),
+ DataFixture(
+ TaxRuleFixture::class,
+ [
+ 'customer_tax_class_ids' => [3],
+ 'product_tax_class_ids' => ['$product_tax_class.classId$'],
+ 'tax_rate_ids' => ['$rate.id$']
+ ],
+ 'rule'
+ ),
+ DataFixture(ProductFixture::class, [
+ 'price' => self::PRODUCT_PRICE,
+ 'custom_attributes' => ['tax_class_id' => '$product_tax_class.classId$']
+ ], as: 'product'),
+ DataFixture(CustomerFixture::class, as: 'customer'),
+ DataFixture(CustomerCartFixture::class, ['customer_id' => '$customer.id$'], as: 'quote'),
+ DataFixture(
+ AddProductToCartFixture::class,
+ [
+ 'cart_id' => '$quote.id$',
+ 'product_id' => '$product.id$',
+ 'qty' => self::TOTAL_QTY
+ ]
+ ),
+ DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(SetShippingAddressFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(SetPaymentMethodFixture::class, ['cart_id' => '$quote.id$']),
+ DataFixture(PlaceOrderFixture::class, ['cart_id' => '$quote.id$'], 'order')
+ ]
+ public function testGrandTotalExclTaxWithoutDiscount(): void
+ {
+ $this->assertOrderResponse();
+ }
+
+ /**
+ * Assert order response for grand total excluding tax
+ *
+ * @return void
+ * @throws AuthenticationException|LocalizedException
+ * @throws Exception
+ */
+ private function assertOrderResponse(): void
+ {
+ /** @var OrderInterface $order */
+ $order = $this->fixtures->get('order');
+ $this->assertEquals(
+ [
+ 'customer' => [
+ 'orders' => [
+ 'items' => [
+ [
+ 'number' => $order->getIncrementId(),
+ 'total' => [
+ 'grand_total' => [
+ 'value' => $order->getGrandTotal(),
+ 'currency' => 'USD'
+ ],
+ 'grand_total_excl_tax' => [
+ 'value' => (float)($order->getSubtotal()
+ + $order->getShippingAmount()
+ - abs((float)$order->getDiscountAmount())),
+ 'currency' => 'USD'
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ ],
+ $this->graphQlQuery(
+ $this->getCustomerOrdersQuery(
+ $order->getIncrementId()
+ ),
+ [],
+ '',
+ $this->getCustomerAuthHeaders($this->fixtures->get('customer')->getEmail())
+ )
+ );
+ }
+
+ /**
+ * Get customer orders query with total fields
+ *
+ * @param string $orderId
+ * @return string
+ */
+ private function getCustomerOrdersQuery(string $orderId): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($email, 'password');
+ return ['Authorization' => 'Bearer ' . $customerToken];
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/SalesRule/CartRulesStoreConfigTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/SalesRule/CartRulesStoreConfigTest.php
index 5aff568d9e81..cd6c6931ad68 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/SalesRule/CartRulesStoreConfigTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/SalesRule/CartRulesStoreConfigTest.php
@@ -7,48 +7,52 @@
namespace Magento\GraphQl\SalesRule;
-use Exception;
use Magento\TestFramework\Fixture\Config;
use Magento\TestFramework\TestCase\GraphQlAbstract;
-/**
- * Test coverage for Config Data from Customer->Promotion->GraphQl
- */
class CartRulesStoreConfigTest extends GraphQlAbstract
{
-
- /**
- * @throws Exception
- */
#[
- Config('promo/graphql/share_all_sales_rule', 1),
- Config('promo/graphql/share_applied_sales_rule', 1)
+ Config('promo/graphql/share_applied_cart_rule', true)
]
public function testCartRulesGraphQlStoreConfig(): void
{
$this->assertEquals(
[
'storeConfig' => [
- 'share_all_sales_rule' => 1,
- 'share_applied_sales_rule' => 1,
- ],
+ 'share_applied_cart_rule' => true
+ ]
+ ],
+ $this->graphQlQuery($this->getStoreConfigQuery())
+ );
+ }
+
+ #[
+ Config('promo/graphql/share_applied_cart_rule', false)
+ ]
+ public function testCartRulesGraphQlStoreConfigDisabled(): void
+ {
+ $this->assertEquals(
+ [
+ 'storeConfig' => [
+ 'share_applied_cart_rule' => false
+ ]
],
- $this->graphQlQuery($this->getQuery())
+ $this->graphQlQuery($this->getStoreConfigQuery())
);
}
/**
- * Generates storeConfig query with configurations from promo->graphql
+ * Generates storeConfig query with newly added configurations
*
* @return string
*/
- private function getQuery(): string
+ private function getStoreConfigQuery(): string
{
return <<fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
- }
-
- /**
- * Test to retrieve all cart rules when promo/graphql/share_all_sales_rule is enabled.
- *
- * @throws Exception
- */
- #[
- Config('promo/graphql/share_all_sales_rule', 1),
- DataFixture(SalesRuleFixture::class, as: 'rule1'),
- DataFixture(SalesRuleFixture::class, as: 'rule2'),
- DataFixture(SalesRuleFixture::class, as: 'rule3'),
- DataFixture(SalesRuleFixture::class, ['is_active' => 0], as: 'rule4')
- ]
- public function testGetAllCartRules(): void
- {
- $this->assertEmpty(
- array_diff(
- array_column($this->graphQlQuery($this->getAllSalesRulesQuery()), 'name'),
- array_column($this->fetchAllSalesRules(), 'name')
- )
- );
- }
-
- /**
- * Test to retrieve all sales rules when promo/graphql/share_all_sales_rule is disabled.
- *
- * @throws Exception
- */
- #[
- Config('promo/graphql/share_all_sales_rule', 0)
- ]
- public function testGetAllCartRulesWhenConfigDisabled(): void
- {
- $this->expectException(ResponseContainsErrorsException::class);
- $this->expectExceptionMessage(
- "Sharing Cart Rules information is disabled or not configured."
- );
- $this->graphQlQuery($this->getAllSalesRulesQuery());
- }
-
- /**
- * Get all sales rules
- *
- * @return array[]
- */
- private function fetchAllSalesRules(): array
- {
- return [
- "allCartRules" => [
- ['name' => $this->fixtures->get('rule1')->getName()],
- ['name' => $this->fixtures->get('rule2')->getName()],
- ['name' => $this->fixtures->get('rule3')->getName()]
- ]
- ];
- }
-
- /**
- * Get all sales rules query
- *
- * @return string
- */
- private function getAllSalesRulesQuery(): string
- {
- return <<fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
+ $this->idEncoder = Bootstrap::getObjectManager()->get(Uid::class);
}
/**
- * Test to retrieve applied cart rules when promo/graphql/share_applied_sales_rule is enabled.
- *
- * @throws Exception
+ * Test to retrieve applied cart rules when promo/graphql/share_applied_cart_rule is enabled.
*/
#[
- Config('promo/graphql/share_applied_sales_rule', 1),
- Config('sales/multicoupon/maximum_number_of_coupons_per_order', 2),
+ Config('promo/graphql/share_applied_cart_rule', true),
+ Config('sales/multicoupon/maximum_number_of_coupons_per_order', '2'),
DataFixture(SalesRuleFixture::class, [
'coupon_type' => SalesRule::COUPON_TYPE_SPECIFIC,
- 'coupon_code' => self::COUPON_1,
- 'stop_rules_processing' => false,
+ 'coupon_code' => 'COUPON_1',
+ 'sort_order' => 10,
+ 'stop_rules_processing' => false
], as: 'rule1'),
DataFixture(SalesRuleFixture::class, [
'coupon_type' => SalesRule::COUPON_TYPE_NO_COUPON,
- 'stop_rules_processing' => false,
+ 'sort_order' => 20,
+ 'stop_rules_processing' => false
], as: 'rule2'),
- DataFixture(SalesRuleFixture::class, [
- 'coupon_type' => SalesRule::COUPON_TYPE_SPECIFIC,
- 'coupon_code' => self::COUPON_3,
- ], as: 'rule3'),
- DataFixture(SalesRuleFixture::class, ['is_active' => 0], as: 'rule4'),
+ DataFixture(SalesRuleFixture::class, ['is_active' => 0, 'sort_order' => 30], as: 'rule3'),
DataFixture(ProductFixture::class, as: 'product'),
DataFixture(GuestCart::class, as: 'cart'),
DataFixture(AddProductToCartFixture::class, [
@@ -77,7 +70,7 @@ public function testGetAppliedCartRules(): void
{
$maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
- $this->graphQlMutation($this->getApplyCouponMutation($maskedQuoteId, self::COUPON_1));
+ $this->graphQlMutation($this->getApplyCouponMutation($maskedQuoteId, 'COUPON_1'));
$this->assertEquals(
$this->fetchAppliedSalesRules(),
@@ -86,17 +79,15 @@ public function testGetAppliedCartRules(): void
}
/**
- * Test to retrieve applied sales rules when promo/graphql/share_applied_sales_rule is disabled.
- *
- * @throws Exception
+ * Test to retrieve applied cart rules when promo/graphql/share_applied_cart_rule is disabled.
*/
#[
- Config('promo/graphql/share_applied_sales_rule', 0),
+ Config('promo/graphql/share_applied_cart_rule', false),
DataFixture(ProductFixture::class, as: 'product'),
DataFixture(GuestCart::class, as: 'cart'),
DataFixture(AddProductToCartFixture::class, [
'cart_id' => '$cart.id$',
- 'product_id' => '$product.id$',
+ 'product_id' => '$product.id$'
]),
DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask')
]
@@ -105,15 +96,40 @@ public function testGetAllCartRulesWhenConfigDisabled(): void
$this->assertEquals(
[
'cart' => [
- 'rules' => null,
- ],
+ 'rules' => null
+ ]
+ ],
+ $this->graphQlQuery($this->getCartQuery($this->fixtures->get('quoteIdMask')->getMaskedId()))
+ );
+ }
+
+ /**
+ * Test to retrieve applied cart rules when configuration is enabled but no cart rules are applied to the cart.
+ */
+ #[
+ Config('promo/graphql/share_applied_cart_rule', true),
+ DataFixture(ProductFixture::class, as: 'product'),
+ DataFixture(GuestCart::class, as: 'cart'),
+ DataFixture(AddProductToCartFixture::class, [
+ 'cart_id' => '$cart.id$',
+ 'product_id' => '$product.id$'
+ ]),
+ DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask')
+ ]
+ public function testGetAllCartRulesWhenConfigEnabledButRulesNotApplied(): void
+ {
+ $this->assertEquals(
+ [
+ 'cart' => [
+ 'rules' => []
+ ]
],
$this->graphQlQuery($this->getCartQuery($this->fixtures->get('quoteIdMask')->getMaskedId()))
);
}
/**
- * Get applied sales rules
+ * Get applied cart rules
*
* @return array[]
*/
@@ -123,10 +139,10 @@ private function fetchAppliedSalesRules(): array
'cart' => [
'rules' => [
[
- 'name' => $this->fixtures->get('rule1')->getName()
+ 'uid' => $this->idEncoder->encode($this->fixtures->get('rule1')->getId())
],
[
- 'name' => $this->fixtures->get('rule2')->getName()
+ 'uid' => $this->idEncoder->encode($this->fixtures->get('rule2')->getId())
]
]
]
@@ -157,7 +173,7 @@ private function getApplyCouponMutation(string $cartId, string $couponCode): str
}
/**
- * Get all sales rules query
+ * Get applied cart rules query
*
* @param string $cartId
* @return string
@@ -168,7 +184,7 @@ private function getCartQuery(string $cartId): string
query Cart {
cart(cart_id: "{$cartId}") {
rules {
- name
+ uid
}
}
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/AddWishlistItemsToCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/AddWishlistItemsToCartTest.php
index 26daa2669ab8..c5321ab7f841 100755
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/AddWishlistItemsToCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Wishlist/AddWishlistItemsToCartTest.php
@@ -68,12 +68,11 @@ public function testAddIncompleteItemsToCart(): void
$query = $this->getQuery($wishlistId, $itemId);
$response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
-
$this->assertArrayHasKey('addWishlistItemsToCart', $response);
$wishlistAfterAddingToCart = $response['addWishlistItemsToCart']['wishlist'];
$userErrors = $response['addWishlistItemsToCart']['add_wishlist_items_to_cart_user_errors'];
$this->assertEquals($userErrors[0]['message'], 'You need to choose options for your item.');
- $this->assertEquals($userErrors[0]['code'], 'UNDEFINED');
+ $this->assertEquals($userErrors[0]['code'], 'REQUIRED_PARAMETER_MISSING');
$this->assertEquals($userErrors[0]['wishlistId'], $wishlistId);
$this->assertEquals($userErrors[0]['wishlistItemId'], $itemId);
$wishlistItems = $wishlistAfterAddingToCart['items_v2']['items'];
@@ -296,7 +295,6 @@ private function getQuery(
* Returns GraphQl mutation string
*
* @param string $wishlistId
- * @param string $itemId
* @return string
*/
private function getAddAllItemsToCartQuery(
@@ -385,8 +383,8 @@ private function getCustomerWishlistQuery(): string
* Returns the GraphQl mutation string for products added to wishlist
*
* @param string $wishlistId
- * @param string $sku2
- * @param int $quantity2
+ * @param string $sku
+ * @param int $quantity
* @return string
*/
private function addSecondProductToWishlist(
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/App/State/GraphQlStateDiff.php b/dev/tests/integration/testsuite/Magento/GraphQl/App/State/GraphQlStateDiff.php
index cc1e8ebae246..66588cd2b988 100644
--- a/dev/tests/integration/testsuite/Magento/GraphQl/App/State/GraphQlStateDiff.php
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/App/State/GraphQlStateDiff.php
@@ -1,7 +1,7 @@
doRequest($query, $authInfo);
$this->objectManagerForTest->_resetState();
$this->comparator->rememberObjectsStateAfter($firstRequest);
- $result = $this->comparator->compareBetweenRequests($operationName);
+ $result = $this->handleRequestProperties($this->comparator->compareBetweenRequests($operationName));
$test->assertEmpty(
$result,
sprintf(
@@ -202,7 +202,7 @@ private function request(
var_export($result, true)
)
);
- $result = $this->comparator->compareConstructedAgainstCurrent($operationName);
+ $result = $this->handleRequestProperties($this->comparator->compareConstructedAgainstCurrent($operationName));
$test->assertEmpty(
$result,
sprintf(
@@ -325,4 +325,18 @@ public function getResetPasswordToken(string $email): string
$customerSecure = $customerRegistry->retrieveSecureData(1);
return $customerSecure->getRpToken();
}
+
+ /**
+ * Handle request properties for sslOffloadHeader
+ *
+ * @param array $result
+ * @return array
+ */
+ public function handleRequestProperties(array $result): array
+ {
+ if (isset($result['Magento\Framework\Webapi\Request']['properties']['sslOffloadHeader'])) {
+ unset($result['Magento\Framework\Webapi\Request']);
+ }
+ return $result;
+ }
}