mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 02:31:45 +01:00
fix: keep shipping_type SHIPPING for individual postage (#785)
This commit is contained in:
@@ -553,7 +553,7 @@ class AdExtractor(WebScrapingMixin):
|
|||||||
# Find all options with the same price to determine the package size
|
# Find all options with the same price to determine the package size
|
||||||
matching_options = [opt for opt in shipping_costs if opt["priceInEuroCent"] == price_in_cent]
|
matching_options = [opt for opt in shipping_costs if opt["priceInEuroCent"] == price_in_cent]
|
||||||
if not matching_options:
|
if not matching_options:
|
||||||
return "NOT_APPLICABLE", ship_costs, shipping_options
|
return "SHIPPING", ship_costs, None
|
||||||
|
|
||||||
# Use the package size of the first matching option
|
# Use the package size of the first matching option
|
||||||
matching_size = matching_options[0]["packageSize"]
|
matching_size = matching_options[0]["packageSize"]
|
||||||
@@ -570,11 +570,11 @@ class AdExtractor(WebScrapingMixin):
|
|||||||
# Only use the matching option if it's not excluded
|
# Only use the matching option if it's not excluded
|
||||||
matching_option = next((x for x in shipping_costs if x["priceInEuroCent"] == price_in_cent), None)
|
matching_option = next((x for x in shipping_costs if x["priceInEuroCent"] == price_in_cent), None)
|
||||||
if not matching_option:
|
if not matching_option:
|
||||||
return "NOT_APPLICABLE", ship_costs, shipping_options
|
return "SHIPPING", ship_costs, None
|
||||||
|
|
||||||
shipping_option = shipping_option_mapping.get(matching_option["id"])
|
shipping_option = shipping_option_mapping.get(matching_option["id"])
|
||||||
if not shipping_option or shipping_option in self.config.download.excluded_shipping_options:
|
if not shipping_option or shipping_option in self.config.download.excluded_shipping_options:
|
||||||
return "NOT_APPLICABLE", ship_costs, shipping_options
|
return "SHIPPING", ship_costs, None
|
||||||
shipping_options = [shipping_option]
|
shipping_options = [shipping_option]
|
||||||
|
|
||||||
except TimeoutError: # no pricing box -> no shipping given
|
except TimeoutError: # no pricing box -> no shipping given
|
||||||
|
|||||||
@@ -304,6 +304,38 @@ class TestAdExtractorShipping:
|
|||||||
else:
|
else:
|
||||||
assert options is None
|
assert options is None
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
async def test_extract_shipping_info_with_all_matching_options_no_match(self, test_extractor:AdExtractor) -> None:
|
||||||
|
"""Test shipping extraction when include-all is enabled but no option matches the price."""
|
||||||
|
shipping_response = {
|
||||||
|
"content": json.dumps(
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"shippingOptionsResponse": {
|
||||||
|
"options": [
|
||||||
|
{"id": "DHL_001", "priceInEuroCent": 500, "packageSize": "SMALL"},
|
||||||
|
{"id": "HERMES_001", "priceInEuroCent": 600, "packageSize": "SMALL"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test_extractor.config.download = DownloadConfig.model_validate({"include_all_matching_shipping_options": True})
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch.object(test_extractor, "page", MagicMock()),
|
||||||
|
patch.object(test_extractor, "web_text", new_callable = AsyncMock, return_value = "+ Versand ab 4,89 €"),
|
||||||
|
patch.object(test_extractor, "web_request", new_callable = AsyncMock, return_value = shipping_response),
|
||||||
|
):
|
||||||
|
shipping_type, costs, options = await test_extractor._extract_shipping_info_from_ad_page()
|
||||||
|
|
||||||
|
assert shipping_type == "SHIPPING"
|
||||||
|
assert costs == 4.89
|
||||||
|
assert options is None
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
async def test_extract_shipping_info_with_excluded_options(self, test_extractor:AdExtractor) -> None:
|
async def test_extract_shipping_info_with_excluded_options(self, test_extractor:AdExtractor) -> None:
|
||||||
@@ -370,10 +402,54 @@ class TestAdExtractorShipping:
|
|||||||
):
|
):
|
||||||
shipping_type, costs, options = await test_extractor._extract_shipping_info_from_ad_page()
|
shipping_type, costs, options = await test_extractor._extract_shipping_info_from_ad_page()
|
||||||
|
|
||||||
assert shipping_type == "NOT_APPLICABLE"
|
assert shipping_type == "SHIPPING"
|
||||||
assert costs == 4.89
|
assert costs == 4.89
|
||||||
assert options is None
|
assert options is None
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
async def test_extract_shipping_info_with_no_matching_option(self, test_extractor:AdExtractor) -> None:
|
||||||
|
"""Test shipping info extraction when price exists but NO matching option in API response."""
|
||||||
|
shipping_response = {
|
||||||
|
"content": json.dumps(
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"shippingOptionsResponse": {
|
||||||
|
"options": [
|
||||||
|
{"id": "DHL_001", "priceInEuroCent": 500, "packageSize": "SMALL"},
|
||||||
|
{"id": "HERMES_001", "priceInEuroCent": 600, "packageSize": "SMALL"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch.object(test_extractor, "page", MagicMock()),
|
||||||
|
patch.object(test_extractor, "web_text", new_callable = AsyncMock, return_value = "+ Versand ab 7,00 €"),
|
||||||
|
patch.object(test_extractor, "web_request", new_callable = AsyncMock, return_value = shipping_response),
|
||||||
|
):
|
||||||
|
shipping_type, costs, options = await test_extractor._extract_shipping_info_from_ad_page()
|
||||||
|
|
||||||
|
assert shipping_type == "SHIPPING"
|
||||||
|
assert costs == 7.0
|
||||||
|
assert options is None
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
async def test_extract_shipping_info_timeout(self, test_extractor:AdExtractor) -> None:
|
||||||
|
"""Test shipping info extraction when shipping element is missing (TimeoutError)."""
|
||||||
|
with (
|
||||||
|
patch.object(test_extractor, "page", MagicMock()),
|
||||||
|
patch.object(test_extractor, "web_text", new_callable = AsyncMock, side_effect = TimeoutError),
|
||||||
|
):
|
||||||
|
shipping_type, costs, options = await test_extractor._extract_shipping_info_from_ad_page()
|
||||||
|
|
||||||
|
assert shipping_type == "NOT_APPLICABLE"
|
||||||
|
assert costs is None
|
||||||
|
assert options is None
|
||||||
|
|
||||||
|
|
||||||
class TestAdExtractorNavigation:
|
class TestAdExtractorNavigation:
|
||||||
"""Tests for navigation related functionality."""
|
"""Tests for navigation related functionality."""
|
||||||
|
|||||||
Reference in New Issue
Block a user