QuickBooks PHP API 添加 Payment 时出现 Invalid ID 错误
支付小周
结论
$Invoice->getId() 返回的 {-10643} 不是 QuickBooks 接受的原始 Invoice ID,也不代表 ID 是负数。这是 quickbooks-php 对 Intuit ID 类型的内部表示。大括号和连字符都属于包装格式,实际应发送给 API 的 ID 是 10643。
设置 LinkedTxn.TxnId 前,应通过库提供的 QuickBooks_IPP_IDS::usableIDType() 提取可用于请求的 ID:
$invoiceId = QuickBooks_IPP_IDS::usableIDType($Invoice->getId());
$LinkedTxn->setTxnId($invoiceId);
最终生成的 XML 应为:
<TxnId>10643</TxnId>
不能是:
<TxnId>{-10643}</TxnId>
原因
在某些版本中,quickbooks-php 会将 Intuit 的复合 ID 表示为:
{domain-id}
当 domain 为空时,结果可能显示为:
{-10643}
这里的 - 是内部格式的分隔符,不是数学意义上的负号。如果直接将这个包装后的值传给:
$LinkedTxn->setTxnId($invoiceId);
请求 XML 中就会包含 {、} 和 -。QuickBooks API 无法将 {-10643} 解析为合法的实体 ID,因此会返回:
2030: Invalid ID
Id should be a valid number. Supplied value:{-10643}
请求内容也表明,出错的位置是 LinkedTxn.TxnId:
<LinkedTxn>
<TxnId>{-10643}</TxnId>
<TxnType>Invoice</TxnType>
</LinkedTxn>
修改方法
取得 Invoice 后,先将内部 ID 转换为 API 可接受的 ID:
$Invoice = $invoices[0];
$invoiceId = QuickBooks_IPP_IDS::usableIDType(
$Invoice->getId()
);
再创建关联:
$LinkedTxn = new QuickBooks_IPP_Object_LinkedTxn();
$LinkedTxn->setTxnId($invoiceId);
$LinkedTxn->setTxnType('Invoice');
$Line->setLinkedTxn($LinkedTxn);
完整的核心代码可以写成:
$invoices = $InvoiceService->query(
$Context,
$realm,
"SELECT * FROM Invoice WHERE DocNumber = '" . $invoiceNumber . "'"
);
if (!$invoices || !isset($invoices[0])) {
throw new RuntimeException(
'Invoice not found: ' . $invoiceNumber
);
}
$Invoice = $invoices[0];
$invoiceId = QuickBooks_IPP_IDS::usableIDType(
$Invoice->getId()
);
$CustomerRef = $Invoice->getCustomerRef();
$PaymentService = new QuickBooks_IPP_Service_Payment();
$Payment = new QuickBooks_IPP_Object_Payment();
$Payment->setPaymentRefNum($invoiceNumber);
$Payment->setTxnDate(date('Y-m-d'));
$Payment->setTotalAmt($depositAmount);
$Payment->setCustomerRef($CustomerRef);
$Line = new QuickBooks_IPP_Object_Line();
$Line->setAmount($depositAmount);
$LinkedTxn = new QuickBooks_IPP_Object_LinkedTxn();
$LinkedTxn->setTxnId($invoiceId);
$LinkedTxn->setTxnType('Invoice');
$Line->setLinkedTxn($LinkedTxn);
$Payment->addLine($Line);
if ($paymentId = $PaymentService->add(
$Context,
$realm,
$Payment
)) {
print('Our new Payment ID is: [' . $paymentId . ']');
} else {
print($PaymentService->lastError());
}
如何确认修复是否生效
发送 Payment 前,检查转换前后的值:
debug($Invoice->getId());
debug($invoiceId);
预期结果类似:
{-10643}
10643
还应检查:
$PaymentService->lastRequest()
其中的 LinkedTxn 应变为:
<LinkedTxn xmlns="http://schema.intuit.com/finance/v3">
<TxnId>10643</TxnId>
<TxnType>Invoice</TxnType>
</LinkedTxn>
注意事项
不要直接使用 abs()、删除负号或仅通过字符串替换来处理这个值。例如:
$invoiceId = abs($Invoice->getId());
这种写法依赖 PHP 的隐式类型转换,也没有正确处理库的 ID 包装格式。应优先使用:
QuickBooks_IPP_IDS::usableIDType()
还需注意:
- 确认查询结果不为空后,再访问
$invoices[0]。 TxnId必须使用 Invoice 的内部实体 ID,不能使用DocNumber。PaymentRefNum可以填写业务上的付款编号,但不能代替LinkedTxn.TxnId。- Payment 的
CustomerRef应与所关联 Invoice 的客户一致。 - 如果当前安装的
quickbooks-php版本没有usableIDType(),需要通过该版本的 ID 对象接口取得原始 value,或者升级到包含此辅助方法的兼容版本。不要将带大括号的内部表示原样写入 XML。
备注:内容仅供参考。
