示例#1
0
        private void deleteItemButton_Click(object sender, EventArgs e)
        {
            var iCellIndex = wantsView.Columns["idWant"].Index;

            if (wantsView.SelectedRows.Count == 0)
            {
                MessageBox.Show("Please select the row you want to delete!");
                return;
            }

            foreach (DataGridViewRow selectedRow in wantsView.SelectedRows)
            {
                string idWant = selectedRow.Cells[iCellIndex].Value.ToString();

                string sRequestXML = MKMInteract.RequestHelper.deleteWantsListBody(idWant);
                sRequestXML = MKMInteract.RequestHelper.getRequestBody(sRequestXML);
                string sListId = (wantListsBox.SelectedItem as MKMHelpers.ComboboxItem).Value.ToString();

                try
                {
                    MKMInteract.RequestHelper.makeRequest("https://api.cardmarket.com/ws/v2.0/wantslist/" + sListId, "PUT",
                                                          sRequestXML);
                }
                catch (Exception eError)
                {
                    MKMHelpers.LogError("deleting from wantlist item #" + idWant, eError.Message, true, sRequestXML);
                }
            }
            wantsListBoxReload();
        }
示例#2
0
        public MainView()
        {
            InitializeComponent();

#if DEBUG
            logBox.AppendText("DEBUG MODE ON!\n");
#endif
            try
            {
                if (!File.Exists(@".\\config.xml"))
                {
                    MessageBox.Show("No config file found! Create a config.xml first.");

                    Application.Exit();
                }

                MKMHelpers.GetProductList();

                var doc2 = MKMInteract.RequestHelper.getAccount();

                MKMHelpers.sMyOwnCountry = doc2["response"]["account"]["country"].InnerText;
                MKMHelpers.sMyId         = doc2["response"]["account"]["idUser"].InnerText;

                bot = new MKMBot();
            }
            catch (Exception eError)
            {
                MessageBox.Show(eError.Message);
            }
        }
示例#3
0
        /// <summary>
        /// Loads all setting presets stored as .xml files in /Presets/ folder
        /// and populates the combobox with their names.
        /// </summary>
        private void loadPresets()
        {
            DirectoryInfo d = new DirectoryInfo(@".//Presets");

            FileInfo[] Files = d.GetFiles("*.xml");
            presets = new Dictionary <string, MKMBotSettings>();
            foreach (FileInfo file in Files)
            {
                MKMBotSettings s = new MKMBotSettings();
                try
                {
                    XmlDocument doc = new XmlDocument();
                    doc.Load(file.FullName);
                    s.Parse(doc);
                    string name = file.Name.Substring(0, file.Name.Length - 4); // cut off the ".xml"
                    presets[name] = s;
                    comboBoxPresets.Items.Add(name);
                }
                catch (Exception eError)
                {
                    MKMHelpers.LogError("reading preset " + file.Name, eError.Message, false);
                }
            }
            comboBoxPresets.SelectedIndex = comboBoxPresets.Items.Add("Choose Preset...");
        }
示例#4
0
        private void addButton_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem item in cardView.SelectedItems)
            {
                var idProduct = item.Text;

                //MessageBox.Show(idProduct);

                //addWantsListBody(string idProduct, string minCondition, string idLanguage, string isFoil, string isAltered, string isPlayset, string isSigned)
                var sRequestXML = MKMInteract.RequestHelper.addWantsListBody(idProduct,
                                                                             conditionCombo.Text,
                                                                             (langCombo.SelectedItem as MKMHelpers.ComboboxItem).Value.ToString(),
                                                                             foilBox.CheckState.ToString(),
                                                                             alteredBox.CheckState.ToString(),
                                                                             playsetBox.CheckState.ToString(),
                                                                             signedBox.CheckState.ToString());

                sRequestXML = MKMInteract.RequestHelper.getRequestBody(sRequestXML);

                try
                {
                    var sListId = (wantListsBox.SelectedItem as MKMHelpers.ComboboxItem).Value.ToString();

                    MKMInteract.RequestHelper.makeRequest("https://api.cardmarket.com/ws/v2.0/wantslist/" + sListId, "PUT",
                                                          sRequestXML);
                }
                catch (Exception eError)
                {
                    MKMHelpers.LogError("adding to wantlist, product id " + idProduct, eError.Message, true, sRequestXML);
                    return;
                }
            }
            wantsListBoxReload();
        }
示例#5
0
        private void buttonPresetsDelete_Click(object sender, EventArgs e)
        {
            string name = comboBoxPresets.SelectedItem.ToString();

            if (MessageBox.Show("Are you sure you want to delete preset '" + name + "'? This cannot be undone.",
                                "Delete preset", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                try
                {
                    FileInfo f = new FileInfo(@".//Presets//" + name + ".xml");
                    if (f.Exists) // better check, could have been deleted manually during the run
                    {
                        f.Delete();
                    }
                    presets.Remove(name);
                    comboBoxPresets.Items.RemoveAt(comboBoxPresets.SelectedIndex);
                    comboBoxPresets.SelectedIndex = comboBoxPresets.Items.Add("Choose Preset...");
                    labelPresetsDescr.Text        = "";
                }
                catch (Exception exc)
                {
                    MKMHelpers.LogError("deleting preset", exc.Message, true);
                }
            }
        }
示例#6
0
        public void initWantLists()
        {
            XmlDocument doc = null;

            try
            {
                doc = MKMInteract.RequestHelper.getWantsLists();
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("initializing want list, editor will be disabled", eError.Message, true);
                addButton.Enabled        = false;
                deleteItemButton.Enabled = false;
                return;
            }

            var node = doc.GetElementsByTagName("wantslist");

            if (node.Count > 0)
            {
                wantListsBox.Items.Clear();
                foreach (XmlNode nWantlist in node)
                {
                    var item = new MKMHelpers.ComboboxItem();

                    item.Text  = nWantlist["name"].InnerText;
                    item.Value = nWantlist["idWantslist"].InnerText;

                    wantListsBox.Items.Add(item);

                    wantListsBox.SelectedIndex = 0;
                }
            }
        }
示例#7
0
        public DataTable buildProperWantsList(string sListId)
        {
            try
            {
                var doc = MKMInteract.RequestHelper.getWantsListByID(sListId);

                var xmlReader = new XmlNodeReader(doc);

                var ds = new DataSet();

                ds.ReadXml(xmlReader);

                if (!ds.Tables.Contains("item"))
                {
                    return(new DataTable());
                }

                DataTable eS = MKMHelpers.ReadSQLiteToDt("expansions");

                var dv = MKMHelpers.JoinDataTables(dt, eS,
                                                   (row1, row2) => row1.Field <string>("Expansion ID") == row2.Field <string>("idExpansion"));

                dv = MKMHelpers.JoinDataTables(dv, ds.Tables["item"],
                                               (row1, row2) => row1.Field <string>("idProduct") == row2.Field <string>("idProduct"));

                return(dv);
            }
            catch (Exception eError)
            {
                MessageBox.Show(eError.ToString());
                return(new DataTable());
            }
        }
        /// Uses the provided price guides to compute the price according to the formula.
        /// <param name="priceGuides">Row from the priceGuides table containing guides for the card for which to evaluate this formula.
        /// If this formula UsesPriceGuides, must be set to contain all the columns, otherwise exception is thrown.</param>
        /// <param name="currentPrice">Our current sale price of the card (can be used as a guide).</param>
        /// <returns>The final price this formula evaluates to. NaN if the necessary guides are not found.</returns>
        public double Evaluate(DataRow priceGuides, double currentPriceSingle)
        {
            double term;

            foreach (var guideTerm in guidesToResolve)
            {
                if (guideTerm.Value == "CURRENT")
                {
                    term = currentPriceSingle;
                }
                else
                {
                    term = MKMHelpers.ConvertDoubleAnySep(priceGuides[guideTerm.Value].ToString());
                }
                if (double.IsNaN(term))
                {
                    return(term);
                }
                operands[guideTerm.Key] = term;
            }
            double val = operands[0];

            for (int i = 0; i < operators.Count; i++)
            {
                val = operators[i](val, operands[i + 1]);
            }
            return(val);
        }
示例#9
0
        /// <summary>
        /// Initializes the instance of this MainView.
        /// Because error logging mechanism uses the MainView's console, it needs to be called only after the handle for the window
        /// has been created --> during the "Load" event or later (after the form has been created and shown).
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void initialize(object sender, EventArgs e)
        {
            Config         = new MKMToolConfig();
            timer.Interval = 1440 * 1000 * 60; // set the interval to one day (1440 minutes in ms)
            try
            {
                var doc2 = MKMInteract.RequestHelper.getAccount();

                if (Config.MyCountryCode == "") // signifies user wants auto-detect, otherwise the chosen setting overrides what we get from MKM
                {
                    Config.MyCountryCode = doc2["response"]["account"]["country"].InnerText;
                }
                MKMHelpers.sMyId = doc2["response"]["account"]["idUser"].InnerText;
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("initializing product list and account info", eError.Message, true);
            }
            bot                      = new MKMBot();
            settingsWindow           = new UpdatePriceSettings("LastSettingsPreset", "Settings of Update Price");
            stockViewWindow          = new StockView();
            checkCheapDealsWindow    = new CheckWantsView();
            checkDisplayPricesWindow = new CheckDisplayPrices();
            wantlistEditorViewWindow = new WantlistEditorView();
            priceExternalListWindow  = new PriceExternalList();
        }
示例#10
0
        public void initCardView()
        {
            try
            {
                cardView.View          = View.Details;
                cardView.GridLines     = true;
                cardView.FullRowSelect = true;

                cardView.BackColor = Color.WhiteSmoke;

                cardView.Columns.Add("ProduktID", 60);
                cardView.Columns.Add("Card Name", 220);
                cardView.Columns.Add("Edition", 120);

                dj = new DataTable();

                dj = MKMHelpers.JoinDataTables(dt, eS,
                                               (row1, row2) => row1.Field <string>("Expansion ID") == row2.Field <string>("idExpansion"));

                foreach (DataRow row in dj.Rows)
                {
                    var item = new ListViewItem(row["idProduct"].ToString());

                    item.SubItems.Add(row["Name"].ToString());
                    item.SubItems.Add(row["enName"].ToString());

                    cardView.Items.Add(item);
                }
            }
            catch (Exception eError)
            {
                MessageBox.Show(eError.ToString());
            }
        }
示例#11
0
        public void initWantLists()
        {
            XmlDocument doc = null;

            try
            {
                doc = MKMInteract.RequestHelper.getWantsLists();
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("fetching all want lists, disabling Check Wantlist", eError.Message, true);
                checkListButton.Enabled = false;
                return;
            }

            var node = doc.GetElementsByTagName("wantslist");

            foreach (XmlNode nWantlist in node)
            {
                var item = new MKMHelpers.ComboboxItem();

                item.Text  = nWantlist["name"].InnerText;
                item.Value = nWantlist["idWantslist"].InnerText;

                wantListsBox2.Items.Add(item);

                wantListsBox2.SelectedIndex = 0;
            }
        }
示例#12
0
            /// <summary>
            /// Sends stock update to MKM.
            /// </summary>
            /// <param name="sRequestXML">The raw (= not as an API request yet) XML with all article updates. Check that it is not empty before calling this.
            /// Also, it must match the used method - PUT requires to know articleID for each article, POST productID.</param>
            /// <param name="method">"PUT" to update articles already in stock, "POST" to upload new articles</param>
            public static void SendStockUpdate(string sRequestXML, string method)
            {
                sRequestXML = getRequestBody(sRequestXML);

                try
                {
                    XmlDocument rdoc = makeRequest("https://api.cardmarket.com/ws/v2.0/stock", method,
                                                   sRequestXML);
                    int iUpdated = 0, iFailed = 0;
                    if (method == "PUT")
                    {
                        var xUpdatedArticles    = rdoc.GetElementsByTagName("updatedArticles");
                        var xNotUpdatedArticles = rdoc.GetElementsByTagName("notUpdatedArticles");

                        iUpdated = xUpdatedArticles.Count;
                        iFailed  = xNotUpdatedArticles.Count;
                    }
                    else if (method == "POST")
                    {
                        XmlNodeList inserted = rdoc.GetElementsByTagName("inserted");
                        foreach (XmlNode x in inserted)
                        {
                            if (x["success"].InnerText == "true")
                            {
                                iUpdated++;
                            }
                            else
                            {
                                iFailed++;
                            }
                        }
                    }

                    MainView.Instance.LogMainWindow(
                        iUpdated + " articles updated successfully, " + iFailed + " failed");

                    if (iFailed > 0)
                    {
                        try
                        {
                            File.WriteAllText(@".\\log" + DateTime.Now.ToString("ddMMyyyy-HHmm") + ".log", rdoc.InnerText.ToString());
                        }
                        catch (Exception eError)
                        {
                            MKMHelpers.LogError("logging failed stock update articles", eError.Message, false);
                        }
                        MainView.Instance.LogMainWindow(
                            "Failed articles logged in " + @".\\log" + DateTime.Now.ToString("ddMMyyyy-HHmm") + ".log");
                    }
                }
                catch (Exception eError)
                {
                    // for now this does not break the price update, i.e. the bot will attempt to update the following items - maybe it shouldn't as it is likely to fail again?
                    MKMHelpers.LogError("sending stock update to MKM", eError.Message, false, sRequestXML);
                }
            }
示例#13
0
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                MKMInteract.RequestHelper.emptyCart();

                MainView.Instance.LogMainWindow("Shopping Cart emptied.");
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("emptying shopping cart, cart not emptied", eError.Message, true);
            }
        }
示例#14
0
        public StockView()
        {
            InitializeComponent();

            try
            {
                eS = MKMHelpers.ReadSQLiteToDt("expansions");

                stockGridView.ReadOnly = true;
            }
            catch (Exception eError)
            {
                MessageBox.Show(eError.ToString());
            }

            try
            {
                var doc = MKMInteract.RequestHelper.readStock();

                var xmlReader = new XmlNodeReader(doc);

                var ds = new DataSet();

                ds.ReadXml(xmlReader);

                var dj = MKMHelpers.JoinDataTables(ds.Tables[0], dt,
                                                   (row1, row2) => row1.Field <string>("idProduct") == row2.Field <string>("idProduct"));

                dj = MKMHelpers.JoinDataTables(dj, eS,
                                               (row1, row2) => row1.Field <string>("Expansion ID") == row2.Field <string>("idExpansion"));

                dj.Columns.Remove("article_Id");
                dj.Columns.Remove("Date Added");
                dj.Columns.Remove("Category ID");
                dj.Columns.Remove("Category");
                dj.Columns.Remove("Metacard ID");
                dj.Columns.Remove("idArticle");
                dj.Columns.Remove("idProduct");
                dj.Columns.Remove("Expansion ID");
                dj.Columns.Remove("idExpansion");

                dj.Columns[dj.Columns.IndexOf("Name")].SetOrdinal(0);

                stockGridView.DataSource = dj;
                //dataGridView1.DataSource = dt;
            }
            catch (Exception eError)
            {
                MessageBox.Show(eError.ToString());
            }
        }
示例#15
0
        private void button1_Click(object sender, EventArgs e)
        {
            string searchString = searchBox.Text.Replace("'", "");

            try
            {
                (stockGridView.DataSource as DataTable).DefaultView.RowFilter =
                    string.Format("Name LIKE '%{0}%'", searchString);
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("searching for " + searchString + " in Stock View", eError.Message, true);
            }
        }
示例#16
0
        /// <summary>
        /// Initializes the instance of this MainView.
        /// Because error logging mechanism uses the MainView's console, it needs to be called only after the handle for the window
        /// has been created --> during the "Load" event or later (after the form has been created and shown).
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void initialize(object sender, EventArgs e)
        {
            timer.Interval = 1440 * 1000 * 60; // set the interval to one day (1440 minutes in ms)
            try
            {
                var doc2 = MKMInteract.RequestHelper.getAccount();

                MKMHelpers.sMyOwnCountry = doc2["response"]["account"]["country"].InnerText;
                MKMHelpers.sMyId         = doc2["response"]["account"]["idUser"].InnerText;
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("initializing product list and account info", eError.Message, true);
            }
            bot = new MKMBot();
        }
示例#17
0
        /// Sets this from string.
        /// <param name="formula">The formula as string.</param>
        /// <returns>True if parsing finished successfully, false if some of the operands were neither numbers nor price guides.</returns>
        public bool Parse(string formula)
        {
            string formulaOrig = formula;

            formula = formula.Trim();
            var separators = new char[] { '*', '-', '+' };
            // parse the first operand, there must be at least one and the formula cannot start with an operand
            string operand = formula.Split(separators, 2)[0];

            if (!parseAndAddOperand(operand.Trim()))
            {
                MKMHelpers.LogError("parsing price formula", "failed to parse operand " + operand + " in formula " + formulaOrig
                                    + ", it cannot be used.", true);
                return(false);
            }
            formula = formula.Substring(operand.Length);
            while (formula.Length > 0)
            {
                char oper = formula[0]; // the next symbol is surely the operand
                switch (oper)
                {
                case '*':
                    operators.Add(mult);
                    break;

                case '-':
                    operators.Add(subtract);
                    break;

                case '+':
                    operators.Add(adding);
                    break;
                }
                formula = formula.Substring(1);
                // there must be another operand after operator, otherwise it is an error
                operand = formula.Split(separators, 2)[0];
                if (!parseAndAddOperand(operand.Trim()))
                {
                    MKMHelpers.LogError("parsing price formula", "failed to parse operand " + operand + " in formula " + formulaOrig
                                        + ", it cannot be used.", false);
                    return(false);
                }
                formula = formula.Substring(operand.Length);
                formula.Trim();
            }
            return(true);
        }
示例#18
0
        public AccountInfo()
        {
            InitializeComponent();
            treeView1.Nodes.Clear();
            treeView1.Nodes.Add(new TreeNode("Account Details"));
            var tNode = treeView1.Nodes[0];

            try
            {
                var doc = MKMInteract.RequestHelper.GetAccount();

                addNode(doc["response"]["account"], tNode);
            }
            catch (System.Exception eError)
            {
                MKMHelpers.LogError("fetching account info", eError.Message, true);
            }
            //treeView1.ExpandAll();
        }
示例#19
0
            public static byte[] GetPriceGuideFile(string gameId)
            {
                var doc = MakeRequest("https://api.cardmarket.com/ws/v2.0/priceguide?idGame="
                                      + gameId, "GET");

                var node = doc.GetElementsByTagName("response");

                if (node.Count > 0 && node.Item(0)["priceguidefile"].InnerText != null)
                {
                    var data          = Convert.FromBase64String(node.Item(0)["priceguidefile"].InnerText);
                    var aDecompressed = MKMHelpers.GzDecompress(data);
                    return(aDecompressed);
                }
                else
                {
                    MKMHelpers.LogError("getting price guide file", "failed to get the price guide file from MKM.", false);
                    return(null);
                }
            }
示例#20
0
        // this is done whenever it is shown/hidden - in case it is made visible, reload all data in case something has changed in the meantime
        private void CheckWantsView_VisibleChanged(object sender, EventArgs e)
        {
            if (Visible)
            {
                MKMDbManager.Instance.PopulateExpansionsComboBox(editionBox);
                if (editionBox.Items.Count > 0)
                {
                    editionBox.Sorted        = true;
                    editionBox.SelectedIndex = 0;
                }
                else
                {
                    MKMHelpers.LogError("loading expansions from local database for Check Cheap Deals", "Database empty.", false);
                }

                conditionCombo.SelectedIndex = 4;
                initWantLists();
            }
        }
示例#21
0
        /// Converts the operand to number or price guide and stores it
        /// <param name="operand">Trimmed string representation of the operand.</param>
        /// <returns>False if the parsing failed.</returns>
        private bool parseAndAddOperand(string operand)
        {
            double number = MKMHelpers.ConvertDoubleAnySep(operand);

            if (double.IsNaN(number))
            {
                foreach (var guide in MKMHelpers.PriceGuides)
                {
                    if (guide.Value.Code == operand)
                    {
                        guidesToResolve.Add(new KeyValuePair <int, string>(operands.Count, operand));
                        operands.Add(-9999);
                        return(true);
                    }
                }
            }
            else
            {
                operands.Add(number);
                return(true);
            }
            return(false);
        }
示例#22
0
            public MKMToolConfig()
            {
                var xConfigFile = new XmlDocument();

                xConfigFile.Load(@".//config.xml");
                if (xConfigFile["config"]["settings"] != null)
                {
                    var settings = xConfigFile["config"]["settings"];
                    foreach (XmlNode setting in settings)
                    {
                        switch (setting.Name)
                        {
                        case "UseStockGetFile":
                            if (bool.TryParse(setting.InnerText, out bool stockGetMethod))
                            {
                                UseStockGetFile = stockGetMethod;
                            }
                            break;

                        case "Games":
                            var split = setting.InnerText.Split(';');
                            if (split.Length == 0)
                            {
                                MKMHelpers.LogError("reading Games setting", "No games specified in config.xml.", false);
                            }
                            else
                            {
                                Games.Clear();
                                foreach (var game in split)
                                {
                                    var trimmed = game.Trim();
                                    if (trimmed.Length > 0)
                                    {
                                        if (MKMHelpers.gameIDsByName.ContainsKey(trimmed))
                                        {
                                            Games.Add(MKMHelpers.gameIDsByName[trimmed]);
                                        }
                                        else
                                        {
                                            MKMHelpers.LogError("reading Games setting",
                                                                "Unknown game " + trimmed + " specified, will be ignored.", false);
                                        }
                                    }
                                }
                            }
                            break;

                        case "CSVExportSeparator":
                            CSVExportSeparator = setting.InnerText;
                            break;

                        case "MyCountryCode":
                            if (setting.InnerText != "" && MKMHelpers.countryNames.ContainsKey(setting.InnerText))
                            {
                                MyCountryCode = setting.InnerText;
                            }
                            // else leave the default, i.e. ""
                            break;
                        }
                    }
                }
            }
示例#23
0
        // reload data each time the form is made visible in case the user's stock has changed so they can reload the stockview this way
        private void stockView_VisibleChanged(object sender, EventArgs e)
        {
            if (Visible)
            {
                var articles = new DataTable();
                try
                {
                    // getAllStockSingles creates a DataTable and converts it to list of cards, so theoretically we are wasting some work
                    // but it also filters out non-singles and converting to MKMcard will make sure we use the primary column names rather than synonyms
                    var cards = MKMInteract.RequestHelper.GetAllStockSingles(MainView.Instance.Config.UseStockGetFile);
                    if (cards.Count == 0)
                    {
                        MainView.Instance.LogMainWindow("Stock is empty. Did you select correct idGame in config.xml?");
                        return;
                    }
                    foreach (var card in cards)
                    {
                        card.WriteItselfIntoTable(articles, true, MCFormat.MKM, true);
                    }
                    // Remove columns we don't want showing
                    // TODO - what is and isn't shown should probably be customizable and left to the user to choose in some way
                    if (articles.Columns.Contains(MCAttribute.ArticleID))
                    {
                        articles.Columns.Remove(MCAttribute.ArticleID);
                    }
                    if (articles.Columns.Contains(MCAttribute.LanguageID))
                    {
                        articles.Columns.Remove(MCAttribute.LanguageID);
                    }
                    if (articles.Columns.Contains(MCAttribute.MetaproductID))
                    {
                        articles.Columns.Remove(MCAttribute.MetaproductID);
                    }
                    if (articles.Columns.Contains("onSale"))
                    {
                        articles.Columns.Remove("onSale"); // don't even know what this one is supposed to be, it's not even in the API documentation
                    }
                    if (articles.Columns.Contains(MCAttribute.MKMCurrencyCode))
                    {
                        articles.Columns.Remove(MCAttribute.MKMCurrencyCode);
                    }
                    if (articles.Columns.Contains(MCAttribute.MKMCurrencyId))
                    {
                        articles.Columns.Remove(MCAttribute.MKMCurrencyId);
                    }

                    var dj = MKMDbManager.JoinDataTables(articles, MKMDbManager.Instance.Expansions,
                                                         (row1, row2) => row1.Field <string>(MCAttribute.ExpansionID) == row2.Field <string>(MKMDbManager.ExpansionsFields.ExpansionID));

                    if (dj.Columns.Contains(MCAttribute.ExpansionID))
                    {
                        dj.Columns.Remove(MCAttribute.ExpansionID); // duplicated
                    }
                    if (dj.Columns.Contains(MKMDbManager.ExpansionsFields.ExpansionID))
                    {
                        dj.Columns.Remove(MKMDbManager.ExpansionsFields.ExpansionID); // ...and we don't want it anyway
                    }
                    if (dj.Columns.Contains(MKMDbManager.ExpansionsFields.Name))
                    {
                        dj.Columns.Remove(MKMDbManager.ExpansionsFields.Name); // duplicated
                    }
                    // use the same order with or without UseStockGetFile
                    System.Collections.Generic.List <string> attsOrdered = new System.Collections.Generic.List <string>
                    {
                        MCAttribute.Name, MCAttribute.Expansion, MCAttribute.Language, MCAttribute.ProductID,
                        MCAttribute.MKMPrice, MCAttribute.Condition, MCAttribute.Comments, MCAttribute.Foil,
                        MCAttribute.Altered, MCAttribute.Signed, MCAttribute.Playset, MCAttribute.Count,
                        MCAttribute.Rarity, MCAttribute.ExpansionAbb
                    };
                    int ordinal = 0;
                    foreach (string att in attsOrdered)
                    {
                        if (dj.Columns.Contains(att))
                        {
                            dj.Columns[dj.Columns.IndexOf(att)].SetOrdinal(ordinal++);
                        }
                    }

                    // convert columns with numerical data from string so that sorting works correctly
                    if (dj.Columns.Contains(MCAttribute.ProductID))
                    {
                        convertNumberColumn(dj, MCAttribute.ProductID, false);
                    }
                    if (dj.Columns.Contains(MCAttribute.Count))
                    {
                        convertNumberColumn(dj, MCAttribute.Count, false);
                    }
                    if (dj.Columns.Contains(MCAttribute.MKMPrice))
                    {
                        convertNumberColumn(dj, MCAttribute.MKMPrice, true);
                    }

                    stockGridView.DataSource = dj;

                    buttonExport.Enabled = true;
                }
                catch (Exception eError)
                {
                    MKMHelpers.LogError("listing stock in Stock View", eError.Message, true);
                }
            }
        }
示例#24
0
        private void wantsListBoxReload()
        {
            var sListId = (wantListsBox.SelectedItem as MKMHelpers.ComboboxItem).Value.ToString();

            wantsView.Columns.Clear();
            DataTable dv = null;

            try
            {
                var doc = MKMInteract.RequestHelper.getWantsListByID(sListId);

                var xmlReader = new XmlNodeReader(doc);

                var ds = new DataSet();

                ds.ReadXml(xmlReader);

                if (!ds.Tables.Contains("item"))
                {
                    return;
                }

                dv = ds.Tables["item"];
                dv.Columns.Add("enName");
                dv.Columns.Add("expansionName");
                dv.Columns["enName"].SetOrdinal(0); // put the name and expansion at the beggining of the table
                dv.Columns["expansionName"].SetOrdinal(1);
                int itemCounter = 0;
                foreach (XmlNode child in doc["response"]["wantslist"].ChildNodes)
                {
                    if (child.Name == "item")
                    {
                        if (child["type"].InnerText == "product")
                        {
                            dv.Rows[itemCounter]["enName"]        = child["product"]["enName"].InnerText;
                            dv.Rows[itemCounter]["expansionName"] = child["product"]["expansionName"].InnerText;
                        }
                        else // it is a metaproduct
                        {
                            dv.Rows[itemCounter]["enName"] = child["metaproduct"]["enName"].InnerText; // we don't care which child is the first, the name is the same for all
                            // we would have to do an additional API call to get the list of expansions
                            // given that the current code refreshes this view everytime an item is added to wantlist, it is not very practical
                            dv.Rows[itemCounter]["expansionName"] = "<any>";
                        }
                        itemCounter++;
                    }
                }
                dv = ds.Tables["item"];
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("processing wantlist " + sListId + ", it will be ignored", eError.Message, true);
                return;
            }
            if (dv.Select().Length > 0)
            {
                wantsView.AutoGenerateColumns = true;
                wantsView.DataSource          = dv;

                wantsView.Refresh();

                if (wantsView.Columns.Contains("idProduct")) // if the wantlist has only metaproducts, there will be no idProduct entry
                {
                    wantsView.Columns["idProduct"].Visible = false;
                }
                wantsView.Columns["idWant"].Visible    = false;
                wantsView.Columns["type"].Visible      = false;
                wantsView.Columns["wishPrice"].Visible = false;
                wantsView.Columns["count"].Visible     = false;

                wantsView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
                wantsView.ReadOnly            = true;
            }
        }
示例#25
0
        // idArticle - if not empty, article will be added to shopping cart only if it is matching the specified idArticle. used for searching for cheap deals by user
        // idLanguages - list of languages to check for. if all are OK, pass in either an empty list or a list with exactly one entry which is an empty string
        private void checkArticle(string idProduct, System.Collections.Generic.List <string> idLanguages, string minCondition, string isFoil,
                                  string isSigned, string isAltered, string isPlayset, string matchingArticle,
                                  double maxAllowedPrice, double shippingAddition, double percentBelowOthers, bool checkTrend)
        {
            var sUrl = "https://api.cardmarket.com/ws/v2.0/articles/" + idProduct +
                       "?minCondition=" + minCondition +
                       "&start=0&maxResults=50";

            if (isFoil != "")
            {
                sUrl += "&isFoil=" + isFoil;
            }

            if (isSigned != "")
            {
                sUrl += "&isSigned=" + isSigned;
            }

            if (isAltered != "")
            {
                sUrl += "&isAltered=" + isAltered;
            }

            if (isPlayset != "")
            {
                sUrl += "&isPlayset=" + isPlayset;
            }

            if (idLanguages.Count == 1 && idLanguages[0] != "") // if there is exactly one language specified, fetch only articles in that one language, otherwise get all
            {
                sUrl += "&idLanguage=" + idLanguages[0];
            }

            XmlDocument doc2 = null;

            try
            {
                doc2 = MKMInteract.RequestHelper.makeRequest(sUrl, "GET");
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("checking article id " + idProduct, eError.Message, false, sUrl);
                return;
            }

            var node2 = doc2.GetElementsByTagName("article");

            var counter = 0;

            var noBestPrice = true;

            var aPrices = new float[4];

            var bestPriceArticle = "";

            float bestPriceInternational = 0;

            foreach (XmlNode offer in node2)
            {
                /*
                 * Wantstates:
                 * Empty    = n/a
                 * true     = yes
                 * false    = no
                 */

                if (offer["seller"]["address"]["country"].InnerText != MKMHelpers.sMyOwnCountry && domesticCheck.Checked)
                {
                    continue;
                }

                bool languageOk = true;
                if (idLanguages.Count > 1) // only some languages were specified, filter
                {
                    languageOk = false;
                    foreach (string lang in idLanguages)
                    {
                        if (lang == offer["language"]["idLanguage"].InnerText)
                        {
                            languageOk = true;
                            break;
                        }
                    }
                }
                if (!languageOk)
                {
                    continue;
                }

                // save cheapest price found anywhere
                aPrices[counter] = Convert.ToSingle(offer["price"].InnerText, CultureInfo.InvariantCulture);
                if (noBestPrice)
                {
                    bestPriceInternational = aPrices[counter];
                    noBestPrice            = false;
                }


                if (aPrices[0] + shippingAddition > maxAllowedPrice)
                {
                    //frm1.logBox.Invoke(new Form1.logboxAppendCallback(frm1.logBoxAppend), "Price higher than Max Price\n");
                    continue;
                }

                if (counter == 0)
                {
                    bestPriceArticle = offer["idArticle"].InnerText;
                    // if looking for matching article, no point to continue if it is not the cheapest - perhaps could be modified to pick things that are among matching?
                    if (matchingArticle != "" && matchingArticle != bestPriceArticle)
                    {
                        break;
                    }
                }

                counter++;

                if (counter == 3)
                {
                    double factor = percentBelowOthers;

                    factor = factor / 100 + 1;

                    MainView.Instance.LogMainWindow("Price 1: " + aPrices[0] + " Price 2: " + aPrices[1]);
                    MainView.Instance.LogMainWindow(
                        "Factor Price 1: " + Math.Round(aPrices[0] * factor + shippingAddition, 2)
                        + " Factor Price 2: " + Math.Round(aPrices[1] * factor + shippingAddition, 2));

                    //X% under others
                    if (
                        (aPrices[0] * factor + shippingAddition < aPrices[1]) &&
                        (aPrices[0] * factor + shippingAddition < aPrices[2])
                        )
                    {
                        double fTrendprice = 100000; // fictive price

                        if (checkTrend)
                        {
                            //check Trend Price
                            try
                            {
                                var doc3 = MKMInteract.RequestHelper.makeRequest(
                                    "https://api.cardmarket.com/ws/v2.0/products/" + idProduct, "GET");

                                fTrendprice =
                                    Convert.ToDouble(doc3.GetElementsByTagName("TREND")[0].InnerText.Replace(".", ","));

                                MainView.Instance.LogMainWindow("Trend: " + fTrendprice);
                            }
                            catch (Exception eError)
                            {
                                MKMHelpers.LogError("checking trend price for " + offer["product"]["locName"].InnerText, eError.Message, false);
                            }
                        }

                        //only relevant if we search domestic
                        if (domesticCheck.Checked)
                        {
                            // is best price international (+/-5%)?
                            if (!(aPrices[0] * 0.95 <= bestPriceInternational))
                            {
                                break;
                            }
                        }

                        // X% under TREND
                        if (aPrices[0] * factor < fTrendprice)
                        {
                            MainView.Instance.LogMainWindow("Found cheap offer, ID " + bestPriceArticle);
                            try
                            {
                                var sRequestXML = MKMInteract.RequestHelper.addCartBody(bestPriceArticle);

                                sRequestXML = MKMInteract.RequestHelper.getRequestBody(sRequestXML);

                                MKMInteract.RequestHelper.makeRequest("https://api.cardmarket.com/ws/v2.0/shoppingcart",
                                                                      "PUT", sRequestXML);
                            }
                            catch (Exception eError)
                            {
                                MKMHelpers.LogError("adding article " + offer["product"]["locName"].InnerText + " to cart", eError.Message, false);
                            }
                        }
                    }

                    break;
                }
            }
        }
示例#26
0
        /// <summary>
        /// For actually performing the check for cheap deals from a given user, expected to be run in its separate thread.
        /// </summary>
        /// <param name="selectedExpansionID">Leave as empty string if all expansion should be checked.</param>
        private void checkUserRun(string user, string isFoil, string isSigned, string isAltered, string isPlayset, string minCondition,
                                  bool domesticOnly, double maxPrice, double shippingAddition, double percentBelowOthers, bool checkTrend,
                                  System.Collections.Generic.List <string> selectedLanguage, string selectedExpansionID = "")
        {
            MainView.Instance.LogMainWindow("Check for cheap deals from seller '" + user + "'...");
            if (domesticOnly)
            {
                MainView.Instance.LogMainWindow("WARNING - domestics only is checked, if the specified seller is from a foreign country, no deals will be found.");
            }
            // Go through the stock of a specified user, checks for cheap deals and add them to the cart.
            int start = 0;

            while (true)
            {
                String      sUrl = "https://api.cardmarket.com/ws/v2.0/users/" + user + "/articles?start=" + start + "&maxResults=1000";
                XmlDocument doc2 = null;
                try
                {
                    // get the users stock, filtered by the selected parameters
                    doc2 = MKMInteract.RequestHelper.makeRequest(sUrl, "GET");
                }
                catch (Exception eError)
                {
                    MKMHelpers.LogError("looking for cheap deals from user " + user, eError.Message, false, sUrl);
                    break;
                }

                var node2 = doc2.GetElementsByTagName("article");
                foreach (XmlNode article in node2)
                {
                    if (selectedExpansionID != "") // if we want only cards from a specified set, check if this product is from that set using local database
                    {
                        DataRow card = MKMDbManager.Instance.GetSingleCard(article[MKMDbManager.InventoryFields.ProductID].InnerText);

                        if (card == null || card.Field <string>(MKMDbManager.InventoryFields.ExpansionID) != selectedExpansionID) // compare
                        {
                            continue;
                        }
                    }

                    if ( // do as much filtering here as possible to reduce the number of API calls
                        MKMHelpers.IsBetterOrSameCondition(article["condition"].InnerText, minCondition) &&
                        (!foilBox.Checked || article["isFoil"].InnerText == "true") &&
                        (!playsetBox.Checked || article["isPlayset"].InnerText == "true") &&
                        (selectedLanguage[0] == "" || article["language"]["idLanguage"].InnerText == selectedLanguage[0]) &&
                        (!signedBox.Checked || article["isSigned"].InnerText == "true") &&
                        (!signedBox.Checked || article["isAltered"].InnerText == "true") &&
                        (maxPrice >= Convert.ToDouble(article["price"].InnerText, CultureInfo.InvariantCulture))
                        )
                    {
                        MainView.Instance.LogMainWindow("Checking product ID: " + article["idProduct"].InnerText);
                        checkArticle(article["idProduct"].InnerText,
                                     selectedLanguage, minCondition, isFoil, isSigned,
                                     isAltered, isPlayset, article["idArticle"].InnerText, maxPrice, shippingAddition, percentBelowOthers, checkTrend);
                    }
                }
                if (node2.Count != 1000) // there is no additional items to fetch
                {
                    break;
                }
                start += 1000;
            }
            MainView.Instance.LogMainWindow("Check finished.");
        }
        /// <summary>
        /// Checks the expected ROI of a given display. Expected to be run in a separate thread
        /// </summary>
        private void checkDisplayPrice_run(float fMythicFactor, float fPackUncommon, float fPackRareMythic, float fRareCardsNotinPacks,
                                           float fMythicCardsNotinPacks, float fUncommonCardsNotinPacks, float fBoxContent, string editionID)
        {
            try
            {
                //used to determine index of best start edition
                //MessageBox.Show((editionBox.SelectedIndex.ToString()));

                var doc = MKMInteract.RequestHelper.getExpansionsSingles(editionID);
                //would be easier if mkm would deliver detailed info with this call but ...

                MainView.Instance.LogMainWindow("====== Expansion Stats ======");

                //Multiplier
                float fCardsInSet = doc.SelectNodes("response/single").Count;
                MainView.Instance.LogMainWindow("Cards in set: " + fCardsInSet);


                var xRares    = doc.SelectNodes("response/single/rarity[. = \"Rare\"]");
                var xMythic   = doc.SelectNodes("response/single/rarity[. = \"Mythic\"]");
                var xUncommon = doc.SelectNodes("response/single/rarity[. = \"Uncommon\"]");

                var iCountRares     = xRares.Count - fRareCardsNotinPacks;        //53F;
                var iCountMythics   = xMythic.Count - fMythicCardsNotinPacks;     //15F;
                var iCountUncommons = xUncommon.Count - fUncommonCardsNotinPacks; //80F;

                MainView.Instance.LogMainWindow("Rares in set: " + iCountRares);
                MainView.Instance.LogMainWindow("Mythic in set: " + iCountMythics);
                MainView.Instance.LogMainWindow("Uncommon in set: " + iCountUncommons);

                //factors per booster
                var fFactorUncommon           = fPackUncommon / iCountUncommons;                 //0,0375
                var fFactorMythicRareCombined = fPackRareMythic / (iCountRares + iCountMythics); // 0,014
                var fFactorMythic             = fFactorMythicRareCombined / fMythicFactor;       //chance is 1:8 fpr Mythic
                var fFactorRare = fFactorMythicRareCombined / fMythicFactor * (fMythicFactor - 1);

                MainView.Instance.LogMainWindow("====== Calculated Booster Factors ======");
                MainView.Instance.LogMainWindow("Uncommon: " + fFactorUncommon);
                MainView.Instance.LogMainWindow("MR Combo: " + fFactorMythicRareCombined);
                MainView.Instance.LogMainWindow("Rare:" + fFactorRare);
                MainView.Instance.LogMainWindow("Mythic:" + fFactorMythic);

                var fFactorUncommonBox           = fFactorUncommon * fBoxContent;
                var fFactorMythicRareCombinedBox = fFactorMythicRareCombined * fBoxContent;
                var fFactorMythicBox             = fFactorMythic * fBoxContent;
                var fFactorRareBox = fFactorRare * fBoxContent;

                MainView.Instance.LogMainWindow("====== Calculated Box Factors ======");
                MainView.Instance.LogMainWindow("Uncommon: " + fFactorUncommonBox);
                MainView.Instance.LogMainWindow("MR Combo: " + fFactorMythicRareCombinedBox);
                MainView.Instance.LogMainWindow("Rare:" + fFactorRareBox);
                MainView.Instance.LogMainWindow("Mythic:" + fFactorMythicBox);

                xRares = doc.SelectNodes("response/single");

                float fBoxValue = 0;

                foreach (XmlNode xn in xRares)
                {
                    if (xn["rarity"].InnerText == "Rare")
                    {
                        MainView.Instance.LogMainWindow("Checking (R): " + xn["enName"].InnerText);

                        var doc2 =
                            MKMInteract.RequestHelper.makeRequest(
                                "https://api.cardmarket.com/ws/v2.0/products/" + xn["idProduct"].InnerText, "GET");

                        if (doc2.HasChildNodes)
                        {
                            var fCardPrice =
                                (float)Convert.ToDouble(
                                    doc2.SelectSingleNode("response/product/priceGuide/SELL").InnerText, CultureInfo.InvariantCulture);

                            MainView.Instance.LogMainWindow("Current SELL Price: " + fCardPrice);

                            fBoxValue += fCardPrice * fFactorMythicRareCombinedBox;
                            //changed cause it's actually a rare + Mythic not rare or mythic I think?  was fFactorRareBox;
                        }
                    }

                    if (xn["rarity"].InnerText == "Mythic")
                    {
                        MainView.Instance.LogMainWindow("Checking (M): " + xn["enName"].InnerText);

                        var doc2 =
                            MKMInteract.RequestHelper.makeRequest(
                                "https://api.cardmarket.com/ws/v2.0/products/" + xn["idProduct"].InnerText, "GET");

                        if (doc2.HasChildNodes)
                        {
                            var fCardPrice =
                                (float)Convert.ToDouble(
                                    doc2.SelectSingleNode("response/product/priceGuide/SELL").InnerText, CultureInfo.InvariantCulture);
                            MainView.Instance.LogMainWindow("Current SELL Price: " + fCardPrice);

                            fBoxValue += fCardPrice * fFactorMythicBox;
                        }
                    }

                    if (xn["rarity"].InnerText == "Uncommon")
                    {
                        MainView.Instance.LogMainWindow("Checking (U): " + xn["enName"].InnerText);

                        var doc2 =
                            MKMInteract.RequestHelper.makeRequest(
                                "https://api.cardmarket.com/ws/v2.0/products/" + xn["idProduct"].InnerText, "GET");

                        if (doc2.HasChildNodes)
                        {
                            var fCardPrice =
                                (float)Convert.ToDouble(
                                    doc2.SelectSingleNode("response/product/priceGuide/SELL").InnerText, CultureInfo.InvariantCulture);

                            MainView.Instance.LogMainWindow("Current SELL Price: " + fCardPrice);

                            fBoxValue += fCardPrice * fFactorUncommonBox;
                        }
                    }
                }
                MainView.Instance.LogMainWindow("Calculated Result *: " + fBoxValue);

                MainView.Instance.LogMainWindow(
                    "* Estimated average booster box singles value at MKM SELL Pricing (EUR)\n");
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("checking display prices", eError.Message, true);
            }
        }
示例#28
0
        /// <summary>
        /// For actually performing the check for cheap deals from wantlist, expected to be run in its separate thread
        /// </summary>
        private void checkListRun(string listID, double maxAllowedPrice, double shippingAdd, double percentBelow, bool checkTrend)
        {
            XmlDocument doc = null;

            try
            {
                doc = MKMInteract.RequestHelper.getWantsListByID(listID);
            }
            catch (Exception eError)
            {
                MKMHelpers.LogError("checking wantlist ID " + listID, eError.Message, true);
                return;
            }

            MainView.Instance.LogMainWindow("Starting to check your wantlist ID:" + listID + " ...");
            var node = doc.GetElementsByTagName("item");

            foreach (XmlNode article in node)
            {
                // articles in a wantlist can be either product or metaproducts (the same card from multiple sets)
                // each metaproduct needs to be expanded into a list of products that are "realized" by it
                System.Collections.Generic.List <XmlNode> products = new System.Collections.Generic.List <XmlNode>();
                if (article["type"].InnerText == "product")
                {
                    products.Add(article["product"]);
                }
                else // it is a metaproduct
                {
                    try
                    {
                        XmlDocument metaDoc   = MKMInteract.RequestHelper.getMetaproduct(article["metaproduct"]["idMetaproduct"].InnerText);
                        XmlNodeList mProducts = metaDoc.GetElementsByTagName("product");
                        foreach (XmlNode prod in mProducts)
                        {
                            products.Add(prod);
                        }
                    }
                    catch (Exception eError)
                    {
                        MKMHelpers.LogError("checking wantlist metaproduct ID " + article["metaproduct"]["idMetaproduct"], eError.Message, false);
                        continue;
                    }
                }
                foreach (XmlNode product in products)
                {
                    // As of 25.6.2019, the countArticles and countFoils fields are not described in MKM documentation, but they seem to be there.
                    // I think this is indeed a new thing that appeared since MKM started to force promo-sets as foils only
                    // We can use this to prune lot of useless calls that will end up in empty responses from searching for non foils in promo (foil only) sets
                    int total = int.Parse(product["countArticles"].InnerText);
                    int foils = int.Parse(product["countFoils"].InnerText);
                    if ((article["isFoil"].InnerText == "true" && foils == 0) ||    // there are only non-foils of this article and we want foils
                        (article["isFoil"].InnerText == "false" && foils == total)) // there are only foils and we want non-foil
                    {
                        continue;
                    }

                    MainView.Instance.LogMainWindow("checking:" + product["enName"].InnerText + " from " + product["expansionName"].InnerText + "...");

                    // a wantlist item can have more idLanguage entries, one for each wanted language
                    System.Collections.Generic.List <string> selectedLanguages = new System.Collections.Generic.List <string>();
                    foreach (XmlNode langNodes in product.ChildNodes)
                    {
                        if (langNodes.Name == "idLanguage")
                        {
                            selectedLanguages.Add(langNodes.InnerText);
                        }
                    }
                    checkArticle(product["idProduct"].InnerText, selectedLanguages, article["minCondition"].InnerText,
                                 article["isFoil"].InnerText, article["isSigned"].InnerText, article["isAltered"].InnerText,
                                 // isPlayset seems to no longer be part of the API, instead there is a count of how many times is the card wanted, let's use it
                                 int.Parse(article["count"].InnerText) == 4 ? "true" : "false",
                                 "", maxAllowedPrice, shippingAdd, percentBelow, checkTrend);
                }
            }
            MainView.Instance.LogMainWindow("Check finished.");
        }
示例#29
0
        // reload data each time the form is made visible in case the user's stock has changed so they can reload the stockview this way
        private void StockView_VisibleChanged(object sender, EventArgs e)
        {
            if (Visible)
            {
                int start    = 1;
                var articles = new DataTable();
                try
                {
                    while (true)
                    {
                        var doc = MKMInteract.RequestHelper.readStock(start);
                        if (doc.HasChildNodes)
                        {
                            var result       = doc.GetElementsByTagName("article");
                            int elementCount = 0;
                            foreach (XmlNode article in result)
                            {
                                if (article["condition"] != null) // is null for articles that are not cards (boosters etc.) - don't process those
                                {
                                    MKMMetaCard m = new MKMMetaCard(article);
                                    m.WriteItselfIntoTable(articles, true, MCFormat.MKM);
                                    elementCount++;
                                }
                            }
                            if (elementCount != 100)
                            {
                                break;
                            }
                            start += elementCount;
                        }
                        else
                        {
                            break;  // document is empty -> end*/
                        }
                    }

                    // Remove columns we don't want showing
                    // TODO - what is and isn't shown should probably be customizable and left to the user to choose in some way
                    articles.Columns.Remove(MCAttribute.ArticleID);
                    articles.Columns.Remove(MCAttribute.ProductID);
                    articles.Columns.Remove(MCAttribute.LanguageID);
                    articles.Columns.Remove(MCAttribute.CardNumber);

                    var dj = MKMDbManager.JoinDataTables(articles, MKMDbManager.Instance.Expansions,
                                                         (row1, row2) => row1.Field <string>(MKMDbManager.InventoryFields.ExpansionID) == row2.Field <string>(MKMDbManager.ExpansionsFields.ExpansionID));

                    dj.Columns.Remove(MCAttribute.ExpansionID);                   // duplicated
                    dj.Columns.Remove(MKMDbManager.ExpansionsFields.ExpansionID); // ...and we don't want it anyway
                    dj.Columns.Remove(MKMDbManager.ExpansionsFields.Name);        // duplicated

                    dj.Columns[dj.Columns.IndexOf(MCAttribute.Name)].SetOrdinal(0);
                    dj.Columns[dj.Columns.IndexOf(MCAttribute.Expansion)].SetOrdinal(1);
                    dj.Columns[dj.Columns.IndexOf(MCAttribute.Language)].SetOrdinal(2);

                    stockGridView.DataSource = dj;

                    buttonExport.Enabled = true;
                }
                catch (Exception eError)
                {
                    MKMHelpers.LogError("listing stock in Stock View", eError.Message, true);
                }
            }
        }
        private void checkEditionButton_Click(object sender, EventArgs e)
        {
            checkEditionButton.Enabled = false;
            checkEditionButton.Text    = "Checking cheap deals...";
            var isFoil       = "";
            var isSigned     = "";
            var isAltered    = "";
            var isPlayset    = "";
            var minCondition = conditionCombo.Text;

            if (foilBox.Checked)
            {
                isFoil = "true";
            }

            if (signedBox.Checked)
            {
                isSigned = "true";
            }

            if (alteredBox.Checked)
            {
                isAltered = "true";
            }

            if (playsetBox.Checked)
            {
                isPlayset = "true";
            }


            if (checkBoxUser.Enabled)
            {
                if (domnesticCheck.Checked)
                {
                    frm1.logBox.Invoke(new MainView.logboxAppendCallback(frm1.logBoxAppend),
                                       "WARNING - domestics only is checked, if the specified seller is from a foreign country, no deals will be found.\n");
                }
                // Go through the stock of a specified user, checks for cheap deals and add them to the cart.
                int    start           = 0;
                double maxAllowedPrice = Convert.ToDouble(maxPrice.Text);
                while (true)
                {
                    String sUrl = "https://api.cardmarket.com/ws/v2.0/users/" + textBoxUser.Text + "/articles?start=" + start + "&maxResults=1000";

                    try
                    {
                        // get the users stock, filtered by the selected parameters
                        var doc2 = MKMInteract.RequestHelper.makeRequest(sUrl, "GET");

                        var    node2    = doc2.GetElementsByTagName("article");
                        String language = (langCombo.SelectedItem as MKMHelpers.ComboboxItem).Value.ToString();
                        foreach (XmlNode article in node2)
                        {
                            if ( // do as much filtering here as possible to reduce the number of API calls
                                MKMHelpers.IsBetterOrSameCondition(article["condition"].InnerText, conditionCombo.Text) &&
                                (!foilBox.Checked || article["isFoil"].InnerText == "true") &&
                                (!playsetBox.Checked || article["isPlayset"].InnerText == "true") &&
                                (language == "" || article["language"]["idLanguage"].InnerText == language) &&
                                (!signedBox.Checked || article["isSigned"].InnerText == "true") &&
                                (!signedBox.Checked || article["isAltered"].InnerText == "true") &&
                                (maxAllowedPrice >= Convert.ToDouble(article["price"].InnerText, CultureInfo.InvariantCulture))
                                )
                            {
                                frm1.logBox.Invoke(new MainView.logboxAppendCallback(frm1.logBoxAppend),
                                                   "Checking: " + article["idProduct"].InnerText + "\n");
                                checkArticle(article["idProduct"].InnerText,
                                             language, minCondition, isFoil, isSigned,
                                             isAltered, isPlayset, article["idArticle"].InnerText);

                                frm1.logBox.Invoke(new MainView.logboxAppendCallback(frm1.logBoxAppend), "Done.\n");
                            }
                        }
                        if (node2.Count != 1000) // there is no additional items to fetch
                        {
                            break;
                        }
                    }
                    catch (Exception eError)
                    {
                        frm1.logBox.Invoke(new MainView.logboxAppendCallback(frm1.logBoxAppend),
                                           "ERR Msg : " + eError.Message + "\n");
                        frm1.logBox.Invoke(new MainView.logboxAppendCallback(frm1.logBoxAppend), "ERR URL : " + sUrl + "\n");

                        using (var sw = File.AppendText(@".\\error_log.txt"))
                        {
                            sw.WriteLine("ERR Msg : " + eError.Message);
                            sw.WriteLine("ERR URL : " + sUrl);
                        }
                    }
                    start += 1000;
                }
            }
            else
            {
                var sEdId = editionBox.SelectedItem.ToString();

                var sT = dt.Clone();

                var result = dt.Select(string.Format("[Expansion ID] = '{0}'", sEdId));

                foreach (var row in result)
                {
                    sT.ImportRow(row);
                }

                foreach (DataRow oRecord in sT.Rows)
                {
                    frm1.logBox.Invoke(new MainView.logboxAppendCallback(frm1.logBoxAppend),
                                       "Checking: " + oRecord["idProduct"] + "\n");
                    checkArticle(oRecord["idProduct"].ToString(),
                                 (langCombo.SelectedItem as MKMHelpers.ComboboxItem).Value.ToString(), minCondition, isFoil, isSigned,
                                 isAltered, isPlayset, "");

                    frm1.logBox.Invoke(new MainView.logboxAppendCallback(frm1.logBoxAppend), "Done.\n");
                }
            }

            checkEditionButton.Text    = "Check now";
            checkEditionButton.Enabled = true;
        }