Skip to content

Commit a2689a0

Browse files
authored
LYNX-731 Provide cart rules related information via GraphQL API
1 parent f99a581 commit a2689a0

File tree

13 files changed

+677
-5
lines changed

13 files changed

+677
-5
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesRule\Model\Config;
9+
10+
use Magento\Framework\App\Config\ScopeConfigInterface;
11+
use Magento\Store\Model\ScopeInterface;
12+
13+
class Coupon
14+
{
15+
public const XML_PATH_PROMO_GRAPHQL_SHARE_ALL_RULES = 'promo/graphql/share_all_sales_rule';
16+
public const XML_PATH_PROMO_GRAPHQL_SHARE_APPLIED_RULES = 'promo/graphql/share_applied_sales_rule';
17+
18+
/**
19+
* Coupon Constructor
20+
*
21+
* @param ScopeConfigInterface $scopeConfig
22+
*/
23+
public function __construct(
24+
private readonly ScopeConfigInterface $scopeConfig,
25+
) {
26+
}
27+
28+
/**
29+
* Get share all sales rule flag value
30+
*
31+
* @return bool
32+
*/
33+
public function isShareAllSalesRulesEnabled(): bool
34+
{
35+
return $this->scopeConfig->isSetFlag(
36+
self::XML_PATH_PROMO_GRAPHQL_SHARE_ALL_RULES,
37+
ScopeInterface::SCOPE_STORE
38+
);
39+
}
40+
41+
/**
42+
* Get share currently applied sales rule flag value
43+
*
44+
* @return bool
45+
*/
46+
public function isShareAppliedSalesRulesEnabled(): bool
47+
{
48+
return $this->scopeConfig->isSetFlag(
49+
self::XML_PATH_PROMO_GRAPHQL_SHARE_APPLIED_RULES,
50+
ScopeInterface::SCOPE_STORE
51+
);
52+
}
53+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesRule\Model\ResourceModel;
9+
10+
use Exception;
11+
use Magento\Framework\App\ResourceConnection;
12+
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
13+
use Magento\Framework\EntityManager\MetadataPool;
14+
use Magento\SalesRule\Api\Data\RuleInterface;
15+
16+
class GetAllCartRules
17+
{
18+
/**
19+
* GetAllCartRules constructor
20+
*
21+
* @param ResourceConnection $resourceConnection
22+
* @param MetadataPool $metadataPool
23+
*/
24+
public function __construct(
25+
private readonly ResourceConnection $resourceConnection,
26+
private readonly MetadataPool $metadataPool
27+
) {
28+
}
29+
30+
/**
31+
* Get all active rule names
32+
*
33+
* @param ContextInterface $context
34+
* @return array
35+
* @throws Exception
36+
*/
37+
public function execute(ContextInterface $context): array
38+
{
39+
$connection = $this->resourceConnection->getConnection();
40+
$linkField = $this->metadataPool->getMetadata(RuleInterface::class)->getLinkField();
41+
42+
return $connection->fetchAll(
43+
$connection->select()
44+
->from(['sr' => $this->resourceConnection->getTableName('salesrule')])
45+
->reset('columns')
46+
->columns(['name'])
47+
->join(
48+
['srw' => $this->resourceConnection->getTableName('salesrule_website')],
49+
"sr.rule_id = srw.$linkField",
50+
[]
51+
)
52+
->where('sr.is_active = ?', 1)
53+
->where(
54+
'srw.website_id = ?',
55+
(int)$context->getExtensionAttributes()->getStore()->getWebsiteId()
56+
)
57+
) ?? [];
58+
}
59+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesRule\Model\ResourceModel;
9+
10+
use Exception;
11+
use Magento\Framework\App\ResourceConnection;
12+
use Magento\Framework\EntityManager\MetadataPool;
13+
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
14+
use Magento\SalesRule\Api\Data\RuleInterface;
15+
16+
class GetAppliedCartRules
17+
{
18+
/**
19+
* GetAppliedCartRules constructor
20+
*
21+
* @param ResourceConnection $resourceConnection
22+
* @param MetadataPool $metadataPool
23+
*/
24+
public function __construct(
25+
private readonly ResourceConnection $resourceConnection,
26+
private readonly MetadataPool $metadataPool
27+
) {
28+
}
29+
30+
/**
31+
* Get rule names from specified rule ids
32+
*
33+
* @param string $ruleIds
34+
* @param ContextInterface $context
35+
* @return array
36+
* @throws Exception
37+
*/
38+
public function execute(string $ruleIds, ContextInterface $context): array
39+
{
40+
$connection = $this->resourceConnection->getConnection();
41+
$linkField = $this->metadataPool->getMetadata(RuleInterface::class)->getLinkField();
42+
43+
return $connection->fetchAll(
44+
$connection->select()
45+
->from(['sr' => $this->resourceConnection->getTableName('salesrule')])
46+
->reset('columns')
47+
->columns(['name'])
48+
->join(
49+
['srw' => $this->resourceConnection->getTableName('salesrule_website')],
50+
"sr.rule_id = srw.$linkField",
51+
[]
52+
)
53+
->where('sr.is_active = ?', 1)
54+
->where('sr.rule_id IN (?)', explode(',', $ruleIds))
55+
->where(
56+
'srw.website_id = ?',
57+
(int)$context->getExtensionAttributes()->getStore()->getWebsiteId()
58+
)
59+
) ?? [];
60+
}
61+
}

app/code/Magento/SalesRule/etc/adminhtml/system.xml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
@@ -40,6 +40,19 @@
4040
<frontend_class>validate-digits</frontend_class>
4141
</field>
4242
</group>
43+
<group id="graphql" translate="label" showInDefault="1" sortOrder="20">
44+
<label>GraphQl Configurations</label>
45+
<field id="share_all_sales_rule" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
46+
<label>Share All Sales Rules</label>
47+
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
48+
<comment>Configuration to allow to disable providing all cart rules via GraphQL</comment>
49+
</field>
50+
<field id="share_applied_sales_rule" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
51+
<label>Share Applied Sales Rules</label>
52+
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
53+
<comment>Configuration to allow to disable currently applied sales rules for cart via GraphQL</comment>
54+
</field>
55+
</group>
4356
</section>
4457
<section id="rss">
4558
<group id="catalog">

app/code/Magento/SalesRule/etc/config.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
@@ -13,6 +13,10 @@
1313
<quantity_limit>250000</quantity_limit>
1414
<format>1</format>
1515
</auto_generated_coupon_codes>
16+
<graphql>
17+
<share_all_sales_rule>1</share_all_sales_rule>
18+
<share_applied_sales_rule>1</share_applied_sales_rule>
19+
</graphql>
1620
</promo>
1721
</default>
1822
</config>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesRuleGraphQl\Model\Resolver;
9+
10+
use Magento\Framework\GraphQl\Config\Element\Field;
11+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
12+
use Magento\Framework\GraphQl\Query\ResolverInterface;
13+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
14+
use Magento\SalesRule\Model\Config\Coupon;
15+
use Magento\SalesRule\Model\ResourceModel\GetAllCartRules;
16+
17+
class AllCartRules implements ResolverInterface
18+
{
19+
/**
20+
* AllCartRules Constructor
21+
*
22+
* @param Coupon $config
23+
* @param GetAllCartRules $getAllCartRules
24+
*/
25+
public function __construct(
26+
private readonly Coupon $config,
27+
private readonly GetAllCartRules $getAllCartRules
28+
) {
29+
}
30+
31+
/**
32+
* @inheritDoc
33+
*/
34+
public function resolve(
35+
Field $field,
36+
$context,
37+
ResolveInfo $info,
38+
?array $value = null,
39+
?array $args = null
40+
) {
41+
if (!$this->config->isShareAllSalesRulesEnabled()) {
42+
throw new GraphQlInputException(__('Sharing Cart Rules information is disabled or not configured.'));
43+
}
44+
45+
return array_map(
46+
static fn ($rule) => ['name' => $rule['name']],
47+
$this->getAllCartRules->execute($context)
48+
);
49+
}
50+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesRuleGraphQl\Model\Resolver;
9+
10+
use Magento\Framework\Exception\LocalizedException;
11+
use Magento\Framework\GraphQl\Config\Element\Field;
12+
use Magento\Framework\GraphQl\Query\ResolverInterface;
13+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
14+
use Magento\Quote\Api\Data\CartInterface;
15+
use Magento\SalesRule\Model\Config\Coupon;
16+
use Magento\SalesRule\Model\ResourceModel\GetAppliedCartRules;
17+
18+
class AppliedCartRules implements ResolverInterface
19+
{
20+
/**
21+
* AppliedCartRules Constructor
22+
*
23+
* @param Coupon $config
24+
* @param GetAppliedCartRules $getAppliedCartRules
25+
*/
26+
public function __construct(
27+
private readonly Coupon $config,
28+
private readonly GetAppliedCartRules $getAppliedCartRules
29+
) {
30+
}
31+
32+
/**
33+
* @inheritDoc
34+
*/
35+
public function resolve(
36+
Field $field,
37+
$context,
38+
ResolveInfo $info,
39+
?array $value = null,
40+
?array $args = null
41+
) {
42+
if (!(($value['model'] ?? null) instanceof CartInterface)) {
43+
throw new LocalizedException(__('"model" value should be specified'));
44+
}
45+
46+
if (!$this->config->isShareAppliedSalesRulesEnabled()) {
47+
return null; //returning null so that whole cart response is not broken
48+
}
49+
50+
$ruleIds = $value['model']->getAppliedRuleIds();
51+
52+
return $ruleIds ? array_map(
53+
fn ($rule) => ['name' => $rule['name']],
54+
$this->getAppliedCartRules->execute($ruleIds, $context)
55+
) : [];
56+
}
57+
}

app/code/Magento/SalesRuleGraphQl/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"require": {
88
"php": "~8.2.0||~8.3.0||~8.4.0",
99
"magento/framework": "*",
10-
"magento/module-sales-rule": "*"
10+
"magento/module-sales-rule": "*",
11+
"magento/module-quote": "*"
1112
},
1213
"type": "magento2-module",
1314
"license": [
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
9+
<type name="Magento\StoreGraphQl\Model\Resolver\Store\StoreConfigDataProvider">
10+
<arguments>
11+
<argument name="extendedConfigData" xsi:type="array">
12+
<item name="share_all_sales_rule" xsi:type="string">promo/graphql/share_all_sales_rule</item>
13+
<item name="share_applied_sales_rule" xsi:type="string">promo/graphql/share_applied_sales_rule</item>
14+
</argument>
15+
</arguments>
16+
</type>
17+
</config>

app/code/Magento/SalesRuleGraphQl/etc/schema.graphqls

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,20 @@
55
type Discount {
66
coupon: AppliedCoupon @resolver(class: "Magento\\SalesRuleGraphQl\\Model\\Resolver\\Coupon") @doc(description:"The coupon related to the discount.")
77
}
8+
9+
type StoreConfig {
10+
share_all_sales_rule: Boolean! @doc(description: "Configuration data from promo/graphql/share_all_sales_rule")
11+
share_applied_sales_rule: Boolean! @doc(description: "Configuration data from promo/graphql/share_applied_sales_rule")
12+
}
13+
14+
type Query {
15+
allCartRules: [CartRule!] @doc(description: "Provides all active cart rules in the store.") @resolver(class: "Magento\\SalesRuleGraphQl\\Model\\Resolver\\AllCartRules")
16+
}
17+
18+
type Cart {
19+
rules: [CartRule!] @doc(description: "Provides applied cart rules in the current active cart") @resolver(class: "Magento\\SalesRuleGraphQl\\Model\\Resolver\\AppliedCartRules")
20+
}
21+
22+
type CartRule {
23+
name: String! @doc(description: "Name of the cart price rule")
24+
}

0 commit comments

Comments
 (0)