C# .NET Application with QuickBooks Desktop Edition

This article is an introduction on how to integrate a .NET application with QuickBooks Desktop Edition using the QuickBooks Foundation Classes (QBFC) Library and C#.

Introduction

QuickBooks is a small-business accounting software made by Intuit. It has online and desktop editions (Pro, Premier, etc.). It is widely used and Intuit provided an SDK so that third-party applications can access or write QuickBooks data. Applications communicate with QuickBooks using XML for requests and responses. Fortunately for us .NET developers, Intuit also provided the QBFC Library so we can use C# or VB to build requests or accept responses, although XML (or qbXML as Intuit calls it) is still used internally. I find very few articles regarding the integration of a .NET application with QuickBooks for desktop, which makes it hard for developers just beginning programming with QuickBooks.

Getting Started

In this article, I’ll be creating a WPF application that can add, update, and get some data to and from the QuickBooks company file. For this, we need to have QuickBooks and the QuickBooks SDK installed in our development machine. You can get these from Intuit’s website. The following figure shows the demo application.



Figure 1. Example WPF Application

This application allows the user to add, update, delete and view customers, invoices and items. The right panel content changes according to what Button the user clicked on the left panel. In the figure above, the right panel shows the form for adding, updating or deleting a customer. This form contains a Name and a QuickBooks ID field. The QuickBooks ID field is not editable and will have a value after saving the new customer. Let us implement adding of a customer. In the Save Button’s Click event handler, we will connect to QuickBooks and send a request for adding a customer. To use QBFC in our .NET application, we have to add a reference to the QBFC library. This is found under the COM Tab in the Add Reference dialog. In the example, we’ll be adding qbFC10 1.0 Type Library.



Figure 2. Add Reference to QBFC Library

In writing code for making requests to QuickBooks, the best reference material to check is the Unified Onscreen Reference (OSR). It is installed along with the QuickBooks SDK or can be accessed online at http://developer.intuit.com/qbSDK-Current/Common/newOSR/index.html. This is useful when checking what fields are required when making requests. There are also examples on how to create requests using C# and VB .NET. Since we are interested in adding a customer in QuickBooks, we will select the CustomerAdd message as shown in the figure below. In the Request tab, you can see that the only required field is the Name field.



Figure 3. CustomerAdd Message in Unified Onscreen Reference

Aside from checking what the required fields are, there are also other things we can see in the OSR worth noting like the maximum number (Desktop or Online Edition may differ) of characters for a string-type field or what version of QuickBooks is a field supported. Under the C# tab, there is an example code that we can copy and modify. The example code sets all fields of the request and is more of a guide due to a lot of comments rather than a working example. It might not compile because strings are used in some fields instead of values of the correct types. Going back to our example, we just need to set the required fields. The following code listing shows how to create a customer in QuickBooks via QBFC. I copied the code from the OSR and modified it a bit.

private void SaveBtn_Click(object sender, RoutedEventArgs e)
{
    bool sessionBegun = false;
    bool connectionOpen = false;
    QBSessionManager sessionManager = null;

    try
    {
         //Create the session Manager object
        sessionManager = new QBSessionManager();

        //Create the message set request object to hold our request
        IMsgSetRequest requestMsgSet = sessionManager.CreateMsgSetRequest("US", 8, 0);
        requestMsgSet.Attributes.OnError = ENRqOnError.roeContinue;

         //Connect to QuickBooks and begin a session
        sessionManager.OpenConnection(@"C:\Users\Public\Documents\Intuit\QuickBooks\Company Files\My Company.QBW", "QuickBooks Integration Demo");
        connectionOpen = true;
        sessionManager.BeginSession("", ENOpenMode.omDontCare);
        sessionBegun = true;

        ICustomerAdd customerAddRq = requestMsgSet.AppendCustomerAddRq();
         customerAddRq.Name.SetValue(Customer.Name);

         //Send the request and get the response from QuickBooks
        IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
        IResponse response = responseMsgSet.ResponseList.GetAt(0);
        ICustomerRet customerRet = (ICustomerRet)response.Detail;

        Customer.QuickBooksID = customerRet.ListID.GetValue();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Error");
    }
    finally
     {
        //End the session and close the connection to QuickBooks
        if (sessionBegun)
        {
             sessionManager.EndSession();
        }
         if (connectionOpen)
        {
            sessionManager.CloseConnection();
        }
    }
}

Listing 1. Creating a Customer

The following are the usual steps in making requests to QuickBooks.
1. Create a session manager
2. Open a connection
3. Create a session
4. Create a set of requests
5. Add requests to the set
6. Perform the requests
7. Process the response
8. End the session
9. Close the connection

In the OpenConnection method, we have to specify the path of the company file to be accessed, and the name of the application that will access the company file. If we specify an empty string for the company file path, the current company file that is opened in QuickBooks will be used. In the CreateMsgSetRequest method, you can see that we passed some parameters. These parameters indicate what versions of QuickBooks and qbXML/QBFC the request is targeted at. To check what qbXML specification version is supported by your QuickBooks software, you can check the release notes under the Intuit SDKs folder on the Start menu. After getting an IMsgSetRequest object, we can append requests to it, as shown in the above code when we called the AppendCustomerAddRq method. We then called the DoRequests method to process the requests. This method returns an IMsgSetResponse object, which contains a list of responses, in the form of IResponse objects. Each response corresponds to a request. To get a specific response, we have to use the GetAt method and pass the index of the response. An IResponse object has a Detail property which we can then cast to the appropriate object, ICustomerRet in the above example.

Assuming that we haven’t opened QuickBooks yet and we try to save a new customer using the demo application, we will get the following exception message: Could not start QuickBooks. The reason is that the application is not yet authorized to access the QuickBooks company file.

Authorizing the Application

On the first time that an application connects to a QuickBooks company file, QuickBooks should be opened and a user is there to authorize the access. When we try to save a customer again and QuickBooks is running this time, a dialog will appear in QuickBooks, as shown in the figure below. We should take note that this will block the current thread so if we used the UI thread, then the UI will become unresponsive.



Figure 4. Authorize Application Access in QuickBooks

In the figure above, you can see that the currently opened file is called My Company. Here, we may or may not allow the application have access to the company file. We can also specify whether to prompt us every time the application tries to access the company file or always allow the application to access the company file whether QuickBooks is running or not. In our example, let us allow the application to access the company file even if QuickBooks is not running. After clicking on the Continue… Button, we will see that the customer is added to QuickBooks.

Figure 5. Added Customer in QuickBooks

After the customer is added to the company file, it is given a unique ID within the list of customers, which is called ListID in QuickBooks. In the demo application, the ListID is shown in the QuickBooks ID TextBox.



Figure 6. Customer ListID

Other objects like inventory items and vendors also have ListIDs. The IDs of transactions, like invoices and purchase orders, are called TxnIDs. The ListID is like an auto-increment primary key in SQL Server. Using the ListID, we can get a list object like a customer and update the customer information. Aside from the ListID, the FullName field is also used to uniquely identify a list object in QuickBooks. A FullName is the Name of the list object prefixed with its ancestors’ names. You can think of an ancestor as a category of a list object. To assign a parent to a list object, we have to specify a value in the ParentRef field. In our example, we did not specify a value for this field. Adding a customer of the same name without a different parent will give us an error.

Getting Customers

To get a specific customer, we can use the CustomerQuery method and specify either a ListID or FullName. If both ListID and FullName are specified, the FullName will be ignored. In the demo application however, we will be getting all customers so we won’t be setting the ListID or FullName in the query. When the View All Customers Button is clicked, the right panel will show a DataGrid of customers. The DataGrid is filled with customer details when it is loaded. The following code snippet shows a part of the DataGrid’s Loaded event handler. For brevity, I did not include some parts like creating the session manager and disposing of it.

ICustomerQuery customerQueryRq = requestMsgSet.AppendCustomerQueryRq();                  

//Send the request and get the response from QuickBooks
IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
IResponse response = responseMsgSet.ResponseList.GetAt(0);
ICustomerRetList customerRetList = (ICustomerRetList)response.Detail;

var customers = new List<Customer>();

if (customerRetList != null)
{
    for (int i = 0; i < customerRetList.Count; i++)
    {
        ICustomerRet customerRet = customerRetList.GetAt(i);

        var customer = new Customer
        {
            Name = customerRet.Name.GetValue(),
            QuickBooksID = customerRet.ListID.GetValue(),
            EditSequence = customerRet.EditSequence.GetValue()
         };

        customers.Add(customer);
    }
}

customersDataGrid.ItemsSource = customers;

Listing 2. Getting the List of Customers

You can notice the differences between getting customers and adding a customer. Here we used the AppendCustomerQueryRq method. Also, the Detail property of the IResponse object is an ICustomerRetList object. We can get individual ICustomerRet objects by using the GetAt method. To get the information we need like Name and ListID, remember to use the GetValue method. If we looked at the CustomerQuery message in the Onscreen Reference, we will see fields that we can set to filter the results of the query. For example, we can set the ListIDList so that the query will only return customers that have a matching ListID in the ListIDList. There is also a NameFilter field where we can match a customer using a name. We can also specify whether the query returns the count only, data only, or both using the metaData field. The metaData field is useful when we only want to know the number of results and do not want to load all of the query results into memory since we might be working on thousands of records. Another interesting field is the IncludeRetElementList. Using this, we can specify what fields of the results will have values to limit the data returned by QuickBooks. In our example above, we can add the Name, ListID, and EditSequence fields to the IncludeRetElementList since these are the only fields we are currently interested in. Check out the Onscreen Reference for other fields that you can set. The following figure shows the DataGrid containing the new customer.



Figure 7. List of Customers

In the DataGrid, I have added a Modify Button so that we can edit the customer name (since that is the only field that we can edit in the application). Clicking on the Modify Button will show the customer details on the same form used for adding a customer.
Modifying a Customer

Since adding and modifying a customer is almost the same, I just used the same form although I modified the Save Button’s event handler. The application will determine whether to add or modify a customer object by checking if the QuickBooksID property has a value. Here is the updated code.

if (Customer.QuickBooksID == null)
{
    ICustomerAdd customerAddRq = requestMsgSet.AppendCustomerAddRq();
    customerAddRq.Name.SetValue(Customer.Name);

    //Send the request and get the response from QuickBooks
    IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
    IResponse response = responseMsgSet.ResponseList.GetAt(0);
    ICustomerRet customerRet = (ICustomerRet)response.Detail;

    Customer.QuickBooksID = customerRet.ListID.GetValue();
}
else
{
    ICustomerMod customerModRq = requestMsgSet.AppendCustomerModRq();
    customerModRq.Name.SetValue(Customer.Name);
     customerModRq.ListID.SetValue(Customer.QuickBooksID);
    customerModRq.EditSequence.SetValue(Customer.EditSequence);

    //Send the request to QuickBooks
    sessionManager.DoRequests(requestMsgSet);
}

Listing 3. Adding or Modifying a Customer

In the preceding code, we used the Customer’s QuickBooksID property to determine whether to add or modify a customer. The Customer object is set in the constructor. To modify a customer, we have to use the AppendCustomerModRq method. Aside from setting the Name and ListID fields, we also need to set the required EditSequence field.

The EditSequence field value is generated by QuickBooks for an object and ensures that we won’t be able to modify the object if we are not working on the latest copy. This is useful when there are other people modifying data in QuickBooks. This prevents us from overwriting other people’s modifications. For example, we queried an object from QuickBooks and we are given an EditSequence value. We then passed this EditSequence value along with the request to modify the object. QuickBooks will then compare the EditSequence we passed and the latest EditSequence. If they are the same, the request succeeds. However, if someone modified the object before we can submit our request, then the latest EditSequence will be different and our request will fail. In the demo application, clicking on the Save Button twice (without refreshing the list of customers) would give us an error like the following "The provided edit sequence "1291625289" is out-of-date."

Deleting a List Object

Deleting a list object is a bit different from creating or modifying it. For a customer list object, we have requests like ICustomerAdd, ICustomerMod and ICustomerQuery. However, the QuickBooks SDK does not have an ICustomerDel. Instead, there is an IListDel request, which is the request used for deleting list objects. You can specify what type of list object to delete using the ListDelType field, as shown in the following code snippet.

IListDel listDelRq = requestMsgSet.AppendListDelRq();
listDelRq.ListDelType.SetValue(ENListDelType.ldtCustomer);
listDelRq.ListID.SetValue(qbIdTbx.Text);

//Send the request to QuickBooks
sessionManager.DoRequests(requestMsgSet);

Listing 4. Deleting a Customer

Clicking on the Delete Button will delete the customer from QuickBooks. However, if the customer had been referenced by a transaction, say an invoice, the customer can’t be deleted. You can either make the customer inactive or delete first all the transactions that reference the customer.

Differences between Customer and Item

Before we can make a sales invoice, we should have a customer and the items the customer bought. We already have the code for adding customers in our application, leaving us with the code for creating items. Although customer and item types are both list objects in QuickBooks, there are some differences we need to know of. Here’s the code for adding or modifying an item in the demo application.

if (Item.QuickBooksID == null)
{
    if (Item.ItemType == ItemType.Inventory)
    {
        IItemInventoryAdd itemInventoryAddRq = requestMsgSet.AppendItemInventoryAddRq();
         itemInventoryAddRq.Name.SetValue(Item.Name);
        itemInventoryAddRq.SalesDesc.SetValue(Item.Description);
        itemInventoryAddRq.SalesPrice.SetValue(Item.Rate);
        itemInventoryAddRq.IncomeAccountRef.FullName.SetValue("Sales - Hardware");
        itemInventoryAddRq.AssetAccountRef.FullName.SetValue("Inventory");
        itemInventoryAddRq.COGSAccountRef.FullName.SetValue("Purchases - Hardware for Resale");

        //Send the request and get the response from QuickBooks
        IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
        IResponse response = responseMsgSet.ResponseList.GetAt(0);
        IItemInventoryRet itemInventoryRet = (IItemInventoryRet)response.Detail;

        Item.QuickBooksID = itemInventoryRet.ListID.GetValue();
    }
    else // ItemType.Service
    {
        IItemServiceAdd itemServiceAddRq = requestMsgSet.AppendItemServiceAddRq();
         itemServiceAddRq.Name.SetValue(Item.Name);
        itemServiceAddRq.ORSalesPurchase.SalesOrPurchase.Desc.SetValue(Item.Description);
        itemServiceAddRq.ORSalesPurchase.SalesOrPurchase.ORPrice.Price.SetValue(Item.Rate);
        itemServiceAddRq.ORSalesPurchase.SalesOrPurchase.AccountRef.FullName.SetValue("Sales - Support and Maintenance");

        //Send the request and get the response from QuickBooks
        IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
        IResponse response = responseMsgSet.ResponseList.GetAt(0);
        IItemServiceRet itemServiceRet = (IItemServiceRet)response.Detail;

        Item.QuickBooksID = itemServiceRet.ListID.GetValue();
    }
}
else
{
    if (Item.ItemType == ItemType.Inventory)
    {
        IItemInventoryMod itemInventoryModRq = requestMsgSet.AppendItemInventoryModRq();
         itemInventoryModRq.Name.SetValue(Item.Name);
        itemInventoryModRq.SalesDesc.SetValue(Item.Description);
        itemInventoryModRq.SalesPrice.SetValue(Item.Rate);
        itemInventoryModRq.ListID.SetValue(Item.QuickBooksID);
        itemInventoryModRq.EditSequence.SetValue(Item.EditSequence);

        //Send the request to QuickBooks
        sessionManager.DoRequests(requestMsgSet);
    }
    else // ItemType.Service
    {
        IItemServiceMod itemServiceModRq = requestMsgSet.AppendItemServiceModRq();
         itemServiceModRq.Name.SetValue(Item.Name);
        itemServiceModRq.ORSalesPurchaseMod.SalesOrPurchaseMod.Desc.SetValue(Item.Description);
        itemServiceModRq.ORSalesPurchaseMod.SalesOrPurchaseMod.ORPrice.Price.SetValue(Item.Rate);
        itemServiceModRq.ListID.SetValue(Item.QuickBooksID);
        itemServiceModRq.EditSequence.SetValue(Item.EditSequence);

        //Send the request to QuickBooks
        sessionManager.DoRequests(requestMsgSet);
    }
}

Listing 5. Adding or Modifying an Item

There are several types of items in QuickBooks. There are inventory, non-inventory, and service items, among others. I only used inventory and service items in the demo application. In the preceding code, you can see that there are different requests for the different types of items. That is because different types of items will have different fields. An inventory item has a QuantityOnHand field while a service item doesn’t. Some requests also require that you reference income accounts, asset accounts, etc. On the other hand, deleting an item doesn’t differ much from deleting a customer. We just need to use an if-else construct again to determine whether to delete an inventory or service item.

IListDel listDelRq = requestMsgSet.AppendListDelRq();
listDelRq.ListID.SetValue(Item.QuickBooksID);

if (Item.ItemType == ItemType.Inventory)
{
    listDelRq.ListDelType.SetValue(ENListDelType.ldtItemInventory);
}
else // ItemType.Service
{
    listDelRq.ListDelType.SetValue(ENListDelType.ldtItemService);
}

//Send the request to QuickBooks
sessionManager.DoRequests(requestMsgSet);

Listing 6. Deleting an Item

When querying items from QuickBooks, we have an option to use the different requests for the different types of items. Some requests are IItemInventoryQuery and IItemServiceQuery. We can also get all the items, regardless of type, by using the IItemQuery request. This is what we used in viewing all the items in the demo application.

IItemQuery itemQueryRq = requestMsgSet.AppendItemQueryRq();     

//Send the request and get the response from QuickBooks
IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
IResponse response = responseMsgSet.ResponseList.GetAt(0);
IORItemRetList itemRetList = (IORItemRetList)response.Detail;

var items = new List<Item>();

if (itemRetList != null)
{
    for (int i = 0; i < itemRetList.Count; i++)
    {
        IORItemRet itemRet = itemRetList.GetAt(i);

         if (itemRet.ItemInventoryRet != null)
        {
            IItemInventoryRet itemInventoryRet = itemRet.ItemInventoryRet;

            var item = new Item
            {
                Name = itemInventoryRet.Name.GetValue(),
                Description = itemInventoryRet.SalesDesc.GetValue(),
                Rate = itemInventoryRet.SalesPrice.GetValue(),
                ItemType = ItemType.Inventory,
                QuickBooksID = itemInventoryRet.ListID.GetValue(),
                EditSequence = itemInventoryRet.EditSequence.GetValue()
             };

             items.Add(item);
        }
         else if (itemRet.ItemServiceRet != null)
        {
            IItemServiceRet itemServiceRet = itemRet.ItemServiceRet;

            var item = new Item
            {
                Name = itemServiceRet.Name.GetValue(),
                Description = itemServiceRet.ORSalesPurchase.SalesOrPurchase.Desc.GetValue(),
                Rate = itemServiceRet.ORSalesPurchase.SalesOrPurchase.ORPrice.Price.GetValue(),
                ItemType = ItemType.Service,
                QuickBooksID = itemServiceRet.ListID.GetValue(),
                EditSequence = itemServiceRet.EditSequence.GetValue()
             };

             items.Add(item);
        }
    }
}

itemsDataGrid.ItemsSource = items;

Listing 7. Getting All Items

In the preceding code, the Detail property of the IResponse object is of type IORItemRetList. It is the list of the items we queried and we can get individual IORItemRet objects by using the GetAt method. The actual item object is stored in one of the IORItemRet properties. If the item is of type IItemServiceRet, then it is stored in the IORItemRet’s ItemServiceRet property. By checking if a property is not null, we can determine the type of the item.

Creating an Invoice

To create an invoice, we are required to pass a reference to the customer and the items he purchased. That is why I showed how to create customers and items first. In the demo application, we have the following form used for creating or modifying an invoice.



Figure 8. Invoice Form

In the example above, we have an existing customer named test and an item called part 1. After the invoice has been saved, the invoice will have an assigned transaction ID. This will be shown in the QuickBooks ID TextBox. An invoice can contain the items purchased by the customer and each row in the DataGrid corresponds to an invoice line in QuickBooks. An invoice line is also assigned a unique ID, which we can refer to as transaction line ID. Here is a screenshot of the application after saving the sample invoice.



Figure 9. Saved Invoice

The code for adding an invoice is not much different from creating a customer. We just have to specify the invoice lines. To add an invoice line, we can append an IORInvoiceLineAdd request to the ORInvoiceLineAddList property of the IInvoiceAdd request. We don’t directly append it to the IMsgSetRequest object.

IInvoiceAdd invoiceAddRq = requestMsgSet.AppendInvoiceAddRq();
invoiceAddRq.CustomerRef.ListID.SetValue(Invoice.Customer.QuickBooksID);

foreach (InvoiceItem invoiceItem in Invoice.InvoiceItems)
{
    IORInvoiceLineAdd orInvoiceLineAdd = invoiceAddRq.ORInvoiceLineAddList.Append();
    orInvoiceLineAdd.InvoiceLineAdd.ItemRef.ListID.SetValue(invoiceItem.Item.QuickBooksID);
    orInvoiceLineAdd.InvoiceLineAdd.Amount.SetValue(invoiceItem.Amount);
}

//Send the request and get the response from QuickBooks
IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
IResponse response = responseMsgSet.ResponseList.GetAt(0);
IInvoiceRet invoiceRet = (IInvoiceRet)response.Detail;
                    
Invoice.QuickBooksID = invoiceRet.TxnID.GetValue();

for (int i = 0; i < invoiceRet.ORInvoiceLineRetList.Count; i++)
{
    Invoice.InvoiceItems[i].QuickBooksID = invoiceRet.ORInvoiceLineRetList.GetAt(i).InvoiceLineRet.TxnLineID.GetValue();
}

Listing 8. Adding an Invoice

Meanwhile, modifying an invoice deserves a little more explanation.

Modifying an Invoice

To modify an invoice, we need to use the IInvoiceMod request. However, it is not as straightforward as editing a customer since an invoice has invoice lines. We can delete an invoice line from an invoice, modify an invoice line, or add a new one. Strictly speaking, we cannot actually delete an invoice line. However, we can replace the existing invoice lines with a new set of invoice lines. To make it look like we deleted an invoice line, we can pass the same set of invoice lines minus the invoice line we want to delete. Since we are replacing invoice lines to mimic a deletion, we cannot delete an invoice line if it is the only invoice line in the invoice. Here is the code for modifying an invoice.

IInvoiceMod invoiceModRq = requestMsgSet.AppendInvoiceModRq();
invoiceModRq.CustomerRef.ListID.SetValue(Invoice.Customer.QuickBooksID);
invoiceModRq.TxnID.SetValue(Invoice.QuickBooksID);
invoiceModRq.EditSequence.SetValue(Invoice.EditSequence);

foreach (InvoiceItem invoiceItem in Invoice.InvoiceItems)
{
    IORInvoiceLineMod orInvoiceLineMod = invoiceModRq.ORInvoiceLineModList.Append();
    if (invoiceItem.QuickBooksID == null)
        orInvoiceLineMod.InvoiceLineMod.TxnLineID.SetValue("-1");
    else
        orInvoiceLineMod.InvoiceLineMod.TxnLineID.SetValue(invoiceItem.QuickBooksID);
    orInvoiceLineMod.InvoiceLineMod.ItemRef.ListID.SetValue(invoiceItem.Item.QuickBooksID);
    orInvoiceLineMod.InvoiceLineMod.Amount.SetValue(invoiceItem.Amount);
}

//Send the request to QuickBooks
IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
IResponse response = responseMsgSet.ResponseList.GetAt(0);
IInvoiceRet invoiceRet = (IInvoiceRet)response.Detail;

for (int i = 0; i < invoiceRet.ORInvoiceLineRetList.Count; i++)
{
    if (Invoice.InvoiceItems[i].QuickBooksID == null)
        Invoice.InvoiceItems[i].QuickBooksID =
            invoiceRet.ORInvoiceLineRetList.GetAt(i).InvoiceLineRet.TxnLineID.GetValue();
}

Listing 9. Modifying an Invoice

To modify an existing invoice line, we need to append an IORInvoiceLineMod request and set its InvoiceLineMod.TxnLineID property to the transaction line ID of the invoice line. If we want to add a new invoice line, we have to set the TxnLineID to “-1” as you can see in the preceding code listing.

Getting Invoices

The code for getting invoices is a bit longer because we also need to get the details of the customer and the items referenced by the invoice. By default, invoice lines are not included in the query results so we have to set the IncludeLineItems property to true.

IInvoiceQuery invoiceQueryRq = requestMsgSet.AppendInvoiceQueryRq();
invoiceQueryRq.IncludeLineItems.SetValue(true);

//Send the request and get the response from QuickBooks
IMsgSetResponse responseMsgSet = sessionManager.DoRequests(requestMsgSet);
IResponse response = responseMsgSet.ResponseList.GetAt(0);
IInvoiceRetList invoiceRetList = (IInvoiceRetList)response.Detail;

var invoices = new List<Invoice>();

if (invoiceRetList != null)
{
    for (int i = 0; i < invoiceRetList.Count; i++)
    {
        IInvoiceRet invoiceRet = invoiceRetList.GetAt(i);

        var invoice = new Invoice
        {                                                        
            QuickBooksID = invoiceRet.TxnID.GetValue(),
            EditSequence = invoiceRet.EditSequence.GetValue()
        };

        requestMsgSet.ClearRequests();
        ICustomerQuery customerQueryRq = requestMsgSet.AppendCustomerQueryRq();
         customerQueryRq.ORCustomerListQuery.ListIDList.Add(invoiceRet.CustomerRef.ListID.GetValue());

         //Send the request and get the response from QuickBooks
        responseMsgSet = sessionManager.DoRequests(requestMsgSet);
        response = responseMsgSet.ResponseList.GetAt(0);
        ICustomerRetList customerRetList = (ICustomerRetList)response.Detail;
        ICustomerRet customerRet = customerRetList.GetAt(0);

        invoice.Customer = new Customer
        {
            Name = customerRet.Name.GetValue(),
            QuickBooksID = customerRet.ListID.GetValue(),
            EditSequence = customerRet.EditSequence.GetValue()
         };

        if (invoiceRet.ORInvoiceLineRetList != null)
        {
             for (int j = 0; j < invoiceRet.ORInvoiceLineRetList.Count; j++)
            {
                IORInvoiceLineRet ORInvoiceLineRet = invoiceRet.ORInvoiceLineRetList.GetAt(j);

                var invoiceItem = new InvoiceItem
                {
                    Amount = ORInvoiceLineRet.InvoiceLineRet.Amount.GetValue(),
                    QuickBooksID = ORInvoiceLineRet.InvoiceLineRet.TxnLineID.GetValue()
                };

                requestMsgSet.ClearRequests();
                IItemQuery itemQueryRq = requestMsgSet.AppendItemQueryRq();
                 itemQueryRq.ORListQuery.ListIDList.Add(ORInvoiceLineRet.InvoiceLineRet.ItemRef.ListID.GetValue());

                  //Send the request and get the response from QuickBooks
                responseMsgSet = sessionManager.DoRequests(requestMsgSet);
                response = responseMsgSet.ResponseList.GetAt(0);
                IORItemRetList itemRetList = (IORItemRetList)response.Detail;
                IORItemRet itemRet = itemRetList.GetAt(0);

                 if (itemRet.ItemInventoryRet != null)
                {
                    IItemInventoryRet itemInventoryRet = itemRet.ItemInventoryRet;

                    var item = new Item
                    {
                        Name = itemInventoryRet.Name.GetValue(),
                        Description = itemInventoryRet.SalesDesc.GetValue(),
                        Rate = itemInventoryRet.SalesPrice.GetValue(),
                        ItemType = ItemType.Inventory,
                        QuickBooksID = itemInventoryRet.ListID.GetValue(),
                        EditSequence = itemInventoryRet.EditSequence.GetValue()
                    };

                    invoiceItem.Item = item;
                 }
                 else if (itemRet.ItemServiceRet != null)
                {
                    IItemServiceRet itemServiceRet = itemRet.ItemServiceRet;

                    var item = new Item
                    {
                        Name = itemServiceRet.Name.GetValue(),
                        Description = itemServiceRet.ORSalesPurchase.SalesOrPurchase.Desc.GetValue(),
                        Rate = itemServiceRet.ORSalesPurchase.SalesOrPurchase.ORPrice.Price.GetValue(),
                        ItemType = ItemType.Service,
                        QuickBooksID = itemServiceRet.ListID.GetValue(),
                        EditSequence = itemServiceRet.EditSequence.GetValue()
                    };

                    invoiceItem.Item = item;
                 }

                 invoice.InvoiceItems.Add(invoiceItem);
             }
        }

        invoices.Add(invoice);
    }
}

invoicesDataGrid.ItemsSource = invoices;

Listing 10. Getting Invoices

In the above code, we have several requests: get an invoice, get the referenced customer, and get the referenced items. The same IMsgSetRequest object is used for these requests and the ClearRequests method is used to remove existing requests in the set so they are not processed more than once.

Deleting a Transaction

Deleting a transaction is similar to deleting a list object. We have to specify the type of transaction to delete and the ID of the transaction. The difference is that we will use an ITxnDel request instead of IListDel.

ITxnDel txnDelRq = requestMsgSet.AppendTxnDelRq();
txnDelRq.TxnDelType.SetValue(ENTxnDelType.tdtInvoice);
txnDelRq.TxnID.SetValue(Invoice.QuickBooksID);

//Send the request to QuickBooks
sessionManager.DoRequests(requestMsgSet);

Listing 11. Delete a Transaction

I hope I covered at least the basics of programming with .NET and QuickBooks using the QBFC Library. The Visual Studio 2010 solution of the demo application can be downloaded here.

By Michael Detras   Popularity  (9052 Views)
Biography - Michael Detras
.NET developer. Interested in WPF, Silverlight, and XNA.
My blog