feat: exclude admins from report reminders

This commit is contained in:
Codex 2026-05-08 17:30:30 +08:00
parent b538e2f8cb
commit 9a00bcf5d2
5 changed files with 87 additions and 6 deletions

View File

@ -120,6 +120,18 @@ class Database:
).fetchall()
return [dict(row) for row in rows]
def list_report_required_employees(self) -> list[dict[str, Any]]:
with self._lock:
rows = self.connection.execute(
"""
SELECT feishu_user_id, name, department, manager, role, active
FROM employees
WHERE active = 1 AND role != 'admin'
ORDER BY department, name
"""
).fetchall()
return [dict(row) for row in rows]
def find_employee(self, feishu_user_id: str) -> dict[str, Any] | None:
with self._lock:
row = self.connection.execute(

View File

@ -61,14 +61,19 @@ class ReportService:
)
return next(
report
for report in self.list_reports_for_date(report_date)["reports"]
for report in self.database.list_reports_for_employee(feishu_user_id, 1)
if report["feishu_user_id"] == feishu_user_id
)
def list_reports_for_date(self, report_date: str) -> dict[str, Any]:
date = _required_text(report_date, "report_date")
employees = self.database.list_active_employees()
reports = self.database.list_reports_for_date(date)
employees = self.database.list_report_required_employees()
required_ids = {employee["feishu_user_id"] for employee in employees}
reports = [
report
for report in self.database.list_reports_for_date(date)
if report["feishu_user_id"] in required_ids
]
submitted_ids = {report["feishu_user_id"] for report in reports}
missing = [employee for employee in employees if employee["feishu_user_id"] not in submitted_ids]
return {

View File

@ -120,6 +120,32 @@ class ReportServiceTest(unittest.TestCase):
finally:
db.close()
def test_admins_are_not_required_to_submit_reports(self) -> None:
db = make_database(
[
{"feishu_user_id": "u_admin", "name": "Admin", "active": True, "role": "admin"},
{"feishu_user_id": "u_staff", "name": "Staff", "active": True, "role": "staff"},
]
)
service = ReportService(db, clock=lambda: datetime(2026, 5, 7, 10, tzinfo=timezone.utc))
try:
service.upsert_report(
{
"feishu_user_id": "u_admin",
"report_date": "2026-05-07",
"today_done": "1. 查看汇总",
"tomorrow_plan": "1. 继续跟进",
}
)
result = service.list_reports_for_date("2026-05-07")
self.assertEqual(result["expectedCount"], 1)
self.assertEqual(result["submittedCount"], 0)
self.assertEqual(result["missingCount"], 1)
self.assertEqual(result["missing"][0]["name"], "Staff")
self.assertEqual(result["reports"], [])
finally:
db.close()
if __name__ == "__main__":
unittest.main()

View File

@ -95,6 +95,44 @@ class ScheduledTest(unittest.TestCase):
self.assertEqual(result["mode"], "bot_private")
self.assertEqual([item[1] for item in sent], ["ou_2", "ou_1"])
def test_send_reminder_skips_admins(self) -> None:
with tempfile.TemporaryDirectory(prefix="daily-report-scheduled-") as temp:
root = Path(temp)
seed_path = root / "employees.json"
seed_path.write_text(
json.dumps(
[
{"feishu_user_id": "ou_admin", "name": "Admin", "active": True, "role": "admin"},
{"feishu_user_id": "ou_staff", "name": "Staff", "active": True, "role": "staff"},
],
ensure_ascii=False,
),
encoding="utf-8",
)
fake_file = root / "daily_report" / "config.py"
fake_file.parent.mkdir()
fake_file.write_text("", encoding="utf-8")
env = {
"DATABASE_PATH": "test.sqlite",
"EMPLOYEE_SEED_PATH": "employees.json",
"BASE_URL": "http://localhost:8787",
"FEISHU_APP_ID": "cli_test",
"FEISHU_APP_SECRET": "secret",
}
sent = []
with patch("daily_report.config.__file__", str(fake_file)), patch.dict("os.environ", env, clear=True), patch(
"daily_report.scheduled.get_tenant_access_token", lambda app_id, app_secret: "tenant-token"
), patch(
"daily_report.scheduled.send_bot_interactive_message",
lambda token, receive_id, payload: sent.append(receive_id) or {"ok": True},
), patch("daily_report.scheduled.date") as fake_date:
fake_date.today.return_value = date(2026, 5, 7)
result = scheduled.send_reminder()
self.assertEqual(result["mode"], "bot_private")
self.assertEqual(sent, ["ou_staff"])
def test_send_summary_private_messages_admins_only(self) -> None:
with tempfile.TemporaryDirectory(prefix="daily-report-scheduled-") as temp:
root = Path(temp)

View File

@ -137,15 +137,15 @@ class WebTest(unittest.TestCase):
db.upsert_employee(
{
"feishu_user_id": "u_1",
"name": "Lin",
"feishu_user_id": "u_admin",
"name": "Admin",
"department": "Design",
"manager": "",
"active": True,
"role": "admin",
}
)
status, body = get_with_cookie(f"{base_url}/api/reports?date=2026-05-07", admin_cookie())
status, body = get_with_cookie(f"{base_url}/api/reports?date=2026-05-07", admin_cookie("u_admin", "Admin"))
summary = json.loads(body)
self.assertEqual(status, 200)
self.assertEqual(summary["submittedCount"], 1)