+
This commit is contained in:
@@ -6,10 +6,14 @@
|
||||
# </DESIGN_NOTE>
|
||||
|
||||
# <IMPORTS>
|
||||
import logging
|
||||
from pydantic import BaseModel, Field, HttpUrl
|
||||
from pydantic.functional_validators import model_validator
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
import uuid
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
# </IMPORTS>
|
||||
|
||||
# <MAIN_CONTRACT for="ProductVariant">
|
||||
@@ -19,8 +23,18 @@ import uuid
|
||||
class ProductVariant(BaseModel):
|
||||
# <STATE name="product_variant_fields">
|
||||
name: str = Field(..., description="Название продукта.")
|
||||
volume: str = Field(..., description="Объем или вариант продукта (например, '50мл', '10 капсул').")
|
||||
price: int = Field(..., gt=0, description="Цена продукта в числовом формате, должна быть положительной.")
|
||||
volume: Optional[str] = Field(None, description="Объем или вариант продукта (например, '50мл', '10 капсул'). Может быть пустым, если не применимо.")
|
||||
price: int = Field(..., description="Цена продукта в числовом формате. Должна быть положительной, если товар в наличии, иначе может быть 0.")
|
||||
is_in_stock: bool = Field(..., description="Наличие товара.")
|
||||
|
||||
@model_validator(mode='after')
|
||||
def validate_price_based_on_stock(self) -> 'ProductVariant':
|
||||
if not self.is_in_stock and self.price != 0:
|
||||
logger.warning(f"[CONTRACT_VIOLATION] Product '{self.name}' (URL: {self.url}) is out of stock but has a non-zero price ({self.price}). Setting price to 0.")
|
||||
self.price = 0
|
||||
elif self.is_in_stock and self.price <= 0:
|
||||
raise ValueError("Price must be greater than 0 for in-stock products.")
|
||||
return self
|
||||
url: HttpUrl = Field(..., description="Полный URL страницы варианта продукта.")
|
||||
is_in_stock: bool = Field(..., description="Наличие товара.")
|
||||
# </STATE>
|
||||
|
||||
@@ -67,12 +67,14 @@ class Settings(BaseModel):
|
||||
|
||||
# <CONFIG name="logging_settings">
|
||||
log_to_db: bool = Field(default=os.getenv('PARSER_LOG_TO_DB', 'true').lower() == 'true')
|
||||
log_dir: Path = Field(default=BASE_DIR / "logs", description="Директория для сохранения логов")
|
||||
# </CONFIG>
|
||||
|
||||
# <CONFIG name="performance_settings">
|
||||
request_timeout: int = Field(default=int(os.getenv('PARSER_TIMEOUT', 30)))
|
||||
delay_between_requests: float = Field(default=float(os.getenv('PARSER_DELAY', 1.0)))
|
||||
max_retries: int = Field(default=int(os.getenv('PARSER_RETRIES', 3)))
|
||||
num_parser_threads: int = Field(default=int(os.getenv('PARSER_THREADS', 5)), description="Количество потоков для парсинга")
|
||||
# </CONFIG>
|
||||
|
||||
# <CONFIG name="selectors_config_instance">
|
||||
@@ -81,8 +83,8 @@ class Settings(BaseModel):
|
||||
VARIANT_LIST_ITEM='.product-version-select li',
|
||||
PRODUCT_PAGE_NAME='h1.product-h1',
|
||||
ACTIVE_VOLUME='.product-version-select li.active',
|
||||
PRICE_BLOCK='.product-sale-box .price span',
|
||||
PRODUCT_UNAVAILABLE='.product-unavailable',
|
||||
PRICE_BLOCK='.product-sale-box .price span, .price-value, .product-price, .price',
|
||||
PRODUCT_UNAVAILABLE='.product-unavailable, .out-of-stock-message, .unavailable-message, .stock-status.out-of-stock, li.not-available, div.disabled',
|
||||
)
|
||||
# </CONFIG>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user