QuickBooks PHP API问题:无法将费用采购关联至发票
问题
使用QuickBooks PHP API创建发票时,时间条目可成功关联到发票,但新生成的费用(Purchase)无法通过代码关联到发票,无任何报错。费用已在QuickBooks中创建,前端可手动关联,但代码实现失败。
发票创建代码
$Invoice = new QuickBooksOnline\API\Data\IPPInvoice(); //Setup the Invoice Object $Invoice->CustomerRef = $Values['CustomerId']; $Invoice->EmailStatus = "NotSet"; $Invoice->BillEmail = new IPPEmailAddress(); $Invoice->BillEmail->Address = $Values['CustomerEmail']; $Invoice->DocNumber = $Values['DocNumber']; //..then add all the time charges as line items foreach ($Values['InvoiceTimeCharge'] as $LineItem) { $LineDetails = $Values['InvoiceLineItems'][array_search($LineItem['WHID'], array_column($Values['InvoiceLineItems'], "WHID"))]; if ($LineItem['Type'] === "Time") { //Unset the type from the array we pass in to create a new Transaction unset($LineItem['Type']); $Line = new QuickBooksOnline\API\Data\IPPLine(); $Line->Amount = (float)$LineItem['Hours'] * (float)$LineItem['HourlyRate']; $Line->DetailType = "SalesItemLineDetail"; $Line->LinkedTxn = [ new QuickBooksOnline\API\Data\IPPLinkedTxn([ 'TxnId' => $this->CreateTimeActivity($LineItem)['NewTimeActivityID'], 'TxnType' => 'TimeActivity' ]) ]; $Line->SalesItemLineDetail = new QuickBooksOnline\API\Data\IPPSalesItemLineDetail(); $Line->SalesItemLineDetail->ItemRef = $Values['OfferingId']; $Line->SalesItemLineDetail->TaxCodeRef = "TAX"; $Line->SalesItemLineDetail->Qty = $LineDetails['Quantity']; $Line->SalesItemLineDetail->UnitPrice = (float)$LineDetails['Rate']; $Line->Description = $LineDetails['Description']; $Invoice->Line[] = $Line; } elseif ($LineItem['Type'] === "Material") { if (isset($LineDetails['QBPaymentAccountID'])) { $Line = new QuickBooksOnline\API\Data\IPPLine(); $Line->Amount = (float)$LineDetails['LineItemValue']; $Line->DetailType = "AccountBasedExpenseLineDetail"; $Line->LinkedTxn = [ new QuickBooksOnline\API\Data\IPPLinkedTxn([ 'TxnId' => $this->CreatePurchase( [ "PaymentAccount" => $LineDetails['QBPaymentAccountID'], "LineItemCategory" => $LineDetails['QBExpenseCategoryID'], "LineItemValue" => (float)$LineDetails['LineItemValue'], "CostID" => $LineDetails['WHID'], "CustomerId" => $Values['CustomerId'], "Description" => $LineDetails['ExpenseDesc'] ] )['NewPurchaseID'], 'TxnType' => 'Expense' ]) ]; $Line->AccountBasedExpenseLineDetail = new QuickBooksOnline\API\Data\IPPAccountBasedExpenseLineDetail(); $Line->AccountBasedExpenseLineDetail->AccountRef = $LineDetails['QBPaymentAccountID']; $Line->AccountBasedExpenseLineDetail->CustomerRef = $Values['CustomerId']; $Line->AccountBasedExpenseLineDetail->BillableStatus = "Billable"; $Invoice->Line[] = $Line; } else { $Line = new QuickBooksOnline\API\Data\IPPLine(); $Line->Amount = (float)$LineDetails['LineItemValue']; $Line->DetailType = "SalesItemLineDetail"; $Line->SalesItemLineDetail = new QuickBooksOnline\API\Data\IPPSalesItemLineDetail(); $Line->SalesItemLineDetail->ItemRef = $Values['OfferingId']; $Line->SalesItemLineDetail->Amount = (float)$LineDetails['LineItemValue']; $Line->Description = $LineDetails['Description']; $Invoice->Line[] = $Line; } } } // Create the new Invoice in QuickBooks $NewInvoice = $this->_DataService->Add($Invoice); $error = $this->_DataService->getLastError();
CreatePurchase函数代码
//Adds a purchase record to quickbooks (initially for expenses) public function CreatePurchase($Values) { // Create a new QuickBooks's Invoice & Line object $PurchaseItem = new QuickBooksOnline\API\Facades\Purchase(); $PurchaseValues = [ 'AccountRef' => [ 'value' => $Values['PaymentAccount'], ], 'PaymentType' => 'Cash', 'TotalAmt' => $Values['LineItemValue'], // The total amount of the expense 'Line' => [ [ 'Amount' => $Values['LineItemValue'], // The amount of the line item 'DetailType' => 'AccountBasedExpenseLineDetail', 'AccountBasedExpenseLineDetail' => [ 'AccountRef' => [ 'value' => $Values['LineItemCategory'], // The ID of the expense account for the line item ], 'CustomerRef' => [ 'value' => $Values['CustomerId'] ], "BillableStatus" => "Billable" ], 'Description' => $Values['Description'] ] ] ]; // Create the new Invoice in QuickBooks $NewPurchase = $this->_DataService->Add($PurchaseItem->create($PurchaseValues)); $error = $this->_DataService->getLastError(); if ($error) { //throw new Exception($error->getIntuitErrorDetail()); return ["status" => false, "error" => $error->getIntuitErrorDetail()]; } else { return ["status" => true, "NewPurchaseID" => $NewPurchase->Id, "NewPurchaseObject" => $NewPurchase, "XrefID" => $XrefUpdateResult]; } }
解决方案
问题出在两个关键错误:
1. LinkedTxn的TxnType不匹配
你通过CreatePurchase创建的是Purchase类型的交易,但代码里关联时指定的TxnType是'Expense',QuickBooks API要求这里必须严格匹配实际交易类型,需要改为'Purchase'。
2. 发票行的DetailType错误
发票属于销售类交易,不能使用针对费用的AccountBasedExpenseLineDetail,必须改用SalesItemLineDetail,同时确保关联的项目是可计费的,并且参数设置正确。
修改后的Material类型发票行代码如下:
elseif ($LineItem['Type'] === "Material") { if (isset($LineDetails['QBPaymentAccountID'])) { $purchaseResult = $this->CreatePurchase([ "PaymentAccount" => $LineDetails['QBPaymentAccountID'], "LineItemCategory" => $LineDetails['QBExpenseCategoryID'], "LineItemValue" => (float)$LineDetails['LineItemValue'], "CostID" => $LineDetails['WHID'], "CustomerId" => $Values['CustomerId'], "Description" => $LineDetails['ExpenseDesc'] ]); // 先确认采购创建成功 if (!$purchaseResult['status']) { // 处理错误逻辑 continue; } $Line = new QuickBooksOnline\API\Data\IPPLine(); $Line->Amount = (float)$LineDetails['LineItemValue']; $Line->DetailType = "SalesItemLineDetail"; $Line->LinkedTxn = [ new QuickBooksOnline\API\Data\IPPLinkedTxn([ 'TxnId' => $purchaseResult['NewPurchaseID'], 'TxnType' => 'Purchase' // 修正为Purchase ]) ]; $Line->SalesItemLineDetail = new QuickBooksOnline\API\Data\IPPSalesItemLineDetail(); $Line->SalesItemLineDetail->ItemRef = $Values['OfferingId']; // 确保此Item支持计费 $Line->SalesItemLineDetail->TaxCodeRef = "TAX"; // 根据实际情况调整 $Line->SalesItemLineDetail->BillableStatus = "Billable"; $Line->SalesItemLineDetail->CustomerRef = $Values['CustomerId']; $Line->Description = $LineDetails['Description']; $Invoice->Line[] = $Line; } else { // 原代码逻辑保留 $Line = new QuickBooksOnline\API\Data\IPPLine(); $Line->Amount = (float)$LineDetails['LineItemValue']; $Line->DetailType = "SalesItemLineDetail"; $Line->SalesItemLineDetail = new QuickBooksOnline\API\Data\IPPSalesItemLineDetail(); $Line->SalesItemLineDetail->ItemRef = $Values['OfferingId']; $Line->SalesItemLineDetail->Amount = (float)$LineDetails['LineItemValue']; $Line->Description = $LineDetails['Description']; $Invoice->Line[] = $Line; } }
额外注意事项
- 确保
$Values['OfferingId']对应的Item在QuickBooks中设置为可计费(Billable)。 - 创建Purchase后,务必检查返回结果的
status,避免使用无效的TxnId进行关联。 - 如果关联后仍有问题,可以开启QuickBooks API的调试日志,查看实际发送的请求和返回的响应,确认参数是否符合API规范。
内容的提问来源于stack exchange,提问作者Rob Santoro
相关产品推荐
相关产品推荐

