PAYATHON 2026

Intershop 7.10 如何实现零金额购物车免支付结账

支付阿杰

结论

Intershop 7.10 没有通用 preference,无法让零金额 basket 在完全不设置 payment method 的情况下直接创建订单。

即使 Total Amount 为 0,标准订单创建流程仍会校验 basket 的支付信息,并查找适用的 payment method。如果找不到,就会抛出:

No payment method is applicable for basket

更稳妥的做法是配置或开发一个零金额订单专用的 payment method,例如 Free Order 或 Zero Payment。这个方式不处理真实支付,只用于满足结账流程和订单模型对支付方式的要求。

为什么金额为 0 仍然需要 payment method

在 Intershop 7.10 的标准流程中,“是否需要扣款”和”订单是否需要支付方式”是两个不同的判断。

金额为 0 只表示:

payment amount = 0

订单创建时仍可能执行以下检查:

  • basket 是否有适用的 payment method;
  • 当前 payment method 是否适用于该 basket;
  • 是否可以创建 payment instrument 或 payment transaction;
  • basket 的支付分配是否完整;
  • 支付数据能否复制到订单。

所以,不能因为 Total Amount == 0 就认定 payment method 可以为空。报错来自 PaymentServiceBORepositoryImpl,说明流程失败在支付方式适用性检查阶段,而不是实际扣款阶段。

推荐方案:提供零金额支付方式

可以为零金额订单提供一个不接入外部支付处理的 payment method,并限制它只能用于待支付金额为零的 basket。

这个支付方式通常需要满足以下条件:

  • 只在待支付金额为 0 时适用;
  • 不显示信用卡、银行账户等输入字段;
  • 不调用 PSP;
  • 不执行 authorization、capture 或 refund;
  • 在订单中保留明确的支付类型,例如 ZERO_PAYMENT;
  • 不能用于非零金额 basket。

storefront 可以自动选择这个方式,并跳过常规的 payment method 选择页面。这里的”跳过”是指客户无须手工选择,basket 中仍然需要设置 payment method。

零金额判断

判断依据应该是最终待支付金额,而不是商品小计。折扣、运费、税费、礼品卡和舍入都可能改变最终金额。

示意代码如下:

Money payableAmount = basket.getTotal();

boolean isZeroAmount =
        payableAmount != null
        && payableAmount.getValue().signum() == 0;

实际项目中,需要将其替换为当前 7.10 定制层使用的 basket API。不要通过字符串或 double 比较金额,例如:

// 不推荐
basket.getTotal().getValue().doubleValue() == 0.0;

如果业务允许出现负金额 basket,还需要单独处理,不能将所有”小于等于零”的情况都当作免费订单。

结账流程中的处理方式

在进入 payment selection 前检查最终金额。如果金额为零,就自动写入专用 payment method,然后进入下一步:

if (isZeroAmount(basket)) {
    assignZeroPaymentMethod(basket);
    validateBasket(basket);
    continueCheckout();
} else {
    showPaymentMethodSelection();
}

assignZeroPaymentMethod 的具体实现取决于项目采用的支付框架和 cartridge。重点是通过标准 payment service 将支付方式或 payment instrument 关联到 basket,而不是只写入一个自定义属性:

private void assignZeroPaymentMethod(Basket basket) {
    PaymentMethod zeroPayment = findPaymentMethod("ZERO_PAYMENT");

    if (zeroPayment == null || !zeroPayment.isApplicable(basket)) {
        throw new IllegalStateException(
            "ZERO_PAYMENT is not configured for the current application"
        );
    }

    setBasketPaymentMethod(basket, zeroPayment);
}

上面的类名和方法仅用于说明处理逻辑,并不是可以在 Intershop 7.10 中原样编译的公共 API。实际实现需要根据项目使用的 BasketBO、payment instrument 和 payment service 接口进行适配。

支付方式的适用性规则

零金额支付方式至少要检查以下条件:

public boolean isApplicable(Basket basket) {
    Money amount = basket.getTotal();

    return amount != null
        && amount.getValue().signum() == 0;
}

同时还要确认它已在以下范围内启用:

  • 当前 channel;
  • 当前 application;
  • 当前 currency;
  • 当前 customer type;
  • 当前 shipping destination;
  • 当前 basket 类型。

如果 payment method 已经创建,却没有分配给对应的 channel 或 application,创建订单时仍可能出现相同的错误。

是否可以彻底不设置 payment method

技术上可以,但需要定制订单创建和支付校验流程,无法通过 preference 调整实现。

至少需要同步修改:

  • basket 支付完整性校验;
  • applicable payment method 查询;
  • basket 到 order 的支付数据复制;
  • order creation validation;
  • 后续订单处理、导出和状态流转;
  • 取消、退货、退款以及客服后台对支付信息的处理。

只绕过抛出异常的那一处检查通常解决不了问题。后续代码、订单导出接口或 OMS 集成仍可能默认订单带有支付方式。除非整个订单链路都明确支持”无支付信息订单”,否则不建议将 payment method 设为 null。

Storefront 展示建议

对客户来说,零金额订单不需要展示可操作的支付步骤。可以采用以下流程:

  1. 重新计算并验证 basket。
  2. 确认最终待支付金额为 0。
  3. 后台自动设置 ZERO_PAYMENT。
  4. 隐藏或跳过支付方式选择页面。
  5. 在订单确认页显示”无需支付”或”免费订单”。

这样既符合客户预期,也能保留 Intershop 标准订单模型要求的支付信息。

注意事项

  • 必须等促销、税费、运费和舍入全部计算完成后,再判断金额是否为零。
  • 不要用普通支付方式处理 0 金额,部分 PSP 会拒绝零金额 authorization。
  • ZERO_PAYMENT 不能用于任何正金额订单。
  • basket 重新计算后,如果金额从 0 变为正数,需要清除该支付方式并要求客户重新选择。
  • 如果订单通过礼品卡或余额抵扣到零,需要区分”免费订单”和”已由储值工具全额支付”。两者的财务记录通常不同。
  • 上线前需要覆盖匿名客户、注册客户、不同币种、促销、免运费、税费调整、订单取消和退货等场景。

因此,在 Intershop 7.10 中,推荐的处理方式不是让 payment method 缺失,而是为零金额 basket 自动设置一个不会触发真实支付处理的专用 payment method。

备注:内容仅供参考。