feat: add Letzshop vendor directory with sync and admin management
- Add LetzshopVendorCache model to store cached vendor data from Letzshop API - Create LetzshopVendorSyncService for syncing vendor directory - Add Celery task for background vendor sync - Create admin page at /admin/letzshop/vendor-directory with: - Stats dashboard (total, claimed, unclaimed vendors) - Searchable/filterable vendor list - "Sync Now" button to trigger sync - Ability to create platform vendors from Letzshop cache - Add API endpoints for vendor directory management - Add Pydantic schemas for API responses Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -507,3 +507,120 @@ class LetzshopHistoricalImportStartResponse(BaseModel):
|
||||
job_id: int
|
||||
status: str = "pending"
|
||||
message: str = "Historical import job started"
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Vendor Directory Schemas (Letzshop Marketplace Cache)
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class LetzshopCachedVendorItem(BaseModel):
|
||||
"""Schema for a cached Letzshop vendor in list view."""
|
||||
|
||||
id: int
|
||||
letzshop_id: str
|
||||
slug: str
|
||||
name: str
|
||||
company_name: str | None = None
|
||||
email: str | None = None
|
||||
phone: str | None = None
|
||||
website: str | None = None
|
||||
city: str | None = None
|
||||
categories: list[str] = []
|
||||
is_active: bool = True
|
||||
is_claimed: bool = False
|
||||
claimed_by_vendor_id: int | None = None
|
||||
last_synced_at: datetime | None = None
|
||||
letzshop_url: str
|
||||
|
||||
|
||||
class LetzshopCachedVendorDetail(BaseModel):
|
||||
"""Schema for detailed cached Letzshop vendor."""
|
||||
|
||||
id: int
|
||||
letzshop_id: str
|
||||
slug: str
|
||||
name: str
|
||||
company_name: str | None = None
|
||||
description_en: str | None = None
|
||||
description_fr: str | None = None
|
||||
description_de: str | None = None
|
||||
email: str | None = None
|
||||
phone: str | None = None
|
||||
fax: str | None = None
|
||||
website: str | None = None
|
||||
street: str | None = None
|
||||
street_number: str | None = None
|
||||
city: str | None = None
|
||||
zipcode: str | None = None
|
||||
country_iso: str | None = None
|
||||
latitude: str | None = None
|
||||
longitude: str | None = None
|
||||
categories: list[str] = []
|
||||
background_image_url: str | None = None
|
||||
social_media_links: list[str] = []
|
||||
opening_hours_en: str | None = None
|
||||
opening_hours_fr: str | None = None
|
||||
opening_hours_de: str | None = None
|
||||
representative_name: str | None = None
|
||||
representative_title: str | None = None
|
||||
is_active: bool = True
|
||||
is_claimed: bool = False
|
||||
claimed_by_vendor_id: int | None = None
|
||||
claimed_at: datetime | None = None
|
||||
last_synced_at: datetime | None = None
|
||||
letzshop_url: str
|
||||
|
||||
|
||||
class LetzshopVendorDirectoryStats(BaseModel):
|
||||
"""Schema for vendor directory cache statistics."""
|
||||
|
||||
total_vendors: int = 0
|
||||
active_vendors: int = 0
|
||||
claimed_vendors: int = 0
|
||||
unclaimed_vendors: int = 0
|
||||
unique_cities: int = 0
|
||||
last_synced_at: str | None = None
|
||||
|
||||
|
||||
class LetzshopVendorDirectoryStatsResponse(BaseModel):
|
||||
"""Response schema for vendor directory stats endpoint."""
|
||||
|
||||
success: bool = True
|
||||
stats: LetzshopVendorDirectoryStats
|
||||
|
||||
|
||||
class LetzshopCachedVendorListResponse(BaseModel):
|
||||
"""Response schema for vendor directory list endpoint."""
|
||||
|
||||
success: bool = True
|
||||
vendors: list[LetzshopCachedVendorItem]
|
||||
total: int
|
||||
page: int
|
||||
limit: int
|
||||
has_more: bool
|
||||
|
||||
|
||||
class LetzshopCachedVendorDetailResponse(BaseModel):
|
||||
"""Response schema for vendor directory detail endpoint."""
|
||||
|
||||
success: bool = True
|
||||
vendor: LetzshopCachedVendorDetail
|
||||
|
||||
|
||||
class LetzshopVendorDirectorySyncResponse(BaseModel):
|
||||
"""Response schema for vendor directory sync trigger."""
|
||||
|
||||
success: bool = True
|
||||
message: str
|
||||
task_id: str | None = None
|
||||
mode: str = "celery"
|
||||
|
||||
|
||||
class LetzshopCreateVendorFromCacheResponse(BaseModel):
|
||||
"""Response schema for creating vendor from Letzshop cache."""
|
||||
|
||||
success: bool = True
|
||||
message: str
|
||||
vendor: dict[str, Any] | None = None
|
||||
letzshop_vendor_slug: str
|
||||
|
||||
Reference in New Issue
Block a user