Example #1
0
    def add_stock(self, payload=None, provided_oauth=None):
        ## https://api.cardmarket.com/ws/documentation/API_2.0:Stock_Management
        url = f"{self.base_url}/stock"

        # idProduct
        # count
        # idLanguage
        # comments
        # price
        # condition
        # isFoil
        # isSigned
        # isAltered
        # isPlayset
        # isFirstEd

        # clean data because the API treats "False" as true, must be "false".
        for entry in payload:
            for key, value in entry.items():
                if isinstance(value, bool):
                    entry[key] = str.lower(str(value))

        mkm_oauth = self.__setup_auth_session(url, provided_oauth)

        self.logger.debug(">> Adding stock")
        chunked_list = list(self.__chunks(payload, 100))
        r = None
        for chunk in chunked_list:
            # chunk[0]["comments"] = "DO NOT BUY"  # HACK: temp comment for testing
            try:
                xml_payload = PyMkmHelper.dicttoxml(chunk)
                r = mkm_oauth.post(
                    url,
                    data=xml_payload,
                    timeout=self.config["cardmarket_request_timeout"],
                )
                mkm_oauth.close()
                inserted = r.json()
                if "error" in inserted:
                    raise CardmarketError(inserted["error"])
                else:
                    for item in inserted["inserted"]:
                        if not item["success"]:
                            raise CardmarketError(
                                f"{item['error']}: {item['tried']}"  # , url=r.request.url
                            )
                        else:
                            self.logger.debug(
                                f">> Added {item['idArticle']['product']['enName']}."
                            )

            except CardmarketError as err:
                self.logger.error(f"{err.mkm_msg()} {err.url}")
                # print(err.mkm_msg())
        # TODO: Only considers the last response.
        if self.__handle_response(r):
            return r.json()
Example #2
0
    def delete_stock(self, payload=None, provided_oauth=None):
        ## https://api.cardmarket.com/ws/documentation/API_2.0:Stock_Management
        url = f"{self.base_url}/stock"

        mkm_oauth = self.__setup_auth_session(url, provided_oauth)

        self.logger.debug(">> Deleting stock")
        chunked_list = list(self.__chunks(payload, 100))
        r = None
        for chunk in chunked_list:
            xml_payload = PyMkmHelper.dicttoxml(chunk)
            r = mkm_oauth.delete(url, data=xml_payload)

        # TODO: Only considers the last response.
        if self.__handle_response(r):
            return r.json()
Example #3
0
    def set_stock(self, payload=None, provided_oauth=None):
        ## https://api.cardmarket.com/ws/documentation/API_2.0:Stock_Management
        url = f"{self.base_url}/stock"

        allowed_items = [
            "idArticle",
            "idLanguage",
            "comments",
            "count",
            "price",
            "condition",
            "isFoil",
            "isSigned",
            "isPlayset",
        ]
        # clean data because the API treats "False" as true, must be "false".
        clean_payload = []
        for entry in payload:
            clean_entry = {
                k: v
                for k, v in entry.items() if k in allowed_items
            }

            for key, value in clean_entry.items():
                if isinstance(value, bool):
                    clean_entry[key] = str.lower(str(value))
            clean_payload.append(clean_entry)

        mkm_oauth = self.__setup_auth_session(url, provided_oauth)

        self.logger.debug(">> Updating stock")
        chunked_list = list(self.__chunks(clean_payload, 100))
        index = 0
        r = None
        for chunk in chunked_list:
            index += 1
            self.logger.debug(f"chunk {index}/{len(chunked_list)}")
            xml_payload = PyMkmHelper.dicttoxml(chunk)
            r = mkm_oauth.put(
                url,
                data=xml_payload,
                timeout=self.config["cardmarket_request_timeout"])
            mkm_oauth.close()
            try:
                json_response = r.json()
                if len(json_response["updatedArticles"]) > 0:
                    for success in json_response["updatedArticles"]:
                        self.logger.debug(
                            f"Updated price for aid: {success['idArticle']}, pid: {success['idProduct']}, {success['product']['enName']})."
                        )
                if len(json_response["notUpdatedArticles"]) > 0:
                    for failure in json_response["notUpdatedArticles"]:
                        self.logger.warning(
                            f"Failed update price for aid: {failure['tried']['idArticle']})."
                        )
                        print(failure)
                        # TODO: remove this when stable. update config to log level WARNING as default
            except Exception as err:
                self.logger.error(err)

        # TODO: Only considers the last response.
        if self.__handle_response(r):
            return r.json()
Example #4
0
class TestPyMkmHelperFunctions(unittest.TestCase):
    def setUp(self):
        self.helper = PyMkmHelper()

    def test_dict_to_cardmarket_xml_request(self):
        add_to_stock_dict = [{
            "idProduct": 100569,
            "idLanguage": 1,
            "comments": "Inserted through the API",
            "count": 1,
            "price": 4,
            "condition": "EX",
            "isFoil": True,
            "isSigned": False,
            "isPlayset": False,
        }]

        add_to_stock_xml = """<request>
               <article>
                   <idProduct>100569</idProduct>
                   <idLanguage>1</idLanguage>
                   <comments>Inserted through the API</comments>
                   <count>1</count>
                   <price>4</price>
                   <condition>EX</condition>
                   <isFoil>true</isFoil>
                   <isSigned>false</isSigned>
                   <isPlayset>false</isPlayset>
               </article>
           </request>"""
        add_to_stock_xml = re.sub(r"[\t\s]+", "", add_to_stock_xml)

        xml_data = self.helper.dicttoxml(add_to_stock_dict)
        xml_data = re.sub(r"[\t\s]+", "", xml_data)
        self.assertEqual(xml_data, add_to_stock_xml)

    def test_string_to_float_or_int(self):
        self.assertEqual(self.helper.string_to_float_or_int("1.0"), 1)
        self.assertEqual(self.helper.string_to_float_or_int("1"), 1)
        self.assertEqual(self.helper.string_to_float_or_int("AAAAA"), "AAAAA")
        self.assertEqual(self.helper.string_to_float_or_int("11.3"), 11.3)
        self.assertEqual(self.helper.string_to_float_or_int(str(4 / 3)), 4 / 3)

    def test_calculate_average(self):
        table = [
            ["Yxskaft", "SE", "NM", 1, 1.21],
            ["Frazze11", "SE", "NM", 3, 1.3],
            ["andli826", "SE", "NM", 2, 1.82],
        ]
        self.assertEqual(self.helper.calculate_average(table, 3, 4), 1.46)

    def test_calculate_median(self):
        table = [
            ["Yxskaft", "SE", "NM", 1, 1.21],
            ["Frazze11", "SE", "NM", 3, 1.3],
            ["andli826", "SE", "NM", 2, 1.82],
        ]
        self.assertEqual(self.helper.calculate_median(table, 3, 4), 1.3)
        self.assertEqual(self.helper.calculate_average(table, 3, 4), 1.46)

    def test_calculate_lowest(self):
        table = [
            ["Yxskaft", "SE", "NM", 1, 1.21],
            ["Frazze11", "SE", "NM", 3, 1.3],
            ["andli826", "SE", "NM", 2, 1.82],
        ]
        self.assertEqual(self.helper.get_lowest_price_from_table(table, 4),
                         1.21)

    def test_round_up_to_limit(self):
        self.assertEqual(
            self.helper.round_up_to_multiple_of_lower_limit(0.25, 0.99), 1)
        self.assertEqual(
            self.helper.round_up_to_multiple_of_lower_limit(0.25, 0), 0)
        self.assertEqual(
            self.helper.round_up_to_multiple_of_lower_limit(0.25, 0.1), 0.25)

        self.assertEqual(
            self.helper.round_up_to_multiple_of_lower_limit(0.1, 0.99), 1)
        self.assertEqual(
            self.helper.round_up_to_multiple_of_lower_limit(0.01, 0.011), 0.02)
        self.assertEqual(
            self.helper.round_up_to_multiple_of_lower_limit(0.01, 1), 1)
        self.assertEqual(
            self.helper.round_up_to_multiple_of_lower_limit(1, 0.1), 1)

    def test_round_down_to_limit(self):
        self.assertEqual(
            self.helper.round_down_to_multiple_of_lower_limit(0.25, 0.99),
            0.75)
        self.assertEqual(
            self.helper.round_down_to_multiple_of_lower_limit(0.25, 1.01), 1)
        self.assertEqual(
            self.helper.round_down_to_multiple_of_lower_limit(0.25, 0.1), 0.25)

        self.assertEqual(
            self.helper.round_down_to_multiple_of_lower_limit(0.1, 0.99), 0.9)
        self.assertEqual(
            self.helper.round_down_to_multiple_of_lower_limit(0.01, 0.011),
            0.01)
        self.assertEqual(
            self.helper.round_down_to_multiple_of_lower_limit(0.01, 1), 1)
        self.assertEqual(
            self.helper.round_down_to_multiple_of_lower_limit(1, 0.1), 1)

        self.assertEqual(
            self.helper.round_down_to_multiple_of_lower_limit(0.10, 8.44), 8.4)

    @patch("sys.stdout", new_callable=io.StringIO)
    @patch("builtins.input", side_effect=["y", "n", "p", "n", ""])
    def test_prompt_bool(self, mock_input, mock_stdout):
        self.assertTrue(self.helper.prompt_bool("test_y"))
        self.assertFalse(self.helper.prompt_bool("test_n"))
        self.helper.prompt_bool("test_error")
        self.assertRegex(mock_stdout.getvalue(),
                         r"\nPlease answer with y\/n\n")
        self.assertFalse(self.helper.prompt_bool("test_empty"))

    @patch("builtins.input", side_effect=["y"])
    def test_prompt_string(self, mock_input):
        self.assertEqual(self.helper.prompt_string("test"), "y")