138 lines
5.7 KiB
Python
138 lines
5.7 KiB
Python
from typing import Optional
|
||
import enum
|
||
from sqlalchemy import Column, Integer, String, DECIMAL, DateTime, Enum, ForeignKey
|
||
from sqlalchemy.sql import func
|
||
from pydantic import BaseModel, Field, model_validator
|
||
from .database import Base
|
||
from sqlalchemy.orm import relationship, backref
|
||
from app.core.imageprocessor import process_image, ImageFormat
|
||
from app.core import utils
|
||
|
||
class CommunityStatus(str, enum.Enum):
|
||
UNOPEN = "UNOPEN" # 未运营
|
||
OPENING = "OPENING" # 已运营
|
||
|
||
# 数据库模型
|
||
class CommunityDB(Base):
|
||
__tablename__ = "communities"
|
||
|
||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||
name = Column(String(100), nullable=False)
|
||
address = Column(String(200), nullable=False)
|
||
longitude = Column(DECIMAL(9,6), nullable=False) # 经度,精确到小数点后6位
|
||
latitude = Column(DECIMAL(9,6), nullable=False) # 纬度,精确到小数点后6位
|
||
status = Column(Enum(CommunityStatus), nullable=False, default=CommunityStatus.UNOPEN)
|
||
qy_group_qrcode = Column(String(200), nullable=True) # 企业微信群二维码地址
|
||
webot_webhook = Column(String(200), nullable=True) # 企业微信机器人webhook
|
||
|
||
# 小区定价
|
||
base_price = Column(DECIMAL(10,2), nullable=False, default=3.0) # 基础费用
|
||
extra_package_price = Column(DECIMAL(10,2), nullable=False, default=1.0) # 额外包裹费用
|
||
extra_package_threshold = Column(Integer, nullable=False, default=2) # 额外收费阈值
|
||
more_station_price = Column(DECIMAL(10,2), nullable=False, default=2.0) # 多驿站加价
|
||
|
||
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
||
|
||
admin_id = Column(Integer, ForeignKey("users.userid"), nullable=True)
|
||
|
||
# 关联管理员 - 明确指定外键
|
||
admin = relationship("UserDB", foreign_keys=[admin_id], backref=backref("managed_communities", lazy="dynamic"))
|
||
|
||
# 通过映射表关联的社区分润
|
||
community_profit_sharing = relationship("CommunityProfitSharing", backref="community", uselist=False)
|
||
|
||
# 关联社区集合
|
||
community_set_mappings = relationship("CommunitySetMapping", backref="community")
|
||
|
||
@property
|
||
def optimized_qy_group_qrcode(self):
|
||
if self.qy_group_qrcode:
|
||
return process_image(self.qy_group_qrcode).thumbnail(800, 800).format(ImageFormat.WEBP).build()
|
||
return None
|
||
|
||
# Pydantic 模型
|
||
class CommunityCreate(BaseModel):
|
||
name: str = Field(..., max_length=100)
|
||
address: str = Field(..., max_length=200)
|
||
longitude: float = Field(..., ge=-180, le=180)
|
||
latitude: float = Field(..., ge=-90, le=90)
|
||
status: CommunityStatus = Field(default=CommunityStatus.UNOPEN)
|
||
qy_group_qrcode: Optional[str] = Field(None, max_length=200)
|
||
webot_webhook: Optional[str] = Field(None, max_length=200)
|
||
|
||
class CommunityUpdate(BaseModel):
|
||
name: Optional[str] = Field(None, max_length=100)
|
||
address: Optional[str] = Field(None, max_length=200)
|
||
longitude: Optional[float] = Field(None, ge=-180, le=180)
|
||
latitude: Optional[float] = Field(None, ge=-90, le=90)
|
||
status: Optional[CommunityStatus] = None
|
||
qy_group_qrcode: Optional[str] = Field(None, max_length=200)
|
||
webot_webhook: Optional[str] = Field(None, max_length=200)
|
||
base_price: Optional[float] = Field(None)
|
||
extra_package_price: Optional[float] = Field(None)
|
||
extra_package_threshold: Optional[int] = Field(None)
|
||
more_station_price: Optional[float] = Field(None)
|
||
admin_id: Optional[int] = Field(None)
|
||
|
||
class CommunityInfo(BaseModel):
|
||
id: int
|
||
name: str
|
||
address: str
|
||
latitude: float
|
||
longitude: float
|
||
admin_id: Optional[int] = None
|
||
status: CommunityStatus
|
||
qy_group_qrcode: Optional[str] = None
|
||
webot_webhook: Optional[str] = None
|
||
base_price: Optional[float] = None
|
||
extra_package_price: Optional[float] = None
|
||
extra_package_threshold: Optional[int] = None
|
||
more_station_price: Optional[float] = None
|
||
optimized_qy_group_qrcode: Optional[str] = None
|
||
distance: Optional[float] = None # 距离,单位:米
|
||
|
||
# 添加分润信息字段
|
||
profit_sharing: Optional[dict] = None
|
||
|
||
# 添加管理员信息字段
|
||
admin: Optional[object] = None
|
||
|
||
|
||
class Config:
|
||
from_attributes = True
|
||
|
||
@model_validator(mode='after')
|
||
def set_admin(self):
|
||
if hasattr(self, 'admin') and getattr(self, 'admin') is not None:
|
||
admin = getattr(self, 'admin')
|
||
# 检查admin是否已经是字典类型
|
||
if isinstance(admin, dict):
|
||
return self
|
||
|
||
# 处理UserDB对象
|
||
try:
|
||
self.admin = {
|
||
"id": admin.userid,
|
||
"nickname": admin.nickname if hasattr(admin, 'nickname') else None,
|
||
"phone": utils.CommonUtils.desensitize_phone(admin.phone) if hasattr(admin, 'phone') and admin.phone else None,
|
||
"avatar": admin.avatar if hasattr(admin, 'avatar') else None
|
||
}
|
||
except Exception as e:
|
||
# 如果处理失败,设置为None
|
||
self.admin = None
|
||
return self
|
||
|
||
@model_validator(mode='after')
|
||
def set_profit_sharing(self):
|
||
# 从ORM对象中获取分润信息
|
||
if hasattr(self, 'community_profit_sharing') and getattr(self, 'community_profit_sharing') is not None:
|
||
profit_sharing = getattr(self, 'community_profit_sharing')
|
||
self.profit_sharing = {
|
||
"id": profit_sharing.id,
|
||
"platform_rate": profit_sharing.platform_rate,
|
||
"partner_rate": profit_sharing.partner_rate,
|
||
"admin_rate": profit_sharing.admin_rate,
|
||
"delivery_rate": profit_sharing.delivery_rate
|
||
}
|
||
return self |