新增设置分润

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 fastapi import APIRouter, Depends
from sqlalchemy.orm import Session from sqlalchemy.orm import Session, joinedload
from typing import List, Optional from typing import List, Optional
from app.models.community import ( from app.models.community import (
CommunityDB, CommunityCreate, CommunityUpdate, CommunityDB, CommunityCreate, CommunityUpdate,
@ -9,6 +9,8 @@ from app.models.database import get_db
from app.api.deps import get_admin_user from app.api.deps import get_admin_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.community_profit_sharing import CommunityProfitSharing
from app.api.endpoints.community_profit_sharing import CommunityProfitSharingResponse
router = APIRouter() router = APIRouter()
@ -67,8 +69,8 @@ async def get_communities(
db: Session = Depends(get_db) db: Session = Depends(get_db)
): ):
"""获取社区列表""" """获取社区列表"""
# 构建查询 # 构建查询, 关联社区分润
query = db.query(CommunityDB) query = db.query(CommunityDB).options(joinedload(CommunityDB.community_profit_sharing))
# 状态过滤 # 状态过滤
if status: if status:
@ -82,21 +84,40 @@ async def get_communities(
community_list = [] community_list = []
for community in communities: 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: if latitude is not None and longitude is not None:
distance = calculate_distance( distance = calculate_distance(
latitude, longitude, 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) community_list.append(community_info)
# 如果计算了距离,则按距离排序 # 如果计算了距离,则按距离排序
if latitude is not None and longitude is not None: 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={ return success_response(data={
"total": total, "total": total,
@ -127,7 +148,7 @@ async def get_community(
db: Session = Depends(get_db) 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: if not community:
return error_response(code=404, message="社区不存在") return error_response(code=404, message="社区不存在")
return success_response(data=CommunityInfo.model_validate(community)) 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 import FastAPI
from fastapi.middleware.cors import CORSMiddleware 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 app.models.database import Base, engine
from fastapi.exceptions import RequestValidationError from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
@ -13,7 +13,6 @@ from app.core.config import settings
from app.core.wecombot import WecomBot from app.core.wecombot import WecomBot
from app.api.endpoints import wecom from app.api.endpoints import wecom
from app.api.endpoints import feedback from app.api.endpoints import feedback
from app.api.endpoints import partner
from starlette.middleware.sessions import SessionMiddleware from starlette.middleware.sessions import SessionMiddleware
import os 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.router, prefix="/api/community", tags=["社区"])
app.include_router(community_set.router, prefix="/api/community-sets", 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_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(timeperiod.router, prefix="/api/time-periods", tags=["配送时段"])
app.include_router(community_timeperiod.router, prefix="/api/community-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=["社区楼栋"]) app.include_router(community_building.router, prefix="/api/community/building", tags=["社区楼栋"])

View File

@ -2,7 +2,7 @@ from typing import Optional
import enum import enum
from sqlalchemy import Column, Integer, String, DECIMAL, DateTime, Enum from sqlalchemy import Column, Integer, String, DECIMAL, DateTime, Enum
from sqlalchemy.sql import func from sqlalchemy.sql import func
from pydantic import BaseModel, Field from pydantic import BaseModel, Field, model_validator
from .database import Base from .database import Base
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from app.core.imageprocessor import process_image, ImageFormat 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()) 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())
# 通过映射表关联的社区分润
community_profit_sharing = relationship("CommunityProfitSharing", backref="community", uselist=False)
# 关联社区集合
community_set_mappings = relationship("CommunitySetMapping", backref="community")
@property @property
def optimized_qy_group_qrcode(self): def optimized_qy_group_qrcode(self):
if self.qy_group_qrcode: if self.qy_group_qrcode:
@ -75,5 +81,22 @@ class CommunityInfo(BaseModel):
optimized_qy_group_qrcode: Optional[str] = None optimized_qy_group_qrcode: Optional[str] = None
distance: Optional[float] = None # 距离,单位:米 distance: Optional[float] = None # 距离,单位:米
# 添加分润信息字段
profit_sharing: Optional[dict] = None
class Config: 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

@ -12,3 +12,6 @@ class CommunitySet(Base):
user_id = Column(Integer, nullable=True, comment="创建用户ID") user_id = Column(Integer, nullable=True, comment="创建用户ID")
create_time = Column(DateTime, default=datetime.datetime.now, comment="创建时间") 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")