Add store-scoped customer & address attribute management to Grand.Web.Store#722
Merged
KrzysztofPajak merged 2 commits intoJul 4, 2026
Merged
Conversation
….Store Store owners can create, edit and delete their own customer attributes and address attributes. Global attributes are visible in read-only preview mode; attributes limited to other stores are hidden and access is blocked at the controller level. - CustomerAttribute and AddressAttribute implement IStoreLinkEntity (LimitedToStores + Stores) - GetAllCustomerAttributes(storeId) / GetAllAddressAttributes(storeId) service overloads with per-store cache keys - Storefront handlers and validators filter attributes by current store; GetAttributeWarnings(attrs, storeId) parser overloads so required attributes of other stores do not block registration/checkout - Admin: Stores selector on customer/address attribute forms - Grand.Web.Store: CustomerAttributeController + AddressAttributeController with views following the ContactAttribute pattern (PR #710); Stores field hidden and auto-set to the staff store - New translation resources (limitedtostores, globalreadonly) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends GrandNode’s multi-store attribute system by adding store-scoped Customer Attributes and Address Attributes management to Grand.Web.Store, and updating storefront/service-layer parsing + validation so attributes are filtered/validated against the current store.
Changes:
- Add
IStoreLinkEntitystore-linking (LimitedToStores+Stores) toCustomerAttributeandAddressAttribute, plus admin UI support for selecting stores. - Introduce store-aware service/parser overloads and update web handlers/validators to fetch and validate only the current-store attributes.
- Add Grand.Web.Store controllers, models, validators, AutoMapper profiles, and full view sets to enable store-manager CRUD for store-owned attributes and read-only preview for global ones.
Reviewed changes
Copilot reviewed 61 out of 62 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Web/Grand.Web/Validators/Orders/MerchandiseReturnValidator.cs | Pass current store id into address-attribute warning validation. |
| src/Web/Grand.Web/Validators/Customer/RegisterValidator.cs | Pass store id into customer-attribute warning validation during registration. |
| src/Web/Grand.Web/Validators/Customer/CustomerInfoValidator.cs | Pass store id into customer-attribute warning validation during profile update. |
| src/Web/Grand.Web/Validators/Customer/CustomerAddressEditValidator.cs | Thread IContextAccessor into nested address validation for store-scoped warnings. |
| src/Web/Grand.Web/Validators/Customer/CheckoutShippingAddressValidator.cs | Thread IContextAccessor into shipping address validation for store-scoped warnings. |
| src/Web/Grand.Web/Validators/Customer/CheckoutBillingAddressValidator.cs | Thread IContextAccessor into billing address validation for store-scoped warnings. |
| src/Web/Grand.Web/Validators/Common/AddressValidator.cs | Validate address attributes’ required-ness with current store id. |
| src/Web/Grand.Web/Features/Handlers/Customers/GetParseCustomAttributesHandler.cs | Parse customer attributes using store-filtered attribute list. |
| src/Web/Grand.Web/Features/Handlers/Customers/GetCustomAttributesHandler.cs | Build customer attribute models from store-filtered attribute list. |
| src/Web/Grand.Web/Features/Handlers/Common/GetParseCustomAddressAttributesHandler.cs | Parse address attributes using store-filtered attribute list. |
| src/Web/Grand.Web/Features/Handlers/Common/GetAddressModelHandler.cs | Render custom address attributes using store-filtered attribute list when store provided. |
| src/Web/Grand.Web/Commands/Handler/Customers/CustomerRegisteredCommandHandler.cs | Validate default address required attributes using the registration store id. |
| src/Web/Grand.Web.Store/Validators/CustomerAttributeStoreValidator.cs | Store-panel validator wrapper that reuses the base admin-shared validator. |
| src/Web/Grand.Web.Store/Validators/AddressAttributeStoreValidator.cs | Store-panel validator wrapper that reuses the base admin-shared validator. |
| src/Web/Grand.Web.Store/Models/Customers/CustomerAttributeStoreModel.cs | Store-panel model adds IsGlobalAttribute (read-only preview mode). |
| src/Web/Grand.Web.Store/Models/Common/AddressAttributeStoreModel.cs | Store-panel model adds IsGlobalAttribute (read-only preview mode). |
| src/Web/Grand.Web.Store/Mapper/CustomerAttributeStoreProfile.cs | AutoMapper profile for CustomerAttribute → store-panel model mapping. |
| src/Web/Grand.Web.Store/Mapper/AddressAttributeStoreProfile.cs | AutoMapper profile for AddressAttribute → store-panel model mapping. |
| src/Web/Grand.Web.Store/Controllers/CustomerAttributeController.cs | New store-panel CRUD controller with store visibility/ownership checks and value management. |
| src/Web/Grand.Web.Store/Controllers/AddressAttributeController.cs | New store-panel CRUD controller with store visibility/ownership checks and value management. |
| src/Web/Grand.Web.Store/Areas/Store/Views/CustomerAttribute/ValueEditPopup.cshtml | Popup UI for editing customer attribute values. |
| src/Web/Grand.Web.Store/Areas/Store/Views/CustomerAttribute/ValueCreatePopup.cshtml | Popup UI for creating customer attribute values. |
| src/Web/Grand.Web.Store/Areas/Store/Views/CustomerAttribute/Partials/CreateOrUpdateValue.cshtml | Shared partial for customer attribute value create/edit form. |
| src/Web/Grand.Web.Store/Areas/Store/Views/CustomerAttribute/Partials/CreateOrUpdate.TabValues.cshtml | Customer attribute values grid + add/edit/delete UI (with read-only mode handling). |
| src/Web/Grand.Web.Store/Areas/Store/Views/CustomerAttribute/Partials/CreateOrUpdate.TabInfo.cshtml | Customer attribute edit UI for info tab (with read-only mode handling). |
| src/Web/Grand.Web.Store/Areas/Store/Views/CustomerAttribute/Partials/CreateOrUpdate.cshtml | Tabstrip composition for customer attribute create/edit. |
| src/Web/Grand.Web.Store/Areas/Store/Views/CustomerAttribute/List.cshtml | Customer attributes list grid in store panel. |
| src/Web/Grand.Web.Store/Areas/Store/Views/CustomerAttribute/Edit.cshtml | Customer attribute edit page with read-only global preview messaging. |
| src/Web/Grand.Web.Store/Areas/Store/Views/CustomerAttribute/Create.cshtml | Customer attribute create page in store panel. |
| src/Web/Grand.Web.Store/Areas/Store/Views/AddressAttribute/ValueEditPopup.cshtml | Popup UI for editing address attribute values. |
| src/Web/Grand.Web.Store/Areas/Store/Views/AddressAttribute/ValueCreatePopup.cshtml | Popup UI for creating address attribute values. |
| src/Web/Grand.Web.Store/Areas/Store/Views/AddressAttribute/Partials/CreateOrUpdateValue.cshtml | Shared partial for address attribute value create/edit form. |
| src/Web/Grand.Web.Store/Areas/Store/Views/AddressAttribute/Partials/CreateOrUpdate.TabValues.cshtml | Address attribute values grid + add/edit/delete UI (with read-only mode handling). |
| src/Web/Grand.Web.Store/Areas/Store/Views/AddressAttribute/Partials/CreateOrUpdate.TabInfo.cshtml | Address attribute edit UI for info tab (with read-only mode handling). |
| src/Web/Grand.Web.Store/Areas/Store/Views/AddressAttribute/Partials/CreateOrUpdate.cshtml | Tabstrip composition for address attribute create/edit. |
| src/Web/Grand.Web.Store/Areas/Store/Views/AddressAttribute/List.cshtml | Address attributes list grid in store panel. |
| src/Web/Grand.Web.Store/Areas/Store/Views/AddressAttribute/Edit.cshtml | Address attribute edit page with read-only global preview messaging. |
| src/Web/Grand.Web.Store/Areas/Store/Views/AddressAttribute/Create.cshtml | Address attribute create page in store panel. |
| src/Web/Grand.Web.Store/Areas/Store/Views/_ViewImports.cshtml | Add store-panel model namespaces for attribute views. |
| src/Web/Grand.Web.AdminShared/Models/Customers/CustomerAttributeModel.cs | Add Stores and implement IStoreLinkModel for admin/shared model. |
| src/Web/Grand.Web.AdminShared/Models/Common/AddressAttributeModel.cs | Add Stores and implement IStoreLinkModel for admin/shared model. |
| src/Web/Grand.Web.AdminShared/Mapper/CustomerAttributeProfile.cs | Map LimitedToStores from Stores for customer attributes. |
| src/Web/Grand.Web.AdminShared/Mapper/AddressAttributeProfile.cs | Map LimitedToStores from Stores for address attributes. |
| src/Web/Grand.Web.Admin/Areas/Admin/Views/CustomerAttribute/Partials/CreateOrUpdate.TabInfo.cshtml | Add Stores selector UI to admin customer attribute edit view. |
| src/Web/Grand.Web.Admin/Areas/Admin/Views/AddressAttribute/Partials/CreateOrUpdate.TabInfo.cshtml | Add Stores selector UI to admin address attribute edit view. |
| src/Tests/Grand.Web.Tests/Validators/Customer/CustomerValidatorsStoreScopingTests.cs | Update mocks for new storeId overload on attribute warning APIs. |
| src/Tests/Grand.Mapping.Tests/AdminShared/CustomerMappingTests.CustomerAttributeModel_ToDomain.verified.txt | Snapshot update for LimitedToStores mapping output. |
| src/Tests/Grand.Mapping.Tests/AdminShared/CommonMappingTests.AddressAttributeModel_ToDomain.verified.txt | Snapshot update for LimitedToStores mapping output. |
| src/Tests/Grand.Business.Customers.Tests/Services/CustomerAttributeServiceTests.cs | Update service ctor tests for new AccessControlConfig dependency. |
| src/Tests/Grand.Business.Customers.Tests/Services/CustomerAttributeParserTests.cs | Update parser tests for store-aware attribute service call. |
| src/Tests/Grand.Business.Common.Tests/Services/Addresses/AddressAttributeServiceTests.cs | Update service ctor tests for new AccessControlConfig dependency. |
| src/Core/Grand.Domain/Customers/CustomerAttribute.cs | Add store-link properties and implement IStoreLinkEntity. |
| src/Core/Grand.Domain/Common/AddressAttribute.cs | Add store-link properties and implement IStoreLinkEntity. |
| src/Business/Grand.Business.Customers/Services/CustomerAttributeService.cs | Add store-filtered GetAllCustomerAttributes(storeId) with per-store cache keys + IgnoreStoreLimitations support. |
| src/Business/Grand.Business.Customers/Services/CustomerAttributeParser.cs | Add store-aware GetAttributeWarnings(..., storeId) overload to validate required attrs per store. |
| src/Business/Grand.Business.Core/Interfaces/Customers/ICustomerAttributeService.cs | Add storeId overload for retrieving customer attributes. |
| src/Business/Grand.Business.Core/Interfaces/Customers/ICustomerAttributeParser.cs | Add storeId overload for attribute warnings. |
| src/Business/Grand.Business.Core/Interfaces/Common/Addresses/IAddressAttributeService.cs | Add storeId overload for retrieving address attributes. |
| src/Business/Grand.Business.Core/Interfaces/Common/Addresses/IAddressAttributeParser.cs | Add storeId overload for attribute warnings. |
| src/Business/Grand.Business.Common/Services/Addresses/AddressAttributeService.cs | Add store-filtered GetAllAddressAttributes(storeId) with per-store cache keys + IgnoreStoreLimitations support. |
| src/Business/Grand.Business.Common/Services/Addresses/AddressAttributeParser.cs | Add store-aware GetAttributeWarnings(..., storeId) overload to validate required attrs per store. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- RegisterValidator/CustomerInfoValidator: always scope attribute validation to the current store instead of the per-store-identity storeId, which is empty when RegisterCustomersPerStore is disabled - Store CustomerAttribute/AddressAttribute Edit POST: repopulate Locales when redisplaying the form after a validation failure - Store ValueDelete endpoints: return a structured DataSourceResult error instead of throwing (500) when the value id is not found Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Store owners can manage their own Customer attributes and Address attributes in Grand.Web.Store. They see only global attributes (read-only preview) and attributes belonging to their store (full CRUD). Attributes limited to other stores are hidden and access is blocked at the controller level. The Stores / LimitedToStores fields are hidden in the store panel and set automatically to the staff store.
Changes
CustomerAttributeandAddressAttributeimplementIStoreLinkEntity(LimitedToStores+Stores) — existing documents remain global by default, no migration neededGetAllCustomerAttributes(storeId)/GetAllAddressAttributes(storeId)overloads with per-store cache keys, respectingAccessControlConfig.IgnoreStoreLimitationsGetAttributeWarnings(attrs, storeId)parser overloads so a required attribute of another store no longer blocks registration/checkout in the current storeCustomerAttributeControllerandAddressAttributeControllerwith full view sets, following the ContactAttribute pattern from Add store-scoped contact attribute management to Grand.Web.Store #710 (IsGlobalAttributepreview mode, ownership checks viaAccessToEntityByStore)limitedtostoresandglobalreadonlytranslation keysTests
AccessControlConfigparam), parser mocks and Verify snapshots🤖 Generated with Claude Code