diff --git a/app/api/deps.py b/app/api/deps.py index 033c250..425d2ae 100644 --- a/app/api/deps.py +++ b/app/api/deps.py @@ -49,4 +49,13 @@ async def get_merchant_user( """验证商家权限""" if UserRole.MERCHANT not in current_user.roles: raise HTTPException(status_code=403, detail="需要商家权限") + return current_user + + +async def get_partner_user( + current_user: UserDB = Depends(get_current_user) +) -> UserDB: + """验证合伙人权限""" + if UserRole.PARTNER not in current_user.roles: + raise HTTPException(status_code=403, detail="需要合伙人权限") return current_user \ No newline at end of file diff --git a/app/api/endpoints/order.py b/app/api/endpoints/order.py index c3712ab..a13bfbd 100644 --- a/app/api/endpoints/order.py +++ b/app/api/endpoints/order.py @@ -147,6 +147,13 @@ def calculate_price(price_request: OrderPriceCalculateRequest,user: UserDB,db: S return result +def calculate_delivery_share(order: ShippingOrderDB, deliveryman: UserDB) -> float: + if deliveryman.delivery_commission_fixed > 0: + return deliveryman.delivery_commission_fixed + elif deliveryman.delivery_commission_rate > 0: + return round(order.original_amount_with_additional_fee * (deliveryman.delivery_commission_rate / 100.0), 2) + else: + return 0 def format_delivery_time(delivery_date: datetime, time_period_name: str) -> str: if delivery_date == datetime.now().date(): @@ -408,15 +415,6 @@ async def get_order_detail( if not order: return error_response(code=404, message="订单不存在") - # 计算配送员分账金额 - deliveryman_share = 0 - if current_user.delivery_commission_fixed > 0: - deliveryman_share = current_user.delivery_commission_fixed - elif current_user.delivery_commission_rate > 0: - deliveryman_share = round(order.original_amount_with_additional_fee * (current_user.delivery_commission_rate / 100.0), 2) - else: - deliveryman_share = 0 - # 如果有配送员 id,则获取配送员信息 if order.deliveryman_user_id: deliveryman_user = db.query(UserDB).filter( @@ -501,7 +499,7 @@ async def get_order_detail( "point_discount_amount": order.point_discount_amount, "coupon_id": order.coupon_id, "final_amount": order.final_amount, - "deliveryman_share": deliveryman_share, + "deliveryman_share": order.delivery_share if order.delivery_share > 0 else calculate_delivery_share(order, current_user), "status": order.status, "complete_images": order.optimized_complete_images, "packages": package_list, @@ -1166,21 +1164,13 @@ async def deliveryman_complete_order( # 更新完成时间 order.completed_time = datetime.now() - - # 计算配送员分账金额 - if current_user.delivery_commission_rate > 0: - deliveryman_share = order.original_amount_with_additional_fee * current_user.delivery_commission_rate / 100 - elif current_user.delivery_commission_fixed > 0: - deliveryman_share = current_user.delivery_commission_fixed - else: - deliveryman_share = 0 # 使用账户管理器处理分账 - if deliveryman_share > 0: + if order.delivery_share > 0: account_manager = AccountManager(db) account_manager.change_balance( user_id=order.deliveryman_user_id, - amount=deliveryman_share, + amount= order.delivery_share, description=f"配送订单收益", transaction_id=orderid ) @@ -1275,11 +1265,15 @@ async def deliveryman_receive_order( ).all() try: + # 更新订单状态和配送员ID order.status = OrderStatus.RECEIVED order.deliveryman_user_id = deliveryman.userid order.received_time = datetime.now() - + + # 接单就确认收益 + order.delivery_share = calculate_delivery_share(order, deliveryman) + db.commit() # 发送企业微信消息 diff --git a/app/api/endpoints/partner.py b/app/api/endpoints/partner.py new file mode 100644 index 0000000..48f59bb --- /dev/null +++ b/app/api/endpoints/partner.py @@ -0,0 +1,168 @@ +from fastapi import APIRouter, Depends, Query +from sqlalchemy.orm import Session +from sqlalchemy import func, and_, distinct +from app.models.database import get_db +from app.models.user_account import UserAccountDB, AccountDetailDB, AccountDetailType +from app.models.user import UserDB +from app.api.deps import get_current_user +from app.core.response import success_response, ResponseModel +from datetime import datetime, timedelta +from decimal import Decimal +from typing import Optional +from pydantic import BaseModel +from app.models.community_set_mapping import CommunitySetMapping +from app.models.community_set import CommunitySet +from app.models.order import ShippingOrderDB, OrderStatus +from app.models.community import CommunityDB + +router = APIRouter() + +@router.get("/summary", response_model=ResponseModel) +async def partner_summary( + db: Session = Depends(get_db), + current_user: UserDB = Depends(get_current_user) +): + """获取合伙人收益汇总""" + + # 获取当前用户管理的小区ID列表,直接在数据库层面去重 + community_ids = db.query(CommunitySetMapping.community_id)\ + .join(CommunitySet, CommunitySetMapping.set_id == CommunitySet.id)\ + .filter(CommunitySet.user_id == current_user.userid)\ + .distinct()\ + .all() + + # 将结果转换为简单列表 + community_ids = [community_id[0] for community_id in community_ids] + + # 总订单数 + total_order_count = db.query(ShippingOrderDB).filter( + ShippingOrderDB.address_community_id.in_(community_ids), + ShippingOrderDB.status == OrderStatus.COMPLETED + ).count() + + # 获取当前小区今日、昨日订单量 + today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + today_end = datetime.now().replace(hour=23, minute=59, second=59, microsecond=999999) + yesterday_start = today_start - timedelta(days=1) + yesterday_end = today_end - timedelta(days=1) + + today_order_count = db.query(ShippingOrderDB).filter( + ShippingOrderDB.address_community_id.in_(community_ids), + ShippingOrderDB.create_time >= today_start, + ShippingOrderDB.create_time <= today_end, + ShippingOrderDB.status == OrderStatus.COMPLETED + ).count() + + yesterday_order_count = db.query(ShippingOrderDB).filter( + ShippingOrderDB.address_community_id.in_(community_ids), + ShippingOrderDB.create_time >= yesterday_start, + ShippingOrderDB.create_time <= yesterday_end, + ShippingOrderDB.status == OrderStatus.COMPLETED + ).count() + + # 总营收 + total_income = db.query(func.sum(ShippingOrderDB.original_amount + ShippingOrderDB.additional_fee_amount)).filter( + ShippingOrderDB.address_community_id.in_(community_ids), + ShippingOrderDB.status == OrderStatus.COMPLETED + ).scalar() + + # 获取今日、昨日收益 + today_income = db.query(func.sum(ShippingOrderDB.original_amount + ShippingOrderDB.additional_fee_amount)).filter( + ShippingOrderDB.address_community_id.in_(community_ids), + ShippingOrderDB.create_time >= today_start, + ShippingOrderDB.create_time <= today_end, + ShippingOrderDB.status == OrderStatus.COMPLETED + ).scalar() + + yesterday_income = db.query(func.sum(ShippingOrderDB.original_amount + ShippingOrderDB.additional_fee_amount)).filter( + ShippingOrderDB.address_community_id.in_(community_ids), + ShippingOrderDB.create_time >= yesterday_start, + ShippingOrderDB.create_time <= yesterday_end, + ShippingOrderDB.status == OrderStatus.COMPLETED + ).scalar() + + return success_response(data= + {"community_count": len(community_ids), + "total_order_count": total_order_count, + "today_order_count": today_order_count, + "yesterday_order_count": yesterday_order_count, + "total_order_amount": 0 if total_income is None else total_income, + "today_order_amount": 0 if today_income is None else today_income, + "yesterday_order_amount": 0 if yesterday_income is None else yesterday_income}) + + +@router.get("/community_list", response_model=ResponseModel) +async def partner_community_list( + db: Session = Depends(get_db), + skip: int = 0, + limit: int = 10, + current_user: UserDB = Depends(get_current_user) +): + """获取合伙人小区列表""" + # 获取当前用户管理的小区ID列表,直接在数据库层面去重 + community_ids = db.query(CommunitySetMapping.community_id)\ + .join(CommunitySet, CommunitySetMapping.set_id == CommunitySet.id)\ + .filter(CommunitySet.user_id == current_user.userid)\ + .distinct()\ + .offset(skip)\ + .limit(limit)\ + .all() + + total_count = db.query(CommunitySetMapping.community_id)\ + .join(CommunitySet, CommunitySetMapping.set_id == CommunitySet.id)\ + .filter(CommunitySet.user_id == current_user.userid)\ + .distinct()\ + .count() + + # 将结果转换为简单列表 + community_ids = [community_id[0] for community_id in community_ids] + + results = [] + for community_id in community_ids: + community = db.query(CommunityDB).filter(CommunityDB.id == community_id).first() + + # 获取今日、昨日订单量 + today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + today_end = datetime.now().replace(hour=23, minute=59, second=59, microsecond=999999) + yesterday_start = today_start - timedelta(days=1) + yesterday_end = today_end - timedelta(days=1) + + today_order_count = db.query(ShippingOrderDB).filter( + ShippingOrderDB.address_community_id == community_id, + ShippingOrderDB.create_time >= today_start, + ShippingOrderDB.create_time <= today_end, + ShippingOrderDB.status == OrderStatus.COMPLETED + ).count() + + yesterday_order_count = db.query(ShippingOrderDB).filter( + ShippingOrderDB.address_community_id == community_id, + ShippingOrderDB.create_time >= yesterday_start, + ShippingOrderDB.create_time <= yesterday_end, + ShippingOrderDB.status == OrderStatus.COMPLETED + ).count() + + # 获取今日、昨日收益 + today_income = db.query(func.sum(ShippingOrderDB.original_amount + ShippingOrderDB.additional_fee_amount)).filter( + ShippingOrderDB.address_community_id == community_id, + ShippingOrderDB.create_time >= today_start, + ShippingOrderDB.create_time <= today_end, + ShippingOrderDB.status == OrderStatus.COMPLETED + ).scalar() + + yesterday_income = db.query(func.sum(ShippingOrderDB.original_amount + ShippingOrderDB.additional_fee_amount)).filter( + ShippingOrderDB.address_community_id == community_id, + ShippingOrderDB.create_time >= yesterday_start, + ShippingOrderDB.create_time <= yesterday_end, + ShippingOrderDB.status == OrderStatus.COMPLETED + ).scalar() + + results.append({ + "community_id": community_id, + "community_name": community.name, + "today_order_count": today_order_count, + "yesterday_order_count": yesterday_order_count, + "today_income": 0 if today_income is None else today_income, + "yesterday_income": 0 if yesterday_income is None else yesterday_income + }) + + return success_response(data={"items": results, "total": total_count}) diff --git a/app/main.py b/app/main.py index e7adaec..2eb8190 100644 --- a/app/main.py +++ b/app/main.py @@ -13,6 +13,7 @@ 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 @@ -49,6 +50,7 @@ app.include_router(dashboard.router, prefix="/api/dashboard", tags=["仪表盘"] app.include_router(wechat.router,prefix="/api/wechat",tags=["微信"]) app.include_router(mp.router, prefix="/api/mp", tags=["微信公众号"]) app.include_router(wecom.router, prefix="/api/wecom", tags=["企业微信"]) +app.include_router(partner.router, prefix="/api/partner", tags=["合伙人"]) app.include_router(user.router, prefix="/api/user", tags=["用户"]) app.include_router(bank_card.router, prefix="/api/bank-cards", tags=["用户银行卡"]) app.include_router(withdraw.router, prefix="/api/withdraw", tags=["提现"]) @@ -58,11 +60,11 @@ app.include_router(point_product_order.router, prefix="/api/point-product-orders app.include_router(account.router, prefix="/api/account", tags=["账户"]) app.include_router(address.router, prefix="/api/address", tags=["配送地址"]) app.include_router(community.router, prefix="/api/community", tags=["社区"]) -app.include_router(community_building.router, prefix="/api/community/building", 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(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=["社区楼栋"]) app.include_router(station.router, prefix="/api/station", tags=["驿站"]) app.include_router(order.router, prefix="/api/order", tags=["订单"]) app.include_router(order_additional_fee.router, prefix="/api/order-additional-fee", tags=["订单加价"]) diff --git a/app/models/order.py b/app/models/order.py index ca2c6b1..b76a991 100644 --- a/app/models/order.py +++ b/app/models/order.py @@ -67,6 +67,7 @@ class ShippingOrderDB(Base): delivery_method = Column(Enum(DeliveryMethod), nullable=False) delivery_date = Column(Date, nullable=False, default=datetime.now().date()) + delivery_share = Column(Float, default=0) # 配送费分润 package_count = Column(Integer, nullable=False) original_amount = Column(Float, nullable=False) coupon_discount_amount = Column(Float, default=0) @@ -179,6 +180,7 @@ class OrderInfo(BaseModel): create_time: datetime delivery_method: DeliveryMethod delivery_date: date + delivery_share: float = 0 deliveryman_user_id: Optional[int] = None