L1L2 gen1Gen2 kialakítása
This commit is contained in:
138
backend/app/schemas/commission.py
Normal file
138
backend/app/schemas/commission.py
Normal file
@@ -0,0 +1,138 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/schemas/commission.py
|
||||
"""
|
||||
Pydantic schemas for CommissionRule CRUD operations.
|
||||
|
||||
THOUGHT PROCESS:
|
||||
- CommissionRuleCreate: All fields required for creating a new rule.
|
||||
Uses Optional for type-specific fields (L1 vs L2).
|
||||
- CommissionRuleUpdate: All fields optional for partial updates.
|
||||
- CommissionRuleResponse: Full read model with from_attributes=True
|
||||
for ORM compatibility.
|
||||
- CommissionRuleListResponse: Paginated wrapper for admin listing.
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import date, datetime
|
||||
from typing import Optional, List
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class CommissionRuleTypeEnum(str, Enum):
|
||||
"""Jutalék típus: L1 = egyéni jutalom, L2 = céges jutalék."""
|
||||
L1_REWARD = "L1_REWARD"
|
||||
L2_COMMISSION = "L2_COMMISSION"
|
||||
|
||||
|
||||
class CommissionTierEnum(str, Enum):
|
||||
"""Jutalék szintek."""
|
||||
STANDARD = "STANDARD"
|
||||
VIP = "VIP"
|
||||
PLATINUM = "PLATINUM"
|
||||
ENTERPRISE = "ENTERPRISE"
|
||||
CONTRACTED = "CONTRACTED"
|
||||
|
||||
|
||||
class CommissionRuleCreate(BaseModel):
|
||||
"""Schema új jutalék szabály létrehozásához."""
|
||||
rule_type: CommissionRuleTypeEnum
|
||||
tier: CommissionTierEnum = CommissionTierEnum.STANDARD
|
||||
region_code: str = "GLOBAL"
|
||||
xp_reward: Optional[int] = None
|
||||
credit_reward: Optional[int] = None
|
||||
commission_percent: Optional[float] = None
|
||||
upline_commission_percent: Optional[float] = None
|
||||
renewal_commission_percent: Optional[float] = None
|
||||
commission_max_amount: Optional[float] = None
|
||||
is_campaign: bool = False
|
||||
start_date: Optional[date] = None
|
||||
end_date: Optional[date] = None
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class CommissionRuleUpdate(BaseModel):
|
||||
"""Schema meglévő jutalék szabály módosításához (minden mező opcionális)."""
|
||||
rule_type: Optional[CommissionRuleTypeEnum] = None
|
||||
tier: Optional[CommissionTierEnum] = None
|
||||
region_code: Optional[str] = None
|
||||
xp_reward: Optional[int] = None
|
||||
credit_reward: Optional[int] = None
|
||||
commission_percent: Optional[float] = None
|
||||
upline_commission_percent: Optional[float] = None
|
||||
renewal_commission_percent: Optional[float] = None
|
||||
commission_max_amount: Optional[float] = None
|
||||
is_campaign: Optional[bool] = None
|
||||
start_date: Optional[date] = None
|
||||
end_date: Optional[date] = None
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
|
||||
class CommissionRuleResponse(BaseModel):
|
||||
"""Schema jutalék szabály adatainak lekéréséhez."""
|
||||
id: int
|
||||
rule_type: CommissionRuleTypeEnum
|
||||
tier: CommissionTierEnum
|
||||
region_code: str
|
||||
xp_reward: Optional[int] = None
|
||||
credit_reward: Optional[int] = None
|
||||
commission_percent: Optional[float] = None
|
||||
upline_commission_percent: Optional[float] = None
|
||||
renewal_commission_percent: Optional[float] = None
|
||||
commission_max_amount: Optional[float] = None
|
||||
is_campaign: bool
|
||||
start_date: Optional[date] = None
|
||||
end_date: Optional[date] = None
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
is_active: bool
|
||||
created_by: Optional[int] = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class CommissionRuleListResponse(BaseModel):
|
||||
"""Paginated list response for admin commission rules."""
|
||||
items: List[CommissionRuleResponse]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int
|
||||
|
||||
|
||||
class CommissionDistributionRequest(BaseModel):
|
||||
"""
|
||||
Request schema for the 2-level MLM commission distribution engine.
|
||||
|
||||
When a referred company makes a purchase, this request triggers the
|
||||
distribution logic:
|
||||
- Gen1 (direct referrer) receives commission_percent
|
||||
- Gen2 (upline / Gen1's referrer) receives upline_commission_percent
|
||||
"""
|
||||
buyer_user_id: int = Field(..., description="The user ID who made the purchase")
|
||||
transaction_amount: float = Field(..., gt=0, description="The purchase/subscription amount")
|
||||
transaction_date: date = Field(..., description="Date of the transaction")
|
||||
region_code: str = Field("GLOBAL", max_length=10, description="Region code for rule matching")
|
||||
|
||||
|
||||
class CommissionDistributionItem(BaseModel):
|
||||
"""Single commission payout item for one level."""
|
||||
level: int = Field(..., description="1 = Gen1 (direct referrer), 2 = Gen2 (upline)")
|
||||
user_id: int = Field(..., description="The user ID receiving the commission")
|
||||
commission_percent: float = Field(..., description="The applied commission percentage")
|
||||
commission_amount: float = Field(..., description="The calculated commission amount")
|
||||
rule_id: int = Field(..., description="The CommissionRule ID that was applied")
|
||||
|
||||
|
||||
class CommissionDistributionResponse(BaseModel):
|
||||
"""
|
||||
Response schema for the 2-level MLM commission distribution.
|
||||
|
||||
Contains the payout breakdown for both Gen1 and Gen2 levels.
|
||||
"""
|
||||
transaction_amount: float
|
||||
items: List[CommissionDistributionItem]
|
||||
total_commission: float = Field(..., description="Sum of all commission payouts")
|
||||
@@ -35,12 +35,8 @@ class CategoryTreeNode(BaseModel):
|
||||
"""
|
||||
id: int
|
||||
key: str
|
||||
# --- 🏗️ i18n JSONB Migration (Phase 3) ---
|
||||
name_i18n: dict = Field(default_factory=dict, description="Lokalizált név (JSONB: {\"hu\": \"...\", \"en\": \"...\"})")
|
||||
description_i18n: Optional[dict] = Field(None, description="Lokalizált leírás (JSONB)")
|
||||
# --- [DEPRECATED] Old columns (Phase 3) ---
|
||||
name_hu: Optional[str] = Field(None, description="[DEPRECATED] Use name_i18n instead")
|
||||
name_en: Optional[str] = Field(None, description="[DEPRECATED] Use name_i18n instead")
|
||||
level: int = 0
|
||||
path: Optional[str] = None
|
||||
is_official: bool = True
|
||||
@@ -57,11 +53,7 @@ class CategoryAutocompleteItem(BaseModel):
|
||||
"""
|
||||
id: int
|
||||
key: str
|
||||
# --- 🏗️ i18n JSONB Migration (Phase 3) ---
|
||||
name_i18n: dict = Field(default_factory=dict, description="Lokalizált név (JSONB: {\"hu\": \"...\", \"en\": \"...\"})")
|
||||
# --- [DEPRECATED] Old columns (Phase 3) ---
|
||||
name_hu: Optional[str] = Field(None, description="[DEPRECATED] Use name_i18n instead")
|
||||
name_en: Optional[str] = Field(None, description="[DEPRECATED] Use name_i18n instead")
|
||||
level: int = 0
|
||||
path: Optional[str] = None
|
||||
parent_id: Optional[int] = None
|
||||
@@ -80,11 +72,7 @@ class ExpertiseCategoryOut(BaseModel):
|
||||
"""
|
||||
id: int
|
||||
key: str
|
||||
# --- 🏗️ i18n JSONB Migration (Phase 3) ---
|
||||
name_i18n: dict = Field(default_factory=dict, description="Lokalizált név (JSONB: {\"hu\": \"...\", \"en\": \"...\"})")
|
||||
# --- [DEPRECATED] Old columns (Phase 3) ---
|
||||
name_hu: Optional[str] = Field(None, description="[DEPRECATED] Use name_i18n instead")
|
||||
name_en: Optional[str] = Field(None, description="[DEPRECATED] Use name_i18n instead")
|
||||
category: Optional[str] = None
|
||||
level: int = 0
|
||||
parent_id: Optional[int] = None
|
||||
@@ -101,11 +89,7 @@ class CategoryInfo(BaseModel):
|
||||
szolgáltatásokat a kártyákon.
|
||||
"""
|
||||
id: int
|
||||
# --- 🏗️ i18n JSONB Migration (Phase 3) ---
|
||||
name_i18n: dict = Field(default_factory=dict, description="Lokalizált név (JSONB: {\"hu\": \"...\", \"en\": \"...\"})")
|
||||
# --- [DEPRECATED] Old columns (Phase 3) ---
|
||||
name_hu: Optional[str] = Field(None, description="[DEPRECATED] Use name_i18n instead")
|
||||
name_en: Optional[str] = Field(None, description="[DEPRECATED] Use name_i18n instead")
|
||||
level: int = 0
|
||||
key: str
|
||||
|
||||
|
||||
Reference in New Issue
Block a user