Skip to content

控除計算層

控除計算層は、CategoryJudgment 層が生成した CategoryJudgmentResult(→ DM-409)を入力として受け取り、各控除の適用可否・控除額を算出する。控除ごとの計算過程は DeductionDetail(→ DM-502)として記録する。

→ 控除の分類と詳細: 控除 → 控除種類マスタ: DM-803 DeductionTypeMaster

控除の分類と計算ロジック概要

人的控除(Exemption)9種:

#控除名計算ロジック概要入力
1基礎控除本人の合計所得金額に応じた段階テーブル(R7: 本則58万円+加算額、9区分)本人の合計所得金額
2配偶者控除本人の合計所得金額×配偶者年齢区分の2軸テーブル(3段階×2区分)IsKoujoTaishoHaigusha, 本人の合計所得金額, 配偶者年齢
3配偶者特別控除配偶者の合計所得金額×本人の合計所得金額の2軸段階逓減テーブル(9段階×3段階)IsHaigushaTokubetsuKoujoTaisho, 配偶者の合計所得金額, 本人の合計所得金額
4扶養控除年齢区分(一般38万円/特定63万円/老人48万円/同居老親等58万円)IsKoujoTaishoFuyoShinzoku, 年齢区分フラグ群
5特定親族特別控除特定親族の合計所得金額に応じた段階逓減テーブル(9段階)IsTokuteiShinzoku, 特定親族の合計所得金額
6障害者控除区分別定額(一般27万円/特別40万円/同居特別75万円)DisabilityGrade
7寡婦控除 / ひとり親控除要件判定後に定額(寡婦27万円/ひとり親35万円)本人属性(婚姻歴、子の有無、合計所得金額)
8勤労学生控除要件判定後に定額(27万円)本人属性(学生、合計所得金額、勤労所得割合)

物的控除(Deduction)4種:

#控除名計算ロジック概要入力
9社会保険料控除支払額全額(給与天引分 + 本人申告分)InsuranceDeduction
10小規模企業共済等掛金控除支払額全額InsuranceDeduction
11生命保険料控除3区分(一般/介護医療/個人年金)×新旧制度の計算式→合算上限12万円InsuranceDeduction
12地震保険料控除地震保険+旧長期損害保険の計算式→合算上限5万円InsuranceDeduction

調整2種:

#控除名計算ロジック概要パイプラインステップ
13所得金額調整控除給与収入850万円超の場合、(min(収入,1000万円)−850万円)×10%③(所得控除ではなく給与所得の調整)
14住宅借入金等特別控除税額控除(所得控除ではない)

CategoryJudgmentResult → DeductionDetail への変換

csharp
// カテゴリ判定結果を一度だけ計算し、複数の控除計算関数で共有
var categories = judge.EvaluateAll(taxpayer, familyMembers);

// 各控除計算関数はカテゴリの bool フラグのみを参照(生の所得額・閾値を直接参照しない)
var deductions = new List<DeductionDetail>
{
    BasicDeductionCalculator.Calculate(taxpayer.TotalIncome, parameters),
    SpouseDeductionCalculator.Calculate(categories, taxpayer.TotalIncome, parameters),
    DependentDeductionCalculator.Calculate(categories, parameters),
    DisabilityDeductionCalculator.Calculate(categories),
    SpecifiedRelativeDeductionCalculator.Calculate(categories, parameters),
    // ... 物的控除
    SocialInsuranceCalculator.Calculate(insuranceData),
    LifeInsuranceCalculator.Calculate(insuranceData, categories, parameters),
    EarthquakeInsuranceCalculator.Calculate(insuranceData, parameters),
};

DeductionDetail(→ DM-502)には、控除種類(→ DM-803 DeductionTypeMaster)、適用/非適用の判定結果、適用理由(どの税法カテゴリに基づくか)、計算式の各項、算出された控除額、端数処理の適用有無を記録する。


変更影響表示(CalculationDiff)

入力内容の変更により再計算が行われた際、「何がどう変わったか」を利用者に伝えるための差分データを生成する。再計算前後の TaxCalculationResult インスタンスを比較する純粋関数として Tax Calculation Core 内に実装する。

→ データモデル: DM-410 CalculationDiff

設計方針

  • インスタンス比較による差分生成: 依存グラフの追跡やイベント発行ではなく、イミュータブルレコード同士の構造比較で差分を検出する。純粋関数+イミュータブルレコードの設計により、再計算の前後で2つのインスタンスが自然に手元にある
  • 3層の段階的開示: ユーザーの関心度に応じて情報量を制御する。全員が見るべき最終結果(Layer 1)から、専門家向けの判定変化(Layer 3)まで段階的に開示
  • DB 非永続化: CalculationDiff は API レスポンスとして都度生成し、DB には保存しない。元となる TaxCalculationResult が保存されていれば、いつでも再生成可能

データ構造

csharp
// Tax Calculation Core 内の純粋関数
public static class CalculationDiffGenerator
{
    public static CalculationDiff Generate(
        TaxCalculationResult before,
        TaxCalculationResult after);
}

// Layer 1: パイプライン最終結果の変動
public record CalculationDiff
{
    public decimal PreviousYeaAnnualTax { get; init; }
    public decimal CurrentYeaAnnualTax { get; init; }
    public decimal TaxDifference { get; init; }           // + = 増税, − = 減税

    public decimal PreviousOverUnderPayment { get; init; }
    public decimal CurrentOverUnderPayment { get; init; }

    // Layer 2: 控除の変動
    public IReadOnlyList<DeductionChange> DeductionChanges { get; init; }

    // Layer 3: カテゴリ判定の変動
    public IReadOnlyList<CategoryChange> CategoryChanges { get; init; }

    public bool HasChanges => TaxDifference != 0;
}

// Layer 2: 控除の変動
public record DeductionChange
{
    public string DeductionTypeCode { get; init; }        // DM-803 の控除種類コード
    public decimal PreviousAmount { get; init; }
    public decimal CurrentAmount { get; init; }
    public decimal Difference { get; init; }
    public DeductionChangeKind Kind { get; init; }
}

public enum DeductionChangeKind
{
    Appeared,       // 非適用 → 適用
    AmountChanged,  // 適用のまま金額変動
    Disappeared     // 適用 → 非適用
}

// Layer 3: カテゴリ判定の変動
public record CategoryChange
{
    public Guid FamilyMemberId { get; init; }
    public string CategoryName { get; init; }             // "控除対象配偶者" 等
    public bool PreviousValue { get; init; }
    public bool CurrentValue { get; init; }               // true→false = 該当→非該当
}

比較タイミングと before/after の対応

状態beforeafter用途
Draft 中の編集直前スナップショットの仮計算結果編集後の再計算結果リアルタイムプレビュー
Draft → Submitted最新 Draft の仮計算結果Submitted 時の確定計算結果提出前の最終確認
Returned → 再 DraftReturned 時点の計算結果修正後の再計算結果差し戻し修正の影響確認
再年調Finalized (v1) の TaxCalculationResult再計算 (v2) の TaxCalculationResult訂正による影響額の確認

ポータル別のデフォルト表示レベル

ポータルデフォルト表示展開可能
従業員Layer 1(過不足額の変動)Layer 2(控除の変動サマリ)
企業管理者Layer 1 + Layer 2Layer 3(カテゴリ判定変化)
代行事業者Layer 1 + Layer 2 + Layer 3全展開

既存機能との関係

既存機能比較軸CalculationDiff との関係
前年差分ハイライト年度間の**属性(事実)**の差分別の仕組み。属性 vs 計算結果で対象が異なる
控除対象外理由現時点の判定理由(単一スナップショット)Layer 3 が動的な before/after 版として補完
計算結果表示現時点の計算結果(単一スナップショット)Layer 1-2 が変動情報を追加
計算プロセス可視化現時点のパイプライン(単一スナップショット)パイプライン各ステップの before/after に拡張