diff --git a/CONSTITUTION.md b/CONSTITUTION.md index 580a602..25c8fbc 100644 --- a/CONSTITUTION.md +++ b/CONSTITUTION.md @@ -2,7 +2,7 @@ > 本文件定義專案開發的核心準則與不可違反的規範 > **建立日期**: 2026-01-12 -> **當前版本**: V10.23 (OpenClaw Bot Telegram helper 拆分版) +> **當前版本**: V10.24 (EDM Dashboard blueprint endpoint 修復版) > **最後更新**: 2026-04-30 --- diff --git a/app.py b/app.py index aac7f79..da53313 100644 --- a/app.py +++ b/app.py @@ -95,8 +95,8 @@ except Exception as e: sys_log.error(f"無法檢測磁碟空間: {e}") # 🚩 系統版本定義 (備份與顯示用) -# 🚩 2026-04-30 V10.23: OpenClaw Telegram API helper extraction -SYSTEM_VERSION = "V10.23" +# 🚩 2026-04-30 V10.24: EDM dashboard blueprint endpoint sort link fix +SYSTEM_VERSION = "V10.24" # ========================================== # 🔒 SQL Injection 防護函數 diff --git a/config.py b/config.py index 28679cc..16c07eb 100644 --- a/config.py +++ b/config.py @@ -254,7 +254,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.23" +SYSTEM_VERSION = "V10.24" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/docs/memory/history_logs.md b/docs/memory/history_logs.md index 14bc765..0ca4632 100644 --- a/docs/memory/history_logs.md +++ b/docs/memory/history_logs.md @@ -45,6 +45,7 @@ - **模組化治理守門**: 盤點 15 個超過 800 行 Python 大檔,新增 `docs/guides/modularization_governance.md` 與 `tests/test_modularization_governance.py`,防止未分類巨檔再長出來。 - **Legacy 5888 入口清理**: 刪除 `tests/main_test.py` standalone Flask 死碼,測試與自動匯入文件改用 Port 80 `/auto_import` 入口。 - **OpenClaw Bot 第一刀拆分**: Telegram API send/retry/file upload helper 移到 `services/openclaw_bot/telegram_api.py`,`routes/openclaw_bot_routes.py` 往 thin Blueprint 收斂。 +- **EDM Dashboard endpoint 修復**: 部署後健康檢查抓到活動看板排序連結少 `edm.` blueprint 前綴,修正模板 endpoint 推導並補 5 個活動頁排序連結回歸測試。 ### 2026-04-28~29:Phase 3e 重構大戰 + daily_sales cache 隱形 bug 根除 - **app.py 縮減 -10.8%**: 7,386 → 6,590 行,11 commits 全綠零 502。 diff --git a/templates/edm_dashboard.html b/templates/edm_dashboard.html index 9ea8a2a..a28042a 100644 --- a/templates/edm_dashboard.html +++ b/templates/edm_dashboard.html @@ -205,7 +205,7 @@ - {% set current_endpoint = 'edm_dashboard' if current_promo_page == 'edm' else 'festival_dashboard' %} + {% set current_endpoint = 'edm.' ~ current_promo_page ~ '_dashboard' %}
@@ -428,4 +428,4 @@ } - \ No newline at end of file + diff --git a/tests/test_edm_dashboard_template.py b/tests/test_edm_dashboard_template.py new file mode 100644 index 0000000..93c5426 --- /dev/null +++ b/tests/test_edm_dashboard_template.py @@ -0,0 +1,79 @@ +from flask import Blueprint, Flask, render_template, url_for + + +def _build_test_app(): + app = Flask( + __name__, + template_folder="../templates", + ) + app.jinja_env.globals["csrf_token"] = lambda: "" + app.jinja_env.filters["number_format"] = lambda value: f"{value:,}" + + edm = Blueprint("edm", __name__) + + for endpoint, path in { + "edm_dashboard": "/edm", + "festival_dashboard": "/festival", + "mothers_day_dashboard": "/mothers_day", + "valentine_520_dashboard": "/valentine_520", + "labor_day_dashboard": "/labor_day", + }.items(): + edm.add_url_rule(path, endpoint, lambda: "") + + app.register_blueprint(edm) + return app + + +def test_edm_dashboard_sort_links_use_blueprint_endpoint(): + app = _build_test_app() + page_paths = { + "edm": "/edm", + "festival": "/festival", + "mothers_day": "/mothers_day", + "valentine_520": "/valentine_520", + "labor_day": "/labor_day", + } + + with app.test_request_context("/edm"): + promo_pages = [ + { + "url": url_for(f"edm.{page}_dashboard"), + "name": page, + "id": page, + } + for page in page_paths + ] + + for page, path in page_paths.items(): + html = render_template( + "edm_dashboard.html", + promo_pages=promo_pages, + current_promo_page=page, + page_title=page, + activity_time="", + last_update="", + total_edm_products=0, + scheduler_stats={}, + slot_stats={ + "10:00": { + "on_shelf": 0, + "new": 0, + "up": 0, + "down": 0, + } + }, + grouped_items={"10:00": []}, + active_tab="10:00", + current_sort="default", + current_order="desc", + slugify=lambda value: value.replace(":", ""), + datetime_now="", + metabase_url="", + grist_url="", + ) + + assert f'{path}?sort_by=name&order=desc' in html + assert f'{path}?sort_by=price&order=desc' in html + + if page == "edm": + assert f'{path}?sort_by=remain_qty&order=desc' in html