При работе с Оптимизировать Commerce Connectвстроенный конвейер ценообразования автоматически проверяет и обновляет данные каждой позиции. PlacedPrice по ценам каталога.
Это отлично подходит для обычных SKU, но что, если ваша бизнес-модель позволяет введенные пользователем суммытакой как пожертвования, суммы подарковили плати сколько хочешь продукты?
По умолчанию поток проверки Commerce перезаписывает пользовательскую цену на цену каталога по умолчанию при каждой проверке или сохранении корзины.
В этом посте вы узнаете, как продлевать IPlacedPriceProcessor чтобы Optimizely не заменял цены, определенные пользователем, сохраняя при этом остальную систему ценообразования.
Понимание роли IPlacedPriceProcessor
IPlacedPriceProcessor — это компонент, отвечающий за получение и назначение правильной цены по каталогу позиции при ее добавлении в корзину или проверке.
Реализация по умолчанию (PlacedPriceProcessor) выполняется во время конвейера проверки корзины:
// Called internally by DefaultOrderGroupValidator
_placedPriceProcessor.UpdatePlacedPrice(lineItem, customerContact, marketId, currency, onValidationError);
Это гарантирует, что для каждого продукта будет указана действительная каталожная цена, но это также означает, что любая установленная вручную цена lineItem.PlacedPrice значения заменяются.
Для поддержки цен, вводимых пользователем (например, пожертвований), мы можем заменять этот процессор позволяет пропустить переоценку, когда мы знаем, что цена поступила непосредственно из пользовательского интерфейса.
Сценарий пожертвования
Представьте себе блок «Подари подарок» на вашем сайте, который позволяет жертвователям:
- Выберите повод (вариант)
- Выберите получателя
- Введите индивидуальная сумма пожертвования
- Нажмите «Отправить подарок», чтобы добавить его в корзину.
Когда пожертвование попадает в корзину Commerce, конвейер работает, и если мы его не остановим, наш PlacedPrice (например, 25 долларов США, введенные донором) заменяются ценой по каталогу по умолчанию (например, 10 долларов США из прайс-листов).
Решение: индивидуальный подход IPlacedPriceProcessor
Самый чистый и безопасный способ сохранить введенные пользователем цены — это обернуть значение по умолчанию IPlacedPriceProcessor с вашей собственной реализацией.
Это позволяет сократить поиск по каталогу, когда позиция имеет специальный флаг (например, IsCustomPrice).
Выполнение
// /Features/Commerce/Pricing/CustomPlacedPriceProcessor.cs
using System;
using EPiServer.Commerce.Catalog.ContentTypes;
using EPiServer.Commerce.Order;
using Mediachase.Commerce;
using Mediachase.Commerce.Customers;
namespace YourProject.Features.Commerce.Pricing
{
public class CustomPlacedPriceProcessor : IPlacedPriceProcessor
{
public const string IsCustomPriceKey = "IsCustomPrice";
private readonly IPlacedPriceProcessor _inner;
public CustomPlacedPriceProcessor(IPlacedPriceProcessor inner)
{
_inner = inner ?? throw new ArgumentNullException(nameof(inner));
}
private static bool IsCustom(ILineItem lineItem)
{
if (lineItem == null) return false;
if (lineItem.Properties.ContainsKey(IsCustomPriceKey))
{
var val = lineItem.Properties[IsCustomPriceKey];
return val is bool b && b && lineItem.PlacedPrice > 0m;
}
return false;
}
public bool UpdatePlacedPrice(
ILineItem lineItem,
CustomerContact customerContact,
MarketId marketId,
Currency currency,
Action onValidationError)
{
// Skip catalog price lookup for user-defined amounts
if (IsCustom(lineItem))
{
return true; // consider price valid as-is
}
return _inner.UpdatePlacedPrice(lineItem, customerContact, marketId, currency, onValidationError);
}
public Money? GetPlacedPrice(
EntryContentBase entry,
decimal quantity,
CustomerContact customerContact,
MarketId marketId,
Currency currency)
{
// delegate for all non-custom cases
return _inner.GetPlacedPrice(entry, quantity, customerContact, marketId, currency);
}
}
}
Регистрация собственной реализации
context.Services.Intercept((locator, defaultImplementation) =>
new CustomPlacedPriceProcessor(defaultImplementation));
Маркировка позиций с индивидуальной ценой
При создании или обновлении корзины (например, в вашем CartService или контроллер), отметьте любую строку, в которой не должны быть указаны цены по каталогу:
if (request.PlacedPrice.HasValue && request.PlacedPrice.Value > 0)
{
lineItem.PlacedPrice = request.PlacedPrice.Value;
lineItem.Properties[CustomPlacedPriceProcessor.IsCustomPriceKey] = true;
}
Этот флаг сообщает вашему процессору: «Не перезаписывайте это значение — оно уже правильное».
Что происходит сейчас
Когда корзина подтверждена:
DefaultOrderGroupValidatorзвонки_placedPriceProcessor.UpdatePlacedPrice(...).- Ваша реализация видит
IsCustomPriceфлаг. - Он возвращает
trueнемедленно — внутренний процессор никогда не запускается. - Введенная сумма донора остается нетронутой.
- Остальные цены, скидки и налоговые расчеты продолжаются в обычном режиме.
Почему это правильная точка расширения
Многие разработчики сначала пытаются переопределить ILineItemCalculator или изменить корзину после проверки, но это реактивный и хрупкий процесс.
Изменение IPlacedPriceProcessor работает в источник — именно тот момент, когда Optimizely устанавливает цену — и полностью интегрируется с существующим сервисным конвейером.
Продолжение темы

