Add POST /api/v1/admin/marketplace-import-jobs endpoint to allow admins to create import jobs for any vendor. Changes: - Add AdminMarketplaceImportJobRequest schema with vendor_id field - Add create_marketplace_import_job endpoint in admin/marketplace.py - Make vendor_code and vendor_name optional in response model to handle edge cases where vendor relationship may not be loaded This fixes the 405 Method Not Allowed error when trying to import products from the admin marketplace page. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
105 lines
3.0 KiB
Python
105 lines
3.0 KiB
Python
from datetime import datetime
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
|
|
|
|
class MarketplaceImportJobRequest(BaseModel):
|
|
"""Request schema for triggering marketplace import.
|
|
|
|
Note: vendor_id is injected by middleware, not from request body.
|
|
"""
|
|
|
|
source_url: str = Field(..., description="URL to CSV file from marketplace")
|
|
marketplace: str = Field(default="Letzshop", description="Marketplace name")
|
|
batch_size: int | None = Field(
|
|
1000, description="Processing batch size", ge=100, le=10000
|
|
)
|
|
|
|
@field_validator("source_url")
|
|
@classmethod
|
|
def validate_url(cls, v):
|
|
# Basic URL security validation
|
|
if not v.startswith(("http://", "https://")):
|
|
raise ValueError("URL must start with http:// or https://")
|
|
return v.strip()
|
|
|
|
@field_validator("marketplace")
|
|
@classmethod
|
|
def validate_marketplace(cls, v):
|
|
return v.strip()
|
|
|
|
|
|
class AdminMarketplaceImportJobRequest(BaseModel):
|
|
"""Request schema for admin-triggered marketplace import.
|
|
|
|
Includes vendor_id since admin can import for any vendor.
|
|
"""
|
|
|
|
vendor_id: int = Field(..., description="Vendor ID to import products for")
|
|
source_url: str = Field(..., description="URL to CSV file from marketplace")
|
|
marketplace: str = Field(default="Letzshop", description="Marketplace name")
|
|
batch_size: int | None = Field(
|
|
1000, description="Processing batch size", ge=100, le=10000
|
|
)
|
|
|
|
@field_validator("source_url")
|
|
@classmethod
|
|
def validate_url(cls, v):
|
|
# Basic URL security validation
|
|
if not v.startswith(("http://", "https://")):
|
|
raise ValueError("URL must start with http:// or https://")
|
|
return v.strip()
|
|
|
|
@field_validator("marketplace")
|
|
@classmethod
|
|
def validate_marketplace(cls, v):
|
|
return v.strip()
|
|
|
|
|
|
class MarketplaceImportJobResponse(BaseModel):
|
|
"""Response schema for marketplace import job."""
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
job_id: int
|
|
vendor_id: int
|
|
vendor_code: str | None = None # Populated from vendor relationship
|
|
vendor_name: str | None = None # Populated from vendor relationship
|
|
marketplace: str
|
|
source_url: str
|
|
status: str
|
|
|
|
# Counts
|
|
imported: int = 0
|
|
updated: int = 0
|
|
total_processed: int = 0
|
|
error_count: int = 0
|
|
|
|
# Error details
|
|
error_message: str | None = None
|
|
|
|
# Timestamps
|
|
created_at: datetime
|
|
started_at: datetime | None = None
|
|
completed_at: datetime | None = None
|
|
|
|
|
|
class MarketplaceImportJobListResponse(BaseModel):
|
|
"""Response schema for list of import jobs."""
|
|
|
|
jobs: list[MarketplaceImportJobResponse]
|
|
total: int
|
|
skip: int
|
|
limit: int
|
|
|
|
|
|
class MarketplaceImportJobStatusUpdate(BaseModel):
|
|
"""Schema for updating import job status (internal use)."""
|
|
|
|
status: str
|
|
imported_count: int | None = None
|
|
updated_count: int | None = None
|
|
error_count: int | None = None
|
|
total_processed: int | None = None
|
|
error_message: str | None = None
|