Vahe Vahe - 1 year ago 62
C# Question

Quickbooks Online Accounting - How to add multiple line items in an invoice?

With the following code I want to create multiple line items to show up in a new invoice.

How do I create multiple line items in my invoice, corresponding to my multiple order items from my custom application?

Running the following code with OrderItems having 4 items in order shows only one item in the invoice. Price and name is correct but number of products are not. Only one shows up.

I believe this line is the correct line to add line items. But does it actually add line item(s)?


invoice.Line = new Line[] { invoiceLine };


Code

var orderItems = order.OrderItems;

foreach (var orderItem in orderItems)
{
//Line
Line invoiceLine = new Line();

//Line Description
invoiceLine.Description = itemRepository.Get(i=>i.ItemID == orderItem.ItemID).First().FullDescription;

//Line Amount
invoiceLine.Amount = orderItem.Price * orderItem.Quantity;
invoiceLine.AmountSpecified = true;

//Line Detail Type
invoiceLine.DetailType = LineDetailTypeEnum.SalesItemLineDetail;
invoiceLine.DetailTypeSpecified = true;

//Line Sales Item Line Detail
SalesItemLineDetail lineSalesItemLineDetail = new SalesItemLineDetail();

//Line Sales Item Line Detail - ItemRef
lineSalesItemLineDetail.ItemRef = new ReferenceType()
{
name = itemRepository.Get(
i=>i.ItemID == orderItem.ItemID).First().FullDescription,
Value = item.Id
};

//Line Sales Item Line Detail - UnitPrice
lineSalesItemLineDetail.AnyIntuitObject = orderItem.Price;//33m;
lineSalesItemLineDetail.ItemElementName = ItemChoiceType.UnitPrice;

//Line Sales Item Line Detail - Qty
lineSalesItemLineDetail.Qty = orderItem.Quantity;//10;
lineSalesItemLineDetail.QtySpecified = true;

//Line Sales Item Line Detail - TaxCodeRef
//For US companies, this can be 'TAX' or 'NON
lineSalesItemLineDetail.TaxCodeRef = new ReferenceType()
{
Value = "TAX"
};

//Line Sales Item Line Detail - ServiceDate
lineSalesItemLineDetail.ServiceDate = DateTime.Now.Date;
lineSalesItemLineDetail.ServiceDateSpecified = true;

//Assign Sales Item Line Detail to Line Item
invoiceLine.AnyIntuitObject = lineSalesItemLineDetail;

//Assign Line Item to Invoice
invoice.Line = new Line[] { invoiceLine };


}

EDIT:

OAuthRequestValidator reqValidator = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerKeySecret);
ServiceContext qboContextoAuth = new ServiceContext(realmId, IntuitServicesType.QBO, reqValidator);
var service = new DataService(qboContextoAuth);

//Find Customer
var customerQueryService = new QueryService<Customer>(qboContextoAuth);
Customer customer = customerQueryService.ExecuteIdsQuery("Select * From Customer Where DisplayName = 'John Doe' StartPosition 1 MaxResults 1").FirstOrDefault();

//Find Tax Code for Invoice - Searching for a tax code named 'StateSalesTax' in this example
var stateTaxCodeQueryService = new QueryService<TaxCode>(qboContextoAuth);
TaxCode stateTaxCode = stateTaxCodeQueryService.ExecuteIdsQuery("Select * From TaxCode Where Name='Los Angeles' StartPosition 1 MaxResults 1").FirstOrDefault();

//Find Item
var itemQueryService = new QueryService<Item>(qboContextoAuth);
Item item = itemQueryService.ExecuteIdsQuery("Select * From Item StartPosition 1").FirstOrDefault();


//Find Account - Accounts Receivable account required
var accountQueryService = new QueryService<Account>(qboContextoAuth);
Account account = accountQueryService.ExecuteIdsQuery("Select * From Account Where AccountType='Accounts Receivable' StartPosition 1 MaxResults 1").FirstOrDefault();

//Find Term
var termQueryService = new QueryService<Term>(qboContextoAuth);
Term term = termQueryService.ExecuteIdsQuery("Select * From Term StartPosition 1 MaxResults 1").FirstOrDefault();

Invoice invoice = new Invoice();

//DocNumber - QBO Only, otherwise use DocNumber
invoice.AutoDocNumber = true;
invoice.AutoDocNumberSpecified = true;

//TxnDate
invoice.TxnDate = DateTime.Now.Date;
invoice.TxnDateSpecified = true;

//PrivateNote
invoice.PrivateNote = "This is a private note";


var orderItems = order.OrderItems;

int idx = 0;

var lines = new List<Line>();

foreach (var orderItem in orderItems)
{
//Line
Line invoiceLine = new Line();
//Line Description
invoiceLine.Description = itemRepository.Get(i => i.ItemID == orderItem.ItemID).First().FullDescription;
//Line Amount
invoiceLine.Amount = orderItem.Price * orderItem.Quantity;
invoiceLine.AmountSpecified = true;
//Line Detail Type
invoiceLine.DetailType = LineDetailTypeEnum.SalesItemLineDetail;
invoiceLine.DetailTypeSpecified = true;
//Line Sales Item Line Detail


SalesItemLineDetail lineSalesItemLineDetail = new SalesItemLineDetail();


//Line Sales Item Line Detail - ItemRef
lineSalesItemLineDetail.ItemRef = new ReferenceType()
{
name = itemRepository.Get(i => i.ItemID == orderItem.ItemID).First().FullDescription,
Value = (idx + 1).ToString()
};
//Line Sales Item Line Detail - UnitPrice
lineSalesItemLineDetail.AnyIntuitObject = orderItem.Price;//33m;
lineSalesItemLineDetail.ItemElementName = ItemChoiceType.UnitPrice;
//Line Sales Item Line Detail - Qty
lineSalesItemLineDetail.Qty = orderItem.Quantity;//10;
lineSalesItemLineDetail.QtySpecified = true;
//Line Sales Item Line Detail - TaxCodeRef
//For US companies, this can be 'TAX' or 'NON

lineSalesItemLineDetail.TaxCodeRef = new ReferenceType()
{
Value = "TAX"
};
//Line Sales Item Line Detail - ServiceDate
lineSalesItemLineDetail.ServiceDate = DateTime.Now.Date;
lineSalesItemLineDetail.ServiceDateSpecified = true;
//Assign Sales Item Line Detail to Line Item
invoiceLine.AnyIntuitObject = lineSalesItemLineDetail;
//Assign Line Item to Invoice
//invoice.Line = new Line[] { invoiceLine };
lines.Add(invoiceLine);

//TxnTaxDetail
TxnTaxDetail txnTaxDetail = new TxnTaxDetail();
txnTaxDetail.TxnTaxCodeRef = new ReferenceType()
{
name = stateTaxCode.Name,
Value = stateTaxCode.Id
};
Line taxLine = new Line();
taxLine.DetailType = LineDetailTypeEnum.TaxLineDetail;
TaxLineDetail taxLineDetail = new TaxLineDetail();
//Assigning the fist Tax Rate in this Tax Code
taxLineDetail.TaxRateRef = stateTaxCode.SalesTaxRateList.TaxRateDetail[0].TaxRateRef;
taxLine.AnyIntuitObject = taxLineDetail;
txnTaxDetail.TaxLine = new Line[] { taxLine };
invoice.TxnTaxDetail = txnTaxDetail;

idx++;
}
//Customer (Client)
invoice.CustomerRef = new ReferenceType()
{
name = customer.DisplayName,
Value = customer.Id
};
var _user = userRepository.Get(u => u.UserID == order.CreatedUserID, includeProperties: "ContactMethod, ContactMethod.Addresses, Location, Location.Organization").FirstOrDefault();

if (_user != null)
{
var addresses = _user.ContactMethod.Addresses.Where(a => a.StatusCode == Convert.ToByte(StatusCodes.Active) && a.IsPrimary).ToList();


var _billingAddress = addresses.Where(a => a.AddressTypeId == Convert.ToByte(AddressTypes.Billing)).FirstOrDefault();
var _shippingAddress = addresses.Where(a => a.AddressTypeId == Convert.ToByte(AddressTypes.Shipping)).FirstOrDefault();


//Billing Address
PhysicalAddress billAddr = new PhysicalAddress();
billAddr.Line1 = _billingAddress.Address1;
billAddr.Line2 = _billingAddress.Address2;
billAddr.City = _billingAddress.City;
billAddr.CountrySubDivisionCode = _billingAddress.State;
billAddr.Country = _billingAddress.Country;
billAddr.PostalCode = _billingAddress.ZipCode;
billAddr.Note = "Billing Address Note";
invoice.BillAddr = billAddr;

//Shipping Address
PhysicalAddress shipAddr = new PhysicalAddress();
shipAddr.Line1 = _shippingAddress.Address1;
shipAddr.City = _shippingAddress.City;
shipAddr.CountrySubDivisionCode = _shippingAddress.City;
shipAddr.Country = _shippingAddress.Country;
shipAddr.PostalCode = _shippingAddress.ZipCode;
shipAddr.Note = "Shipping Address Note";
invoice.ShipAddr = shipAddr;

}

invoice.Line = lines.ToArray();

//SalesTermRef
invoice.SalesTermRef = new ReferenceType()
{
name = term.Name,
Value = term.Id
};

//DueDate
invoice.DueDate = DateTime.Now.AddDays(30).Date;
invoice.DueDateSpecified = true;

//ARAccountRef
invoice.ARAccountRef = new ReferenceType()
{
name = account.Name,
Value = account.Id
};

Invoice invoiceAdded = service.Add(invoice);

return invoiceAdded;

Answer Source

Currently every time the loop executes this line

invoice.Line = new Line[] { invoiceLine };

it is overwriting the previous value by assigning a new array. There will always be one item in the array once there are order items based on your current code.

Either store the lines in a list and then convert to an array after processing all the order items.

var orderItems = order.OrderItems;
var lines = new List<Line>();
foreach (var orderItem in orderItems) {
    //Line
    Line invoiceLine = new Line();

    //...code removed for brevity

    lines.Add(invoiceLine);
}    
//Assign Line Items to Invoice
invoice.Line = lines.ToArray();

Or the other option would be to create the array before and populate it as the line items are created.

var orderItems = order.OrderItems;
var lineCount = orderItems.Count();
//Creating Line array before
invoice.Line = new Line[lineCount];   
for (int index = 0; index < lineCount; index++) {
    //Order item
    var orderItem = orderItems[index];
    //Line
    Line invoiceLine = new Line();

    //...code removed for brevity

    //Assign Line Item to Invoice
    invoice.Line[index] = invoiceLine;
}   

UPDATE:

Get the item reference and set the necessary values

var itemRef = itemRepository.Get(i => i.ItemID == orderItem.ItemID).FirstOrDefault();
if (itemRef != null) {
    //Line Sales Item Line Detail - ItemRef
    lineSalesItemLineDetail.ItemRef = new ReferenceType() {
        Name = itemRef.FullDescription,
        Value = itemRef.ItemID 
    };
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download