diff --git a/app/models/settlement.py b/app/models/settlement.py new file mode 100644 index 0000000..6db739d --- /dev/null +++ b/app/models/settlement.py @@ -0,0 +1,39 @@ +from sqlalchemy import Column, Integer, String, DateTime, JSON, Date, ForeignKey +from sqlalchemy.sql import func +from pydantic import BaseModel, Field +from typing import Optional, Dict, Any +from datetime import date, datetime +from .database import Base +from .community import CommunityDB + +class SettlementHistoryDB(Base): + """结算历史记录表""" + __tablename__ = "settlement_history" + + id = Column(Integer, primary_key=True, autoincrement=True) + settle_date = Column(Date, nullable=False, index=True, comment="结算日期") + community_id = Column(Integer, ForeignKey("communities.id"), nullable=False, index=True, comment="小区ID") + community_name = Column(String(100), nullable=False, comment="小区名称") + settle_details = Column(JSON, nullable=False, comment="结算详情,JSON格式") + create_time = Column(DateTime(timezone=True), server_default=func.now(), comment="创建时间") + + class Config: + orm_mode = True + +# Pydantic 模型 +class SettlementHistoryCreate(BaseModel): + settle_date: date + community_id: int + community_name: str + settle_details: Dict[str, Any] + +class SettlementHistoryInfo(BaseModel): + id: int + settle_date: date + community_id: int + community_name: str + settle_details: Dict[str, Any] + create_time: datetime + + class Config: + from_attributes = True \ No newline at end of file diff --git a/app/tasks/daily_tasks.py b/app/tasks/daily_tasks.py index 037a503..ce50240 100644 --- a/app/tasks/daily_tasks.py +++ b/app/tasks/daily_tasks.py @@ -15,8 +15,9 @@ from app.models.user import UserDB, UserRole from app.models.community_set import CommunitySet from app.models.community_set_mapping import CommunitySetMapping from app.core.account import AccountManager - +from app.models.settlement import SettlementHistoryDB logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) async def daily_community_order_statistics(): """每日小区订单统计任务 @@ -52,7 +53,7 @@ async def daily_community_order_statistics(): JOIN communities c ON o.address_community_id = c.id WHERE - o.create_time BETWEEN :start_time AND :end_time + o.completed_time BETWEEN :start_time AND :end_time AND o.status = 'COMPLETED' GROUP BY c.id, c.name @@ -244,7 +245,26 @@ async def daily_partner_settlement(): total_original_amount = 0 total_final_amount = 0 + settlement_history = [] for stat in yesterday_stats: + + # 检查是否已存在该日期的结算记录 + existing_settlement = db.query(SettlementHistoryDB).filter( + SettlementHistoryDB.settle_date == yesterday, + SettlementHistoryDB.community_id == stat.community_id, + ).first() + + if existing_settlement: + logger.info(f"小区 {stat.community_name} 已存在结算记录,跳过结算") + continue + + + # 结算明细 + settle_details = { + "total_order_amount": stat.total_original_amount, + "total_pay_amount": stat.total_final_amount + } + print(f"日期:{stat.stats_date} 小区: {stat.community_name} 订单数: {stat.order_count} 订单金额: {stat.total_original_amount} 支付金额: {stat.total_final_amount}") total_order_count += stat.order_count total_original_amount += stat.total_original_amount @@ -274,48 +294,93 @@ async def daily_partner_settlement(): platform_profit_sharing = community.community_profit_sharing.platform_rate # 计算运营商分成金额 - per_partner_profit = stat.total_final_amount * (float(partner_profit_sharing) / len(partner_ids)) / 100 + partner_profit = stat.total_final_amount * (float(partner_profit_sharing)) / 100 + admin_profit = stat.total_final_amount * (float(admin_profit_sharing) / 100) + delivery_profit = stat.total_final_amount * (float(delivery_profit_sharing) / 100) + platform_profit = stat.total_final_amount * (float(platform_profit_sharing) / 100) + + # 如果没有运营商、服务商,则需要沉淀到平台 + profit_sediment = { + "partner_profit": partner_profit, + "admin_profit": admin_profit + } # 计算每个运营商的分成金额 for partner_id in partner_ids: - partner_profit = per_partner_profit - print(f"运营商 {partner_id} 分成金额: {partner_profit}") - total_partner_profit += partner_profit + per_partner_profit = partner_profit / len(partner_ids) + print(f"运营商 {partner_id} 分成金额: {per_partner_profit}") + total_partner_profit += per_partner_profit + settle_details["partner_profit"] = { + "user_id": partner_id, + "profit": per_partner_profit + } # 更新运营商账户余额 - if partner_profit > 0: + if per_partner_profit > 0: account_manager = AccountManager(db) - account_manager.change_balance(partner_id, partner_profit, f"{stat.community_name} 订单收益") + account_manager.change_balance(partner_id, per_partner_profit, f"{stat.community_name} 订单收益") + + # 计算沉淀金额 + profit_sediment["partner_profit"] -= per_partner_profit # 计算服务商分成 - admin_profit = stat.total_final_amount * (float(admin_profit_sharing) / 100) print(f"服务商分成金额: {admin_profit}") total_admin_profit += admin_profit + settle_details["admin_profit"] = { + "user_id": community.admin_id, + "profit": admin_profit + } + if admin_profit > 0 and community.admin_id and community.admin_id > 0: account_manager = AccountManager(db) account_manager.change_balance(community.admin_id, admin_profit, f"{stat.community_name} 订单收益") + else: + # 计算沉淀金额 + profit_sediment["admin_profit"] -= admin_profit # 计算配送员分成 - delivery_profit = stat.total_final_amount * (float(delivery_profit_sharing) / 100) print(f"配送员分成金额: {delivery_profit}") total_delivery_profit += delivery_profit - # if delivery_profit > 0: - # account_manager = AccountManager(db) - # account_manager.change_balance(community.admin_id, delivery_profit, f"{stat.community_name} 订单收益") + settle_details["delivery_profit"] = { + "user_id": 0, + "profit": delivery_profit + } + # 计算平台分成 - platform_profit = stat.total_final_amount * (float(platform_profit_sharing) / 100) - print(f"平台分成金额: {platform_profit}") - total_platform_profit += platform_profit + # 计算分成 + 沉淀金额 + final_platform_profit = platform_profit + profit_sediment["partner_profit"] + profit_sediment["admin_profit"] - if platform_profit > 0: + print(f"平台分成 + 沉淀金额: {final_platform_profit}") + total_platform_profit += final_platform_profit + + + settle_details["platform_profit"] = { + "user_id": settings.PLATFORM_USER_ID, + "profit": final_platform_profit + } + + + if final_platform_profit > 0: account_manager = AccountManager(db) - account_manager.change_balance(settings.PLATFORM_USER_ID, platform_profit, f"{stat.community_name} 订单收益") + account_manager.change_balance(settings.PLATFORM_USER_ID, final_platform_profit, f"{stat.community_name} 订单收益") + # 保存结算明细 + settlement = SettlementHistoryDB( + settle_date=yesterday, + community_id=stat.community_id, + community_name=stat.community_name, + settle_details=settle_details + ) + settlement_history.append(settlement) + + db.add_all(settlement_history) + db.commit() + # 生成分润报告 message = f"""### {yesterday.strftime("%Y-%m-%d")} 分润报告 @@ -327,7 +392,7 @@ async def daily_partner_settlement(): > - 支付总金额: {total_final_amount:.1f} ### 分润汇总 -> - 合伙人分成: {total_partner_profit:.1f} +> - 运营商分成: {total_partner_profit:.1f} > - 服务商分成: {total_admin_profit:.1f} > - 配送员分成: {total_delivery_profit:.1f} > - 平台分成: {total_platform_profit:.1f} @@ -341,6 +406,8 @@ async def daily_partner_settlement(): logger.info("每日合伙人结算报告已发送到企业微信") except Exception as e: logger.error(f"发送企业微信消息失败: {str(e)}") + + except Exception as e: db.rollback() logger.error(f"运行每日合伙人结算任务失败: {str(e)}") diff --git a/jobs.sqlite b/jobs.sqlite index a4b3183..e71e586 100644 Binary files a/jobs.sqlite and b/jobs.sqlite differ