ふるさと納税の試算シミュレーション

# はじめに
この時期、年末に向けて、ふるさと納税を検討される方は多いのではないでしょうか。
ふるさと納税のシミュレーションについて、D言語で実装しました。

# シミュレーションの実装方法
[総務省のふるさと納税ポータルサイト](https://www.soumu.go.jp/main_sosiki/jichi_zeisei/czaisei/czaisei_seido/furusato/mechanism/deduction.html)（以降、「ポータルサイト」と書きます）に、ふるさと納税を検討する際の目安表が掲載されています。この目安表をD言語で実装することを目標とします。
ただし、この目安表は「平成27年以降」版との記載があります。その後、税制の変更がありますので、最新の内容も取り入れたいと思います。

目安表を作成するために、ポータルサイトに「控除額の計算」方法が書かれています。
**③住民税からの控除（特例分）**の上限が2割なので、その場合のふるさと納税金額を計算すればよさそうです。

>① 所得税からの控除 = （ふるさと納税額－2,000円）×「所得税の税率」
所得税からの控除額は、上記①の計算式で決まります。<br>なお、控除の対象となるふるさと納税額は、総所得金額等の40％が上限です。
※    平成49年中の寄附までは、所得税の税率は復興特別所得税の税率を加えた率となります。
※    所得税の税率は、課税所得の増加に応じて高くなるように設定されており、その納税者に適用される税率を用います。
    所得税の税率について（国税庁）別ウィンドウで開きます
住民税からの控除には「基本分」と「特例分」があり、それぞれ以下のように決まります。

>② 住民税からの控除（基本分） = （ふるさと納税額－2,000円）×10％
住民税からの控除の基本分は、上記②の計算式で決まります。
なお、控除の対象となるふるさと納税額は、総所得金額等の30％が上限です。

>③住民税からの控除（特例分） = （ふるさと納税額 - 2,000円）×（100％ - 10％（基本分） - 所得税の税率）
住民税からの控除の特例分は、この特例分が住民税所得割額の2割を超えない場合は、上記③の計算式で決まります。 上記③における所得税の税率は、個人住民税の課税所得金額から人的控除差調整額を差し引いた金額により求めた所得税の税率であり、上記①の所得税の税率と異なる場合があります。

>③'住民税からの控除（特例分） = （住民税所得割額）×20％
特例分（③で計算した場合の特例分）が住民税所得割額の2割を超える場合は、上記③'の計算式となります。 この場合、①、②及び③'の3つの控除を合計しても（ふるさと納税額－2,000円）の全額が控除されず、実質負担額は2,000円を超えます。

# ソースコード

```d:furusato.d
import std.algorithm;
import std.stdio;

void main()
{
// 「夫婦」は配偶者控除ありのケース
// 「共働き」は配偶者控除なしのケース
	writeln("|給与収入|独身又は<br>共働き|夫婦|共働き<br>高校生|共働き<br>大学生|夫婦<br>高校生|共働き<br>大＋高|夫婦<br>大＋高|");
	writeln("|:--|:--|:--|:--|:--|:--|:--|:--|");
	for ( long salary =  3_000_000; salary <  10_000_000; salary +=   250_000 ){
		writeLine(salary);
	}
	for ( long salary = 10_000_000; salary <= 25_000_000; salary += 1_000_000 ){
		writeLine(salary);
	}
}

void writeLine(long salary)
{
	writef("|%10,3d|", salary);				// 給与収入
	writef("%8,3d|", getLimit(salary, false, 0, 0));
	writef("%8,3d|", getLimit(salary, true , 0, 0));
	writef("%8,3d|", getLimit(salary, false, 1, 0));
	writef("%8,3d|", getLimit(salary, false, 0, 1));
	writef("%8,3d|", getLimit(salary, true , 1, 0));
	writef("%8,3d|", getLimit(salary, false, 1, 1));
	writef("%8,3d|", getLimit(salary, true , 1, 1));
	writeln();
}

long getLimit(long salary, bool haig, int fuyo, int fuyot)
{
// salary 給与収入
// haig   配偶者控除対象か
// fuyo   扶養人数
// fuyot  特定扶養人数
	long income = getSalaryIncome(salary);	// 給与所得
	if ( salary > 8_500_000 && (fuyo > 0 || fuyot > 0) ){
		// 所得金額調整控除
		income -= (min(salary, 10_000_000) - 8_500_000) / 10;
	}
	long insuranceFee;						// 社会保険料
	if ( salary > 18_000_000 ){
		insuranceFee = 1_620_000;
	} else if ( salary > 9_000_000 ){
		insuranceFee = salary *  3 / 100 + 1_080_000;
	} else {
		insuranceFee = salary * 15 / 100;	// 社会保険料を給与収入の15%と仮定
	}
	
	long deduction = getIncomeTaxPersonalDeduction(income, haig, fuyo, fuyot);
	long rate = getTaxRate(max(income - insuranceFee - deduction, 0));	// 所得税率
	
	deduction = getResidentTaxPersonalDeduction(income, haig, fuyo, fuyot);
	income = max(income - insuranceFee - deduction, 0);		// 総合課税所得
	income = income / 1_000 * 1_000;		// 千円未満の端数切捨て
	
	long municipal = getMunicipalTax(income, 0);			// 住民税所得割額
	municipal -= getAdjustment(income, haig, fuyo, fuyot);	// 調整控除
	long furusato  = getFurusatoTax(municipal, rate);		// ふるさと納税額
	
	return ( furusato );
}

long getSalaryIncome(long salary)
{// 給与収入から給与所得を返す
	long[] boundary = [ 1_625_000, 1_800_000, 3_600_000, 6_600_000, 8_500_000];
	long[] rate     = [ 0, 4, 3, 2, 1, 0];
	long[] adjust   = [ 550_000, -100_000, 80_000, 440_000, 1_100_000, 1_950_000];
	auto index = count!("a < b")(boundary, salary);
	long deduction = salary * rate[index] / 10 + adjust[index];
	return ( max(salary - deduction, 0) );
}

long getTaxRate(long income)
{// 所得税率を返す
	long[] boundary  = [ 1_950_000, 3_300_000, 6_950_000, 9_000_000, 18_000_000, 40_000_000];
	long[] taxrate   = [ 5, 10, 20, 23, 33, 40, 45];
	auto index = count!("a < b")(boundary, income);
	return ( taxrate[index] );
}

long getIncomeTaxPersonalDeduction(long income, bool haig, int fuyo, int fuyot)
{// 所得税の人的控除額を返す
	long deduction = 480_000;
	if ( haig ){
		if ( income > 10_000_000 ){
		} else if ( income > 9_500_000 ){
			deduction += 130_000;
		} else if ( income > 9_000_000 ){
			deduction += 260_000;
		} else {
			deduction += 380_000;
		}
	}
	deduction += fuyo  * 380_000;
	deduction += fuyot * 630_000;
	return ( deduction );
}

long getResidentTaxPersonalDeduction(long income, bool haig, int fuyo, int fuyot)
{// 住民税の人的控除額を返す
	long deduction = 430_000;
	if ( haig ){
		if ( income > 10_000_000 ){
		} else if ( income > 9_500_000 ){
			deduction += 110_000;
		} else if ( income > 9_000_000 ){
			deduction += 220_000;
		} else {
			deduction += 330_000;
		}
	}
	deduction += fuyo  * 330_000;
	deduction += fuyot * 450_000;
	return ( deduction );
}

long getMunicipalTax(long income, long capital)
{// 住民税所得割額を返す
	return ( max(income / 10 + capital / 20, 0) );
}

long getAdjustment(long income, bool haig, int fuyo, int fuyot)
{// 調整控除額を返す
	long deduction = 50_000;
	if ( haig ){
		if ( income > 10_000_000 ){
		} else if ( income > 9_500_000 ){
			deduction += 20_000;
		} else if ( income > 9_000_000 ){
			deduction += 40_000;
		} else {
			deduction += 50_000;
		}
	}
	deduction += fuyo  * 50_000;
	deduction += fuyot * 180_000;
	if ( income < 2_000_000){
		deduction = min(income, deduction);
	} else {
		deduction -= income - 2_000_000;
		deduction = max(deduction, 50_000);
	}
	return ( deduction * 5 / 100 );
}

long getFurusatoTax(long municipal, long rate)
{// ふるさと納税額を返す
	long furusato  = cast(long)((max(municipal, 0) / 5) / ((100 - 10 - rate * 1.021) / 100));
	furusato = furusato / 1_000 * 1_000;	// 千円未満の端数切捨て
	furusato += 2_000;
	return ( furusato );
}
```

`main`関数は、目安表を表示するためのループ処理を行っています。
「夫婦」は配偶者控除あり、「共働き」は配偶者控除なしのケースを想定しています。
「高校生」は一般扶養親族、「大学生」は特定扶養親族の扶養控除のケースを想定しています。

`getLimit`関数は、パラメータの条件にあわせた「ふるさと納税金額」を返します。
大まかな処理の流れとしては、以下の通りです。

* 給与収入から給与所得を[算出](https://www.nta.go.jp/m/taxanswer/1410.htm)します。
* 所得税と住民税で控除額が[異なる](https://www.city.abashiri.hokkaido.jp/220zeikin/010shidoumin/040keisannrei/001_keisanrei_salaryman.html)ため、それぞれ算出しています。
* 所得税の税率を[算出](https://www.nta.go.jp/taxes/shiraberu/taxanswer/shotoku/2260.htm)します。
* 給与所得から住民税の控除額を引いて課税所得を算出します。
* 課税所得から住民税所得割額を[算出](https://www.city.osaka.lg.jp/zaisei/page/0000383147.html)します。
* 調整控除額を[算出](https://www.city.osaka.lg.jp/zaisei/page/0000370599.html)します。
* 調整控除された住民税所得割額と所得税率から、ふるさと納税金額を算出します。

`getSalaryIncome`関数は、給与収入から給与所得を算出します。

`getTaxRate`関数は、所得税の課税所得から所得税の税率を算出します。

`getMunicipalTax`関数は、住民税の課税所得と分離課税所得から住民税所得割額を算出します。
今回作成する目安表では分離課税所得が0円のケースですが、分離課税所得がある場合も計算できます。

`getAdjustment`関数は、調整控除額を算出します。

`getFurusatoTax`関数は、調整控除された住民税所得割額と所得税率から、ふるさと納税金額を算出します。

# コンパイル
```text:コマンドプロンプト
D:\Dev> dmd --version
DMD64 D Compiler v2.099.0-dirty
Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved written by Walter Bright

D:\Dev> dmd -m64 furusato.d
```

# 実行例

* ソースコードには、2021年確定申告（2020年分から適用）の変更点を取り込んでいます。
  * [給与所得控除10万円引き下げ](https://www.nta.go.jp/users/gensen/nencho/index/01.htm#a001)
  * [基礎控除10万円引き上げ](https://www.nta.go.jp/users/gensen/nencho/index/01.htm#a002)
  * [所得金額調整控除](https://www.nta.go.jp/m/taxanswer/1411.htm)
* 社会保険料の仮定金額は、ポータルサイトにある[寄附金控除額の計算シミュレーション](https://www.soumu.go.jp/main_content/000408218.xlsx)にあわせています。

```text:コマンドプロンプト
D:\Dev> chcp 65001
Active code page: 65001

D:\Dev> furusato
```
プログラムの出力結果は、以下の通りのMarkdown形式となります。

|給与収入|独身又は<br>共働き|夫婦|共働き<br>高校生|共働き<br>大学生|夫婦<br>高校生|共働き<br>大＋高|夫婦<br>大＋高|
|:--|:--|:--|:--|:--|:--|:--|:--|
| 3,000,000|  28,000|  19,000|  19,000|  15,000|  11,000|   7,000|   2,000|
| 3,250,000|  31,000|  23,000|  23,000|  18,000|  14,000|  10,000|   3,000|
| 3,500,000|  34,000|  26,000|  26,000|  22,000|  18,000|  13,000|   5,000|
| 3,750,000|  38,000|  29,000|  29,000|  25,000|  21,000|  17,000|   8,000|
| 4,000,000|  42,000|  33,000|  33,000|  29,000|  25,000|  21,000|  12,000|
| 4,250,000|  45,000|  37,000|  37,000|  33,000|  29,000|  24,000|  16,000|
| 4,500,000|  52,000|  41,000|  41,000|  37,000|  33,000|  28,000|  20,000|
| 4,750,000|  56,000|  45,000|  45,000|  40,000|  36,000|  32,000|  24,000|
| 5,000,000|  61,000|  49,000|  49,000|  44,000|  40,000|  36,000|  28,000|
| 5,250,000|  65,000|  56,000|  56,000|  49,000|  44,000|  40,000|  31,000|
| 5,500,000|  69,000|  60,000|  60,000|  57,000|  48,000|  44,000|  35,000|
| 5,750,000|  73,000|  64,000|  64,000|  61,000|  56,000|  48,000|  39,000|
| 6,000,000|  77,000|  69,000|  69,000|  66,000|  60,000|  57,000|  43,000|
| 6,250,000|  81,000|  73,000|  73,000|  70,000|  64,000|  61,000|  48,000|
| 6,500,000|  97,000|  77,000|  77,000|  74,000|  68,000|  65,000|  53,000|
| 6,750,000| 102,000|  81,000|  81,000|  78,000|  73,000|  70,000|  62,000|
| 7,000,000| 108,000|  86,000|  86,000|  83,000|  78,000|  75,000|  66,000|
| 7,250,000| 113,000| 104,000| 104,000|  88,000|  82,000|  79,000|  71,000|
| 7,500,000| 118,000| 109,000| 109,000| 106,000|  87,000|  84,000|  76,000|
| 7,750,000| 124,000| 114,000| 114,000| 111,000| 105,000|  89,000|  80,000|
| 8,000,000| 129,000| 120,000| 120,000| 116,000| 110,000| 107,000|  85,000|
| 8,250,000| 135,000| 125,000| 125,000| 122,000| 116,000| 112,000|  90,000|
| 8,500,000| 140,000| 131,000| 131,000| 127,000| 121,000| 118,000| 108,000|
| 8,750,000| 146,000| 137,000| 136,000| 132,000| 126,000| 123,000| 114,000|
| 9,000,000| 152,000| 143,000| 141,000| 138,000| 132,000| 128,000| 119,000|
| 9,250,000| 159,000| 150,000| 148,000| 144,000| 138,000| 135,000| 125,000|
| 9,500,000| 166,000| 157,000| 154,000| 150,000| 144,000| 141,000| 131,000|
| 9,750,000| 173,000| 164,000| 160,000| 157,000| 151,000| 147,000| 138,000|
|10,000,000| 180,000| 171,000| 166,000| 163,000| 157,000| 153,000| 144,000|
|11,000,000| 218,000| 202,000| 194,000| 191,000| 185,000| 181,000| 172,000|
|12,000,000| 247,000| 247,000| 232,000| 229,000| 229,000| 219,000| 206,000|
|13,000,000| 326,000| 326,000| 261,000| 258,000| 261,000| 248,000| 248,000|
|14,000,000| 360,000| 360,000| 343,000| 339,000| 343,000| 277,000| 277,000|
|15,000,000| 395,000| 395,000| 377,000| 373,000| 377,000| 361,000| 361,000|
|16,000,000| 429,000| 429,000| 412,000| 408,000| 412,000| 396,000| 396,000|
|17,000,000| 463,000| 463,000| 446,000| 442,000| 446,000| 430,000| 430,000|
|18,000,000| 498,000| 498,000| 481,000| 477,000| 481,000| 465,000| 465,000|
|19,000,000| 533,000| 533,000| 516,000| 512,000| 516,000| 500,000| 500,000|
|20,000,000| 569,000| 569,000| 552,000| 548,000| 552,000| 536,000| 536,000|
|21,000,000| 604,000| 604,000| 587,000| 583,000| 587,000| 571,000| 571,000|
|22,000,000| 640,000| 640,000| 623,000| 619,000| 623,000| 607,000| 607,000|
|23,000,000| 773,000| 773,000| 754,000| 749,000| 754,000| 642,000| 642,000|
|24,000,000| 814,000| 814,000| 795,000| 790,000| 795,000| 776,000| 776,000|
|25,000,000| 855,000| 855,000| 835,000| 830,000| 835,000| 817,000| 817,000|

# 参考情報
[総務省のふるさと納税ポータルサイト](https://www.soumu.go.jp/main_sosiki/jichi_zeisei/czaisei/czaisei_seido/furusato/mechanism/deduction.html)
[住民税額シミュレーション(川崎市)](https://zeisim.e-civion.net/tax-project/KawasakiMenuAction)
[住民税の計算例(網走市)](https://www.city.abashiri.hokkaido.jp/220zeikin/010shidoumin/040keisannrei/001_keisanrei_salaryman.html)

# 更新履歴
* 2020.11.21 初回投稿
* 2023.10.28 ソースコード修正