From f78527ded6422a329cc5f1c5beac7bd63a25b893 Mon Sep 17 00:00:00 2001 From: Sven Bursch-Osewold Date: Mon, 21 Apr 2025 15:54:46 +0200 Subject: [PATCH 1/3] Ean Search added --- src/python_picnic_api2/client.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/python_picnic_api2/client.py b/src/python_picnic_api2/client.py index b1b04bd..8a82b1f 100644 --- a/src/python_picnic_api2/client.py +++ b/src/python_picnic_api2/client.py @@ -177,5 +177,30 @@ def print_categories(self, depth: int = 0): tree = "\n".join(_tree_generator(self.get_categories(depth=depth))) print(tree) + def get_product_from_gtin(self, etan: str, maxRedirects: int = 5): + + # Finds the product ID for a gtin/ean (barcode). + headers = ( + { + "x-picnic-agent": "30100;1.15.272-15295;", + "x-picnic-did": "3C417201548B2E3B", + } + ) + url = "https://picnic.app/" + self._country_code.lower() + "/qr/gtin/" + etan + while maxRedirects > 0: + if url == "http://picnic.app/nl/link/store/storefront": + # gtin unknown + return None + r = self.session.get(url, headers=headers, allow_redirects=False) + maxRedirects -= 1 + if ";id=" in r.url: + # found the product id + return r.url.split(";id=",1)[1] + if "Location" not in r.headers: + # product id not found but also no futher redirect + return None + url = r.headers["Location"] + return None + __all__ = ["PicnicAPI"] From d7e25dd76c3773f5a96a3a0fc09383660821a195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Gro=C3=9F?= Date: Mon, 28 Apr 2025 19:21:38 +0000 Subject: [PATCH 2/3] Add tests for ean search --- integration_tests/test_client.py | 11 +++++++++++ src/python_picnic_api2/client.py | 31 +++++++++++-------------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/integration_tests/test_client.py b/integration_tests/test_client.py index 43f7a2a..ffd2f29 100644 --- a/integration_tests/test_client.py +++ b/integration_tests/test_client.py @@ -56,6 +56,17 @@ def test_get_article_with_category_name(): picnic.get_article("s1018620", add_category_name=True) +def test_get_article_by_gtin(): + response = picnic.get_article_by_gtin("4311501044209") + assert response["id"] == "s1018620" + assert response["name"] == "Gut&Günstig H-Milch 3,5%" + + +def test_get_article_by_gtin_unknown(): + response = picnic.get_article_by_gtin("4311501040000") + assert response is None + + def test_get_cart(): response = picnic.get_cart() assert isinstance(response, dict) diff --git a/src/python_picnic_api2/client.py b/src/python_picnic_api2/client.py index 8a82b1f..8a02e72 100644 --- a/src/python_picnic_api2/client.py +++ b/src/python_picnic_api2/client.py @@ -15,6 +15,10 @@ GLOBAL_GATEWAY_URL = "https://gateway-prod.global.picnicinternational.com" DEFAULT_COUNTRY_CODE = "NL" DEFAULT_API_VERSION = "15" +_HEADERS = { + "x-picnic-agent": "30100;1.15.272-15295;", + "x-picnic-did": "3C417201548B2E3B", +} class PicnicAPI: @@ -47,14 +51,7 @@ def _get(self, path: str, add_picnic_headers=False): url = self._base_url + path # Make the request, add special picnic headers if needed - headers = ( - { - "x-picnic-agent": "30100;1.15.272-15295;", - "x-picnic-did": "3C417201548B2E3B", - } - if add_picnic_headers - else None - ) + headers = _HEADERS if add_picnic_headers else None response = self.session.get(url, headers=headers).json() if self._contains_auth_error(response): @@ -177,27 +174,21 @@ def print_categories(self, depth: int = 0): tree = "\n".join(_tree_generator(self.get_categories(depth=depth))) print(tree) - def get_product_from_gtin(self, etan: str, maxRedirects: int = 5): + def get_article_by_gtin(self, etan: str, maxRedirects: int = 5): + # Finds the article ID for a gtin/ean (barcode). - # Finds the product ID for a gtin/ean (barcode). - headers = ( - { - "x-picnic-agent": "30100;1.15.272-15295;", - "x-picnic-did": "3C417201548B2E3B", - } - ) url = "https://picnic.app/" + self._country_code.lower() + "/qr/gtin/" + etan while maxRedirects > 0: if url == "http://picnic.app/nl/link/store/storefront": # gtin unknown return None - r = self.session.get(url, headers=headers, allow_redirects=False) + r = self.session.get(url, headers=_HEADERS, allow_redirects=False) maxRedirects -= 1 if ";id=" in r.url: - # found the product id - return r.url.split(";id=",1)[1] + # found the article id + return self.get_article(r.url.split(";id=", 1)[1]) if "Location" not in r.headers: - # product id not found but also no futher redirect + # article id not found but also no futher redirect return None url = r.headers["Location"] return None From 0e88b36d3ae9cff9b0aef14ae17ec1043539d940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Gro=C3=9F?= Date: Mon, 28 Apr 2025 19:29:15 +0000 Subject: [PATCH 3/3] Add unit test for ean search --- tests/test_client.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index 727129c..96a85ca 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -106,6 +106,14 @@ def test_search_encoding(self): headers=PICNIC_HEADERS, ) + def test_get_article_by_gtin(self): + self.client.get_article_by_gtin("123456789") + self.session_mock().get.assert_called_with( + "https://picnic.app/nl/qr/gtin/123456789", + headers=PICNIC_HEADERS, + allow_redirects=False, + ) + def test_get_cart(self): self.client.get_cart() self.session_mock().get.assert_called_with(