# Implementing Member Based Pricing

By default, Umbraco Commerce uses a single price for a product. However, in some cases, you may want to have different prices for different customers. In this guide, you learn how to implement member-based pricing in Umbraco Commerce.

## Member Configuration

1. Creating the Member Groups to use for the member-based pricing. In this example two member groups are created: *Platinum* and *Gold*.

![Member Groups](https://3343668521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlHETtFOx4I72xhuc27Kt%2Fuploads%2Fgit-blob-f88b51aefa58fa8198444d5e4ab91895f3069780%2Fmember-groups.png?alt=media)

2. Create one Member for each group:

![Members](https://3343668521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlHETtFOx4I72xhuc27Kt%2Fuploads%2Fgit-blob-df2ae3c3f4a26d9d419089c1cae4d57845be9771%2Fmembers.png?alt=media)

## Property Editor Configuration

Next, you will create a new property editor for the member-based pricing. The in-built Block List Editor is used for this.

1. Create a `Member Price` element type with a `Price` and `Member Group` property.
2. Use the default Umbraco Commerce `Price` property editor for the `Price` property.
3. Use the in-built `Member Group Picker` property editor for the `Member Group` property.

![Member Price Element](https://3343668521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlHETtFOx4I72xhuc27Kt%2Fuploads%2Fgit-blob-60e32ee00ae2847065da5dfbc1c234720e1f5520%2Fmember-price-element.png?alt=media)

4. Open the **Product** Document Type.
5. Add a new `Member Price` property using a new Block List Property editor configuration.
6. Select the `Member Price` element type as the only allowed block type.

![Member Price Block List Configuration](https://3343668521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlHETtFOx4I72xhuc27Kt%2Fuploads%2Fgit-blob-8745ed31db393d7ad09da8eef4b0de617a6c6d77%2Fmember-price-block-list.png?alt=media)

7. Navigate to the Content section.
8. Assign member-based pricing for any product you wish.
9. Populate the `Member Price` field with the required Member Group and price combination.

![Member Group Price](https://3343668521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlHETtFOx4I72xhuc27Kt%2Fuploads%2Fgit-blob-63c5623b01a652d3080dc64bd044b7243908fe44%2Fmember-price-content.png?alt=media)

## Product Adapter

With the prices defined, it's time to configure Umbraco Commerce to select the correct price based on the logged-in Member. This is done by creating a custom product adapter to override the default product adapter and select the correct price.

{% code title="MemberPricingProductAdapter.cs" %}

```csharp
public class MemberPricingProductAdapter : UmbracoProductAdapter
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IMemberService _memberService;
    private readonly IMemberGroupService _memberGroupService;
    private readonly UmbracoCommerceContext _umbracoCommerce;

    public MemberPricingProductAdapter(
        IUmbracoContextFactory umbracoContextFactory, 
        IContentService contentService, 
        PublishedContentWrapperFactory publishedContentWrapperFactory, 
        IExamineManager examineManager, 
        PublishedContentHelper publishedContentHelper, 
        IUmbracoProductNameExtractor umbracoProductNameExtractor, 
        UmbracoCommerceServiceContext services,
        IHttpContextAccessor httpContextAccessor,
        IMemberService memberService,
        IMemberGroupService memberGroupService,
        UmbracoCommerceContext umbracoCommerce) 
        : base(umbracoContextFactory, contentService, publishedContentWrapperFactory, examineManager, publishedContentHelper, umbracoProductNameExtractor, services)
    {
        _httpContextAccessor = httpContextAccessor;
        _memberService = memberService;
        _memberGroupService = memberGroupService;
        _umbracoCommerce = umbracoCommerce;
    }

    public override async Task<IProductSnapshot> GetProductSnapshotAsync(Guid storeId, string productReference, string productVariantReference, string languageIsoCode, CancellationToken cancellationToken = default)
    {
        var baseSnapshot = (UmbracoProductSnapshot)await base.GetProductSnapshotAsync(storeId, productReference, productVariantReference, languageIsoCode, cancellationToken);

        if (_httpContextAccessor.HttpContext?.User.Identity is { IsAuthenticated: true }
            && baseSnapshot is { Content: Product { MemberPrice: not null } productPage }
            && productPage.MemberPrice.Any())
        {
            var memberId = _httpContextAccessor.HttpContext.User.Claims.First(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var memberGroupName = _memberService.GetAllRoles(int.Parse(memberId)).First();
            var memberGroupId = (await _memberGroupService.GetByNameAsync(memberGroupName))!.Id;

            var memberPrice = productPage.MemberPrice
                .Select(x => x.Content as MemberPrice)
                .FirstOrDefault(x => int.Parse(x.MemberGroup) == memberGroupId);
                
            if (memberPrice != null)
            {
                var list2 = new List<ProductPrice>();

                var currencies = await _umbracoCommerce.Services.CurrencyService.GetCurrenciesAsync(baseSnapshot.StoreId);
                foreach (var currency in currencies)
                {
                    var productPrice = memberPrice.Price!.TryGetPriceFor(currency.Id);
                    if (memberPrice.Price != null && productPrice.Success)
                    {
                        list2.Add(new ProductPrice(productPrice.Result!.Value, productPrice.Result.CurrencyId));
                    }
                }

                baseSnapshot.Prices = list2;
            }
        }
        
        return baseSnapshot;
    }
}
```

{% endcode %}

Add the following to a `Composer` file to register the custom product adapter:

{% code title="SwiftShopComposer.cs" %}

```csharp
internal class SwiftShopComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.Services.AddUnique<IProductAdapter, MemberPricingProductAdapter>();
    }
}
```

{% endcode %}

## Results

With all this implemented, the product page will display the correct price based on the logged-in Member.

The expected result for the standard product page:

![Default Product Page](https://3343668521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlHETtFOx4I72xhuc27Kt%2Fuploads%2Fgit-blob-ffa83f9cda281af0bd1c5e302e7ffdcdc84f6b92%2Fdefault-product-page.png?alt=media)

The expected result for a *Gold* Member:

![Gold Product Page](https://3343668521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlHETtFOx4I72xhuc27Kt%2Fuploads%2Fgit-blob-a166635ac83c344c44c86f199d8c732856052594%2Fgold-product-page.png?alt=media)

The expected result for a *Platinum* Member:

![Platinum Product Page](https://3343668521-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlHETtFOx4I72xhuc27Kt%2Fuploads%2Fgit-blob-89818a94277546314f4a1198e0a48c8f31aa6b9d%2Fplatinum-product-page.png?alt=media)
