feat: multi-module improvements across merchant, store, i18n, and customer systems
All checks were successful
All checks were successful
- Fix platform-grouped merchant sidebar menu with core items at root level - Add merchant store management (detail page, create store, team page) - Fix store settings 500 error by removing dead stripe/API tab - Move onboarding translations to module-owned locale files - Fix onboarding banner i18n with server-side rendering + context inheritance - Refactor login language selectors to use languageSelector() function (LANG-002) - Move HTTPException handling to global exception handler in merchant routes (API-003) - Add language selector to all login pages and portal headers - Fix customer module: drop order stats from customer model, add to orders module - Fix admin menu config visibility for super admin platform context - Fix storefront auth and layout issues - Add missing i18n translations for onboarding steps (en/fr/de/lb) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -80,6 +80,9 @@ from app.modules.tenancy.schemas.merchant import (
|
||||
MerchantPortalProfileUpdate,
|
||||
MerchantPortalStoreListResponse,
|
||||
MerchantResponse,
|
||||
MerchantStoreCreate,
|
||||
MerchantStoreDetailResponse,
|
||||
MerchantStoreUpdate,
|
||||
MerchantSummary,
|
||||
MerchantTransferOwnership,
|
||||
MerchantTransferOwnershipResponse,
|
||||
@@ -163,6 +166,9 @@ __all__ = [
|
||||
"MerchantPortalProfileUpdate",
|
||||
"MerchantPortalStoreListResponse",
|
||||
"MerchantResponse",
|
||||
"MerchantStoreCreate",
|
||||
"MerchantStoreDetailResponse",
|
||||
"MerchantStoreUpdate",
|
||||
"MerchantSummary",
|
||||
"MerchantTransferOwnership",
|
||||
"MerchantTransferOwnershipResponse",
|
||||
|
||||
@@ -261,3 +261,73 @@ class MerchantPortalStoreListResponse(BaseModel):
|
||||
total: int
|
||||
skip: int
|
||||
limit: int
|
||||
can_create_store: bool = True
|
||||
|
||||
|
||||
class MerchantStoreCreate(BaseModel):
|
||||
"""Store creation from the merchant portal.
|
||||
Subset of admin StoreCreate — excludes admin-only fields."""
|
||||
|
||||
name: str = Field(..., min_length=2, max_length=255, description="Store name")
|
||||
store_code: str = Field(
|
||||
..., min_length=2, max_length=50, description="Unique store code"
|
||||
)
|
||||
subdomain: str = Field(
|
||||
..., min_length=2, max_length=100, description="Store subdomain"
|
||||
)
|
||||
description: str | None = Field(None, description="Store description")
|
||||
platform_ids: list[int] = Field(
|
||||
default_factory=list, description="Platform IDs to assign store to"
|
||||
)
|
||||
|
||||
@field_validator("subdomain")
|
||||
@classmethod
|
||||
def validate_subdomain(cls, v):
|
||||
"""Validate subdomain format."""
|
||||
import re
|
||||
|
||||
v = v.lower().strip()
|
||||
if not re.match(r"^[a-z0-9][a-z0-9-]*[a-z0-9]$", v) and len(v) > 1:
|
||||
raise ValueError(
|
||||
"Subdomain must contain only lowercase letters, numbers, and hyphens"
|
||||
)
|
||||
return v
|
||||
|
||||
@field_validator("store_code")
|
||||
@classmethod
|
||||
def normalize_store_code(cls, v):
|
||||
"""Normalize store code to uppercase."""
|
||||
return v.upper().strip()
|
||||
|
||||
|
||||
class MerchantStoreDetailResponse(BaseModel):
|
||||
"""Store detail for the merchant portal."""
|
||||
|
||||
id: int
|
||||
store_code: str
|
||||
subdomain: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
is_active: bool
|
||||
is_verified: bool
|
||||
contact_email: str | None = None
|
||||
contact_phone: str | None = None
|
||||
website: str | None = None
|
||||
business_address: str | None = None
|
||||
tax_number: str | None = None
|
||||
default_language: str | None = None
|
||||
created_at: str | None = None
|
||||
platforms: list[dict] = Field(default_factory=list)
|
||||
|
||||
|
||||
class MerchantStoreUpdate(BaseModel):
|
||||
"""Store update from the merchant portal.
|
||||
Only merchant-allowed fields."""
|
||||
|
||||
name: str | None = Field(None, min_length=2, max_length=255)
|
||||
description: str | None = None
|
||||
contact_email: EmailStr | None = None
|
||||
contact_phone: str | None = None
|
||||
website: str | None = None
|
||||
business_address: str | None = None
|
||||
tax_number: str | None = None
|
||||
|
||||
Reference in New Issue
Block a user