Skip to content

Tax Calculation Core(税計算コア)

税額計算ロジックは、Webフレームワークから完全に分離した 純粋なクラスライブラリ として実装する。ASP.NET Core、EF Core、データベースへの一切の依存を持たず、単体でテスト可能なプロジェクトとして構成する。なお、税計算ロジックはTASHIKAの競争優位性の源泉であり、NuGetパッケージ等での外部配布は行わない。

設計原則

原則説明
Calculation Core as LibraryWeb API や DB に一切依存せず、単体でテスト可能。外部配布は行わない
純粋関数 (Pure Functions)状態変異を排除し、同一入力に対して常に同一結果を保証
イミュータブル (Immutability)入出力のデータ構造はすべて不変(record / readonly
年度別バージョニング税制改正に対応するため、年度ごとに計算ロジックをバージョン管理
Fact/Judgment 分離事実データ(属性)と控除判定結果を分離し、判定は常に計算で導出する

→ 満たす要件: CR-005 データの不変性と再現性

計算処理の実行方針: バックエンド集約

税計算・控除判定のロジックは バックエンド(Tax Calculation Core)にのみ実装し、フロントエンドでは一切行わない

観点バックエンド集約(採用)フロント+バック二重実装
Single Source of TruthC# の1実装のみ。国税庁計算例との照合もここで保証C# と TypeScript の2実装を常に同期する必要がある
税制改正の対応コスト1箇所の修正で完了2言語で改正を同時反映。端数処理(切捨て/切上げ混在)の乖離リスクが高い
ロジックの秘匿性サーバー内に閉じるJS バンドルに閾値・判定条件が含まれる
検証の信頼性サーバーが唯一の権威フロント計算は参考値にしかならず、二重実装のコストに見合わない

パフォーマンス: 純粋関数パイプラインの全体再計算は <1ms であり、API ラウンドトリップを含めてもユーザー体感上の問題にならない。Draft 中のリアルタイムプレビューは入力の debounce(300-500ms)+ TanStack Query のキャッシュで十分な応答性を確保できる。

フロントエンドの役割: 表示フォーマット(通貨書式、端数表示)と入力の即時フィードバック(形式バリデーション)に限定する。

ライブラリ構成

Tax Calculation Core は以下の3層で構成する。各層は名前空間で分離し、依存方向を厳密に制御する。

Tashika.TaxCalculation/
├── CategoryJudgment/    -- 第1層: 税法カテゴリ判定(事実 → カテゴリ該当有無)
├── DeductionCalculation/ -- 第2層: 控除計算(カテゴリ → 控除額)
├── Pipeline/             -- 第3層: 年税額計算パイプライン(11ステップ)
├── Parameters/           -- 年度パラメータ(TaxYearMaster 由来の値オブジェクト群)
├── Models/               -- 入出力モデル(イミュータブル record)
└── SpeedTables/          -- 速算表(給与所得控除、所得税率)

11ステップ年税額計算パイプライン

年末調整の年税額(年調年税額)算出は、11ステップの段階的パイプラインとして実装する。各ステップは純粋関数であり、前ステップの出力を入力として受け取る。

→ 出典: 国税庁 年末調整のしかた(令和7年分)p37-39 → ドメイン知識の詳細: 年税額計算 → Golden Test データ: ゴールデンテスト

"① 給与等の収入金額(総額)PayrollImport[② 給与所得控除後の給与等の金額速算表適用 / 1円未満切捨て③ 所得金額調整控除額850万超+要件該当 / 1円未満切上げ④ 調整控除後の給与所得金額② − ③⑤ 所得控除の合計額人的控除9種 + 物的控除4種⑥ 課税給与所得金額max(④ − ⑤, 0) / 1,000円未満切捨て⑦ 算出所得税額速算表: ⑥ × 税率 − 控除額⑧ 住宅借入金等特別控除額税額控除 / 100円未満切捨て⑨ 年調所得税額max(⑦ − ⑧, 0)⑩ 年調年税額⑨ × 102.1% / 100円未満切捨て⑪ 過不足額⑩ − 源泉徴収済み税額CategoryJudgmentResult
"① 給与等の収入金額(総額)PayrollImport[② 給与所得控除後の給与等の金額速算表適用 / 1円未満切捨て③ 所得金額調整控除額850万超+要件該当 / 1円未満切上げ④ 調整控除後の給与所得金額② − ③⑤ 所得控除の合計額人的控除9種 + 物的控除4種⑥ 課税給与所得金額max(④ − ⑤, 0) / 1,000円未満切捨て⑦ 算出所得税額速算表: ⑥ × 税率 − 控除額⑧ 住宅借入金等特別控除額税額控除 / 100円未満切捨て⑨ 年調所得税額max(⑦ − ⑧, 0)⑩ 年調年税額⑨ × 102.1% / 100円未満切捨て⑪ 過不足額⑩ − 源泉徴収済み税額CategoryJudgmentResult

各ステップの詳細

#ステップ名入力出力計算ロジック端数処理
給与等の収入金額(総額)PayrollImport[]decimal GrossSalary1月〜12月の給与・賞与の合計なし
給与所得控除後の給与等の金額GrossSalarydecimal SalaryIncomeAfterDeduction給与所得控除速算表を適用(→ DM-802 TaxYearMaster)660万円以上の算式計算時: 1円未満 切捨て
所得金額調整控除額GrossSalary, CategoryJudgmentResultdecimal IncomeAdjustmentDeduction収入850万円超 かつ 所定の要件に該当する場合: (min(GrossSalary, 1000万円) − 850万円) × 10%1円未満 切上げ
調整控除後の給与所得金額, decimal AdjustedSalaryIncome② − ③(③の適用がない場合は②がそのまま④)なし
所得控除の合計額DeductionDetail[]decimal TotalIncomeDeductions人的控除9種 + 物的控除4種 の合計(→ 控除計算層生命保険料: 1円未満切上げ、地震保険料: 1円未満切上げ
課税給与所得金額, decimal TaxableIncomemax(④ − ⑤, 0)1,000円未満切捨て1,000円未満 切捨て
算出所得税額decimal AssessedTax所得税速算表: ⑥ × 税率 − 控除額(→ DM-802 TaxYearMaster)なし(速算表適用前に⑥が1,000円単位に丸め済み)
住宅借入金等特別控除額HousingLoanDeductiondecimal HousingLoanCredit住宅借入金等特別控除申告書の提出がある場合に適用(税額控除100円未満 切捨て
年調所得税額, decimal YeaIncomeTaxmax(⑦ − ⑧, 0)マイナスにならない0に切捨て(フロア)
年調年税額decimal YeaAnnualTax⑨ × 102.1%(復興特別所得税)、100円未満切捨て100円未満 切捨て
過不足額, decimal WithheldTotaldecimal OverUnderPayment⑩ − 源泉徴収済み税額の合計。プラス→不足額(追加徴収)、マイナス→過納額(還付)なし

パイプライン関数のシグネチャ(C#)

csharp
// 各ステップは純粋関数として実装。年度パラメータは TaxYearParameters に集約。
public static class TaxCalculationPipeline
{
    // ② 給与所得控除後の金額(速算表適用)
    public static decimal CalculateSalaryIncomeAfterDeductionAsync(
        decimal grossSalary,
        SalaryDeductionTable deductionTable);

    // ③ 所得金額調整控除額
    public static decimal CalculateIncomeAdjustmentDeduction(
        decimal grossSalary,
        CategoryJudgmentResult categories,
        IncomeAdjustmentParameters parameters);

    // ⑥ 課税給与所得金額(1,000円未満切捨て、≥0)
    public static decimal CalculateTaxableIncome(
        decimal adjustedSalaryIncome,
        decimal totalIncomeDeductions);

    // ⑦ 算出所得税額(速算表適用)
    public static decimal CalculateAssessedTax(
        decimal taxableIncome,
        TaxRateTable taxRateTable);

    // ⑨ 年調所得税額(≥0)
    public static decimal CalculateYeaIncomeTax(
        decimal assessedTax,
        decimal housingLoanCredit);

    // ⑩ 年調年税額(×102.1%、100円未満切捨て)
    public static decimal CalculateYeaAnnualTax(
        decimal yeaIncomeTax,
        decimal reconstructionTaxRate);

    // ⑪ 過不足額
    public static decimal CalculateOverUnderPayment(
        decimal yeaAnnualTax,
        decimal withheldTotal);

    // パイプライン全体を実行し TaxCalculationResult を生成
    public static TaxCalculationResult ExecutePipeline(
        TaxCalculationInput input,
        TaxYearParameters parameters);
}

算出所得税額の速算表(令和7年分)

速算表は年度パラメータ(→ DM-802 TaxYearMaster)として管理する。

課税給与所得金額 (A)税率 (B)控除額 (C)税額 = (A)×(B) − (C)
1,950,000円以下5%0円(A) × 5%
1,950,000円超〜3,300,000円以下10%97,500円(A) × 10% − 97,500
3,300,000円超〜6,950,000円以下20%427,500円(A) × 20% − 427,500
6,950,000円超〜9,000,000円以下23%636,000円(A) × 23% − 636,000
9,000,000円超〜18,000,000円以下33%1,536,000円(A) × 33% − 1,536,000
18,000,000円超〜18,050,000円以下40%2,796,000円(A) × 40% − 2,796,000

注意: 課税給与所得金額が18,050,000円を超える場合は年末調整の対象外。速算表の「控除額」は累進課税のギャップ調整値であり、所得控除とは無関係。

端数処理のまとめ

年末調整の計算過程では 切捨てと切上げが混在 するが、いずれも 納税者有利の方向 に丸められる設計意図がある。

#対象端数処理パイプラインステップ
1給与所得控除後の金額(算式計算、660万円以上)1円未満切捨て
2所得金額調整控除額1円未満切上げ
3生命保険料控除額1円未満切上げ
4地震保険料控除額1円未満切上げ
5住宅借入金等特別控除額100円未満切捨て
6課税給与所得金額1,000円未満切捨て
7年調所得税額(控除しきれない部分)0にフロア
8年調年税額(×102.1%)100円未満切捨て

パターン: 控除額の計算は切上げ(納税者に有利)、課税所得・税額の計算は切捨て(同じく納税者に有利)。