Example #1
0
def test_print_categories(capsys):
    picnic = PicnicAPI()

    picnic.print_categories()
    captured = capsys.readouterr()

    assert isinstance(captured.out, str)
Example #2
0
    def test_login_failed(self):
        response = {
            "error": {
                "code": "AUTH_INVALID_CRED",
                "message": "Invalid credentials."
            }
        }
        self.session_mock().post.return_value = self.MockResponse(
            response, 200)

        client = PicnicAPI()
        with self.assertRaises(PicnicAuthError):
            client.login('test-user', 'test-password')
class PicnicSetupGrocy():

    picnic = PicnicAPI(username=config.picnic_user,
                       password=config.picnic_passwd, country_code="NL", store=False)
    grocy = GrocyAPI(config.picnic_img_size, config.picnic_img_baseurl)
    json_picnic_data = {}

    def importIntoGrocy(self, url: str, api_url: str, key: str):
        print("Starting importing: " + url)
        json_data = json.loads(requests.get(url).text)
        for obj in json_data[key]:
            print("Importing: " + obj["name"] + " into grocy database...")
            res = self.grocy.postToGrocy(api_url, obj)
            if not res.ok:
                print("failed importing: " + res.text)

    def setupQuantities(self):
        self.importIntoGrocy(config.picnic_quantity_list,
                             "objects/quantity_units", "data")

    def setupUserfields(self):
        self.importIntoGrocy(config.picnic_userfields_list,
                             "objects/userfields", "data")

    def setupStoreAndLocation(self):
        self.importIntoGrocy(config.picnic_stores_list,
                             "objects/shopping_locations", "data")
        self.importIntoGrocy(config.picnic_location_list,
                             "objects/locations", "data")

    def installAll(self):  # make sure to have an empty grocy database.
        self.setupUserfields()
        self.setupStoreAndLocation()
        self.setupQuantities()
Example #4
0
def search_items(picnic_api: PicnicAPI, term: str) -> List[Item]:
    result = picnic_api.search(term=term)
    items_dict = result[0]["items"]
    items = [
        Item(**item) for item in items_dict
        if ("name" in item) and ("unit_quantity_sub" in item)
    ]
    return items
Example #5
0
 def test_login_credentials(self):
     self.session_mock().authenticated = False
     PicnicAPI(username='******', password='******')
     self.session_mock().post.assert_called_with(
         self.expected_base_url + '/user/login',
         json={
             'key': '*****@*****.**',
             'secret': '098f6bcd4621d373cade4e832627b4f6',
             "client_id": 1
         })
Example #6
0
def cheapest(
        search_term: str = Argument(..., help="Search term for product."),
        n: int = Option(default=5,
                        help="Max. number of cheapest findings to show."),
        username: str = Option(None, help="Username of Picnic account."),
        password: str = Option(None, help="Password of Picnic account."),
        country_code: str = Option(default="DE", help="Country code of shop."),
):
    # connect to picnic api
    if (not username) or (not password):
        print("loading credentials from config file...")
        username, password, country_code = credentials_from_file(
            path=CREDENTIALS_PATH)
    picnic = PicnicAPI(username=username,
                       password=password,
                       country_code=country_code)
    # search items, filter cheapest
    items = search_items(picnic_api=picnic, term=search_term)
    cheapest_items = filter_cheapest_items(items=items, max_n=n)
    # format results
    for item in cheapest_items:
        print(f"* {item.name}: {item.unit_quantity_sub}")
Example #7
0
def test_get_delivery():
    picnic = PicnicAPI()
    response = picnic.get_deliveries()
    deliveryId = response[0]["id"]
    response = picnic.get_delivery(deliveryId)
    assert isinstance(response, dict)
Example #8
0
def test_get_deliveries():
    picnic = PicnicAPI()
    response_1 = picnic.get_deliveries()
    response_2 = picnic.get_deliveries(summary=True)
    assert isinstance(response_1, list)
    assert isinstance(response_2, list)
Example #9
0
def test_get_delivery_slots():
    picnic = PicnicAPI()
    response = picnic.get_delivery_slots()
    assert isinstance(response, dict)
Example #10
0
class PicNic():
    picnic_user = config.picnic_user
    picnic_passwd = config.picnic_passwd
    picnic_image_size = config.picnic_img_size
    picnic_img_baseurl = config.picnic_img_baseurl
    picnic_numofelementsimport = config.picnic_max_import_products
    picnic_ean_codes_url = config.picnic_product_ean_list
    quantities = dict()
    grocy_items = []

    picnic = PicnicAPI(username=picnic_user,
                       password=picnic_passwd,
                       country_code="NL",
                       store=False)
    grocy = GrocyAPI(picnic_image_size, picnic_img_baseurl)
    json_picnic_data = {}

    picnic_store_id = ""
    picnic_last_delivery_id = ""
    home_location_id = ""

    def __init__(self):
        # download all json ean products from file
        json_data = json.loads(requests.get(self.picnic_ean_codes_url).text)
        self.json_picnic_data = json_data["data"]
        self.getAllGrocyProducts()  # first load all existing grocy products.
        self.getQuantityUnits()  # import all grocy quantities.
        self.getPicnicStoreData(
        )  # get store ID and delivery ID with name Picnic
        self.getHomeLocationID()  # get location ID with name Home

    #  print(self.getProductInformation(10465898))

    def getEANFromPicnicID(self, picnic_id: str):
        for json_item in self.json_picnic_data:
            if str(json_item["picnic_id"]) == picnic_id:
                return str(json_item["ean"])
        return ""

    def getHomeLocationID(self):
        json_data = self.grocy.getFromGrocy("objects/locations")

        found_location = [x for x in json_data if x["name"] == "Home"]
        if len(found_location) > 0:
            self.home_location_id = found_location[0]["id"]

    def getPicnicStoreData(self):
        json_data = self.grocy.getFromGrocy("objects/shopping_locations")

        found_store = [x for x in json_data if x["name"] == "Picnic"]
        if len(found_store) > 0:
            self.picnic_store_id = found_store[0]["id"]
            self.picnic_last_delivery_id = found_store[0]["userfields"][
                "lastdeliveryid"]

    def setLastDeliveryID(self, delivery_id: str):
        self.grocy.addUserFieldToStore(
            str(self.picnic_store_id),
            "{\"lastdeliveryid\":\"" + delivery_id + "\"}")

    def addPicnicIDToProduct(self, product_id: str, picnic_id: str):
        self.grocy.addUserFieldToProduct(str(product_id),
                                         "{\"picnic\":\"" + picnic_id + "\"}")

    def addPicNicProductToGrocy(self, name: str, qu_id: str, picnic_id: str,
                                imgId: str, price: str):
        postData = {}
        postData["name"] = name
        postData["qu_id_purchase"] = qu_id
        postData["qu_id_stock"] = qu_id
        postData["qu_factor_purchase_to_stock"] = 1.0
        postData["shopping_location_id"] = self.picnic_store_id
        postData["location_id"] = self.home_location_id
        postData["barcode"] = self.getEANFromPicnicID(picnic_id)
        # disable tenminste houdtbaar tot
        postData["default_best_before_days"] = config.disable_tht

        result = self.grocy.postToGrocy("objects/products", postData)
        if result.ok:
            json_result = json.loads(result.text)
            grocy_product_id = json_result["created_object_id"]
            print("Added picnic product to grocy: " + grocy_product_id +
                  ", picnic_id: " + picnic_id)
            self.addPicnicIDToProduct(grocy_product_id, picnic_id)
            print("Uploading picnic image to grocy...")
            self.grocy.changePictureFileNameProduct(
                grocy_product_id, self.grocy.addPictureToProduct(imgId))
            return grocy_product_id
        else:
            print("Failed to add picnic product to grocy: " + result.text)
            return 0

    def getProductInformation(self, productID: str):
        path = "/product/" + str(productID)  # , just a test.
        return self.picnic._get(path)

    def importLastPicnicDelivery(self):
        last_delivery_index = -1
        order_data = self.picnic.get_deliveries(
        )[0]["orders"][last_delivery_index]["creation_time"]
        delivery_date = self.picnic.get_deliveries(
        )[0]["delivery_time"]["start"]
        delivery_id = self.picnic.get_deliveries()[0]["delivery_id"]

        if self.picnic_last_delivery_id == delivery_id:
            print("Failed: order already imported, exit script...")
            return

        self.setLastDeliveryID(delivery_id)

        print("Setting last delivery ID: " + json.dumps(delivery_id))
        # last order of picnic
        for picnic_item in self.picnic.get_deliveries()[0]["orders"][
                last_delivery_index]["items"][:self.
                                              picnic_numofelementsimport]:
            # picnic data:
            name = picnic_item["items"][0]["name"]
            id = picnic_item["items"][0]["id"]
            image_ids = picnic_item["items"][0]["image_ids"][0]
            # used in stock data
            price = (picnic_item["items"][0]["price"] / 100)
            unit_quantity = picnic_item["items"][0]["unit_quantity"]
            converted_quantity = self.fillQuantity(unit_quantity)
            sort_of_quantity = converted_quantity[1]
            how_much = converted_quantity[0]

            # grocy_data:
            grocy_id_existing_product = self.getPicnicProductInGrocy(id)
            if grocy_id_existing_product != 0:
                #   print("picnic item already in grocy..." + price)
                print("Increasing stock: " + how_much + " with id: " +
                      sort_of_quantity)
                self.setInStock(grocy_id_existing_product, how_much, price,
                                order_data)
            else:
                new_grocy_id = self.addPicNicProductToGrocy(
                    name, sort_of_quantity, id, image_ids, price)
                if new_grocy_id != 0:
                    self.setInStock(new_grocy_id, how_much, price, order_data)

                # todo increase stock after adding product.

    def fillQuantity(self, quantity_text: str):
        replaced_text = quantity_text.replace(",", ".")
        temp = re.compile("([\d.]*\d+) ([a-zA-Z]+)")
        res = temp.match(replaced_text).groups()
        if res[1] == "x":
            temp = re.compile("([\d.]*\d+) x ([\d.]*\d+) ([a-zA-Z]+)")
            res = temp.match(replaced_text).groups()
            calculatie = int(res[0]) * int(res[1])
            new = [calculatie, res[2]]

            return [
                str(new[0]),
                str(self.matchPicnicQuantityByGrocyQuantity(new[1]))
            ]
        else:
            # returns HOW_MUCH, WHAT_KIND_OF
            return [
                str(res[0]),
                str(self.matchPicnicQuantityByGrocyQuantity(res[1]))
            ]

    def matchPicnicQuantityByGrocyQuantity(self, picnicQuantity: str):
        #print("picnicquanitity: " + picnicQuantity)
        found_quantity = ([
            self.quantities[key] for key in self.quantities
            if picnicQuantity in key.lower()
        ])
        if len(found_quantity) > 0:
            return found_quantity[0]
        else:
            return 0
        # return self.quantities[picnicQuantity]["id"]
        # for quantity in self.quantities:

        #     if picnicQuantity == quantity["name"):
        #        return quantity["id"]

    def getQuantityUnits(self):
        json_data = self.grocy.getFromGrocy('objects/quantity_units')
        for quantity in json_data:
            self.quantities[quantity["name"]] = quantity["id"]

    #   print(self.quantities)

    def setInStock(self, grocy_id: str, stock: str, price: str, order_date):
        post_data = {}
        post_data["amount"] = str(stock)
        post_data["price"] = str(price)
        post_data["purchased_date"] = str(order_date)  # order_date
        print("grocy_id: " + grocy_id)
        result = self.grocy.postToGrocy('stock/products/' + grocy_id + '/add',
                                        post_data)
        if result.ok:
            print("setInStock: succes")
        else:
            print("Failed to add stock: " + result.text)

    def getPicnicProductInGrocy(self, picnic_id: str):
        for grocy_item in self.grocy_items:
            if grocy_item.picnic_id == picnic_id:
                return grocy_item.grocy_id
        return 0

    def getAllGrocyProducts(self):
        json_data = self.grocy.getFromGrocy('objects/products')

        for product in json_data:
            grocy_product = GrocyPicnicProduct(product["userfields"]["picnic"],
                                               product["id"], product["name"],
                                               product["picture_file_name"],
                                               product["tare_weight"],
                                               product["qu_id_stock"])
            self.grocy_items.append(grocy_product)
from python_picnic_api import PicnicAPI
from dotenv import load_dotenv
import os

load_dotenv()

username = os.getenv("USERNAME")
password = os.getenv("PASSWORD")
country_code = os.getenv("COUNTRY_CODE")

picnic = PicnicAPI(username, password, country_code=country_code)


def _get_amount(cart: dict, product_id: str):
    items = cart["items"][0]["items"]
    product = next((item for item in items if item["id"] == product_id), None)
    return product["decorators"][0]["quantity"]


def test_get_user():
    response = picnic.get_user()
    assert isinstance(response, dict)
    assert "contact_email" in response.keys()
    assert response["contact_email"] == username


def test_search():
    response = picnic.search("koffie")
    assert isinstance(response, list)
    assert isinstance(response[0], dict)
    assert "id" in response[0].keys()
Example #12
0
 def test_login_auth_token(self):
     self.session_mock().authenticated = True
     PicnicAPI(username='******',
               password='******',
               auth_token='a3fwo7f3h78kf3was7h8f3ahf3ah78f3')
     self.session_mock().login.assert_not_called()
Example #13
0
 def setUp(self) -> None:
     self.session_patcher = patch(
         "python_picnic_api.client.PicnicAPISession")
     self.session_mock = self.session_patcher.start()
     self.client = PicnicAPI(username="******", password="******")
     self.expected_base_url = DEFAULT_URL.format("nl", "15")
Example #14
0
class TestClient(unittest.TestCase):
    class MockResponse:
        def __init__(self, json_data, status_code):
            self.json_data = json_data
            self.status_code = status_code

        def json(self):
            return self.json_data

    def setUp(self) -> None:
        self.session_patcher = patch(
            "python_picnic_api.client.PicnicAPISession")
        self.session_mock = self.session_patcher.start()
        self.client = PicnicAPI(username="******", password="******")
        self.expected_base_url = DEFAULT_URL.format("nl", "15")

    def tearDown(self) -> None:
        self.session_patcher.stop()

    def test_login_credentials(self):
        self.session_mock().authenticated = False
        PicnicAPI(username='******', password='******')
        self.session_mock().post.assert_called_with(
            self.expected_base_url + '/user/login',
            json={
                'key': '*****@*****.**',
                'secret': '098f6bcd4621d373cade4e832627b4f6',
                "client_id": 1
            })

    def test_login_auth_token(self):
        self.session_mock().authenticated = True
        PicnicAPI(username='******',
                  password='******',
                  auth_token='a3fwo7f3h78kf3was7h8f3ahf3ah78f3')
        self.session_mock().login.assert_not_called()

    def test_login_failed(self):
        response = {
            "error": {
                "code": "AUTH_INVALID_CRED",
                "message": "Invalid credentials."
            }
        }
        self.session_mock().post.return_value = self.MockResponse(
            response, 200)

        client = PicnicAPI()
        with self.assertRaises(PicnicAuthError):
            client.login('test-user', 'test-password')

    def test_get_user(self):
        response = {
            "user_id": "594-241-3623",
            "firstname": "Firstname",
            "lastname": "Lastname",
            "address": {
                "house_number": 25,
                "house_number_ext": "b",
                "postcode": "1234 AB",
                "street": "Dorpsstraat",
                "city": "Het dorp",
            },
            "phone": "+31123456798",
            "contact_email": "*****@*****.**",
            "total_deliveries": 25,
            "completed_deliveries": 20,
        }
        self.session_mock().get.return_value = self.MockResponse(response, 200)

        user = self.client.get_user()
        self.session_mock().get.assert_called_with(self.expected_base_url +
                                                   "/user",
                                                   headers=None)
        self.assertDictEqual(user, response)

    def test_search(self):
        self.client.search("test-product")
        self.session_mock().get.assert_called_with(
            self.expected_base_url + "/search?search_term=test-product",
            headers=None)

    def test_get_lists(self):
        self.client.get_lists()
        self.session_mock().get.assert_called_with(self.expected_base_url +
                                                   "/lists",
                                                   headers=None)

    def test_get_sublist(self):
        self.client.get_sublist(list_id="promotion", sublist_id="12345")
        self.session_mock().get.assert_called_with(
            self.expected_base_url + "/lists/promotion?sublist=12345",
            headers=None)

    def test_get_list_by_id(self):
        self.client.get_lists("abc")
        self.session_mock().get.assert_called_with(self.expected_base_url +
                                                   "/lists/abc",
                                                   headers=None)

    def test_get_cart(self):
        self.client.get_cart()
        self.session_mock().get.assert_called_with(self.expected_base_url +
                                                   "/cart",
                                                   headers=None)

    def test_add_product(self):
        self.client.add_product("p3f2qa")
        self.session_mock().post.assert_called_with(
            self.expected_base_url + "/cart/add_product",
            json={
                "product_id": "p3f2qa",
                "count": 1
            },
        )

    def test_add_multiple_products(self):
        self.client.add_product("gs4puhf3a", count=5)
        self.session_mock().post.assert_called_with(
            self.expected_base_url + "/cart/add_product",
            json={
                "product_id": "gs4puhf3a",
                "count": 5
            },
        )

    def test_remove_product(self):
        self.client.remove_product("gs4puhf3a", count=5)
        self.session_mock().post.assert_called_with(
            self.expected_base_url + "/cart/remove_product",
            json={
                "product_id": "gs4puhf3a",
                "count": 5
            },
        )

    def test_clear_cart(self):
        self.client.clear_cart()
        self.session_mock().post.assert_called_with(self.expected_base_url +
                                                    "/cart/clear",
                                                    json=None)

    def test_get_delivery_slots(self):
        self.client.get_delivery_slots()
        self.session_mock().get.assert_called_with(self.expected_base_url +
                                                   "/cart/delivery_slots",
                                                   headers=None)

    def test_get_delivery(self):
        self.client.get_delivery("3fpawshusz3")
        self.session_mock().get.assert_called_with(self.expected_base_url +
                                                   "/deliveries/3fpawshusz3",
                                                   headers=None)

    def test_get_delivery_scenario(self):
        self.client.get_delivery_scenario("3fpawshusz3")
        self.session_mock().get.assert_called_with(
            self.expected_base_url + "/deliveries/3fpawshusz3/scenario",
            headers=PICNIC_HEADERS,
        )

    def test_get_delivery_position(self):
        self.client.get_delivery_position("3fpawshusz3")
        self.session_mock().get.assert_called_with(
            self.expected_base_url + "/deliveries/3fpawshusz3/position",
            headers=PICNIC_HEADERS,
        )

    def test_get_deliveries(self):
        self.client.get_deliveries()
        self.session_mock().post.assert_called_with(self.expected_base_url +
                                                    "/deliveries",
                                                    json=[])

    def test_get_deliveries_summary(self):
        self.client.get_deliveries(summary=True)
        self.session_mock().post.assert_called_with(self.expected_base_url +
                                                    "/deliveries/summary",
                                                    json=[])

    def test_get_current_deliveries(self):
        self.client.get_current_deliveries()
        self.session_mock().post.assert_called_with(self.expected_base_url +
                                                    "/deliveries",
                                                    json=["CURRENT"])

    def test_get_categories(self):
        self.session_mock().get.return_value = self.MockResponse(
            {
                "type":
                "MY_STORE",
                "catalog": [
                    {
                        "type": "CATEGORY",
                        "id": "purchases",
                        "name": "Besteld"
                    },
                    {
                        "type": "CATEGORY",
                        "id": "promotions",
                        "name": "Acties"
                    },
                ],
                "user": {},
            },
            200,
        )

        categories = self.client.get_categories()
        self.session_mock().get.assert_called_with(self.expected_base_url +
                                                   "/my_store?depth=0",
                                                   headers=None)

        self.assertDictEqual(categories[0], {
            "type": "CATEGORY",
            "id": "purchases",
            "name": "Besteld"
        })

    def test_get_auth_exception(self):
        self.session_mock().get.return_value = self.MockResponse(
            {"error": {
                "code": "AUTH_ERROR"
            }}, 400)

        with self.assertRaises(PicnicAuthError):
            self.client.get_user()

    def test_post_auth_exception(self):
        self.session_mock().post.return_value = self.MockResponse(
            {"error": {
                "code": "AUTH_ERROR"
            }}, 400)

        with self.assertRaises(PicnicAuthError):
            self.client.clear_cart()
Example #15
0
def test_get_current_deliveries():
    picnic = PicnicAPI()
    response = picnic.get_current_deliveries()
    assert isinstance(response, list)
Example #16
0
def test_get_categories():
    picnic = PicnicAPI()
    response = picnic.get_categories()
    assert isinstance(response, list)
Example #17
0
def test_get_lists():
    picnic = PicnicAPI()
    response_1 = picnic.get_lists()
    response_2 = picnic.get_lists("21725")
    assert isinstance(response_1, list)
    assert isinstance(response_2, list)
Example #18
0
def test_search():
    picnic = PicnicAPI()
    response = picnic.search("koffie")
    assert isinstance(response, list)
Example #19
0
def test_get_user():
    picnic = PicnicAPI()
    response = picnic.get_user()
    assert isinstance(response, dict)
Example #20
0
 def authenticate(username, password, country_code) -> tuple[str, dict]:
     """Test if we can authenticate with the Picnic API."""
     picnic = PicnicAPI(username, password, country_code)
     return picnic.session.auth_token, picnic.get_user()
Example #21
0
def test_remove_product():
    picnic = PicnicAPI()
    response = picnic.remove_product("10407428")
    assert isinstance(response, dict)
Example #22
0
def create_picnic_client(entry: ConfigEntry):
    """Create an instance of the PicnicAPI client."""
    return PicnicAPI(
        auth_token=entry.data.get(CONF_ACCESS_TOKEN),
        country_code=entry.data.get(CONF_COUNTRY_CODE),
    )
Example #23
0
def test_clear_cart():
    picnic = PicnicAPI()
    response = picnic.clear_cart()
    assert isinstance(response, dict)