This commit is contained in:
admin
2026-03-03 00:01:43 +09:00
parent 3b028b8fc0
commit 068903b933
31 changed files with 3204 additions and 889 deletions

View File

@@ -3,8 +3,18 @@
// ===============================================
console.log("🔧 trial-balance.js ファイルが読み込まれました");
// 初期读入関数
// 防止重复初始化
let trialBalanceInitialized = false;
// 初期読込関数
function initTrialBalance() {
// 已经初始化过就直接返回
if (trialBalanceInitialized) {
console.log("⚠️ initTrialBalance() はすでに実行済みです");
return;
}
trialBalanceInitialized = true;
console.log("✓ initTrialBalance() 関数が実行されました");
const API_URL = `/trial-balance`;
@@ -69,12 +79,90 @@ function initTrialBalance() {
tbody.innerHTML = "";
let totalOpening = 0;
let totalDebit = 0;
let totalCredit = 0;
let totalClosing = 0;
// =========================================
// 科目タイプ判定関数(日本企業損益計算書対応)
// =========================================
function getAccountType(accountCode) {
if (!accountCode) return "unknown";
const code = parseInt(accountCode);
// 営業収益(売上高)
if (code === 701) return "operating_revenue";
// 非営業収益(受取利息、雑収入)
if (code === 702 || code === 709) return "non_operating_revenue";
// 売上原価(仕入高)
if (code === 801) return "cogs";
// 営業費用仕入高以外の800-899、ただし520-599は除外
if (code >= 802 && code <= 899) return "operating_expense";
// 法人税等504- 損益計算に含めない
if (code === 504) return "corporate_tax";
// 消費税等505- 損益計算に含めない
if (code === 505) return "consumption_tax";
// その他は貸借科目
return "balance_sheet";
}
// =========================================
// 各タイプの合計集計(日本企業損益計算書対応)
// =========================================
let operatingRevenue = 0; // 701: 売上高(貸方)
let cogs = 0; // 801: 売上原価(借方)
let operatingExpenses = 0; // 802-820: 営業費用(借方)
let nonOperatingRevenue = 0; // 702, 709: 営業外収益(貸方)
let corporateTax = 0; // 504: 法人税等(貸方)
let consumptionTax = 0; // 505: 消費税(貸方)
// 税理士資料形式P/L科目の原始借方・貸方合計
let plTotalDebit = 0; // 全費用科目の借方合計801-820
let plTotalCredit = 0; // 全収益科目の貸方合計701-709
let bsDebit = 0; // 貸借科目合計(借方)
let bsCredit = 0; // 貸借科目合計(貸方)
data.accounts.forEach((row) => {
const code = row.account_code;
const debit = Number(row.debit ?? 0);
const credit = Number(row.credit ?? 0);
const type = getAccountType(code);
if (type === "operating_revenue") {
operatingRevenue += credit - debit;
plTotalCredit += credit;
} else if (type === "non_operating_revenue") {
nonOperatingRevenue += credit - debit;
plTotalCredit += credit;
} else if (type === "cogs") {
cogs += debit - credit;
plTotalDebit += debit;
} else if (type === "operating_expense") {
operatingExpenses += debit - credit;
plTotalDebit += debit;
} else if (type === "balance_sheet") {
bsDebit += debit;
bsCredit += credit;
}
});
// 日本企業損益計算書の標準フロー
// ※ 504(未払法人税等)、505(未払消費税等) は負債科目のため損益計算に含めない
const grossProfit = operatingRevenue - cogs; // 売上総利益 = 売上高 - 売上原価
const operatingProfit = grossProfit - operatingExpenses; // 営業利益 = 売上総利益 - 営業費用
const ordinaryProfit = operatingProfit + nonOperatingRevenue; // 経常利益 = 営業利益 + 営業外収益
// 801-820科目の合計を計算用の変量
let operatingExpense801_820Debit = 0;
let operatingExpense801_820Credit = 0;
// 税引前当期純利益 = 経常利益(特別損益の分類がないため)
const netProfit = ordinaryProfit; // 当期純利益 = 経常利益(法人税等は損益計算に含めない)
data.accounts.forEach((row) => {
const code = row.account_code;
const debit = Number(row.debit ?? 0);
const credit = Number(row.credit ?? 0);
const opening = Number(row.opening_balance ?? 0);
@@ -85,14 +173,6 @@ function initTrialBalance() {
// =========================
const isTotalRow = !row.account_code; // null / "" / undefined 全覆盖
// 明细行だけ合計に含める
if (!isTotalRow) {
totalOpening += opening;
totalDebit += debit;
totalCredit += credit;
totalClosing += closing;
}
const tr = document.createElement("tr");
if (isTotalRow) {
@@ -106,32 +186,32 @@ function initTrialBalance() {
const ratio = row.ratio ?? "0.00";
// =========================
// 借方・貸方は全科目共通でそのまま表示
// =========================
const displayDebit = debit ? debit.toLocaleString() : "";
const displayCredit = credit ? credit.toLocaleString() : "";
// 期末残高のフォーマット(マイナス値も表示)
let displayClosing = "";
if (closing !== 0) {
displayClosing = closing.toLocaleString();
}
tr.innerHTML = `
<td class="left">${row.account_code ?? ""}</td>
<td class="left">${row.account_name ?? ""}</td>
<td class="right">${opening ? opening.toLocaleString() : ""}</td>
<td class="right">${debit ? debit.toLocaleString() : ""}</td>
<td class="right">${credit ? credit.toLocaleString() : ""}</td>
<td class="right">${closing ? closing.toLocaleString() : ""}</td>
<td class="right">${displayDebit}</td>
<td class="right">${displayCredit}</td>
<td class="right">${displayClosing}</td>
<td class="right">${ratio}</td>
`;
tbody.appendChild(tr);
});
// =========================
// フッター合計
// =========================
document.getElementById("totalOpening").textContent =
totalOpening.toLocaleString();
document.getElementById("totalDebit").textContent =
totalDebit.toLocaleString();
document.getElementById("totalCredit").textContent =
totalCredit.toLocaleString();
document.getElementById("totalClosing").textContent =
totalClosing.toLocaleString();
document.getElementById("totalRatio").textContent =
data.totals?.ratio ?? "100.00";
// フッター合計は削除
// 加載中ステータスを非表示
const loadingEl = document.getElementById("loadingStatus");
@@ -166,9 +246,15 @@ function initTrialBalance() {
toDate.getMonth() + 1
}${toDate.getDate()}`;
document.getElementById("periodInfo").textContent = periodText;
// thead内の期間情報も更新印刷用
const theadPeriodInfo = document.getElementById("theadPeriodInfo");
if (theadPeriodInfo) {
theadPeriodInfo.textContent = periodText;
}
}
// 検索ボタンのイベント
// 檢索按鈕的事件
document.getElementById("btnSearch").addEventListener("click", () => {
const dateFrom = document.getElementById("dateFrom").value;
const dateTo = document.getElementById("dateTo").value;
@@ -198,6 +284,31 @@ function initTrialBalance() {
loadTrialBalance(dateFrom, dateTo);
});
// 印刷ボタンのイベント(最新データを読み込んでから印刷)
document.getElementById("btnPrint").addEventListener("click", () => {
const dateFrom = document.getElementById("dateFrom").value;
const dateTo = document.getElementById("dateTo").value;
if (!dateFrom || !dateTo) {
alert("開始年月日と終了年月日を入力してください");
return;
}
if (dateFrom > dateTo) {
alert("開始年月日は終了年月日より前の日付を指定してください");
return;
}
// 最新データを読込んでから印刷
loadTrialBalance(dateFrom, dateTo);
// データ読込完了を待って印刷開始(少し遅延させる)
setTimeout(() => {
setupPrintDate(); // 打印前更新日期
window.print();
}, 800);
});
// 初期読み込み5/31決算に対応
try {
const defaultPeriod = getDefaultPeriod();
@@ -219,3 +330,38 @@ if (document.readyState === "loading") {
// ページがすでに読み込まれている場合、すぐに実行
setTimeout(initTrialBalance, 100);
}
// 打印日期和页码设置
// ===============================================
function setupPrintDate() {
const printDateEl = document.getElementById("printDate");
if (!printDateEl) return;
// 设置打印日期
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0");
const date = String(today.getDate()).padStart(2, "0");
const dateStr = `${year}${month.replace(/^0/, "")}${date.replace(
/^0/,
"",
)}`;
printDateEl.textContent = `印刷日:${dateStr}`;
// thead内の印刷日も更新
const theadPrintDate = document.getElementById("theadPrintDate");
if (theadPrintDate) {
theadPrintDate.textContent = `印刷日:${dateStr}`;
console.log("✓ 印刷日を更新しました:", theadPrintDate.textContent);
} else {
console.warn("⚠️ theadPrintDate要素が見つかりません");
}
}
// 页面加载时设置一次(仅一次)
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", setupPrintDate, { once: true });
} else {
setupPrintDate();
}