This commit is contained in:
admin
2026-02-20 15:47:27 +09:00
parent c60cbf2d9a
commit 584530937b
108 changed files with 12112 additions and 416 deletions

View File

@@ -0,0 +1,313 @@
// ============================================================================
// 【前端集成指南】 - 修正版本追踪系統
// ============================================================================
/**
* 【API 變更概要】
*
* 舊 API
* - POST /journal-entries (parent_entry_id) // 創建逆仕訳
* - 複雜的逆仕訳生成邏輯
*
* 新 API
* - POST /journal-entries (original_entry_id) // 直接創建修正版本
* - GET /journal-entries/{id}/revision-history // 查看修正歷史
*/
// ============================================================================
// 【1】創建新交易無修正- 基本用法
// ============================================================================
async function createJournalEntry(entryData) {
const payload = {
entry_date: entryData.date, // "2025-01-15"
description: entryData.description, // "銷售收入"
lines: entryData.lines, // 交易明細
tax_paid_account_id: entryData.taxPaidId,
tax_received_account_id: entryData.taxReceivedId,
rounding_mode: "round"
// 注意:這裡 original_entry_id 沒有指定,表示這是新交易
};
const response = await fetch("/journal-entries", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (response.ok) {
const result = await response.json();
console.log("✓ 交易創建成功:", result.journal_entry_id);
return result;
} else {
alert("❌ 創建失敗");
}
}
// ============================================================================
// 【2】創建修正版本 - 關鍵變更
// ============================================================================
async function createRevisionEntry(originalEntryId, entryData) {
const payload = {
entry_date: entryData.date,
description: `【修正】${entryData.description}`, // 添加【修正】標記
lines: entryData.lines,
tax_paid_account_id: entryData.taxPaidId,
tax_received_account_id: entryData.taxReceivedId,
rounding_mode: "round",
// ✨ 新參數:指向原始交易
original_entry_id: originalEntryId
};
const response = await fetch("/journal-entries", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (response.ok) {
const result = await response.json();
console.log("✓ 修正版本創建成功:");
console.log(` 原始交易 ID: ${originalEntryId}`);
console.log(` 新版本 ID: ${result.journal_entry_id}`);
console.log(` 版本: ${result.revision_created ? "新版本" : "覆蓋"}`);
return result;
}
}
// ============================================================================
// 【3】查看修正歷史 - 新功能
// ============================================================================
async function viewRevisionHistory(journalId) {
const response = await fetch(`/journal-entries/${journalId}/revision-history`);
if (response.ok) {
const data = await response.json();
console.log(`修正歷史 (原始交易 ID: ${data.original_entry_id}):`);
console.log(`總版本數: ${data.total_versions}`);
data.versions.forEach(version => {
const status = version.is_latest ? "【最新】" : "【已過時】";
console.log(`
版本 ${version.revision_count}: ${status}
- 交易 ID: ${version.journal_entry_id}
- 摘要: ${version.description}
- 建立時間: ${version.created_at}
`);
});
return data;
}
}
// ============================================================================
// 【4】前端修正流程 - 完整示例
// ============================================================================
async function handleEditTransaction(originalEntryId) {
// 步驟 1: 顯示修正對話框
const originalData = await fetchJournalEntry(originalEntryId); // 現有的 API
const editedData = showEditDialog(originalData); // 用户編緬
if (!editedData) {
console.log("⚠️ 編輯已取消");
return;
}
// 步驟 2: 檢查是否有實際變更
if (areEntriesEqual(originalData, editedData)) {
console.log("⚠️ 沒有任何變更");
return;
}
// 步驟 3: 創建修正版本
const result = await createRevisionEntry(originalEntryId, editedData);
if (result && result.status === "ok") {
// 步驟 4: 更新頁面
refreshJournalList(); // 重新加載列表
alert(`✓ 交易已修正。新版本 ID: ${result.journal_entry_id}`);
// 步驟 5: 可選 - 顯示修正歷史
// await showRevisionHistory(originalEntryId);
}
}
// ============================================================================
// 【5】試算表查詢 - 前端優化
// ============================================================================
/**
* 舊做法(不需要):
* const entries = await fetchAllJournalEntries();
* const latestOnly = entries.filter(e => e.parent_entry_id === null);
*
* 新做法(推薦):
* 後端已經自動過濾, 返回的都是 is_latest = true 的交易
*/
async function fetchTrialBalance(fromDate, toDate) {
// 不需要任何客戶端過濾邏輯
// 後端已確保只返回 is_latest = true 的交易
const response = await fetch(
`/journal-entries?from_date=${fromDate}&to_date=${toDate}`,
{ method: "GET" }
);
if (response.ok) {
const entries = await response.json();
// entries 已經只包含最新版本
// 直接計算試算表
return calculateTrialBalance(entries);
}
}
// ============================================================================
// 【6】修正歷史界面 - UI 示例
// ============================================================================
function displayRevisionHistory(journalId) {
// HTML 結構
const html = `
<div class="revision-history">
<h3>修正歷史</h3>
<div class="revision-timeline" id="timeline">
<!-- 將使用 JavaScript 動態填充 -->
</div>
<button onclick="showRevisionComparison()">
對比版本
</button>
</div>
`;
// 獲取歷史數據
viewRevisionHistory(journalId).then(data => {
const timeline = document.getElementById("timeline");
data.versions.forEach(version => {
const element = document.createElement("div");
element.className = `revision-item ${version.is_latest ? "latest" : "outdated"}`;
element.innerHTML = `
<div class="revision-header">
<span class="version-number">版本 ${version.revision_count}</span>
<span class="status">
${version.is_latest ? "✓ 最新" : "過時"}
</span>
</div>
<div class="revision-details">
<p><strong>摘要:</strong> ${version.description}</p>
<p><strong>日期:</strong> ${version.entry_date}</p>
<p><strong>建立:</strong> ${new Date(version.created_at).toLocaleString()}</p>
<p><strong>操作員:</strong> ${version.created_by}</p>
</div>
`;
timeline.appendChild(element);
});
});
}
// ============================================================================
// 【7】向後兼容性 - 舊 parent_entry_id 支持
// ============================================================================
/**
* 為了向後兼容,後端仍然接受 parent_entry_id 參數
* 但將被忽略,請改用 original_entry_id
*
* 舊代碼仍然有效(會自動轉換):
*/
async function createRevisionParentMethod(parentId, data) {
// ⚠️ 不推薦 - 舊方式
return await fetch("/journal-entries", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
...data,
parent_entry_id: parentId // ← 舊參數(向後兼容)
})
});
}
// ============================================================================
// 【8】錯誤處理
// ============================================================================
async function createRevisionWithErrorHandling(originalEntryId, data) {
try {
const result = await createRevisionEntry(originalEntryId, data);
if (!result.status) {
throw new Error("API 響應格式錯誤");
}
if (result.status === "error") {
throw new Error(result.detail || "未知錯誤");
}
return result;
} catch (error) {
console.error("❌ 修正失敗:", error.message);
alert(`修正失敗: ${error.message}`);
throw error;
}
}
// ============================================================================
// 【9】測試檢查清單
// ============================================================================
/**
* 部署前請確認以下功能正常:
*
* [ ] 創建新交易 (original_entry_id = null)
* [ ] 創建修正版本 (original_entry_id ≠ null)
* [ ] 試算表只顯示最新版本
* [ ] 修正歷史端點返回完整列表
* [ ] 舊的 parent_entry_id 參數仍然可用(向後兼容)
* [ ] 修改同一交易三次,全部版本都能查詢
*/
// ============================================================================
// 【10】遷移檢查表 - 前端
// ============================================================================
const PRE_DEPLOYMENT_CHECKLIST = {
API_Changes: [
"✓ 使用 original_entry_id 創建修正版本",
"✓ 調用 GET .../revision-history 查看歷史",
"✓ 試算表查詢已包含 is_latest = true後端處理"
],
UI_Updates: [
"[ ] 修正的交易不再出現在主列表中",
"[ ] 添加"查看歷史"按鈕",
"[ ] 添加修正時間線顯示",
"[ ] 錯誤提示信息已更新"
],
Testing: [
"[ ] 單元測試已更新",
"[ ] 集成測試已完成",
"[ ] E2E 測試已通過",
"[ ] 性能測試已驗證"
],
Documentation: [
"[ ] 用户文檔已更新",
"[ ] API 文檔已更新",
"[ ] 訓練資料已準備"
]
};
// ============================================================================