From d4fca415b849e76400a2066d7b5453854c7b83a3 Mon Sep 17 00:00:00 2001 From: fezzlk Date: Tue, 3 Mar 2026 09:44:24 +0900 Subject: [PATCH] =?UTF-8?q?=E7=94=BB=E9=9D=A2=E5=8F=8A=E3=81=B3=E6=A9=9F?= =?UTF-8?q?=E8=83=BD=E6=94=B9=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MCP_AUTO_RECOVERY_SETUP.md | 77 ++++++++++ scripts/assets/rich_menu_default.png | Bin 79596 -> 89978 bytes scripts/capture_rich_menu.py | 24 ++++ scripts/rich_menu_preview.html | 131 ++++++++++++++++++ scripts/setup_line_rich_menu.py | 2 +- src/Domains/Entities/HabitTask.py | 8 ++ src/Domains/Entities/Stock.py | 8 +- src/UseCases/Line/AddStockUseCase.py | 1 - src/UseCases/Line/CheckExpiredStockUseCase.py | 50 ++++--- src/UseCases/Line/CheckHabitTaskUseCase.py | 13 +- .../Line/HandleIntentOperationUseCase.py | 74 ++++++++-- src/UseCases/Line/ReplyHelpUseCase.py | 96 ++++++++----- src/UseCases/Line/ReplyStockUseCase.py | 81 +++++++---- .../Line/RequestLinkLineWebUseCase.py | 41 +----- .../test_check_expired_stock_use_case.py | 34 +++-- .../Line/tests/test_habit_task_use_cases.py | 120 ++++++++++++++++ .../test_handle_intent_operation_use_case.py | 87 ++++++++++-- .../Line/tests/test_reply_help_use_case.py | 15 +- .../Line/tests/test_reply_stock_use_case.py | 5 +- .../test_request_link_line_web_use_case.py | 95 ++----------- src/UseCases/Web/UpdateStockUseCase.py | 15 +- src/models/StockViewModel.py | 3 +- src/routes/handle_line_event.py | 4 + src/services/LineIntentParserService.py | 84 ++++++++--- .../tests/test_line_intent_parser_service.py | 75 +++++++--- 25 files changed, 855 insertions(+), 288 deletions(-) create mode 100644 MCP_AUTO_RECOVERY_SETUP.md create mode 100644 scripts/capture_rich_menu.py create mode 100644 scripts/rich_menu_preview.html diff --git a/MCP_AUTO_RECOVERY_SETUP.md b/MCP_AUTO_RECOVERY_SETUP.md new file mode 100644 index 0000000..afb058e --- /dev/null +++ b/MCP_AUTO_RECOVERY_SETUP.md @@ -0,0 +1,77 @@ +# Codex MCP Auto-Recovery Setup + +PC再起動後も、CodexがMCP接続時に `cloud-run-logging-mcp` を自動起動・復旧するための手順です。 +他プロジェクトへ横展開できるように、共通化前提でまとめています。 + +## 前提 + +- Codexは `~/.codex/config.toml` の `mcp_servers` を参照してMCPを起動する +- 再起動後に接続が切れる主な原因は以下 + - Docker daemon 未起動 + - MCPイメージ未build + - 鍵ファイルパス不整合 + +## 1. ラッパースクリプトを作成 + +各プロジェクトに `scripts/start_cloud_run_logging_mcp.sh` を作成します。 + +```bash +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +MCP_REPO_DIR="${MCP_REPO_DIR:-${SCRIPT_DIR}/../../cloud-run-logging-mcp}" +MCP_IMAGE="${MCP_IMAGE:-cloud-run-logging-mcp:local}" +MCP_KEY_PATH="${MCP_KEY_PATH:-/absolute/path/to/sa.json}" + +docker info >/dev/null 2>&1 || { [[ "$(uname)" == "Darwin" ]] && open -ga Docker || true; } +for i in {1..90}; do docker info >/dev/null 2>&1 && break; sleep 2; done +docker info >/dev/null 2>&1 + +docker image inspect "${MCP_IMAGE}" >/dev/null 2>&1 || docker build -t "${MCP_IMAGE}" "${MCP_REPO_DIR}" +[[ -f "${MCP_KEY_PATH}" ]] + +exec docker run --rm -i \ + -e GCP_SA_JSON_PATH=/secrets/key.json \ + -v "${MCP_KEY_PATH}:/secrets/key.json:ro" \ + "${MCP_IMAGE}" +``` + +## 2. 実行権限を付与 + +```bash +chmod +x scripts/start_cloud_run_logging_mcp.sh +``` + +## 3. `~/.codex/config.toml` を設定 + +`mcp_servers.cloud-run-logging-mcp` をラッパー呼び出しに変更します。 + +```toml +personality = "pragmatic" + +[mcp_servers.cloud-run-logging-mcp] +command = "/bin/zsh" +args = ["-lc", "/ABSOLUTE/PATH/TO/PROJECT/scripts/start_cloud_run_logging_mcp.sh"] +enabled = true +``` + +## 4. プロジェクト差分を環境変数で吸収 + +必要に応じて以下を上書きします。 + +- `MCP_KEY_PATH` +- `MCP_REPO_DIR` +- `MCP_IMAGE` + +## 5. 動作確認 + +1. Dockerを停止した状態でCodexを起動 +2. MCPツール(Cloud Runログ取得)を実行 +3. 自動でDocker起動待ち・MCP起動され、ログ取得できることを確認 + +## 運用メモ + +- 複数プロジェクトで同一MCPを使う場合: + - スクリプトを `~/.codex/bin/` などに1本化し、各プロジェクトは同じスクリプトを参照 +- `config.toml` は相対パスより絶対パス運用が安定 diff --git a/scripts/assets/rich_menu_default.png b/scripts/assets/rich_menu_default.png index 1530eb52e02e1c046f905067ae072cc5107db06c..3d96d2028d9d4d708cc3ca66ffef4c57f1e5796c 100644 GIT binary patch literal 89978 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 literal 79596 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 diff --git a/scripts/capture_rich_menu.py b/scripts/capture_rich_menu.py new file mode 100644 index 0000000..758e2fc --- /dev/null +++ b/scripts/capture_rich_menu.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +"""Capture rich_menu_preview.html as a 2500x1686 PNG using Playwright.""" +import sys +from pathlib import Path +from playwright.sync_api import sync_playwright + +HTML_PATH = Path(__file__).parent / "rich_menu_preview.html" +OUTPUT = Path(__file__).parent / "assets" / "rich_menu_default.png" + + +def main(): + with sync_playwright() as p: + browser = p.chromium.launch() + page = browser.new_page(viewport={"width": 2500, "height": 1686}) + page.goto(f"file://{HTML_PATH.resolve()}") + # Google Fontsの読み込みを待つ + page.wait_for_load_state("networkidle") + page.screenshot(path=str(OUTPUT), full_page=False) + browser.close() + print(f"Saved: {OUTPUT}") + + +if __name__ == "__main__": + main() diff --git a/scripts/rich_menu_preview.html b/scripts/rich_menu_preview.html new file mode 100644 index 0000000..bc677cc --- /dev/null +++ b/scripts/rich_menu_preview.html @@ -0,0 +1,131 @@ + + + + + + + + +

+ +
+
+ format_list_bulleted +
+
一覧
+
+ +
+
+ add_circle +
+
登録
+
+ +
+
+ help +
+
使い方
+
+ +
+
+ language +
+
Web一覧
+
+ +
+
+ calendar_month +
+
カレンダー
+
+ +
+
+ task_alt +
+
習慣タスク
+
+
+ + diff --git a/scripts/setup_line_rich_menu.py b/scripts/setup_line_rich_menu.py index 7ef08e7..0d0be3c 100644 --- a/scripts/setup_line_rich_menu.py +++ b/scripts/setup_line_rich_menu.py @@ -73,7 +73,7 @@ def _build_rich_menu(name: str, chat_bar_text: str, server_url: str) -> RichMenu ), RichMenuArea( bounds=RichMenuBounds(x=833, y=843, width=833, height=843), - action=MessageAction(label="連携", text="アカウント連携"), + action=URIAction(label="カレンダー", uri=habit_url), ), RichMenuArea( bounds=RichMenuBounds(x=1666, y=843, width=834, height=843), diff --git a/src/Domains/Entities/HabitTask.py b/src/Domains/Entities/HabitTask.py index 27d3132..143838a 100644 --- a/src/Domains/Entities/HabitTask.py +++ b/src/Domains/Entities/HabitTask.py @@ -1,5 +1,6 @@ from dataclasses import dataclass from datetime import datetime +from typing import Optional @dataclass() @@ -12,6 +13,8 @@ class HabitTask: is_active: bool created_at: datetime updated_at: datetime + notify_day_of_week: Optional[int] # 0=月〜6=日(weekly用) + notify_day_of_month: Optional[int] # 1〜31(monthly用) def __init__( self, @@ -23,6 +26,9 @@ def __init__( is_active: bool = True, created_at: datetime = datetime.now(), updated_at: datetime = datetime.now(), + notify_day_of_week: Optional[int] = None, + notify_day_of_month: Optional[int] = None, + **kwargs, ): self._id = _id self.owner_id = owner_id @@ -32,3 +38,5 @@ def __init__( self.is_active = is_active self.created_at = created_at self.updated_at = updated_at + self.notify_day_of_week = notify_day_of_week + self.notify_day_of_month = notify_day_of_month diff --git a/src/Domains/Entities/Stock.py b/src/Domains/Entities/Stock.py index 01d97a7..965273b 100644 --- a/src/Domains/Entities/Stock.py +++ b/src/Domains/Entities/Stock.py @@ -1,5 +1,6 @@ from dataclasses import dataclass from datetime import datetime +from typing import Optional STOCK_STATUS = ['disabled', 'active', 'archived'] @@ -11,7 +12,7 @@ class Stock: owner_id: str expiry_date: datetime status: int - notify_enabled: bool + notify_days_before: Optional[int] created_at: datetime updated_at: datetime @@ -22,15 +23,16 @@ def __init__( owner_id: str = None, expiry_date: datetime = None, status: int = 0, - notify_enabled: bool = False, + notify_days_before: Optional[int] = None, created_at: datetime = datetime.now(), updated_at: datetime = datetime.now(), + **kwargs, ): self._id = _id self.item_name = item_name self.owner_id = owner_id self.expiry_date = expiry_date self.status = status - self.notify_enabled = notify_enabled + self.notify_days_before = notify_days_before self.created_at = created_at self.updated_at = updated_at diff --git a/src/UseCases/Line/AddStockUseCase.py b/src/UseCases/Line/AddStockUseCase.py index cb4342e..47079da 100644 --- a/src/UseCases/Line/AddStockUseCase.py +++ b/src/UseCases/Line/AddStockUseCase.py @@ -70,7 +70,6 @@ def execute(self) -> None: owner_id=self._line_request_service.req_line_user_id, expiry_date=expiry_date, status=1, - notify_enabled=False, ) self._stock_repository.create(new_stock) diff --git a/src/UseCases/Line/CheckExpiredStockUseCase.py b/src/UseCases/Line/CheckExpiredStockUseCase.py index 47ed2f2..e5489a2 100644 --- a/src/UseCases/Line/CheckExpiredStockUseCase.py +++ b/src/UseCases/Line/CheckExpiredStockUseCase.py @@ -1,11 +1,16 @@ from datetime import datetime, timezone -from src import config from src.Domains.IRepositories.IStockRepository import IStockRepository from src.Domains.IRepositories.IWebUserRepository import IWebUserRepository from src.UseCases.Interface.ILineResponseService import ILineResponseService from src.UseCases.Interface.IUseCase import IUseCase -from src.line_rich_messages import add_stock_web_link_button + + +def _should_notify(stock, days_until_expire: int) -> bool: + """notify_days_beforeに基づいて通知すべきかを判定""" + if stock.notify_days_before is None: # 常に通知 + return True + return days_until_expire <= stock.notify_days_before class CheckExpiredStockUseCase(IUseCase): @@ -52,41 +57,40 @@ def execute(self) -> None: "status": 1, } ) - near_due_stocks = [] - notify_on_items = [] + notify_stocks = [] for stock in stocks: - if stock.notify_enabled: - notify_on_items.append(stock.item_name) - if stock.expiry_date is None: continue days_until_expire = (stock.expiry_date.date() - today).days - if days_until_expire < 0 or days_until_expire > 3: + + if not _should_notify(stock, days_until_expire): continue - if days_until_expire == 0: + if days_until_expire < 0: + label = f"{abs(days_until_expire)}日超過" + icon = "🔴" + elif days_until_expire == 0: label = "今日まで" + icon = "🟠" elif days_until_expire == 1: label = "明日まで" + icon = "🟠" + elif days_until_expire <= 3: + label = f"残り{days_until_expire}日" + icon = "🟠" + elif days_until_expire <= 7: + label = f"残り{days_until_expire}日" + icon = "🟡" else: - label = f"あと{days_until_expire}日" - near_due_stocks.append(f"{stock.item_name}: {label}") + label = f"残り{days_until_expire}日" + icon = "🟢" + notify_stocks.append(f"{icon} {stock.item_name}({label})") - if len(near_due_stocks) == 0: + if not notify_stocks: continue self._line_response_service.add_message( - "期限が3日以内のもの:\n" + "\n".join(near_due_stocks) - ) - add_stock_web_link_button( - line_response_service=self._line_response_service, - server_url=config.SERVER_URL, + f"📋 期限通知({len(notify_stocks)}件)\n" + "\n".join(notify_stocks) ) - if len(notify_on_items) == 0: - self._line_response_service.add_message("通知ONのアイテム: なし") - else: - self._line_response_service.add_message( - "通知ONのアイテム:\n" + "\n".join(notify_on_items) - ) self._line_response_service.push(to=schedule.line_user_id) diff --git a/src/UseCases/Line/CheckHabitTaskUseCase.py b/src/UseCases/Line/CheckHabitTaskUseCase.py index 42bb8b0..7567636 100644 --- a/src/UseCases/Line/CheckHabitTaskUseCase.py +++ b/src/UseCases/Line/CheckHabitTaskUseCase.py @@ -29,6 +29,8 @@ def __init__( def execute(self) -> None: now = datetime.now(self._notify_timezone) now_hhmm = now.strftime("%H:%M") + today_weekday = now.weekday() # 0=Monday, 6=Sunday + today_day_of_month = now.day scheduled_date = now.strftime("%Y-%m-%d") line_users = self._line_user_repository.find() @@ -41,14 +43,21 @@ def execute(self) -> None: ) linked_web_user_id = web_users[0]._id if len(web_users) != 0 else "" - tasks = self._habit_task_repository.find( + all_time_tasks = self._habit_task_repository.find( { "owner_id__in": [line_user.line_user_id, linked_web_user_id], "is_active": True, - "frequency": "daily", "notify_time": now_hhmm, } ) + tasks = [] + for task in all_time_tasks: + if task.frequency == "daily": + tasks.append(task) + elif task.frequency == "weekly" and task.notify_day_of_week == today_weekday: + tasks.append(task) + elif task.frequency == "monthly" and task.notify_day_of_month == today_day_of_month: + tasks.append(task) pushed_count = 0 for task in tasks: diff --git a/src/UseCases/Line/HandleIntentOperationUseCase.py b/src/UseCases/Line/HandleIntentOperationUseCase.py index 3410269..dd7aaf4 100644 --- a/src/UseCases/Line/HandleIntentOperationUseCase.py +++ b/src/UseCases/Line/HandleIntentOperationUseCase.py @@ -67,9 +67,11 @@ def execute(self) -> None: "item_name": parsed["item_name"], "expiry_date": parsed["expiry_date"], "exclude_expiry_date": parsed.get("exclude_expiry_date"), - "notify_enabled": parsed.get("notify_enabled", False), + "notify_days_before": parsed.get("notify_days_before"), "frequency": parsed.get("frequency"), "notify_time": parsed.get("notify_time"), + "notify_day_of_week": parsed.get("notify_day_of_week"), + "notify_day_of_month": parsed.get("notify_day_of_month"), "enabled": parsed.get("enabled"), "scheduled_date": parsed.get("scheduled_date"), "result": parsed.get("result"), @@ -83,22 +85,43 @@ def _reply_confirmation(self, parsed): item_name = parsed["item_name"] expiry_date = parsed["expiry_date"] exclude_expiry_date = parsed.get("exclude_expiry_date") - notify_enabled = parsed.get("notify_enabled", False) + notify_days_before = parsed.get("notify_days_before") frequency = parsed.get("frequency") notify_time = parsed.get("notify_time") if intent == "register": + if notify_days_before is None: + notify_suffix = "(常に通知)" + else: + notify_suffix = f"({notify_days_before}日前から通知)" if expiry_date: date_text = datetime.strptime(expiry_date, "%Y-%m-%d").strftime("%Y年%m月%d日") - notify_suffix = "(通知あり)" if notify_enabled else "" message = f'"{item_name}" を期限 {date_text} で登録します{notify_suffix}。よろしいですか?' else: - notify_suffix = "(通知あり)" if notify_enabled else "" message = f'"{item_name}" を登録します{notify_suffix}。よろしいですか?' elif intent == "register_habit": - freq_text = "毎週" if frequency == "weekly" else "毎日" + DOW_NAMES = ["月", "火", "水", "木", "金", "土", "日"] + if frequency == "weekly": + dow = parsed.get("notify_day_of_week") + day_text = f"毎週{DOW_NAMES[dow]}曜日" if dow is not None else "毎週" + elif frequency == "monthly": + dom = parsed.get("notify_day_of_month") + day_text = f"毎月{dom}日" if dom is not None else "毎月" + else: + day_text = "毎日" time_text = notify_time or "12:00" - message = f'習慣タスク "{item_name}" を登録します({freq_text} {time_text} にリマインド)。よろしいですか?' + message = f'習慣タスク "{item_name}" を登録します({day_text} {time_text} にリマインド)。よろしいですか?' + elif intent == "update_habit_frequency": + DOW_NAMES = ["月", "火", "水", "木", "金", "土", "日"] + dow = parsed.get("notify_day_of_week") + dom = parsed.get("notify_day_of_month") + if frequency == "weekly": + label = f"毎週{DOW_NAMES[dow]}曜日" if dow is not None else "毎週" + elif frequency == "monthly": + label = f"毎月{dom}日" if dom is not None else "毎月" + else: + label = "毎日" + message = f'習慣タスク "{item_name}" の頻度を {label} に変更します。よろしいですか?' elif intent == "update": date_text = datetime.strptime(expiry_date, "%Y-%m-%d").strftime("%Y年%m月%d日") message = f'"{item_name}" の期限を {date_text} に更新します。よろしいですか?' @@ -124,8 +147,8 @@ def _reply_confirmation(self, parsed): parts.append(f"時刻={notify_time}") message = f'通知設定を変更します({" / ".join(parts)})。よろしいですか?' elif intent == "update_stock_notify": - notify_enabled = parsed.get("notify_enabled", False) - message = f'"{item_name}" の通知を {"オン" if notify_enabled else "オフ"} にします。よろしいですか?' + label = "常に通知" if notify_days_before is None else f"{notify_days_before}日前から通知" + message = f'"{item_name}" の通知を {label} に設定します。よろしいですか?' elif intent == "update_habit_log": scheduled_date = parsed.get("scheduled_date") result = parsed.get("result") @@ -170,7 +193,7 @@ def _execute_pending(self, line_user_id: str) -> None: owner_id=line_user_id, expiry_date=parsed_expiry_date, status=1, - notify_enabled=operation.get("notify_enabled", False), + notify_days_before=operation.get("notify_days_before"), ) ) if parsed_expiry_date: @@ -240,6 +263,7 @@ def _execute_pending(self, line_user_id: str) -> None: self._line_response_service.add_message("習慣タスク登録は現在利用できません。") self._pending_operation_service.clear(line_user_id) return + DOW_NAMES = ["月", "火", "水", "木", "金", "土", "日"] frequency = operation.get("frequency") or "daily" notify_time = operation.get("notify_time") or "12:00" self._habit_task_repository.create( @@ -248,12 +272,21 @@ def _execute_pending(self, line_user_id: str) -> None: task_name=item_name, frequency=frequency, notify_time=notify_time, + notify_day_of_week=operation.get("notify_day_of_week"), + notify_day_of_month=operation.get("notify_day_of_month"), is_active=True, ) ) - freq_text = "毎週" if frequency == "weekly" else "毎日" + if frequency == "weekly": + dow = operation.get("notify_day_of_week") + day_text = f"毎週{DOW_NAMES[dow]}曜日" if dow is not None else "毎週" + elif frequency == "monthly": + dom = operation.get("notify_day_of_month") + day_text = f"毎月{dom}日" if dom is not None else "毎月" + else: + day_text = "毎日" self._line_response_service.add_message( - f'習慣タスク "{item_name}" を登録しました({freq_text} {notify_time} にリマインド)。' + f'習慣タスク "{item_name}" を登録しました({day_text} {notify_time} にリマインド)。' ) elif intent == "delete_habit": if self._habit_task_repository is None: @@ -303,12 +336,29 @@ def _execute_pending(self, line_user_id: str) -> None: elif intent == "update_stock_notify": count = self._stock_repository.update( query={"owner_id": line_user_id, "item_name": item_name, "status": 1}, - new_values={"notify_enabled": operation.get("notify_enabled", False)}, + new_values={"notify_days_before": operation.get("notify_days_before")}, ) if count > 0: self._line_response_service.add_message(f'"{item_name}" の通知設定を更新しました。') else: self._line_response_service.add_message(f'"{item_name}" が見つかりませんでした。') + elif intent == "update_habit_frequency": + if self._habit_task_repository is None: + self._line_response_service.add_message("習慣タスク操作は現在利用できません。") + self._pending_operation_service.clear(line_user_id) + return + count = self._habit_task_repository.update( + query={"owner_id": line_user_id, "task_name": item_name, "is_active": True}, + new_values={ + "frequency": operation.get("frequency") or "daily", + "notify_day_of_week": operation.get("notify_day_of_week"), + "notify_day_of_month": operation.get("notify_day_of_month"), + }, + ) + if count > 0: + self._line_response_service.add_message(f'習慣タスク "{item_name}" の頻度を変更しました。') + else: + self._line_response_service.add_message(f'"{item_name}" が見つかりませんでした。') elif intent == "update_habit_log": if self._habit_task_repository is None or self._habit_task_log_repository is None: self._line_response_service.add_message("習慣タスク操作は現在利用できません。") diff --git a/src/UseCases/Line/ReplyHelpUseCase.py b/src/UseCases/Line/ReplyHelpUseCase.py index a29a7fe..dd4d7ff 100644 --- a/src/UseCases/Line/ReplyHelpUseCase.py +++ b/src/UseCases/Line/ReplyHelpUseCase.py @@ -1,8 +1,16 @@ +from linebot.models import MessageAction, QuickReply, QuickReplyButton, TextSendMessage + from src import config from src.UseCases.Interface.IUseCase import IUseCase from src.UseCases.Interface.ILineRequestService import ILineRequestService from src.UseCases.Interface.ILineResponseService import ILineResponseService +_QUICK_REPLY_BUTTONS = QuickReply(items=[ + QuickReplyButton(action=MessageAction(label='➕ 登録の使い方', text='使い方 登録')), + QuickReplyButton(action=MessageAction(label='📄 一覧の使い方', text='使い方 一覧')), + QuickReplyButton(action=MessageAction(label='🔗 連携の使い方', text='使い方 アカウント連携')), +]) + class ReplyHelpUseCase(IUseCase): def __init__( @@ -16,44 +24,64 @@ def __init__( def execute(self) -> None: args = self._line_request_service.message.split() keyword = args[1] if len(args) >= 2 else None - messages = self._get_description(keyword) - for message in messages: - self._line_response_service.add_message(message) + text = self._get_description(keyword) + + if keyword is None and hasattr(self._line_response_service, 'buttons'): + self._line_response_service.buttons.append( + TextSendMessage(text=text, quick_reply=_QUICK_REPLY_BUTTONS) + ) + else: + self._line_response_service.add_message(text) - def _get_description(self, keyword): + def _get_description(self, keyword) -> str: if keyword is None: - return [ - '使い方ガイドです', - '例: 「ソファ組み立て」「ライブチケット購入 3/20まで」「打ち合わせ日程調整 2/28まで」', - '「一覧表示」「リスト表示」で一覧、「webで操作」「webで表示」でWebリンクを返します', - '更新例: 「卵の期限を3/22にして」 / 削除例: 「卵を使い切った」', - ] + return ( + '📋 Simple Alert の使い方\n\n' + 'このBotでできること:\n' + '• 期限・締切のあるものを登録して通知を受け取る\n' + '• 期限1週間前から毎日12時にリマインド\n' + '• 習慣タスクの記録・管理\n\n' + '💬 使い方はシンプル。やりたいことを日本語で送るだけ!\n\n' + '【登録】\n「卵 3/15まで」「ライブチケット 3/20まで」\n\n' + '【更新】\n「卵の期限を3/22にして」\n\n' + '【削除】\n「卵を使い切った」\n\n' + '【一覧確認】\n「一覧」と送るか、下のメニューから' + ) elif keyword in ('一覧', '一覧表示', 'リスト表示'): - return [ - '登録したアイテムを一覧で表示します', - '例: 「一覧表示」または「登録済み一覧」', - ] + return ( + '📄 一覧表示\n\n' + '登録中のアイテムをすべて表示します。\n\n' + '「一覧」と送るか、メニューの「一覧」ボタンを押してください。\n' + 'Web画面で確認したい場合はメニューの「Web一覧」から。' + ) elif keyword in ('登録', '追加'): - return [ - '食材・家具などの非食品・チケット購入・日程調整などを管理できます', - '期限が1週間前までに近づいている場合、毎日12時に通知がきます', - '例: 「卵は3/15まで」「ライブチケット購入 3/20まで」「打ち合わせ日程調整 2/28まで」', - '更新は「卵の期限を3/22にして」、削除は「卵を使い切った」と送ってください。', - ] + return ( + '➕ アイテムの登録\n\n' + '登録できるもの:食材・日用品・チケット・締切タスクなど\n\n' + '【送り方の例】\n' + '「卵 3/15まで」\n' + '「ライブチケット購入 3/20まで」\n' + '「レポート提出 2/28まで」\n\n' + '期限1週間前から毎日12時に通知が届きます。\n\n' + '更新:「卵の期限を3/22にして」\n' + '削除:「卵を使い切った」' + ) elif keyword == 'アカウント連携': - return [ - 'Web 上のアカウントと LINE アカウントを紐付けます', - '紐付けが完了すると LINE で登録したストックを Web 上で確認できるようになります', - f'まずは web 上でログインしてください → {config.SERVER_URL}/stock?openExternalBrowser=1', - '次にこのチャットにて\n"アカウント連携 [メールアドレス]"\nと送ってください。', - ] + return ( + '✅ ログインについて\n\n' + 'アカウント連携機能は廃止されました。\n\n' + '現在はLINEアカウントで直接ログインできます。\n' + f'こちらからWebアプリにアクセスしてください👇\n' + f'{config.SERVER_URL}/stock?openExternalBrowser=1' + ) elif keyword in ('URL', 'web', 'Web'): - return [ - 'Web アプリの URL を表示します', - ] + return 'WebアプリのURLを表示します。' else: - return [ - '使い方ガイドです', - '登録はアイテム名をそのまま送信(例: 「卵は3/15まで」)', - '一覧は「一覧表示」、Webは「webで操作」と送ってください。', - ] + return ( + '📋 Simple Alert の使い方\n\n' + 'やりたいことを日本語で送るだけで操作できます。\n\n' + '「卵 3/15まで」→ 登録\n' + '「卵の期限を3/22にして」→ 更新\n' + '「卵を使い切った」→ 削除\n' + '「一覧」→ 一覧表示' + ) diff --git a/src/UseCases/Line/ReplyStockUseCase.py b/src/UseCases/Line/ReplyStockUseCase.py index 7dea972..fd4a3ec 100644 --- a/src/UseCases/Line/ReplyStockUseCase.py +++ b/src/UseCases/Line/ReplyStockUseCase.py @@ -1,11 +1,36 @@ -from src import config from datetime import datetime from src.UseCases.Interface.IUseCase import IUseCase from src.Domains.IRepositories.IStockRepository import IStockRepository from src.Domains.IRepositories.IWebUserRepository import IWebUserRepository from src.UseCases.Interface.ILineRequestService import ILineRequestService from src.UseCases.Interface.ILineResponseService import ILineResponseService -from src.line_rich_messages import add_stock_web_link_button + + +def _days_left(expiry_date: datetime) -> int: + return (expiry_date.date() - datetime.now().date()).days + + +def _expiry_label(expiry_date: datetime) -> str: + days = _days_left(expiry_date) + date_str = expiry_date.strftime("%-m/%-d") + if days < 0: + return f'{date_str}({abs(days)}日超過)' + if days == 0: + return f'{date_str}(今日まで)' + if days == 1: + return f'{date_str}(明日まで)' + return f'{date_str}(残り{days}日)' + + +def _urgency_icon(expiry_date: datetime) -> str: + days = _days_left(expiry_date) + if days < 0: + return '🔴' + if days <= 3: + return '🟠' + if days <= 7: + return '🟡' + return '🟢' class ReplyStockUseCase(IUseCase): @@ -26,8 +51,7 @@ def execute(self) -> None: 'linked_line_user_id': self._line_request_service.req_line_user_id, 'is_linked_line': True, }) - linked_web_user_id = linked_web_users[0]._id if len( - linked_web_users) != 0 else '' + linked_web_user_id = linked_web_users[0]._id if len(linked_web_users) != 0 else '' stocks = self._stock_repository.find({ 'owner_id__in': [ linked_web_user_id, @@ -36,27 +60,30 @@ def execute(self) -> None: 'status': 1, }) - stocks_with_expire_date = [] - stocks_without_expire_date = [] - for stock in stocks: - if stock.expiry_date is not None: - stocks_with_expire_date.append( - f'{stock.item_name}: {stock.expiry_date.strftime("%Y年%m月%d日")}') - else: - elapsed_time = (datetime.now() - stock.created_at).days + 1 - stocks_without_expire_date.append( - f'{stock.item_name}: 登録から{elapsed_time}日目') - - sections = [] - if len(stocks_without_expire_date) != 0: - sections.append('期限未設定:\n' + '\n'.join(stocks_without_expire_date)) - if len(stocks_with_expire_date) != 0: - sections.append('期限あり:\n' + '\n'.join(stocks_with_expire_date)) - if len(sections) == 0: - sections.append('登録中のアイテムはありません。') - - self._line_response_service.add_message('\n\n'.join(sections)) - add_stock_web_link_button( - line_response_service=self._line_response_service, - server_url=config.SERVER_URL, + if not stocks: + self._line_response_service.add_message('登録中のアイテムはありません。') + return + + with_expiry = sorted( + [s for s in stocks if s.expiry_date is not None], + key=lambda s: s.expiry_date, ) + without_expiry = [s for s in stocks if s.expiry_date is None] + + lines = [f'📋 登録中のアイテム({len(stocks)}件)'] + + if with_expiry: + lines.append('') + lines.append('⏰ 期限あり') + for s in with_expiry: + icon = _urgency_icon(s.expiry_date) + lines.append(f'{icon} {s.item_name} {_expiry_label(s.expiry_date)}') + + if without_expiry: + lines.append('') + lines.append('📌 期限なし') + for s in without_expiry: + elapsed = (datetime.now() - s.created_at).days + 1 + lines.append(f'• {s.item_name}(登録{elapsed}日目)') + + self._line_response_service.add_message('\n'.join(lines)) diff --git a/src/UseCases/Line/RequestLinkLineWebUseCase.py b/src/UseCases/Line/RequestLinkLineWebUseCase.py index 1040179..2d3fe69 100644 --- a/src/UseCases/Line/RequestLinkLineWebUseCase.py +++ b/src/UseCases/Line/RequestLinkLineWebUseCase.py @@ -17,40 +17,9 @@ def __init__( self._line_response_service = line_response_service def execute(self) -> None: - args = self._line_request_service.message.split() - - if len(args) != 2: - self._line_response_service.add_message( - 'Web アカウントと紐付けするには "アカウント連携 [メールアドレス]" と送ってください。') - return - - email = args[1] - web_users = self._web_user_repository.find({'web_user_email': email}) - - if len(web_users) == 0: - self._line_response_service.add_message( - f'{email} は登録されていません。一度ブラウザでログインしてください。') - self._line_response_service.add_message( - f'{config.SERVER_URL}/line/approve?openExternalBrowser=1') - return - - if web_users[0].is_linked_line_user: - self._line_response_service.add_message( - f'{email} はすでに LINE アカウントと紐付けされています。') - self._line_response_service.add_message( - f'{config.SERVER_URL}/line/approve?openExternalBrowser=1') - return - - result = self._web_user_repository.update( - {'_id': web_users[0]._id}, - {'linked_line_user_id': self._line_request_service.req_line_user_id}, - ) - - if result == 0: - self._line_response_service.add_message('アカウント連携リクエストに失敗しました。') - return - self._line_response_service.add_message( - 'アカウント連携リクエストを送信しました。ブラウザでログインし、承認してください。') - self._line_response_service.add_message( - f'{config.SERVER_URL}/line/approve?openExternalBrowser=1') + 'アカウント連携機能は廃止されました。\n\n' + '現在はLINEアカウントで直接ログインできます。\n' + f'こちらからWebアプリにアクセスしてください👇\n' + f'{config.SERVER_URL}/stock?openExternalBrowser=1' + ) diff --git a/src/UseCases/Line/tests/test_check_expired_stock_use_case.py b/src/UseCases/Line/tests/test_check_expired_stock_use_case.py index a81e693..5bcbd1a 100644 --- a/src/UseCases/Line/tests/test_check_expired_stock_use_case.py +++ b/src/UseCases/Line/tests/test_check_expired_stock_use_case.py @@ -106,7 +106,6 @@ def now(cls, tz=None): "src.UseCases.Line.CheckExpiredStockUseCase.datetime", FixedDatetime, ) - monkeypatch.setattr(config, "SERVER_URL", "https://example.com") due_schedule = NotificationSchedule( line_user_id="U1", @@ -124,12 +123,18 @@ def now(cls, tz=None): ) stocks = [ - Stock(item_name="no_expiry", owner_id="U1", expiry_date=None, status=1, notify_enabled=True, created_at=fixed_now), + # expiry_date=None → 通知対象外(expiry_dateなしはスキップ) + Stock(item_name="no_expiry", owner_id="U1", expiry_date=None, status=1, created_at=fixed_now), + # 2日超過 → notify_days_before=None(常に通知)なので含まれる Stock(item_name="expired", owner_id="U1", expiry_date=datetime(2025, 1, 8), status=1, created_at=fixed_now), + # 今日まで → 常に通知 Stock(item_name="today", owner_id="U1", expiry_date=datetime(2025, 1, 10), status=1, created_at=fixed_now), + # 明日まで → 常に通知 Stock(item_name="tomorrow", owner_id="U1", expiry_date=datetime(2025, 1, 11), status=1, created_at=fixed_now), - Stock(item_name="three_days", owner_id="U1", expiry_date=datetime(2025, 1, 13), status=1, notify_enabled=True, created_at=fixed_now), - Stock(item_name="future", owner_id="U1", expiry_date=datetime(2025, 1, 20), status=1, notify_enabled=True, created_at=fixed_now), + # 残り3日 → notify_days_before=3 なので3日前から通知 → 含まれる + Stock(item_name="three_days", owner_id="U1", expiry_date=datetime(2025, 1, 13), status=1, notify_days_before=3, created_at=fixed_now), + # 残り10日 → notify_days_before=5 なので5日前から通知 → 10日 > 5日 → 含まれない + Stock(item_name="future", owner_id="U1", expiry_date=datetime(2025, 1, 20), status=1, notify_days_before=5, created_at=fixed_now), ] notification_schedule_repository = DummyNotificationScheduleRepository([due_schedule]) @@ -149,15 +154,14 @@ def now(cls, tz=None): assert notification_schedule_repository.claimed_line_user_ids == ["U1"] assert line_response_service.pushes == ["U1"] joined = "\n".join(line_response_service.messages) - assert "webで一覧を確認" in joined - assert "期限が3日以内のもの" in joined - assert "today: 今日まで" in joined - assert "tomorrow: 明日まで" in joined - assert "three_days: あと3日" in joined - assert "通知ONのアイテム" in joined - assert "no_expiry" in joined - assert "future" in joined - assert "expired" not in joined + assert "期限通知" in joined + assert "今日まで" in joined + assert "明日まで" in joined + assert "three_days" in joined + assert "日超過" in joined # expiredアイテムが含まれる + assert "expired" in joined + assert "no_expiry" not in joined # expiry_dateなしは除外 + assert "future" not in joined # notify_days_before=5 で10日先は除外 def test_check_expired_stock_does_not_push_when_no_active_stocks(monkeypatch): @@ -193,7 +197,9 @@ def now(cls, tz=None): web_user_repository = DummyWebUserRepository([web_user]) stock_repository = DummyStockRepository( [ - Stock(item_name="far", owner_id="U1", expiry_date=datetime(2025, 1, 30), status=1), + # notify_days_before=5 かつ残り20日 → 5日前まで通知しないので対象外 + Stock(item_name="far", owner_id="U1", expiry_date=datetime(2025, 1, 30), status=1, notify_days_before=5), + # expiry_dateなし → 常に通知でも期限なしはスキップ Stock(item_name="none", owner_id="U1", expiry_date=None, status=1), ] ) diff --git a/src/UseCases/Line/tests/test_habit_task_use_cases.py b/src/UseCases/Line/tests/test_habit_task_use_cases.py index 57f5956..9e05698 100644 --- a/src/UseCases/Line/tests/test_habit_task_use_cases.py +++ b/src/UseCases/Line/tests/test_habit_task_use_cases.py @@ -159,6 +159,126 @@ def now(cls, tz=None): assert any("習慣タスク確認" in msg for msg in use_case._line_response_service.messages) +def test_check_habit_weekly_task_sends_on_correct_day(monkeypatch): + # 土曜日(weekday=5)にnotify_day_of_week=5のタスクが通知される + fixed_now = datetime(2026, 3, 7, 9, 0, 0) # 2026-03-07は土曜日 + + class FixedDatetime(datetime): + @classmethod + def now(cls, tz=None): + return fixed_now + + monkeypatch.setattr("src.UseCases.Line.CheckHabitTaskUseCase.datetime", FixedDatetime) + + line_users = [LineUser(line_user_name="u1", line_user_id="U1")] + web_users = [] + tasks = [ + HabitTask(_id="T1", owner_id="U1", task_name="週次筋トレ", + frequency="weekly", notify_time="09:00", notify_day_of_week=5) + ] + + use_case = CheckHabitTaskUseCase( + line_user_repository=DummyLineUserRepository(line_users), + web_user_repository=DummyWebUserRepository(web_users), + habit_task_repository=DummyHabitTaskRepository(tasks), + habit_task_log_repository=DummyHabitTaskLogRepository(), + habit_pending_confirmation_repository=DummyHabitPendingRepository(), + line_response_service=DummyLineResponseService(), + ) + use_case.execute() + assert use_case._line_response_service.pushes == ["U1"] + + +def test_check_habit_weekly_task_not_sent_on_wrong_day(monkeypatch): + # 日曜日(weekday=6)にnotify_day_of_week=5(土)のタスクは通知されない + fixed_now = datetime(2026, 3, 8, 9, 0, 0) # 2026-03-08は日曜日 + + class FixedDatetime(datetime): + @classmethod + def now(cls, tz=None): + return fixed_now + + monkeypatch.setattr("src.UseCases.Line.CheckHabitTaskUseCase.datetime", FixedDatetime) + + line_users = [LineUser(line_user_name="u1", line_user_id="U1")] + web_users = [] + tasks = [ + HabitTask(_id="T1", owner_id="U1", task_name="週次筋トレ", + frequency="weekly", notify_time="09:00", notify_day_of_week=5) + ] + + use_case = CheckHabitTaskUseCase( + line_user_repository=DummyLineUserRepository(line_users), + web_user_repository=DummyWebUserRepository(web_users), + habit_task_repository=DummyHabitTaskRepository(tasks), + habit_task_log_repository=DummyHabitTaskLogRepository(), + habit_pending_confirmation_repository=DummyHabitPendingRepository(), + line_response_service=DummyLineResponseService(), + ) + use_case.execute() + assert use_case._line_response_service.pushes == [] + + +def test_check_habit_monthly_task_sends_on_correct_day(monkeypatch): + # 14日にnotify_day_of_month=14のタスクが通知される + fixed_now = datetime(2026, 3, 14, 12, 0, 0) + + class FixedDatetime(datetime): + @classmethod + def now(cls, tz=None): + return fixed_now + + monkeypatch.setattr("src.UseCases.Line.CheckHabitTaskUseCase.datetime", FixedDatetime) + + line_users = [LineUser(line_user_name="u1", line_user_id="U1")] + web_users = [] + tasks = [ + HabitTask(_id="T1", owner_id="U1", task_name="家計簿", + frequency="monthly", notify_time="12:00", notify_day_of_month=14) + ] + + use_case = CheckHabitTaskUseCase( + line_user_repository=DummyLineUserRepository(line_users), + web_user_repository=DummyWebUserRepository(web_users), + habit_task_repository=DummyHabitTaskRepository(tasks), + habit_task_log_repository=DummyHabitTaskLogRepository(), + habit_pending_confirmation_repository=DummyHabitPendingRepository(), + line_response_service=DummyLineResponseService(), + ) + use_case.execute() + assert use_case._line_response_service.pushes == ["U1"] + + +def test_check_habit_monthly_task_not_sent_on_wrong_day(monkeypatch): + # 15日にnotify_day_of_month=14のタスクは通知されない + fixed_now = datetime(2026, 3, 15, 12, 0, 0) + + class FixedDatetime(datetime): + @classmethod + def now(cls, tz=None): + return fixed_now + + monkeypatch.setattr("src.UseCases.Line.CheckHabitTaskUseCase.datetime", FixedDatetime) + + line_users = [LineUser(line_user_name="u1", line_user_id="U1")] + web_users = [] + tasks = [ + HabitTask(_id="T1", owner_id="U1", task_name="家計簿", + frequency="monthly", notify_time="12:00", notify_day_of_month=14) + ] + + use_case = CheckHabitTaskUseCase( + line_user_repository=DummyLineUserRepository(line_users), + web_user_repository=DummyWebUserRepository(web_users), + habit_task_repository=DummyHabitTaskRepository(tasks), + habit_task_log_repository=DummyHabitTaskLogRepository(), + habit_pending_confirmation_repository=DummyHabitPendingRepository(), + line_response_service=DummyLineResponseService(), + ) + use_case.execute() + assert use_case._line_response_service.pushes == [] + + def test_handle_habit_task_response_other_flow(): pending_repo = DummyHabitPendingRepository() pending_repo.create( diff --git a/src/UseCases/Line/tests/test_handle_intent_operation_use_case.py b/src/UseCases/Line/tests/test_handle_intent_operation_use_case.py index 3c3e081..03023bb 100644 --- a/src/UseCases/Line/tests/test_handle_intent_operation_use_case.py +++ b/src/UseCases/Line/tests/test_handle_intent_operation_use_case.py @@ -305,8 +305,8 @@ def test_followup_expiry_date_updates_recently_registered_item(): assert pending.get("U1") is None -def test_register_with_notify_enabled(): - req = DummyLineRequestService(message="通知ありで確定申告 3/15まで") +def test_register_with_notify_days_before(): + req = DummyLineRequestService(message="7日前から通知で確定申告 3/15まで") res = DummyLineResponseService() repo = DummyStockRepository() parser = DummyIntentParserService( @@ -314,7 +314,7 @@ def test_register_with_notify_enabled(): "intent": "register", "item_name": "確定申告", "expiry_date": "2026-03-15", - "notify_enabled": True, + "notify_days_before": 7, } ) pending = DummyPendingOperationService() @@ -327,13 +327,13 @@ def test_register_with_notify_enabled(): ) use_case.execute() - assert any("通知あり" in m for m in res.messages) + assert any("7日前から通知" in m for m in res.messages) req.message = "はい" use_case.execute() assert repo.created is not None assert repo.created.item_name == "確定申告" - assert repo.created.notify_enabled is True + assert repo.created.notify_days_before == 7 def test_register_habit_creates_habit_task(): @@ -371,6 +371,73 @@ def test_register_habit_creates_habit_task(): assert habit_repo.created.notify_time == "09:00" +def test_register_habit_weekly(): + req = DummyLineRequestService(message="毎週月曜9時に筋トレをリマインドして") + res = DummyLineResponseService() + repo = DummyStockRepository() + parser = DummyIntentParserService( + { + "intent": "register_habit", + "item_name": "筋トレ", + "expiry_date": None, + "frequency": "weekly", + "notify_time": "09:00", + "notify_day_of_week": 0, + "notify_day_of_month": None, + } + ) + pending = DummyPendingOperationService() + habit_repo = DummyHabitTaskRepository() + use_case = HandleIntentOperationUseCase( + stock_repository=repo, + line_request_service=req, + line_response_service=res, + intent_parser_service=parser, + pending_operation_service=pending, + habit_task_repository=habit_repo, + ) + + use_case.execute() + assert any("毎週月曜日" in m for m in res.messages) + + req.message = "はい" + use_case.execute() + assert habit_repo.created is not None + assert habit_repo.created.task_name == "筋トレ" + assert habit_repo.created.frequency == "weekly" + assert habit_repo.created.notify_day_of_week == 0 + assert habit_repo.created.notify_day_of_month is None + + +def test_update_habit_frequency(): + req = DummyLineRequestService(message="筋トレを毎週水曜日に変更して") + res = DummyLineResponseService() + habit_repo = DummyHabitTaskRepository() + parser = DummyIntentParserService( + { + "intent": "update_habit_frequency", + "item_name": "筋トレ", + "expiry_date": None, + "frequency": "weekly", + "notify_day_of_week": 2, + "notify_day_of_month": None, + } + ) + pending = DummyPendingOperationService() + use_case = _make_use_case(req, res, parser, pending, habit_repo=habit_repo) + + use_case.execute() + assert any("毎週水曜日" in m for m in res.messages) + + req.message = "はい" + use_case.execute() + assert habit_repo.updated_query["task_name"] == "筋トレ" + assert habit_repo.updated_values["frequency"] == "weekly" + assert habit_repo.updated_values["notify_day_of_week"] == 2 + assert habit_repo.updated_values["notify_day_of_month"] is None + assert any("頻度を変更しました" in m for m in res.messages) + + def test_delete_with_exclude_expiry_filters_python_side(): req = DummyLineRequestService(message="期限が3/11以外の卵を削除して") res = DummyLineResponseService() @@ -494,22 +561,24 @@ def test_update_notification_setting_off(): assert any("更新しました" in m for m in res.messages) -def test_update_stock_notify_on(): - req = DummyLineRequestService(message="牛乳の通知をオンにして") +def test_update_stock_notify(): + req = DummyLineRequestService(message="牛乳を3日前から通知して") res = DummyLineResponseService() repo = DummyStockRepository() parser = DummyIntentParserService( - {"intent": "update_stock_notify", "item_name": "牛乳", "notify_enabled": True, "expiry_date": None} + {"intent": "update_stock_notify", "item_name": "牛乳", "notify_days_before": 3, "expiry_date": None} ) pending = DummyPendingOperationService() use_case = _make_use_case(req, res, parser, pending, repo=repo) use_case.execute() + assert any("3日前から通知" in m for m in res.messages) + req.message = "はい" use_case.execute() assert repo.updated_query["item_name"] == "牛乳" - assert repo.updated_values["notify_enabled"] is True + assert repo.updated_values["notify_days_before"] == 3 assert any("更新しました" in m for m in res.messages) diff --git a/src/UseCases/Line/tests/test_reply_help_use_case.py b/src/UseCases/Line/tests/test_reply_help_use_case.py index a5ce055..3f75246 100644 --- a/src/UseCases/Line/tests/test_reply_help_use_case.py +++ b/src/UseCases/Line/tests/test_reply_help_use_case.py @@ -41,6 +41,7 @@ def delete_req_info(self) -> None: class DummyLineResponseService(ILineResponseService): def __init__(self): self.messages = [] + self.buttons = [] def add_message(self, text: str) -> None: self.messages.append(text) @@ -71,8 +72,16 @@ def test_reply_help_default_lists_commands(): use_case.execute() - assert any("使い方ガイド" in message for message in line_response_service.messages) - assert any("一覧表示" in message for message in line_response_service.messages) + # キーワードなしはクイックリプライ付きメッセージとして buttons に追加される + assert len(line_response_service.buttons) == 1 + msg = line_response_service.buttons[0] + assert "Simple Alert" in msg.text + assert "一覧" in msg.text + assert msg.quick_reply is not None + labels = [item.action.label for item in msg.quick_reply.items] + assert any("登録" in label for label in labels) + assert any("一覧" in label for label in labels) + assert any("連携" in label for label in labels) def test_reply_help_specific_keyword(): @@ -85,4 +94,4 @@ def test_reply_help_specific_keyword(): use_case.execute() - assert any("期限が1週間前" in message for message in line_response_service.messages) + assert any("期限1週間前" in message for message in line_response_service.messages) diff --git a/src/UseCases/Line/tests/test_reply_stock_use_case.py b/src/UseCases/Line/tests/test_reply_stock_use_case.py index 44aaed8..4389a02 100644 --- a/src/UseCases/Line/tests/test_reply_stock_use_case.py +++ b/src/UseCases/Line/tests/test_reply_stock_use_case.py @@ -137,7 +137,8 @@ def now(cls, tz=None): messages = use_case._line_response_service.messages joined = "\n".join(messages) - assert "期限未設定:" in joined - assert "期限あり:" in joined + assert "期限なし" in joined + assert "期限あり" in joined assert "no_expiry" in joined assert "with_expiry" in joined + assert "残り" in joined # 残り日数が表示される diff --git a/src/UseCases/Line/tests/test_request_link_line_web_use_case.py b/src/UseCases/Line/tests/test_request_link_line_web_use_case.py index 54ed4a0..8d73c00 100644 --- a/src/UseCases/Line/tests/test_request_link_line_web_use_case.py +++ b/src/UseCases/Line/tests/test_request_link_line_web_use_case.py @@ -1,5 +1,5 @@ -from src.Domains.Entities.WebUser import WebUser from src.Domains.IRepositories.IWebUserRepository import IWebUserRepository +from src.Domains.Entities.WebUser import WebUser from src.UseCases.Interface.ILineRequestService import ILineRequestService from src.UseCases.Interface.ILineResponseService import ILineResponseService from src.UseCases.Line.RequestLinkLineWebUseCase import RequestLinkLineWebUseCase @@ -64,104 +64,33 @@ def push_a_message(self, to: str, message: str) -> None: class DummyWebUserRepository(IWebUserRepository): - def __init__(self, find_result: list[WebUser], update_result: int = 1): - self._find_result = find_result - self._update_result = update_result - self.updated = None + def __init__(self, find_result: list = None): + self._find_result = find_result or [] def create(self, new_web_user: WebUser) -> WebUser: return new_web_user def update(self, query, new_web_user) -> int: - self.updated = (query, new_web_user) - return self._update_result + return 0 def delete(self, query) -> int: return 0 - def find(self, query) -> list[WebUser]: + def find(self, query) -> list: return self._find_result -def test_request_link_invalid_args(): - use_case = RequestLinkLineWebUseCase( - web_user_repository=DummyWebUserRepository(find_result=[]), - line_request_service=DummyLineRequestService(message="アカウント連携"), - line_response_service=DummyLineResponseService(), - ) - - use_case.execute() - - assert any("アカウント連携" in message for message in use_case._line_response_service.messages) - - -def test_request_link_email_not_found(): - response = DummyLineResponseService() - use_case = RequestLinkLineWebUseCase( - web_user_repository=DummyWebUserRepository(find_result=[]), - line_request_service=DummyLineRequestService(message="アカウント連携 test@example.com"), - line_response_service=response, - ) - - use_case.execute() - - assert any("登録されていません" in message for message in response.messages) - - -def test_request_link_already_linked(): - response = DummyLineResponseService() - web_user = WebUser( - _id="507f1f77bcf86cd799439011", - web_user_name="dummy", - web_user_email="test@example.com", - is_linked_line_user=True, - ) - use_case = RequestLinkLineWebUseCase( - web_user_repository=DummyWebUserRepository(find_result=[web_user]), - line_request_service=DummyLineRequestService(message="アカウント連携 test@example.com"), - line_response_service=response, - ) - - use_case.execute() - - assert any("すでに LINE アカウントと紐付けされています" in message for message in response.messages) - - -def test_request_link_update_failure(): +def test_request_link_returns_deprecation_message(): + """アカウント連携機能は廃止済みのため、廃止メッセージとWebアプリURLを返す。""" response = DummyLineResponseService() - web_user = WebUser( - _id="507f1f77bcf86cd799439011", - web_user_name="dummy", - web_user_email="test@example.com", - is_linked_line_user=False, - ) use_case = RequestLinkLineWebUseCase( - web_user_repository=DummyWebUserRepository(find_result=[web_user], update_result=0), - line_request_service=DummyLineRequestService(message="アカウント連携 test@example.com"), - line_response_service=response, - ) - - use_case.execute() - - assert any("失敗しました" in message for message in response.messages) - - -def test_request_link_success(): - response = DummyLineResponseService() - web_user = WebUser( - _id="507f1f77bcf86cd799439011", - web_user_name="dummy", - web_user_email="test@example.com", - is_linked_line_user=False, - ) - repo = DummyWebUserRepository(find_result=[web_user], update_result=1) - use_case = RequestLinkLineWebUseCase( - web_user_repository=repo, - line_request_service=DummyLineRequestService(message="アカウント連携 test@example.com"), + web_user_repository=DummyWebUserRepository(), + line_request_service=DummyLineRequestService(message="アカウント連携"), line_response_service=response, ) use_case.execute() - assert repo.updated is not None - assert any("承認してください" in message for message in response.messages) + assert len(response.messages) == 1 + assert "廃止" in response.messages[0] + assert "LINEアカウント" in response.messages[0] diff --git a/src/UseCases/Web/UpdateStockUseCase.py b/src/UseCases/Web/UpdateStockUseCase.py index 87d4008..759d1c0 100644 --- a/src/UseCases/Web/UpdateStockUseCase.py +++ b/src/UseCases/Web/UpdateStockUseCase.py @@ -61,10 +61,17 @@ def _parse_date_value(raw: str) -> datetime: elif key == 'notify_status': if val is None: continue - upper = val.strip().upper() - if upper not in ('ON', 'OFF'): - raise BadRequest('通知は ON または OFF を指定してください。') - new_values['notify_enabled'] = upper == 'ON' + v = val.strip() + if v.upper() in ('ON', '') or v == '常に通知': + new_values['notify_days_before'] = None # 常に通知 + elif v.upper() == 'OFF': + new_values['notify_days_before'] = None # OFFはデフォルト(常に通知)扱い + elif v.rstrip('日前から').isdigit(): + new_values['notify_days_before'] = int(v.rstrip('日前から')) + elif v.isdigit(): + new_values['notify_days_before'] = int(v) + else: + raise BadRequest('通知設定が不正です。') res = self._stock_repository.update( query={ diff --git a/src/models/StockViewModel.py b/src/models/StockViewModel.py index 02079c7..4809d08 100644 --- a/src/models/StockViewModel.py +++ b/src/models/StockViewModel.py @@ -34,7 +34,8 @@ def __init__( ).strftime('%Y/%m/%d') self.str_created_at = '' if stock.created_at is None else stock.created_at.date( ).strftime('%Y/%m/%d') - self.notify_status = 'ON' if stock.notify_enabled else 'OFF' + ndb = stock.notify_days_before + self.notify_status = '常に通知' if ndb is None else f'{ndb}日前から' else: self._id = _id self.item_name = item_name diff --git a/src/routes/handle_line_event.py b/src/routes/handle_line_event.py index ba4cbb3..1670042 100644 --- a/src/routes/handle_line_event.py +++ b/src/routes/handle_line_event.py @@ -194,6 +194,10 @@ def get_use_case_text_message(event: Event): # keep explicit commands direct if keyword in use_case_list['stock_keywords']: if event.source.type == 'user' and keyword == '登録': + # 「登録」単体はアイテム名がないので使い方ガイドを返す + if message == '登録': + line_request_service.message = '使い方 登録' + return help_use_case return HandleIntentOperationUseCase( stock_repository=stock_repository, line_request_service=line_request_service, diff --git a/src/services/LineIntentParserService.py b/src/services/LineIntentParserService.py index 05c1e78..66c37bf 100644 --- a/src/services/LineIntentParserService.py +++ b/src/services/LineIntentParserService.py @@ -21,11 +21,11 @@ "parameters": { "type": "object", "properties": { - "item_name": {"type": "string"}, - "expiry_date": {"type": ["string", "null"]}, - "notify_enabled": {"type": "boolean"}, + "item_name": {"type": "string"}, + "expiry_date": {"type": ["string", "null"]}, + "notify_days_before": {"type": ["integer", "null"], "description": "何日前から通知するか。null = 常に通知、省略や不明もnull。"}, }, - "required": ["item_name", "expiry_date", "notify_enabled"], + "required": ["item_name", "expiry_date", "notify_days_before"], "additionalProperties": False, }, "strict": True, @@ -70,15 +70,36 @@ "type": "function", "function": { "name": "register_habit_task", - "description": "毎日・毎週の習慣タスクを登録する。notify_timeはHH:MM形式、不明ならnull。", + "description": "毎日・毎週・毎月の習慣タスクを登録する。notify_timeはHH:MM形式、不明ならnull。weeklyの場合はnotify_day_of_week(0=月〜6=日)、monthlyの場合はnotify_day_of_month(1〜31)を指定。dailyはどちらもnull。", "parameters": { "type": "object", "properties": { - "item_name": {"type": "string"}, - "frequency": {"type": "string", "enum": ["daily", "weekly"]}, - "notify_time": {"type": ["string", "null"]}, + "item_name": {"type": "string"}, + "frequency": {"type": "string", "enum": ["daily", "weekly", "monthly"]}, + "notify_time": {"type": ["string", "null"]}, + "notify_day_of_week": {"type": ["integer", "null"], "description": "週次の場合の曜日(0=月〜6=日)。daily/monthlyはnull。"}, + "notify_day_of_month": {"type": ["integer", "null"], "description": "月次の場合の日(1〜31)。daily/weeklyはnull。"}, + }, + "required": ["item_name", "frequency", "notify_time", "notify_day_of_week", "notify_day_of_month"], + "additionalProperties": False, + }, + "strict": True, + }, + }, + { + "type": "function", + "function": { + "name": "update_habit_frequency", + "description": "習慣タスクの頻度を変更する。weekly→notify_day_of_week(0〜6)、monthly→notify_day_of_month(1〜31)を指定。", + "parameters": { + "type": "object", + "properties": { + "task_name": {"type": "string"}, + "frequency": {"type": "string", "enum": ["daily", "weekly", "monthly"]}, + "notify_day_of_week": {"type": ["integer", "null"]}, + "notify_day_of_month": {"type": ["integer", "null"]}, }, - "required": ["item_name", "frequency", "notify_time"], + "required": ["task_name", "frequency", "notify_day_of_week", "notify_day_of_month"], "additionalProperties": False, }, "strict": True, @@ -136,14 +157,14 @@ "type": "function", "function": { "name": "update_stock_notify", - "description": "登録済みアイテムの通知設定(notify_enabled)を変更する。", + "description": "登録済みアイテムの通知設定を変更する。何日前から通知するかを指定する。", "parameters": { "type": "object", "properties": { - "item_name": {"type": "string"}, - "notify_enabled": {"type": "boolean"}, + "item_name": {"type": "string"}, + "notify_days_before": {"type": ["integer", "null"], "description": "何日前から通知するか。null = 常に通知、省略や不明もnull。"}, }, - "required": ["item_name", "notify_enabled"], + "required": ["item_name", "notify_days_before"], "additionalProperties": False, }, "strict": True, @@ -177,6 +198,7 @@ "register_habit_task": "register_habit", "delete_habit_task": "delete_habit", "update_habit_notify_time": "update_habit_notify_time", + "update_habit_frequency": "update_habit_frequency", "update_notification_setting": "update_notification", "update_stock_notify": "update_stock_notify", "update_habit_log": "update_habit_log", @@ -259,9 +281,11 @@ def _build_result_from_tool_call(self, tool_name: str, args: dict) -> dict: "item_name": args.get("item_name") or args.get("task_name"), "expiry_date": args.get("expiry_date"), "exclude_expiry_date": args.get("exclude_expiry_date"), - "notify_enabled": bool(args.get("notify_enabled", False)), + "notify_days_before": args.get("notify_days_before"), "frequency": args.get("frequency"), "notify_time": args.get("notify_time"), + "notify_day_of_week": args.get("notify_day_of_week"), + "notify_day_of_month": args.get("notify_day_of_month"), "enabled": args.get("enabled"), "scheduled_date": args.get("scheduled_date"), "result": args.get("result"), @@ -288,9 +312,15 @@ def _check_time(v: Any) -> Optional[str]: return None frequency = parsed.get("frequency") - if frequency not in ("daily", "weekly"): + if frequency not in ("daily", "weekly", "monthly"): frequency = None + dow = parsed.get("notify_day_of_week") + notify_day_of_week = dow if isinstance(dow, int) and 0 <= dow <= 6 else None + + dom = parsed.get("notify_day_of_month") + notify_day_of_month = dom if isinstance(dom, int) and 1 <= dom <= 31 else None + intent = parsed.get("intent", "none") if intent in {"register", "delete"} and not item_name: intent = "none" @@ -298,10 +328,20 @@ def _check_time(v: Any) -> Optional[str]: intent = "none" if intent == "register_habit" and not item_name: intent = "none" + if intent == "register_habit" and frequency == "weekly" and notify_day_of_week is None: + intent = "none" + if intent == "register_habit" and frequency == "monthly" and notify_day_of_month is None: + intent = "none" if intent == "delete_habit" and not item_name: intent = "none" if intent == "update_habit_notify_time" and (not item_name or not _check_time(parsed.get("notify_time"))): intent = "none" + if intent == "update_habit_frequency" and not item_name: + intent = "none" + if intent == "update_habit_frequency" and frequency == "weekly" and notify_day_of_week is None: + intent = "none" + if intent == "update_habit_frequency" and frequency == "monthly" and notify_day_of_month is None: + intent = "none" if intent == "update_notification": if parsed.get("enabled") is None and not _check_time(parsed.get("notify_time")): intent = "none" @@ -311,14 +351,22 @@ def _check_time(v: Any) -> Optional[str]: if not item_name or not _check_date(parsed.get("scheduled_date")) or parsed.get("result") not in ("done", "not_done", "other"): intent = "none" + ndb = parsed.get("notify_days_before") + if isinstance(ndb, int) and ndb >= 0: + notify_days_before = ndb + else: + notify_days_before = None + return { "intent": intent, "item_name": item_name, "expiry_date": _check_date(parsed.get("expiry_date")), "exclude_expiry_date": _check_date(parsed.get("exclude_expiry_date")), - "notify_enabled": bool(parsed.get("notify_enabled", False)), + "notify_days_before": notify_days_before, "frequency": frequency, "notify_time": _check_time(parsed.get("notify_time")), + "notify_day_of_week": notify_day_of_week, + "notify_day_of_month": notify_day_of_month, "enabled": parsed.get("enabled"), "scheduled_date": _check_date(parsed.get("scheduled_date")), "result": parsed.get("result"), @@ -331,9 +379,11 @@ def _none_result(self) -> Dict[str, Any]: "item_name": None, "expiry_date": None, "exclude_expiry_date": None, - "notify_enabled": False, + "notify_days_before": None, "frequency": None, "notify_time": None, + "notify_day_of_week": None, + "notify_day_of_month": None, "enabled": None, "scheduled_date": None, "result": None, diff --git a/src/services/tests/test_line_intent_parser_service.py b/src/services/tests/test_line_intent_parser_service.py index d7e781e..5039e20 100644 --- a/src/services/tests/test_line_intent_parser_service.py +++ b/src/services/tests/test_line_intent_parser_service.py @@ -124,7 +124,7 @@ def teardown_method(self): def test_fc_register_with_date(self): resp = _make_tool_response("register_stock", { - "item_name": "確定申告", "expiry_date": "2026-03-15", "notify_enabled": False + "item_name": "確定申告", "expiry_date": "2026-03-15", "notify_days_before": None }) with _mock_api(resp): result = self.svc.parse("確定申告は3/15まで") @@ -134,7 +134,7 @@ def test_fc_register_with_date(self): def test_fc_register_without_date(self): resp = _make_tool_response("register_stock", { - "item_name": "牛乳", "expiry_date": None, "notify_enabled": False + "item_name": "牛乳", "expiry_date": None, "notify_days_before": None }) with _mock_api(resp): result = self.svc.parse("牛乳買った") @@ -142,14 +142,14 @@ def test_fc_register_without_date(self): assert result["item_name"] == "牛乳" assert result["expiry_date"] is None - def test_fc_register_notify_enabled(self): + def test_fc_register_notify_days_before(self): resp = _make_tool_response("register_stock", { - "item_name": "確定申告", "expiry_date": "2026-03-15", "notify_enabled": True + "item_name": "確定申告", "expiry_date": "2026-03-15", "notify_days_before": 7 }) with _mock_api(resp): - result = self.svc.parse("通知ありで確定申告 3/15まで") + result = self.svc.parse("7日前から通知で確定申告 3/15まで") assert result["intent"] == "register" - assert result["notify_enabled"] is True + assert result["notify_days_before"] == 7 assert result["expiry_date"] == "2026-03-15" def test_fc_update(self): @@ -195,7 +195,8 @@ def test_fc_delete_with_exclude(self): def test_fc_register_habit_with_time(self): resp = _make_tool_response("register_habit_task", { - "item_name": "筋トレ", "frequency": "daily", "notify_time": "09:00" + "item_name": "筋トレ", "frequency": "daily", "notify_time": "09:00", + "notify_day_of_week": None, "notify_day_of_month": None, }) with _mock_api(resp): result = self.svc.parse("毎朝9時に筋トレをリマインドして") @@ -203,10 +204,13 @@ def test_fc_register_habit_with_time(self): assert result["item_name"] == "筋トレ" assert result["frequency"] == "daily" assert result["notify_time"] == "09:00" + assert result["notify_day_of_week"] is None + assert result["notify_day_of_month"] is None def test_fc_register_habit_no_time(self): resp = _make_tool_response("register_habit_task", { - "item_name": "英語学習", "frequency": "daily", "notify_time": None + "item_name": "英語学習", "frequency": "daily", "notify_time": None, + "notify_day_of_week": None, "notify_day_of_month": None, }) with _mock_api(resp): result = self.svc.parse("英語学習を毎日リマインドして") @@ -214,6 +218,45 @@ def test_fc_register_habit_no_time(self): assert result["item_name"] == "英語学習" assert result["notify_time"] is None + def test_fc_register_habit_weekly(self): + resp = _make_tool_response("register_habit_task", { + "item_name": "筋トレ", "frequency": "weekly", "notify_time": "09:00", + "notify_day_of_week": 0, "notify_day_of_month": None, + }) + with _mock_api(resp): + result = self.svc.parse("毎週月曜9時に筋トレをリマインドして") + assert result["intent"] == "register_habit" + assert result["item_name"] == "筋トレ" + assert result["frequency"] == "weekly" + assert result["notify_day_of_week"] == 0 + assert result["notify_day_of_month"] is None + + def test_fc_register_habit_monthly(self): + resp = _make_tool_response("register_habit_task", { + "item_name": "家計簿", "frequency": "monthly", "notify_time": "12:00", + "notify_day_of_week": None, "notify_day_of_month": 1, + }) + with _mock_api(resp): + result = self.svc.parse("毎月1日12時に家計簿をつけるリマインドして") + assert result["intent"] == "register_habit" + assert result["item_name"] == "家計簿" + assert result["frequency"] == "monthly" + assert result["notify_day_of_week"] is None + assert result["notify_day_of_month"] == 1 + + def test_fc_update_habit_frequency(self): + resp = _make_tool_response("update_habit_frequency", { + "task_name": "筋トレ", "frequency": "weekly", + "notify_day_of_week": 2, "notify_day_of_month": None, + }) + with _mock_api(resp): + result = self.svc.parse("筋トレを毎週水曜日に変更して") + assert result["intent"] == "update_habit_frequency" + assert result["item_name"] == "筋トレ" + assert result["frequency"] == "weekly" + assert result["notify_day_of_week"] == 2 + assert result["notify_day_of_month"] is None + def test_fc_delete_habit(self): resp = _make_tool_response("delete_habit_task", {"task_name": "筋トレ"}) with _mock_api(resp): @@ -251,13 +294,13 @@ def test_fc_update_notification_time(self): def test_fc_update_stock_notify(self): resp = _make_tool_response("update_stock_notify", { - "item_name": "牛乳", "notify_enabled": True + "item_name": "牛乳", "notify_days_before": 3 }) with _mock_api(resp): - result = self.svc.parse("牛乳の通知をオンにして") + result = self.svc.parse("牛乳を3日前から通知して") assert result["intent"] == "update_stock_notify" assert result["item_name"] == "牛乳" - assert result["notify_enabled"] is True + assert result["notify_days_before"] == 3 def test_fc_update_habit_log(self): resp = _make_tool_response("update_habit_log", { @@ -319,7 +362,7 @@ def test_invalid_date_format_becomes_none(self): "item_name": "牛乳", "expiry_date": "2026/03/15", "exclude_expiry_date": None, - "notify_enabled": False, + "notify_days_before": None, "frequency": None, "notify_time": None, } @@ -332,7 +375,7 @@ def test_item_name_too_long_becomes_none(self): "item_name": "a" * 101, "expiry_date": None, "exclude_expiry_date": None, - "notify_enabled": False, + "notify_days_before": None, "frequency": None, "notify_time": None, } @@ -346,7 +389,7 @@ def test_item_name_with_newline_becomes_none(self): "item_name": "牛乳\n卵", "expiry_date": None, "exclude_expiry_date": None, - "notify_enabled": False, + "notify_days_before": None, "frequency": None, "notify_time": None, } @@ -360,7 +403,7 @@ def test_invalid_notify_time_becomes_none(self): "item_name": "筋トレ", "expiry_date": None, "exclude_expiry_date": None, - "notify_enabled": False, + "notify_days_before": None, "frequency": "daily", "notify_time": "9:00", } @@ -373,7 +416,7 @@ def test_update_without_expiry_becomes_none(self): "item_name": "牛乳", "expiry_date": None, "exclude_expiry_date": None, - "notify_enabled": False, + "notify_days_before": None, "frequency": None, "notify_time": None, }