from pydantic import BaseModel, Field, field_validator from typing import Optional, Any from datetime import datetime # 如果需要 datetime 对象 # 如果你有 TimestampMixin,需要在这里导入或定义 # class TimestampMixin(BaseModel): # created_at: Optional[datetime] = None # updated_at: Optional[datetime] = None class CrmCustomerBase(BaseModel): # 保留 JSON 中存在的字段,并添加 alias customer_name: Optional[str] = Field(default=None, alias="customerName") province: Optional[str] = Field(default=None, alias="province") city: Optional[str] = Field(default=None, alias="city") area: Optional[str] = Field(default=None, alias="area") clinch_order: Optional[str] = Field(default=None, alias="clinchOrder") clinch_price: Optional[str] = Field(default=None, alias="clinchPrice") first_clinch_time: Optional[str] = Field(default=None, alias="firstClinchTime") last_clinch_time: Optional[str] = Field(default=None, alias="lastClinchTime") refund_order_times: Optional[str] = Field(default=None, alias="refundOrderTimes") refund_amount: Optional[str] = Field(default=None, alias="refundAmount") private_flag: Optional[int] = Field(default=None, alias="privateFlag") # JSON 中是 int touch_flag: Optional[int] = Field(default=None, alias="touchFlag") # JSON 中是 int open_id: Optional[str] = Field(default=None, alias="openId") xy_id: Optional[int] = Field(default=None, alias="xyId") # JSON 中是 int last_touch_time: Optional[str] = Field(default=None, alias="lastTouchTime") add_wechat_time: Optional[str] = Field(default=None, alias="addWeChatTime") mobile: Optional[str] = Field(default=None, alias="mobile") source: Optional[str] = Field(default=None, alias="source") we_chat_image: Optional[str] = Field(default=None, alias="weChatImage") cid: Optional[int] = Field(default=None, alias="cid") # JSON 中是 int last_trade_time: Optional[str] = Field(default=None, alias="lastTradeTime") private_jump: Optional[int] = Field(default=None, alias="privateJump") # JSON 中是 int lst_pay_ord_amt: Optional[float] = Field(default=None, alias="lstPayOrdAmt") # JSON 中是 float pay_avg_ord_amt_td: Optional[float] = Field(default=None, alias="payAvgOrdAmtTd") # JSON 中是 float refund_ord_rate_td: Optional[str] = Field(default=None, alias="refundOrdRateTd") # JSON 中是 string like '0.00%' touch_cnt_td: Optional[int] = Field(default=None, alias="touchCntTd") # JSON 中是 int pay_ord_day_cnt_1y: Optional[int] = Field(default=None, alias="payOrdDayCnt1y") # JSON 中是 int pay_same_item_max_cnt_td: Optional[int] = Field(default=None, alias="paySameItemMaxCntTd") # JSON 中是 int pay_diff_item_cnt_td: Optional[int] = Field(default=None, alias="payDiffItemCntTd") # JSON 中是 int pay_item_max_cnt_td: Optional[int] = Field(default=None, alias="payItemMaxCntTd") # JSON 中是 int user_type_90d: Optional[int] = Field(default=None, alias="userType90d") # JSON 中是 int # shop_id 和 shop_name 不在 JSON 中,但根据你的 Tortoise 模型定义,它们是 CrmCustomer 特有的,所以不加 alias shop_id: Optional[int] = Field(default=None) # 没有 alias,因为它在 JSON 中不存在 shop_name: Optional[str] = Field(default=None) # 没有 alias,因为它在 JSON 中不存在 class Config: populate_by_name = True # 允许使用别名或字段名创建实例 class CrmCustomerCreate(CrmCustomerBase): pass class CrmCustomerUpdate(BaseModel): # 这个模型的字段与 JSON 结构无关,保留原有定义 customer_name: Optional[str] = None customer_remark: Optional[str] = None customer_desc: Optional[str] = None mobiles: Optional[list[str]] = None labels: Optional[list[dict[str, Any]]] = None follow_member_name: Optional[str] = None follow_member_mobile: Optional[str] = None follow_member_dept: Optional[str] = None source_tips: Optional[str] = None cus_channel: Optional[str] = None class CrmCustomer(CrmCustomerBase): id: int = Field(alias="id") # JSON 中的 'id' 字段 data_source: Optional[str] = None last_updated_from: Optional[str] = None # updated_at: Optional[datetime] = Field(default=None, alias="updatedAt") # 如果需要 datetime 对象 updated_at: Optional[str] = Field(default=None, alias="updatedAt") # 使用 str 匹配 JSON 格式 class Config: from_attributes = True populate_by_name = True def convert_to_str(v) -> Optional[str]: """将输入值转换为字符串""" if v is None: return v return str(v) class CrmCustomerBase(BaseModel): # 对应 Tortoise 模型字段,并使用 JSON 中的键作为 alias cid: Optional[int] = Field(default=None, alias="cid", description="CID") customer_name: Optional[str] = Field(default=None, max_length=64, alias="customerName", description="客户名称") clinch_order: Optional[str] = Field(default=None, max_length=64, alias="clinchOrder", description="成交订单数") clinch_price: Optional[str] = Field(default=None, max_length=64, alias="clinchPrice", description="成交金额") first_clinch_time: Optional[datetime] = Field(default=None, alias="firstClinchTime", description="首次成交时间") last_clinch_time: Optional[datetime] = Field(default=None, alias="lastClinchTime", description="最后成交时间") refund_order_times: Optional[str] = Field(default=None, max_length=64, alias="refundOrderTimes", description="退款订单数") refund_amount: Optional[str] = Field(default=None, max_length=64, alias="refundAmount", description="退款金额") private_flag: Optional[bool] = Field(default=False, alias="privateFlag", description="是否私有") touch_flag: Optional[bool] = Field(default=False, alias="touchFlag", description="是否触达") open_id: Optional[str] = Field(default=None, max_length=64, alias="openId", description="微信openid") xy_id: Optional[int] = Field(default=None, alias="xyId", description="星云有客中的用户ID", index=True) last_touch_time: Optional[datetime] = Field(default=None, alias="lastTouchTime", description="最后触达时间") add_wechat_time: Optional[datetime] = Field(default=None, alias="addWeChatTime", description="添加微信时间") mobile: Optional[str] = Field(default=None, max_length=64, alias="mobile", description="手机号") source: Optional[str] = Field(default=None, max_length=64, alias="source", description="来源") we_chat_image: Optional[str] = Field(default=None, max_length=512, alias="weChatImage", description="微信头像") last_trade_time: Optional[datetime] = Field(default=None, alias="lastTradeTime", description="最后交易时间") private_jump: Optional[bool] = Field(default=False, alias="privateJump", description="是否跳转") lst_pay_ord_amt: Optional[str] = Field(default=None, alias="lstPayOrdAmt", description="最近一次支付金额") pay_avg_ord_amt_td: Optional[str] = Field(default=None, alias="payAvgOrdAmtTd", description="最近30天平均支付金额") refund_ord_rate_td: Optional[str] = Field(default=None, alias="refundOrdRateTd", description="最近30天退款订单数") touch_cnt_td: Optional[int] = Field(default=None, alias="touchCntTd", description="最近30天触达次数") pay_ord_day_cnt_1y: Optional[int] = Field(default=None, alias="payOrdDayCnt1y", description="最近一年支付订单数") pay_same_item_max_cnt_td: Optional[int] = Field(default=None, alias="paySameItemMaxCntTd", description="最近30天相同商品最大购买数量") pay_diff_item_cnt_td: Optional[int] = Field(default=None, alias="payDiffItemCntTd", description="最近30天不同商品购买数量") pay_item_max_cnt_td: Optional[int] = Field(default=None, alias="payItemMaxCntTd", description="最近30天最大购买商品数量") user_type_90d: Optional[int] = Field(default=None, alias="userType90d", description="最近90天用户类型") # shop_id 和 shop_name 在 JSON 中不存在,因此不设置 alias shop_id: Optional[int] = Field(default=None, description="店铺ID", index=True) shop_name: Optional[str] = Field(default=None, max_length=64, description="店铺名称") @field_validator('lst_pay_ord_amt', 'pay_avg_ord_amt_td', 'refund_ord_rate_td', mode='before') def validate_and_convert_to_str(cls, v): return convert_to_str(v) class Config: populate_by_name = True # 允许使用别名或字段名创建实例 class CrmCustomerCreate(CrmCustomerBase): pass class CrmCustomerUpdate(BaseModel): # 保留原始定义(如果需要) customer_name: Optional[str] = None customer_remark: Optional[str] = None customer_desc: Optional[str] = None mobiles: Optional[list[str]] = None labels: Optional[list[dict[str, Any]]] = None follow_member_name: Optional[str] = None follow_member_mobile: Optional[str] = None follow_member_dept: Optional[str] = None source_tips: Optional[str] = None cus_channel: Optional[str] = None class BaseCrmBindInfo(BaseModel): platform: Optional[str]= None customer_id: Optional[int]= None orderId: Optional[str]= None buyer_id: Optional[str]= None userid: Optional[str]= None name: Optional[str]= None nick_name: Optional[str]= None avatar: Optional[str]= None platform_id: Optional[str]= None need_confirm: Optional[bool]= None tenant_name: Optional[str]= None tenant_id: Optional[str]= None remark: Optional[str]= None extra: Optional[str]= None class CrmBindInfoCreate(BaseCrmBindInfo): id: Optional[int] = None pass class CrmBindInfoUpdate(BaseCrmBindInfo): id: int = Field(..., description="绑定信息ID") orderId: str = Field(..., description="订单ID") customer_id: int = Field(..., description="客户ID") name: str = Field(..., description="客户名称")