修正
This commit is contained in:
313
FRONTEND_INTEGRATION_GUIDE.js
Normal file
313
FRONTEND_INTEGRATION_GUIDE.js
Normal 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 文檔已更新",
|
||||
"[ ] 訓練資料已準備"
|
||||
]
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
Reference in New Issue
Block a user