from datetime import date, datetime from sqlalchemy import select, func from sqlalchemy.ext.asyncio import AsyncSession from app.models.visit import Visit from app.models.daily_note import DailyNote from app.models.user import User from app.services.wecom import wecom_client from app.utils.timezone import today_cst async def check_daily_reporting(db: AsyncSession) -> dict: """Check today's reporting progress and send wecom reminders to managers who haven't reported.""" today = today_cst() weekday = today.weekday() if weekday >= 5: # Skip weekends return {"status": "weekend", "date": str(today)} # Get all managers with wecom_userid result = await db.execute( select(User).where(User.role == "manager", User.wecom_userid.isnot(None)) ) managers = result.scalars().all() if not managers: return {"status": "ok", "date": str(today), "total_managers": 0, "reported": 0, "not_reported": 0} # Get managers who have reported today reported_visits = await db.execute( select(Visit.manager_id).where(Visit.visit_date == today) ) reported_notes = await db.execute( select(DailyNote.manager_id).where(DailyNote.note_date == today) ) reported_map = {str(uid): True for uid, in reported_visits.all()} for uid, in reported_notes.all(): reported_map[str(uid)] = True not_reported = [] reported_names = [] for m in managers: if str(m.id) in reported_map: reported_names.append(m.name) else: not_reported.append(m) # 1. Send template card to not-reported managers (tap to open app) if not_reported: user_ids = [m.wecom_userid for m in not_reported if m.wecom_userid] if user_ids: desc = f"{today} | 已填报 {len(reported_names)}/{len(managers)} 人" success = await wecom_client.send_template_card( user_ids=user_ids, title="📋 今日填报提醒", desc=desc, url="https://qj.dhdx.fun/m", btn_text="去填报", ) # Fallback to text if not success: names_text = "、".join(m.name for m in not_reported) await wecom_client.send_text_message( user_ids, f"📋 今日填报提醒\n\n{desc}\n未填报:{names_text}\n\n请尽快完成填报 🙏\nhttps://qj.dhdx.fun/m", ) # 2. Send summary to director directors = await db.execute( select(User).where(User.role.in_(["director", "leader"]), User.wecom_userid.isnot(None)) ) for d in directors.scalars().all(): if managers: pct = len(reported_map) / len(managers) * 100 summary = ( f"## 📊 今日填报汇总\n\n" f"> 日期:{today}\n" f"> 填报率:**{pct:.0f}%** ({len(reported_map)}/{len(managers)})\n\n" ) if not_reported: summary += "**未填报:**\n" + "".join(f"- {m.name}\n" for m in not_reported) else: summary += "✅ 全体已完成今日填报" await wecom_client.send_markdown_message(summary) # broadcast for director visibility return { "status": "ok", "date": str(today), "total_managers": len(managers), "reported": len(reported_map), "not_reported": len(not_reported), }