feat: remind only missing reporters with follow-up
This commit is contained in:
parent
310a82dc1a
commit
3c7b7096dd
@ -85,6 +85,7 @@ http://你的可访问地址:8787/auth/feishu/callback
|
|||||||
本项目提供 Windows 任务计划脚本。任务每天触发,但发送前会读取 `data/workday-calendar.json`,只在国家法定工作日发送:
|
本项目提供 Windows 任务计划脚本。任务每天触发,但发送前会读取 `data/workday-calendar.json`,只在国家法定工作日发送:
|
||||||
|
|
||||||
- 工作日 18:00:日报填写提醒
|
- 工作日 18:00:日报填写提醒
|
||||||
|
- 工作日 18:50:只提醒仍未提交的人
|
||||||
- 工作日 19:00:日报提交汇总
|
- 工作日 19:00:日报提交汇总
|
||||||
|
|
||||||
这意味着:
|
这意味着:
|
||||||
|
|||||||
@ -24,7 +24,8 @@ def send_reminder() -> dict:
|
|||||||
payload = create_reminder_payload(f"{config.base_url}/submit")
|
payload = create_reminder_payload(f"{config.base_url}/submit")
|
||||||
database = Database(config.database_path, config.employee_seed_path)
|
database = Database(config.database_path, config.employee_seed_path)
|
||||||
try:
|
try:
|
||||||
employees = database.list_active_employees()
|
service = ReportService(database)
|
||||||
|
employees = service.list_reports_for_date(date.today().isoformat())["missing"]
|
||||||
if config.feishu_app_id and config.feishu_app_secret:
|
if config.feishu_app_id and config.feishu_app_secret:
|
||||||
token = get_tenant_access_token(config.feishu_app_id, config.feishu_app_secret)
|
token = get_tenant_access_token(config.feishu_app_id, config.feishu_app_secret)
|
||||||
sent = []
|
sent = []
|
||||||
|
|||||||
76
scripts/install-linux-timers.sh
Normal file
76
scripts/install-linux-timers.sh
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROJECT_ROOT="/root/kaikai_test"
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/kaikai-daily-reminder.service <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Kaikai Daily Report Reminder
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
WorkingDirectory=/root/kaikai_test
|
||||||
|
ExecStart=/usr/bin/python3 -m daily_report.scheduled reminder
|
||||||
|
Type=oneshot
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/kaikai-daily-reminder.timer <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Run Kaikai Daily Report Reminder at 18:00
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=*-*-* 18:00:00
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/kaikai-daily-reminder-followup.service <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Kaikai Daily Report Follow-up Reminder
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
WorkingDirectory=/root/kaikai_test
|
||||||
|
ExecStart=/usr/bin/python3 -m daily_report.scheduled reminder
|
||||||
|
Type=oneshot
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/kaikai-daily-reminder-followup.timer <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Run Kaikai Daily Report Follow-up Reminder at 18:50
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=*-*-* 18:50:00
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/kaikai-daily-summary.service <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Kaikai Daily Report Summary
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
WorkingDirectory=/root/kaikai_test
|
||||||
|
ExecStart=/usr/bin/python3 -m daily_report.scheduled summary
|
||||||
|
Type=oneshot
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/kaikai-daily-summary.timer <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Run Kaikai Daily Report Summary at 19:00
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=*-*-* 19:00:00
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now kaikai-daily-reminder.timer
|
||||||
|
systemctl enable --now kaikai-daily-reminder-followup.timer
|
||||||
|
systemctl enable --now kaikai-daily-summary.timer
|
||||||
|
systemctl list-timers --all | grep kaikai || true
|
||||||
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||||||
import json
|
import json
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
from datetime import date
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ class ScheduledTest(unittest.TestCase):
|
|||||||
self.assertIn("0/2", text)
|
self.assertIn("0/2", text)
|
||||||
self.assertIn("Chen、Lin", text)
|
self.assertIn("Chen、Lin", text)
|
||||||
|
|
||||||
def test_send_reminder_private_messages_all_active_employees(self) -> None:
|
def test_send_reminder_private_messages_missing_employees_only(self) -> None:
|
||||||
with tempfile.TemporaryDirectory(prefix="daily-report-scheduled-") as temp:
|
with tempfile.TemporaryDirectory(prefix="daily-report-scheduled-") as temp:
|
||||||
root = Path(temp)
|
root = Path(temp)
|
||||||
seed_path = root / "employees.json"
|
seed_path = root / "employees.json"
|
||||||
@ -87,7 +88,8 @@ class ScheduledTest(unittest.TestCase):
|
|||||||
|
|
||||||
with patch("daily_report.config.__file__", str(fake_file)), patch.dict("os.environ", env, clear=True), patch(
|
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"
|
"daily_report.scheduled.get_tenant_access_token", lambda app_id, app_secret: "tenant-token"
|
||||||
), patch("daily_report.scheduled.send_bot_interactive_message", fake_send):
|
), patch("daily_report.scheduled.send_bot_interactive_message", fake_send), patch("daily_report.scheduled.date") as fake_date:
|
||||||
|
fake_date.today.return_value = date(2026, 5, 7)
|
||||||
result = scheduled.send_reminder()
|
result = scheduled.send_reminder()
|
||||||
|
|
||||||
self.assertEqual(result["mode"], "bot_private")
|
self.assertEqual(result["mode"], "bot_private")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user