From 560dfa82ad16f566dcd856290913fa19bcfd615f Mon Sep 17 00:00:00 2001 From: aaron <> Date: Mon, 10 Mar 2025 16:14:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AE=BE=E7=BD=AE=E5=88=86?= =?UTF-8?q?=E6=B6=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/endpoints/community.py | 37 +++- app/api/endpoints/community_profit_sharing.py | 206 ++++++++++++++++++ app/main.py | 4 +- app/models/community.py | 27 ++- app/models/community_profit_sharing.py | 17 ++ app/models/community_set.py | 5 +- app/models/community_set_mapping.py | 2 +- 7 files changed, 284 insertions(+), 14 deletions(-) create mode 100644 app/api/endpoints/community_profit_sharing.py create mode 100644 app/models/community_profit_sharing.py diff --git a/app/api/endpoints/community.py b/app/api/endpoints/community.py index 9ed036b..eb5aec0 100644 --- a/app/api/endpoints/community.py +++ b/app/api/endpoints/community.py @@ -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)) diff --git a/app/api/endpoints/community_profit_sharing.py b/app/api/endpoints/community_profit_sharing.py new file mode 100644 index 0000000..7ebce6c --- /dev/null +++ b/app/api/endpoints/community_profit_sharing.py @@ -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="社区分润记录已删除") \ No newline at end of file diff --git a/app/main.py b/app/main.py index 2eb8190..93bc7ae 100644 --- a/app/main.py +++ b/app/main.py @@ -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=["社区楼栋"]) diff --git a/app/models/community.py b/app/models/community.py index ead8269..81d4886 100644 --- a/app/models/community.py +++ b/app/models/community.py @@ -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 \ No newline at end of file + 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 \ No newline at end of file diff --git a/app/models/community_profit_sharing.py b/app/models/community_profit_sharing.py new file mode 100644 index 0000000..80f61b4 --- /dev/null +++ b/app/models/community_profit_sharing.py @@ -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="更新时间") \ No newline at end of file diff --git a/app/models/community_set.py b/app/models/community_set.py index 23f019c..e06db9a 100644 --- a/app/models/community_set.py +++ b/app/models/community_set.py @@ -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="更新时间") \ No newline at end of file + update_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment="更新时间") + + # 关联社区集合映射 + community_set_mappings = relationship("CommunitySetMapping", backref="set") diff --git a/app/models/community_set_mapping.py b/app/models/community_set_mapping.py index 3c9c73f..c4936b0 100644 --- a/app/models/community_set_mapping.py +++ b/app/models/community_set_mapping.py @@ -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="更新时间") \ No newline at end of file