This commit is contained in:
admin
2026-01-12 20:59:52 +09:00
parent 76d8e7622e
commit 59e8e8625d
7 changed files with 840 additions and 314 deletions

View File

@@ -1,98 +1,134 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>修正仕訳入力</title>
<style>
body { font-family: sans-serif; margin: 24px; }
table { border-collapse: collapse; width: 100%; margin-top: 12px; }
th, td { border: 1px solid #ccc; padding: 6px; text-align: center; }
th { background: #f5f5f5; }
input, select, button { padding: 6px; }
.right { text-align: right; }
.error { color: #c00; margin-top: 8px; }
.ok { color: #090; margin-top: 8px; }
</style>
</head>
<body>
<head>
<meta charset="UTF-8" />
<title>修正仕訳入力</title>
<style>
body {
font-family: sans-serif;
margin: 24px;
}
table {
border-collapse: collapse;
width: 100%;
margin-top: 12px;
}
th,
td {
border: 1px solid #ccc;
padding: 6px;
text-align: center;
}
th {
background: #f5f5f5;
}
input,
select,
button {
padding: 6px;
}
.right {
text-align: right;
}
.error {
color: #c00;
margin-top: 8px;
}
.ok {
color: #090;
margin-top: 8px;
}
</style>
</head>
<body>
<h2>修正仕訳入力</h2>
<h2>修正仕訳入力</h2>
<label>仕訳日</label>
<input type="date" id="entryDate" />
<label>仕訳日</label>
<input type="date" id="entryDate">
<label>摘要</label>
<input type="text" id="description" style="width: 60%" />
<label>摘要</label>
<input type="text" id="description" style="width:60%">
<table id="linesTable">
<thead>
<tr>
<th>科目</th>
<th>借方</th>
<th>貸方</th>
<th>操作</th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<th>合計</th>
<th id="debitTotal" class="right">0</th>
<th id="creditTotal" class="right">0</th>
<th></th>
</tr>
</tfoot>
</table>
<table id="linesTable">
<thead>
<tr>
<th>科目</th>
<th>借方</th>
<th>貸方</th>
<th>操作</th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<th>合計</th>
<th id="debitTotal" class="right">0</th>
<th id="creditTotal" class="right">0</th>
<th></th>
</tr>
</tfoot>
</table>
<div style="margin-top: 12px">
<button onclick="addRow()"> 行追加</button>
<button onclick="submitEntry()">修正版仕訳を登録</button>
<button onclick="cancelEdit()" style="background-color: #f0f0f0">
キャンセル
</button>
</div>
<button onclick="addRow()"> 行追加</button>
<button onclick="submitEntry()">修正版仕訳を登録</button>
<div id="result"></div>
<div id="result"></div>
<script>
const API = "http://127.0.0.1:18080";
let accounts = [];
<script>
const API = "http://127.0.0.1:18080";
let accounts = [];
// ------------------------------------
// 初期化
// ------------------------------------
async function init() {
// 科目取得
const res = await fetch(`${API}/accounts`);
const data = await res.json();
accounts = data.items ?? data;
// ------------------------------------
// 初期化
// ------------------------------------
async function init() {
// 科目取得
const res = await fetch(`${API}/accounts`);
accounts = await res.json();
// 元仕訳取得
const src = localStorage.getItem("editSource");
if (!src) {
showError("修正元の仕訳データが見つかりません");
return;
}
const srcData = JSON.parse(src);
// 元仕訳取得
const src = localStorage.getItem("editSource");
if (!src) {
showError("修正元の仕訳データが見つかりません");
return;
}
const data = JSON.parse(src);
// ヘッダ反映
document.getElementById("entryDate").value = srcData.entry_date;
document.getElementById(
"description"
).value = `【修正後】${srcData.description}`;
// ヘッダ反映
document.getElementById("entryDate").value = data.entry_date;
document.getElementById("description").value = `【修正後】${data.description}`;
// 明細反映
srcData.lines.forEach((l) => addRow(l));
// 明細反映
data.lines.forEach(l => addRow(l));
recalc();
}
init();
recalc();
}
init();
// ------------------------------------
// 行操作
// ------------------------------------
function addRow(line = null) {
const tbody = document.querySelector("#linesTable tbody");
const tr = document.createElement("tr");
// ------------------------------------
// 行操作
// ------------------------------------
function addRow(line = null) {
const tbody = document.querySelector("#linesTable tbody");
const tr = document.createElement("tr");
tr.innerHTML = `
tr.innerHTML = `
<td>
<select>
${accounts.map(a =>
`<option value="${a.account_id}">${a.account_code} ${a.account_name}</option>`
).join("")}
${accounts
.map(
(a) =>
`<option value="${a.account_id}">${a.account_code} ${a.account_name}</option>`
)
.join("")}
</select>
</td>
<td><input type="number" min="0"></td>
@@ -100,97 +136,108 @@ function addRow(line = null) {
<td><button onclick="removeRow(this)">削除</button></td>
`;
tbody.appendChild(tr);
tbody.appendChild(tr);
if (line) {
tr.querySelector("select").value = line.account_id;
tr.querySelectorAll("input")[0].value = line.debit || "";
tr.querySelectorAll("input")[1].value = line.credit || "";
}
}
if (line) {
tr.querySelector("select").value = line.account_id;
tr.querySelectorAll("input")[0].value = line.debit || "";
tr.querySelectorAll("input")[1].value = line.credit || "";
}
}
function removeRow(btn) {
btn.closest("tr").remove();
recalc();
}
function removeRow(btn) {
btn.closest("tr").remove();
recalc();
}
// ------------------------------------
// 合計再計算
// ------------------------------------
function recalc() {
let d = 0, c = 0;
document.querySelectorAll("#linesTable tbody tr").forEach(tr => {
d += Number(tr.querySelectorAll("input")[0].value || 0);
c += Number(tr.querySelectorAll("input")[1].value || 0);
});
document.getElementById("debitTotal").textContent = d.toLocaleString();
document.getElementById("creditTotal").textContent = c.toLocaleString();
}
// ------------------------------------
// 合計再計算
// ------------------------------------
function recalc() {
let d = 0,
c = 0;
document.querySelectorAll("#linesTable tbody tr").forEach((tr) => {
d += Number(tr.querySelectorAll("input")[0].value || 0);
c += Number(tr.querySelectorAll("input")[1].value || 0);
});
document.getElementById("debitTotal").textContent = d.toLocaleString();
document.getElementById("creditTotal").textContent = c.toLocaleString();
}
// ------------------------------------
// 登録
// ------------------------------------
async function submitEntry() {
const result = document.getElementById("result");
result.textContent = "";
result.className = "";
// ------------------------------------
// 登録
// ------------------------------------
async function submitEntry() {
const result = document.getElementById("result");
result.textContent = "";
result.className = "";
const entryDate = document.getElementById("entryDate").value;
const desc = document.getElementById("description").value;
const entryDate = document.getElementById("entryDate").value;
const desc = document.getElementById("description").value;
if (!entryDate || !desc) {
showError("日付と摘要は必須です");
return;
}
if (!entryDate || !desc) {
showError("日付と摘要は必須です");
return;
}
const lines = [];
let d = 0, c = 0;
const lines = [];
let d = 0,
c = 0;
document.querySelectorAll("#linesTable tbody tr").forEach(tr => {
const accountId = Number(tr.querySelector("select").value);
const debit = Number(tr.querySelectorAll("input")[0].value || 0);
const credit = Number(tr.querySelectorAll("input")[1].value || 0);
if (debit === 0 && credit === 0) return;
lines.push({ account_id: accountId, debit, credit });
d += debit;
c += credit;
});
document.querySelectorAll("#linesTable tbody tr").forEach((tr) => {
const accountId = Number(tr.querySelector("select").value);
const debit = Number(tr.querySelectorAll("input")[0].value || 0);
const credit = Number(tr.querySelectorAll("input")[1].value || 0);
if (debit === 0 && credit === 0) return;
lines.push({ account_id: accountId, debit, credit });
d += debit;
c += credit;
});
if (lines.length < 2) return showError("仕訳行は2行以上必要です");
if (d !== c) return showError("借方合計と貸方合計が一致していません");
if (lines.length < 2) return showError("仕訳行は2行以上必要です");
if (d !== c) return showError("借方合計と貸方合計が一致していません");
const payload = {
entry_date: entryDate,
description: desc,
lines
};
const payload = {
entry_date: entryDate,
description: desc,
lines,
tax_paid_account_id: null,
tax_received_account_id: null,
rounding_mode: "floor",
};
try {
const res = await fetch(`${API}/journal-entries`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
const data = await res.json();
if (!res.ok) return showError(data.detail || "登録失敗");
showOk(`修正版仕訳を登録しましたID: ${data.journal_entry_id}`);
localStorage.removeItem("editSource");
} catch {
showError("通信エラー");
}
}
try {
const res = await fetch(`${API}/journal-entries`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
const data = await res.json();
if (!res.ok) return showError(data.detail || "登録失敗");
showOk(`修正版仕訳を登録しましたID: ${data.journal_entry_id}`);
localStorage.removeItem("editSource");
} catch {
showError("通信エラー");
}
}
function showError(msg) {
const r = document.getElementById("result");
r.textContent = msg;
r.className = "error";
}
function showOk(msg) {
const r = document.getElementById("result");
r.textContent = msg;
r.className = "ok";
}
</script>
function showError(msg) {
const r = document.getElementById("result");
r.textContent = msg;
r.className = "error";
}
function showOk(msg) {
const r = document.getElementById("result");
r.textContent = msg;
r.className = "ok";
}
</body>
function cancelEdit() {
if (confirm("編集をキャンセルして一覧画面に戻りますか?")) {
localStorage.removeItem("editSource");
window.location.href = "journal-list.html";
}
}
</script>
</body>
</html>