feat: exclude admins from report reminders
This commit is contained in:
parent
b538e2f8cb
commit
9a00bcf5d2
@ -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(
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user