新增设置分润

This commit is contained in:
aaron 2025-03-10 16:14:13 +08:00
parent aae96d1a6e
commit 560dfa82ad
7 changed files with 284 additions and 14 deletions

View File

@ -1,5 +1,5 @@
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from sqlalchemy.orm import Session, joinedload
from typing import List, Optional
from app.models.community import (
CommunityDB, CommunityCreate, CommunityUpdate,
@ -9,6 +9,8 @@ from app.models.database import get_db
from app.api.deps import get_admin_user
from app.models.user import UserDB
from app.core.response import success_response, error_response, ResponseModel
from app.models.community_profit_sharing import CommunityProfitSharing
from app.api.endpoints.community_profit_sharing import CommunityProfitSharingResponse
router = APIRouter()
@ -67,8 +69,8 @@ async def get_communities(
db: Session = Depends(get_db)
):
"""获取社区列表"""
# 构建查询
query = db.query(CommunityDB)
# 构建查询, 关联社区分润
query = db.query(CommunityDB).options(joinedload(CommunityDB.community_profit_sharing))
# 状态过滤
if status:
@ -82,21 +84,40 @@ async def get_communities(
community_list = []
for community in communities:
community_info = CommunityInfo.model_validate(community)
community_info = {
"id": community.id,
"name": community.name,
"address": community.address,
"latitude": float(community.latitude),
"longitude": float(community.longitude),
"status": community.status,
"qy_group_qrcode": community.qy_group_qrcode,
"webot_webhook": community.webot_webhook,
"base_price": float(community.base_price),
"extra_package_price": float(community.extra_package_price),
"extra_package_threshold": community.extra_package_threshold,
"profit_sharing": None if community.community_profit_sharing is None else {
"id": community.community_profit_sharing.id,
"platform_rate": float(community.community_profit_sharing.platform_rate),
"partner_rate": float(community.community_profit_sharing.partner_rate),
"admin_rate": float(community.community_profit_sharing.admin_rate),
"delivery_rate": float(community.community_profit_sharing.delivery_rate)
}
}
# 如果提供了经纬度,则计算距离
if latitude is not None and longitude is not None:
distance = calculate_distance(
latitude, longitude,
community.latitude, community.longitude
float(community.latitude), float(community.longitude)
)
community_info.distance = distance
community_info["distance"] = distance
community_list.append(community_info)
# 如果计算了距离,则按距离排序
if latitude is not None and longitude is not None:
community_list.sort(key=lambda x: x.distance)
community_list.sort(key=lambda x: x["distance"])
return success_response(data={
"total": total,
@ -127,7 +148,7 @@ async def get_community(
db: Session = Depends(get_db)
):
"""获取社区详情"""
community = db.query(CommunityDB).filter(CommunityDB.id == community_id).first()
community = db.query(CommunityDB).options(joinedload(CommunityDB.community_profit_sharing)).filter(CommunityDB.id == community_id).first()
if not community:
return error_response(code=404, message="社区不存在")
return success_response(data=CommunityInfo.model_validate(community))

View File

@ -0,0 +1,206 @@
from fastapi import APIRouter, Depends, HTTPException, Query, Path
from sqlalchemy.orm import Session
from typing import List, Optional
from pydantic import BaseModel, Field, field_validator
from app.models.database import get_db
from app.models.community_profit_sharing import CommunityProfitSharing
from app.models.community import CommunityDB
from app.api.deps import get_current_user, get_admin_user
from app.models.user import UserDB
from datetime import datetime
from decimal import Decimal
from app.core.response import error_response, success_response
router = APIRouter()
# 请求和响应模型
class CommunityProfitSharingCreate(BaseModel):
community_id: int = Field(..., ge=1, description="社区ID")
platform_rate: float = Field(..., ge=0, le=100, description="平台分润比例(%)")
partner_rate: float = Field(..., ge=0, le=100, description="合伙人分润比例(%)")
admin_rate: float = Field(..., ge=0, le=100, description="管理员分润比例(%)")
delivery_rate: float = Field(..., ge=0, le=100, description="配送员分润比例(%)")
class CommunityProfitSharingUpdate(BaseModel):
platform_rate: float = Field(..., ge=0, le=100, description="平台分润比例(%)")
partner_rate: float = Field(..., ge=0, le=100, description="合伙人分润比例(%)")
admin_rate: float = Field(..., ge=0, le=100, description="管理员分润比例(%)")
delivery_rate: float = Field(..., ge=0, le=100, description="配送员分润比例(%)")
class CommunityProfitSharingResponse(BaseModel):
id: int
community_id: int
platform_rate: float
partner_rate: float
admin_rate: float
delivery_rate: float
create_time: datetime
update_time: datetime
# 包含社区名称
community_name: Optional[str] = None
class Config:
from_attributes = True
# 创建社区分润
@router.post("/", response_model=CommunityProfitSharingResponse)
async def create_community_profit_sharing(
profit_sharing: CommunityProfitSharingCreate,
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_admin_user)
):
"""创建社区分润"""
# 检查社区是否存在
community = db.query(CommunityDB).filter(CommunityDB.id == profit_sharing.community_id).first()
if not community:
return error_response(code=404, message="社区不存在")
# 检查该社区是否已有分润记录
existing_profit_sharing = db.query(CommunityProfitSharing).filter(
CommunityProfitSharing.community_id == profit_sharing.community_id
).first()
if existing_profit_sharing:
return error_response(code=400, message="该社区已有分润记录,请使用更新接口")
# 检查分润比例之和是否等于100%
total_rate = profit_sharing.platform_rate + profit_sharing.partner_rate + profit_sharing.admin_rate + profit_sharing.delivery_rate
if total_rate != 100:
return error_response(code=400, message="分润比例之和必须等于100%")
# 创建新分润记录
new_profit_sharing = CommunityProfitSharing(
community_id=profit_sharing.community_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
)
db.add(new_profit_sharing)
db.commit()
db.refresh(new_profit_sharing)
# 添加社区名称
result = CommunityProfitSharingResponse.model_validate(new_profit_sharing)
result.community_name = community.name
return success_response(data=result)
# 获取所有社区分润
@router.get("/", response_model=List[CommunityProfitSharingResponse])
async def get_community_profit_sharings(
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_admin_user),
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=100)
):
"""获取所有社区分润"""
profit_sharings = db.query(CommunityProfitSharing).offset(skip).limit(limit).all()
# 添加社区名称
results = []
for profit_sharing in profit_sharings:
community = db.query(CommunityDB).filter(CommunityDB.id == profit_sharing.community_id).first()
result = CommunityProfitSharingResponse.model_validate(profit_sharing)
result.community_name = community.name if community else None
results.append(result)
return success_response(data=results)
# 获取特定社区的分润
@router.get("/community/{community_id}", response_model=CommunityProfitSharingResponse)
async def get_community_profit_sharing(
community_id: int = Path(..., ge=1),
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_admin_user)
):
"""获取特定社区的分润"""
# 检查社区是否存在
community = db.query(CommunityDB).filter(CommunityDB.id == community_id).first()
if not community:
return error_response(code=404, message="社区不存在")
profit_sharing = db.query(CommunityProfitSharing).filter(
CommunityProfitSharing.community_id == community_id
).first()
if not profit_sharing:
return error_response(code=404, message="该社区暂无分润记录")
# 添加社区名称
result = CommunityProfitSharingResponse.model_validate(profit_sharing)
result.community_name = community.name
return success_response(data=result)
# 更新社区分润
@router.put("/community/{community_id}", response_model=CommunityProfitSharingResponse)
async def update_community_profit_sharing(
profit_sharing: CommunityProfitSharingUpdate,
community_id: int = Path(..., ge=1),
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_admin_user)
):
"""更新社区分润"""
# 检查社区是否存在
community = db.query(CommunityDB).filter(CommunityDB.id == community_id).first()
if not community:
return error_response(code=404, message="社区不存在")
# 检查该社区是否有分润记录
db_profit_sharing = db.query(CommunityProfitSharing).filter(
CommunityProfitSharing.community_id == community_id
).first()
if not db_profit_sharing:
return error_response(code=404, message="该社区暂无分润记录,请先创建")
# 检查分润比例之和是否等于100%
total_rate = profit_sharing.platform_rate + profit_sharing.partner_rate + profit_sharing.admin_rate + profit_sharing.delivery_rate
if total_rate != 100:
return error_response(code=400, message="分润比例之和必须等于100%")
# 更新分润记录
db_profit_sharing.platform_rate = profit_sharing.platform_rate
db_profit_sharing.partner_rate = profit_sharing.partner_rate
db_profit_sharing.admin_rate = profit_sharing.admin_rate
db_profit_sharing.delivery_rate = profit_sharing.delivery_rate
db_profit_sharing.update_time = datetime.now()
db.commit()
db.refresh(db_profit_sharing)
# 添加社区名称
result = CommunityProfitSharingResponse.model_validate(db_profit_sharing)
result.community_name = community.name
return success_response(data=result)
# 删除社区分润
@router.delete("/community/{community_id}", response_model=dict)
async def delete_community_profit_sharing(
community_id: int = Path(..., ge=1),
db: Session = Depends(get_db),
current_user: UserDB = Depends(get_admin_user)
):
"""删除社区分润"""
# 检查社区是否存在
community = db.query(CommunityDB).filter(CommunityDB.id == community_id).first()
if not community:
return error_response(code=404, message="社区不存在")
# 检查该社区是否有分润记录
db_profit_sharing = db.query(CommunityProfitSharing).filter(
CommunityProfitSharing.community_id == community_id
).first()
if not db_profit_sharing:
return error_response(code=404, message="该社区暂无分润记录")
# 删除分润记录
db.delete(db_profit_sharing)
db.commit()
return success_response(message="社区分润记录已删除")

View File

@ -1,6 +1,6 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.api.endpoints import wechat,user, address, community, station, order, coupon, community_building, upload, merchant, merchant_product, merchant_order, point, config, merchant_category, log, account,merchant_pay_order, message, bank_card, withdraw, mp, point_product, point_product_order, coupon_activity, dashboard, wecom, feedback, timeperiod, community_timeperiod, order_additional_fee, ai, community_set, community_set_mapping
from app.api.endpoints import wechat,user, address, community, station, order, coupon, community_building, upload, merchant, merchant_product, merchant_order, point, config, merchant_category, log, account,merchant_pay_order, message, bank_card, withdraw, mp, point_product, point_product_order, coupon_activity, dashboard, wecom, feedback, timeperiod, community_timeperiod, order_additional_fee, ai, community_set, community_set_mapping, community_profit_sharing, partner
from app.models.database import Base, engine
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
@ -13,7 +13,6 @@ from app.core.config import settings
from app.core.wecombot import WecomBot
from app.api.endpoints import wecom
from app.api.endpoints import feedback
from app.api.endpoints import partner
from starlette.middleware.sessions import SessionMiddleware
import os
@ -62,6 +61,7 @@ app.include_router(address.router, prefix="/api/address", tags=["配送地址"])
app.include_router(community.router, prefix="/api/community", tags=["社区"])
app.include_router(community_set.router, prefix="/api/community-sets", tags=["社区集合"])
app.include_router(community_set_mapping.router, prefix="/api/community-set-mappings", tags=["社区集合映射"])
app.include_router(community_profit_sharing.router, prefix="/api/community-profit-sharings", tags=["社区分润"])
app.include_router(timeperiod.router, prefix="/api/time-periods", tags=["配送时段"])
app.include_router(community_timeperiod.router, prefix="/api/community-time-periods", tags=["社区配送时段"])
app.include_router(community_building.router, prefix="/api/community/building", tags=["社区楼栋"])

View File

@ -2,7 +2,7 @@ from typing import Optional
import enum
from sqlalchemy import Column, Integer, String, DECIMAL, DateTime, Enum
from sqlalchemy.sql import func
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, model_validator
from .database import Base
from sqlalchemy.orm import relationship
from app.core.imageprocessor import process_image, ImageFormat
@ -32,6 +32,12 @@ class CommunityDB(Base):
create_time = Column(DateTime(timezone=True), server_default=func.now())
update_time = Column(DateTime(timezone=True), onupdate=func.now())
# 通过映射表关联的社区分润
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:
@ -75,5 +81,22 @@ class CommunityInfo(BaseModel):
optimized_qy_group_qrcode: Optional[str] = None
distance: Optional[float] = None # 距离,单位:米
# 添加分润信息字段
profit_sharing: Optional[dict] = None
class Config:
from_attributes = True
from_attributes = True
@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

View File

@ -0,0 +1,17 @@
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, DECIMAL, UniqueConstraint
from sqlalchemy.orm import relationship
from app.models.database import Base
import datetime
class CommunityProfitSharing(Base):
"""社区分润模型,记录每个社区的分润比例"""
__tablename__ = "community_profit_sharings"
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
community_id = Column(Integer, ForeignKey("communities.id"), nullable=False, unique=True, comment="社区ID")
platform_rate = Column(DECIMAL(5, 2), nullable=False, default=0, comment="平台分润比例(%)")
partner_rate = Column(DECIMAL(5, 2), nullable=False, default=0, comment="合伙人分润比例(%)")
admin_rate = Column(DECIMAL(5, 2), nullable=False, default=0, comment="管理员分润比例(%)")
delivery_rate = Column(DECIMAL(5, 2), nullable=False, default=0, comment="配送员分润比例(%)")
create_time = Column(DateTime, default=datetime.datetime.now, comment="创建时间")
update_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment="更新时间")

View File

@ -11,4 +11,7 @@ class CommunitySet(Base):
set_name = Column(String(100), nullable=False, comment="集合名称")
user_id = Column(Integer, nullable=True, comment="创建用户ID")
create_time = Column(DateTime, default=datetime.datetime.now, comment="创建时间")
update_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment="更新时间")
update_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment="更新时间")
# 关联社区集合映射
community_set_mappings = relationship("CommunitySetMapping", backref="set")

View File

@ -11,4 +11,4 @@ class CommunitySetMapping(Base):
set_id = Column(Integer, ForeignKey("community_sets.id"), nullable=False, comment="社区集合ID")
community_id = Column(Integer, ForeignKey("communities.id"), nullable=False, comment="社区ID")
create_time = Column(DateTime, default=datetime.datetime.now, comment="创建时间")
update_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment="更新时间")
update_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment="更新时间")