from sqlalchemy import Column, String, Integer, Float, DateTime, JSON, ForeignKey, Enum from sqlalchemy.dialects.mysql import DECIMAL from sqlalchemy.sql import func, select from pydantic import BaseModel, Field from typing import Optional, List from datetime import datetime from .database import Base from app.core.utils import CommonUtils from app.core.imageprocessor import process_image, ImageFormat import enum class MerchantStatus(str, enum.Enum): """商家状态枚举""" PENDING = "PENDING" # 申请中 ONLINE = "ONLINE" # 已上线 OFFLINE = "OFFLINE" # 已下线 # 数据库模型 class MerchantDB(Base): __tablename__ = "merchants" id = Column(Integer, primary_key=True, autoincrement=True) user_id = Column(Integer, ForeignKey("users.userid"), nullable=False) # 归属用户 community_id = Column(Integer, ForeignKey("communities.id"), nullable=False) # 所属小区 name = Column(String(100), nullable=False) business_hours = Column(String(100), nullable=False) # 营业时间,如 "09:00-22:00" address = Column(String(200), nullable=False) longitude = Column(DECIMAL(9, 6), nullable=False) # 经度,精确到小数点后6位 latitude = Column(DECIMAL(9, 6), nullable=False) # 纬度,精确到小数点后6位 phone = Column(String(20), nullable=False) brand_image_url = Column(String(200)) # 品牌图片地址 pay_gift_points_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 支付赠送积分比例,默认0% pay_share_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 在线买单分润比例,默认0% status = Column(Enum(MerchantStatus), default=MerchantStatus.PENDING, nullable=False) # 商家状态 create_time = Column(DateTime(timezone=True), server_default=func.now()) update_time = Column(DateTime(timezone=True), onupdate=func.now()) category_id = Column(Integer, ForeignKey("merchant_categories.id"), nullable=True) @property def optimized_brand_image_url(self): return process_image(self.brand_image_url).thumbnail(width=800, height=800).format(ImageFormat.WEBP).build() class MerchantCreate(BaseModel): user_id: int community_id: int # 所属小区ID name: str = Field(..., max_length=100) business_hours: str = Field(..., max_length=100) address: str = Field(..., max_length=200) longitude: float = Field(..., ge=-180, le=180, description="经度") latitude: float = Field(..., ge=-90, le=90, description="纬度") phone: str = Field(..., max_length=20, pattern=r'^\d+$') pay_gift_points_rate: Optional[float] = Field(10.00, ge=0, le=100) # 支付赠送积分比例 pay_share_rate: Optional[float] = Field(0.00, ge=0, le=100) # 在线买单分润比例 brand_image_url: Optional[str] = Field(None, max_length=200) category_id: Optional[int] = None status: Optional[MerchantStatus] = Field(MerchantStatus.PENDING, description="商家状态") class MerchantApply(BaseModel): name: str = Field(..., max_length=100) community_id: int = Field(..., ge=0) # 所属小区ID business_hours: str = Field(..., max_length=100) address: str = Field(..., max_length=200) longitude: float = Field(..., ge=-180, le=180, description="经度") latitude: float = Field(..., ge=-90, le=90, description="纬度") phone: str = Field(..., max_length=20, pattern=r'^\d+$') brand_image_url: str = Field(..., max_length=200) category_id: int = Field(..., ge=0) pay_share_rate: float = Field(0.00, ge=0, le=100) # 在线买单分润比例 license_image_url: str = Field(..., max_length=200) id_front_url: str = Field(..., max_length=200) id_back_url: str = Field(..., max_length=200) class MerchantUpdate(BaseModel): user_id: Optional[int] = None community_id: Optional[int] = None # 所属小区ID name: Optional[str] = Field(None, max_length=100) business_hours: Optional[str] = Field(None, max_length=100) address: Optional[str] = Field(None, max_length=200) longitude: Optional[float] = Field(None, ge=-180, le=180, description="经度") latitude: Optional[float] = Field(None, ge=-90, le=90, description="纬度") phone: Optional[str] = Field(None, max_length=20, pattern=r'^\d+$') pay_gift_points_rate: Optional[float] = Field(None, ge=0, le=100) # 支付赠送积分比例 pay_share_rate: Optional[float] = Field(None, ge=0, le=100) # 在线买单分润比例 brand_image_url: Optional[str] = Field(None, max_length=200) category_id: Optional[int] = None status: Optional[MerchantStatus] = None class MerchantInfo(BaseModel): id: int user_id: int community_id: int # 所属小区ID community_name: Optional[str] = None # 用于关联查询显示小区名称 user_phone: Optional[str] = None user_nickname: Optional[str] = None online_pay_count: Optional[int] = 0 name: str business_hours: str address: str longitude: float latitude: float distance: Optional[int] = None # 距离(米) phone: str pay_gift_points_rate: float pay_share_rate: float brand_image_url: Optional[str] = None optimized_brand_image_url: Optional[str] = None status: MerchantStatus # 商家状态 create_time: datetime update_time: Optional[datetime] distance: Optional[int] = None # 距离(米) category_id: Optional[int] = None category_name: Optional[str] = None # 用于关联查询显示分类名称 class Config: from_attributes = True