PAYATHON 2026

退款后如何禁用自动生成 voucher

支付老李

结论

在 PrestaShop 的标准退款流程中,勾选 Generate a credit slip 只会生成退款单(credit slip),不会创建供客户下次购物使用的 voucher。系统只有在勾选 Generate a voucher 后,才会创建相应金额的购物优惠券。

如果没有勾选 Generate a voucher,系统却仍然生成了 voucher,通常需要排查支付模块、第三方模块或 AdminOrdersController 的 override。不要以关闭 credit slip 的方式规避问题,应找到退款流程中创建 CartRule 的代码并将其移除。

先确认生成的到底是什么

PrestaShop 中有两个容易混淆的对象:

  • Credit slip:退款凭证,通常可以生成 PDF,数据保存在 order_slip 等相关表中。
  • Voucher:客户下次下单时可以使用的优惠券,本质上是 CartRule,数据通常保存在 cart_rule、cart_rule_lang 等表中。

如果客户收到的只是退款单 PDF,这是勾选 Generate a credit slip 后的正常结果,不等于客户获得了可消费余额。

只有当后台的 Catalog → Discounts 中出现新规则,或者客户账户中出现可用于购物车的优惠码时,才能确定系统确实创建了 voucher。

检查退款请求参数

经典版 PrestaShop 的订单退款页面通常使用两个独立参数控制退款单和优惠券:

generateCreditSlip
generateDiscount

正常情况下,只生成退款单的请求应为:

$generateCreditSlip = true;
$generateDiscount = false;

可以打开浏览器开发者工具,在 Network 面板中检查退款请求。确认请求中没有以下参数,或者该参数的值为空、0:

generateDiscount

如果页面上没有勾选对应选项,但提交的请求中仍包含有效的 generateDiscount,需要检查后台模板、JavaScript 或相关模块是否改动了表单。

检查支付模块和 override

搜索退款相关代码时,重点查看是否创建并保存了 CartRule:

$cartRule = new CartRule();
$cartRule->reduction_amount = $refundAmount;
$cartRule->add();

还可以搜索以下关键词:

CartRule
generateDiscount
reduction_amount
actionProductCancel
actionOrderStatusPostUpdate
actionOrderStatusUpdate
refund

常见的检查位置有:

/modules/你的支付模块/
/override/controllers/admin/AdminOrdersController.php
/override/classes/order/
/controllers/admin/AdminOrdersController.php

具体目录和退款实现会因 PrestaShop 版本而异。核心文件可以用来对照标准流程,但不建议直接修改,因为升级时很容易被覆盖。

如果模块中有类似代码,可以删除创建 voucher 的逻辑,或者为它增加明确的配置条件:

if ((bool) Configuration::get('PAYMENT_MODULE_CREATE_REFUND_VOUCHER')) {
    $cartRule = new CartRule();

    // 仅在商店明确启用退款优惠券时设置并保存 CartRule。
    // 具体必填字段取决于当前 PrestaShop 版本。
    $cartRule->add();
}

如果退款已经通过支付渠道或线下方式返还,该配置默认应为关闭状态:

Configuration::updateValue(
    'PAYMENT_MODULE_CREATE_REFUND_VOUCHER',
    false
);

外部退款、生成 credit slip 和创建 voucher 应是三个彼此独立的操作。

排查订单状态触发逻辑

部分模块会在订单状态变为“已退款”时自动创建优惠券。例如:

public function hookActionOrderStatusPostUpdate(array $params)
{
    $newOrderStatus = $params['newOrderStatus'];

    if ((bool) $newOrderStatus->refunded) {
        $this->createRefundVoucher($params);
    }
}

如果退款已经在 PrestaShop 外部完成,应删除这段创建 voucher 的逻辑,或者至少使用单独的配置项控制它:

public function hookActionOrderStatusPostUpdate(array $params)
{
    if (!(bool) Configuration::get('PAYMENT_MODULE_CREATE_REFUND_VOUCHER')) {
        return;
    }

    $newOrderStatus = $params['newOrderStatus'];

    if ((bool) $newOrderStatus->refunded) {
        $this->createRefundVoucher($params);
    }
}

不要只根据订单状态为“已退款”就无条件创建 CartRule,否则后台手工退款、API 退款和状态同步都可能导致重复发券。

修改后清理缓存

删除或修改 override 后,需要清理 PrestaShop 缓存。可以通过后台的性能设置操作;如果项目使用命令行工具,则应采用当前版本支持的缓存清理方式。不同 PrestaShop 版本的缓存目录和控制台命令可能不同,不要直接套用。

清理后还要确认 override 是否继续生效。某些旧版本会生成类索引缓存,如果只删除源文件而不重建缓存,修改可能不会生效。

已经创建的 voucher 如何处理

修复代码不会自动撤销之前生成的 voucher。对于已经创建的优惠券,建议在后台禁用,不要直接删除数据库记录:

  1. 找到退款后生成的购物车规则。
  2. 确认它对应相关客户和订单。
  3. 将状态改为禁用。
  4. 检查优惠券是否已经使用。

如果优惠券已经被使用,不应直接删除,以免影响历史订单的核对和审计。

注意事项

  • 不要修改 PrestaShop 核心控制器来强制关闭 voucher,应优先修复模块或 override。
  • 不要将 credit slip 和 voucher 混为一谈。credit slip 是退款凭证,通常可以保留。
  • 部分退款可能多次触发退款事件,模块需要避免重复创建优惠券或重复执行外部退款。
  • 修改前应确认 PrestaShop 的具体版本,并检查是否安装了退货、钱包、积分或店铺余额模块。这些模块也可能在退款后创建可用余额,来源不一定是支付模块。
  • 如果标准请求中的 generateDiscount 为假,代码中也没有执行 CartRule::add(),还需要检查第三方模块注册的退款或订单状态 hooks。

备注:内容仅供参考。