Backend: - Add setup-backend.sh/bat for one-click backend setup - Fix test_auth.py mock settings (JWT_EXPIRE_HOURS) - Fix test_excel_export.py TEMPLATE_DIR reference Frontend: - Add config.json for runtime API URL configuration - Add init.js and settings.js for config loading - Update main.js to load config from external file - Update api.js to use dynamic API_BASE_URL - Update all pages to initialize config before API calls - Update package.json with extraResources for config Build: - Add build-client.sh/bat for packaging Electron + Sidecar - Add build-all.ps1 PowerShell script with -ApiUrl parameter - Add GitHub Actions workflow for Windows builds - Add scripts/README.md documentation This allows IT to configure backend URL without rebuilding. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
124 lines
4.2 KiB
Python
124 lines
4.2 KiB
Python
"""Test Excel export functionality with template filling."""
|
|
import os
|
|
import sys
|
|
from datetime import datetime, date
|
|
from openpyxl import load_workbook
|
|
|
|
# Add parent directory to path
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from app.routers.export import fill_template_workbook, create_default_workbook, BASE_DIR
|
|
from app.config import settings
|
|
|
|
TEMPLATE_DIR = settings.get_template_dir(BASE_DIR)
|
|
RECORD_DIR = settings.get_record_dir(BASE_DIR)
|
|
|
|
|
|
def test_excel_export():
|
|
"""Test Excel generation with mock data."""
|
|
|
|
# Mock meeting data
|
|
meeting = {
|
|
"meeting_id": 1,
|
|
"uuid": "test-uuid-123",
|
|
"meeting_number": "M-20251211-01",
|
|
"subject": "專案進度討論會議",
|
|
"meeting_time": datetime(2025, 12, 11, 14, 30),
|
|
"location": "會議室A",
|
|
"chairperson": "王經理",
|
|
"recorder": "李小明",
|
|
"attendees": "張三, 李四, 王五",
|
|
"created_by": "test@example.com",
|
|
}
|
|
|
|
# Mock conclusions
|
|
conclusions = [
|
|
{"conclusion_id": 1, "content": "確認專案時程延後兩週", "system_code": "C-20251211-01"},
|
|
{"conclusion_id": 2, "content": "同意增加測試人力", "system_code": "C-20251211-02"},
|
|
{"conclusion_id": 3, "content": "下次會議改為線上進行", "system_code": "C-20251211-03"},
|
|
]
|
|
|
|
# Mock action items
|
|
actions = [
|
|
{
|
|
"action_id": 1,
|
|
"content": "更新專案時程表",
|
|
"owner": "張三",
|
|
"due_date": date(2025, 12, 15),
|
|
"status": "Open",
|
|
"system_code": "A-20251211-01",
|
|
},
|
|
{
|
|
"action_id": 2,
|
|
"content": "聯繫人資部門增聘測試人員",
|
|
"owner": "李四",
|
|
"due_date": date(2025, 12, 20),
|
|
"status": "In Progress",
|
|
"system_code": "A-20251211-02",
|
|
},
|
|
{
|
|
"action_id": 3,
|
|
"content": "準備線上會議設備",
|
|
"owner": "王五",
|
|
"due_date": None,
|
|
"status": "Open",
|
|
"system_code": "A-20251211-03",
|
|
},
|
|
]
|
|
|
|
# Check paths
|
|
template_path = os.path.join(TEMPLATE_DIR, "meeting_template.xlsx")
|
|
print(f"Template directory: {TEMPLATE_DIR}")
|
|
print(f"Record directory: {RECORD_DIR}")
|
|
print(f"Template exists: {os.path.exists(template_path)}")
|
|
|
|
# Ensure record directory exists
|
|
os.makedirs(RECORD_DIR, exist_ok=True)
|
|
|
|
# Generate filename with meeting number
|
|
meeting_number = meeting.get("meeting_number", "")
|
|
filename = f"{meeting_number}.xlsx" if meeting_number else f"meeting_{meeting['uuid']}.xlsx"
|
|
output_path = os.path.join(RECORD_DIR, filename)
|
|
|
|
# Test with template if exists
|
|
if os.path.exists(template_path):
|
|
print("\n=== Testing with template ===")
|
|
wb = load_workbook(template_path)
|
|
wb = fill_template_workbook(wb, meeting, conclusions, actions)
|
|
wb.save(output_path)
|
|
print(f"Saved to: {output_path}")
|
|
|
|
# Verify cell values
|
|
ws = wb.active
|
|
print("\n--- Verification ---")
|
|
print(f"D3 (Subject): {ws['D3'].value}")
|
|
print(f"D4 (Time): {ws['D4'].value}")
|
|
print(f"D5 (Chair): {ws['D5'].value}")
|
|
print(f"F4 (Location): {ws['F4'].value}")
|
|
print(f"F5 (Recorder): {ws['F5'].value}")
|
|
print(f"D6 (Attendees): {ws['D6'].value}")
|
|
print(f"C8 (Meeting Number): {ws['C8'].value}")
|
|
print(f"D8 (Conclusions): {ws['D8'].value}")
|
|
print(f"\nAction Items:")
|
|
for i in range(3):
|
|
row = 10 + i
|
|
print(f" Row {row}: C={ws[f'C{row}'].value}, D={ws[f'D{row}'].value}, F={ws[f'F{row}'].value}, G={ws[f'G{row}'].value}, H={ws[f'H{row}'].value}")
|
|
else:
|
|
print("\n=== Template not found, using default generation ===")
|
|
wb = create_default_workbook(meeting, conclusions, actions)
|
|
wb.save(output_path)
|
|
print(f"Saved to: {output_path}")
|
|
|
|
print(f"\n✅ Test completed! File saved to: {output_path}")
|
|
|
|
# List files in record directory
|
|
print(f"\n--- Files in record directory ---")
|
|
for f in os.listdir(RECORD_DIR):
|
|
print(f" {f}")
|
|
|
|
return True
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_excel_export()
|