Files
windmill/workflows/f/shiraou/shiraou_notification__flow/変更確認・line通知.py
2026-02-21 07:00:01 +00:00

133 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import urllib.request
import urllib.parse
import json
import ssl
from datetime import datetime, timezone, timedelta
import wmill
JST = timezone(timedelta(hours=9))
def main():
# シークレット取得
api_key = wmill.get_variable("u/admin/NOTIFICATION_API_KEY")
line_token = wmill.get_variable("u/admin/LINE_CHANNEL_ACCESS_TOKEN")
line_to = wmill.get_variable("u/admin/LINE_TO")
# 前回実行時刻を取得(初回は現在時刻 - 10分
try:
last_checked = wmill.get_variable("u/admin/SHIRAOU_LAST_CHECKED_AT")
if not last_checked:
last_checked = None
except Exception:
last_checked = None
if last_checked:
since = last_checked
else:
since = (datetime.now(JST) - timedelta(minutes=10)).isoformat()
print(f"[通知] 変更確認: since={since}")
# API呼び出し
ssl_ctx = ssl.create_default_context()
ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.CERT_NONE
params = urllib.parse.urlencode({"since": since})
url = f"https://shiraou.keinafarm.net/reservations/api/changes/?{params}"
req = urllib.request.Request(url, headers={"X-API-Key": api_key})
with urllib.request.urlopen(req, context=ssl_ctx, timeout=30) as resp:
data = json.loads(resp.read().decode("utf-8"))
checked_at = data["checked_at"]
reservations = data.get("reservations", [])
usages = data.get("usages", [])
print(f"[通知] checked_at={checked_at}, 予約={len(reservations)}件, 実績={len(usages)}")
# 変更があればLINE通知エラー時は状態を更新しない
if reservations or usages:
message = _format_message(reservations, usages)
_send_line(line_token, line_to, message)
print("[通知] LINE送信完了")
else:
print("[通知] 変更なし、通知スキップ")
# 正常完了時のみ状態更新
wmill.set_variable("u/admin/SHIRAOU_LAST_CHECKED_AT", checked_at)
print(f"[通知] last_checked_at更新: {checked_at}")
return {
"since": since,
"checked_at": checked_at,
"reservations_count": len(reservations),
"usages_count": len(usages),
"notified": bool(reservations or usages),
}
def _format_message(reservations, usages):
lines = ["\U0001f4cb 営農システム 変更通知\n"]
OP_R = {
"create": ("\U0001f7e2", "予約作成"),
"update": ("\U0001f535", "予約変更"),
"cancel": ("\U0001f534", "予約キャンセル"),
}
OP_U = {
"create": ("\U0001f7e2", "実績登録"),
"update": ("\U0001f535", "実績修正"),
"delete": ("\U0001f534", "実績削除"),
}
for r in reservations:
start = r["start_at"][:16].replace("T", " ")
end = r["end_at"][:16].replace("T", " ")
icon, label = OP_R.get(r["operation"], ("\u26aa", r["operation"]))
lines += [
f"{icon} {label}",
f" 機械: {r['machine_name']}",
f" 利用者: {r['user_name']}",
f" 日時: {start} \uff5e {end}",
]
if r.get("reason"):
lines.append(f" 理由: {r['reason']}")
lines.append("")
for u in usages:
start = u["start_at"][:16].replace("T", " ")
icon, label = OP_U.get(u["operation"], ("\u26aa", u["operation"]))
lines += [
f"{icon} {label}",
f" 機械: {u['machine_name']}",
f" 利用者: {u['user_name']}",
f" 利用量: {u['amount']}{u['unit']}",
f" 日: {start[:10]}",
]
if u.get("reason"):
lines.append(f" 理由: {u['reason']}")
lines.append("")
return "\n".join(lines).strip()
def _send_line(token, to, message):
payload = json.dumps({
"to": to,
"messages": [{"type": "text", "text": message}],
}).encode("utf-8")
req = urllib.request.Request(
"https://api.line.me/v2/bot/message/push",
data=payload,
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req, timeout=30) as resp:
return resp.read().decode("utf-8")