Beispiel #1
0
        public static string DoRequest(XmlDocument doc)
        {
            RequestProcessor2 rp = null;
            string ticket = null;
            string response = null;
            bool errorOccurred = false;
            int maxTries = 1;
            int tries = 0;

            do
            {
                try
                {
                    tries++;
                    rp = new RequestProcessor2();
                    rp.OpenConnection("QBMT1", "QBMigrationTool");
                    ticket = rp.BeginSession("", QBFileMode.qbFileOpenDoNotCare);
                    CheckIfBuildTypeAndQuickBooksFileMatch(rp.GetCurrentCompanyFileName(ticket));
                    response = rp.ProcessRequest(ticket, doc.OuterXml);

                    if (errorOccurred)
                    {
                        Logging.RototrackErrorLog("QBMigrationTool: " + RototrackConfig.GetBuildType() + ": " + "DoRequest Retry succeeded.");
                        errorOccurred = false;
                    }
                }
                catch (System.Runtime.InteropServices.COMException e)
                {
                    Logging.RototrackErrorLog("QBMigrationTool: " + RototrackConfig.GetBuildType() + ": " + "Error in DoRequest.  Retrying.  Details: " + e.ToString());
                    //MessageBox.Show("Outer: " + doc.OuterXml);
                    errorOccurred = true;
                }
                catch (Exception e)
                {
                    Logging.RototrackErrorLog("QBMigrationTool: " + RototrackConfig.GetBuildType() + ": " + "Error in DoRequest.  Retrying.  Details: " + e.ToString());
                    break;
                }
                finally
                {
                    if (ticket != null)
                    {
                        rp.EndSession(ticket);
                    }
                    if (rp != null)
                    {
                        rp.CloseConnection();
                    }
                }

            } while (errorOccurred && tries <= maxTries);

            return response;
        }
Beispiel #2
0
        public void Reverse()
        {
            // Disable the buttons.
            IsExitEnabled      = false;
            IsTryEnabled       = false;
            IsStartOverEnabled = false;
            OnPropertyChanged("IsExitEnabled");
            OnPropertyChanged("IsTryEnabled");
            OnPropertyChanged("IsStartOverEnabled");

            // Reset error count.
            SaveErrorCount = 0;

            StatusText = string.Format("{0} - Starting.\r\n", DateTime.Now.ToString());
            OnPropertyChanged("StatusText");

            var service = new QuickBooksService();

            StatusText += string.Format("{0} - Connecting to QuickBooks.\r\n", DateTime.Now.ToString());
            OnPropertyChanged("StatusText");

            // QBXML request processor must always be closed after use.
            var req = new RequestProcessor2();

            try
            {
                req.OpenConnection2("", "BRIZBEE Integration Utility", QBXMLRPConnectionType.localQBD);
                var ticket          = req.BeginSession("", QBFileMode.qbFileOpenDoNotCare);
                var companyFileName = req.GetCurrentCompanyFileName(ticket);

                StatusText += string.Format("{0} - Reversing.\r\n", DateTime.Now.ToString());
                OnPropertyChanged("StatusText");


                // ------------------------------------------------------------
                // Collect the QuickBooks host details.
                // ------------------------------------------------------------

                // Prepare a new QBXML document.
                var hostQBXML    = service.MakeQBXMLDocument();
                var hostDocument = hostQBXML.Item1;
                var hostElement  = hostQBXML.Item2;
                service.BuildHostQueryRq(hostDocument, hostElement);

                // Make the request.
                var hostResponse = req.ProcessRequest(ticket, hostDocument.OuterXml);

                // Then walk the response.
                var hostWalkResponse = service.WalkHostQueryRsAndParseHostDetails(hostResponse);
                var hostDetails      = hostWalkResponse.Item3;


                // ------------------------------------------------------------
                // Prepare the reverse request.
                // ------------------------------------------------------------

                string   reverseTransactionType = Application.Current.Properties["ReverseTransactionType"] as string;
                string   transactionType        = "";
                string[] selectedTxnIds         = new string[] { };
                string   syncId = "";

                if (reverseTransactionType == "Punches")
                {
                    var selectedSync = Application.Current.Properties["SelectedSync"] as QuickBooksDesktopExport;

                    selectedTxnIds  = selectedSync.TxnIDs.Split(',');
                    transactionType = "TimeTracking";
                    syncId          = selectedSync.Id.ToString();
                }
                else if (reverseTransactionType == "Consumption")
                {
                    var selectedSync = Application.Current.Properties["SelectedSync"] as QBDInventoryConsumptionSync;

                    if (Path.GetFileName(companyFileName) != selectedSync.HostCompanyFileName)
                    {
                        throw new Exception("The open company file in QuickBooks is not the same as the one that was synced.");
                    }

                    selectedTxnIds  = selectedSync.TxnIDs.Split(',');
                    transactionType = selectedSync.RecordingMethod; // InventoryAdjustment, SalesReceipt, or Bill
                    syncId          = selectedSync.Id.ToString();
                }


                // ------------------------------------------------------------
                // Reverse the transaction.
                // ------------------------------------------------------------

                foreach (var txnId in selectedTxnIds)
                {
                    // Prepare a new QBXML document.
                    var delQBXML    = service.MakeQBXMLDocument();
                    var delDocument = delQBXML.Item1;
                    var delElement  = delQBXML.Item2;
                    service.BuildTxnDelRq(delDocument, delElement, transactionType, txnId); // InventoryAdjustment, SalesReceipt, TimeTracking, or Bill

                    // Make the request.
                    Logger.Debug(delDocument.OuterXml);
                    var delResponse = req.ProcessRequest(ticket, delDocument.OuterXml);
                    Logger.Debug(delResponse);

                    // Then walk the response.
                    var delWalkResponse = service.WalkTxnDelRs(delResponse);
                }

                // ------------------------------------------------------------
                // Send the request to the server.
                // ------------------------------------------------------------

                // Build the request.
                if (reverseTransactionType == "Consumption")
                {
                    var syncHttpRequest = new RestRequest("api/QBDInventoryConsumptionSyncs/Reverse", Method.POST);
                    syncHttpRequest.AddQueryParameter("id", syncId);

                    // Execute request.
                    var syncHttpResponse = client.Execute(syncHttpRequest);
                    if ((syncHttpResponse.ResponseStatus == ResponseStatus.Completed) &&
                        (syncHttpResponse.StatusCode == System.Net.HttpStatusCode.OK))
                    {
                        StatusText += string.Format("{0} - Reversed Successfully.\r\n", DateTime.Now.ToString());
                        OnPropertyChanged("StatusText");
                    }
                    else
                    {
                        StatusText += $"{DateTime.Now} - {syncHttpResponse.Content}";
                        StatusText += string.Format("{0} - Reverse failed.\r\n", DateTime.Now.ToString());
                        OnPropertyChanged("StatusText");
                    }
                }
                else
                {
                    StatusText += string.Format("{0} - Reversed Successfully.\r\n", DateTime.Now.ToString());
                    OnPropertyChanged("StatusText");
                }

                // Close the QuickBooks connection.
                req.EndSession(ticket);
                req.CloseConnection();
                req = null;
            }
            catch (COMException cex)
            {
                Logger.Error(cex.ToString());

                if ((uint)cex.ErrorCode == 0x80040408)
                {
                    StatusText += string.Format("{0} - Reverse failed. QuickBooks Desktop is not open.\r\n", DateTime.Now.ToString());
                    OnPropertyChanged("StatusText");
                }
                else
                {
                    StatusText += string.Format("{0} - Reverse failed. {1}\r\n", DateTime.Now.ToString(), cex.Message);
                    OnPropertyChanged("StatusText");
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex.ToString());

                StatusText += string.Format("{0} - Reverse failed. {1}\r\n", DateTime.Now.ToString(), ex.Message);
                OnPropertyChanged("StatusText");
            }
            finally
            {
                // Enable the buttons.
                IsExitEnabled      = true;
                IsTryEnabled       = true;
                IsStartOverEnabled = true;
                OnPropertyChanged("IsExitEnabled");
                OnPropertyChanged("IsTryEnabled");
                OnPropertyChanged("IsStartOverEnabled");

                // Try to close the QuickBooks connection if it is still open.
                if (req != null)
                {
                    req.CloseConnection();
                    req = null;
                }
            }
        }
Beispiel #3
0
 public static string DoRequestRaw(string rawXML)
 {
     RequestProcessor2 rp = null;
     string ticket = null;
     string response = null;
     try
     {
         rp = new RequestProcessor2();
         rp.OpenConnection("QBMT1", "QBMigrationTool");
         ticket = rp.BeginSession("", QBFileMode.qbFileOpenDoNotCare);
         CheckIfBuildTypeAndQuickBooksFileMatch(rp.GetCurrentCompanyFileName(ticket));
         response = rp.ProcessRequest(ticket, rawXML);
         return response;
     }
     catch (System.Runtime.InteropServices.COMException ex)
     {
         MessageBox.Show("COM Error Description = " + ex.Message, "COM error");
         return ex.Message;
     }
     catch (Exception e)
     {
         MessageBox.Show("QBMigrationTool: " + RototrackConfig.GetBuildType() + ": " + "Error in DoRequestRaw.  Details: " + e.ToString(), "Exception");
         return e.Message;
     }
     finally
     {
         if (ticket != null)
         {
             rp.EndSession(ticket);
         }
         if (rp != null)
         {
             rp.CloseConnection();
         }
     }
 }
Beispiel #4
0
        public void Sync()
        {
            // Disable the buttons.
            IsExitEnabled      = false;
            IsTryEnabled       = false;
            IsStartOverEnabled = false;
            OnPropertyChanged("IsExitEnabled");
            OnPropertyChanged("IsTryEnabled");
            OnPropertyChanged("IsStartOverEnabled");

            // Reset error count.
            ValidationErrorCount = 0;
            SaveErrorCount       = 0;

            StatusText = string.Format("{0} - Starting.\r\n", DateTime.Now.ToString());
            OnPropertyChanged("StatusText");

            // Open the offset mapping file first, but only if one has been specified.
            List <OffsetMapping> offsetMappings = new List <OffsetMapping>(0);

            if (!string.IsNullOrEmpty(offsetFileName))
            {
                try
                {
                    Logger.Debug($"Opening offset mapping file at {offsetFileName}");

                    using (var reader = new StreamReader(offsetFileName))
                        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
                        {
                            offsetMappings = csv.GetRecords <OffsetMapping>().ToList();
                        }

                    Logger.Debug($"There are {offsetMappings.Count} mappings");
                }
                catch (Exception ex)
                {
                    Logger.Error(ex.ToString());

                    StatusText += string.Format("{0} - Sync failed. {1}\r\n", DateTime.Now.ToString(), ex.Message);
                    OnPropertyChanged("StatusText");

                    return;
                }
            }

            var service = new QuickBooksService();

            StatusText += string.Format("{0} - Connecting to QuickBooks.\r\n", DateTime.Now.ToString());
            OnPropertyChanged("StatusText");

            // QBXML request processor must always be closed after use.
            var req = new RequestProcessor2();

            try
            {
                req.OpenConnection2("", "BRIZBEE Integration Utility", QBXMLRPConnectionType.localQBD);
                var ticket          = req.BeginSession("", QBFileMode.qbFileOpenDoNotCare);
                var companyFileName = req.GetCurrentCompanyFileName(ticket);

                StatusText += string.Format("{0} - Syncing.\r\n", DateTime.Now.ToString());
                OnPropertyChanged("StatusText");

                // ------------------------------------------------------------
                // Collect the QuickBooks host details.
                // ------------------------------------------------------------

                // Prepare a new QBXML document.
                var hostQBXML    = service.MakeQBXMLDocument();
                var hostDocument = hostQBXML.Item1;
                var hostElement  = hostQBXML.Item2;
                service.BuildHostQueryRq(hostDocument, hostElement);

                // Make the request.
                var hostResponse = req.ProcessRequest(ticket, hostDocument.OuterXml);

                // Then walk the response.
                var hostWalkResponse = service.WalkHostQueryRsAndParseHostDetails(hostResponse);
                var hostDetails      = hostWalkResponse.Item3;

                // ------------------------------------------------------------
                // Collect the inventory items.
                // ------------------------------------------------------------

                var items = new List <QBDInventoryItem>();

                StatusText += string.Format("{0} - Collecting inventory items.\r\n", DateTime.Now.ToString());
                items       = SyncInventoryItems(service, ticket, req);

                // Cannot continue to sync if there are no items.
                if (items.Count == 0)
                {
                    throw new Exception("There are no inventory items to sync.");
                }

                // Apply the offset items.
                foreach (var item in items)
                {
                    var found = offsetMappings
                                .Where(o => o.InventoryItemFullName == item.FullName)
                                .FirstOrDefault();

                    if (found != null)
                    {
                        item.OffsetItemFullName = found.OffsetItemFullName;
                    }
                }

                // ------------------------------------------------------------
                // Collect the inventory sites.
                // ------------------------------------------------------------

                var sites = new List <QBDInventorySite>();

                // Attempt to sync sites even if they are not enabled or available.
                StatusText += string.Format("{0} - Collecting inventory sites.\r\n", DateTime.Now.ToString());
                sites       = SyncInventorySites(service, ticket, req);

                // ------------------------------------------------------------
                // Collect the units of measure.
                // ------------------------------------------------------------

                var units = new List <QBDUnitOfMeasureSet>();

                // Attempt to sync sites even if they are not enabled or available.
                StatusText += string.Format("{0} - Collecting unit of measure sets.\r\n", DateTime.Now.ToString());
                units       = SyncUnitOfMeasureSets(service, ticket, req);

                // ------------------------------------------------------------
                // Send the items to the server.
                // ------------------------------------------------------------

                // Build the payload.
                var payload = new
                {
                    InventoryItems    = items ?? new List <QBDInventoryItem>(),
                    InventorySites    = sites ?? new List <QBDInventorySite>(),
                    UnitOfMeasureSets = units ?? new List <QBDUnitOfMeasureSet>()
                };

                // Build the request to send the sync details.
                var syncHttpRequest = new RestRequest("api/QBDInventoryItems/Sync", Method.POST);
                syncHttpRequest.AddJsonBody(payload);
                syncHttpRequest.AddQueryParameter("productName", hostDetails.QBProductName);
                syncHttpRequest.AddQueryParameter("majorVersion", hostDetails.QBMajorVersion);
                syncHttpRequest.AddQueryParameter("minorVersion", hostDetails.QBMinorVersion);
                syncHttpRequest.AddQueryParameter("country", hostDetails.QBCountry);
                syncHttpRequest.AddQueryParameter("supportedQBXMLVersion", hostDetails.QBSupportedQBXMLVersions);
                syncHttpRequest.AddQueryParameter("hostname", Environment.MachineName);
                syncHttpRequest.AddQueryParameter("companyFilePath", companyFileName);

                // Execute request.
                var syncHttpResponse = client.Execute(syncHttpRequest);
                if ((syncHttpResponse.ResponseStatus == ResponseStatus.Completed) &&
                    (syncHttpResponse.StatusCode == System.Net.HttpStatusCode.OK))
                {
                    StatusText += string.Format("{0} - Synced Successfully.\r\n", DateTime.Now.ToString());
                    OnPropertyChanged("StatusText");
                }
                else
                {
                    StatusText += $"{DateTime.Now} - {syncHttpResponse.Content}";
                    StatusText += string.Format("{0} - Sync failed.\r\n", DateTime.Now.ToString());
                    OnPropertyChanged("StatusText");
                }

                // Close the QuickBooks connection.
                req.EndSession(ticket);
                req.CloseConnection();
                req = null;
            }
            catch (COMException cex)
            {
                Logger.Error(cex.ToString());

                if ((uint)cex.ErrorCode == 0x80040408)
                {
                    StatusText += string.Format("{0} - Sync failed. QuickBooks Desktop is not open.\r\n", DateTime.Now.ToString());
                    OnPropertyChanged("StatusText");
                }
                else
                {
                    StatusText += string.Format("{0} - Sync failed. {1}\r\n", DateTime.Now.ToString(), cex.Message);
                    OnPropertyChanged("StatusText");
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex.ToString());

                StatusText += string.Format("{0} - Sync failed. {1}\r\n", DateTime.Now.ToString(), ex.Message);
                OnPropertyChanged("StatusText");
            }
            finally
            {
                // Enable the buttons.
                IsExitEnabled      = true;
                IsTryEnabled       = true;
                IsStartOverEnabled = true;
                OnPropertyChanged("IsExitEnabled");
                OnPropertyChanged("IsTryEnabled");
                OnPropertyChanged("IsStartOverEnabled");

                // Try to close the QuickBooks connection if it is still open.
                if (req != null)
                {
                    req.CloseConnection();
                    req = null;
                }
            }
        }
Beispiel #5
0
        private void btnImport_Click(object sender, EventArgs e)
        {
            try
            {
                _Rp = new RequestProcessor2();
                _Rp.OpenConnection("", "Apex Interface");
                _Ticket            = _Rp.BeginSession("", Interop.QBXMLRP2.QBFileMode.qbFileOpenDoNotCare);
                _QBCompanyName     = Path.GetFileName(_Rp.GetCurrentCompanyFileName(_Ticket));
                _ApexTargetCompany = GetApexTargetCompany(_QBCompanyName);
                if (_ApexTargetCompany == "*") //invalid company open
                {
                    Application.Exit();
                    return;
                }
                lblApexCompany.Text    = "Quickbooks Company: " + Path.GetFileName(_QBCompanyName);
                lblApexCompany.Visible = true;
                lblApexCompany.Refresh();

                //For efficiency we are creating these items once and reusing them for each QuickBooks transfer
                XmlSerializer           serializer = new XmlSerializer(typeof(QBXML));
                XmlSerializerNamespaces ns         = new XmlSerializerNamespaces();
                ns.Add("", "");


                var qbxml = new QBXML();
                qbxml.ItemsElementName = new ItemsChoiceType99[1] {
                    ItemsChoiceType99.QBXMLMsgsRq
                };
                qbxml.Items = new object[1];
                var qbMsgsRq = new QBXMLMsgsRq();
                qbMsgsRq.Items   = new object[1];
                qbMsgsRq.onError = QBXMLMsgsRqOnError.stopOnError;

                Cursor.Current = Cursors.WaitCursor;

                try
                {
                    StatusLabel.Text = "Receiving jobs...";
                    TransferJobs(serializer, ns, qbxml, qbMsgsRq);

                    StatusLabel.Text = "Receiving vendors...";
                    TransferVendors(serializer, ns, qbxml, qbMsgsRq);

                    StatusLabel.Text = "Receiving terms...";
                    TransferTerms(serializer, ns, qbxml, qbMsgsRq);

                    if (DEBUGMODE)
                    {
                        StatusLabel.Text = "Receiving accounts...";
                        TransferAccounts(serializer, ns, qbxml, qbMsgsRq);

                        StatusLabel.Text = "Receiving classes...";
                        TransferClasses(serializer, ns, qbxml, qbMsgsRq);
                    }
                }
                finally
                {
                    StatusLabel.Text = "";
                    Cursor.Current   = Cursors.Default;
                }

                MessageBox.Show("QuickBooks data has been imported", "Importing complete");
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                MessageBox.Show("COM Error Description = " + ex.Message, "COM error");
                return;
            }
            finally
            {
                StatusLabel.Text = "";

                if (_Ticket != null)
                {
                    _Rp.EndSession(_Ticket);
                }
                if (_Rp != null)
                {
                    _Rp.CloseConnection();
                }
            };
        }
Beispiel #6
0
        protected void SendApexInvoices()
        {
            using (ApexDataDataContext apexData = new ApexDataDataContext(_SqlConnBuilder.ConnectionString))
            {
                try
                {
                    _Rp = new RequestProcessor2();
                    _Rp.OpenConnection("", "Apex Interface");
                    _Ticket            = _Rp.BeginSession("", Interop.QBXMLRP2.QBFileMode.qbFileOpenDoNotCare);
                    _QBCompanyName     = Path.GetFileName(_Rp.GetCurrentCompanyFileName(_Ticket));
                    _ApexTargetCompany = GetApexTargetCompany(_QBCompanyName);
                    if (_ApexTargetCompany == "*") //invalid company open
                    {
                        Application.Exit();
                        return;
                    }
                    lblApexCompany.Text    = "Quickbooks Company: " + Path.GetFileName(_QBCompanyName);
                    lblApexCompany.Visible = true;
                    lblApexCompany.Refresh();

                    _StatusLines.Clear();

                    List <VendIvc> apexInvoiceList = (from ivc in apexData.VendIvcs
                                                      join po in apexData.POs on ivc.PO equals po.Po1
                                                      where ivc.IvcStatus == "A" &&
                                                      po.Company == _ApexTargetCompany
                                                      select ivc).ToList();

                    if (apexInvoiceList.Count == 0)
                    {
                        MessageBox.Show("There are no invoices to send.");
                    }
                    else
                    {
                        _InvoicesSent = true;  //We have a valid invoice to send so present the interface status report when complete

                        try
                        {
                            GLAcctUtility.GLAcctList = GLAcctUtility.BuildGLAcctList(apexData);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message, "G/L Setup Error");
                            return;
                        }

                        foreach (VendIvc invoice in apexInvoiceList)
                        {
                            decimal ponet         = apexData.POs.Where(s => s.Po1 == invoice.PO).Select(s => s.PoNet).SingleOrDefault() ?? 0;
                            decimal totalInvoiced = apexData.VendIvcs.Where(s => s.PO == invoice.PO).Sum(s => s.IvcAmt) ?? 0;

                            if (apexData.QBInvoices.Where(s => s.Invoice == invoice.Invoice && s.PO == invoice.PO).Any())
                            {
                                _StatusLines.Add(new StatusLine
                                {
                                    Invoice = invoice.Invoice,
                                    PO      = invoice.PO.Trim(),
                                    Message = "Duplicate invoice"
                                });
                            }
                            else
                            {
                                if (totalInvoiced != 0 && (totalInvoiced - ponet > _MaxDiffAmt))
                                {
                                    _StatusLines.Add(new StatusLine
                                    {
                                        Invoice = invoice.Invoice,
                                        PO      = invoice.PO.Trim(),
                                        Message = $"The total invoiced {totalInvoiced:c} exceeds the P/O Net amount {ponet:c} by over {_MaxDiffAmt:c}"
                                    });
                                }
                                else
                                {
                                    decimal ivcTotal = 0; decimal poTaxableAmt = 0;
                                    foreach (VendIvcL ivcLine in invoice.VendIvcLs)
                                    {
                                        ivcTotal += ivcLine.AmtIvc ?? 0;
                                        POLine poline = apexData.POLines.Where(s => s.Po == ivcLine.PO && s.PoLine1 == ivcLine.POLine).SingleOrDefault();
                                        if (poline?.Taxable == "Y")
                                        {
                                            poTaxableAmt += ivcLine.AmtIvc ?? 0;
                                        }
                                    }
                                    double poTaxRate = apexData.POs.Where(s => s.Po1 == invoice.PO).Select(s => s.TaxRate).SingleOrDefault() ?? 0;
                                    ivcTotal += poTaxableAmt * ((decimal)(poTaxRate * 0.01));

                                    decimal invoiceDiff = Math.Abs((invoice.IvcAmt ?? 0) - ivcTotal);

                                    if (ivcTotal != 0 && ((double)((invoiceDiff / ivcTotal)) > (_MaxDiffPct * 0.01) ||
                                                          invoiceDiff > _MaxDiffAmt))
                                    {
                                        //This enforces a business rule set by the client regarding tolerances when reconciling a vendor invoice
                                        _StatusLines.Add(new StatusLine
                                        {
                                            Invoice = invoice.Invoice,
                                            PO      = invoice.PO.Trim(),
                                            Message = $"The P/O lines invoiced {ivcTotal:c} are more than {_MaxDiffAmt:c} or {_MaxDiffPct}% different from the invoice amount {invoice.IvcAmt:c}"
                                        });
                                    }
                                    else
                                    {
                                        //Initial audits passed; process invoice
                                        ProcessInvoice(invoice, apexData);
                                    }
                                }
                            }
                        }
                    }
                }

                catch (System.Runtime.InteropServices.COMException ex)
                {
                    MessageBox.Show("COM Error Description = " + ex.Message, "COM error");
                    return;
                }

                finally
                {
                    if (_Ticket != null)
                    {
                        _Rp.EndSession(_Ticket);
                    }
                    if (_Rp != null)
                    {
                        _Rp.CloseConnection();
                    }
                    UpdateStatus("Export complete");
                }
            };
        }
Beispiel #7
0
        public void Sync()
        {
            // Disable the buttons.
            IsExitEnabled      = false;
            IsTryEnabled       = false;
            IsStartOverEnabled = false;
            OnPropertyChanged("IsExitEnabled");
            OnPropertyChanged("IsTryEnabled");
            OnPropertyChanged("IsStartOverEnabled");

            // Reset error count.
            ValidationErrorCount = 0;
            SaveErrorCount       = 0;

            StatusText = string.Format("{0} - Starting.\r\n", DateTime.Now.ToString());
            OnPropertyChanged("StatusText");


            // ------------------------------------------------------------
            // Ensure the vendor name is specified.
            // ------------------------------------------------------------

            if (string.IsNullOrEmpty(vendorFullName))
            {
                StatusText = string.Format("{0} - Must specify the InventoryConsumptionVendorName in the configuration.\r\n", DateTime.Now.ToString());
                OnPropertyChanged("StatusText");

                // Enable the buttons.
                IsExitEnabled      = true;
                IsTryEnabled       = true;
                IsStartOverEnabled = true;
                OnPropertyChanged("IsExitEnabled");
                OnPropertyChanged("IsTryEnabled");
                OnPropertyChanged("IsStartOverEnabled");

                return;
            }


            // ------------------------------------------------------------
            // Prepare the QuickBooks connection.
            // ------------------------------------------------------------

            var service = new QuickBooksService();

            StatusText += string.Format("{0} - Connecting to QuickBooks.\r\n", DateTime.Now.ToString());
            OnPropertyChanged("StatusText");

            // QBXML request processor must always be closed after use.
            var req = new RequestProcessor2();

            try
            {
                req.OpenConnection2("", "BRIZBEE Integration Utility", QBXMLRPConnectionType.localQBD);
                var ticket          = req.BeginSession("", QBFileMode.qbFileOpenDoNotCare);
                var companyFileName = req.GetCurrentCompanyFileName(ticket);

                StatusText += string.Format("{0} - Syncing.\r\n", DateTime.Now.ToString());
                OnPropertyChanged("StatusText");

                // Determine the method of recording consumption.
                if (selectedMethod == "Inventory Adjustment")
                {
                    StatusText += string.Format("{0} - Using {1} method.\r\n", DateTime.Now.ToString(), selectedMethod);
                    OnPropertyChanged("StatusText");
                }
                else if (selectedMethod == "Sales Receipt")
                {
                    StatusText += string.Format("{0} - Using {1} method and {2} value.\r\n", DateTime.Now.ToString(), selectedMethod, selectedValue);
                    OnPropertyChanged("StatusText");
                }
                else if (selectedMethod == "Bill")
                {
                    StatusText += string.Format("{0} - Using {1} method and {2} value with {3} vendor.\r\n",
                                                DateTime.Now.ToString(), selectedMethod, selectedValue, vendorFullName);
                    OnPropertyChanged("StatusText");
                }


                // ------------------------------------------------------------
                // Collect the QuickBooks host details.
                // ------------------------------------------------------------

                // Prepare a new QBXML document.
                var hostQBXML    = service.MakeQBXMLDocument();
                var hostDocument = hostQBXML.Item1;
                var hostElement  = hostQBXML.Item2;
                service.BuildHostQueryRq(hostDocument, hostElement);

                // Make the request.
                Logger.Debug(hostDocument.OuterXml);
                var hostResponse = req.ProcessRequest(ticket, hostDocument.OuterXml);
                Logger.Debug(hostResponse);

                // Then walk the response.
                var hostWalkResponse = service.WalkHostQueryRsAndParseHostDetails(hostResponse);
                var hostDetails      = hostWalkResponse.Item3;


                // ------------------------------------------------------------
                // Collect any unsynced consumption.
                // ------------------------------------------------------------

                var consumptions = GetConsumption();
                var txnIds       = new List <string>(consumptions.Count);

                if (consumptions.Count == 0)
                {
                    StatusText += string.Format("{0} - There is no inventory consumption to sync.\r\n", DateTime.Now.ToString());
                    OnPropertyChanged("StatusText");
                }
                else
                {
                    // ------------------------------------------------------------
                    // Record the unsynced consumptions.
                    // ------------------------------------------------------------

                    // Build the request to store consumptions.
                    if (selectedMethod == "Sales Receipt")
                    {
                        // Prepare a new QBXML document.
                        var consQBXML    = service.MakeQBXMLDocument();
                        var consDocument = consQBXML.Item1;
                        var consElement  = consQBXML.Item2;

                        service.BuildSalesReceiptAddRq(consDocument, consElement, consumptions, selectedValue.ToUpperInvariant());

                        // Make the request.
                        Logger.Debug(consDocument.OuterXml);
                        var consResponse = req.ProcessRequest(ticket, consDocument.OuterXml);
                        Logger.Debug(consResponse);

                        // Then walk the response.
                        var walkReponse = service.WalkSalesReceiptAddRs(consResponse);
                        txnIds = walkReponse.Item3;
                    }
                    else if (selectedMethod == "Bill")
                    {
                        foreach (var consumption in consumptions)
                        {
                            // Prepare a new QBXML document.
                            var consQBXML    = service.MakeQBXMLDocument();
                            var consDocument = consQBXML.Item1;
                            var consElement  = consQBXML.Item2;

                            service.BuildBillAddRq(consDocument, consElement, consumption, vendorFullName, refNumber, selectedValue.ToUpperInvariant());

                            // Make the request.
                            Logger.Debug(consDocument.OuterXml);
                            var consResponse = req.ProcessRequest(ticket, consDocument.OuterXml);
                            Logger.Debug(consResponse);

                            // Then walk the response.
                            var walkReponse = service.WalkBillAddRs(consResponse);
                            txnIds = txnIds.Concat(walkReponse.Item3).ToList();
                        }
                    }
                    else if (selectedMethod == "Inventory Adjustment")
                    {
                        // Prepare a new QBXML document.
                        var consQBXML    = service.MakeQBXMLDocument();
                        var consDocument = consQBXML.Item1;
                        var consElement  = consQBXML.Item2;

                        service.BuildInventoryAdjustmentAddRq(consDocument, consElement, consumptions, selectedValue.ToUpperInvariant());

                        // Make the request.
                        Logger.Debug(consDocument.OuterXml);
                        var consResponse = req.ProcessRequest(ticket, consDocument.OuterXml);
                        Logger.Debug(consResponse);

                        // Then walk the response.
                        var walkReponse = service.WalkInventoryAdjustmentAddRs(consResponse);
                        txnIds = walkReponse.Item3;
                    }

                    if (SaveErrorCount > 0)
                    {
                        StatusText += string.Format("{0} - Sync failed. Please correct the {1} errors first.\r\n", DateTime.Now.ToString(), SaveErrorCount);
                        OnPropertyChanged("StatusText");

                        var transactionType = "";

                        switch (selectedMethod)
                        {
                        case "Sales Receipt":
                            transactionType = "SalesReceipt";
                            break;

                        case "Bill":
                            transactionType = "Bill";
                            break;

                        case "Inventory Adjustment":
                            transactionType = "InventoryAdjustment";
                            break;
                        }

                        // Reverse the transactions.
                        foreach (var txnId in txnIds)
                        {
                            // Prepare a new QBXML document.
                            var delQBXML    = service.MakeQBXMLDocument();
                            var delDocument = delQBXML.Item1;
                            var delElement  = delQBXML.Item2;
                            service.BuildTxnDelRq(delDocument, delElement, transactionType, txnId); // InventoryAdjustment, SalesReceipt, or Bill

                            // Make the request.
                            Logger.Debug(delDocument.OuterXml);
                            var delResponse = req.ProcessRequest(ticket, delDocument.OuterXml);
                            Logger.Debug(delResponse);

                            // Then walk the response.
                            var delWalkResponse = service.WalkTxnDelRs(delResponse);
                        }
                    }
                    else
                    {
                        // Build the payload.
                        var payload = new
                        {
                            TxnIDs = txnIds,
                            Ids    = consumptions.Select(c => c.Id).ToArray()
                        };

                        // Build the request to send the sync details.
                        var syncHttpRequest = new RestRequest("api/QBDInventoryConsumptions/Sync", Method.POST);
                        syncHttpRequest.AddJsonBody(payload);
                        syncHttpRequest.AddQueryParameter("recordingMethod", selectedMethod);
                        syncHttpRequest.AddQueryParameter("valueMethod", selectedValue);
                        syncHttpRequest.AddQueryParameter("productName", hostDetails.QBProductName);
                        syncHttpRequest.AddQueryParameter("majorVersion", hostDetails.QBMajorVersion);
                        syncHttpRequest.AddQueryParameter("minorVersion", hostDetails.QBMinorVersion);
                        syncHttpRequest.AddQueryParameter("country", hostDetails.QBCountry);
                        syncHttpRequest.AddQueryParameter("supportedQBXMLVersion", hostDetails.QBSupportedQBXMLVersions);
                        syncHttpRequest.AddQueryParameter("hostname", Environment.MachineName);
                        syncHttpRequest.AddQueryParameter("companyFilePath", companyFileName);

                        // Execute request.
                        var syncHttpResponse = client.Execute(syncHttpRequest);
                        if ((syncHttpResponse.ResponseStatus == ResponseStatus.Completed) &&
                            (syncHttpResponse.StatusCode == System.Net.HttpStatusCode.OK))
                        {
                            StatusText += string.Format("{0} - Synced Successfully.\r\n", DateTime.Now.ToString());
                            OnPropertyChanged("StatusText");
                        }
                        else
                        {
                            StatusText += $"{DateTime.Now} - {syncHttpResponse.Content}";
                            StatusText += string.Format("{0} - Sync failed.\r\n", DateTime.Now.ToString());
                            OnPropertyChanged("StatusText");
                        }
                    }
                }

                // Close the QuickBooks connection.
                req.EndSession(ticket);
                req.CloseConnection();
                req = null;
            }
            catch (DownloadFailedException)
            {
                StatusText += string.Format("{0} - Sync failed. Could not download consumption from the server.\r\n", DateTime.Now.ToString());
                OnPropertyChanged("StatusText");
            }
            catch (COMException cex)
            {
                Logger.Error(cex.ToString());

                if ((uint)cex.ErrorCode == 0x80040408)
                {
                    StatusText += string.Format("{0} - Sync failed. QuickBooks Desktop is not open.\r\n", DateTime.Now.ToString());
                    OnPropertyChanged("StatusText");
                }
                else
                {
                    StatusText += string.Format("{0} - Sync failed. {1}\r\n", DateTime.Now.ToString(), cex.Message);
                    OnPropertyChanged("StatusText");
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex.ToString());

                StatusText += string.Format("{0} - Sync failed. {1}\r\n", DateTime.Now.ToString(), ex.Message);
                OnPropertyChanged("StatusText");
            }
            finally
            {
                // Enable the buttons.
                IsExitEnabled      = true;
                IsTryEnabled       = true;
                IsStartOverEnabled = true;
                OnPropertyChanged("IsExitEnabled");
                OnPropertyChanged("IsTryEnabled");
                OnPropertyChanged("IsStartOverEnabled");

                // Try to close the QuickBooks connection if it is still open.
                if (req != null)
                {
                    req.CloseConnection();
                    req = null;
                }
            }
        }