简体   繁体   English

如何为QBO IPP .NET SDK V3的发票行项目指定产品/服务?

[英]How can I specify Product/Service for an Invoice Line Item for QBO IPP .NET SDK V3?

I'm trying to specify a Product/Service list item for invoice line items of invoices that I am importing to QuickBooks Online (QBO) company file and I am getting an error. 我正在尝试为要导入到QuickBooks Online(QBO)公司文件的发票的发票行项目指定“产品/服务”列表项,但出现错误。

Error I receive is: 我收到的错误是:

Intuit.Ipp.Exception.IdsException: InternalServerError ---> Intuit.Ipp.Exception.EndpointNotFoundException: Ids service endpoint was not found.

The exception doesn't give any further breakdown as to if what I'm doing is valid or not. 该异常不会进一步细分我正在做的事情是否有效。

My unit test method: 我的单元测试方法:

    [TestMethod()]
    public void CreateTest()
    {
        Entities.Invoice invoice = new Entities.Invoice();
        invoice.ReferenceId = Guid.NewGuid().ToString("N").Substring(0, 10);
        invoice.CreatedDate = DateTime.Now;
        invoice.CustomerId = 1;
        invoice.LineItems.Add(new InvoiceLine() { ItemName = "Initial Funding", Description = "Initial Funding", Amount = 5500 });
        invoice.LineItems.Add(new InvoiceLine() { ItemName = "Lien Fee", Description = "Lien Fee", Amount = 100 });


        IPPRestProfile restProfile = new IPPRestProfile(realmId, accessToken, accessTokenSecret, Intuit.Ipp.Core.IntuitServicesType.QBO, consumerKey, consumerSecret);
        IPP.Invoices target = new IPP.Invoices(restProfile);
        Intuit.Ipp.Data.Invoice actual = target.Create(invoice);

        if (actual != null)
        {
            Console.WriteLine("QB Invoice ID: {0}", actual.Id);
            Console.WriteLine("QB Sync Token: {0}", actual.SyncToken);
            Console.WriteLine("================================================");
            ObjectDumper.Write(actual, 4);
        }
    }

The method that the unit test calls: 单元测试调用的方法:

        public Intuit.Ipp.Data.Invoice Create(Entities.Invoice invoice)
    {
        // Check pre-conditions
        if (invoice == null) { throw new ArgumentException("Invoice object is required.", "invoice"); }

        var qboInvoice = new Intuit.Ipp.Data.Invoice();
        BuildInvoiceEntity(qboInvoice, invoice);

        return _Service.Add(qboInvoice) as Intuit.Ipp.Data.Invoice;
    }

And finally the build invoice method: 最后是生成发票的方法:

    private void BuildInvoiceEntity(Intuit.Ipp.Data.Invoice qboInvoice, Entities.Invoice invoice)
    {
        if (qboInvoice != null && invoice != null)
        {
            IQuickBooksHeader header = invoice as IQuickBooksHeader;

            if (String.IsNullOrEmpty(header.Id))
            {
                qboInvoice.DocNumber = invoice.ReferenceId;
                qboInvoice.TxnDate = invoice.CreatedDate;
                qboInvoice.TxnDateSpecified = true;

                // Customer
                qboInvoice.CustomerRef = new ReferenceType()
                {
                    type = objectNameEnumType.Customer.ToString(),
                    Value = invoice.CustomerId.ToString()
                };

                // AR Account
                qboInvoice.ARAccountRef = new ReferenceType()
                {
                    type = objectNameEnumType.Account.ToString(),
                    name = "Accounts Receivable"
                };
            }

            if (invoice.LineItems.Count > 0)
            {
                Intuit.Ipp.Data.Line[] invoiceLineCollection = new Intuit.Ipp.Data.Line[invoice.LineItems.Count];
                for (int i = 0; i < invoice.LineItems.Count; i++)
                {
                    var line = invoice.LineItems[i];
                    var qboInvoiceLine = new Intuit.Ipp.Data.Line()
                    {
                        Amount = line.Amount,
                        AmountSpecified = true,
                        Description = line.Description,
                        DetailType = LineDetailTypeEnum.SalesItemLineDetail,
                        DetailTypeSpecified = true,
                        AnyIntuitObject = new SalesItemLineDetail()
                        {
                            ItemRef = new ReferenceType()
                            {
                                name = line.ItemName,
                            },
                            ItemElementName = ItemChoiceType.UnitPrice,
                            AnyIntuitObject = line.Amount
                        }
                    };
                    invoiceLineCollection[i] = qboInvoiceLine;
                }
                qboInvoice.Line = invoiceLineCollection;
            }
        }
    }

If I remove this piece of code from my build method: 如果我从构建方法中删除这段代码:

      ItemRef = new ReferenceType()
      {
          name = line.ItemName,
      },

the invoice is successfully added with the default "Services" list item for the Product/Service of the invoice line items. 成功为发票行项目的“产品/服务”添加了默认的“服务”列表项。

The online documentation for the IPP .NET SDK V3 is vague on what to specify for ReferenceType. IPP .NET SDK V3的联机文档在为ReferenceType指定什么方面含糊。 What is wrong about just specifying the name of the list item? 仅指定列表项的名称有什么问题? If I'm wrong about how I'm trying to specify a Product/Service list item for invoice line items, what is the correct way? 如果我对尝试为发票订单项指定产品/服务列表项有误,那么正确的方法是什么?

After days of researching, I never did find an answer as to why I can't just use the name like I wanted to, even though it works that way when specifying an AccountRef. 经过数天的研究,尽管为什么在指定AccountRef时可以使用我想使用的名称,但我仍未找到答案。 But I digress, here is my solution: 但是我离题了,这是我的解决方案:

// Hold a collection of QBO items
private ReadOnlyCollection<Item> _Items;

// I set the collection in the constructor only once
public Invoices(Entities.IPPRestProfile restProfile)
{
    if (restProfile == null)
        throw new ArgumentException("IPPRestProfile object is required.", "restProfile");

    OAuthRequestValidator oAuthValidator = new OAuthRequestValidator(restProfile.OAuthAccessToken, restProfile.OAuthAccessTokenSecret,
            restProfile.ConsumerKey, restProfile.ConsumerSecret);
    ServiceContext context = new ServiceContext(restProfile.RealmId, restProfile.DataSource, oAuthValidator);
    _Service = new DataService(context);
    _Items = (new QueryService<Item>(context)).ExecuteIdsQuery("SELECT * FROM Item", QueryOperationType.query);
}

Whenever I build my invoice I query the collection for the Id of the item by name: 每当我创建发票时,我都会通过名称查询集合的项目ID:

private void BuildInvoiceEntity(Intuit.Ipp.Data.Invoice qboInvoice, Entities.Invoice invoice)
{
    ...
    // Get the Id value of the item by name
    string itemTypeId = _Items.Where(o => o.Name == line.ItemName).FirstOrDefault().Id;

    // Specify the Id value in the item reference of the SalesItemLineDetail
    var qboInvoiceLine = new Intuit.Ipp.Data.Line()
    {
        Amount = (decimal)amount,
        AmountSpecified = true,
        Description = line.Description,
        DetailType = LineDetailTypeEnum.SalesItemLineDetail,
        DetailTypeSpecified = true,
        AnyIntuitObject = new SalesItemLineDetail()
        {
            ItemRef = new ReferenceType() { Value = itemTypeId },
            AnyIntuitObject = (decimal)line.Rate,
            ItemElementName = ItemChoiceType.UnitPrice
        }
    };
    ...
}

Hopefully this helps point someone in the right direction to a possible better solution. 希望这有助于向正确的方向指明某人,以寻求更好的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM