PAYATHON 2026

NopCommerce 4.2 门店自提时隐藏 Cash On Delivery

支付小周

结论

在 nopCommerce 4.2 中,客户提交门店自提选项后,系统会将选中的 PickupPoint 保存到当前客户的通用属性 NopCustomerDefaults.SelectedPickupPointAttribute。

因此,HidePaymentMethod 无需读取页面上的单选框。取得当前客户的 PickupPoint 后,如果结果不为 null,返回 true 即可隐藏 Cash On Delivery。原有的“购物车是否需要配送”判断仍需保留。

修改方式

在支付插件中注入以下两个服务:

  • IWorkContext:用于取得当前客户。
  • IStoreContext:用于取得当前店铺 ID。

同时引入客户、配送和通用属性相关的命名空间:

using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Shipping;
using Nop.Services.Common;

添加字段

private readonly IStoreContext _storeContext;
private readonly IWorkContext _workContext;

修改构造函数

public CashOnDeliveryPaymentProcessor(
    CashOnDeliveryPaymentSettings cashOnDeliveryPaymentSettings,
    ILocalizationService localizationService,
    IPaymentService paymentService,
    ISettingService settingService,
    IShoppingCartService shoppingCartService,
    IWebHelper webHelper,
    IStoreContext storeContext,
    IWorkContext workContext)
{
    _cashOnDeliveryPaymentSettings = cashOnDeliveryPaymentSettings;
    _localizationService = localizationService;
    _paymentService = paymentService;
    _settingService = settingService;
    _shoppingCartService = shoppingCartService;
    _webHelper = webHelper;
    _storeContext = storeContext;
    _workContext = workContext;
}

nopCommerce 的依赖注入容器通常会自动提供这两个服务,无需额外注册。

修改 HidePaymentMethod

public bool HidePaymentMethod(IList<ShoppingCartItem> cart)
{
    var pickupPoint = _workContext.CurrentCustomer.GetAttribute<PickupPoint>(
        NopCustomerDefaults.SelectedPickupPointAttribute,
        _storeContext.CurrentStore.Id);

    if (pickupPoint != null)
        return true;

    return _cashOnDeliveryPaymentSettings.ShippableProductRequired &&
           !_shoppingCartService.ShoppingCartRequiresShipping(cart);
}

也可以把两个条件合并到一个返回表达式中:

public bool HidePaymentMethod(IList<ShoppingCartItem> cart)
{
    var pickupPoint = _workContext.CurrentCustomer.GetAttribute<PickupPoint>(
        NopCustomerDefaults.SelectedPickupPointAttribute,
        _storeContext.CurrentStore.Id);

    return pickupPoint != null ||
           (_cashOnDeliveryPaymentSettings.ShippableProductRequired &&
            !_shoppingCartService.ShoppingCartRequiresShipping(cart));
}

为什么不能直接读取单选框

系统在生成可用支付方式列表时会调用 HidePaymentMethod。此时通常已经离开配送方式的提交阶段,当前请求未必还包含 pickupInStore 单选框字段。

客户提交门店自提选择后,nopCommerce 会把 PickupPoint 保存到当前客户的通用属性中。直接读取客户属性更可靠,也符合结账流程保存数据的方式。

需要注意的地方

门店自提选项必须已经成功提交。如果只在浏览器中点击单选框,尚未保存或刷新结账页面,服务器端就无法读取新的选择。

如果项目使用的 nopCommerce 4.2 源码要求为 GetAttribute 显式传入服务参数,还需要注入 IGenericAttributeService,并改为:

var pickupPoint = _workContext.CurrentCustomer.GetAttribute<PickupPoint>(
    _genericAttributeService,
    NopCustomerDefaults.SelectedPickupPointAttribute,
    _storeContext.CurrentStore.Id);

请以当前项目引用的 nopCommerce 4.2 源码所提供的具体重载为准。

完成修改后,需要重新编译 Nop.Plugin.Payments.CashOnDelivery,将生成结果部署到对应的插件目录,然后重启应用或重新加载插件。测试时至少要覆盖以下两种情况:

  • 选择普通配送:Cash On Delivery 按原配置显示。
  • 选择 Pick-up in store:支付方式列表中不再显示 Cash On Delivery。

备注:内容仅供参考。