You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP Xero API创建重复BankTransaction超额支付记录问题求助

解决Xero API重复超额支付的问题

要避免重复创建超额支付,核心是实现幂等性,结合Xero API的特性和本地校验,以下是具体方案:

1. 利用Xero API的Reference字段做幂等标识

Xero允许通过Reference字段确保同一笔交易的唯一性——相同Reference的重复请求会被API直接拒绝。你需要生成一个全局唯一的字符串(比如UUID、业务系统的订单ID)作为Reference,每次创建超额支付时带上这个值:

修改你的$postFields数组,添加Reference字段:

// 生成唯一标识,可用UUID或业务唯一ID
$uniqueReference = 'OVERPAY-' . uniqid($contactID . '-', true);
// 若PHP启用了uuid扩展,也可以用:$uniqueReference = uuid_create(UUID_TYPE_RANDOM);

$postFields = array(
    "Type" => "RECEIVE-OVERPAYMENT",
    "Reference" => $uniqueReference, // 新增幂等标识
    'Contact' => ['ContactID' => $contactID],
    'BankAccount' => ['accountID' => $xero_settings['account_id']],
    'LineAmountTypes' => 'NoTax',
    'LineItems' => [0 => [
        'Description' => 'Customer Credit',
        'LineAmount' => $price
    ]]
);

2. 本地请求日志与前置校验

在发送API请求前,先在本地系统(数据库/缓存)记录这个唯一Reference的状态,从源头避免重复触发:

  • 发送请求前,检查本地是否已有该Reference的记录:
    • 如果有且状态为「已成功」,直接跳过发送;
    • 如果状态为「处理中」,等待一段时间再检查结果,避免重复发送;
  • 请求发送后,根据Xero返回的状态码和响应,更新本地记录的状态(成功/失败/未知)。

示例逻辑(基于数据库):

// 前置校验:检查本地是否已有该请求记录
$stmt = $pdo->prepare("SELECT status FROM xero_overpayments WHERE reference = ?");
$stmt->execute([$uniqueReference]);
$existing = $stmt->fetch(PDO::FETCH_ASSOC);

if ($existing) {
    if ($existing['status'] === 'success') {
        exit('Overpayment already created');
    } elseif ($existing['status'] === 'pending') {
        exit('Overpayment is being processed');
    }
}

// 记录请求为处理中
$stmt = $pdo->prepare("INSERT INTO xero_overpayments (reference, contact_id, amount, status) VALUES (?, ?, ?, 'pending')");
$stmt->execute([$uniqueReference, $contactID, $price]);

// 执行原有的CURL请求...

// 请求完成后更新状态
if ($status_code === 200) {
    $stmt = $pdo->prepare("UPDATE xero_overpayments SET status = 'success', response = ? WHERE reference = ?");
    $stmt->execute([$response, $uniqueReference]);
} else {
    $stmt = $pdo->prepare("UPDATE xero_overpayments SET status = 'failed', error = ?, response = ? WHERE reference = ?");
    $stmt->execute([curl_error($ch), $response, $uniqueReference]);
}

3. 修复CURL错误处理

你的代码中用@屏蔽了CURL的错误,这会导致你无法准确判断请求是否真的发送成功(比如网络超时、连接失败时,你可能误以为请求没发送,从而重复触发)。去掉所有@符号,加入错误判断:

try {
    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, $endpoint);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields, JSON_PRETTY_PRINT));
    // 设置超时时间,避免长时间阻塞
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);

    $response = curl_exec($ch);

    if (curl_errno($ch)) {
        $error = curl_error($ch);
        error_log("CURL Error: " . $error);
        // 可根据错误类型决定是否重试,但需结合本地幂等记录
    }

    $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    error_log($status_code);
    error_log($response);
} finally {
    curl_close($ch); 
}

总结

  • 用Xero的Reference字段让API层面拒绝重复请求;
  • 本地记录请求状态,从源头避免重复触发;
  • 修复错误处理,准确判断请求状态,减少不必要的重试。

内容的提问来源于stack exchange,提问作者jpruizs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 10:25:24