diff --git a/AyaNovaQBI/util.cs b/AyaNovaQBI/util.cs
index 74903e3..45f32d7 100644
--- a/AyaNovaQBI/util.cs
+++ b/AyaNovaQBI/util.cs
@@ -10,6 +10,7 @@ using Newtonsoft.Json.Linq;
using Interop.QBFC15;
using System.Text.RegularExpressions;
using System.Windows.Forms;
+using System.Data;
namespace AyaNovaQBI
{
@@ -891,6 +892,1528 @@ namespace AyaNovaQBI
#endregion qb specific utils
+ #region QB API helper methods/ attributes/cached lists
+ ///
+ /// Populate or repopulate the list of
+ ///
+ public static void PopulateQBListCache()
+ {
+ //Get the cached QB data
+ Waiting w = new Waiting();
+ w.Show();
+ w.Ops = "Reading from QuickBooks...";
+
+
+
+ w.Step = "Classes";
+ PopulateQBClassCache();
+
+ w.Step = "Vendors";
+ PopulateQBVendorCache();
+
+ w.Step = "Customers";
+ PopulateQBClientCache();
+
+ w.Step = "Items";
+ PopulateQBItemCache();
+
+ if (!(QVersion < 3))//qbXML 3.0 or higher (QB 2004 any country or newer)
+ {
+ w.Step = "Invoice templates";
+ PopulateQBInvoiceTemplates();
+ }
+
+ //case 632
+ w.Step = "Accounts";
+ PopulateQBAccountCache();
+
+ //case 519
+ w.Step = "Terms";
+ PopulateQBTermsCache();
+
+ w.Close();
+ }
+
+ #region QuickBooks "items"
+ public enum qbitemtype
+ {
+ Inventory,
+ NonInventory,
+ Service,
+ OtherCharge,
+ Assembly
+
+ }
+
+ private static DataTable _dtQBItems = null;
+
+ ///
+ /// qb items
+ ///
+ public static DataTable QBItems
+ {
+ get
+ {
+ return _dtQBItems;
+ }
+ }
+
+
+ ///
+ /// Given a QB Item ID, return the
+ /// AyaNova Vendor ID linked to that items
+ /// QB preferred Vendor ID or
+ /// Guid empty on any problem or not found
+ ///
+ ///
+ ///
+ public static Guid AyaVendorForQBItem(string QBItemID)
+ {
+ if (QBItemID == null || QBItemID == "") return Guid.Empty;
+ DataRow dr = _dtQBItems.Rows.Find(QBItemID);
+ if (dr == null || dr["VendorID"] == null || dr["VendorID"].ToString() == "") return Guid.Empty;
+
+ DataRow drVendor = _dtQBVendors.Rows.Find(dr["VendorID"].ToString());
+ if (drVendor == null) return Guid.Empty;
+
+ if (!QBI.Maps.Contains(drVendor["ID"].ToString(), RootObjectTypes.Vendor)) return Guid.Empty;
+
+ //Ok we have a matching vendor in the list, return the guid of it
+ return QBI.Maps[drVendor["ID"].ToString(), RootObjectTypes.Vendor].RootObjectID;
+ }
+
+
+ ///
+ /// Populate the cached qb data
+ /// billable
+ ///
+ private static void PopulateQBItemCache()
+ {
+ if (_dtQBItems == null)
+ {
+ _dtQBItems = new DataTable("QBItems");
+ //setup the columns
+ _dtQBItems.Columns.Add("ID", typeof(string));
+ _dtQBItems.Columns.Add("FullName", typeof(string));
+ _dtQBItems.Columns.Add("Type", typeof(qbitemtype));
+ _dtQBItems.Columns.Add("Modified", typeof(DateTime));
+ _dtQBItems.Columns.Add("Price", typeof(decimal));
+
+ _dtQBItems.Columns.Add("Cost", typeof(decimal));
+ _dtQBItems.Columns.Add("SalesDesc", typeof(string));
+ _dtQBItems.Columns.Add("ReorderPoint", typeof(decimal));
+ _dtQBItems.Columns.Add("VendorID", typeof(string));
+
+
+
+ _dtQBItems.PrimaryKey = new DataColumn[] { _dtQBItems.Columns[0] };
+
+ //Case 237
+ _dtQBItems.DefaultView.Sort = "FullName asc";
+ }
+ else
+ _dtQBItems.Clear();
+
+ //Connect to QB and fill
+ // IY: Create the session manager object using QBFC
+ QBSessionManager sessionManager = new QBSessionManager();
+
+ // IY: We want to know if we begun a session so we can end it if an
+ // error happens
+ bool booSessionBegun = false;
+
+ try
+ {
+ // IY: Get the RequestMsgSet based on the correct QB Version
+ IMsgSetRequest requestSet = getLatestMsgSetRequest(sessionManager);
+
+ // IY: Initialize the message set request object
+ requestSet.Attributes.OnError = ENRqOnError.roeStop;
+
+ // IY: Add the request to the message set request object
+ IItemQuery ItemQ = requestSet.AppendItemQueryRq();
+
+ //Active items only
+ ItemQ.ORListQuery.ListFilter.ActiveStatus.SetValue(ENActiveStatus.asActiveOnly);
+
+
+ //This is intended to be called after already sucessfully connected
+ //to get version info so no special safety checks here
+ sessionManager.OpenConnection2("", "AyaNova QBI", ENConnectionType.ctLocalQBDLaunchUI);
+ sessionManager.BeginSession("", ENOpenMode.omDontCare);
+ booSessionBegun = true;
+
+ // IY: Do the request and get the response message set object
+ IMsgSetResponse responseSet = sessionManager.DoRequests(requestSet);
+
+ // Uncomment the following to view and save the request and response XML
+ //string requestXML = requestSet.ToXMLString();
+ //MessageBox.Show(requestXML);
+ // SaveXML(requestXML);
+ //string responseXML = responseSet.ToXMLString();
+ //MessageBox.Show(responseXML);
+ // SaveXML(responseXML);
+
+ IResponse response = responseSet.ResponseList.GetAt(0);
+
+ //Added: 21-June-2006 nonzero status codes 500 and higher are serious errors, less than 500 could just mean no matching items in list
+ if (response.StatusCode > 499)
+ {
+ throw new ApplicationException(response.StatusMessage + " Code: " + response.StatusCode);
+
+ }
+
+ //Added: 21-June-2006 outer if to avoid crash on no match response (code 1)
+ if (response.StatusCode == 0)
+ {
+
+ IORItemRetList orItemRetList = response.Detail as IORItemRetList;
+
+ if (!(orItemRetList.Count == 0))
+ {
+ for (int ndx = 0; ndx <= (orItemRetList.Count - 1); ndx++)
+ {
+ IORItemRet orItemRet = orItemRetList.GetAt(ndx);
+
+ // IY: The ortype property returns an enum
+ // of the elements that can be contained in the OR object
+ switch (orItemRet.ortype)
+ {
+ case ENORItemRet.orirItemServiceRet:
+ {
+ // orir prefix comes from OR + Item + Ret
+ IItemServiceRet ItemServiceRet = orItemRet.ItemServiceRet;
+
+ IORSalesPurchase sp = ItemServiceRet.ORSalesPurchase;
+ _dtQBItems.Rows.Add(new object[] {
+ ItemServiceRet.ListID.GetValue(),
+ ItemServiceRet.FullName.GetValue(),
+ qbitemtype.Service,
+ ItemServiceRet.TimeModified.GetValue(),
+ PriceGrabber(sp),
+ CostGrabber(sp),
+ SalesDescGrabber(sp),
+ 0,
+ PrefVendorGrabber(sp)
+
+ });
+
+
+
+
+ }
+ break;
+ case ENORItemRet.orirItemInventoryRet:
+ {
+ IItemInventoryRet ItemInventoryRet = orItemRet.ItemInventoryRet;
+ _dtQBItems.Rows.Add(new object[] {
+ ItemInventoryRet.ListID.GetValue(),
+ ItemInventoryRet.FullName.GetValue(),
+ qbitemtype.Inventory,
+ ItemInventoryRet.TimeModified.GetValue(),
+ PriceGrabber(ItemInventoryRet.SalesPrice),
+ PriceGrabber(ItemInventoryRet.PurchaseCost),
+ ProcessQBString(ItemInventoryRet.SalesDesc),
+ QuanGrabber(ItemInventoryRet.ReorderPoint),
+ BaseRefIDGrabber(ItemInventoryRet.PrefVendorRef)
+
+
+
+ });
+ }
+ break;
+ case ENORItemRet.orirItemNonInventoryRet:
+ {
+ IItemNonInventoryRet ItemNonInventoryRet = orItemRet.ItemNonInventoryRet;
+ _dtQBItems.Rows.Add(new object[] {
+ ItemNonInventoryRet.ListID.GetValue(),
+ ItemNonInventoryRet.FullName.GetValue(),
+ qbitemtype.NonInventory,
+ ItemNonInventoryRet.TimeModified.GetValue(),
+ PriceGrabber(ItemNonInventoryRet.ORSalesPurchase),
+ CostGrabber(ItemNonInventoryRet.ORSalesPurchase),
+ SalesDescGrabber(ItemNonInventoryRet.ORSalesPurchase),
+ 0,
+ PrefVendorGrabber(ItemNonInventoryRet.ORSalesPurchase)
+
+ });
+ }
+ break;
+ case ENORItemRet.orirItemOtherChargeRet:
+ {
+ IItemOtherChargeRet ItemOtherChargeRet = orItemRet.ItemOtherChargeRet;
+ _dtQBItems.Rows.Add(new object[] {
+ ItemOtherChargeRet.ListID.GetValue(),
+ ItemOtherChargeRet.FullName.GetValue(),
+ qbitemtype.OtherCharge,
+ ItemOtherChargeRet.TimeModified.GetValue(),
+ PriceGrabber(ItemOtherChargeRet.ORSalesPurchase),
+ CostGrabber(ItemOtherChargeRet.ORSalesPurchase),
+ SalesDescGrabber(ItemOtherChargeRet.ORSalesPurchase),
+ 0,
+ PrefVendorGrabber(ItemOtherChargeRet.ORSalesPurchase)
+
+ });
+ }
+ break;
+ case ENORItemRet.orirItemInventoryAssemblyRet:
+ {
+ IItemInventoryAssemblyRet ItemInventoryAssemblyRet = orItemRet.ItemInventoryAssemblyRet;
+ _dtQBItems.Rows.Add(new object[] {
+ ItemInventoryAssemblyRet.ListID.GetValue(),
+ ItemInventoryAssemblyRet.FullName.GetValue(),
+ qbitemtype.Assembly,
+ ItemInventoryAssemblyRet.TimeModified.GetValue(),
+ PriceGrabber(ItemInventoryAssemblyRet.SalesPrice),
+ PriceGrabber(ItemInventoryAssemblyRet.PurchaseCost),
+ ProcessQBString(ItemInventoryAssemblyRet.SalesDesc),
+ QuanGrabber(ItemInventoryAssemblyRet.BuildPoint),
+ BaseRefIDGrabber(ItemInventoryAssemblyRet.PrefVendorRef)
+
+ });
+ }
+ break;
+ }
+ } // for loop
+ } // if
+
+ }
+ // IY: Close the session and connection with QuickBooks
+ sessionManager.EndSession();
+ booSessionBegun = false;
+ sessionManager.CloseConnection();
+
+
+ }
+ catch (Exception ex)
+ {
+ await IntegrationLog( "PopulateQBItems: Failed with exception:" + ex.Message);
+ if (booSessionBegun)
+ {
+ sessionManager.EndSession();
+ sessionManager.CloseConnection();
+ }
+ throw;
+ }
+
+ }
+
+
+ ///
+ /// Given a qb BaseRef object
+ /// return the ListID or empty string if null
+ ///
+ ///
+ ///
+ private static string BaseRefIDGrabber(IQBBaseRef b)
+ {
+
+
+ if (b != null && b.ListID != null)
+ {
+ return b.ListID.GetValue();
+ }
+ return "";
+
+
+
+ }
+
+ ///
+ /// Given a qb Pricetype object
+ /// return the price or zero on any issue
+ ///
+ ///
+ ///
+ private static decimal PriceGrabber(IQBPriceType p)
+ {
+ decimal d = 0;//default
+
+ if (p != null)
+ {
+ d = System.Convert.ToDecimal(p.GetValue());
+ }
+
+
+ return d;
+ }
+ ///
+ /// Given a qb IQBQuanType object
+ /// return the value as decimal or zero on any issue
+ ///
+ ///
+ ///
+ private static decimal QuanGrabber(IQBQuanType p)
+ {
+ decimal d = 0;//default
+
+ if (p != null)
+ {
+ d = System.Convert.ToDecimal(p.GetValue());
+ }
+
+
+ return d;
+ }
+ ///
+ /// Given a qb salespurchase object
+ /// return the price
+ ///
+ ///
+ ///
+ private static decimal PriceGrabber(IORSalesPurchase sp)
+ {
+ decimal d = 0;//default
+ decimal d1 = 0;
+ decimal d2 = 0;
+ if (sp != null)
+ {
+ if (sp.SalesOrPurchase != null && sp.SalesOrPurchase.ORPrice != null && sp.SalesOrPurchase.ORPrice.Price != null)
+ {
+ d1 = System.Convert.ToDecimal(sp.SalesOrPurchase.ORPrice.Price.GetValue());
+ }
+
+ if (sp.SalesAndPurchase != null && sp.SalesAndPurchase.SalesPrice != null)
+ {
+ d2 = System.Convert.ToDecimal(sp.SalesAndPurchase.SalesPrice.GetValue());
+ }
+
+ //get the highest price of the two
+
+ if (d1 > d2)
+ d = d1;
+ else
+ d = d2;
+ }
+
+
+ return d;
+ }
+
+
+ ///
+ /// Given a qb salespurchase object
+ /// return the purchase cose
+ ///
+ ///
+ ///
+ private static decimal CostGrabber(IORSalesPurchase sp)
+ {
+ decimal d = 0;//default
+
+ if (sp != null)
+ {
+
+ if (sp.SalesAndPurchase != null && sp.SalesAndPurchase.PurchaseCost != null)
+ {
+ d = System.Convert.ToDecimal(sp.SalesAndPurchase.PurchaseCost.GetValue());
+ }
+
+
+ }
+
+
+ return d;
+ }
+
+ ///
+ /// return the sales description if available
+ ///
+ ///
+ ///
+ private static string SalesDescGrabber(IORSalesPurchase sp)
+ {
+ string str = "";
+
+ if (sp != null)
+ {
+
+ if (sp.SalesOrPurchase != null && sp.SalesOrPurchase.Desc != null)
+ {
+ str = sp.SalesOrPurchase.Desc.GetValue();
+ }
+
+
+ if (sp.SalesAndPurchase != null && sp.SalesAndPurchase.SalesDesc != null)
+ {
+ str = sp.SalesAndPurchase.SalesDesc.GetValue();
+ }
+
+
+ }
+
+
+ return str;
+ }
+
+ ///
+ /// return the preferred vendor if available
+ ///
+ ///
+ ///
+ private static string PrefVendorGrabber(IORSalesPurchase sp)
+ {
+ string str = "";
+
+ if (sp != null)
+ {
+
+ if (sp.SalesAndPurchase != null && sp.SalesAndPurchase.PrefVendorRef != null && sp.SalesAndPurchase.PrefVendorRef.ListID != null)
+ {
+ str = sp.SalesAndPurchase.PrefVendorRef.ListID.GetValue();
+ }
+
+
+ }
+
+
+ return str;
+ }
+ #endregion quickbooks items
+
+ #region QuickBooks "Transactionclasses"
+
+
+ private static DataTable _dtQBClasses = null;
+
+ ///
+ /// QB Transaction Classes
+ ///
+ public static DataTable QBClasses
+ {
+ get
+ {
+ return _dtQBClasses;
+ }
+ }
+
+
+
+
+ ///
+ /// Populate the cached qb data
+ /// billable
+ ///
+ private static void PopulateQBClassCache()
+ {
+ if (_dtQBClasses == null)
+ {
+ _dtQBClasses = new DataTable("QBClasses");
+ //setup the columns
+ _dtQBClasses.Columns.Add("ID", typeof(string));
+ _dtQBClasses.Columns.Add("FullName", typeof(string));
+
+
+ _dtQBClasses.PrimaryKey = new DataColumn[] { _dtQBClasses.Columns[0] };
+ //Case 237
+ _dtQBClasses.DefaultView.Sort = "FullName asc";
+ }
+ else
+ _dtQBClasses.Clear();
+
+ //case 3268
+ _dtQBClasses.Rows.Add(new object[] { TRANSACTION_CLASS_NO_CLASS_SELECTED, "< Do not use classes >" });
+
+ //Connect to QB and fill
+ // IY: Create the session manager object using QBFC
+ QBSessionManager sessionManager = new QBSessionManager();
+
+ // IY: We want to know if we begun a session so we can end it if an
+ // error happens
+ bool booSessionBegun = false;
+
+ try
+ {
+ // IY: Get the RequestMsgSet based on the correct QB Version
+ IMsgSetRequest requestSet = getLatestMsgSetRequest(sessionManager);
+
+ // IY: Initialize the message set request object
+ requestSet.Attributes.OnError = ENRqOnError.roeStop;
+
+ // IY: Add the request to the message set request object
+ IClassQuery cq = requestSet.AppendClassQueryRq();
+
+ //transactions
+ cq.ORListQuery.ListFilter.ActiveStatus.SetValue(ENActiveStatus.asActiveOnly);
+
+
+
+ //This is intended to be called in a secondary thread immediately after already sucessfully connected
+ //to get version info so no special safety checks here
+ sessionManager.OpenConnection2("", "AyaNova QBI", ENConnectionType.ctLocalQBDLaunchUI);
+ sessionManager.BeginSession("", ENOpenMode.omDontCare);
+ booSessionBegun = true;
+
+ // IY: Do the request and get the response message set object
+ IMsgSetResponse responseSet = sessionManager.DoRequests(requestSet);
+
+ // Uncomment the following to view and save the request and response XML
+ //string requestXML = requestSet.ToXMLString();
+ //MessageBox.Show(requestXML);
+ // SaveXML(requestXML);
+ //string responseXML = responseSet.ToXMLString();
+ //MessageBox.Show(responseXML);
+ // SaveXML(responseXML);
+
+ IResponse response = responseSet.ResponseList.GetAt(0);
+ //nonzero indicates an error, likely no classes defined
+ if (response.StatusCode == 0)
+ {
+
+ //int statusCode = response.StatusCode;
+ //string statusMessage = response.StatusMessage;
+ //string statusSeverity = response.StatusSeverity;
+ //MessageBox.Show("Status:\nCode = " + statusCode + "\nMessage = " + statusMessage + "\nSeverity = " + statusSeverity);
+ IClassRetList cl = response.Detail as IClassRetList;
+
+ if (!(cl.Count == 0))
+ {
+ for (int ndx = 0; ndx <= (cl.Count - 1); ndx++)
+ {
+ IClassRet clitem = cl.GetAt(ndx);
+ if (clitem != null && clitem.FullName != null && clitem.ListID != null)
+ {
+ //add a record to the datatable
+ _dtQBClasses.Rows.Add(new object[] { clitem.ListID.GetValue(), clitem.FullName.GetValue() });
+ }
+ } // for loop
+ } // if
+ }//if status ==0 nonzero means some error, probably no classes defined
+
+ // IY: Close the session and connection with QuickBooks
+ sessionManager.EndSession();
+ booSessionBegun = false;
+ sessionManager.CloseConnection();
+
+
+ }
+ catch (Exception ex)
+ {
+ await IntegrationLog( "PopulateQBClasses: Failed with exception:" + ex.Message);
+ if (booSessionBegun)
+ {
+ sessionManager.EndSession();
+ sessionManager.CloseConnection();
+ }
+ throw;
+ }
+
+ }
+
+
+
+ #endregion quickbooks transaction classes
+
+ #region QuickBooks Invoice Templates
+
+
+ private static DataTable _dtQBInvoiceTemplates = null;
+
+ ///
+ /// QB Transaction Templates
+ ///
+ public static DataTable QBInvoiceTemplates
+ {
+ get
+ {
+ return _dtQBInvoiceTemplates;
+ }
+ }
+
+
+
+
+ ///
+ /// Populate the cached qb data
+ /// Invoice templates
+ ///
+ private static void PopulateQBInvoiceTemplates()
+ {
+ if (_dtQBInvoiceTemplates == null)
+ {
+ _dtQBInvoiceTemplates = new DataTable("QBInvoiceTemplates");
+ //setup the columns
+ _dtQBInvoiceTemplates.Columns.Add("ID", typeof(string));
+ _dtQBInvoiceTemplates.Columns.Add("FullName", typeof(string));
+ _dtQBInvoiceTemplates.PrimaryKey = new DataColumn[] { _dtQBInvoiceTemplates.Columns[0] };
+
+ //Case 237
+ _dtQBInvoiceTemplates.DefaultView.Sort = "FullName asc";
+ }
+ else
+ _dtQBInvoiceTemplates.Clear();
+
+ _dtQBInvoiceTemplates.Rows.Add(new object[] { "", "< Use default >" });
+
+ //Connect to QB and fill
+ // IY: Create the session manager object using QBFC
+ QBSessionManager sessionManager = new QBSessionManager();
+
+ // IY: We want to know if we begun a session so we can end it if an
+ // error happens
+ bool booSessionBegun = false;
+
+ try
+ {
+ // IY: Get the RequestMsgSet based on the correct QB Version
+ IMsgSetRequest requestSet = getLatestMsgSetRequest(sessionManager);
+
+ // IY: Initialize the message set request object
+ requestSet.Attributes.OnError = ENRqOnError.roeStop;
+
+ // IY: Add the request to the message set request object
+ ITemplateQuery cq = requestSet.AppendTemplateQueryRq();
+
+
+ //This is intended to be called in a secondary thread immediately after already sucessfully connected
+ //to get version info so no special safety checks here
+ sessionManager.OpenConnection2("", "AyaNova QBI", ENConnectionType.ctLocalQBDLaunchUI);
+ sessionManager.BeginSession("", ENOpenMode.omDontCare);
+ booSessionBegun = true;
+
+ // IY: Do the request and get the response message set object
+ IMsgSetResponse responseSet = sessionManager.DoRequests(requestSet);
+
+ // Uncomment the following to view and save the request and response XML
+ //sLastRequestXML = requestSet.ToXMLString();
+ //MessageBox.Show(requestXML);
+ // SaveXML(requestXML);
+ //string responseXML = responseSet.ToXMLString();
+ //MessageBox.Show(responseXML);
+ // SaveXML(responseXML);
+
+ IResponse response = responseSet.ResponseList.GetAt(0);
+ //nonzero indicates an error, likely no templates defined
+ if (response.StatusCode == 0)
+ {
+
+ //int statusCode = response.StatusCode;
+ //string statusMessage = response.StatusMessage;
+ //string statusSeverity = response.StatusSeverity;
+ //MessageBox.Show("Status:\nCode = " + statusCode + "\nMessage = " + statusMessage + "\nSeverity = " + statusSeverity);
+ ITemplateRetList cl = response.Detail as ITemplateRetList;
+
+ if (!(cl.Count == 0))
+ {
+ for (int ndx = 0; ndx <= (cl.Count - 1); ndx++)
+ {
+ try
+ {
+
+ ITemplateRet clitem = cl.GetAt(ndx);
+ bool b = clitem.IsActive.GetValue();
+ b = clitem.TemplateType == null;
+ if (clitem != null &&
+ clitem.Name != null &&
+ clitem.ListID != null &&
+ clitem.TemplateType.IsSet() &&
+ clitem.TemplateType.GetValue() == ENTemplateType.tttInvoice)
+ {
+ //add a record to the datatable
+ _dtQBInvoiceTemplates.Rows.Add(new object[] { clitem.ListID.GetValue(), clitem.Name.GetValue() });
+ }
+ }
+ catch (System.Runtime.InteropServices.COMException ex)//QBFC7 - throwing this exception here on last item in list can't pin it down
+ {
+ string s = ex.ToString();
+ }
+
+ } // for loop
+ } // if
+ }//if status ==0 nonzero means some error, probably no classes defined
+
+ // IY: Close the session and connection with QuickBooks
+ sessionManager.EndSession();
+ booSessionBegun = false;
+ sessionManager.CloseConnection();
+
+
+ }
+ catch (Exception ex)
+ {
+
+ await IntegrationLog( "PopulateQBInvoiceTemplates: Failed with exception:" + ex.Message);
+ if (booSessionBegun)
+ {
+ sessionManager.EndSession();
+ sessionManager.CloseConnection();
+ }
+ throw;
+ }
+
+ }
+
+
+
+ #endregion quickbooks Templates
+
+ #region QuickBooks "Customers"
+
+ private static string GetQBCustomerEditSequence(string customerid)
+ {
+
+ string strEditSequence = "";
+
+ //Connect to QB and fill
+ // IY: Create the session manager object using QBFC
+ QBSessionManager sessionManager = new QBSessionManager();
+
+ // IY: We want to know if we begun a session so we can end it if an
+ // error happens
+ bool booSessionBegun = false;
+
+ try
+ {
+ // IY: Get the RequestMsgSet based on the correct QB Version
+ IMsgSetRequest requestSet = getLatestMsgSetRequest(sessionManager);
+
+ // IY: Initialize the message set request object
+ requestSet.Attributes.OnError = ENRqOnError.roeStop;
+
+ // IY: Add the request to the message set request object
+ ICustomerQuery cq = requestSet.AppendCustomerQueryRq();
+ cq.IncludeRetElementList.Add("EditSequence");
+ cq.ORCustomerListQuery.ListIDList.Add(customerid);
+
+
+ sessionManager.OpenConnection2("", "AyaNova QBI", ENConnectionType.ctLocalQBDLaunchUI);
+ sessionManager.BeginSession("", ENOpenMode.omDontCare);
+ booSessionBegun = true;
+
+ // IY: Do the request and get the response message set object
+ IMsgSetResponse responseSet = sessionManager.DoRequests(requestSet);
+
+ // Uncomment the following to view and save the request and response XML
+ //string requestXML = requestSet.ToXMLString();
+ //MessageBox.Show(requestXML);
+ // SaveXML(requestXML);
+ //string responseXML = responseSet.ToXMLString();
+ //MessageBox.Show(responseXML);
+ // SaveXML(responseXML);
+
+ IResponse response = responseSet.ResponseList.GetAt(0);
+ //nonzero indicates an error this is unrecoverable
+ //so throw an exception
+
+ //Changed: 21-June-2006 nonzero status codes 500 and higher are serious errors, less than 500 could just mean no matching items in list
+ if (response.StatusCode > 499)
+ {
+ throw new ApplicationException(response.StatusMessage + " Code: " + response.StatusCode);
+
+ }
+
+ //Added: 21-June-2006 outer if to avoid crash on no match response (code 1)
+ if (response.StatusCode == 0)
+ {
+ ICustomerRetList cl = response.Detail as ICustomerRetList;
+ if (!(cl.Count == 0))
+ {
+ ICustomerRet clitem = cl.GetAt(0);
+ if (clitem != null)
+ strEditSequence = clitem.EditSequence.GetValue();
+ }
+
+ }
+ // IY: Close the session and connection with QuickBooks
+ sessionManager.EndSession();
+ booSessionBegun = false;
+ sessionManager.CloseConnection();
+
+
+ }
+ catch (Exception ex)
+ {
+ await IntegrationLog( "GetClientEditSequence: Failed with exception:" + ex.Message);
+ if (booSessionBegun)
+ {
+ sessionManager.EndSession();
+ sessionManager.CloseConnection();
+ }
+ throw;
+
+ }
+
+ return strEditSequence;
+ }
+
+ private static DataTable _dtQBClients = null;
+
+ ///
+ /// QB Transaction Clients
+ ///
+ public static DataTable QBClients
+ {
+ get
+ {
+ return _dtQBClients;
+ }
+ }
+
+ #region Address structure
+ ///
+ /// Address properties
+ ///
+ public struct Address
+ {
+
+ public string DeliveryAddress;
+ public string City;
+ public string StateProv;
+ public string Country;
+ public string Postal;
+ }
+
+ #endregion
+ ///
+ /// Populate the cached qb data
+ /// of customers / clients
+ ///
+ private static void PopulateQBClientCache()
+ {
+ if (_dtQBClients == null)
+ {
+ _dtQBClients = new DataTable("QBClients");
+
+ //setup the columns
+ _dtQBClients.Columns.Add("ID", typeof(string));
+ _dtQBClients.Columns.Add("FullName", typeof(string));
+ _dtQBClients.Columns.Add("MailAddress", typeof(Address));
+ _dtQBClients.Columns.Add("StreetAddress", typeof(Address));
+ _dtQBClients.Columns.Add("Phone", typeof(string));
+ _dtQBClients.Columns.Add("Fax", typeof(string));
+ _dtQBClients.Columns.Add("AltPhone", typeof(string));
+ _dtQBClients.Columns.Add("Email", typeof(string));
+ _dtQBClients.Columns.Add("Contact", typeof(string));
+ _dtQBClients.Columns.Add("Created", typeof(DateTime));
+ _dtQBClients.Columns.Add("Modified", typeof(DateTime));
+ _dtQBClients.Columns.Add("Account", typeof(string));
+
+ _dtQBClients.PrimaryKey = new DataColumn[] { _dtQBClients.Columns[0] };
+
+ //Case 237
+ _dtQBClients.DefaultView.Sort = "FullName asc";
+ }
+ else
+ _dtQBClients.Clear();
+
+
+
+ //Connect to QB and fill
+ // IY: Create the session manager object using QBFC
+ QBSessionManager sessionManager = new QBSessionManager();
+
+ // IY: We want to know if we begun a session so we can end it if an
+ // error happens
+ bool booSessionBegun = false;
+
+ try
+ {
+ // IY: Get the RequestMsgSet based on the correct QB Version
+ IMsgSetRequest requestSet = getLatestMsgSetRequest(sessionManager);
+
+ // IY: Initialize the message set request object
+ requestSet.Attributes.OnError = ENRqOnError.roeStop;
+
+ // IY: Add the request to the message set request object
+ ICustomerQuery cq = requestSet.AppendCustomerQueryRq();
+
+ //Active Customers only
+ cq.ORCustomerListQuery.CustomerListFilter.ActiveStatus.SetValue(ENActiveStatus.asActiveOnly);
+
+ //case 1664
+ //not sure why these were ever in here to be honest
+
+ //whups, it's *necessary* see case 1100
+ //there is a bug in qbfc7 which blows if there are "special" characters
+ //it was fixed later but we use qbfc7 currently
+
+ cq.ORCustomerListQuery.CustomerListFilter.ORNameFilter.NameRangeFilter.FromName.SetValue("0");
+ cq.ORCustomerListQuery.CustomerListFilter.ORNameFilter.NameRangeFilter.ToName.SetValue("ZZ");
+
+
+ sessionManager.OpenConnection2("", "AyaNova QBI", ENConnectionType.ctLocalQBDLaunchUI);
+ sessionManager.BeginSession("", ENOpenMode.omDontCare);
+ booSessionBegun = true;
+
+ // IY: Do the request and get the response message set object
+ IMsgSetResponse responseSet = sessionManager.DoRequests(requestSet);
+
+ // Uncomment the following to view and save the request and response XML
+ // string requestXML = requestSet.ToXMLString();
+ // MessageBox.Show(requestXML);
+ // SaveXML(requestXML);
+ //string responseXML = responseSet.ToXMLString();
+ // MessageBox.Show(responseXML);
+ // SaveXML(responseXML);
+
+ IResponse response = responseSet.ResponseList.GetAt(0);
+ //nonzero indicates an error this is unrecoverable
+ //so throw an exception
+
+ //Changed: 21-June-2006 nonzero status codes 500 and higher are serious errors, less than 500 could just mean no matching items in list
+ if (response.StatusCode > 499)
+ {
+ throw new ApplicationException(response.StatusMessage + " Code: " + response.StatusCode);
+
+ }
+
+ //Added: 21-June-2006 outer if to avoid crash on no match response (code 1)
+ if (response.StatusCode == 0)
+ {
+ //int statusCode = response.StatusCode;
+ //string statusMessage = response.StatusMessage;
+ //string statusSeverity = response.StatusSeverity;
+ //MessageBox.Show("Status:\nCode = " + statusCode + "\nMessage = " + statusMessage + "\nSeverity = " + statusSeverity);
+ ICustomerRetList cl = response.Detail as ICustomerRetList;
+
+ if (!(cl.Count == 0))
+ {
+ for (int ndx = 0; ndx <= (cl.Count - 1); ndx++)
+ {
+ ICustomerRet clitem = cl.GetAt(ndx);
+ if (clitem != null)
+ {
+ //add a record to the datatable
+
+
+ DataRow dr = _dtQBClients.Rows.Add(
+ new object[]{
+ clitem.ListID.GetValue(),
+ clitem.FullName.GetValue(),
+ ProcessAddress(clitem.BillAddress),
+ ProcessAddress(clitem.ShipAddress),
+ ProcessQBString(clitem.Phone),
+ ProcessQBString(clitem.Fax),
+ ProcessQBString(clitem.AltPhone),
+ ProcessQBString(clitem.Email),
+ ProcessQBString(clitem.Contact),
+ clitem.TimeCreated.GetValue(),
+ clitem.TimeModified.GetValue(),
+ ProcessQBString(clitem.AccountNumber),
+
+ });
+ }
+ } // for loop
+ } // if
+
+ }
+ // IY: Close the session and connection with QuickBooks
+ sessionManager.EndSession();
+ booSessionBegun = false;
+ sessionManager.CloseConnection();
+
+
+ }
+ catch (Exception ex)
+ {
+ await IntegrationLog( "PopulateQBClients: Failed with exception:" + ex.Message);
+ if (booSessionBegun)
+ {
+ sessionManager.EndSession();
+ sessionManager.CloseConnection();
+ }
+ throw;
+
+ }
+
+ }
+
+ ///
+ /// Take a qb address and return an AyaNova friendly
+ /// address structure
+ ///
+ ///
+ ///
+ private static Address ProcessAddress(IAddress a)
+ {
+ Address b = new Address();
+ b.City = "";
+ b.Country = "";
+ b.DeliveryAddress = "";
+ b.Postal = "";
+ b.StateProv = "";
+ if (a == null) return b;
+ //Append each line of the address, add cr/lf for each line if present after
+ //the first line
+ //Assumption: First line always has *something* in it
+ b.DeliveryAddress = ProcessQBString(a.Addr1);
+ b.DeliveryAddress += AyaBizUtils.SS("\r\n", ProcessQBString(a.Addr2), "");
+ b.DeliveryAddress += AyaBizUtils.SS("\r\n", ProcessQBString(a.Addr3), "");
+
+ //Address line 4 is a qbxml 2 or higher feature
+ if (QVersion > 1.1)
+ b.DeliveryAddress += AyaBizUtils.SS("\r\n", ProcessQBString(a.Addr4), "");
+
+ //Country specific:
+ b.City = ProcessQBString(a.City);
+
+ //QBFC7 unifies county and province to "state"
+ b.StateProv = ProcessQBString(a.State);
+
+ //switch(QCountry)
+ //{
+ // case "CA":
+ // b.StateProv=ProcessQBString(a.Province);
+ // break;
+ // case "UK":
+ // b.StateProv=ProcessQBString(a.County);
+ // break;
+ // default:
+ // b.StateProv=ProcessQBString(a.State);
+ // break;
+
+ //}
+
+ b.Country = ProcessQBString(a.Country);
+
+ b.Postal = ProcessQBString(a.PostalCode);
+
+
+
+ return b;
+ }
+
+ ///
+ /// Handle null qb string types with "aplomb" :)
+ ///
+ ///
+ ///
+ private static string ProcessQBString(IQBStringType qs)
+ {
+ if (qs == null) return "";
+ return qs.GetValue();
+ }
+
+ #endregion quickbooks transaction Clients
+
+ #region QuickBooks "Vendors"
+
+
+ private static DataTable _dtQBVendors = null;
+
+ ///
+ /// QB Vendors
+ ///
+ public static DataTable QBVendors
+ {
+ get
+ {
+ return _dtQBVendors;
+ }
+ }
+
+
+ ///
+ /// Populate the cached qb data
+ /// of Vendors
+ ///
+ private static void PopulateQBVendorCache()
+ {
+ if (_dtQBVendors == null)
+ {
+ _dtQBVendors = new DataTable("QBVendors");
+
+ //setup the columns
+ _dtQBVendors.Columns.Add("ID", typeof(string));
+ _dtQBVendors.Columns.Add("FullName", typeof(string));
+ _dtQBVendors.Columns.Add("MailAddress", typeof(Address));
+ _dtQBVendors.Columns.Add("StreetAddress", typeof(Address));
+ _dtQBVendors.Columns.Add("Phone", typeof(string));
+ _dtQBVendors.Columns.Add("Fax", typeof(string));
+ _dtQBVendors.Columns.Add("AltPhone", typeof(string));
+ _dtQBVendors.Columns.Add("Email", typeof(string));
+ _dtQBVendors.Columns.Add("Contact", typeof(string));
+ _dtQBVendors.Columns.Add("Created", typeof(DateTime));
+ _dtQBVendors.Columns.Add("Modified", typeof(DateTime));
+ _dtQBVendors.Columns.Add("Account", typeof(string));
+
+ _dtQBVendors.PrimaryKey = new DataColumn[] { _dtQBVendors.Columns[0] };
+
+ //Case 237
+ _dtQBVendors.DefaultView.Sort = "FullName asc";
+ }
+ else
+ _dtQBVendors.Clear();
+
+
+
+ //Connect to QB and fill
+ // IY: Create the session manager object using QBFC
+ QBSessionManager sessionManager = new QBSessionManager();
+
+ // IY: We want to know if we begun a session so we can end it if an
+ // error happens
+ bool booSessionBegun = false;
+
+ try
+ {
+ // IY: Get the RequestMsgSet based on the correct QB Version
+ IMsgSetRequest requestSet = getLatestMsgSetRequest(sessionManager);
+
+ // IY: Initialize the message set request object
+ requestSet.Attributes.OnError = ENRqOnError.roeStop;
+
+ // IY: Add the request to the message set request object
+ IVendorQuery cq = requestSet.AppendVendorQueryRq();
+
+ //Active Vendors only
+ cq.ORVendorListQuery.VendorListFilter.ActiveStatus.SetValue(ENActiveStatus.asActiveOnly);
+
+ sessionManager.OpenConnection2("", "AyaNova QBI", ENConnectionType.ctLocalQBDLaunchUI);
+ sessionManager.BeginSession("", ENOpenMode.omDontCare);
+ booSessionBegun = true;
+
+ // IY: Do the request and get the response message set object
+ IMsgSetResponse responseSet = sessionManager.DoRequests(requestSet);
+
+ // Uncomment the following to view and save the request and response XML
+ //string requestXML = requestSet.ToXMLString();
+ //MessageBox.Show(requestXML);
+ // SaveXML(requestXML);
+ //string responseXML = responseSet.ToXMLString();
+ //MessageBox.Show(responseXML);
+ // SaveXML(responseXML);
+
+ IResponse response = responseSet.ResponseList.GetAt(0);
+ //nonzero indicates an error; this is unrecoverable
+ //so throw an exception
+
+ //Changed: 21-June-2006 nonzero status codes 500 and higher are serious errors, less than 500 could just mean no matching items in list
+ if (response.StatusCode > 499)
+ {
+ throw new ApplicationException(response.StatusMessage + " Code: " + response.StatusCode);
+
+ }
+ //Added: 21-June-2006 outer if to avoid crash on no match response (code 1)
+ if (response.StatusCode == 0)
+ {
+ //int statusCode = response.StatusCode;
+ //string statusMessage = response.StatusMessage;
+ //string statusSeverity = response.StatusSeverity;
+ //MessageBox.Show("Status:\nCode = " + statusCode + "\nMessage = " + statusMessage + "\nSeverity = " + statusSeverity);
+ IVendorRetList cl = response.Detail as IVendorRetList;
+
+ if (!(cl.Count == 0))
+ {
+ for (int ndx = 0; ndx <= (cl.Count - 1); ndx++)
+ {
+ IVendorRet clitem = cl.GetAt(ndx);
+ if (clitem != null)
+ {
+ //add a record to the datatable
+
+
+ DataRow dr = _dtQBVendors.Rows.Add(
+ new object[]
+{
+ clitem.ListID.GetValue(),
+ clitem.Name.GetValue(),
+ ProcessAddress(clitem.VendorAddress),
+ ProcessAddress(clitem.VendorAddress),
+ ProcessQBString(clitem.Phone),
+ ProcessQBString(clitem.Fax),
+ ProcessQBString(clitem.AltPhone),
+ ProcessQBString(clitem.Email),
+ ProcessQBString(clitem.Contact),
+ clitem.TimeCreated.GetValue(),
+ clitem.TimeModified.GetValue(),
+ ProcessQBString(clitem.AccountNumber)
+});
+ }
+ } // for loop
+ } // if
+
+ }
+
+
+ // IY: Close the session and connection with QuickBooks
+ sessionManager.EndSession();
+ booSessionBegun = false;
+ sessionManager.CloseConnection();
+
+
+ }
+ catch (Exception ex)
+ {
+ await IntegrationLog( "PopulateQBVendors: Failed with exception:" + ex.Message);
+ if (booSessionBegun)
+ {
+ sessionManager.EndSession();
+ sessionManager.CloseConnection();
+ }
+ throw;
+ }
+
+ }
+
+
+
+ #endregion quickbooks Vendors
+
+
+
+ #region QuickBooks "accounts"
+
+
+ private static DataTable _dtQBAccounts = null;
+
+ ///
+ /// QB Transaction Classes
+ ///
+ public static DataTable QBAccounts
+ {
+ get
+ {
+ return _dtQBAccounts;
+ }
+ }
+
+
+
+
+ ///
+ /// Populate the cached qb account list data
+ ///
+ private static void PopulateQBAccountCache()
+ {
+ if (_dtQBAccounts == null)
+ {
+ _dtQBAccounts = new DataTable("QBAccounts");
+ //setup the columns
+ _dtQBAccounts.Columns.Add("ID", typeof(string));
+ _dtQBAccounts.Columns.Add("FullName", typeof(string));
+ _dtQBAccounts.Columns.Add("Type", typeof(string));
+
+ _dtQBAccounts.PrimaryKey = new DataColumn[] { _dtQBAccounts.Columns[0] };
+ //Case 237
+ _dtQBAccounts.DefaultView.Sort = "FullName asc";
+ }
+ else
+ _dtQBAccounts.Clear();
+
+
+
+ //Connect to QB and fill
+ // IY: Create the session manager object using QBFC
+ QBSessionManager sessionManager = new QBSessionManager();
+
+ // IY: We want to know if we begun a session so we can end it if an
+ // error happens
+ bool booSessionBegun = false;
+
+ try
+ {
+ // IY: Get the RequestMsgSet based on the correct QB Version
+ IMsgSetRequest requestSet = getLatestMsgSetRequest(sessionManager);
+
+ // IY: Initialize the message set request object
+ requestSet.Attributes.OnError = ENRqOnError.roeStop;
+
+ // IY: Add the request to the message set request object
+ IAccountQuery cq = requestSet.AppendAccountQueryRq();
+
+ //accounts (active ones only)
+ cq.ORAccountListQuery.AccountListFilter.ActiveStatus.SetValue(ENActiveStatus.asActiveOnly);
+
+
+
+ //This is intended to be called in a secondary thread immediately after already sucessfully connected
+ //to get version info so no special safety checks here
+ sessionManager.OpenConnection2("", "AyaNova QBI", ENConnectionType.ctLocalQBDLaunchUI);
+ sessionManager.BeginSession("", ENOpenMode.omDontCare);
+ booSessionBegun = true;
+
+ // IY: Do the request and get the response message set object
+ IMsgSetResponse responseSet = sessionManager.DoRequests(requestSet);
+
+ // Uncomment the following to view and save the request and response XML
+ //string requestXML = requestSet.ToXMLString();
+ //MessageBox.Show(requestXML);
+ // SaveXML(requestXML);
+ //string responseXML = responseSet.ToXMLString();
+ //MessageBox.Show(responseXML);
+ // SaveXML(responseXML);
+
+ IResponse response = responseSet.ResponseList.GetAt(0);
+ //nonzero indicates an error, likely no classes defined
+ if (response.StatusCode == 0)
+ {
+
+ //int statusCode = response.StatusCode;
+ //string statusMessage = response.StatusMessage;
+ //string statusSeverity = response.StatusSeverity;
+ //MessageBox.Show("Status:\nCode = " + statusCode + "\nMessage = " + statusMessage + "\nSeverity = " + statusSeverity);
+ IAccountRetList cl = response.Detail as IAccountRetList;
+
+ if (!(cl.Count == 0))
+ {
+ for (int ndx = 0; ndx <= (cl.Count - 1); ndx++)
+ {
+ IAccountRet clitem = cl.GetAt(ndx);
+ if (clitem != null && clitem.FullName != null && clitem.ListID != null)
+ {
+ //add a record to the datatable
+ _dtQBAccounts.Rows.Add(new object[] { clitem.ListID.GetValue(), clitem.AccountType.GetAsString() + " - " + clitem.FullName.GetValue(), clitem.AccountType.GetAsString() });
+ }
+ } // for loop
+ } // if
+ }//if status ==0 nonzero means some error, probably no classes defined
+
+ // IY: Close the session and connection with QuickBooks
+ sessionManager.EndSession();
+ booSessionBegun = false;
+ sessionManager.CloseConnection();
+
+
+ }
+ catch (Exception ex)
+ {
+ await IntegrationLog( "PopulateQBAccounts: Failed with exception:" + ex.Message);
+ if (booSessionBegun)
+ {
+ sessionManager.EndSession();
+ sessionManager.CloseConnection();
+ }
+ throw;
+ }
+
+ }
+
+
+
+ #endregion quickbooks accounts
+
+ #region QuickBooks "Terms"
+
+
+ private static DataTable _dtQBTerms = null;
+
+ ///
+ /// QB Transaction Classes
+ ///
+ public static DataTable QBTerms
+ {
+ get
+ {
+ return _dtQBTerms;
+ }
+ }
+
+
+
+
+ ///
+ /// Populate the cached qb terms list data
+ ///
+ private async static void PopulateQBTermsCache()
+ {
+ if (_dtQBTerms == null)
+ {
+ _dtQBTerms = new DataTable("QBTerms");
+ //setup the columns
+ _dtQBTerms.Columns.Add("ID", typeof(string));
+ _dtQBTerms.Columns.Add("FullName", typeof(string));
+
+ _dtQBTerms.PrimaryKey = new DataColumn[] { _dtQBTerms.Columns[0] };
+ //Case 237
+ _dtQBTerms.DefaultView.Sort = "FullName asc";
+ }
+ else
+ _dtQBTerms.Clear();
+
+
+
+ //Connect to QB and fill
+ // IY: Create the session manager object using QBFC
+ QBSessionManager sessionManager = new QBSessionManager();
+
+ // IY: We want to know if we begun a session so we can end it if an
+ // error happens
+ bool booSessionBegun = false;
+
+ try
+ {
+ // IY: Get the RequestMsgSet based on the correct QB Version
+ IMsgSetRequest requestSet = getLatestMsgSetRequest(sessionManager);
+
+ // IY: Initialize the message set request object
+ requestSet.Attributes.OnError = ENRqOnError.roeStop;
+
+ // IY: Add the request to the message set request object
+ ITermsQuery cq = requestSet.AppendTermsQueryRq();
+
+
+ //This is intended to be called in a secondary thread immediately after already sucessfully connected
+ //to get version info so no special safety checks here
+ sessionManager.OpenConnection2("", "AyaNova QBI", ENConnectionType.ctLocalQBDLaunchUI);
+ sessionManager.BeginSession("", ENOpenMode.omDontCare);
+ booSessionBegun = true;
+
+ // IY: Do the request and get the response message set object
+ IMsgSetResponse responseSet = sessionManager.DoRequests(requestSet);
+
+ // Uncomment the following to view and save the request and response XML
+ //string requestXML = requestSet.ToXMLString();
+ //MessageBox.Show(requestXML);
+ // SaveXML(requestXML);
+ //string responseXML = responseSet.ToXMLString();
+ //MessageBox.Show(responseXML);
+ // SaveXML(responseXML);
+
+ IResponse response = responseSet.ResponseList.GetAt(0);
+ //nonzero indicates an error, likely no classes defined
+ if (response.StatusCode == 0)
+ {
+
+ //int statusCode = response.StatusCode;
+ //string statusMessage = response.StatusMessage;
+ //string statusSeverity = response.StatusSeverity;
+ //MessageBox.Show("Status:\nCode = " + statusCode + "\nMessage = " + statusMessage + "\nSeverity = " + statusSeverity);
+ IORTermsRetList cl = response.Detail as IORTermsRetList;
+
+ if (!(cl.Count == 0))
+ {
+ for (int ndx = 0; ndx <= (cl.Count - 1); ndx++)
+ {
+ IORTermsRet clitem = cl.GetAt(ndx);
+ if (clitem != null)
+ {
+ //add a record to the datatable
+ if (clitem.StandardTermsRet != null && clitem.StandardTermsRet.ListID.IsSet())
+ _dtQBTerms.Rows.Add(new object[] { clitem.StandardTermsRet.ListID.GetValue(), clitem.StandardTermsRet.Name.GetValue() });
+ else
+ _dtQBTerms.Rows.Add(new object[] { clitem.DateDrivenTermsRet.ListID.GetValue(), clitem.DateDrivenTermsRet.Name.GetValue() });
+
+ }
+ } // for loop
+ } // if
+ }//if status ==0 nonzero means some error, probably no classes defined
+
+ // IY: Close the session and connection with QuickBooks
+ sessionManager.EndSession();
+ booSessionBegun = false;
+ sessionManager.CloseConnection();
+
+
+ }
+ catch (Exception ex)
+ {
+ await IntegrationLog( "PopulateQBTerms: Failed with exception:" + ex.Message);
+ if (booSessionBegun)
+ {
+ sessionManager.EndSession();
+ sessionManager.CloseConnection();
+ }
+ throw;
+ }
+
+ }
+
+
+
+ #endregion quickbooks Terms
+
+ #endregion