diff --git a/README.md b/README.md index 25b90ec..072f70a 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,7 @@ ad_defaults: suffix: "" price_type: NEGOTIABLE # one of: FIXED, NEGOTIABLE, GIVE_AWAY shipping_type: SHIPPING # one of: PICKUP, SHIPPING, NOT_APPLICABLE + shipping_costs: # e.g. 2.95 contact: name: "" street: "" @@ -277,6 +278,7 @@ special_attributes: # haus_mieten.zimmer_d: value # Zimmer shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE +shipping_costs: # e.g. 2.95 # list of wildcard patterns to select images # if relative paths are specified, then they are relative to this ad configuration file diff --git a/kleinanzeigen_bot/__init__.py b/kleinanzeigen_bot/__init__.py index 593e6fb..032b41b 100644 --- a/kleinanzeigen_bot/__init__.py +++ b/kleinanzeigen_bot/__init__.py @@ -241,6 +241,9 @@ class KleinanzeigenBot(SeleniumMixin): if ad_cfg["category"]: ad_cfg["category"] = self.categories.get(ad_cfg["category"], ad_cfg["category"]) + if ad_cfg["shipping_costs"]: + ad_cfg["shipping_costs"] = str(utils.parse_decimal(ad_cfg["shipping_costs"])) + if ad_cfg["images"]: images = set() for image_pattern in ad_cfg["images"]: @@ -397,6 +400,17 @@ class KleinanzeigenBot(SeleniumMixin): else: ensure(is_category_auto_selected, f"No category specified in [{ad_file}] and automatic category detection failed") + ############################# + # set shipping type/costs + ############################# + if ad_cfg["shipping_type"] == "PICKUP": + self.web_click(By.XPATH, '//*[contains(@class, "ShippingPickupSelector")]//label[text()[contains(.,"Nur Abholung")]]/input[@type="radio"]') + elif ad_cfg["shipping_costs"]: + self.web_click(By.XPATH, '//*[contains(@class, "ShippingOption")]//input[@type="radio"]') + self.web_click(By.XPATH, '//*[contains(@class, "CarrierOptionsPopup")]//*[contains(@class, "IndividualPriceSection")]//input[@type="checkbox"]') + self.web_input(By.XPATH, '//*[contains(@class, "IndividualShippingInput")]//input[@type="text"]', str.replace(ad_cfg["shipping_costs"], ".", ",")) + self.web_click(By.XPATH, '//*[contains(@class, "ReactModalPortal")]//button[.//*[text()[contains(.,"Weiter")]]]') + ############################# # set price ############################# diff --git a/kleinanzeigen_bot/resources/ad_fields.yaml b/kleinanzeigen_bot/resources/ad_fields.yaml index b19544c..ff105eb 100644 --- a/kleinanzeigen_bot/resources/ad_fields.yaml +++ b/kleinanzeigen_bot/resources/ad_fields.yaml @@ -7,6 +7,7 @@ special_attributes: {} price: price_type: # one of: FIXED, NEGOTIABLE, GIVE_AWAY shipping_type: # one of: PICKUP, SHIPPING, NOT_APPLICABLE +shipping_costs: images: [] contact: name: diff --git a/kleinanzeigen_bot/utils.py b/kleinanzeigen_bot/utils.py index 04aa955..ddd7ebe 100644 --- a/kleinanzeigen_bot/utils.py +++ b/kleinanzeigen_bot/utils.py @@ -2,7 +2,7 @@ Copyright (C) 2022 Sebastian Thomschke and contributors SPDX-License-Identifier: AGPL-3.0-or-later """ -import copy, json, logging, os, secrets, sys, traceback, time +import copy, decimal, json, logging, os, re, secrets, sys, traceback, time from importlib.resources import read_text as get_resource_as_string from collections.abc import Callable, Iterable from types import ModuleType @@ -216,3 +216,28 @@ def save_dict(filepath:str, content:dict[str, Any]) -> None: yaml.allow_duplicate_keys = False yaml.explicit_start = False yaml.dump(content, file) + + +def parse_decimal(number:float | int | str) -> decimal.Decimal: + """ + >>> parse_decimal(5) + Decimal('5') + >>> parse_decimal(5.5) + Decimal('5.5') + >>> parse_decimal("5.5") + Decimal('5.5') + >>> parse_decimal("5,5") + Decimal('5.5') + >>> parse_decimal("1.005,5") + Decimal('1005.5') + >>> parse_decimal("1,005.5") + Decimal('1005.5') + """ + try: + return decimal.Decimal(number) + except decimal.InvalidOperation as ex: + parts = re.split("[.,]", str(number)) + try: + return decimal.Decimal("".join(parts[:-1]) + "." + parts[-1]) + except decimal.InvalidOperation: + raise decimal.DecimalException(f"Invalid number format: {number}") from ex diff --git a/pyproject.toml b/pyproject.toml index 3a4ceac..d6e3627 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -157,7 +157,7 @@ max-attributes = 10 max-branches = 20 max-locals = 30 max-returns = 10 -max-statements = 80 +max-statements = 90 #####################