PHP调用Xero API创建发票:客户地址与联系电话未同步问题
Xero API创建发票:客户地址与联系电话同步失败排查
使用Xero API创建发票时,客户已成功创建、发票邮件正常发送,但客户地址和联系电话无法同步到Xero平台,其余功能正常,代码执行无报错。以下是相关代码:
$xeroTenantId = $this->Storage_model->getSession()['tenant_id']; if ($this->Storage_model->getHasExpired()) { $provider = new \League\OAuth2\Client\Provider\GenericProvider([ 'clientId' => 'xxxxxxxxxx', 'clientSecret' => 'xxxxxxxxxx', 'redirectUri' => 'xxxxxxxxxx.co.uk/callback', 'urlAuthorize' => 'https://login.xero.com/identity/connect/authorize', 'urlAccessToken' => 'https://identity.xero.com/connect/token', 'urlResourceOwnerDetails' => 'https://api.xero.com/api.xro/2.0/Organisation' ]); $newAccessToken = $provider->getAccessToken('refresh_token', [ 'refresh_token' => $this->Storage_model->getRefreshToken() ]); // Save my token, expiration and refresh token $this->Storage_model->setToken( $newAccessToken->getToken(), $newAccessToken->getExpires(), $xeroTenantId, $newAccessToken->getRefreshToken(), $newAccessToken->getValues()["id_token"] ); } $config = XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken( (string)$this->Storage_model->getSession()['token'] ); $apiInstance = new XeroAPI\XeroPHP\Api\AccountingApi( new GuzzleHttp\Client(), $config ); $idempotencyKey = rand()."IDDEMP"; $summarizeErrors = true; $unitdp = 4; $dateValue = new DateTime('now'); $dueDateValue = new DateTime('now'); $dueDateValue->modify("+1 month"); //test data $contact['firstName'] = "Fred"; $contact['surname'] = "Blogs"; $contact['email'] = "Fred@test.co.uk"; $contact['contactNumber'] = "079671111111"; $contact['billingAddress1'] = "Address 1"; $contact['billingAddress2'] = "Address 2"; $contact['billingAddress3'] = "Address 3"; $contact['billingAddress4'] = "Address 4"; $contact['billingPostcode'] = "DT94XX"; //[add a contact] $setFirstName = $contact['firstName']; $setLastName = $contact['surname']; $setEmailAddress = $contact['email']; $setContactNumber = $contact['contactNumber']; $address = array(array( 'AddressType' => 'STREET', 'AddressLine1' => $contact['billingAddress1'], 'AddressLine2' => $contact['billingAddress2'], 'City' => $contact['billingAddress3'], 'State' => $contact['billingAddress4'], 'PostalCode' => $contact['billingPostcode'] )); $contact = new XeroAPI\XeroPHP\Models\Accounting\Contact; $contact->setName($setFirstName." ".$setLastName) ->setFirstName($setFirstName) ->setLastName($setLastName) ->setEmailAddress($setEmailAddress) ->setContactNumber($setContactNumber) ->setAddresses($address); $arr_contacts = []; array_push($arr_contacts, $contact); $contacts = new XeroAPI\XeroPHP\Models\Accounting\Contacts; $contacts->setContacts($arr_contacts); $apiResponse = $apiInstance->createContacts($xeroTenantId,$contacts); //[/add a contact] $lineItems = array(); $lineItemTracking = new XeroAPI\XeroPHP\Models\Accounting\LineItemTracking; $lineItemTracking->setTrackingCategoryID('00000000-0000-0000-0000-000000000000'); $lineItemTracking->setTrackingOptionID('00000000-0000-0000-0000-000000000000'); $lineItemTrackings = []; array_push($lineItemTrackings, $lineItemTracking); foreach($order as $value) { $lineItem = new XeroAPI\XeroPHP\Models\Accounting\LineItem; $lineItem->setDescription($value['rowTitle']); $lineItem->setQuantity($value['rowQty']); $lineItem->setUnitAmount($value['rowPrice']); $lineItem->setAccountCode('200'); $lineItem->setTracking($lineItemTrackings); array_push($lineItems, $lineItem); } $invoice = new XeroAPI\XeroPHP\Models\Accounting\Invoice; $invoice->setType(XeroAPI\XeroPHP\Models\Accounting\Invoice::TYPE_ACCREC); $invoice->setContact($contact); $invoice->setDate($dateValue); $invoice->setDueDate($dueDateValue); $invoice->setLineItems($lineItems); $invoice->setReference($contact['reference']); $invoice->setStatus('AUTHORISED'); //$invoice->setStatus(XeroAPI\XeroPHP\Models\Accounting\Invoice::STATUS_DRAFT); $invoices = new XeroAPI\XeroPHP\Models\Accounting\Invoices; $arr_invoices = []; array_push($arr_invoices, $invoice); $invoices->setInvoices($arr_invoices); try { $result = $apiInstance->createInvoices($xeroTenantId, $invoices, $idempotencyKey, $summarizeErrors, $unitdp); $data = XeroAPI\XeroPHP\AccountingObjectSerializer::sanitizeForSerialization($result); //email invoice $requestEmpty = new XeroAPI\XeroPHP\Models\Accounting\RequestEmpty; try { $idempotencyKey = rand()."IDDEMP"; $apiInstance->emailInvoice($xeroTenantId, $invocieID = $data->Invoices[0]->InvoiceID, $requestEmpty, $idempotencyKey); } catch (Exception $e) { echo 'Exception when calling AccountingApi->emailInvoice: ', $e->getMessage(), PHP_EOL; } } catch (Exception $e) { echo 'Exception when calling AccountingApi->createInvoices: ', $e->getMessage(), PHP_EOL; } echo "complete";
排查关键点
1. 联系电话字段使用错误
Xero API的Contact模型中,联系电话不能直接用setContactNumber(),需要创建Phone对象并指定电话类型:
// 替换原setContactNumber的代码 $phone = new XeroAPI\XeroPHP\Models\Accounting\Phone(); $phone->setPhoneType(\XeroAPI\XeroPHP\Models\Accounting\Phone::PHONE_TYPE_DEFAULT) ->setPhoneNumber($setContactNumber); $contact->setPhones([$phone]);
2. 地址字段映射与类型问题
- 你当前将
billingAddress3赋值给City、billingAddress4赋值给State,请确认地址数据是否匹配这些字段(比如billingAddress3确实是城市名称),否则会导致Xero无法解析地址。 - 如果需要标记该地址为账单地址,需确保地址的
AddressType设置正确,同时可在Contact对象中指定setBillToAddress($address)(根据SDK版本调整,部分版本需通过Addresses数组的属性标记)。
3. 未使用Xero返回的Contact对象关联发票
调用createContacts后,Xero会返回包含完整信息的Contact对象,你直接使用本地创建的对象关联发票,可能导致部分字段未被同步。应替换为返回的对象:
$apiResponse = $apiInstance->createContacts($xeroTenantId,$contacts); // 获取Xero返回的完整Contact对象 $createdContact = $apiResponse->getContacts()[0]; // 发票中使用该对象 $invoice->setContact($createdContact);
4. 发票Reference字段错误
代码中$invoice->setReference($contact['reference']);的$contact已经被重新赋值为Contact对象,原数组的reference字段不存在,会传入空值,建议删除该行或设置有效的参考值。
内容的提问来源于stack exchange,提问作者user3507560
相关产品推荐
相关产品推荐

