商品增加相关字段。
This commit is contained in:
parent
ba3e00aab6
commit
03bc65e551
@ -9,15 +9,165 @@ from app.models.merchant import (
|
|||||||
MerchantInfo)
|
MerchantInfo)
|
||||||
from app.models.merchant_category import MerchantCategoryDB
|
from app.models.merchant_category import MerchantCategoryDB
|
||||||
from app.models.database import get_db
|
from app.models.database import get_db
|
||||||
from app.api.deps import get_admin_user
|
from app.api.deps import get_admin_user, get_current_user
|
||||||
from app.models.user import UserDB
|
from app.models.user import UserDB
|
||||||
from app.core.response import success_response, error_response, ResponseModel
|
from app.core.response import success_response, error_response, ResponseModel
|
||||||
from app.models.merchant_pay_order import MerchantPayOrderDB
|
from app.models.merchant_pay_order import MerchantPayOrderDB
|
||||||
from sqlalchemy.sql import func, desc
|
from sqlalchemy.sql import func, desc
|
||||||
from app.models.merchant_product import MerchantProductDB, ProductStatus
|
from app.models.merchant_product import MerchantProductDB, ProductStatus
|
||||||
|
from app.models.merchant import MerchantStatus, MerchantApply
|
||||||
|
from app.models.merchant_auth import MerchantAuthDB, MerchantAuthInfo
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.get("/apply", response_model=ResponseModel)
|
||||||
|
async def get_merchant_apply(
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
user: UserDB = Depends(get_current_user)
|
||||||
|
):
|
||||||
|
"""获取商家申请信息"""
|
||||||
|
merchant = db.query(MerchantDB).filter(MerchantDB.user_id == user.userid).first()
|
||||||
|
|
||||||
|
if not merchant:
|
||||||
|
return error_response(code=404, message="商家申请信息不存在")
|
||||||
|
|
||||||
|
auth = db.query(MerchantAuthDB).filter(MerchantAuthDB.merchant_id == merchant.id).first()
|
||||||
|
|
||||||
|
return success_response(data={
|
||||||
|
"merchant": MerchantInfo.model_validate(merchant),
|
||||||
|
"auth": MerchantAuthInfo.model_validate(auth)
|
||||||
|
})
|
||||||
|
|
||||||
|
@router.put("/apply", response_model=ResponseModel)
|
||||||
|
async def update_merchant_apply(
|
||||||
|
apply: MerchantApply,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
user: UserDB = Depends(get_current_user)
|
||||||
|
):
|
||||||
|
"""更新商家申请信息"""
|
||||||
|
merchant = db.query(MerchantDB).filter(MerchantDB.user_id == user.userid).first()
|
||||||
|
if not merchant:
|
||||||
|
return error_response(code=404, message="商家不存在")
|
||||||
|
|
||||||
|
merchant.name = apply.name
|
||||||
|
merchant.business_hours = apply.business_hours
|
||||||
|
merchant.address = apply.address
|
||||||
|
merchant.longitude = apply.longitude
|
||||||
|
merchant.latitude = apply.latitude
|
||||||
|
merchant.phone = apply.phone
|
||||||
|
merchant.brand_image_url = apply.brand_image_url
|
||||||
|
merchant.category_id = apply.category_id
|
||||||
|
merchant.pay_share_rate = apply.pay_share_rate
|
||||||
|
|
||||||
|
auth = db.query(MerchantAuthDB).filter(MerchantAuthDB.merchant_id == merchant.id).first()
|
||||||
|
if auth:
|
||||||
|
auth.license_image_url = apply.license_image_url
|
||||||
|
auth.id_front_url = apply.id_front_url
|
||||||
|
auth.id_back_url = apply.id_back_url
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.refresh(merchant)
|
||||||
|
return success_response(data=MerchantInfo.model_validate(merchant))
|
||||||
|
|
||||||
|
@router.post("/apply", response_model=ResponseModel)
|
||||||
|
async def apply_merchant(
|
||||||
|
apply: MerchantApply,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
user: UserDB = Depends(get_current_user)
|
||||||
|
):
|
||||||
|
"""申请成为商家"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 创建商家
|
||||||
|
merchant_apply = MerchantDB(
|
||||||
|
user_id=user.userid,
|
||||||
|
name=apply.name,
|
||||||
|
business_hours=apply.business_hours,
|
||||||
|
address=apply.address,
|
||||||
|
longitude=apply.longitude,
|
||||||
|
latitude=apply.latitude,
|
||||||
|
phone=apply.phone,
|
||||||
|
brand_image_url=apply.brand_image_url,
|
||||||
|
category_id=apply.category_id,
|
||||||
|
pay_share_rate=apply.pay_share_rate,
|
||||||
|
status=MerchantStatus.PENDING
|
||||||
|
)
|
||||||
|
db.add(merchant_apply)
|
||||||
|
db.refresh(merchant_apply)
|
||||||
|
|
||||||
|
# 创建商家认证信息
|
||||||
|
auth = db.query(MerchantAuthDB).filter(MerchantAuthDB.merchant_id == merchant_apply.id).first()
|
||||||
|
if not auth:
|
||||||
|
merchant_auth = MerchantAuthDB(
|
||||||
|
merchant_id=merchant_apply.id,
|
||||||
|
license_image_url=apply.license_image_url,
|
||||||
|
id_front_url=apply.id_front_url,
|
||||||
|
id_back_url=apply.id_back_url
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
auth.license_image_url = apply.license_image_url
|
||||||
|
auth.id_front_url = apply.id_front_url
|
||||||
|
auth.id_back_url = apply.id_back_url
|
||||||
|
db.add(merchant_auth)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
return success_response()
|
||||||
|
except Exception as e:
|
||||||
|
db.rollback()
|
||||||
|
return error_response(code=500, message=f"申请失败: {str(e)}")
|
||||||
|
|
||||||
|
@router.put("/{merchant_id}/approve", response_model=ResponseModel)
|
||||||
|
async def approve_merchant(
|
||||||
|
merchant_id: int,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
admin: UserDB = Depends(get_admin_user)
|
||||||
|
):
|
||||||
|
"""审核通过商家申请(管理员)"""
|
||||||
|
merchant = db.query(MerchantDB).filter(MerchantDB.id == merchant_id).first()
|
||||||
|
if not merchant:
|
||||||
|
return error_response(code=404, message="商家不存在")
|
||||||
|
|
||||||
|
merchant.status = MerchantStatus.OFFLINE
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.refresh(merchant)
|
||||||
|
return success_response(data=merchant)
|
||||||
|
|
||||||
|
@router.put("/{merchant_id}/offline", response_model=ResponseModel)
|
||||||
|
async def offline_merchant(
|
||||||
|
merchant_id: int,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
admin: UserDB = Depends(get_admin_user)
|
||||||
|
):
|
||||||
|
"""下线商家(管理员)"""
|
||||||
|
merchant = db.query(MerchantDB).filter(MerchantDB.id == merchant_id).first()
|
||||||
|
if not merchant:
|
||||||
|
return error_response(code=404, message="商家不存在")
|
||||||
|
|
||||||
|
merchant.status = MerchantStatus.OFFLINE
|
||||||
|
db.commit()
|
||||||
|
db.refresh(merchant)
|
||||||
|
return success_response(data=merchant)
|
||||||
|
|
||||||
|
@router.get("/{merchant_id}/audit", response_model=ResponseModel)
|
||||||
|
async def get_merchant_audit(
|
||||||
|
merchant_id: int,
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""获取商家审核信息"""
|
||||||
|
merchant = db.query(MerchantDB).filter(MerchantDB.id == merchant_id).first()
|
||||||
|
if not merchant:
|
||||||
|
return error_response(code=404, message="商家不存在")
|
||||||
|
|
||||||
|
auth = db.query(MerchantAuthDB).filter(MerchantAuthDB.merchant_id == merchant_id).first()
|
||||||
|
if not auth:
|
||||||
|
return error_response(code=404, message="商家认证信息不存在")
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"merchant": MerchantInfo.model_validate(merchant),
|
||||||
|
"auth": MerchantAuthInfo.model_validate(auth)
|
||||||
|
}
|
||||||
|
return success_response(data=result)
|
||||||
|
|
||||||
@router.post("", response_model=ResponseModel)
|
@router.post("", response_model=ResponseModel)
|
||||||
async def create_merchant(
|
async def create_merchant(
|
||||||
merchant: MerchantCreate,
|
merchant: MerchantCreate,
|
||||||
@ -147,6 +297,7 @@ async def list_merchants(
|
|||||||
longitude: Optional[float] = None,
|
longitude: Optional[float] = None,
|
||||||
latitude: Optional[float] = None,
|
latitude: Optional[float] = None,
|
||||||
category_id: Optional[int] = None,
|
category_id: Optional[int] = None,
|
||||||
|
status: Optional[MerchantStatus] = None,
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 20,
|
limit: int = 20,
|
||||||
db: Session = Depends(get_db)
|
db: Session = Depends(get_db)
|
||||||
@ -165,6 +316,9 @@ async def list_merchants(
|
|||||||
MerchantDB.user_id == UserDB.userid
|
MerchantDB.user_id == UserDB.userid
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if status is not None:
|
||||||
|
query = query.filter(MerchantDB.status == status)
|
||||||
|
|
||||||
# 添加分类过滤
|
# 添加分类过滤
|
||||||
if category_id is not None:
|
if category_id is not None:
|
||||||
query = query.filter(MerchantDB.category_id == category_id)
|
query = query.filter(MerchantDB.category_id == category_id)
|
||||||
|
|||||||
@ -9,16 +9,34 @@ from app.models.user import UserDB
|
|||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.post("/upload_merchant_auth_image", response_model=ResponseModel)
|
||||||
|
async def upload_merchant_auth_image(
|
||||||
|
image: UploadFile = File(...),
|
||||||
|
current_user: UserDB = Depends(get_current_user)
|
||||||
|
):
|
||||||
|
"""上传商家认证图片"""
|
||||||
|
if not image.content_type.startswith('image/'):
|
||||||
|
return error_response(code=400, message="只能上传图片文件")
|
||||||
|
|
||||||
|
try:
|
||||||
|
folder = f"merchant_auth/{current_user.userid}"
|
||||||
|
url = await qcloud_manager.upload_file(image, folder)
|
||||||
|
return success_response(data=url)
|
||||||
|
except Exception as e:
|
||||||
|
return error_response(code=500, message=f"上传失败: {str(e)}")
|
||||||
|
|
||||||
@router.post("/image", response_model=ResponseModel)
|
@router.post("/image", response_model=ResponseModel)
|
||||||
async def upload_image(
|
async def upload_image(
|
||||||
file: UploadFile = File(...),
|
file: UploadFile = File(...),
|
||||||
|
current_user: UserDB = Depends(get_current_user)
|
||||||
):
|
):
|
||||||
"""上传单张图片"""
|
"""上传单张图片"""
|
||||||
if not file.content_type.startswith('image/'):
|
if not file.content_type.startswith('image/'):
|
||||||
return error_response(code=400, message="只能上传图片文件")
|
return error_response(code=400, message="只能上传图片文件")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
url = await qcloud_manager.upload_file(file)
|
folder = f"uploads/{current_user.userid}"
|
||||||
|
url = await qcloud_manager.upload_file(file, folder)
|
||||||
return success_response(data=UploadResponse(url=url))
|
return success_response(data=UploadResponse(url=url))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return error_response(code=500, message=f"上传失败: {str(e)}")
|
return error_response(code=500, message=f"上传失败: {str(e)}")
|
||||||
@ -26,6 +44,7 @@ async def upload_image(
|
|||||||
@router.post("/images", response_model=ResponseModel)
|
@router.post("/images", response_model=ResponseModel)
|
||||||
async def upload_images(
|
async def upload_images(
|
||||||
files: List[UploadFile] = File(...),
|
files: List[UploadFile] = File(...),
|
||||||
|
current_user: UserDB = Depends(get_current_user)
|
||||||
):
|
):
|
||||||
"""上传多张图片"""
|
"""上传多张图片"""
|
||||||
if len(files) > 5:
|
if len(files) > 5:
|
||||||
@ -36,7 +55,8 @@ async def upload_images(
|
|||||||
for file in files:
|
for file in files:
|
||||||
if not file.content_type.startswith('image/'):
|
if not file.content_type.startswith('image/'):
|
||||||
return error_response(code=400, message="只能上传图片文件")
|
return error_response(code=400, message="只能上传图片文件")
|
||||||
url = await qcloud_manager.upload_file(file)
|
folder = f"uploads/{current_user.userid}"
|
||||||
|
url = await qcloud_manager.upload_file(file, folder)
|
||||||
urls.append(url)
|
urls.append(url)
|
||||||
return success_response(data=MultiUploadResponse(urls=urls))
|
return success_response(data=MultiUploadResponse(urls=urls))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from sqlalchemy import Column, String, Integer, Float, DateTime, JSON, ForeignKey
|
from sqlalchemy import Column, String, Integer, Float, DateTime, JSON, ForeignKey, Enum
|
||||||
from sqlalchemy.dialects.mysql import DECIMAL
|
from sqlalchemy.dialects.mysql import DECIMAL
|
||||||
from sqlalchemy.sql import func, select
|
from sqlalchemy.sql import func, select
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
@ -7,6 +7,13 @@ from datetime import datetime
|
|||||||
from .database import Base
|
from .database import Base
|
||||||
from app.core.utils import CommonUtils
|
from app.core.utils import CommonUtils
|
||||||
from app.core.imageprocessor import process_image, ImageFormat
|
from app.core.imageprocessor import process_image, ImageFormat
|
||||||
|
import enum
|
||||||
|
|
||||||
|
class MerchantStatus(str, enum.Enum):
|
||||||
|
"""商家状态枚举"""
|
||||||
|
PENDING = "PENDING" # 申请中
|
||||||
|
ONLINE = "ONLINE" # 已上线
|
||||||
|
OFFLINE = "OFFLINE" # 已下线
|
||||||
|
|
||||||
# 数据库模型
|
# 数据库模型
|
||||||
class MerchantDB(Base):
|
class MerchantDB(Base):
|
||||||
@ -23,6 +30,7 @@ class MerchantDB(Base):
|
|||||||
brand_image_url = Column(String(200)) # 品牌图片地址
|
brand_image_url = Column(String(200)) # 品牌图片地址
|
||||||
pay_gift_points_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 支付赠送积分比例,默认0%
|
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%
|
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())
|
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
||||||
category_id = Column(Integer, ForeignKey("merchant_categories.id"), nullable=True)
|
category_id = Column(Integer, ForeignKey("merchant_categories.id"), nullable=True)
|
||||||
@ -43,6 +51,22 @@ class MerchantCreate(BaseModel):
|
|||||||
pay_share_rate: Optional[float] = Field(0.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)
|
brand_image_url: Optional[str] = Field(None, max_length=200)
|
||||||
category_id: Optional[int] = None
|
category_id: Optional[int] = None
|
||||||
|
status: Optional[MerchantStatus] = Field(MerchantStatus.PENDING, description="商家状态")
|
||||||
|
|
||||||
|
class MerchantApply(BaseModel):
|
||||||
|
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+$')
|
||||||
|
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):
|
class MerchantUpdate(BaseModel):
|
||||||
user_id: Optional[int] = None
|
user_id: Optional[int] = None
|
||||||
@ -56,6 +80,7 @@ class MerchantUpdate(BaseModel):
|
|||||||
pay_share_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)
|
brand_image_url: Optional[str] = Field(None, max_length=200)
|
||||||
category_id: Optional[int] = None
|
category_id: Optional[int] = None
|
||||||
|
status: Optional[MerchantStatus] = None
|
||||||
|
|
||||||
class MerchantInfo(BaseModel):
|
class MerchantInfo(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
@ -74,6 +99,7 @@ class MerchantInfo(BaseModel):
|
|||||||
pay_share_rate: float
|
pay_share_rate: float
|
||||||
brand_image_url: Optional[str] = None
|
brand_image_url: Optional[str] = None
|
||||||
optimized_brand_image_url: Optional[str] = None
|
optimized_brand_image_url: Optional[str] = None
|
||||||
|
status: MerchantStatus # 商家状态
|
||||||
create_time: datetime
|
create_time: datetime
|
||||||
update_time: Optional[datetime]
|
update_time: Optional[datetime]
|
||||||
distance: Optional[int] = None # 距离(米)
|
distance: Optional[int] = None # 距离(米)
|
||||||
|
|||||||
46
app/models/merchant_auth.py
Normal file
46
app/models/merchant_auth.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey
|
||||||
|
from sqlalchemy.sql import func
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import Optional
|
||||||
|
from datetime import datetime
|
||||||
|
from .database import Base
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
|
class MerchantAuthDB(Base):
|
||||||
|
"""商家认证信息表"""
|
||||||
|
__tablename__ = "merchant_auths"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
|
merchant_id = Column(Integer, ForeignKey("merchants.id"), nullable=False, unique=True) # 商家ID,一个商家只能有一条认证信息
|
||||||
|
license_image_url = Column(String(200), nullable=False) # 营业执照图片URL
|
||||||
|
id_front_url = Column(String(200), nullable=False) # 身份证正面图片URL
|
||||||
|
id_back_url = Column(String(200), nullable=False) # 身份证背面图片URL
|
||||||
|
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
|
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
|
# 关联商家
|
||||||
|
merchant = relationship("MerchantDB", backref="auth_info")
|
||||||
|
|
||||||
|
# Pydantic 模型,用于API请求和响应
|
||||||
|
class MerchantAuthCreate(BaseModel):
|
||||||
|
merchant_id: int = Field(..., description="商家ID")
|
||||||
|
license_image_url: str = Field(..., description="营业执照图片URL")
|
||||||
|
id_front_url: str = Field(..., description="身份证正面图片URL")
|
||||||
|
id_back_url: str = Field(..., description="身份证背面图片URL")
|
||||||
|
|
||||||
|
class MerchantAuthUpdate(BaseModel):
|
||||||
|
license_image_url: Optional[str] = Field(None, description="营业执照图片URL")
|
||||||
|
id_front_url: Optional[str] = Field(None, description="身份证正面图片URL")
|
||||||
|
id_back_url: Optional[str] = Field(None, description="身份证背面图片URL")
|
||||||
|
|
||||||
|
class MerchantAuthInfo(BaseModel):
|
||||||
|
id: int
|
||||||
|
merchant_id: int
|
||||||
|
license_image_url: str
|
||||||
|
id_front_url: str
|
||||||
|
id_back_url: str
|
||||||
|
create_time: datetime
|
||||||
|
update_time: Optional[datetime] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
from_attributes = True
|
||||||
@ -1,9 +1,9 @@
|
|||||||
from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum, Boolean
|
from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum, Boolean, Date, Text
|
||||||
from sqlalchemy.dialects.mysql import DECIMAL
|
from sqlalchemy.dialects.mysql import DECIMAL
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
from datetime import datetime
|
from datetime import datetime, date
|
||||||
from .database import Base
|
from .database import Base
|
||||||
import enum
|
import enum
|
||||||
from app.core.utils import CommonUtils
|
from app.core.utils import CommonUtils
|
||||||
@ -13,6 +13,16 @@ class ProductStatus(str, enum.Enum):
|
|||||||
LISTING = "LISTING" # 上架
|
LISTING = "LISTING" # 上架
|
||||||
UNLISTING = "UNLISTING" # 下架
|
UNLISTING = "UNLISTING" # 下架
|
||||||
|
|
||||||
|
class DeliveryType(str, enum.Enum):
|
||||||
|
"""配送类型枚举"""
|
||||||
|
DELIVERY = "DELIVERY" # 配送到家
|
||||||
|
PICKUP = "PICKUP" # 自提
|
||||||
|
|
||||||
|
class DeliveryTimeType(str, enum.Enum):
|
||||||
|
"""配送时间类型枚举"""
|
||||||
|
IMMEDIATE = "IMMEDIATE" # 立即送
|
||||||
|
SCHEDULED = "SCHEDULED" # 定时送
|
||||||
|
|
||||||
class MerchantProductDB(Base):
|
class MerchantProductDB(Base):
|
||||||
__tablename__ = "merchant_products"
|
__tablename__ = "merchant_products"
|
||||||
|
|
||||||
@ -27,6 +37,14 @@ class MerchantProductDB(Base):
|
|||||||
purchase_limit = Column(Integer, nullable=False, default=0) # 限购次数,0表示不限购
|
purchase_limit = Column(Integer, nullable=False, default=0) # 限购次数,0表示不限购
|
||||||
gift_points_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 购买赠送积分比例,默认0%
|
gift_points_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 购买赠送积分比例,默认0%
|
||||||
promotion_text = Column(String(100)) # 促销文本
|
promotion_text = Column(String(100)) # 促销文本
|
||||||
|
product_detail = Column(Text, nullable=True) # 产品详细描述,Markdown格式
|
||||||
|
purchase_note = Column(Text, nullable=True) # 购买须知,用于提供商品购买相关注意事项
|
||||||
|
qty = Column(Integer, nullable=False, default=0) # 库存
|
||||||
|
is_sellout = Column(Boolean, nullable=False, default=False) # 是否售罄
|
||||||
|
delivery_type = Column(Enum(DeliveryType), nullable=False, default=DeliveryType.DELIVERY) # 配送类型
|
||||||
|
pickup_place = Column(String(200), nullable=True) # 自提点
|
||||||
|
delivery_time_type = Column(Enum(DeliveryTimeType), nullable=False, default=DeliveryTimeType.IMMEDIATE) # 配送时间类型
|
||||||
|
delivery_date = Column(Date, nullable=True) # 配送日期,仅对定时送有效
|
||||||
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
||||||
status = Column(Enum(ProductStatus), nullable=False, default=ProductStatus.UNLISTING)
|
status = Column(Enum(ProductStatus), nullable=False, default=ProductStatus.UNLISTING)
|
||||||
@ -45,6 +63,14 @@ class MerchantProductCreate(BaseModel):
|
|||||||
settlement_amount: float = Field(..., gt=0)
|
settlement_amount: float = Field(..., gt=0)
|
||||||
tags: str = Field("", max_length=200)
|
tags: str = Field("", max_length=200)
|
||||||
purchase_limit: int = Field(0, ge=0) # 限购次数,默认0表示不限购
|
purchase_limit: int = Field(0, ge=0) # 限购次数,默认0表示不限购
|
||||||
|
product_detail: Optional[str] = None # 产品详细描述,Markdown格式
|
||||||
|
purchase_note: Optional[str] = None # 购买须知,用于提供商品购买相关注意事项
|
||||||
|
qty: int = Field(0, ge=0) # 库存
|
||||||
|
is_sellout: bool = Field(False) # 是否售罄
|
||||||
|
delivery_type: DeliveryType = Field(DeliveryType.DELIVERY) # 配送类型
|
||||||
|
pickup_place: Optional[str] = Field(None, max_length=200) # 自提点
|
||||||
|
delivery_time_type: DeliveryTimeType = Field(DeliveryTimeType.IMMEDIATE) # 配送时间类型
|
||||||
|
delivery_date: Optional[date] = Field(None) # 配送日期
|
||||||
status: ProductStatus = ProductStatus.UNLISTING
|
status: ProductStatus = ProductStatus.UNLISTING
|
||||||
promotion_text: Optional[str] = Field(None, max_length=100) # 促销文本
|
promotion_text: Optional[str] = Field(None, max_length=100) # 促销文本
|
||||||
gift_points_rate: Optional[float] = Field(10.00, ge=0, le=100) # 购买赠送积分比例
|
gift_points_rate: Optional[float] = Field(10.00, ge=0, le=100) # 购买赠送积分比例
|
||||||
@ -57,6 +83,14 @@ class MerchantProductUpdate(BaseModel):
|
|||||||
settlement_amount: Optional[float] = Field(None, gt=0)
|
settlement_amount: Optional[float] = Field(None, gt=0)
|
||||||
tags: Optional[str] = Field(None, max_length=200)
|
tags: Optional[str] = Field(None, max_length=200)
|
||||||
purchase_limit: Optional[int] = Field(None, ge=0) # 限购次数,可选字段
|
purchase_limit: Optional[int] = Field(None, ge=0) # 限购次数,可选字段
|
||||||
|
product_detail: Optional[str] = None # 产品详细描述,Markdown格式
|
||||||
|
purchase_note: Optional[str] = None # 购买须知,用于提供商品购买相关注意事项
|
||||||
|
qty: Optional[int] = Field(None, ge=0) # 库存
|
||||||
|
is_sellout: Optional[bool] = None # 是否售罄
|
||||||
|
delivery_type: Optional[DeliveryType] = None # 配送类型
|
||||||
|
pickup_place: Optional[str] = Field(None, max_length=200) # 自提点
|
||||||
|
delivery_time_type: Optional[DeliveryTimeType] = None # 配送时间类型
|
||||||
|
delivery_date: Optional[date] = None # 配送日期
|
||||||
status: Optional[ProductStatus] = None
|
status: Optional[ProductStatus] = None
|
||||||
promotion_text: Optional[str] = Field(None, max_length=100) # 促销文本
|
promotion_text: Optional[str] = Field(None, max_length=100) # 促销文本
|
||||||
gift_points_rate: Optional[float] = Field(None, ge=0, le=100) # 购买赠送积分比例
|
gift_points_rate: Optional[float] = Field(None, ge=0, le=100) # 购买赠送积分比例
|
||||||
@ -73,6 +107,14 @@ class MerchantProductInfo(BaseModel):
|
|||||||
settlement_amount: float
|
settlement_amount: float
|
||||||
tags: str
|
tags: str
|
||||||
purchase_limit: int # 限购次数
|
purchase_limit: int # 限购次数
|
||||||
|
product_detail: Optional[str] = None # 产品详细描述,Markdown格式
|
||||||
|
purchase_note: Optional[str] = None # 购买须知,用于提供商品购买相关注意事项
|
||||||
|
qty: int # 库存
|
||||||
|
is_sellout: bool # 是否售罄
|
||||||
|
delivery_type: DeliveryType # 配送类型
|
||||||
|
pickup_place: Optional[str] = None # 自提点
|
||||||
|
delivery_time_type: DeliveryTimeType # 配送时间类型
|
||||||
|
delivery_date: Optional[date] = None # 配送日期
|
||||||
gift_points_rate: float
|
gift_points_rate: float
|
||||||
promotion_text: Optional[str] = None # 促销文本
|
promotion_text: Optional[str] = None # 促销文本
|
||||||
create_time: datetime
|
create_time: datetime
|
||||||
|
|||||||
37
app/sql/v1.1.sql
Normal file
37
app/sql/v1.1.sql
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
-- 1. 添加库存字段
|
||||||
|
ALTER TABLE merchant_products
|
||||||
|
ADD COLUMN qty INT NOT NULL DEFAULT 0 COMMENT '库存数量';
|
||||||
|
|
||||||
|
-- 2. 添加是否售罄字段
|
||||||
|
ALTER TABLE merchant_products
|
||||||
|
ADD COLUMN is_sellout TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否售罄,0-未售罄,1-已售罄';
|
||||||
|
|
||||||
|
-- 3. 添加配送类型字段(使用MySQL的ENUM类型)
|
||||||
|
ALTER TABLE merchant_products
|
||||||
|
ADD COLUMN delivery_type ENUM('DELIVERY', 'PICKUP') NOT NULL DEFAULT 'DELIVERY' COMMENT '配送类型,DELIVERY-配送到家,PICKUP-自提';
|
||||||
|
|
||||||
|
-- 4. 添加自提点字段
|
||||||
|
ALTER TABLE merchant_products
|
||||||
|
ADD COLUMN pickup_place VARCHAR(200) NULL COMMENT '自提点';
|
||||||
|
|
||||||
|
-- 5. 添加配送时间类型字段(使用MySQL的ENUM类型)
|
||||||
|
ALTER TABLE merchant_products
|
||||||
|
ADD COLUMN delivery_time_type ENUM('IMMEDIATE', 'SCHEDULED') NOT NULL DEFAULT 'IMMEDIATE' COMMENT '配送时间类型,IMMEDIATE-立即送,SCHEDULED-定时送';
|
||||||
|
|
||||||
|
-- 6. 添加配送日期字段
|
||||||
|
ALTER TABLE merchant_products
|
||||||
|
ADD COLUMN delivery_date DATE NULL COMMENT '配送日期,仅对定时送有效';
|
||||||
|
|
||||||
|
-- 7. 创建索引以提高查询效率
|
||||||
|
CREATE INDEX idx_merchant_products_delivery_type ON merchant_products(delivery_type);
|
||||||
|
CREATE INDEX idx_merchant_products_delivery_time_type ON merchant_products(delivery_time_type);
|
||||||
|
CREATE INDEX idx_merchant_products_is_sellout ON merchant_products(is_sellout);
|
||||||
|
|
||||||
|
|
||||||
|
-- 为merchant_products表添加product_detail字段
|
||||||
|
ALTER TABLE merchant_products
|
||||||
|
ADD COLUMN product_detail TEXT COMMENT '产品详细描述,Markdown格式';
|
||||||
|
|
||||||
|
-- 为merchant_products表添加purchase_note字段
|
||||||
|
ALTER TABLE merchant_products
|
||||||
|
ADD COLUMN purchase_note TEXT COMMENT '购买须知,用于提供商品购买相关注意事项';
|
||||||
BIN
jobs.sqlite
BIN
jobs.sqlite
Binary file not shown.
Loading…
Reference in New Issue
Block a user