【Python】雇用保険の基本手当の計算

## 基本手当を計算するコードを書いてみた
### 雇用保険の基本手当日額の計算方法が変更される（令和5年8月1日より）
- 労災保険の基本手当、育児休業給付金、介護休業給付金の計算に使う
- 満15歳に達した日以後の最初の3月31日が終了するまでの児童以上で、且つ65歳未満であること
- 賃金日額 = 直近6ヶ月の給与総額(賞与除く) ÷ 180日
- 賃金日額の下限額: 2,746円
- 年齢や賃金日額のレンジ（範囲）よって計算方法が異なる
- 基本手当の下限額: 2,196円
- 端数処理については、1円未満を切り捨てる
- 厚生労働省の資料に基づく（[資料](https://www.mhlw.go.jp/content/001125522.pdf)）

::: note alert
算定式は定期的に変更されるので、下記のコードを使うときは最新の算定式に修正が必要
::: 

::: note info
__環境__
- MacOS : Sonoma 14.4.1
- python : 3.12.0
:::

::: note info
__ポイント__
- スクリプトを走らせると年齢と給与総額のインプットを求められる
- 後でモジュールとして使えるようにクラス化
- if_name__ = 'main' を使ってスクリプトファイルとして実行できるようにした
- お金の計算なので、Decimalモジュールを使用
- 独自の例外を設定、整数値入力チェック、年齢チェック、総額最低額のチェックを実行
- python的には難しいことは何もやってない😅
:::

### 実行結果

![実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699739/12fcfb82-34dd-9ad5-d2c3-6fefd5108735.png)

### コード
``` kihon_teate_calc_Aug23.py 
# -*- coding: utf-8 -*-

from decimal import *


class AgeTooYoungOrOld(Exception):
    pass

class ChinginNichigakuTooLow(Exception):
    pass

class KihonTeate:
    def __init__(self):
        self.total_salary = None
        self.age = None

    def age_check(self):
        """ 
        ・満15歳に達した日以後の最初の3月31日が終了するまでの児童以上であること
        ・65歳未満であること
        """
        if self.age < 15 or self.age >= 65:
            raise AgeTooYoungOrOld("年齢が適切ではありません")
        else:
            pass

    def amount_check(self):
        """
        ・賃金日額の下限額: 2_746円
        ・直近6ヶ月の給与総額(賞与除く)の下限額: 494_280円
        """
        if self.total_salary < (2_746 * 180):
            raise ChinginNichigakuTooLow("賃金日額の下限額を満たしていません")
        else:
            pass

    # 賃金日額
    def chingin_nichigaku(self):
        """ 賃金日額 = 直近6ヶ月の給与総額(賞与除く) ÷ 180日 """
        return Decimal(self.total_salary / 180).quantize(
            Decimal("0"), rounding=ROUND_DOWN
            )

    # 基本手当
    def kihon_teate(self, chingin_nichigaku):
        """
        ・労災保険の基本手当、育児休業給付金、介護休業給付金の計算に使用
        ・基本手当の下限額: 2_196円
        """
        if self.age < 15:
            raise AgeTooYoungOrOld("年齢が適切ではありません")
        elif self.age >= 15 and self.age < 30:
            if chingin_nichigaku >= 2_746 and chingin_nichigaku < 5_110:
                # 計算式：y = 0.8w
                result = Decimal(Decimal("0.8") * chingin_nichigaku).quantize(
                    Decimal("0"), rounding=ROUND_DOWN
                )
                return result
            elif chingin_nichigaku <= 12_580:
                # 計算式：y = 0.8w-0.3{(w-5110 )/(12580-5110)}w
                result = Decimal(
                    (Decimal("0.8") * chingin_nichigaku)
                    - (Decimal("0.3") * (chingin_nichigaku - 5110) / (12580 - 5110))
                    * chingin_nichigaku
                ).quantize(Decimal("0"), rounding=ROUND_DOWN)
                return result
            elif chingin_nichigaku <= 13_890:
                # 計算式：y = 0.5w
                result = Decimal(Decimal("0.5") * chingin_nichigaku).quantize(
                    Decimal("0"), rounding=ROUND_DOWN
                )
                return result
            elif chingin_nichigaku > 13_890:
                # 計算式：y = 6945
                result = 6945
                return result
        elif self.age >= 30 and self.age < 45:
            if chingin_nichigaku >= 2_746 and chingin_nichigaku < 5_110:
                # 計算式：y = 0.8w
                result = Decimal(Decimal("0.8") * chingin_nichigaku).quantize(
                    Decimal("0"), rounding=ROUND_DOWN
                )
                return result
            elif chingin_nichigaku <= 12_580:
                # 計算式：y = 0.8w-0.3{(w-5110 )/(12580-5110)}w
                result = Decimal(
                    (Decimal("0.8") * chingin_nichigaku)
                    - (Decimal("0.3") * (chingin_nichigaku - 5110) / (12580 - 5110))
                    * chingin_nichigaku
                ).quantize(Decimal("0"), rounding=ROUND_DOWN)
                return result
            elif chingin_nichigaku <= 15_430:
                # 計算式：y = 0.5w
                result = Decimal(Decimal("0.5") * chingin_nichigaku).quantize(
                    Decimal("0"), rounding=ROUND_DOWN
                )
                return result
            elif chingin_nichigaku > 15_430:
                # 計算式：y = 7715
                result = 7715
                return result
        elif self.age >= 45 and self.age < 60:
            if chingin_nichigaku >= 2_746 and chingin_nichigaku < 5_110:
                # 計算式：y = 0.8w
                result = Decimal(Decimal("0.8") * chingin_nichigaku).quantize(
                    Decimal("0"), rounding=ROUND_DOWN
                )
                return result
            elif chingin_nichigaku <= 12_580:
                # 計算式：y = 0.8w-0.3{(w-5110 )/(12580-5110)}w
                result = Decimal(
                    (Decimal("0.8") * chingin_nichigaku)
                    - (Decimal("0.3") * (chingin_nichigaku - 5110) / (12580 - 5110))
                    * chingin_nichigaku
                ).quantize(Decimal("0"), rounding=ROUND_DOWN)
                return result
            elif chingin_nichigaku <= 16_980:
                # 計算式：y = 0.5w
                result = Decimal(Decimal("0.5") * chingin_nichigaku).quantize(
                    Decimal("0"), rounding=ROUND_DOWN
                )
                return result
            elif chingin_nichigaku > 16_980:
                # 計算式：y = 8490
                result = 8490
                return result
        elif self.age >= 60 and self.age < 65:
            if chingin_nichigaku >= 2_746 and chingin_nichigaku < 5_110:
                # 計算式：y = 0.8w
                result = Decimal(Decimal("0.8") * chingin_nichigaku).quantize(
                    Decimal("0"), rounding=ROUND_DOWN
                )
                return result
            elif chingin_nichigaku <= 11_300:
                """
                計算式a: y = 0.8w-0.35{(w-5110)/(11300-5110)}w
                計算式b: y = 0.05w+(11300 x 0.4) 
                のいずれか低い方の額
                """
                a = Decimal(
                    (Decimal("0.8") * chingin_nichigaku)
                    - (Decimal("0.35") * (chingin_nichigaku - 5110) / (11300 - 5110))
                    * chingin_nichigaku
                ).quantize(Decimal("0"), rounding=ROUND_DOWN)

                b = Decimal(
                    Decimal("0.05") * chingin_nichigaku + (11300 * Decimal("0.4"))
                ).quantize(Decimal("0"), rounding=ROUND_DOWN)

                return min(a, b)
            elif chingin_nichigaku <= 16_210:
                # 計算式：y = 0.45w
                result = Decimal(Decimal("0.45") * chingin_nichigaku).quantize(
                    Decimal("0"), rounding=ROUND_DOWN
                )
                return result
            elif chingin_nichigaku > 16_210:
                # 計算式：y = 7294
                result = 7294
                return result
        else:
            raise AgeTooYoungOrOld("年齢が適切ではありません")

    # 基本手当シュミレーション結果
    def basic_allowance(self):
        try:
            # 変数値取得
            print("")
            age = int(input("■ 年齢を入力："))
            self.age = age
            self.age_check()

            total_salary = int(input("■ 直近6ヶ月の給与総額(賞与除く)を入力："))
            self.total_salary = total_salary
            self.amount_check()

            chingin_nichigaku = self.chingin_nichigaku()
            kihon_teate = self.kihon_teate(chingin_nichigaku)

            # 　結果表示
            print("")
            print(f"年齢 : {self.age}歳")
            print(f"直近6ヶ月の給与総額 : {self.total_salary:,}円")
            print(f"賃金日額 : {chingin_nichigaku:,.1f}円")
            print(f"基本手当 : {kihon_teate:,.1f}円")
            print("")

        # エラーハンドリング
        except ValueError:
            print(
                f"""
            【エラー】: 整数値で入力してください。
            """
            )

        except AgeTooYoungOrOld as e:
            print(
                f"""
            入力値(歳): {kt.age}
            【エラー】: {e}。
            """
            )

        except ChinginNichigakuTooLow as e:
            print(
                f"""
            入力値(円): {kt.total_salary:,}
            【エラー】: {e}。
            """
            )


if __name__ == "__main__":

    kt = KihonTeate()
    kt.basic_allowance()

```