예제 #1
0
            /// Generates a XML entry for PUT STOCK for a given article.
            /// <param name="card">The card. Must have idArticle, price, idLanguage, count and condition set.</param>
            /// <param name="sNewPrice">The new price to set.</param>
            /// <returns>The body of the API request.</returns>
            public static string ChangeStockArticleBody(MKMMetaCard card, string sNewPrice)
            {
                var XMLContent = "<article>" +
                                 "<idArticle>" + card.GetAttribute(MCAttribute.ArticleID) + "</idArticle>" +
                                 "<price>" + sNewPrice + "</price>" +
                                 "<idLanguage>" + card.GetAttribute(MCAttribute.LanguageID) + "</idLanguage>" +
                                 new XElement("comments", card.GetAttribute(MCAttribute.Comments)) + // to escape special characters (&, <, > etc.)
                                 "<count>" + card.GetAttribute(MCAttribute.Count) + "</count>" +
                                 "<condition>" + card.GetAttribute(MCAttribute.Condition) + "</condition>" +
                                 "</article>";

                return(XMLContent);
            }
예제 #2
0
            /// Generates a XML entry for POST STOCK for a given article, i.e. uploading a new article to stock.
            /// <param name="card">The card. Must have idProduct, MKMPrice, LanguageID, Count and Condition set.</param>
            /// <param name="sNewPrice">The new price to set.</param>
            /// <returns>The body of the API request.</returns>
            public static string PostStockArticleBody(MKMMetaCard card)
            {
                string isFoil     = card.GetAttribute(MCAttribute.Foil);
                string isSigned   = card.GetAttribute(MCAttribute.Signed);
                string isPlayset  = card.GetAttribute(MCAttribute.Playset);
                string isAltered  = card.GetAttribute(MCAttribute.Altered);
                var    XMLContent = "<article>" +
                                    "<idProduct>" + card.GetAttribute(MCAttribute.ProductID) + "</idProduct>" +
                                    "<idLanguage>" + card.GetAttribute(MCAttribute.LanguageID) + "</idLanguage>" +
                                    new XElement("comments", card.GetAttribute(MCAttribute.Comments)) + // to escape special characters (&, <, > etc.)
                                    "<count>" + card.GetAttribute(MCAttribute.Count) + "</count>" +
                                    "<price>" + card.GetAttribute(MCAttribute.MKMPrice) + "</price>" +
                                    "<condition>" + card.GetAttribute(MCAttribute.Condition) + "</condition>" +
                                    (isFoil == "" ? "" : ("<isFoil>" + isFoil + "</isFoil>")) +
                                    (isSigned == "" ? "" : ("<isSigned>" + isSigned + "</isSigned>")) +
                                    (isPlayset == "" ? "" : ("<isPlayset>" + isPlayset + "</isPlayset>")) +
                                    (isAltered == "" ? "" : ("<isAltered>" + isAltered + "</isAltered>")) +
                                    "</article>";

                return(XMLContent);
            }
예제 #3
0
        /// <summary>
        /// Determines whether the specified other card has the minimum required condition by this card (attribute MinCondition).
        /// </summary>
        /// <param name="otherCard">The other card.</param>
        /// <returns>
        ///   <c>True</c> if the specified other card has Condition at least == this.MinCondition,
        ///   <c>False</c> if it does not and <c>Any</c> if either Condition is not assigned for the other card or MinCondition is not assigned for this card.
        /// </returns>
        public Bool3 IsOfMinCondition(MKMMetaCard otherCard)
        {
            string minC = GetAttribute(MCAttribute.MinCondition);

            if (minC != "")
            {
                string otherC = otherCard.GetAttribute(MCAttribute.Condition);
                if (otherC != "")
                {
                    bool res = IsBetterOrSameCondition(otherC, minC);
                    return(res ? Bool3.True : Bool3.False);
                }
            }
            return(Bool3.Any);
        }
예제 #4
0
        /// <summary>
        /// Imports and processes the input CSV file, i.e. fills the internal MetaCard hash tables and fetches product info from MKM if necessary.
        /// Intended to run in a separate thread.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        private void importRun(string filePath, string defaultFoil, string defaultPlayset, string defaultSigned, string defaultAltered,
                               string defaultCondition, string defaultExpansion, string defaultLanguageID)
        {
            DataTable dt;

            try
            {
                dt = MKMCsvUtils.ConvertCSVtoDataTable(filePath);
            }
            catch (Exception eError)
            {
                LogError("importing file " + filePath, eError.Message, true);
                return;
            }
            importedColumns = dt.Columns;
            MainView.Instance.LogMainWindow("Loaded file with " + dt.Rows.Count + " articles, processing...");

            importedAll.Clear();
            importedValidOnly.Clear();
            int counter = 0, failed = 0, hasPriceGuide = 0;
            // if we search for products based on their locName, we have to make a product query for each of them - store the result to reuse in case there are more of those cards later in the list
            Dictionary <string, string> locNameProducts = new Dictionary <string, string>();

            foreach (DataRow row in dt.Rows)
            {
                MKMMetaCard mc = new MKMMetaCard(row);
                importedAll.Add(mc); // add it no matter if it can be correctly processed or not so that we can export it
                counter++;
                string productID  = mc.GetAttribute(MCAttribute.ProductID);
                string name       = mc.GetAttribute(MCAttribute.Name);
                string languageID = mc.GetAttribute(MCAttribute.LanguageID);
                if (languageID == "" && defaultLanguageID != "")
                {
                    languageID = defaultLanguageID;
                    mc.SetLanguageID(languageID);
                }
                if (name == "" && productID == "") // we have neither name or productID - we have to hope we have locName and language
                {
                    string locName = mc.GetAttribute(MCAttribute.LocName).ToLower();
                    if (locName == "" || languageID == "")
                    {
                        LogError("importing line #" + (counter + 1) + ", article will be ignored",
                                 "Neither product ID, English name, or localized name + language was found, cannot identify the card.", false);
                        failed++;
                        continue;
                    }
                    // have to use search on MKM to get the English name
                    string hash = "" + locName + languageID;          // technically it is unlikely that two different languages would have the same name, but could happen
                    if (!locNameProducts.TryGetValue(hash, out name)) // we haven't had a product like this in the list yet, use MKM API to find it
                    {
                        int            start = 0;
                        List <XmlNode> found = new List <XmlNode>();
                        try
                        {
                            XmlNodeList products;
                            do
                            {
                                XmlDocument doc = MKMInteract.RequestHelper.findProducts(locName, languageID, start);
                                products = doc.GetElementsByTagName("product");
                                // we still want to insert empty string in the hash table - this way we know in the future that this name is invalid
                                locNameProducts[hash] = "";
                                foreach (XmlNode product in products)
                                {
                                    // only take exact matches, otherwise we get all kinds of garbage like sleeves etc. that use the name of the card
                                    if (product["locName"].InnerText.ToLower() == locName)
                                    {
                                        found.Add(product);
                                    }
                                }
                                start += products.Count;
                            } while (products.Count == 100);
                        }
                        catch (Exception eError)
                        {
                            LogError("importing line #" + (counter + 1) + ", trying to find product by its localized name "
                                     + locName + ", article will be ignored", eError.Message, false);
                            failed++;
                            continue;
                        }
                        if (found.Count < 1)
                        {
                            LogError("importing line #" + (counter + 1) + ", trying to find product by its localized name "
                                     + locName + ", article will be ignored", "No article called " + locName + " in "
                                     + mc.GetAttribute(MCAttribute.Language) + " language found on MKM.", false);
                            failed++;
                            continue;
                        }
                        locNameProducts[hash] = name = found[0]["enName"].InnerText;
                        mc.SetAttribute(MCAttribute.Name, name);
                    }
                    else if (name != "")
                    {
                        mc.SetAttribute(MCAttribute.Name, name);
                    }
                    else
                    {
                        LogError("importing line #" + (counter + 1) + ", trying to find product by its localized name "
                                 + locName + ", article will be ignored", "" + locName + " is not a valid name", false);
                        failed++;
                        continue;
                    }
                }
                // process foil and condition now as it can be useful in determining expansion
                string temp = mc.GetAttribute(MCAttribute.Foil);
                Bool3  isFoil;
                if (temp == "")
                {
                    mc.SetBoolAttribute(MCAttribute.Foil, defaultFoil);
                    isFoil = ParseBool3(mc.GetAttribute(MCAttribute.Foil));
                }
                else
                {
                    isFoil = ParseBool3(temp);
                }

                string condition = mc.GetAttribute(MCAttribute.Condition);
                if (condition == "")
                {
                    condition = defaultCondition;
                    mc.SetCondition(condition);
                }

                if (productID == "")                                         // we now know we have the name, but we have to find out which expansion it is from to get the productID
                {
                    string expID = mc.GetAttribute(MCAttribute.ExpansionID); // if the Expansion would be set, ExpansionID would be set as well in constructor of MKMMetaCard
                    if (expID == "")                                         // we have to determine the expansion
                    {
                        var all = MKMDbManager.Instance.GetCardByName(name);
                        // options are: Latest, Oldest, Cheapest, Median Price, Most Expensive
                        if (all.GetEnumerator().MoveNext())
                        {
                            // used for prices based on price guide (cheapest, median, most expensive):
                            // for non-foil, compare the LOWEX+ for EX+ items, LOW for worse conditions, for foil compare the LOWFOIL, for "any foil" compare SELL
                            string priceGuidePrice;
                            if (isFoil == Bool3.True)
                            {
                                priceGuidePrice = "LOWFOIL";
                            }
                            else if (isFoil == Bool3.Any)
                            {
                                priceGuidePrice = "SELL";
                            }
                            else
                            {
                                if (IsBetterOrSameCondition(condition, "EX"))
                                {
                                    priceGuidePrice = "LOWEX+";
                                }
                                else
                                {
                                    priceGuidePrice = "LOW";
                                }
                            }
                            switch (defaultExpansion)
                            {
                            // for latest and oldest, we can just check local database
                            case "Latest":
                                DateTime latestTime = new DateTime(0);
                                foreach (DataRow dr in all)
                                {
                                    string tempExpID   = dr[MKMDbManager.InventoryFields.ExpansionID].ToString();
                                    string releaseDate = MKMDbManager.Instance.GetExpansionByID(
                                        tempExpID)[MKMDbManager.ExpansionsFields.ReleaseDate].ToString();
                                    DateTime rel = DateTime.Parse(releaseDate, CultureInfo.InvariantCulture);
                                    if (latestTime < rel)
                                    {
                                        latestTime = rel;
                                        expID      = tempExpID;
                                    }
                                }
                                mc.SetAttribute(MCAttribute.ExpansionID, expID);
                                mc.SetAttribute(MCAttribute.Expansion,
                                                MKMDbManager.Instance.GetExpansionByID(expID)[MKMDbManager.ExpansionsFields.Name].ToString());
                                break;

                            case "Oldest":
                                DateTime oldestTime = DateTime.Now;
                                foreach (DataRow dr in all)
                                {
                                    string tempExpID   = dr[MKMDbManager.InventoryFields.ExpansionID].ToString();
                                    string releaseDate = MKMDbManager.Instance.GetExpansionByID(
                                        tempExpID)[MKMDbManager.ExpansionsFields.ReleaseDate].ToString();
                                    DateTime rel = DateTime.Parse(releaseDate, CultureInfo.InvariantCulture);
                                    if (oldestTime > rel)
                                    {
                                        latestTime = rel;
                                        expID      = tempExpID;
                                    }
                                }
                                mc.SetAttribute(MCAttribute.ExpansionID, expID);
                                mc.SetAttribute(MCAttribute.Expansion,
                                                MKMDbManager.Instance.GetExpansionByID(expID)[MKMDbManager.ExpansionsFields.Name].ToString());
                                break;

                            // for the others we have to do product queries for each possibility
                            case "Cheapest":
                                XmlNode cheapestProduct = null;     // we know all has at least one item so this will either get assigned or an exception is thrown and caught inside the foreach cycle
                                double  cheapestPrice   = double.MaxValue;
                                foreach (DataRow dr in all)
                                {
                                    try
                                    {
                                        // there should always be exactly one product in the list
                                        XmlNode product = MKMInteract.RequestHelper.getProduct(
                                            dr[MKMDbManager.InventoryFields.ProductID].ToString()).GetElementsByTagName("product")[0];
                                        double price = double.Parse(product["priceGuide"][priceGuidePrice].InnerText);
                                        if (price < cheapestPrice)
                                        {
                                            cheapestPrice   = price;
                                            cheapestProduct = product;
                                        }
                                    }
                                    catch (Exception eError)
                                    {
                                        LogError("importing line #" + (counter + 1) + ", could not identify cheapest expansion for " + name + ", article will be ignored",
                                                 eError.Message, false);
                                        failed++;
                                        continue;
                                    }
                                }
                                mc.FillProductInfo(cheapestProduct);
                                hasPriceGuide++;
                                break;

                            case "Median Price":
                                SortedList <double, XmlNode> prices = new SortedList <double, XmlNode>();
                                foreach (DataRow dr in all)
                                {
                                    try
                                    {
                                        // there should always be exactly one product in the list
                                        XmlNode product = MKMInteract.RequestHelper.getProduct(
                                            dr[MKMDbManager.InventoryFields.ProductID].ToString()).GetElementsByTagName("product")[0];
                                        double price = double.Parse(product["priceGuide"][priceGuidePrice].InnerText);
                                        prices.Add(price, product);
                                    }
                                    catch (Exception eError)
                                    {
                                        LogError("importing line #" + (counter + 1) + ", could not identify median price expansion for " + name + ", article will be ignored",
                                                 eError.Message, false);
                                        failed++;
                                        continue;
                                    }
                                }
                                mc.FillProductInfo(prices.Values[prices.Count / 2]);
                                hasPriceGuide++;
                                break;

                            case "Most Expensive":
                                XmlNode mostExpProduct = null;     // we know all has at least one item so this will either get assigned or an exception is thrown and caught inside the foreach cycle
                                double  highestPrice   = double.MinValue;
                                foreach (DataRow dr in all)
                                {
                                    try
                                    {
                                        // there should always be exactly one product in the list
                                        XmlNode product = MKMInteract.RequestHelper.getProduct(
                                            dr[MKMDbManager.InventoryFields.ProductID].ToString()).GetElementsByTagName("product")[0];
                                        double price = double.Parse(product["priceGuide"][priceGuidePrice].InnerText);
                                        if (price > highestPrice)
                                        {
                                            highestPrice   = price;
                                            mostExpProduct = product;
                                        }
                                    }
                                    catch (Exception eError)
                                    {
                                        LogError("importing line #" + (counter + 1) + ", could not identify cheapest expansion for " + name + ", article will be ignored",
                                                 eError.Message, false);
                                        failed++;
                                        continue;
                                    }
                                }
                                mc.FillProductInfo(mostExpProduct);
                                hasPriceGuide++;
                                break;
                            }
                        }
                        else
                        {
                            LogError("importing line #" + (counter + 1) + ", identifying expansion for " + name + ", article will be ignored",
                                     "No card with this name found.", false);
                            failed++;
                            continue;
                        }
                        // TODO - determine whether the expansion is foil only / cannot be foil and based on the isFoil flag of the current article choose the correct set
                    }
                    // now we have expID and English name -> we can determine the product ID
                    string[] ids = MKMDbManager.Instance.GetCardProductID(name, mc.GetAttribute(MCAttribute.ExpansionID));
                    if (ids.Length == 0)
                    {
                        LogError("importing line #" + (counter + 1) + ", article will be ignored",
                                 "The specified " + name + " and expansion ID " + expID + " do not match - product cannot be identified.", false);
                        failed++;
                        continue;
                    }
                    else if (ids.Length > 1)
                    {
                        string cardNumber = mc.GetAttribute(MCAttribute.CardNumber);
                        if (cardNumber == "")
                        {
                            LogError("importing line #" + (counter + 1) + ", article will be ignored", "The specified " + name +
                                     " and expansion ID " + expID + " match multiple products - please provide Card Number to identify which one it is.", false);
                            failed++;
                            continue;
                        }
                        // search for the matching item
                        int start = 0;
                        try
                        {
                            XmlNodeList products;
                            do
                            {
                                XmlDocument doc = MKMInteract.RequestHelper.findProducts(name, "1", start);
                                products = doc.GetElementsByTagName("product");
                                string expansion = mc.GetAttribute(MCAttribute.Expansion);
                                foreach (XmlNode product in products)
                                {
                                    if (product["number"].InnerText == cardNumber && product["expansionName"].InnerText == expansion)
                                    {
                                        productID = product["idProduct"].InnerText;
                                        // since we already have it, why not fill the product info in the MetaCard
                                        mc.FillProductInfo(product);
                                        break;
                                    }
                                }
                                start += products.Count;
                            } while (products.Count == 100 && productID == "");
                        }
                        catch (Exception eError)
                        {
                            LogError("importing line #" + (counter + 1) + ", trying to find product ID for "
                                     + name + " based on its card number and expansion, article will be ignored", eError.Message, false);
                            failed++;
                            continue;
                        }
                        if (productID == "")
                        {
                            LogError("importing line #" + (counter + 1) + ", article will be ignored", "The specified " + name +
                                     " and expansion ID " + expID
                                     + " match multiple products, Card Number was used to find the correct article, but no match was found, verify the data is correct.", false);
                            failed++;
                            continue;
                        }
                    }
                    else
                    {
                        productID = ids[0];
                    }
                    mc.SetAttribute(MCAttribute.ProductID, productID);
                }

                // if the defaults are "Any", there is not point in checking whether that attribute has been set or not
                if (defaultPlayset != "")
                {
                    temp = mc.GetAttribute(MCAttribute.Playset);
                    if (temp == "")
                    {
                        mc.SetBoolAttribute(MCAttribute.Playset, defaultPlayset);
                    }
                }
                if (defaultSigned != "")
                {
                    temp = mc.GetAttribute(MCAttribute.Signed);
                    if (temp == "")
                    {
                        mc.SetBoolAttribute(MCAttribute.Signed, defaultSigned);
                    }
                }
                if (defaultAltered != "")
                {
                    temp = mc.GetAttribute(MCAttribute.Altered);
                    if (temp == "")
                    {
                        mc.SetBoolAttribute(MCAttribute.Altered, defaultAltered);
                    }
                }
                // rarity might not be present in some cases, check it and get it from database, or worst case from MKM
                var rarity = mc.GetAttribute(MCAttribute.Rarity);
                if (rarity == "")
                {
                    var dataRow = MKMDbManager.Instance.GetSingleCard(productID);
                    rarity = dataRow[MKMDbManager.InventoryFields.Rarity].ToString();
                    if (rarity == "")
                    {
                        try
                        {
                            var productDoc = MKMInteract.RequestHelper.getProduct(productID);
                            rarity = productDoc["response"]["product"]["rarity"].InnerText;
                            dataRow[MKMDbManager.InventoryFields.Rarity] = rarity;
                        }
                        catch (Exception eError)
                        {
                            LogError("getting rarity for product " + productID, eError.Message, false);
                        }
                    }
                    mc.SetAttribute(MCAttribute.Rarity, rarity);
                }

                importedValidOnly.Add(mc);
                if (checkBoxImportLog.Checked)
                {
                    MainView.Instance.LogMainWindow("Imported line #" + (counter + 1) + ", " + name);
                }
            }

            MainView.Instance.LogMainWindow("Card list " + filePath + " imported. Successfully imported " + importedValidOnly.Count +
                                            " articles, failed to import: " + failed + ", articles that include MKM Price Guide: " + hasPriceGuide);
            if (hasPriceGuide > 0)
            {
                priceGuidesGenerated = true;
            }
        }
예제 #5
0
            /// Returns all single cards in our stock as meta cards. This is just a convenience wrapper on getStockFile/readStock.
            /// <param name="useFile">This is for legacy support. If set to false, it will use the old way of getting stock
            /// by the readStock method. New way is to use getStockFile as it takes only a single API request.</param>
            /// <returns>List of all single cards in our stock</returns>
            public static List <MKMMetaCard> GetAllStockSingles(bool useFile)
            {
                MainView.Instance.LogMainWindow("Fetching stock...");
                List <MKMMetaCard> cards = new List <MKMMetaCard>();

                if (useFile)
                {
                    foreach (var game in MainView.Instance.Config.Games)
                    {
                        byte[] stock = getStockFile(game.GameID);
                        if (stock != null && stock.Length > 0)
                        {
                            var articleTable = MKMCsvUtils.ConvertCSVtoDataTable(stock);
                            // the GET STOCK FILE has language ID named Language, fix that
                            articleTable.Columns["Language"].ColumnName = MCAttribute.LanguageID;
                            articleTable.Columns.Remove("Local Name"); // this is in the language of the request...which is always English
                            foreach (DataRow row in articleTable.Rows)
                            {
                                MKMMetaCard mc = new MKMMetaCard(row);
                                // according to the API documentation, "The 'condition' key is only returned for single cards. "
                                // -> check if condition exists to see if this is a single card or something else
                                if (mc.GetAttribute(MCAttribute.Condition) != "" && mc.GetAttribute(MCAttribute.ArticleID) != "")
                                {
                                    // sanitize the false booleans - the empty ones mean no, while in MKMMEtaCard empty means "any"
                                    if (articleTable.Columns.Contains("Foil?") && mc.GetAttribute(MCAttribute.Foil) == "")
                                    {
                                        mc.SetBoolAttribute(MCAttribute.Foil, "false");
                                    }
                                    if (articleTable.Columns.Contains("Altered?") && mc.GetAttribute(MCAttribute.Altered) == "")
                                    {
                                        mc.SetBoolAttribute(MCAttribute.Altered, "false");
                                    }
                                    if (articleTable.Columns.Contains("Signed?") && mc.GetAttribute(MCAttribute.Signed) == "")
                                    {
                                        mc.SetBoolAttribute(MCAttribute.Signed, "false");
                                    }
                                    if (articleTable.Columns.Contains("Playset?") && mc.GetAttribute(MCAttribute.Playset) == "")
                                    {
                                        mc.SetBoolAttribute(MCAttribute.Playset, "false");
                                    }
                                    // this is just a guess, not sure how isFirstEd is written there, or if at all
                                    if (articleTable.Columns.Contains("FirstEd?") && mc.GetAttribute(MCAttribute.FirstEd) == "")
                                    {
                                        mc.SetBoolAttribute(MCAttribute.FirstEd, "false");
                                    }
                                    cards.Add(mc);
                                }
                            }
                        }
                    }
                }
                else
                {
                    var         start = 1;
                    XmlNodeList result;
                    var         count = 0;
                    do
                    {
                        var doc = ReadStock(start);
                        if (doc.HasChildNodes)
                        {
                            result = doc.GetElementsByTagName("article");
                            foreach (XmlNode article in result)
                            {
                                // according to the API documentation, "The 'condition' key is only returned for single cards. "
                                // -> check if condition exists to see if this is a single card or something else
                                if (article["condition"] != null && article["idArticle"].InnerText != null)
                                {
                                    var card = new MKMMetaCard(article);
                                    cards.Add(card);
                                }
                            }
                            count  = result.Count;
                            start += count;
                        }
                    } while (count == 100);
                }
                MainView.Instance.LogMainWindow("Finished fetching stock.");
                return(cards);
            }