Skip to content

退款异常(REFUND.ABNORMAL)通知(JSON)

退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【平台—>交易中心】,手动处理此笔退款

注意:

  • 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是,当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理;如果已处理,则直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
  • 如果在所有通知频率后没有收到微信侧回调,商户应调用查询订单接口确认订单状态。
  • 特别提醒:商户系统对于开启结果通知的内容一定要做签名验证,并校验通知的信息是否与商户侧的信息一致,防止数据泄露导致出现“假通知”,造成资金损失。
  • 商户退款完成后,微信会把相关退款结果和用户信息发送给清算机构,清算机构需要接收处理后返回应答成功,然后继续给异步通知到下游从业机构。
  • 对后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。(通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m)
请求参数类型描述
headersobject通知的头参数
Content-Typestringapplication/json
Request-IDstring通知的唯一标识
Wechatpay-Noncestring数据签名使用的随机串
Wechatpay-Serialstring微信支付公钥ID/平台证书序列号
Wechatpay-Signaturestring签名串
Wechatpay-Signature-Typestring签名算法
WECHATPAY2-SHA256-RSA2048 枚举值
Wechatpay-Timestampstring时间戳
bodyobject通知的JSON数据结构
idstring通知的唯一ID
create_timestring通知创建的时间
event_typestring通知的类型
REFUND.ABNORMAL 枚举值
resource_typestring通知的资源数据类型
summarystring回调摘要
resourceobject通知资源数据
algorithmstring对数据进行加密的加密算法
AEAD_AES_256_GCM 枚举值
associated_datastring数据加密的附加数据
noncestring加密使用的随机串
ciphertextstring加密后的密文数据
original_typestring原始回调类型
sp_mchidstring服务商户号,由微信支付生成并下发 。
sub_mchidstring子商户的商户号,由微信支付生成并下发。
out_trade_nostring返回的商户订单号
transaction_idstring微信支付订单号
out_refund_nostring商户退款单号
refund_idstring微信退款单号
refund_statusstring退款状态
SUCCESS | CLOSED | ABNORMAL 枚举值之一
success_timestring1、退款成功时间
user_received_accountstring取当前退款单的退款入账方。
1、退回银行卡:{银行名称}{卡类型}{卡尾号}
2、退回支付用户零钱: 支付用户零钱
3、退还商户: 商户基本账户、商户结算银行账户
4、退回支付用户零钱通:支付用户零钱通
5、退回用户经营账户:用户经营账户
6、退回支付用户银行电子账户:支付用户银行电子账户
7、退回支付用户零花钱:支付用户零花钱
8、退回支付用户来华零钱包:支付用户来华零钱包
9、退回企业支付商户:企业支付商户
amountobject金额信息
totalnumber订单总金额,单位为分,只能为整数
refundnumber退款金额,币种的最小单位,只能为整数,不能超过原订单支付金额,如果有使用券,后台会按比例退。
payer_totalnumber用户实际支付金额,单位为分,只能为整数
payer_refundnumber退款给用户的金额,不包含所有优惠券金额
mchidstring普通商户的商户号,由微信支付生成并下发。
refund_accountstring电商平台垫资退款专用参数
REFUND_SOURCE_PARTNER_ADVANCE | REFUND_SOURCE_SUB_MERCHANT 枚举值之一
individual_auth_idstring个人收款的微信支付账户,微信用户在该平台的标志
  1. 平台收付通-个人收款场景会返回individual_auth_id字典
php
// 使用Psr标准规范,示例如何处理(取值、验签、解密)「回调通知」事件,WebServer不同,用法略有差异,供参考实现。
function webhookProcessor(\Psr\Http\Message\RequestInterface $request,
  array $platformPublicKeyMap, string $apiv3Key): array {
  if (!\count($platformPublicKeyMap)) {
    throw new \WeChatPay\Exception\InvalidArgumentException('平台证书或者平台公钥数组不能为空');
  }

  if (\strlen($apiv3Key) !== 32) {
    throw new \WeChatPay\Exception\InvalidArgumentException('APIV3密钥为32字节,长度不对');
  }

  if (!($request->hasHeader(\WeChatPay\WechatpayNonce)
    && $request->hasHeader(\WeChatPay\WechatpaySerial)
    && $request->hasHeader(\WeChatPay\WechatpaySignature)
    && $request->hasHeader(\WeChatPay\WechatpayTimestamp))) {
    throw new \WeChatPay\Exception\InvalidArgumentException('通知的头参数缺失必要参数');
  }

  // 检查通知的时间偏移量,允许5分钟之内的偏移
  [$inWechatpayTimestamp] = $request->getHeader(\WeChatPay\WechatpayTimestamp);
  if (\WeChatPay\MAXIMUM_CLOCK_OFFSET < \abs(
    \WeChatPay\Formatter::timestamp() - (int)$inWechatpayTimestamp)) {
    throw new \WeChatPay\Exception\InvalidArgumentException('通知头参数的时间偏移量超过可信阈值');
  }

  // 检查通知的平台证书/平台公钥实例是否存在
  [$inWechatpaySerial] = $request->getHeader(\WeChatPay\WechatpaySerial);
  if (!\array_key_exists($inWechatpaySerial, $platformPublicKeyMap)) {
    throw new \WeChatPay\Exception\InvalidArgumentException('通知头参数的证书序列号/公钥ID本地不存在');
  }

  // 验证通知的数据签名
  [$inWechatpaySignature] = $request->getHeader(\WeChatPay\WechatpaySignature);
  [$inWechatpayNonce] = $request->getHeader(\WeChatPay\WechatpayNonce);
  $inBody = (string)$request->getBody();
  if (!\WeChatPay\Crypto\Rsa::verify(
    \WeChatPay\Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
    $inWechatpaySignature, $platformPublicKeyMap[$inWechatpaySerial]
  )) {
    throw new \WeChatPay\Exception\InvalidArgumentException('通知头参数的数据签名校验未通过');
  }

  // 转换通知的JSON文本消息为PHP Array数组
  $inBodyArray = (array)\json_decode($inBody, true);
  // 使用PHP7+的数据解构语法,从Array中解构并赋值变量
  ['resource' => [
    'ciphertext'      => $ciphertext,
    'nonce'           => $nonce,
    'associated_data' => $aad
  ]] = $inBodyArray;
  // 加密文本消息解密,有可能解密异常(eg: 平台探测流量)会抛 \UnexpectedValueException
  $inBodyResource = \WeChatPay\Crypto\AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
  // 把解密后的文本转换为PHP Array数组
  $inBodyResourceArray = (array)\json_decode($inBodyResource, true);
  // 把解密后的数组定义为'original_data'函数返回
  $inBodyArray['resource']['original_data'] = $inBodyResourceArray;

  return [
    'headers' => $request->getHeaders(),
    'body' => $inBodyArray
  ];
}

// do your business
// ...
// ...
$json = \json_encode([
  'code' => 'SUCCESS',
  'message' => 'OK'
]);
应答规范类型描述
statusnumberHTTP状态码
20X 4XX 5XX 枚举值之一
bodyobject应答的JSON数据结构
codestring业务处理状态码
SUCCESS | FAIL 枚举值之一
messagestring业务处理附加信息

参阅 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档 官方文档

Published on the GitHub by TheNorthMemory