feat(frontend): 將 V2 設為正式預設介面
All checks were successful
CD Pipeline / deploy (push) Successful in 1m46s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m46s
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
> 本文件定義專案開發的核心準則與不可違反的規範
|
||||
> **建立日期**: 2026-01-12
|
||||
> **當前版本**: V10.39 (Vendor stockout import v2 feature flag)
|
||||
> **當前版本**: V10.40 (Frontend V2 production default)
|
||||
> **最後更新**: 2026-05-01
|
||||
|
||||
---
|
||||
|
||||
4
app.py
4
app.py
@@ -95,8 +95,8 @@ except Exception as e:
|
||||
sys_log.error(f"無法檢測磁碟空間: {e}")
|
||||
|
||||
# 🚩 系統版本定義 (備份與顯示用)
|
||||
# 🚩 2026-05-01 V10.39: Vendor stockout import v2 feature flag
|
||||
SYSTEM_VERSION = "V10.39"
|
||||
# 🚩 2026-05-01 V10.40: Frontend V2 as production default
|
||||
SYSTEM_VERSION = "V10.40"
|
||||
|
||||
# ==========================================
|
||||
# 🔒 SQL Injection 防護函數
|
||||
|
||||
@@ -619,7 +619,7 @@ def index():
|
||||
category_name = item['record'].product.category
|
||||
item['category_color'] = get_color_for_string(category_name)
|
||||
|
||||
template_name = 'dashboard_v2.html' if request.args.get('ui') == 'v2' else 'dashboard.html'
|
||||
template_name = 'dashboard.html' if request.args.get('ui') == 'legacy' else 'dashboard_v2.html'
|
||||
|
||||
return render_template(template_name,
|
||||
total_products=total_products_history,
|
||||
|
||||
@@ -321,7 +321,7 @@ def edm_dashboard():
|
||||
scheduler_stats = load_scheduler_stats()
|
||||
now_taipei = datetime.now(TAIPEI_TZ)
|
||||
|
||||
template_name = 'edm_dashboard_v2.html' if request.args.get('ui') == 'v2' else 'edm_dashboard.html'
|
||||
template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html'
|
||||
|
||||
return render_template(template_name,
|
||||
promo_pages=promo_pages,
|
||||
@@ -375,7 +375,7 @@ def festival_dashboard():
|
||||
|
||||
scheduler_stats = load_scheduler_stats()
|
||||
|
||||
template_name = 'edm_dashboard_v2.html' if request.args.get('ui') == 'v2' else 'edm_dashboard.html'
|
||||
template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html'
|
||||
|
||||
return render_template(template_name,
|
||||
promo_pages=promo_pages,
|
||||
@@ -427,7 +427,7 @@ def mothers_day_dashboard():
|
||||
|
||||
scheduler_stats = load_scheduler_stats()
|
||||
|
||||
template_name = 'edm_dashboard_v2.html' if request.args.get('ui') == 'v2' else 'edm_dashboard.html'
|
||||
template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html'
|
||||
|
||||
return render_template(template_name,
|
||||
promo_pages=promo_pages,
|
||||
@@ -479,7 +479,7 @@ def valentine_520_dashboard():
|
||||
|
||||
scheduler_stats = load_scheduler_stats()
|
||||
|
||||
template_name = 'edm_dashboard_v2.html' if request.args.get('ui') == 'v2' else 'edm_dashboard.html'
|
||||
template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html'
|
||||
|
||||
return render_template(template_name,
|
||||
promo_pages=promo_pages,
|
||||
@@ -531,7 +531,7 @@ def labor_day_dashboard():
|
||||
|
||||
scheduler_stats = load_scheduler_stats()
|
||||
|
||||
template_name = 'edm_dashboard_v2.html' if request.args.get('ui') == 'v2' else 'edm_dashboard.html'
|
||||
template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html'
|
||||
|
||||
return render_template(template_name,
|
||||
promo_pages=promo_pages,
|
||||
|
||||
@@ -198,38 +198,38 @@ def _get_vendor_stockout_list_context():
|
||||
def index():
|
||||
"""廠商缺貨系統主頁"""
|
||||
sys_log.info("[VendorStockout] 進入廠商缺貨系統主頁")
|
||||
if request.args.get('ui') == 'v2':
|
||||
return render_template(
|
||||
'vendor_stockout_index_v2.html',
|
||||
active_page='vendor_stockout',
|
||||
stats=_get_vendor_dashboard_stats()
|
||||
)
|
||||
return render_template('vendor_stockout/index.html')
|
||||
if request.args.get('ui') == 'legacy':
|
||||
return render_template('vendor_stockout/index.html')
|
||||
return render_template(
|
||||
'vendor_stockout_index_v2.html',
|
||||
active_page='vendor_stockout',
|
||||
stats=_get_vendor_dashboard_stats()
|
||||
)
|
||||
|
||||
|
||||
@vendor_bp.route('/import')
|
||||
def import_page():
|
||||
"""Excel 匯入頁面"""
|
||||
sys_log.info("[VendorStockout] 進入匯入頁面")
|
||||
if request.args.get('ui') == 'v2':
|
||||
return render_template(
|
||||
'vendor_stockout_import_v2.html',
|
||||
active_page='vendor_stockout'
|
||||
)
|
||||
return render_template('vendor_stockout/import.html')
|
||||
if request.args.get('ui') == 'legacy':
|
||||
return render_template('vendor_stockout/import.html')
|
||||
return render_template(
|
||||
'vendor_stockout_import_v2.html',
|
||||
active_page='vendor_stockout'
|
||||
)
|
||||
|
||||
|
||||
@vendor_bp.route('/list')
|
||||
def list_page():
|
||||
"""缺貨清單頁面"""
|
||||
sys_log.info("[VendorStockout] 進入缺貨清單頁面")
|
||||
if request.args.get('ui') == 'v2':
|
||||
return render_template(
|
||||
'vendor_stockout_list_v2.html',
|
||||
active_page='vendor_stockout',
|
||||
**_get_vendor_stockout_list_context()
|
||||
)
|
||||
return render_template('vendor_stockout/list.html')
|
||||
if request.args.get('ui') == 'legacy':
|
||||
return render_template('vendor_stockout/list.html')
|
||||
return render_template(
|
||||
'vendor_stockout_list_v2.html',
|
||||
active_page='vendor_stockout',
|
||||
**_get_vendor_stockout_list_context()
|
||||
)
|
||||
|
||||
|
||||
@vendor_bp.route('/vendor-management')
|
||||
|
||||
@@ -537,11 +537,11 @@
|
||||
</button>
|
||||
|
||||
<div class="dashboard-segmented">
|
||||
<a class="{% if current_filter == 'all' %}is-active{% endif %}" href="{{ url_for('dashboard.index', ui='v2', filter='all', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">全部</a>
|
||||
<a class="{% if current_filter == 'new' %}is-active{% endif %}" href="{{ url_for('dashboard.index', ui='v2', filter='new', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">新上架</a>
|
||||
<a class="{% if current_filter == 'increase' %}is-active{% endif %}" href="{{ url_for('dashboard.index', ui='v2', filter='increase', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">漲價</a>
|
||||
<a class="{% if current_filter == 'decrease' %}is-active{% endif %}" href="{{ url_for('dashboard.index', ui='v2', filter='decrease', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">降價</a>
|
||||
<a class="{% if current_filter == 'delisted' %}is-active{% endif %}" href="{{ url_for('dashboard.index', ui='v2', filter='delisted', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">下架</a>
|
||||
<a class="{% if current_filter == 'all' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='all', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">全部</a>
|
||||
<a class="{% if current_filter == 'new' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='new', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">新上架</a>
|
||||
<a class="{% if current_filter == 'increase' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='increase', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">漲價</a>
|
||||
<a class="{% if current_filter == 'decrease' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='decrease', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">降價</a>
|
||||
<a class="{% if current_filter == 'delisted' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='delisted', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">下架</a>
|
||||
</div>
|
||||
|
||||
<button class="dashboard-action-button" type="button" onclick="triggerTask()">
|
||||
@@ -576,16 +576,16 @@
|
||||
<th>分類</th>
|
||||
<th>商品名稱</th>
|
||||
<th class="text-end">
|
||||
<a href="{{ url_for('dashboard.index', ui='v2', page=1, sort_by='price', order='asc' if current_sort == 'price' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">當天價格</a>
|
||||
<a href="{{ url_for('dashboard.index', page=1, sort_by='price', order='asc' if current_sort == 'price' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">當天價格</a>
|
||||
</th>
|
||||
<th class="text-end">
|
||||
<a href="{{ url_for('dashboard.index', ui='v2', page=1, sort_by='yesterday_change', order='asc' if current_sort == 'yesterday_change' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">昨日漲跌</a>
|
||||
<a href="{{ url_for('dashboard.index', page=1, sort_by='yesterday_change', order='asc' if current_sort == 'yesterday_change' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">昨日漲跌</a>
|
||||
</th>
|
||||
<th class="text-end">
|
||||
<a href="{{ url_for('dashboard.index', ui='v2', page=1, sort_by='week_change', order='asc' if current_sort == 'week_change' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">週漲跌</a>
|
||||
<a href="{{ url_for('dashboard.index', page=1, sort_by='week_change', order='asc' if current_sort == 'week_change' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">週漲跌</a>
|
||||
</th>
|
||||
<th class="text-end">
|
||||
<a href="{{ url_for('dashboard.index', ui='v2', page=1, sort_by='timestamp', order='asc' if current_sort == 'timestamp' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">更新時間</a>
|
||||
<a href="{{ url_for('dashboard.index', page=1, sort_by='timestamp', order='asc' if current_sort == 'timestamp' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">更新時間</a>
|
||||
</th>
|
||||
<th class="text-end">上架時間</th>
|
||||
</tr>
|
||||
@@ -654,11 +654,11 @@
|
||||
{% if total_pages > 1 %}
|
||||
<div class="dashboard-pagination">
|
||||
{% if current_page > 1 %}
|
||||
<a class="dashboard-action-link" href="{{ url_for('dashboard.index', ui='v2', page=current_page - 1, category=current_category, filter=current_filter, q=search_query, sort_by=current_sort, order=current_order) }}">上一頁</a>
|
||||
<a class="dashboard-action-link" href="{{ url_for('dashboard.index', page=current_page - 1, category=current_category, filter=current_filter, q=search_query, sort_by=current_sort, order=current_order) }}">上一頁</a>
|
||||
{% endif %}
|
||||
<span class="dashboard-table-meta momo-mono">第 {{ current_page }} / {{ total_pages }} 頁</span>
|
||||
{% if current_page < total_pages %}
|
||||
<a class="dashboard-action-link" href="{{ url_for('dashboard.index', ui='v2', page=current_page + 1, category=current_category, filter=current_filter, q=search_query, sort_by=current_sort, order=current_order) }}">下一頁</a>
|
||||
<a class="dashboard-action-link" href="{{ url_for('dashboard.index', page=current_page + 1, category=current_category, filter=current_filter, q=search_query, sort_by=current_sort, order=current_order) }}">下一頁</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -474,7 +474,7 @@
|
||||
<section>
|
||||
<div class="campaign-switcher">
|
||||
{% for page in promo_pages %}
|
||||
<a class="campaign-tab {% if page.id == current_promo_page %}is-active{% endif %}" href="{{ page.url }}?ui=v2">
|
||||
<a class="campaign-tab {% if page.id == current_promo_page %}is-active{% endif %}" href="{{ page.url }}">
|
||||
<span>{{ page.name }}</span>
|
||||
{% if page.id == current_promo_page %}
|
||||
<span class="campaign-tab-count momo-mono">{{ total_edm_products | number_format }}</span>
|
||||
@@ -607,16 +607,16 @@
|
||||
<th>分類</th>
|
||||
<th>
|
||||
{% set next_order_name = 'asc' if current_sort == 'name' and current_order == 'desc' else 'desc' %}
|
||||
<a href="{{ url_for(current_endpoint, ui='v2', sort_by='name', order=next_order_name) }}">商品資訊</a>
|
||||
<a href="{{ url_for(current_endpoint, sort_by='name', order=next_order_name) }}">商品資訊</a>
|
||||
</th>
|
||||
<th class="text-end">
|
||||
{% set next_order_price = 'asc' if current_sort == 'price' and current_order == 'desc' else 'desc' %}
|
||||
<a href="{{ url_for(current_endpoint, ui='v2', sort_by='price', order=next_order_price) }}">價格</a>
|
||||
<a href="{{ url_for(current_endpoint, sort_by='price', order=next_order_price) }}">價格</a>
|
||||
</th>
|
||||
<th class="text-center">
|
||||
{% if current_promo_page == 'edm' %}
|
||||
{% set next_order_qty = 'asc' if current_sort == 'remain_qty' and current_order == 'desc' else 'desc' %}
|
||||
<a href="{{ url_for(current_endpoint, ui='v2', sort_by='remain_qty', order=next_order_qty) }}">倒數組數</a>
|
||||
<a href="{{ url_for(current_endpoint, sort_by='remain_qty', order=next_order_qty) }}">倒數組數</a>
|
||||
{% else %}
|
||||
狀態
|
||||
{% endif %}
|
||||
|
||||
@@ -340,11 +340,11 @@
|
||||
上傳正式缺貨 Excel 後,系統會使用既有匯入 API 寫入 vendor_stockout,完成後直接回傳批次編號與成功、重複、失敗筆數。
|
||||
</p>
|
||||
<div class="stockout-import-actions mt-3">
|
||||
<a class="stockout-action" href="{{ url_for('vendor.index', ui='v2') }}">
|
||||
<a class="stockout-action" href="{{ url_for('vendor.index') }}">
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
回總覽
|
||||
</a>
|
||||
<a class="stockout-action" href="{{ url_for('vendor.list_page', ui='v2') }}">
|
||||
<a class="stockout-action" href="{{ url_for('vendor.list_page') }}">
|
||||
<i class="fas fa-table-list"></i>
|
||||
缺貨清單
|
||||
</a>
|
||||
@@ -436,7 +436,7 @@
|
||||
</div>
|
||||
<div class="stockout-batch-id momo-mono">批次編號 <span id="stockoutBatchId"></span></div>
|
||||
<div class="stockout-import-actions mt-3">
|
||||
<a class="stockout-action is-primary" href="{{ url_for('vendor.list_page', ui='v2') }}">
|
||||
<a class="stockout-action is-primary" href="{{ url_for('vendor.list_page') }}">
|
||||
<i class="fas fa-table-list"></i>
|
||||
查看缺貨清單
|
||||
</a>
|
||||
|
||||
@@ -341,11 +341,11 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="vendor-actions">
|
||||
<a class="vendor-action is-primary" href="{{ url_for('vendor.import_page', ui='v2') }}">
|
||||
<a class="vendor-action is-primary" href="{{ url_for('vendor.import_page') }}">
|
||||
<i class="fas fa-file-import"></i>
|
||||
匯入 Excel
|
||||
</a>
|
||||
<a class="vendor-action" href="{{ url_for('vendor.list_page', ui='v2') }}">
|
||||
<a class="vendor-action" href="{{ url_for('vendor.list_page') }}">
|
||||
<i class="fas fa-list-check"></i>
|
||||
查看清單
|
||||
</a>
|
||||
@@ -408,14 +408,14 @@
|
||||
<span class="title">工作入口</span>
|
||||
</div>
|
||||
<div class="vendor-flow-grid">
|
||||
<a class="vendor-flow-card" href="{{ url_for('vendor.import_page', ui='v2') }}">
|
||||
<a class="vendor-flow-card" href="{{ url_for('vendor.import_page') }}">
|
||||
<span class="vendor-flow-icon"><i class="fas fa-file-import"></i></span>
|
||||
<span>
|
||||
<span class="vendor-flow-title">Excel 匯入</span>
|
||||
<span class="vendor-flow-meta momo-mono">建立缺貨批次</span>
|
||||
</span>
|
||||
</a>
|
||||
<a class="vendor-flow-card" href="{{ url_for('vendor.list_page', ui='v2') }}">
|
||||
<a class="vendor-flow-card" href="{{ url_for('vendor.list_page') }}">
|
||||
<span class="vendor-flow-icon"><i class="fas fa-table-list"></i></span>
|
||||
<span>
|
||||
<span class="vendor-flow-title">缺貨清單</span>
|
||||
|
||||
@@ -330,11 +330,11 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="stockout-actions">
|
||||
<a class="stockout-action" href="{{ url_for('vendor.index', ui='v2') }}">
|
||||
<a class="stockout-action" href="{{ url_for('vendor.index') }}">
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
回總覽
|
||||
</a>
|
||||
<a class="stockout-action is-primary" href="{{ url_for('vendor.import_page', ui='v2') }}">
|
||||
<a class="stockout-action is-primary" href="{{ url_for('vendor.import_page') }}">
|
||||
<i class="fas fa-file-import"></i>
|
||||
匯入 Excel
|
||||
</a>
|
||||
@@ -395,11 +395,11 @@
|
||||
</section>
|
||||
|
||||
<nav class="stockout-status-tabs" aria-label="缺貨狀態篩選">
|
||||
<a class="stockout-tab {% if current_status == 'all' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', ui='v2', q=search_query, batch=current_batch, sort=current_sort) }}">全部</a>
|
||||
<a class="stockout-tab {% if current_status == 'pending' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', ui='v2', status='pending', q=search_query, batch=current_batch, sort=current_sort) }}">待發送</a>
|
||||
<a class="stockout-tab {% if current_status == 'sent' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', ui='v2', status='sent', q=search_query, batch=current_batch, sort=current_sort) }}">已發送</a>
|
||||
<a class="stockout-tab {% if current_status == 'failed' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', ui='v2', status='failed', q=search_query, batch=current_batch, sort=current_sort) }}">失敗</a>
|
||||
<a class="stockout-tab {% if current_status == 'duplicate' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', ui='v2', status='duplicate', q=search_query, batch=current_batch, sort=current_sort) }}">重複</a>
|
||||
<a class="stockout-tab {% if current_status == 'all' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', q=search_query, batch=current_batch, sort=current_sort) }}">全部</a>
|
||||
<a class="stockout-tab {% if current_status == 'pending' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', status='pending', q=search_query, batch=current_batch, sort=current_sort) }}">待發送</a>
|
||||
<a class="stockout-tab {% if current_status == 'sent' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', status='sent', q=search_query, batch=current_batch, sort=current_sort) }}">已發送</a>
|
||||
<a class="stockout-tab {% if current_status == 'failed' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', status='failed', q=search_query, batch=current_batch, sort=current_sort) }}">失敗</a>
|
||||
<a class="stockout-tab {% if current_status == 'duplicate' %}is-active{% endif %}" href="{{ url_for('vendor.list_page', status='duplicate', q=search_query, batch=current_batch, sort=current_sort) }}">重複</a>
|
||||
</nav>
|
||||
|
||||
<section class="stockout-table-card" aria-label="缺貨資料表">
|
||||
@@ -472,11 +472,11 @@
|
||||
|
||||
<div class="stockout-pagination">
|
||||
{% if current_page > 1 %}
|
||||
<a class="stockout-page-link" href="{{ url_for('vendor.list_page', ui='v2', page=current_page - 1, page_size=page_size, status=current_status, q=search_query, batch=current_batch, sort=current_sort) }}">上一頁</a>
|
||||
<a class="stockout-page-link" href="{{ url_for('vendor.list_page', page=current_page - 1, page_size=page_size, status=current_status, q=search_query, batch=current_batch, sort=current_sort) }}">上一頁</a>
|
||||
{% endif %}
|
||||
<span class="stockout-page-link momo-mono">{{ current_page }} / {{ total_pages }}</span>
|
||||
{% if current_page < total_pages %}
|
||||
<a class="stockout-page-link" href="{{ url_for('vendor.list_page', ui='v2', page=current_page + 1, page_size=page_size, status=current_status, q=search_query, batch=current_batch, sort=current_sort) }}">下一頁</a>
|
||||
<a class="stockout-page-link" href="{{ url_for('vendor.list_page', page=current_page + 1, page_size=page_size, status=current_status, q=search_query, batch=current_batch, sort=current_sort) }}">下一頁</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -39,37 +39,40 @@ def test_frontend_v2_shell_uses_real_runtime_context():
|
||||
assert all(marker not in combined for marker in forbidden_markers)
|
||||
|
||||
|
||||
def test_dashboard_v2_is_feature_flagged_and_uses_real_dashboard_data():
|
||||
def test_dashboard_v2_is_production_default_and_uses_real_dashboard_data():
|
||||
route_source = (ROOT / "routes/dashboard_routes.py").read_text(encoding="utf-8")
|
||||
dashboard = (ROOT / "templates/dashboard_v2.html").read_text(encoding="utf-8")
|
||||
|
||||
assert "request.args.get('ui') == 'v2'" in route_source
|
||||
assert "template_name = 'dashboard_v2.html'" in route_source
|
||||
assert "request.args.get('ui') == 'legacy'" in route_source
|
||||
assert "template_name = 'dashboard.html' if request.args.get('ui') == 'legacy' else 'dashboard_v2.html'" in route_source
|
||||
assert "get_full_dashboard_data()" in route_source
|
||||
assert "MockRecord" not in route_source
|
||||
assert "{% for item in items %}" in dashboard
|
||||
assert "ui='v2'" not in dashboard
|
||||
assert "mockProducts" not in dashboard
|
||||
assert "假商品" not in dashboard
|
||||
|
||||
|
||||
def test_edm_dashboard_v2_is_feature_flagged_and_uses_real_campaign_data():
|
||||
def test_edm_dashboard_v2_is_production_default_and_uses_real_campaign_data():
|
||||
route_source = (ROOT / "routes/edm_routes.py").read_text(encoding="utf-8")
|
||||
template = (ROOT / "templates/edm_dashboard_v2.html").read_text(encoding="utf-8")
|
||||
|
||||
assert route_source.count("request.args.get('ui') == 'v2'") == 5
|
||||
assert "template_name = 'edm_dashboard_v2.html'" in route_source
|
||||
assert route_source.count("request.args.get('ui') == 'legacy'") == 5
|
||||
assert "template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html'" in route_source
|
||||
assert "{% for slot, stats in slot_stats.items() %}" in template
|
||||
assert "{% for item in items %}" in template
|
||||
assert "scheduler_stats.get(task_key, [])" in template
|
||||
assert "?ui=v2" not in template
|
||||
assert "ui='v2'" not in template
|
||||
assert "mock" not in template.lower()
|
||||
assert "假商品" not in template
|
||||
|
||||
|
||||
def test_vendor_stockout_v2_is_feature_flagged_and_uses_real_vendor_data():
|
||||
def test_vendor_stockout_v2_is_production_default_and_uses_real_vendor_data():
|
||||
route_source = (ROOT / "routes/vendor_routes.py").read_text(encoding="utf-8")
|
||||
template = (ROOT / "templates/vendor_stockout_index_v2.html").read_text(encoding="utf-8")
|
||||
|
||||
assert "request.args.get('ui') == 'v2'" in route_source
|
||||
assert "request.args.get('ui') == 'legacy'" in route_source
|
||||
assert not (ROOT / "web/templates/vendor_stockout_index_v2.html").exists()
|
||||
assert "vendor_stockout_index_v2.html" in route_source
|
||||
assert "_get_vendor_dashboard_stats()" in route_source
|
||||
@@ -77,6 +80,7 @@ def test_vendor_stockout_v2_is_feature_flagged_and_uses_real_vendor_data():
|
||||
assert "EmailSendLog" in route_source
|
||||
assert "stats.pending_stockouts" in template
|
||||
assert "stats.email_success_rate" in template
|
||||
assert "ui='v2'" not in template
|
||||
assert "mock" not in template.lower()
|
||||
assert "假" not in template
|
||||
|
||||
@@ -97,6 +101,7 @@ def test_vendor_stockout_list_v2_is_feature_flagged_and_uses_real_stockout_rows(
|
||||
assert "record.product_code" in template
|
||||
assert "record.product_name" in template
|
||||
assert "record.vendor_name" in template
|
||||
assert "ui='v2'" not in template
|
||||
assert "mock" not in template.lower()
|
||||
assert "假" not in template
|
||||
|
||||
@@ -112,5 +117,6 @@ def test_vendor_stockout_import_v2_is_feature_flagged_and_does_not_ship_sample_r
|
||||
assert "fetchWithCSRF('/vendor-stockout/api/import/excel'" in template
|
||||
assert "vendor_stockout" in template
|
||||
assert "範例" not in template_function
|
||||
assert "ui='v2'" not in template
|
||||
assert "mock" not in template.lower()
|
||||
assert "假" not in template
|
||||
|
||||
Reference in New Issue
Block a user