Ucommerce
  • Ucommerce Next Gen
    • Getting Started
      • Prerequisites
      • Licensing
      • Ucommerce Templates
      • Headless Template
      • MVC Template
    • Headless
      • Postman Collection
      • Headless API Authentication
        • Token endpoint - Authorization Header
        • Authorization Scopes
        • Refreshing the Access Token
      • Reference
        • Cart
        • Cart / Order Line Items
        • Shipment
        • Billing
        • Promotion Codes
        • Price Groups
        • Payment Methods
        • Countries
        • Shipping Methods
        • Catalogs
        • Cart Custom Properties
        • Line Item Custom Properties
        • Orders
        • Views for Cart modifying operations
      • Custom Headless APIs
      • Error Handling
      • Pagination
      • Deprecation
    • Backoffice Authentication
      • Microsoft Entra ID Example
      • Auth0 Authentication Example
    • Definitions
      • What is a Definition
    • Search and indexing
      • Configuration
      • Indexing
        • Index Definitions
        • Facets
        • Indexing Prices
        • Suggestions
        • Custom Data
      • Searching
    • Payment Providers
      • Stripe Provider Integration
      • Implementing a custom payment provider
    • Data Import
    • Miscellaneous
      • Media
      • Price Group Inheritance
      • Price Group Criteria
      • Soft Deletion Of Entities
      • Logging
      • OpenTelemetry
    • Extensions
      • Extending Pipelines
        • Order Processing Pipelines
        • Checkout Pipelines
      • Changing Service Behavior
        • Images
        • Content
      • Custom Headless APIs
      • Extend the Backoffice
        • Custom UI Components
      • Custom Editor UI
      • Custom Promotion Criteria
      • Custom Price Group Criteria
    • How-To
      • Migrate from Classic
        • Common database issues
      • Entities from code
        • Bootstrapping data on startup
        • Product Definitions & Fields
      • Discover pipelines and their tasks
      • Executing a pipeline
    • Integrations
      • Umbraco Media Delivery API
      • App Slices
        • Product Picker
  • Release Notes
  • Contact Us
Powered by GitBook
On this page
  • Create a Custom Criterion
  • Creating a Definition
  • Implementing a Pipeline Task for Satisfaction Check
  • Validation (Optional)
  • Test that it works
  • Tips for Reusability

Was this helpful?

  1. Ucommerce Next Gen
  2. Extensions

Custom Price Group Criteria

Price group criteria in Ucommerce are used to determine the accessibility of a price group.

Ucommerce has a few built-in criteria to control the context in which a price group is valid. However, if the need arises, it's quite easy to create a custom criterion.

Create a Custom Criterion

Creating a Definition

To create a definition, follow these steps:

  1. Create a definition and add it to your database. The definition must be of the price group criterion definition type.

  2. Add appropriate definition fields to it. Built-in Ucommerce data types will work out of the box.

  3. If you wish to be able to reuse the criterion for future projects we recommend you create a background service to automate this process.

Example: Member-Based Criterion

Below is an example of setting up a criterion that triggers for a specific member:

public class SetupPriceGroupMemberCriterion : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;

    /// <inheritdoc />
    public SetupPriceGroupMemberCriterion(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    /// <inheritdoc />
    protected override async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        await using var asyncScope = _serviceProvider.CreateAsyncScope();
        var dbContext = asyncScope.ServiceProvider.GetRequiredService<UcommerceDbContext>();
        if (dbContext.Set<DefinitionEntity>()
            .Any(x => x.Name == "Member Criterion"))
        {
            return;
        }

        // Set up data using dbContext
        // Find the ShortText data type
        var dataType = dbContext.Set<DataTypeEntity>()
            .FirstOrDefault(x => x.Guid.ToString() == "2d65650b-810a-47d3-8431-a0608a853fed");
        var defFields = new List<DefinitionFieldEntity>
        {
            new()
            {
                Name = "Member",
                DataType = dataType,
                DisplayOnSite = true,
                RenderInEditor = true,
                Guid = Guid.Parse("b4f2b61e-7f71-4fba-a587-3c6ab8a701fe")
            }
        };

        dbContext.Set<DefinitionEntity>()
            .Add(new DefinitionEntity
            {
                BuiltIn = false,
                Description = "Member-based price group criterion",
                Name = "Member Criterion",
                DefinitionTypeId = 94868, //Id of the Price Group Criterion Definition Type
                DefinitionFields = defFields,
                Guid = Guid.Parse("b846d509-d1fb-4688-9db1-a23a4a6c66e1")
            });

        await dbContext.SaveChangesAsync(cancellationToken);
    }
}  

Using explicit GUIDs makes subsequent steps easier.

Background services are run on every startup, so it is important to have a check to prevent multiple additions of the same values.

Implementing a Pipeline Task for Satisfaction Check

To trigger a criterion we need to extend the CheckPriceGroup pipeline with a pipeline task that checks whether the criterion is satisfied. There are three unique concepts to be aware of regarding this task:

  • PriceGroupCriterionDTO is a DTO connecting a criterion with its properties.

  • context.Output.PriceGroupCriteriaDtos iis a dictionary of PriceGroupCriterionDTO grouped by their definition.

  • context.Output.SatisfiedCriteria is a list of satisfied criteria. Add the criterion to this list if it's satisfied.

Remember to register your pipeline task through the pipeline builder.

Example

Here’s an example of a pipeline task that checks if the member criterion is satisfied. It compares the member ID provided in the input with the ID associated with the criterion.

public class CheckPriceGroupMemberCriterionTask : AbstractPipelineTask<CheckPriceGroupInput, CheckPriceGroupOutput>
{
    public override Task Execute(PipelineContext<CheckPriceGroupInput, CheckPriceGroupOutput> context, CancellationToken cancellationToken)
    {
        //Checks if the correct query parameter is given
        if (!context.Input.FilterProperties.ContainsKey("Member"))
        {
            return Task.CompletedTask;
        }

        //Checks if the member criteria is in the list of criteria, using the guid of the definition
        if (!context.Output.PriceGroupCriteriaDtos.TryGetValue(
                Guid.Parse("b846d509-d1fb-4688-9db1-a23a4a6c66e1"),
                out var allMemberCriteria))
        {
            return Task.CompletedTask;
        }

        foreach (var memberCriterion in allMemberCriteria)
        {
            var member = memberCriterion.Properties["b4f2b61e-7f71-4fba-a587-3c6ab8a701fe"]
                .Value; //Guid of the definition field "Member"

            if (context.Input.FilterProperties["Member"] == member)
            {
                context.Output.SatisfiedCriteria = context.Output.SatisfiedCriteria
                    .Add(memberCriterion.Criterion);
            }
        }

        return Task.CompletedTask;
    }
}

Validation (Optional)

It is possible to set validation rules for a criterion using FluentValidation. To make this easier, inherit from UpdateCriterionInputValidatorBase in namespace Ucommerce.Web.BackOffice.Validators.PriceGroups.Criteria.UpdateCriteria to set rules for your custom criteria.

UpdateCriterionInputValidatorBase contains the method RuleForUpdatePropertyValue(string propertyName) where propertyName is the definition field´s name.

After creating a validator it needs to be registered as a service in the program.cs file.

Example

Here's an example of custom rules for the Member-based criterion that was created earlier.

public class UpdateCriteriaBuyAtMostCriteriaValidator : UpdateCriteriaInputValidatorBase
{
    /// <summary>
    /// Initializes a new instance of the <see cref="UpdateCriteriaQuantityCriteriaValidator"/> class.
    /// </summary>
    public UpdateCriterionMemberCriterionValidator()
        : base("b846d509-d1fb-4688-9db1-a23a4a6c66e1")
    {
        RuleForUpdatePropertyValue("Member")
            .Required()
            .IsEmail();
    }
}

RuleForUpdatePropertyValue is case sensitive so the string must exactly match the definition field name in the database.

Test that it works

Ensure the query parameter key matches the key in your pipeline task, and the value represents the user, e.g.:

GET {base_url}/api/v1/price-groups?filters-member=member@gmail.com&
    cultureCode="en-US"

This endpoint returns price groups related to the store you are authenticating with, in order to see your price group, it should be in the allowed price groups list of a catalog on your store.

If the criterion is set up correctly, the price group will appear in the returned list only if the correct query parameter is provided. If the price group has a derived price group that is also accessible, only the deepest accessible price group will be shown.

Tips for Reusability

To facilitate reuse of a custom criterion across projects, it is recommended to create an extension method that registers the needed services.

This is an example of a method for registering the different parts of a custom criterion:

public static IUcommerceBuilder AddPriceGroupMemberCriterion(this IUcommerceBuilder builder)
{
    builder.PipelineBuilder.InsertLast<
        IPipelineTask<CheckPriceGroupInput, CheckPriceGroupOutput>, 
        CheckPriceGroupMemberCriterionTask>();
    builder.Services.AddHostedService<SetupPriceGroupMemberCriterion>();
    return builder;
}

That way, it is now possible to add the criterion to any Ucommerce solution like this:

var ucommerceBuilder = builder.Services
    .AddUcommerce(builder.Configuration)
    .AddBackOffice()
    .AddWebSite()
    .AddInProcess<RouteParser>()
    .UcommerceBuilder
    .AddPriceGroupMemberCriterion(); //Here
PreviousCustom Promotion CriteriaNextHow-To

Last updated 5 months ago

Was this helpful?

After setting up the member-based criterion in the backoffice with a value (e.g., member@gmail.com), test its functionality by calling the headless endpoint for retrieving price groups. The endpoint accepts filter-* query parameters as described in the and converts them into the property dictionary used in the pipeline.

Remember that calling headless endpoints will require .

Price Groups reference
authentication