From a52e44705d35dbcaf9bb1261a993ebfd23f3dbec Mon Sep 17 00:00:00 2001 From: aaron <> Date: Wed, 12 Mar 2025 22:48:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=AE=9A=E6=97=B6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=88=86=E6=B6=A6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/endpoints/order.py | 3 +- app/api/endpoints/partner.py | 13 ++- app/core/config.py | 4 +- app/tasks/daily_tasks.py | 162 +++++++++++++++++++++++++++++++++++ jobs.sqlite | Bin 24576 -> 24576 bytes 5 files changed, 178 insertions(+), 4 deletions(-) diff --git a/app/api/endpoints/order.py b/app/api/endpoints/order.py index f430c70..5ce9975 100644 --- a/app/api/endpoints/order.py +++ b/app/api/endpoints/order.py @@ -233,7 +233,8 @@ async def create_order( # 是否为新人订单 is_first_order = db.query(ShippingOrderDB).filter( - ShippingOrderDB.userid == current_user.userid + ShippingOrderDB.userid == current_user.userid, + ShippingOrderDB.status != OrderStatus.CANCELLED ).count() == 0 # 创建订单 diff --git a/app/api/endpoints/partner.py b/app/api/endpoints/partner.py index b45642f..51a007d 100644 --- a/app/api/endpoints/partner.py +++ b/app/api/endpoints/partner.py @@ -14,7 +14,7 @@ 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 - +from app.models.address import AddressDB router = APIRouter() @router.get("/summary", response_model=ResponseModel) @@ -90,7 +90,6 @@ async def partner_summary( "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), @@ -122,6 +121,12 @@ async def partner_community_list( results = [] for community_id in community_ids: community = db.query(CommunityDB).filter(CommunityDB.id == community_id).first() + + # 根据地址获取当前小区的用户量 + user_count = db.query(AddressDB).filter( + AddressDB.community_id == community_id, + AddressDB.is_default == True + ).count() # 获取今日、昨日订单量 today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) @@ -161,6 +166,7 @@ async def partner_community_list( results.append({ "community_id": community_id, "community_name": community.name, + "user_count": user_count, "today_order_count": today_order_count, "yesterday_order_count": yesterday_order_count, "today_income": 0 if today_income is None else today_income, @@ -168,3 +174,6 @@ async def partner_community_list( }) return success_response(data={"items": results, "total": total_count}) + + + diff --git a/app/core/config.py b/app/core/config.py index 4628507..714d2b5 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -8,6 +8,7 @@ class Settings(BaseSettings): API_V1_STR: str = "/api/v1" PROJECT_NAME: str = "FastAPI 项目" ENV_NAME: str = "开发环境" + PLATFORM_USER_ID: int = 9 API_BASE_URL: str = "https://api-dev.beefast.co" @@ -126,6 +127,7 @@ class DevSettings(Settings): API_V1_STR: str = "/api/v1" PROJECT_NAME: str = "FastAPI 项目 (测试环境)" ENV_NAME: str = "测试环境" + PLATFORM_USER_ID: int = 9 API_BASE_URL: str = "https://api-dev.beefast.co" @@ -153,7 +155,7 @@ class ProdSettings(Settings): PROJECT_NAME: str = "FastAPI 项目 (生产环境)" ENV_NAME: str = "生产环境" API_BASE_URL: str = "https://api.beefast.co" - + PLATFORM_USER_ID: int = 45 # 数据库配置 MYSQL_HOST: str = "cd-cynosdbmysql-grp-7kdd8qe4.sql.tencentcdb.com" MYSQL_PORT: int = 26558 diff --git a/app/tasks/daily_tasks.py b/app/tasks/daily_tasks.py index 4957ccd..386d36e 100644 --- a/app/tasks/daily_tasks.py +++ b/app/tasks/daily_tasks.py @@ -11,6 +11,10 @@ from app.core.config import settings from app.models.statistics import DailyCommunityOrderStats, DailyOrderStats from sqlalchemy.exc import IntegrityError from app.models.community import CommunityDB +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 logger = logging.getLogger(__name__) @@ -212,6 +216,157 @@ def run_daily_community_order_statistics(): except Exception as e: logger.error(f"运行每日小区订单统计任务失败: {str(e)}") +async def daily_partner_settlement(): + """每日合伙人结算任务""" + logger.info(f"开始执行每日合伙人结算任务: {datetime.now()}") + + + with get_db_context() as db: + try: + # 获取昨日订单统计数据 + yesterday = (datetime.now() - timedelta(days=1)).date() + yesterday_stats = db.query(DailyCommunityOrderStats).filter( + DailyCommunityOrderStats.stats_date == yesterday + ).all() + + if not yesterday_stats: + logger.info(f"昨日没有订单统计数据,跳过结算") + return + + # 遍历每个小区的订单统计数据 + total_partner_profit = 0 + total_admin_profit = 0 + total_delivery_profit = 0 + total_platform_profit = 0 + + total_order_count = 0 + total_original_amount = 0 + total_final_amount = 0 + + for stat in yesterday_stats: + print(stat.community_name) + total_order_count += stat.order_count + total_original_amount += stat.total_original_amount + total_final_amount += stat.total_final_amount + + community = db.query(CommunityDB).filter( + CommunityDB.id == stat.community_id + ).first() + + # 找到所有的运营商 + community_sets = db.query(CommunitySet).filter( + CommunitySet.community_set_mappings.any( + CommunitySetMapping.community_id == stat.community_id + ) + ).all() + + # 提取运营商列表 + partner_ids = [] + for sets in community_sets: + if sets.user_id and sets.user_id not in partner_ids: + partner_ids.append(sets.user_id) + + # 获取分成比例 + admin_profit_sharing = community.community_profit_sharing.admin_rate + partner_profit_sharing = community.community_profit_sharing.partner_rate + delivery_profit_sharing = community.community_profit_sharing.delivery_rate + platform_profit_sharing = community.community_profit_sharing.platform_rate + + # 计算运营商分成金额 + per_partner_profit = stat.total_final_amount * (float(partner_profit_sharing) / len(partner_ids)) / 100 + + # 计算每个运营商的分成金额 + print(f"小区 {stat.community_name} 分成比例:{partner_profit_sharing} %,累计收益: {stat.total_final_amount}") + for partner_id in partner_ids: + partner_profit = per_partner_profit + print(f"运营商 {partner_id} 分成金额: {partner_profit}") + total_partner_profit += partner_profit + + # 更新运营商账户余额 + if partner_profit > 0: + account_manager = AccountManager(db) + account_manager.change_balance(partner_id, partner_profit, f"{stat.community_name} 订单收益") + + + # 计算服务商分成 + admin_profit = stat.total_final_amount * (float(admin_profit_sharing) / 100) + print(f"服务商分成金额: {admin_profit}") + total_admin_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} 订单收益") + + # 计算配送员分成 + 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} 订单收益") + + # 计算平台分成 + platform_profit = stat.total_final_amount * (float(platform_profit_sharing) / 100) + print(f"平台分成金额: {platform_profit}") + total_platform_profit += platform_profit + + if platform_profit > 0: + account_manager = AccountManager(db) + account_manager.change_balance(settings.PLATFORM_USER_ID, platform_profit, f"{stat.community_name} 订单收益") + + + # 生成分润报告 + message = f"""### {yesterday.strftime("%Y-%m-%d")} 分润报告 + +**环境:{settings.ENV_NAME}** + +### 订单汇总 +> - 订单总数: {total_order_count} +> - 订单总金额: {total_original_amount:.1f} +> - 支付总金额: {total_final_amount:.1f} + +### 分润汇总 +> - 合伙人分成: {total_partner_profit:.1f} +> - 服务商分成: {total_admin_profit:.1f} +> - 配送员分成: {total_delivery_profit:.1f} +> - 平台分成: {total_platform_profit:.1f} + +""" + + # 发送企业微信消息 + if total_partner_profit + total_admin_profit + total_delivery_profit + total_platform_profit > 0 and settings.URL_WECOMBOT_DAILY_REPORT: + try: + wecom_bot = WecomBot(settings.URL_WECOMBOT_DAILY_REPORT) + await wecom_bot.send_markdown(message) + logger.info("每日合伙人结算报告已发送到企业微信") + except Exception as e: + logger.error(f"发送企业微信消息失败: {str(e)}") + except Exception as e: + db.rollback() + logger.error(f"运行每日合伙人结算任务失败: {str(e)}") + + +def run_daily_partner_settlement(): + """ + 包装异步函数的同步函数,用于APScheduler调度 + """ + try: + # 获取或创建事件循环 + try: + loop = asyncio.get_event_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + # 运行异步任务 + if loop.is_running(): + future = asyncio.ensure_future(daily_partner_settlement()) + future.add_done_callback(lambda f: logger.info("每日合伙人结算任务完成")) + else: + loop.run_until_complete(daily_partner_settlement()) + except Exception as e: + logger.error(f"运行每日合伙人结算任务失败: {str(e)}") def register_daily_tasks(): """注册所有每日定时任务""" @@ -223,5 +378,12 @@ def register_daily_tasks(): minute=0, job_id="daily_community_order_stats" ) + + scheduler.add_cron_job( + run_daily_partner_settlement, + hour=8, + minute=0, + job_id="daily_partner_settlement" + ) logger.info("已注册所有每日定时任务") \ No newline at end of file diff --git a/jobs.sqlite b/jobs.sqlite index 25091ecccc756a489866ef332980e7ac56d6e622..96d021382500bfa46696e1ae47f258323507f6ba 100644 GIT binary patch delta 287 zcmZoTz}Rqrae@>RBmYDhCm^{oVF^DM6FUb3cO^Rq)6R{Jzt}W7@|am|SthEbBxdGR z#up?OmE@%s#TTcRl;ou5rskETUs7ObV4dnT+0k7_Spt`;DLpJ{rFqFydWR!^Vj+PC#;F!V-QiM(#=m?n>^(OglF=W^-?@lJnE`AnyW@pC9jndMSU+PN(rN1-qf9HS4|AYSrQ2H+a!~m|%-|aaS04tawBLDyZ