Skip to content

Commit 1b8236a

Browse files
authored
LYNX-732: Provide customer group related information via GraphQL API
1 parent f112c7a commit 1b8236a

File tree

13 files changed

+736
-7
lines changed

13 files changed

+736
-7
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Customer\Model\Config;
9+
10+
use Magento\Framework\App\Config\ScopeConfigInterface;
11+
12+
class AccountInformation
13+
{
14+
private const XML_PATH_SHARE_ALL_CUSTOMER_GROUPS = 'customer/account_information/graphql_share_all_customer_groups';
15+
private const XML_PATH_SHARE_CUSTOMER_GROUP = 'customer/account_information/graphql_share_customer_group';
16+
17+
/**
18+
* AccountInformation constructor
19+
*
20+
* @param ScopeConfigInterface $scopeConfig
21+
*/
22+
public function __construct(
23+
private readonly ScopeConfigInterface $scopeConfig
24+
) {
25+
}
26+
27+
/**
28+
* Is 'graphql_share_all_customer_groups' config enabled
29+
*
30+
* @return bool
31+
*/
32+
public function isShareAllCustomerGroupsEnabled(): bool
33+
{
34+
return $this->scopeConfig->isSetFlag(self::XML_PATH_SHARE_ALL_CUSTOMER_GROUPS);
35+
}
36+
37+
/**
38+
* Is 'graphql_share_customer_group' config enabled
39+
*
40+
* @return bool
41+
*/
42+
public function isShareCustomerGroupEnabled(): bool
43+
{
44+
return $this->scopeConfig->isSetFlag(self::XML_PATH_SHARE_CUSTOMER_GROUP);
45+
}
46+
}

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

Lines changed: 12 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">
@@ -197,6 +197,16 @@
197197
<label>Require email confirmation if email has been changed</label>
198198
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
199199
</field>
200+
<field id="graphql_share_all_customer_groups" translate="label" type="select" sortOrder="40" showInDefault="1" showInWebsite="0" showInStore="0">
201+
<label>Share all customer groups via GraphQl</label>
202+
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
203+
<comment>Option to disable providing all customer group details via GraphQl</comment>
204+
</field>
205+
<field id="graphql_share_customer_group" translate="label" type="select" sortOrder="50" showInDefault="1" showInWebsite="0" showInStore="0">
206+
<label>Share the customer group via GraphQl for a customer</label>
207+
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
208+
<comment>Option to disable providing customer group details via GraphQl for a customer</comment>
209+
</field>
200210
</group>
201211
<group id="address" translate="label" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
202212
<label>Name and Address Options</label>

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

Lines changed: 4 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">
@@ -33,6 +33,8 @@
3333
<change_email_template>customer_account_information_change_email_template</change_email_template>
3434
<change_email_and_password_template>customer_account_information_change_email_and_password_template</change_email_and_password_template>
3535
<confirm>0</confirm>
36+
<graphql_share_all_customer_groups>1</graphql_share_all_customer_groups>
37+
<graphql_share_customer_group>1</graphql_share_customer_group>
3638
</account_information>
3739
<password>
3840
<forgot_email_identity>support</forgot_email_identity>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CustomerGraphQl\Model;
9+
10+
use Exception;
11+
use Magento\Customer\Api\GroupRepositoryInterface;
12+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
13+
14+
class GetCustomerGroupName
15+
{
16+
/**
17+
* GetCustomerGroupName Constructor
18+
*
19+
* @param GroupRepositoryInterface $groupRepository
20+
*/
21+
public function __construct(
22+
private readonly GroupRepositoryInterface $groupRepository
23+
) {
24+
}
25+
26+
/**
27+
* Get customer group name using customer group id
28+
*
29+
* @param int $groupId
30+
* @param int $websiteId
31+
* @return array
32+
* @throws GraphQlInputException
33+
*/
34+
public function execute(int $groupId, int $websiteId): array
35+
{
36+
try {
37+
$customerGroup = $this->groupRepository->getById($groupId);
38+
$excludedWebsiteIds = $customerGroup->getExtensionAttributes()->getExcludeWebsiteIds() ?? [];
39+
} catch (Exception $e) {
40+
throw new GraphQlInputException(__('The specified customer group is invalid or does not exist.'));
41+
}
42+
43+
return in_array($websiteId, $excludedWebsiteIds) ? [] : ['name' => $customerGroup->getCode()];
44+
}
45+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CustomerGraphQl\Model\Resolver;
9+
10+
use Exception;
11+
use Magento\Customer\Api\GroupRepositoryInterface;
12+
use Magento\Customer\Model\Config\AccountInformation;
13+
use Magento\Framework\Api\SearchCriteriaBuilder;
14+
use Magento\Framework\GraphQl\Config\Element\Field;
15+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
16+
use Magento\Framework\GraphQl\Query\ResolverInterface;
17+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
18+
19+
/**
20+
* Provides data for allCustomerGroups.name
21+
*/
22+
class AllCustomerGroups implements ResolverInterface
23+
{
24+
/**
25+
* AllCustomerGroups Constructor
26+
*
27+
* @param GroupRepositoryInterface $groupRepository
28+
* @param SearchCriteriaBuilder $searchCriteriaBuilder
29+
* @param AccountInformation $config
30+
*/
31+
public function __construct(
32+
private readonly GroupRepositoryInterface $groupRepository,
33+
private readonly SearchCriteriaBuilder $searchCriteriaBuilder,
34+
private readonly AccountInformation $config
35+
) {
36+
}
37+
38+
/**
39+
* @inheritDoc
40+
*/
41+
public function resolve(
42+
Field $field,
43+
$context,
44+
ResolveInfo $info,
45+
array $value = null,
46+
array $args = null
47+
): array {
48+
if (!$this->config->isShareAllCustomerGroupsEnabled()) {
49+
throw new GraphQlInputException(__('Sharing customer group information is disabled or not configured.'));
50+
}
51+
52+
try {
53+
$customerGroups = $this->groupRepository->getList(
54+
$this->searchCriteriaBuilder->create()
55+
)->getItems();
56+
} catch (Exception $e) {
57+
throw new GraphQlInputException(__('Unable to retrieve customer groups.'));
58+
}
59+
60+
return array_map(
61+
fn ($group) => ['name' => $group->getCode()],
62+
array_filter(
63+
$customerGroups,
64+
fn ($group) => !in_array(
65+
(int)$context->getExtensionAttributes()->getStore()->getWebsiteId(),
66+
$group->getExtensionAttributes()->getExcludeWebsiteIds() ?? []
67+
)
68+
)
69+
);
70+
}
71+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CustomerGraphQl\Model\Resolver;
9+
10+
use Magento\Customer\Api\Data\CustomerInterface;
11+
use Magento\Customer\Model\Config\AccountInformation;
12+
use Magento\CustomerGraphQl\Model\GetCustomerGroupName;
13+
use Magento\Framework\Exception\LocalizedException;
14+
use Magento\Framework\GraphQl\Config\Element\Field;
15+
use Magento\Framework\GraphQl\Query\ResolverInterface;
16+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
17+
18+
/**
19+
* Provides data for customer.group.name
20+
*/
21+
class CustomerGroup implements ResolverInterface
22+
{
23+
/**
24+
* CustomerGroup Constructor
25+
*
26+
* @param AccountInformation $config
27+
* @param GetCustomerGroupName $getCustomerGroup
28+
*/
29+
public function __construct(
30+
private readonly AccountInformation $config,
31+
private readonly GetCustomerGroupName $getCustomerGroup
32+
) {
33+
}
34+
35+
/**
36+
* @inheritDoc
37+
*/
38+
public function resolve(
39+
Field $field,
40+
$context,
41+
ResolveInfo $info,
42+
array $value = null,
43+
array $args = null
44+
): ?array {
45+
if (!($value['model'] ?? null) instanceof CustomerInterface) {
46+
throw new LocalizedException(__('"model" value should be specified'));
47+
}
48+
49+
return !$this->config->isShareCustomerGroupEnabled() ? null :
50+
$this->getCustomerGroup->execute(
51+
(int) $value['model']->getGroupId(),
52+
(int) $context->getExtensionAttributes()->getStore()->getWebsiteId()
53+
);
54+
}
55+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CustomerGraphQl\Model\Resolver;
9+
10+
use Magento\CatalogCustomerGraphQl\Model\Resolver\Customer\GetCustomerGroup as CustomerGroup;
11+
use Magento\Customer\Model\Config\AccountInformation;
12+
use Magento\CustomerGraphQl\Model\GetCustomerGroupName;
13+
use Magento\Framework\GraphQl\Config\Element\Field;
14+
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
15+
use Magento\Framework\GraphQl\Query\ResolverInterface;
16+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
17+
18+
/**
19+
* Provides data for customerGroup.name
20+
*/
21+
class GetCustomerGroup implements ResolverInterface
22+
{
23+
/**
24+
* GetCustomerGroup Constructor
25+
*
26+
* @param AccountInformation $config
27+
* @param CustomerGroup $customerGroup
28+
* @param GetCustomerGroupName $getCustomerGroup
29+
*/
30+
public function __construct(
31+
private readonly AccountInformation $config,
32+
private readonly CustomerGroup $customerGroup,
33+
private readonly GetCustomerGroupName $getCustomerGroup
34+
) {
35+
}
36+
37+
/**
38+
* @inheritDoc
39+
*/
40+
public function resolve(
41+
Field $field,
42+
$context,
43+
ResolveInfo $info,
44+
array $value = null,
45+
array $args = null
46+
): array {
47+
if (!$this->config->isShareCustomerGroupEnabled()) {
48+
throw new GraphQlInputException(__('Sharing customer group information is disabled or not configured.'));
49+
}
50+
51+
return $this->getCustomerGroup->execute(
52+
$this->customerGroup->execute($context->getUserId()),
53+
(int)$context->getExtensionAttributes()->getStore()->getWebsiteId()
54+
);
55+
}
56+
}

app/code/Magento/CustomerGraphQl/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"magento/module-tax": "*",
1818
"magento/module-graph-ql-cache": "*",
1919
"magento/module-graph-ql-resolver-cache": "*",
20-
"magento/module-sales": "*"
20+
"magento/module-sales": "*",
21+
"magento/module-catalog-customer-graph-ql": "*"
2122
},
2223
"license": [
2324
"OSL-3.0",

app/code/Magento/CustomerGraphQl/etc/graphql/di.xml

Lines changed: 4 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:framework:ObjectManager/etc/config.xsd">
@@ -38,6 +38,8 @@
3838
<item name="minimum_password_length" xsi:type="string">customer/password/minimum_password_length</item>
3939
<item name="autocomplete_on_storefront" xsi:type="string">customer/password/autocomplete_on_storefront</item>
4040
<item name="create_account_confirmation" xsi:type="string">customer/create_account/confirm</item>
41+
<item name="graphql_share_all_customer_groups" xsi:type="string">customer/account_information/graphql_share_all_customer_groups</item>
42+
<item name="graphql_share_customer_group" xsi:type="string">customer/account_information/graphql_share_customer_group</item>
4143
</argument>
4244
</arguments>
4345
</type>

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ type StoreConfig {
66
minimum_password_length : String @doc(description: "The minimum number of characters required for a valid password.")
77
autocomplete_on_storefront : Boolean @doc(description: "Indicates whether to enable autocomplete on login and forgot password forms.")
88
create_account_confirmation: Boolean @doc(description: "Indicates if the new accounts need confirmation.")
9+
graphql_share_all_customer_groups: Boolean! @doc(description: "Configuration data from customer/account_information/graphql_share_all_customer_groups")
10+
graphql_share_customer_group: Boolean! @doc(description: "Configuration data from customer/account_information/graphql_share_customer_group")
911
}
1012

1113
type Query {
1214
customer: Customer @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\Customer") @doc(description: "Return detailed information about a customer account.") @cache(cacheable: false)
1315
isEmailAvailable (
1416
email: String! @doc(description: "The email address to check.")
1517
): IsEmailAvailableOutput @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\IsEmailAvailable") @doc(description: "Check whether the specified email has already been used to create a customer account.")
18+
allCustomerGroups: [CustomerGroup!] @doc(description: "An array containing a list of all Customer Groups available.") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\AllCustomerGroups")
19+
customerGroup: CustomerGroup! @doc(description: "Provides name of the Customer Group assigned to the Customer or Guest.") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\GetCustomerGroup")
1620
}
1721

1822
type Mutation {
@@ -153,6 +157,7 @@ type Customer @doc(description: "Defines the customer name, addresses, and other
153157
gender: Int @doc(description: "The customer's gender (Male - 1, Female - 2).")
154158
custom_attributes(attributeCodes: [ID!]): [AttributeValueInterface] @doc(description: "Customer's custom attributes.") @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\CustomAttributeFilter")
155159
confirmation_status: ConfirmationStatusEnum! @doc(description: "The customer's confirmation status.") @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\ConfirmationStatus")
160+
group: CustomerGroup @doc(description: "Name of the customer group assigned to the customer") @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\CustomerGroup")
156161
}
157162

158163
type CustomerAddresses {
@@ -491,3 +496,7 @@ enum ConfirmationStatusEnum @doc(description: "List of account confirmation stat
491496
ACCOUNT_CONFIRMED @doc(description: "Account confirmed")
492497
ACCOUNT_CONFIRMATION_NOT_REQUIRED @doc(description: "Account confirmation not required")
493498
}
499+
500+
type CustomerGroup @doc(description: "Data of customer group.") {
501+
name: String @doc(description: "The name of customer group.")
502+
}

0 commit comments

Comments
 (0)