protected override string GetSalesMonth(DateTime exportDate, string filename)
        {
            //Note: This was originally written to work with both live API connections
            //      and manually exported OrderHistory.xml, butAPI sections are now
            //			commented out so it only works with manual exports.
            //      The API version worked, but had to call the API too many times to get
            //			all the orders (250 at a time) and then call again to get the details
            //			for each order. This exceeded the API bandwidth limit for larger stores.

              var stopWatch = new StopWatch(true);

            //get daterange for this month and create query
            var beginDate = new DateTime(exportDate.Year, exportDate.Month, 1);
            var endDate = beginDate.AddMonths(1).AddDays(-1);
            //const string dateFormat = "ddd, dd MMM yyyy HH:mm:ss +0000";
            //string query = string.Format("?min_date_created={0}&max_date_created={1}",
            //                                HttpUtility.UrlEncode(beginDate.ToString(dateFormat)),
            //                                HttpUtility.UrlEncode(endDate.ToString(dateFormat)));

            if (SalesHistory == null || !SalesHistory.Any())
                return Environment.NewLine + "No orders in sales history";
            int rows = SalesHistory.Count();

            //get the order count for this month
            //var ordersXml = CallCartApi("orders/count" + query, "orders");
            //var oCount = ordersXml.Elements("count").First().Value;
            var result = string.Format("{0}{1}: ", Environment.NewLine, filename);
            ProgressText += result;
            string tempDisplay = ProgressText;
            ProgressText += "Exporting...";

            //int rows = Convert.ToInt16(rows);
            //int pages = (int)Math.Ceiling( (decimal)rows / (decimal)250 ); //can only get 250 products at a time
            int errors = 0;  rows = 0;
            var orders = new List<SalesRecord>();
            //for (int page = 1; page <= pages; page++)
            //{
            //  string paging = string.Format("&page={0}&limit=250", page);
            //  ordersXml = CallCartApi("orders" + query + paging, "orders");
            //  if (ordersXml == null) break;

                //var orderElements = ordersXml.Elements("order");
                //var orderElements = SalesHistory.Elements("order");
                //if (orderElements != null)
                //{
                //  foreach (var o in orderElements)
                if (SalesHistory != null)
                {
                    foreach (var o in SalesHistory)
                    {
                        IEnumerable<XElement> productsXml = null;
                        string oCustomer = "", oDate = "", oId = "";
                        try
                        {
                            var dateVal = Client.GetValue(o, "order_date");
                            if (dateVal.Length < 1) continue; //no date

                            DateTime d = DateTime.Parse(dateVal);
                            if ((d.CompareTo(beginDate) < 0) || (d.CompareTo(endDate) > 0))
                                continue;
                            oDate = d.ToShortDateString();
                            oCustomer = Client.GetValue(o, "customer_id");
                            //var dateVal = Client.GetValue(o, "date_created");
                            //oId = Client.GetValue(o, "id");
                            oId = Client.GetValue(o, "order_id");

                            //productsXml = CallCartApi(string.Format("orders/{0}/products", oId), "products").Elements("product");
                            productsXml = o.Elements().Where(x => x.Name.LocalName.Equals("product_details", StringComparison.CurrentCultureIgnoreCase)).Elements("item");
                            if (productsXml == null)
                                throw new ArgumentNullException();
                        }
                        catch (Exception ex)
                        {
                            errors++;
                            continue;
                        }

                        foreach (var p in productsXml)
                        {
                            try
                            {
                                orders.Add(new SalesRecord {
                                                                ProductId = Client.GetValue(p, "product_id"),
                                                                CustomerId = oCustomer,
                                                                //Quantity = Client.GetValue(p, "quantity"),
                                                                Quantity = Client.GetValue(p, "product_qty"),
                                                                Date = oDate
                                                            });
                            }
                            catch { errors++; }
                            ProgressText = string.Format("{0}Extracting...{1} products, {2} errors ({3})", result, ++rows, errors, stopWatch.Lap());
                        }
                    }
                }
            //}
            if (orders.Count < 1)
                return result + "(no data)";

            var countDisplay = string.Format("({0} orders) ", orders.Count);
            ProgressText = tempDisplay + countDisplay + "Uploading...";
            result += countDisplay + m_boostService.WriteTable(m_alias, filename, orders);
            stopWatch.Stop();
              return result;
        }
        protected override string GetCatalog()
        {
            var stopWatch = new StopWatch(true);
              var products = new List<ProductRecord>();

            //get product count
            var countXml = CallCartApi("products/count", "products");
            var countVal = countXml.Elements("count").First().Value;
            int pRows = Convert.ToInt16(countVal);

            //setup progress display
              var result = string.Format("{0}{1}: ({2} items) ", Environment.NewLine, CatalogFilename, countVal);
              ProgressText += result + "Extracting...";
            string tempDisplay = ProgressText;

            //first get all the images because there can be many images for each product so record pages are not aligned
            countXml = CallCartApi("products/images/count", "images");
            countVal = countXml.Elements("count").First().Value;
            int iRows = Convert.ToInt16(countVal);
            int pages = (int)Math.Ceiling( (decimal)iRows / (decimal)250 ); //can only get 250 products at a time
            var imagesXml = new List<XElement>(); //this will hold all images for entire catalog
            for (int page = 1; page <= pages; page++)
            {
                string paging = string.Format("?page={0}&limit=250", page);
                var pageXml = CallCartApi("products/images" + paging, "images");
                if (pageXml == null)
                    break;
                imagesXml.AddRange(pageXml.Elements("image"));
                ProgressText = string.Format("{1}{0}{2} Images ({3})", Environment.NewLine, tempDisplay, imagesXml.Count, stopWatch.Lap());
            }
            tempDisplay = ProgressText;
            #if DEBUG
                if (imagesXml.Count() != iRows)
                {
                    var errMsg = string.Format("Error reading BigCommerce images\nReported count = {0}, actual count = {1}",
                                                                                    iRows, imagesXml.Count());
                    m_log.WriteEntry(errMsg, EventLogEntryType.Information, m_alias);
                }
            #endif

            //Next get all the custom fields so we don't have to make a separate call for each product
            countXml = CallCartApi("products/customfields/count", "customfields");
            countVal = countXml.Elements("count").First().Value;
            iRows = Convert.ToInt16(countVal);
            pages = (int)Math.Ceiling((decimal)iRows / (decimal)250); //can only get 250 products at a time
            var customFieldXml = new List<XElement>(); //this will hold all images for entire catalog
            for (int page = 1; page <= pages; page++)
            {
                string paging = string.Format("?page={0}&limit=250", page);
                var pageXml = CallCartApi("products/customfields" + paging, "customfields");
                if (pageXml == null)
                    break;
                customFieldXml.AddRange(pageXml.Elements("customfield"));
                ProgressText = string.Format("{1}{0}{2} Custom Fields ({3})", Environment.NewLine, tempDisplay, customFieldXml.Count, stopWatch.Lap());
            }
            tempDisplay = ProgressText;

            //Next get all the Categories so we can construct the tree
            countXml = CallCartApi("categories/count", "categories");
            countVal = countXml.Elements("count").First().Value;
            iRows = Convert.ToInt16(countVal);
            pages = (int)Math.Ceiling((decimal)iRows / (decimal)250); //can only get 250 products at a time
            var categoryXml = new List<XElement>(); //this will hold all images for entire catalog
            for (int page = 1; page <= pages; page++)
            {
                string paging = string.Format("?page={0}&limit=250", page);
                var pageXml = CallCartApi("categories" + paging, "categories");
                if (pageXml == null)
                    break;
                categoryXml.AddRange(pageXml.Elements("category"));
                ProgressText = string.Format("{1}{0}{2} Categories ({3})", Environment.NewLine, tempDisplay, categoryXml.Count, stopWatch.Lap());
            }
            SetCategoryParents(categoryXml);
            ProgressText += Environment.NewLine;
            tempDisplay = ProgressText;

            //now get each page of products
            pages = (int)Math.Ceiling((decimal)pRows / (decimal)250); //can only get 250 products at a time
            IEnumerable<XElement> productsXml = null; //this will only hold a single page of products
            int errors = 0; pRows = 0;
            for (int page = 1; page <= pages; page++)
                {
                string paging = string.Format("?page={0}&limit=250", page);
                productsXml = CallCartApi("products" + paging, "products");
                if (productsXml == null)
                {
                    errors++; //not necessarily an error
                    break;
                }

                var productElements = productsXml.Elements("product");
                foreach (var product in productElements)
                {
                    try
                    {
                        var p = new ProductRecord
                                                            {
                                                                Name = Client.GetValue(product, "name"),
                                                                ProductId = Client.GetValue(product, "id"),
                                                                Att2Id = Client.GetValue(product, "brand_id"),
                                                                Price = Client.GetValue(product, "price"),
                                                                SalePrice = Client.GetValue(product, "sale_price"),
                                                                Filter = string.Empty,
                                                                Rating = Client.GetValue(product, "rating_total"),
                                                                StandardCode = Client.GetValue(product, "upc"),
                                                                Link = Client.GetValue(product, "custom_url"),
                                                                ImageLink = string.Empty
                                                            };

                        p.ImageLink = GetProductImage(imagesXml, p.ProductId);
                        p.Att1Id = GetProductCategories(product.Element("categories"));
                        if (p.StandardCode == null)
                            p.StandardCode = string.Empty;

            #if DEBUG
                        if (p.ProductId.Equals("11348") || p.ProductId.Equals("11012"))
                        {
                            var test = CallCartApi(string.Format("products/{0}/customfields", p.ProductId), "customfields");
                            var s = "break here";
                        }
            #endif
                        var customFields = GetProductCustomFields(customFieldXml, p.ProductId);
                        if (customFields.Any())
                            product.Add(customFields);

                        //check category conditions, exclusions, and filters
                        ApplyRules(ref p, product);

                        products.Add(p);
                    }
                    catch { errors++; }
                    ProgressText = string.Format("{0}{1} items completed, {2} errors ({3})", tempDisplay, ++pRows, errors, stopWatch.Lap());
                }
            }
            if (products.Count < 1)
                return result + "(no data)";

            var pCount = string.Format("({0} items) ", products.Count);
              ProgressText = string.Format("{0}{1} items completed ({2}){3}Uploading to server...", tempDisplay, pCount, stopWatch.Lap(), Environment.NewLine);
            result += m_boostService.WriteTable(m_alias, CatalogFilename, products);
            stopWatch.Stop();
              return result;
        }