如何在Xero中添加发票?排查‘验证异常’报错原因
分析Xero发票创建时"A validation exception occurred"错误的原因
从你提供的代码和问题描述来看,有几个明确的问题会触发Xero API的验证异常,我来逐一拆解分析:
1. 未先持久化关联的联系人(核心问题)
你代码里注释掉了api.Contacts.Create(newContact),却直接把本地创建的newContact关联到了发票上。Xero的API要求发票关联的联系人必须是已经存在于Xero系统中的实体——也就是说,你必须先调用API创建并保存联系人,拿到系统返回的已持久化联系人对象后,再将其关联到发票。
现在你的代码里,newContact只是一个本地内存对象,并没有同步到Xero系统,Xero无法识别这个未保存的联系人,自然会抛出验证异常。
2. 发票行项目的金额逻辑矛盾
看你代码里的LineItem设置:
li.LineAmount = Convert.ToDecimal("200.00"); li.Quantity = Convert.ToDecimal("1.0000"); li.UnitAmount = Convert.ToDecimal("50.00");
Xero的验证规则要求LineAmount必须等于UnitAmount * Quantity(无折扣场景下)。这里50 * 1 = 50,但你手动设置了LineAmount=200,两者数值不匹配,这会直接触发验证失败。你要么去掉手动设置的LineAmount(让Xero自动计算),要么确保三者的数值逻辑一致。
3. 关联的基础数据可能不存在
另外,还要检查以下基础数据是否在你的Xero账套中存在:
li.AccountCode = "200":这个科目代码是否已经在Xero中创建?li.ItemCode = "100":这个商品/服务代码是否已存在于Xero系统?
如果这些基础数据不存在,Xero API同样会返回验证异常。
修复后的代码示例
把上述问题修正后,代码可以调整成这样:
private void button1_Click(object sender, EventArgs e) { try { var api = new Xero.Api.Example.Applications.Private.Core(false); // 1. 先创建并保存联系人,拿到系统返回的已持久化对象 Contact newContact = new Contact(); newContact.Name = "Orac"; var savedContact = api.Contacts.Create(newContact); // 2. 创建发票并关联已保存的联系人 Invoice newInvoice = new Invoice(); newInvoice.Contact = savedContact; newInvoice.Date = System.DateTime.Now; newInvoice.DueDate = System.DateTime.Now.AddMonths(1); newInvoice.Status = Xero.Api.Core.Model.Status.InvoiceStatus.Authorised; newInvoice.Type = Xero.Api.Core.Model.Types.InvoiceType.AccountsReceivable; List<LineItem> lines = new List<LineItem>(); LineItem li = new LineItem(); li.Quantity = Convert.ToDecimal("1.0000"); li.ItemCode = "100"; // 确认该ItemCode在Xero中存在 li.Description = "Webdev inv test"; li.AccountCode = "200"; // 确认该AccountCode在Xero中存在 li.UnitAmount = Convert.ToDecimal("50.00"); // 去掉手动设置的LineAmount,让Xero自动计算,或设置为50.00保持一致 lines.Add(li); newInvoice.LineItems = lines; // 3. 调用API创建发票 var savedInvoice = api.Invoices.Create(newInvoice); } catch (Exception ex) { MessageBox.Show(ex.Message); // 建议打印ex.InnerException的内容,Xero通常会在内部异常里给出具体的验证错误细节 } }
另外,建议你在catch块中输出ex.InnerException的信息,Xero的API通常会在内部异常里给出更精准的验证失败原因(比如“联系人不存在”、“行项目金额不匹配”等),这能帮你更快定位问题。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

