diff --git a/backend/app/payroll/bonus/service.py b/backend/app/payroll/bonus/service.py index c2330c2..93eaa0a 100644 --- a/backend/app/payroll/bonus/service.py +++ b/backend/app/payroll/bonus/service.py @@ -1,11 +1,26 @@ """ 賞与計算サービス (Bonus Calculation Service) """ -from decimal import Decimal +import json +import os +import functools +from decimal import Decimal, ROUND_HALF_UP from datetime import date from typing import Dict, Any from ...core.database import get_connection +_BONUS_TAX_RATES_PATH = os.path.join( + os.path.dirname(os.path.dirname(__file__)), + 'config', 'bonus_tax_rates.json' +) + + +@functools.lru_cache(maxsize=1) +def _load_bonus_tax_rates(): + """賞与算出率表をJSONファイルから読み込む(キャッシュ付き)""" + with open(_BONUS_TAX_RATES_PATH, encoding='utf-8') as f: + return json.load(f) + class BonusCalculationService: """賞与計算サービス""" @@ -15,8 +30,10 @@ class BonusCalculationService: """保険料率を取得(賞与用、年度がない場合は前年度を参照)""" with get_connection() as conn: with conn.cursor() as cur: - # rate_yearで年度を判定 - target_year = target_date.year + # 翌月払いのため、新年度料率は5月支払分(4月分)から適用 + # rate_year=XXXX は XXXX年5月支払〜(XXXX+1)年4月支払に適用 + # 1〜4月支払は前年度(year-1)の料率を使用 + target_year = target_date.year if target_date.month >= 5 else target_date.year - 1 cur.execute( """ SELECT * FROM insurance_rates @@ -75,12 +92,12 @@ class BonusCalculationService: """前月までの3ヶ月平均給与を取得(賞与所得税計算用)""" with get_connection() as conn: with conn.cursor() as cur: - # 前月までの3ヶ月の総支給額を取得 + # 前月までの3ヶ月の社会保険料等控除後の給与を取得 cur.execute( """ - SELECT AVG(total_payment - commute_allowance) as avg_salary + SELECT AVG(total_payment - commute_allowance - health_insurance - care_insurance - pension_insurance - employment_insurance - COALESCE(child_support, 0)) as avg_salary FROM ( - SELECT total_payment, commute_allowance + SELECT total_payment, commute_allowance, health_insurance, care_insurance, pension_insurance, employment_insurance, child_support FROM monthly_payroll WHERE employee_id = %s AND payment_date < %s @@ -102,24 +119,34 @@ class BonusCalculationService: ) -> Decimal: """ 賞与所得税を計算 - 賞与税率 = (前月給与額 - 社会保険料) × 扶養人数に応じた税率 + 国税庁「賞与に対する源泉徴収税額の算出率の表」甲欄を使用 + bonus_amount: 社会保険料等控除後の賞与額 + previous_salary_avg: 前月の社会保険料等控除後の給与額 """ - # 簡易計算: 賞与額から社会保険料概算を引いた額の10.21%を所得税とする - # 実際は前月給与から税率を求める複雑な計算が必要 if previous_salary_avg == Decimal("0"): - # 前月給与がない場合は賞与額の10.21% - return (bonus_amount * Decimal("0.1021")).quantize(Decimal("1")) - - # 扶養人数による税率軽減(簡略化) - rate = Decimal("0.1021") # 基本税率 10.21% - if dependents_count == 1: - rate = Decimal("0.0820") # 8.20% - elif dependents_count == 2: - rate = Decimal("0.0619") # 6.19% - elif dependents_count >= 3: - rate = Decimal("0.0418") # 4.18% - - return (bonus_amount * rate).quantize(Decimal("1")) + # 前月給与がない場合: 月額表方式が必要だがフォールバックとして10.21% + return (bonus_amount * Decimal("0.1021")).quantize(Decimal("1"), rounding=ROUND_HALF_UP) + + table = _load_bonus_tax_rates() + salary_k = float(previous_salary_avg) / 1000 # 千円単位に変換 + dep_idx = min(int(dependents_count), 7) + + rate_percent = Decimal("10.21") # フォールバック + for entry in table['entries']: + rng = entry['ranges'][dep_idx] + from_k = rng[0] + to_k = rng[1] + if to_k is None: + # 上限なし(最高税率帯) + if salary_k >= from_k: + rate_percent = Decimal(str(entry['rate'])) + break + elif from_k <= salary_k < to_k: + rate_percent = Decimal(str(entry['rate'])) + break + + rate = rate_percent / Decimal("100") + return (bonus_amount * rate).quantize(Decimal("1"), rounding=ROUND_HALF_UP) @staticmethod def calculate_bonus( @@ -176,7 +203,7 @@ class BonusCalculationService: if health_insurance_rate: health_insurance = ( health_standard_bonus * Decimal(str(health_insurance_rate["employee_rate"])) - ).quantize(Decimal("1")) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) # 介護保険(40歳以上65歳未満が対象) care_insurance = Decimal("0") @@ -185,7 +212,7 @@ class BonusCalculationService: if care_insurance_rate: care_insurance = ( health_standard_bonus * Decimal(str(care_insurance_rate["employee_rate"])) - ).quantize(Decimal("1")) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) # 厚生年金 pension_insurance_rate = BonusCalculationService.get_insurance_rate("厚生年金", payment_date) @@ -193,7 +220,7 @@ class BonusCalculationService: if pension_insurance_rate: pension_insurance = ( pension_standard_bonus * Decimal(str(pension_insurance_rate["employee_rate"])) - ).quantize(Decimal("1")) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) # 雇用保険 employment_insurance_rate = BonusCalculationService.get_insurance_rate("雇用保険", payment_date) @@ -201,35 +228,21 @@ class BonusCalculationService: if employment_insurance_rate: employment_insurance = ( total_bonus * Decimal(str(employment_insurance_rate["employee_rate"])) - ).quantize(Decimal("1")) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) # 子ども・子育て支援金(令和8年4月分以降のみ適用) - # 賞与の場合: 標準報酬月額表の淨化率を使い、total_bonus × 子育て率 / 2 + # 賞与の場合: 社会保険料率設定(insurance_rates)の料率 × 賞与総額で計算 child_support = Decimal("0") is_child_support_applicable = ( - (bonus_year == 2026 and bonus_month >= 4) or bonus_year >= 2027 + (bonus_year == 2026 and bonus_month >= 5) or bonus_year >= 2027 ) if is_child_support_applicable: - with get_connection() as conn: - with conn.cursor() as cur: - # 標準報酬月額表から子育て率を取得(最上位等級rowの child_support/monthly_amountで率を計算) - cur.execute( - """ - SELECT child_support, monthly_amount - FROM standard_remuneration - WHERE rate_year = %s - AND monthly_amount > 0 AND child_support > 0 - ORDER BY monthly_amount DESC - LIMIT 1 - """, - (payment_date.year,) - ) - sr = cur.fetchone() - if sr and sr["monthly_amount"] and sr["monthly_amount"] > 0: - cs_rate = Decimal(str(sr["child_support"])) / Decimal(str(sr["monthly_amount"])) - # 標準賞与額に封上限なし(法定上賞与には標準賞与額上限なし) - child_support = (total_bonus * cs_rate / Decimal("2")).quantize(Decimal("1")) - print(f"[DEBUG] 賞与子育て支援金: 率={cs_rate}, 賞与総額={total_bonus} → 従業員負担={child_support}") + child_support_rate = BonusCalculationService.get_insurance_rate("子ども・子育て支援金", payment_date) + if child_support_rate: + child_support = ( + total_bonus * Decimal(str(child_support_rate["employee_rate"])) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) + print(f"[DEBUG] 賞与子育て支援金: 賞与総額={total_bonus} × 料率={child_support_rate['employee_rate']} = {child_support}") # 所得税の計算(賞与特有の計算) from ..calculation.service import PayrollCalculationService diff --git a/backend/app/payroll/calculation/router.py b/backend/app/payroll/calculation/router.py index f23ac6c..ce78c34 100644 --- a/backend/app/payroll/calculation/router.py +++ b/backend/app/payroll/calculation/router.py @@ -224,7 +224,8 @@ def recalculate_payroll(payroll_id: int, request: schemas.RecalculateRequest = N UPDATE monthly_payroll SET base_salary = %s, overtime_pay = %s, holiday_pay = %s, commute_allowance = %s, total_payment = %s, - health_insurance = %s, pension_insurance = %s, employment_insurance = %s, + health_insurance = %s, care_insurance = %s, pension_insurance = %s, + employment_insurance = %s, child_support = %s, income_tax = %s, total_deduction = %s, net_payment = %s, calculated_at = %s, calculated_by = %s WHERE payroll_id = %s @@ -233,8 +234,9 @@ def recalculate_payroll(payroll_id: int, request: schemas.RecalculateRequest = N ( calc_result["base_salary"], calc_result["overtime_pay"], calc_result["holiday_pay"], calc_result["commute_allowance"], calc_result["total_payment"], - calc_result["health_insurance"], calc_result["pension_insurance"], - calc_result["employment_insurance"], + calc_result["health_insurance"], calc_result["care_insurance"], + calc_result["pension_insurance"], calc_result["employment_insurance"], + calc_result["child_support"], calc_result["income_tax"], calc_result["total_deduction"], calc_result["net_payment"], datetime.now(), calc_result["calculated_by"], payroll_id diff --git a/backend/app/payroll/calculation/schemas.py b/backend/app/payroll/calculation/schemas.py index eb60730..0859293 100644 --- a/backend/app/payroll/calculation/schemas.py +++ b/backend/app/payroll/calculation/schemas.py @@ -84,6 +84,7 @@ class MonthlyPayroll(MonthlyPayrollBase): care_insurance: Decimal pension_insurance: Decimal employment_insurance: Decimal + child_support: Optional[Decimal] = None income_tax: Decimal resident_tax: Decimal other_deduction: Decimal diff --git a/backend/app/payroll/calculation/service.py b/backend/app/payroll/calculation/service.py index 94173e8..6c7d2cd 100644 --- a/backend/app/payroll/calculation/service.py +++ b/backend/app/payroll/calculation/service.py @@ -1,7 +1,7 @@ """ 給与計算サービス (Payroll Calculation Service) """ -from decimal import Decimal +from decimal import Decimal, ROUND_HALF_UP from datetime import date from typing import Dict, Any from ...core.database import get_connection @@ -58,8 +58,10 @@ class PayrollCalculationService: """保険料率を取得(年度がない場合は前年度を参照)""" with get_connection() as conn: with conn.cursor() as cur: - # rate_yearで年度を判定 - target_year = target_date.year + # 翌月払いのため、新年度料率は5月支払分(4月分)から適用 + # rate_year=XXXX は XXXX年5月支払〜(XXXX+1)年4月支払に適用 + # 1〜4月支払は前年度(year-1)の料率を使用 + target_year = target_date.year if target_date.month >= 5 else target_date.year - 1 cur.execute( """ SELECT * FROM insurance_rates @@ -300,7 +302,7 @@ class PayrollCalculationService: # まず指定年度の標準報酬月額表を検索 cur.execute( """ - SELECT monthly_amount, child_support + SELECT monthly_amount FROM standard_remuneration WHERE rate_year = %s AND salary_from <= %s @@ -318,7 +320,7 @@ class PayrollCalculationService: previous_year = target_year - year_offset cur.execute( """ - SELECT monthly_amount, child_support + SELECT monthly_amount FROM standard_remuneration WHERE rate_year = %s AND salary_from <= %s @@ -334,11 +336,9 @@ class PayrollCalculationService: if result: standard_monthly_salary = Decimal(str(result["monthly_amount"])) - child_support_full = Decimal(str(result["child_support"])) if result["child_support"] is not None else Decimal("0") - print(f"[DEBUG] 標準報酬月額表検索: 総支給額={total_payment} → 標準報酬月額={standard_monthly_salary}, 子育て支援金全額={child_support_full}") + print(f"[DEBUG] 標準報酬月額表検索: 総支給額={total_payment} → 標準報酬月額={standard_monthly_salary}") else: print(f"[DEBUG] 標準報酬月額表検索: 該当等級なし(総支給額={total_payment})") - child_support_full = Decimal("0") # 社会保険料上限を取得 @@ -381,7 +381,7 @@ class PayrollCalculationService: if health_insurance_rate: health_insurance = ( health_standard_salary * Decimal(str(health_insurance_rate["employee_rate"])) - ).quantize(Decimal("0.01")) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) elif calc_social_insurance: errors.append(f"健康保険料率が見つかりません(年度: {payment_date.year})") @@ -392,7 +392,7 @@ class PayrollCalculationService: if care_insurance_rate: care_insurance = ( health_standard_salary * Decimal(str(care_insurance_rate["employee_rate"])) - ).quantize(Decimal("0.01")) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) print(f"[DEBUG] 介護保険計算: {health_standard_salary} × {care_insurance_rate['employee_rate']}% = {care_insurance}") else: errors.append(f"介護保険料率が見つかりません(年度: {payment_date.year})") if calc_social_insurance else None @@ -403,7 +403,7 @@ class PayrollCalculationService: if pension_insurance_rate: pension_insurance = ( pension_standard_salary * Decimal(str(pension_insurance_rate["employee_rate"])) - ).quantize(Decimal("0.01")) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) print(f"[DEBUG] 厚生年金計算: {pension_standard_salary} × {pension_insurance_rate['employee_rate']}% = {pension_insurance}") elif calc_social_insurance: errors.append(f"厚生年金保険料率が見つかりません(年度: {payment_date.year})") @@ -412,14 +412,19 @@ class PayrollCalculationService: employment_insurance_rate = PayrollCalculationService.get_insurance_rate("雇用保険", payment_date) employment_insurance = Decimal("0") - # 子ども・子育て支援金(令和8年4月分以降のみ適用) + # 子ども・子育て支援金(令和8年4月分=5月納付分以降のみ適用) + # 翌月払いのため、payroll_month=5(5月支払)が4月分保険料の初回控除月 child_support = Decimal("0") is_child_support_applicable = ( - (payroll_year == 2026 and payroll_month >= 4) or payroll_year >= 2027 + (payroll_year == 2026 and payroll_month >= 5) or payroll_year >= 2027 ) if is_child_support_applicable and calc_social_insurance: - child_support = (child_support_full / Decimal("2")).quantize(Decimal("0.01")) - print(f"[DEBUG] 子育て支援金: 全額={child_support_full} → 折半額(従業員負担)={child_support}") + child_support_rate = PayrollCalculationService.get_insurance_rate("子ども・子育て支援金", payment_date) + if child_support_rate: + child_support = ( + standard_monthly_salary * Decimal(str(child_support_rate["employee_rate"])) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) + print(f"[DEBUG] 子育て支援金: 標準報酬月額={standard_monthly_salary} × 料率={child_support_rate['employee_rate']} = {child_support}") # 雇用保険加入対象かどうか確認 is_employment_insurance_eligible = salary_setting.get("employment_insurance_eligible", True) if salary_setting else True @@ -427,7 +432,7 @@ class PayrollCalculationService: if is_employment_insurance_eligible and employment_insurance_rate: employment_insurance = ( total_payment * Decimal(str(employment_insurance_rate["employee_rate"])) - ).quantize(Decimal("0.01")) + ).quantize(Decimal("1"), rounding=ROUND_HALF_UP) elif not is_employment_insurance_eligible: print(f"[DEBUG] この従業員は雇用保険非対象です") elif not employment_insurance_rate and calc_social_insurance: diff --git a/backend/app/payroll/config/bonus_tax_rates.json b/backend/app/payroll/config/bonus_tax_rates.json new file mode 100644 index 0000000..bf10da8 --- /dev/null +++ b/backend/app/payroll/config/bonus_tax_rates.json @@ -0,0 +1,280 @@ +{ + "version": "令和2年分(令和2年4月1日以降適用)", + "source": "国税庁 賞与に対する源泉徴収税額の算出率の表(甲欄)平成24年3月31日財務省告示第115号別表第三(平成31年3月29日財務省告示第97号改正)", + "note": "単位は千円。rate は%値。ranges[i] は扶養i人の[以上(千円), 未満(千円) または null=上限なし]。賞与の金額は社会保険料等控除後の金額に適用する。", + "entries": [ + { + "rate": 0.0, + "ranges": [ + [0, 68], + [0, 94], + [0, 133], + [0, 171], + [0, 210], + [0, 243], + [0, 275], + [0, 308] + ] + }, + { + "rate": 2.042, + "ranges": [ + [68, 79], + [94, 243], + [133, 269], + [171, 295], + [210, 300], + [243, 300], + [275, 333], + [308, 372] + ] + }, + { + "rate": 4.084, + "ranges": [ + [79, 252], + [243, 282], + [269, 312], + [295, 345], + [300, 378], + [300, 406], + [333, 431], + [372, 456] + ] + }, + { + "rate": 6.126, + "ranges": [ + [252, 300], + [282, 338], + [312, 369], + [345, 398], + [378, 424], + [406, 450], + [431, 476], + [456, 502] + ] + }, + { + "rate": 8.168, + "ranges": [ + [300, 334], + [338, 365], + [369, 393], + [398, 417], + [424, 444], + [450, 472], + [476, 499], + [502, 523] + ] + }, + { + "rate": 10.21, + "ranges": [ + [334, 363], + [365, 394], + [393, 420], + [417, 445], + [444, 470], + [472, 496], + [499, 521], + [523, 545] + ] + }, + { + "rate": 12.252, + "ranges": [ + [363, 395], + [394, 422], + [420, 450], + [445, 477], + [470, 503], + [496, 525], + [521, 547], + [545, 571] + ] + }, + { + "rate": 14.294, + "ranges": [ + [395, 426], + [422, 455], + [450, 484], + [477, 510], + [503, 534], + [525, 557], + [547, 582], + [571, 607] + ] + }, + { + "rate": 16.336, + "ranges": [ + [426, 520], + [455, 520], + [484, 520], + [510, 544], + [534, 570], + [557, 597], + [582, 623], + [607, 650] + ] + }, + { + "rate": 18.378, + "ranges": [ + [520, 601], + [520, 617], + [520, 632], + [544, 647], + [570, 662], + [597, 677], + [623, 693], + [650, 708] + ] + }, + { + "rate": 20.42, + "ranges": [ + [601, 678], + [617, 699], + [632, 721], + [647, 745], + [662, 768], + [677, 792], + [693, 815], + [708, 838] + ] + }, + { + "rate": 22.462, + "ranges": [ + [678, 708], + [699, 733], + [721, 757], + [745, 782], + [768, 806], + [792, 831], + [815, 856], + [838, 880] + ] + }, + { + "rate": 24.504, + "ranges": [ + [708, 745], + [733, 771], + [757, 797], + [782, 823], + [806, 849], + [831, 875], + [856, 900], + [880, 926] + ] + }, + { + "rate": 26.546, + "ranges": [ + [745, 788], + [771, 814], + [797, 841], + [823, 868], + [849, 896], + [875, 923], + [900, 950], + [926, 978] + ] + }, + { + "rate": 28.588, + "ranges": [ + [788, 846], + [814, 874], + [841, 902], + [868, 931], + [896, 959], + [923, 987], + [950, 1015], + [978, 1043] + ] + }, + { + "rate": 30.63, + "ranges": [ + [846, 914], + [874, 944], + [902, 975], + [931, 1005], + [959, 1036], + [987, 1066], + [1015, 1096], + [1043, 1127] + ] + }, + { + "rate": 32.672, + "ranges": [ + [914, 1312], + [944, 1336], + [975, 1360], + [1005, 1385], + [1036, 1409], + [1066, 1434], + [1096, 1458], + [1127, 1482] + ] + }, + { + "rate": 35.735, + "ranges": [ + [1312, 1521], + [1336, 1526], + [1360, 1526], + [1385, 1538], + [1409, 1555], + [1434, 1555], + [1458, 1555], + [1482, 1583] + ] + }, + { + "rate": 38.798, + "ranges": [ + [1521, 2621], + [1526, 2645], + [1526, 2669], + [1538, 2693], + [1555, 2716], + [1555, 2740], + [1555, 2764], + [1583, 2788] + ] + }, + { + "rate": 41.861, + "ranges": [ + [2621, 3495], + [2645, 3527], + [2669, 3559], + [2693, 3590], + [2716, 3622], + [2740, 3654], + [2764, 3685], + [2788, 3717] + ] + }, + { + "rate": 45.945, + "ranges": [ + [3495, null], + [3527, null], + [3559, null], + [3590, null], + [3622, null], + [3654, null], + [3685, null], + [3717, null] + ] + } + ] +} diff --git a/backend/app/payroll/config/monthly_tax_table.json b/backend/app/payroll/config/monthly_tax_table.json new file mode 100644 index 0000000..006cf18 --- /dev/null +++ b/backend/app/payroll/config/monthly_tax_table.json @@ -0,0 +1,3446 @@ +{ + "version": "令和7年分", + "source": "国税庁 給与所得の源泉徴収税額表(月額表)", + "columns": [ + "扶養0人", + "扶養1人", + "扶養2人", + "扶養3人", + "扶養4人", + "扶養5人", + "扶養6人", + "扶養7人以上" + ], + "entries": [ + { + "from": 1, + "to": 88000, + "taxes": [ + 89000, + 130, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 2, + "to": 89000, + "taxes": [ + 90000, + 180, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 3, + "to": 90000, + "taxes": [ + 91000, + 230, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 4, + "to": 91000, + "taxes": [ + 92000, + 290, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 5, + "to": 92000, + "taxes": [ + 93000, + 340, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 6, + "to": 93000, + "taxes": [ + 94000, + 390, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 7, + "to": 94000, + "taxes": [ + 95000, + 440, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 8, + "to": 95000, + "taxes": [ + 96000, + 490, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 9, + "to": 96000, + "taxes": [ + 97000, + 540, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 10, + "to": 97000, + "taxes": [ + 98000, + 590, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 11, + "to": 98000, + "taxes": [ + 99000, + 640, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 12, + "to": 99000, + "taxes": [ + 101000, + 720, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 13, + "to": 101000, + "taxes": [ + 103000, + 830, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 14, + "to": 103000, + "taxes": [ + 105000, + 930, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 15, + "to": 105000, + "taxes": [ + 107000, + 1030, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 16, + "to": 107000, + "taxes": [ + 109000, + 1130, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 17, + "to": 109000, + "taxes": [ + 111000, + 1240, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 18, + "to": 111000, + "taxes": [ + 113000, + 1340, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 19, + "to": 113000, + "taxes": [ + 115000, + 1440, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 20, + "to": 115000, + "taxes": [ + 117000, + 1540, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 21, + "to": 117000, + "taxes": [ + 119000, + 1640, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 22, + "to": 119000, + "taxes": [ + 121000, + 1750, + 120, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 23, + "to": 121000, + "taxes": [ + 123000, + 1850, + 220, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 24, + "to": 123000, + "taxes": [ + 125000, + 1950, + 330, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 25, + "to": 125000, + "taxes": [ + 127000, + 2050, + 430, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 26, + "to": 127000, + "taxes": [ + 129000, + 2150, + 530, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 27, + "to": 129000, + "taxes": [ + 131000, + 2260, + 630, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 28, + "to": 131000, + "taxes": [ + 133000, + 2360, + 740, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 29, + "to": 133000, + "taxes": [ + 135000, + 2460, + 840, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 30, + "to": 135000, + "taxes": [ + 137000, + 2550, + 930, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 31, + "to": 137000, + "taxes": [ + 139000, + 2610, + 990, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 32, + "to": 139000, + "taxes": [ + 141000, + 2680, + 1050, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 33, + "to": 141000, + "taxes": [ + 143000, + 2740, + 1110, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 34, + "to": 143000, + "taxes": [ + 145000, + 2800, + 1170, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 35, + "to": 145000, + "taxes": [ + 147000, + 2860, + 1240, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 36, + "to": 147000, + "taxes": [ + 149000, + 2920, + 1300, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 37, + "to": 149000, + "taxes": [ + 151000, + 2980, + 1360, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 38, + "to": 151000, + "taxes": [ + 153000, + 3050, + 1430, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 39, + "to": 153000, + "taxes": [ + 155000, + 3120, + 1500, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 40, + "to": 155000, + "taxes": [ + 157000, + 3200, + 1570, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 41, + "to": 157000, + "taxes": [ + 159000, + 3270, + 1640, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 42, + "to": 159000, + "taxes": [ + 161000, + 3340, + 1720, + 100, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 43, + "to": 161000, + "taxes": [ + 163000, + 3410, + 1790, + 170, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 44, + "to": 163000, + "taxes": [ + 165000, + 3480, + 1860, + 250, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 45, + "to": 165000, + "taxes": [ + 167000, + 3550, + 1930, + 320, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 46, + "to": 167000, + "taxes": [ + 169000, + 3620, + 2000, + 390, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 47, + "to": 169000, + "taxes": [ + 171000, + 3700, + 2070, + 460, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 48, + "to": 171000, + "taxes": [ + 173000, + 3770, + 2140, + 530, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 49, + "to": 173000, + "taxes": [ + 175000, + 3840, + 2220, + 600, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 50, + "to": 175000, + "taxes": [ + 177000, + 3910, + 2290, + 670, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 51, + "to": 177000, + "taxes": [ + 179000, + 3980, + 2360, + 750, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 52, + "to": 179000, + "taxes": [ + 181000, + 4050, + 2430, + 820, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 53, + "to": 181000, + "taxes": [ + 183000, + 4120, + 2500, + 890, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 54, + "to": 183000, + "taxes": [ + 185000, + 4200, + 2570, + 960, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 55, + "to": 185000, + "taxes": [ + 187000, + 4270, + 2640, + 1030, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 56, + "to": 187000, + "taxes": [ + 189000, + 4340, + 2720, + 1100, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 57, + "to": 189000, + "taxes": [ + 191000, + 4410, + 2790, + 1170, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 58, + "to": 191000, + "taxes": [ + 193000, + 4480, + 2860, + 1250, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 59, + "to": 193000, + "taxes": [ + 195000, + 4550, + 2930, + 1320, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 60, + "to": 195000, + "taxes": [ + 197000, + 4630, + 3000, + 1390, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 61, + "to": 197000, + "taxes": [ + 199000, + 4700, + 3070, + 1460, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 62, + "to": 199000, + "taxes": [ + 201000, + 4770, + 3140, + 1530, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 63, + "to": 201000, + "taxes": [ + 203000, + 4840, + 3220, + 1600, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 64, + "to": 203000, + "taxes": [ + 205000, + 4910, + 3290, + 1670, + 0, + 0, + 0, + 0 + ] + }, + { + "from": 65, + "to": 205000, + "taxes": [ + 207000, + 4980, + 3360, + 1750, + 130, + 0, + 0, + 0 + ] + }, + { + "from": 66, + "to": 207000, + "taxes": [ + 209000, + 5050, + 3430, + 1820, + 200, + 0, + 0, + 0 + ] + }, + { + "from": 67, + "to": 209000, + "taxes": [ + 211000, + 5130, + 3500, + 1890, + 280, + 0, + 0, + 0 + ] + }, + { + "from": 68, + "to": 211000, + "taxes": [ + 213000, + 5200, + 3570, + 1960, + 350, + 0, + 0, + 0 + ] + }, + { + "from": 69, + "to": 213000, + "taxes": [ + 215000, + 5270, + 3640, + 2030, + 420, + 0, + 0, + 0 + ] + }, + { + "from": 70, + "to": 215000, + "taxes": [ + 217000, + 5340, + 3720, + 2100, + 490, + 0, + 0, + 0 + ] + }, + { + "from": 71, + "to": 217000, + "taxes": [ + 219000, + 5410, + 3790, + 2170, + 560, + 0, + 0, + 0 + ] + }, + { + "from": 72, + "to": 219000, + "taxes": [ + 221000, + 5480, + 3860, + 2250, + 630, + 0, + 0, + 0 + ] + }, + { + "from": 73, + "to": 221000, + "taxes": [ + 224000, + 5560, + 3950, + 2340, + 710, + 0, + 0, + 0 + ] + }, + { + "from": 74, + "to": 224000, + "taxes": [ + 227000, + 5680, + 4060, + 2440, + 830, + 0, + 0, + 0 + ] + }, + { + "from": 75, + "to": 227000, + "taxes": [ + 230000, + 5780, + 4170, + 2550, + 930, + 0, + 0, + 0 + ] + }, + { + "from": 76, + "to": 230000, + "taxes": [ + 233000, + 5890, + 4280, + 2650, + 1040, + 0, + 0, + 0 + ] + }, + { + "from": 77, + "to": 233000, + "taxes": [ + 236000, + 5990, + 4380, + 2770, + 1140, + 0, + 0, + 0 + ] + }, + { + "from": 78, + "to": 236000, + "taxes": [ + 239000, + 6110, + 4490, + 2870, + 1260, + 0, + 0, + 0 + ] + }, + { + "from": 79, + "to": 239000, + "taxes": [ + 242000, + 6210, + 4590, + 2980, + 1360, + 0, + 0, + 0 + ] + }, + { + "from": 80, + "to": 242000, + "taxes": [ + 245000, + 6320, + 4710, + 3080, + 1470, + 0, + 0, + 0 + ] + }, + { + "from": 81, + "to": 245000, + "taxes": [ + 248000, + 6420, + 4810, + 3200, + 1570, + 0, + 0, + 0 + ] + }, + { + "from": 82, + "to": 248000, + "taxes": [ + 251000, + 6530, + 4920, + 3300, + 1680, + 0, + 0, + 0 + ] + }, + { + "from": 83, + "to": 251000, + "taxes": [ + 254000, + 6640, + 5020, + 3410, + 1790, + 170, + 0, + 0 + ] + }, + { + "from": 84, + "to": 254000, + "taxes": [ + 257000, + 6750, + 5140, + 3510, + 1900, + 290, + 0, + 0 + ] + }, + { + "from": 85, + "to": 257000, + "taxes": [ + 260000, + 6850, + 5240, + 3620, + 2000, + 390, + 0, + 0 + ] + }, + { + "from": 86, + "to": 260000, + "taxes": [ + 263000, + 6960, + 5350, + 3730, + 2110, + 500, + 0, + 0 + ] + }, + { + "from": 87, + "to": 263000, + "taxes": [ + 266000, + 7070, + 5450, + 3840, + 2220, + 600, + 0, + 0 + ] + }, + { + "from": 88, + "to": 266000, + "taxes": [ + 269000, + 7180, + 5560, + 3940, + 2330, + 710, + 0, + 0 + ] + }, + { + "from": 89, + "to": 269000, + "taxes": [ + 272000, + 7280, + 5670, + 4050, + 2430, + 820, + 0, + 0 + ] + }, + { + "from": 90, + "to": 272000, + "taxes": [ + 275000, + 7390, + 5780, + 4160, + 2540, + 930, + 0, + 0 + ] + }, + { + "from": 91, + "to": 275000, + "taxes": [ + 278000, + 7490, + 5880, + 4270, + 2640, + 1030, + 0, + 0 + ] + }, + { + "from": 92, + "to": 278000, + "taxes": [ + 281000, + 7610, + 5990, + 4370, + 2760, + 1140, + 0, + 0 + ] + }, + { + "from": 93, + "to": 281000, + "taxes": [ + 284000, + 7710, + 6100, + 4480, + 2860, + 1250, + 0, + 0 + ] + }, + { + "from": 94, + "to": 284000, + "taxes": [ + 287000, + 7820, + 6210, + 4580, + 2970, + 1360, + 0, + 0 + ] + }, + { + "from": 95, + "to": 287000, + "taxes": [ + 290000, + 7920, + 6310, + 4700, + 3070, + 1460, + 0, + 0 + ] + }, + { + "from": 96, + "to": 290000, + "taxes": [ + 293000, + 8040, + 6420, + 4800, + 3190, + 1570, + 0, + 0 + ] + }, + { + "from": 97, + "to": 293000, + "taxes": [ + 296000, + 8140, + 6520, + 4910, + 3290, + 1670, + 0, + 0 + ] + }, + { + "from": 98, + "to": 296000, + "taxes": [ + 299000, + 8250, + 6640, + 5010, + 3400, + 1790, + 160, + 0 + ] + }, + { + "from": 99, + "to": 299000, + "taxes": [ + 302000, + 8420, + 6740, + 5130, + 3510, + 1890, + 280, + 0 + ] + }, + { + "from": 100, + "to": 302000, + "taxes": [ + 305000, + 8670, + 6860, + 5250, + 3630, + 2010, + 400, + 0 + ] + }, + { + "from": 101, + "to": 305000, + "taxes": [ + 308000, + 8910, + 6980, + 5370, + 3760, + 2130, + 520, + 0 + ] + }, + { + "from": 102, + "to": 308000, + "taxes": [ + 311000, + 9160, + 7110, + 5490, + 3880, + 2260, + 640, + 0 + ] + }, + { + "from": 103, + "to": 311000, + "taxes": [ + 314000, + 9400, + 7230, + 5620, + 4000, + 2380, + 770, + 0 + ] + }, + { + "from": 104, + "to": 314000, + "taxes": [ + 317000, + 9650, + 7350, + 5740, + 4120, + 2500, + 890, + 0 + ] + }, + { + "from": 105, + "to": 317000, + "taxes": [ + 320000, + 9890, + 7470, + 5860, + 4250, + 2620, + 1010, + 0 + ] + }, + { + "from": 106, + "to": 320000, + "taxes": [ + 323000, + 10140, + 7600, + 5980, + 4370, + 2750, + 1130, + 0 + ] + }, + { + "from": 107, + "to": 323000, + "taxes": [ + 326000, + 10380, + 7720, + 6110, + 4490, + 2870, + 1260, + 0 + ] + }, + { + "from": 108, + "to": 326000, + "taxes": [ + 329000, + 10630, + 7840, + 6230, + 4610, + 2990, + 1380, + 0 + ] + }, + { + "from": 109, + "to": 329000, + "taxes": [ + 332000, + 10870, + 7960, + 6350, + 4740, + 3110, + 1500, + 0 + ] + }, + { + "from": 110, + "to": 332000, + "taxes": [ + 335000, + 11120, + 8090, + 6470, + 4860, + 3240, + 1620, + 0 + ] + }, + { + "from": 111, + "to": 335000, + "taxes": [ + 338000, + 11360, + 8210, + 6600, + 4980, + 3360, + 1750, + 130 + ] + }, + { + "from": 112, + "to": 338000, + "taxes": [ + 341000, + 11610, + 8370, + 6720, + 5110, + 3480, + 1870, + 260 + ] + }, + { + "from": 113, + "to": 341000, + "taxes": [ + 344000, + 11850, + 8620, + 6840, + 5230, + 3600, + 1990, + 380 + ] + }, + { + "from": 114, + "to": 344000, + "taxes": [ + 347000, + 12100, + 8860, + 6960, + 5350, + 3730, + 2110, + 500 + ] + }, + { + "from": 115, + "to": 347000, + "taxes": [ + 350000, + 12340, + 9110, + 7090, + 5470, + 3850, + 2240, + 620 + ] + }, + { + "from": 116, + "to": 350000, + "taxes": [ + 353000, + 12590, + 9350, + 7210, + 5600, + 3970, + 2360, + 750 + ] + }, + { + "from": 117, + "to": 353000, + "taxes": [ + 356000, + 12830, + 9600, + 7330, + 5720, + 4090, + 2480, + 870 + ] + }, + { + "from": 118, + "to": 356000, + "taxes": [ + 359000, + 13080, + 9840, + 7450, + 5840, + 4220, + 2600, + 990 + ] + }, + { + "from": 119, + "to": 359000, + "taxes": [ + 362000, + 13320, + 10090, + 7580, + 5960, + 4340, + 2730, + 1110 + ] + }, + { + "from": 120, + "to": 362000, + "taxes": [ + 365000, + 13570, + 10330, + 7700, + 6090, + 4460, + 2850, + 1240 + ] + }, + { + "from": 121, + "to": 365000, + "taxes": [ + 368000, + 13810, + 10580, + 7820, + 6210, + 4580, + 2970, + 1360 + ] + }, + { + "from": 122, + "to": 368000, + "taxes": [ + 371000, + 14060, + 10820, + 7940, + 6330, + 4710, + 3090, + 1480 + ] + }, + { + "from": 123, + "to": 371000, + "taxes": [ + 374000, + 14300, + 11070, + 8070, + 6450, + 4830, + 3220, + 1600 + ] + }, + { + "from": 124, + "to": 374000, + "taxes": [ + 377000, + 14550, + 11310, + 8190, + 6580, + 4950, + 3340, + 1730 + ] + }, + { + "from": 125, + "to": 377000, + "taxes": [ + 380000, + 14790, + 11560, + 8320, + 6700, + 5070, + 3460, + 1850 + ] + }, + { + "from": 126, + "to": 380000, + "taxes": [ + 383000, + 15040, + 11800, + 8570, + 6820, + 5200, + 3580, + 1970 + ] + }, + { + "from": 127, + "to": 383000, + "taxes": [ + 386000, + 15280, + 12050, + 8810, + 6940, + 5320, + 3710, + 2090 + ] + }, + { + "from": 128, + "to": 386000, + "taxes": [ + 389000, + 15530, + 12290, + 9060, + 7070, + 5440, + 3830, + 2220 + ] + }, + { + "from": 129, + "to": 389000, + "taxes": [ + 392000, + 15770, + 12540, + 9300, + 7190, + 5560, + 3950, + 2340 + ] + }, + { + "from": 130, + "to": 392000, + "taxes": [ + 395000, + 16020, + 12780, + 9550, + 7310, + 5690, + 4070, + 2460 + ] + }, + { + "from": 131, + "to": 395000, + "taxes": [ + 398000, + 16260, + 13030, + 9790, + 7430, + 5810, + 4200, + 2580 + ] + }, + { + "from": 132, + "to": 398000, + "taxes": [ + 401000, + 16510, + 13270, + 10040, + 7560, + 5930, + 4320, + 2710 + ] + }, + { + "from": 133, + "to": 401000, + "taxes": [ + 404000, + 16750, + 13520, + 10280, + 7680, + 6050, + 4440, + 2830 + ] + }, + { + "from": 134, + "to": 404000, + "taxes": [ + 407000, + 17000, + 13760, + 10530, + 7800, + 6180, + 4560, + 2950 + ] + }, + { + "from": 135, + "to": 407000, + "taxes": [ + 410000, + 17240, + 14010, + 10770, + 7920, + 6300, + 4690, + 3070 + ] + }, + { + "from": 136, + "to": 410000, + "taxes": [ + 413000, + 17490, + 14250, + 11020, + 8050, + 6420, + 4810, + 3200 + ] + }, + { + "from": 137, + "to": 413000, + "taxes": [ + 416000, + 17730, + 14500, + 11260, + 8170, + 6540, + 4930, + 3320 + ] + }, + { + "from": 138, + "to": 416000, + "taxes": [ + 419000, + 17980, + 14740, + 11510, + 8290, + 6670, + 5050, + 3440 + ] + }, + { + "from": 139, + "to": 419000, + "taxes": [ + 422000, + 18220, + 14990, + 11750, + 8530, + 6790, + 5180, + 3560 + ] + }, + { + "from": 140, + "to": 422000, + "taxes": [ + 425000, + 18470, + 15230, + 12000, + 8770, + 6910, + 5300, + 3690 + ] + }, + { + "from": 141, + "to": 425000, + "taxes": [ + 428000, + 18710, + 15480, + 12240, + 9020, + 7030, + 5420, + 3810 + ] + }, + { + "from": 142, + "to": 428000, + "taxes": [ + 431000, + 18960, + 15720, + 12490, + 9260, + 7160, + 5540, + 3930 + ] + }, + { + "from": 143, + "to": 431000, + "taxes": [ + 434000, + 19210, + 15970, + 12730, + 9510, + 7280, + 5670, + 4050 + ] + }, + { + "from": 144, + "to": 434000, + "taxes": [ + 437000, + 19450, + 16210, + 12980, + 9750, + 7400, + 5790, + 4180 + ] + }, + { + "from": 145, + "to": 437000, + "taxes": [ + 440000, + 19700, + 16460, + 13220, + 10000, + 7520, + 5910, + 4300 + ] + }, + { + "from": 146, + "to": 440000, + "taxes": [ + 443000, + 20090, + 16700, + 13470, + 10240, + 7650, + 6030, + 4420 + ] + }, + { + "from": 147, + "to": 443000, + "taxes": [ + 446000, + 20580, + 16950, + 13710, + 10490, + 7770, + 6160, + 4540 + ] + }, + { + "from": 148, + "to": 446000, + "taxes": [ + 449000, + 21070, + 17190, + 13960, + 10730, + 7890, + 6280, + 4670 + ] + }, + { + "from": 149, + "to": 449000, + "taxes": [ + 452000, + 21560, + 17440, + 14200, + 10980, + 8010, + 6400, + 4790 + ] + }, + { + "from": 150, + "to": 452000, + "taxes": [ + 455000, + 22050, + 17680, + 14450, + 11220, + 8140, + 6520, + 4910 + ] + }, + { + "from": 151, + "to": 455000, + "taxes": [ + 458000, + 22540, + 17930, + 14690, + 11470, + 8260, + 6650, + 5030 + ] + }, + { + "from": 152, + "to": 458000, + "taxes": [ + 461000, + 23030, + 18170, + 14940, + 11710, + 8470, + 6770, + 5160 + ] + }, + { + "from": 153, + "to": 461000, + "taxes": [ + 464000, + 23520, + 18420, + 15180, + 11960, + 8720, + 6890, + 5280 + ] + }, + { + "from": 154, + "to": 464000, + "taxes": [ + 467000, + 24010, + 18660, + 15430, + 12200, + 8960, + 7010, + 5400 + ] + }, + { + "from": 155, + "to": 467000, + "taxes": [ + 470000, + 24500, + 18910, + 15670, + 12450, + 9210, + 7140, + 5520 + ] + }, + { + "from": 156, + "to": 470000, + "taxes": [ + 473000, + 24990, + 19150, + 15920, + 12690, + 9450, + 7260, + 5650 + ] + }, + { + "from": 157, + "to": 473000, + "taxes": [ + 476000, + 25480, + 19400, + 16160, + 12940, + 9700, + 7380, + 5770 + ] + }, + { + "from": 158, + "to": 476000, + "taxes": [ + 479000, + 25970, + 19640, + 16410, + 13180, + 9940, + 7500, + 5890 + ] + }, + { + "from": 159, + "to": 479000, + "taxes": [ + 482000, + 26460, + 20000, + 16650, + 13430, + 10190, + 7630, + 6010 + ] + }, + { + "from": 160, + "to": 482000, + "taxes": [ + 485000, + 26950, + 20490, + 16900, + 13670, + 10430, + 7750, + 6140 + ] + }, + { + "from": 161, + "to": 485000, + "taxes": [ + 488000, + 27440, + 20980, + 17140, + 13920, + 10680, + 7870, + 6260 + ] + }, + { + "from": 162, + "to": 488000, + "taxes": [ + 491000, + 27930, + 21470, + 17390, + 14160, + 10920, + 7990, + 6380 + ] + }, + { + "from": 163, + "to": 491000, + "taxes": [ + 494000, + 28420, + 21960, + 17630, + 14410, + 11170, + 8120, + 6500 + ] + }, + { + "from": 164, + "to": 494000, + "taxes": [ + 497000, + 28910, + 22450, + 17880, + 14650, + 11410, + 8240, + 6630 + ] + }, + { + "from": 165, + "to": 497000, + "taxes": [ + 500000, + 29400, + 22940, + 18120, + 14900, + 11660, + 8420, + 6750 + ] + }, + { + "from": 166, + "to": 500000, + "taxes": [ + 503000, + 29890, + 23430, + 18370, + 15140, + 11900, + 8670, + 6870 + ] + }, + { + "from": 167, + "to": 503000, + "taxes": [ + 506000, + 30380, + 23920, + 18610, + 15390, + 12150, + 8910, + 6990 + ] + }, + { + "from": 168, + "to": 506000, + "taxes": [ + 509000, + 30880, + 24410, + 18860, + 15630, + 12390, + 9160, + 7120 + ] + }, + { + "from": 169, + "to": 509000, + "taxes": [ + 512000, + 31370, + 24900, + 19100, + 15880, + 12640, + 9400, + 7240 + ] + }, + { + "from": 170, + "to": 512000, + "taxes": [ + 515000, + 31860, + 25390, + 19350, + 16120, + 12890, + 9650, + 7360 + ] + }, + { + "from": 171, + "to": 515000, + "taxes": [ + 518000, + 32350, + 25880, + 19590, + 16370, + 13130, + 9890, + 7480 + ] + }, + { + "from": 172, + "to": 518000, + "taxes": [ + 521000, + 32840, + 26370, + 19900, + 16610, + 13380, + 10140, + 7610 + ] + }, + { + "from": 173, + "to": 521000, + "taxes": [ + 524000, + 33330, + 26860, + 20390, + 16860, + 13620, + 10380, + 7730 + ] + }, + { + "from": 174, + "to": 524000, + "taxes": [ + 527000, + 33820, + 27350, + 20880, + 17100, + 13870, + 10630, + 7850 + ] + }, + { + "from": 175, + "to": 527000, + "taxes": [ + 530000, + 34310, + 27840, + 21370, + 17350, + 14110, + 10870, + 7970 + ] + }, + { + "from": 176, + "to": 530000, + "taxes": [ + 533000, + 34800, + 28330, + 21860, + 17590, + 14360, + 11120, + 8100 + ] + }, + { + "from": 177, + "to": 533000, + "taxes": [ + 536000, + 35290, + 28820, + 22350, + 17840, + 14600, + 11360, + 8220 + ] + }, + { + "from": 178, + "to": 536000, + "taxes": [ + 539000, + 35780, + 29310, + 22840, + 18080, + 14850, + 11610, + 8380 + ] + }, + { + "from": 179, + "to": 539000, + "taxes": [ + 542000, + 36270, + 29800, + 23330, + 18330, + 15090, + 11850, + 8630 + ] + }, + { + "from": 180, + "to": 542000, + "taxes": [ + 545000, + 36760, + 30290, + 23820, + 18570, + 15340, + 12100, + 8870 + ] + }, + { + "from": 181, + "to": 545000, + "taxes": [ + 548000, + 37250, + 30780, + 24310, + 18820, + 15580, + 12340, + 9120 + ] + }, + { + "from": 182, + "to": 548000, + "taxes": [ + 551000, + 37740, + 31270, + 24800, + 19060, + 15830, + 12590, + 9360 + ] + }, + { + "from": 183, + "to": 551000, + "taxes": [ + 554000, + 38280, + 31810, + 25340, + 19330, + 16100, + 12860, + 9630 + ] + }, + { + "from": 184, + "to": 554000, + "taxes": [ + 557000, + 38830, + 32370, + 25890, + 19600, + 16380, + 13140, + 9900 + ] + }, + { + "from": 185, + "to": 557000, + "taxes": [ + 560000, + 39380, + 32920, + 26440, + 19980, + 16650, + 13420, + 10180 + ] + }, + { + "from": 186, + "to": 560000, + "taxes": [ + 563000, + 39930, + 33470, + 27000, + 20530, + 16930, + 13690, + 10460 + ] + }, + { + "from": 187, + "to": 563000, + "taxes": [ + 566000, + 40480, + 34020, + 27550, + 21080, + 17200, + 13970, + 10730 + ] + }, + { + "from": 188, + "to": 566000, + "taxes": [ + 569000, + 41030, + 34570, + 28100, + 21630, + 17480, + 14240, + 11010 + ] + }, + { + "from": 189, + "to": 569000, + "taxes": [ + 572000, + 41590, + 35120, + 28650, + 22190, + 17760, + 14520, + 11280 + ] + }, + { + "from": 190, + "to": 572000, + "taxes": [ + 575000, + 42140, + 35670, + 29200, + 22740, + 18030, + 14790, + 11560 + ] + }, + { + "from": 191, + "to": 575000, + "taxes": [ + 578000, + 42690, + 36230, + 29750, + 23290, + 18310, + 15070, + 11830 + ] + }, + { + "from": 192, + "to": 578000, + "taxes": [ + 581000, + 43240, + 36780, + 30300, + 23840, + 18580, + 15350, + 12110 + ] + }, + { + "from": 193, + "to": 581000, + "taxes": [ + 584000, + 43790, + 37330, + 30850, + 24390, + 18860, + 15620, + 12380 + ] + }, + { + "from": 194, + "to": 584000, + "taxes": [ + 587000, + 44340, + 37880, + 31410, + 24940, + 19130, + 15900, + 12660 + ] + }, + { + "from": 195, + "to": 587000, + "taxes": [ + 590000, + 44890, + 38430, + 31960, + 25490, + 19410, + 16170, + 12940 + ] + }, + { + "from": 196, + "to": 590000, + "taxes": [ + 593000, + 45440, + 38980, + 32510, + 26050, + 19680, + 16450, + 13210 + ] + }, + { + "from": 197, + "to": 593000, + "taxes": [ + 596000, + 46000, + 39530, + 33060, + 26600, + 20130, + 16720, + 13490 + ] + }, + { + "from": 198, + "to": 596000, + "taxes": [ + 599000, + 46550, + 40080, + 33610, + 27150, + 20690, + 17000, + 13760 + ] + }, + { + "from": 199, + "to": 599000, + "taxes": [ + 602000, + 47100, + 40640, + 34160, + 27700, + 21240, + 17280, + 14040 + ] + }, + { + "from": 200, + "to": 602000, + "taxes": [ + 605000, + 47650, + 41190, + 34710, + 28250, + 21790, + 17550, + 14310 + ] + }, + { + "from": 201, + "to": 605000, + "taxes": [ + 608000, + 48200, + 41740, + 35270, + 28800, + 22340, + 17830, + 14590 + ] + }, + { + "from": 202, + "to": 608000, + "taxes": [ + 611000, + 48750, + 42290, + 35820, + 29350, + 22890, + 18100, + 14870 + ] + }, + { + "from": 203, + "to": 611000, + "taxes": [ + 614000, + 49300, + 42840, + 36370, + 29910, + 23440, + 18380, + 15140 + ] + }, + { + "from": 204, + "to": 614000, + "taxes": [ + 617000, + 49860, + 43390, + 36920, + 30460, + 23990, + 18650, + 15420 + ] + }, + { + "from": 205, + "to": 617000, + "taxes": [ + 620000, + 50410, + 43940, + 37470, + 31010, + 24540, + 18930, + 15690 + ] + }, + { + "from": 206, + "to": 620000, + "taxes": [ + 623000, + 50960, + 44500, + 38020, + 31560, + 25100, + 19210, + 15970 + ] + }, + { + "from": 207, + "to": 623000, + "taxes": [ + 626000, + 51510, + 45050, + 38570, + 32110, + 25650, + 19480, + 16240 + ] + }, + { + "from": 208, + "to": 626000, + "taxes": [ + 629000, + 52060, + 45600, + 39120, + 32660, + 26200, + 19760, + 16520 + ] + }, + { + "from": 209, + "to": 629000, + "taxes": [ + 632000, + 52610, + 46150, + 39680, + 33210, + 26750, + 20280, + 16800 + ] + }, + { + "from": 210, + "to": 632000, + "taxes": [ + 635000, + 53160, + 46700, + 40230, + 33760, + 27300, + 20830, + 17070 + ] + }, + { + "from": 211, + "to": 635000, + "taxes": [ + 638000, + 53710, + 47250, + 40780, + 34320, + 27850, + 21380, + 17350 + ] + }, + { + "from": 212, + "to": 638000, + "taxes": [ + 641000, + 54270, + 47800, + 41330, + 34870, + 28400, + 21930, + 17620 + ] + }, + { + "from": 213, + "to": 641000, + "taxes": [ + 644000, + 54820, + 48350, + 41880, + 35420, + 28960, + 22480, + 17900 + ] + }, + { + "from": 214, + "to": 644000, + "taxes": [ + 647000, + 55370, + 48910, + 42430, + 35970, + 29510, + 23030, + 18170 + ] + }, + { + "from": 215, + "to": 647000, + "taxes": [ + 650000, + 55920, + 49460, + 42980, + 36520, + 30060, + 23590, + 18450 + ] + }, + { + "from": 216, + "to": 650000, + "taxes": [ + 653000, + 56470, + 50010, + 43540, + 37070, + 30610, + 24140, + 18730 + ] + }, + { + "from": 217, + "to": 653000, + "taxes": [ + 656000, + 57020, + 50560, + 44090, + 37620, + 31160, + 24690, + 19000 + ] + }, + { + "from": 218, + "to": 656000, + "taxes": [ + 659000, + 57570, + 51110, + 44640, + 38180, + 31710, + 25240, + 19280 + ] + }, + { + "from": 219, + "to": 659000, + "taxes": [ + 662000, + 58130, + 51660, + 45190, + 38730, + 32260, + 25790, + 19550 + ] + }, + { + "from": 220, + "to": 662000, + "taxes": [ + 665000, + 58680, + 52210, + 45740, + 39280, + 32810, + 26340, + 19880 + ] + }, + { + "from": 221, + "to": 665000, + "taxes": [ + 668000, + 59230, + 52770, + 46290, + 39830, + 33370, + 26890, + 20430 + ] + }, + { + "from": 222, + "to": 668000, + "taxes": [ + 671000, + 59780, + 53320, + 46840, + 40380, + 33920, + 27440, + 20980 + ] + }, + { + "from": 223, + "to": 671000, + "taxes": [ + 674000, + 60330, + 53870, + 47390, + 40930, + 34470, + 28000, + 21530 + ] + }, + { + "from": 224, + "to": 674000, + "taxes": [ + 677000, + 60880, + 54420, + 47950, + 41480, + 35020, + 28550, + 22080 + ] + }, + { + "from": 225, + "to": 677000, + "taxes": [ + 680000, + 61430, + 54970, + 48500, + 42030, + 35570, + 29100, + 22640 + ] + }, + { + "from": 226, + "to": 680000, + "taxes": [ + 683000, + 61980, + 55520, + 49050, + 42590, + 36120, + 29650, + 23190 + ] + }, + { + "from": 227, + "to": 683000, + "taxes": [ + 686000, + 62540, + 56070, + 49600, + 43140, + 36670, + 30200, + 23740 + ] + }, + { + "from": 228, + "to": 686000, + "taxes": [ + 689000, + 63090, + 56620, + 50150, + 43690, + 37230, + 30750, + 24290 + ] + }, + { + "from": 229, + "to": 689000, + "taxes": [ + 692000, + 63640, + 57180, + 50700, + 44240, + 37780, + 31300, + 24840 + ] + }, + { + "from": 230, + "to": 692000, + "taxes": [ + 695000, + 64190, + 57730, + 51250, + 44790, + 38330, + 31860, + 25390 + ] + }, + { + "from": 231, + "to": 695000, + "taxes": [ + 698000, + 64740, + 58280, + 51810, + 45340, + 38880, + 32410, + 25940 + ] + }, + { + "from": 232, + "to": 698000, + "taxes": [ + 701000, + 65290, + 58830, + 52360, + 45890, + 39430, + 32960, + 26490 + ] + }, + { + "from": 233, + "to": 701000, + "taxes": [ + 704000, + 65840, + 59380, + 52910, + 46450, + 39980, + 33510, + 27050 + ] + }, + { + "from": 234, + "to": 704000, + "taxes": [ + 707000, + 66400, + 59930, + 53460, + 47000, + 40530, + 34060, + 27600 + ] + }, + { + "from": 235, + "to": 707000, + "taxes": [ + 710000, + 66960, + 60480, + 54020, + 47550, + 41090, + 34620, + 28150 + ] + }, + { + "from": 236, + "to": 710000, + "taxes": [ + 713000, + 67570, + 61100, + 54630, + 48160, + 41700, + 35230, + 28760 + ] + }, + { + "from": 237, + "to": 713000, + "taxes": [ + 716000, + 68180, + 61710, + 55250, + 48770, + 42310, + 35850, + 29370 + ] + }, + { + "from": 238, + "to": 716000, + "taxes": [ + 719000, + 68790, + 62320, + 55860, + 49390, + 42920, + 36460, + 29990 + ] + }, + { + "from": 239, + "to": 719000, + "taxes": [ + 722000, + 69410, + 62930, + 56470, + 50000, + 43540, + 37070, + 30600 + ] + }, + { + "from": 240, + "to": 722000, + "taxes": [ + 725000, + 70020, + 63550, + 57080, + 50610, + 44150, + 37690, + 31210 + ] + }, + { + "from": 241, + "to": 725000, + "taxes": [ + 728000, + 70630, + 64160, + 57700, + 51220, + 44760, + 38300, + 31820 + ] + }, + { + "from": 242, + "to": 728000, + "taxes": [ + 731000, + 71250, + 64770, + 58310, + 51840, + 45370, + 38910, + 32440 + ] + }, + { + "from": 243, + "to": 731000, + "taxes": [ + 734000, + 71860, + 65380, + 58920, + 52450, + 45990, + 39520, + 33050 + ] + }, + { + "from": 244, + "to": 734000, + "taxes": [ + 737000, + 72470, + 66000, + 59530, + 53060, + 46600, + 40140, + 33660 + ] + }, + { + "from": 245, + "to": 737000, + "taxes": [ + 740000, + 73080, + 66610, + 60150, + 53670, + 47210, + 40750, + 34270 + ] + } + ] +} \ No newline at end of file diff --git a/docs/bonus_rate_nta.xlsx b/docs/bonus_rate_nta.xlsx new file mode 100644 index 0000000..37487c9 Binary files /dev/null and b/docs/bonus_rate_nta.xlsx differ diff --git a/docs/賞与に対する源泉徴収税額の算出率の表.xls b/docs/賞与に対する源泉徴収税額の算出率の表.xls new file mode 100644 index 0000000..e4d8bc1 Binary files /dev/null and b/docs/賞与に対する源泉徴収税額の算出率の表.xls differ diff --git a/frontend/payroll-calculation.html b/frontend/payroll-calculation.html index 116e09a..7681ab7 100644 --- a/frontend/payroll-calculation.html +++ b/frontend/payroll-calculation.html @@ -2,13 +2,16 @@ + + + 給与管理 - 月次給与計算 @@ -193,9 +239,11 @@
-
-
+
+
+
+
+ +
+
- -
@@ -966,18 +1014,16 @@ : `従業員ID: ${p.employee_id}`; return `
-
+
${empLabel} ${getStatusLabel(p.status)} - 支給日: ${p.payment_date} -
-
- 差引支給額: ¥${Number(p.net_payment).toLocaleString()} - (総支給: ¥${Number(p.total_payment).toLocaleString()} - 控除: ¥${Number(p.total_deduction).toLocaleString()})
+
支給日: ${p.payment_date}
+
差引支給額: ¥${Number(p.net_payment).toLocaleString()}
+
(総支給: ¥${Number(p.total_payment).toLocaleString()} - 控除: ¥${Number(p.total_deduction).toLocaleString()})
-
@@ -1126,6 +1172,44 @@ }).length : 0; + // 計算明細表示用の変数 + const _health = Number(payroll.health_insurance || 0); + const _care = Number(payroll.care_insurance || 0); + const _pension = Number(payroll.pension_insurance || 0); + const _emp = Number(payroll.employment_insurance || 0); + const _child = Number(payroll.child_support || 0); + const _totalPay = Number(payroll.total_payment || 0); + // 標準報酬月額を厚生年金保険料(個人負担率 9.150%)から逆算 + const _stdRemun = _pension > 0 ? Math.round(_pension / 0.0915) : 0; + const _stdFmt = + _stdRemun > 0 ? "¥" + _stdRemun.toLocaleString() : "-"; + const _hRateFull = + _stdRemun > 0 + ? (((_health * 2) / _stdRemun) * 100).toFixed(2) + : "-"; + const _hRateHalf = + _stdRemun > 0 ? ((_health / _stdRemun) * 100).toFixed(2) : "-"; + const _cRateFull = + _stdRemun > 0 && _care > 0 + ? (((_care * 2) / _stdRemun) * 100).toFixed(2) + : null; + const _cRateHalf = + _stdRemun > 0 && _care > 0 + ? ((_care / _stdRemun) * 100).toFixed(2) + : null; + const _empRate = + _totalPay > 0 ? ((_emp / _totalPay) * 100).toFixed(3) : "-"; + const _csRateFull = + _stdRemun > 0 && _child > 0 + ? (((_child * 2) / _stdRemun) * 100).toFixed(3) + : null; + const _csRateHalf = + _stdRemun > 0 && _child > 0 + ? ((_child / _stdRemun) * 100).toFixed(3) + : null; + const _socialSub = _health + _care + _pension + _emp + _child; + const _taxable = _totalPay - _socialSub; + const html = `

${payroll.payroll_year}年${ payroll.payroll_month @@ -1184,35 +1268,45 @@
総支給額:¥${Number( payroll.total_payment, ).toLocaleString()}
-
健康保険:¥${Number( - payroll.health_insurance, - ).toLocaleString()}
-
介護保険:¥${Number( - payroll.care_insurance || 0, - ).toLocaleString()}
-
厚生年金:¥${Number( - payroll.pension_insurance, - ).toLocaleString()}
-
雇用保険:¥${Number( - payroll.employment_insurance, - ).toLocaleString()}
-
社会保険小計:¥${Number( - Number(payroll.health_insurance || 0) + - Number(payroll.care_insurance || 0) + - Number(payroll.pension_insurance || 0) + - Number(payroll.employment_insurance || 0), - ).toLocaleString()}
+
健康保険:¥${_health.toLocaleString()}
+
+ ${_stdFmt}(標準報酬月額)× ${_hRateFull}%(保険料率・全体)÷ 2(折半)
+ 個人負担率:${_hRateHalf}% ※協会けんぽ東京 +
+
介護保険:¥${_care.toLocaleString()}
+
+ ${ + _cRateFull + ? `${_stdFmt}(標準報酬月額)× ${_cRateFull}%(保険料率・全体)÷ 2(折半)
個人負担率:${_cRateHalf}% ※40歳以上65歳未満が対象` + : "介護保険非該当(40歳未満または65歳以上)" + } +
+
厚生年金:¥${_pension.toLocaleString()}
+
+ ${_stdFmt}(標準報酬月額)× 18.300%(保険料率・全体)÷ 2(折半)
+ 個人負担率:9.150%(固定) +
+
雇用保険:¥${_emp.toLocaleString()}
+
+ 総支給額 ¥${_totalPay.toLocaleString()} × ${_empRate}%(雇用保険料率・従業員負担分)
+ ※標準報酬でなく実際の総支給額に料率を乗じる +
+
子ども・子育て支援金:¥${_child.toLocaleString()}
+
+ ${ + _csRateFull + ? `${_stdFmt}(標準報酬月額)× ${_csRateFull}%(拠出金率・全体)÷ 2(折半)
個人負担率:${_csRateHalf}% ※令和8年5月支払分(4月分)より控除開始` + : "令和8年5月支払分(4月分保険料)より控除開始 → 当月は対象外" + } +
+
社会保険小計:¥${_socialSub.toLocaleString()}
所得税 (甲欄${dependentCount}人): - ¥${Number( - payroll.income_tax, - ).toLocaleString()} + ¥${Number(payroll.income_tax).toLocaleString()}
-
- - ※課税対象額から源泉徴収税額表(甲欄)を参照して計算
-  扶養親族${dependentCount}人(16歳以上が対象) -
+
+ 課税対象額 = 総支給額 ¥${_totalPay.toLocaleString()} − 社会保険料計 ¥${_socialSub.toLocaleString()} = ¥${_taxable.toLocaleString()}
+ → 源泉徴収税額表(甲欄・扶養${dependentCount}人)を参照して計算
住民税:¥${Number( payroll.resident_tax, @@ -1242,14 +1336,13 @@ ` : "" } - + `; document.getElementById("payrollDetail").innerHTML = html; + const splitRightSalary = document.getElementById("splitRightSalary"); + if (splitRightSalary) splitRightSalary.style.display = "block"; document.getElementById("payrollDetail").style.display = "block"; - document - .getElementById("payrollDetail") - .scrollIntoView({ behavior: "smooth" }); } catch (error) { alert("給与明細の取得に失敗しました"); console.error(error); @@ -1435,6 +1528,7 @@ if (response.ok) { alert("再計算が完了しました"); + await loadPayrolls(); viewPayroll(payrollId); } else { const error = await response.json(); @@ -1552,34 +1646,18 @@ return `
-
+
- ${b.bonus_year}年${ - b.bonus_month - }月 - ${ - b.bonus_type - } + ${b.bonus_year}年${b.bonus_month}月 + ${b.bonus_type}
-
+
${empLabel} | 支給日: ${b.payment_date}
-
- 差引支給額: ¥${Number( - b.net_bonus, - ).toLocaleString()} - (総支給: ¥${Number( - b.total_bonus, - ).toLocaleString()} - 控除: ¥${Number( - b.total_deduction || 0, - ).toLocaleString()}) -
+
差引支給額: ¥${Number(b.net_bonus).toLocaleString()}
+
(総支給: ¥${Number(b.total_bonus).toLocaleString()} - 控除: ¥${Number(b.total_deduction || 0).toLocaleString()})
-
@@ -1643,6 +1721,7 @@ const result = await response.json(); alert("賞与計算が完了しました"); closeBonusForm(); + await loadBonus(); viewBonus(result.bonus_id); } else { const error = await response.json(); @@ -1669,6 +1748,25 @@ ); const employee = await empResponse.json(); + // 計算明細表示用の変数(賞与は総支給額に料率を乗じる) + const _bHealth = Number(bonus.health_insurance || 0); + const _bCare = Number(bonus.care_insurance || 0); + const _bPension = Number(bonus.pension_insurance || 0); + const _bEmp = Number(bonus.employment_insurance || 0); + const _bChild = Number(bonus.child_support || 0); + const _bTotal = Number(bonus.total_bonus || 0); + const _bHRateFull = _bTotal > 0 && _bHealth > 0 ? (((_bHealth * 2) / _bTotal) * 100).toFixed(3) : "-"; + const _bHRateHalf = _bTotal > 0 && _bHealth > 0 ? ((_bHealth / _bTotal) * 100).toFixed(3) : "-"; + const _bCRateFull = _bTotal > 0 && _bCare > 0 ? (((_bCare * 2) / _bTotal) * 100).toFixed(3) : null; + const _bCRateHalf = _bTotal > 0 && _bCare > 0 ? ((_bCare / _bTotal) * 100).toFixed(3) : null; + const _bPRateFull = _bTotal > 0 && _bPension > 0 ? (((_bPension * 2) / _bTotal) * 100).toFixed(3) : "-"; + const _bPRateHalf = _bTotal > 0 && _bPension > 0 ? ((_bPension / _bTotal) * 100).toFixed(3) : "-"; + const _bEmpRate = _bTotal > 0 && _bEmp > 0 ? ((_bEmp / _bTotal) * 100).toFixed(3) : "-"; + const _bCSRateFull = _bTotal > 0 && _bChild > 0 ? (((_bChild * 2) / _bTotal) * 100).toFixed(4) : null; + const _bCSRateHalf = _bTotal > 0 && _bChild > 0 ? ((_bChild / _bTotal) * 100).toFixed(4) : null; + const _bSocialSub = _bHealth + _bCare + _bPension + _bEmp + _bChild; + const _bTaxable = _bTotal - _bSocialSub; + const html = `

${bonus.bonus_year}年${ bonus.bonus_month @@ -1697,27 +1795,47 @@

控除項目

-
健康保険:¥${Number( - bonus.health_insurance || 0, - ).toLocaleString()}
-
介護保険:¥${Number( - bonus.care_insurance || 0, - ).toLocaleString()}
-
厚生年金:¥${Number( - bonus.pension_insurance || 0, - ).toLocaleString()}
-
雇用保険:¥${Number( - bonus.employment_insurance || 0, - ).toLocaleString()}
-
社会保険小計:¥${Number( - Number(bonus.health_insurance || 0) + - Number(bonus.care_insurance || 0) + - Number(bonus.pension_insurance || 0) + - Number(bonus.employment_insurance || 0), - ).toLocaleString()}
+
健康保険:¥${_bHealth.toLocaleString()}
+
+ ¥${_bTotal.toLocaleString()}(賞与総支給額)× ${_bHRateFull}%(保険料率・全体)÷ 2(折半)
+ 個人負担率:${_bHRateHalf}% ※協会けんぽ東京 +
+
介護保険:¥${_bCare.toLocaleString()}
+
+ ${ + _bCRateFull + ? `¥${_bTotal.toLocaleString()}(賞与総支給額)× ${_bCRateFull}%(保険料率・全体)÷ 2(折半)
個人負担率:${_bCRateHalf}% ※40歳以上65歳未満が対象` + : "介護保険非該当(40歳未満または65歳以上)" + } +
+
厚生年金:¥${_bPension.toLocaleString()}
+
+ ¥${_bTotal.toLocaleString()}(賞与総支給額)× ${_bPRateFull}%(保険料率・全体)÷ 2(折半)
+ 個人負担率:${_bPRateHalf}%(固定) ※上限:標準賞与額150万円/月 +
+
雇用保険:¥${_bEmp.toLocaleString()}
+
+ ${_bEmp > 0 + ? `¥${_bTotal.toLocaleString()}(賞与総支給額)× ${_bEmpRate}%(雇用保険料率・従業員負担分)` + : "賞与に対する雇用保険は別途計算方式による(または0円)" + } +
+
子ども・子育て支援金:¥${_bChild.toLocaleString()}
+
+ ${ + _bCSRateFull + ? `¥${_bTotal.toLocaleString()}(賞与総支給額)× ${_bCSRateFull}%(拠出金率・全体)÷ 2(折半)
個人負担率:${_bCSRateHalf}% ※令和8年5月支払分(4月分)より控除開始` + : "令和8年5月支払分(4月分保険料)より控除開始 → 当賞与は対象外" + } +
+
社会保険小計:¥${_bSocialSub.toLocaleString()}
所得税:¥${Number( bonus.income_tax || 0, ).toLocaleString()}
+
+ 課税対象額 = 賞与総支給額 ¥${_bTotal.toLocaleString()} − 社会保険料計 ¥${_bSocialSub.toLocaleString()} = ¥${_bTaxable.toLocaleString()}
+ → 賞与に対する源泉徴収税額の算出率の表を参照して計算 +
住民税:¥${Number( bonus.resident_tax || 0, ).toLocaleString()}
@@ -1741,14 +1859,13 @@ - + `; document.getElementById("bonusDetail").innerHTML = html; + const splitRightBonus = document.getElementById("splitRightBonus"); + if (splitRightBonus) splitRightBonus.style.display = "block"; document.getElementById("bonusDetail").style.display = "block"; - document - .getElementById("bonusDetail") - .scrollIntoView({ behavior: "smooth" }); } catch (error) { alert("賞与明細の取得に失敗しました"); console.error(error); @@ -1795,6 +1912,7 @@ if (response.ok) { alert("再計算が完了しました"); + await loadBonus(); viewBonus(bonusId); } else { const error = await response.json(); diff --git a/frontend/payroll-settings.html b/frontend/payroll-settings.html index c9e2bec..bd14ee9 100644 --- a/frontend/payroll-settings.html +++ b/frontend/payroll-settings.html @@ -215,6 +215,9 @@
  • 給与計算と賞与計算で異なる料率を設定できます
  • 事業所所在地(都道府県)ごとに設定できます
  • 介護保険の適用年齢は設定可能です(デフォルト: 40歳以上)
  • +
  • 年度適用期間: 「年度」に設定した値は その年の4月〜翌年3月 に適用されます。
    + 例)2026年度設定 → 2026年4月〜2027年3月の計算に参照されます。
    + 2026年1月〜3月分は 2025年度(rate_year=2025)の料率が参照されます。
  • @@ -802,6 +805,26 @@ pensionRate: metadata.pension_rate, }; + // メタデータに料率がない場合、データから逆算する + if (rates.healthNoCareRate == null) { + const refRow = data.find(r => Number(r.monthly_amount) > 0 && Number(r.health_insurance_no_care) > 0); + if (refRow) { + const ma = Number(refRow.monthly_amount); + rates.healthNoCareRate = Number(refRow.health_insurance_no_care) / ma * 100; + rates.healthWithCareRate = Number(refRow.health_insurance_with_care) / ma * 100; + if (Number(refRow.child_support ?? 0) > 0) { + rates.childSupportRate = Number(refRow.child_support) / ma * 100; + } + } + // 厚生年金は低等級(1-3)で0になるため、pension_insurance > 0 の行を別途検索 + if (rates.pensionRate == null) { + const pensionRefRow = data.find(r => Number(r.monthly_amount) > 0 && Number(r.pension_insurance ?? 0) > 0); + if (pensionRefRow) { + rates.pensionRate = Number(pensionRefRow.pension_insurance) / Number(pensionRefRow.monthly_amount) * 100; + } + } + } + // メタデータはヘッダーに組み込むため、ここでは空にする let metadataHtml = ""; diff --git a/verify_fix.py b/verify_fix.py deleted file mode 100644 index 794a328..0000000 --- a/verify_fix.py +++ /dev/null @@ -1,123 +0,0 @@ -import psycopg -import json -from psycopg.rows import dict_row - -# 連接到数据库 -conn = psycopg.connect( - host="127.0.0.1", - port=5432, - dbname="njts_accounting", - user="postgres", - password="postgres" -) - -with conn: - with conn.cursor(row_factory=dict_row) as cur: - print("=" * 80) - print("【検証1】is_latestフィールドが存在するかどうか") - print("=" * 80) - cur.execute(""" - SELECT COUNT(*) as cnt - FROM information_schema.columns - WHERE table_name = 'journal_entries' AND column_name = 'is_latest' - """) - result = cur.fetchone() - has_is_latest = result['cnt'] > 0 - print(f"is_latest フィールドが存在: {has_is_latest}") - print() - - print("=" * 80) - print("【検証2】test元(ID=431, 432)のバージョン情報") - print("=" * 80) - cur.execute(""" - SELECT - journal_entry_id, - description, - is_latest, - is_deleted, - parent_entry_id, - original_entry_id, - revision_count, - entry_date, - created_at - FROM journal_entries - WHERE description LIKE '%test%' - ORDER BY journal_entry_id - """) - test_entries = cur.fetchall() - for entry in test_entries: - print(f"ID={entry['journal_entry_id']}: {entry['description']}") - print(f" is_latest={entry['is_latest']}, is_deleted={entry['is_deleted']}") - print(f" parent_entry_id={entry['parent_entry_id']}, original_entry_id={entry['original_entry_id']}") - print() - - print("=" * 80) - print("【検証3】修正前のロジック(親IDで排除)の結果") - print("=" * 80) - cur.execute(""" - SELECT - a.account_code, - a.account_name, - SUM(l.debit) as debit, - SUM(l.credit) as credit - FROM journal_lines l - JOIN journal_entries e ON e.journal_entry_id = l.journal_entry_id - JOIN accounts a ON a.account_id = l.account_id - WHERE e.is_deleted = false - AND e.journal_entry_id NOT IN ( - SELECT parent_entry_id - FROM journal_entries - WHERE parent_entry_id IS NOT NULL - ) - AND a.account_code = '701' - GROUP BY a.account_code, a.account_name - """) - old_logic = cur.fetchone() - if old_logic: - print(f"701売上高(旧ロジック): 借={old_logic['debit']}, 貸={old_logic['credit']}") - print() - - print("=" * 80) - print("【検証4】修正後のロジック(is_latest=trueで過濾)の結果") - print("=" * 80) - cur.execute(""" - SELECT - a.account_code, - a.account_name, - SUM(l.debit) as debit, - SUM(l.credit) as credit - FROM journal_lines l - JOIN journal_entries e ON e.journal_entry_id = l.journal_entry_id - JOIN accounts a ON a.account_id = l.account_id - WHERE e.is_deleted = false - AND e.is_latest = true - AND a.account_code = '701' - GROUP BY a.account_code, a.account_name - """) - new_logic = cur.fetchone() - if new_logic: - print(f"701売上高(新ロジック): 借={new_logic['debit']}, 貸={new_logic['credit']}") - print() - - print("=" * 80) - print("【検証5】各test要素の詳細") - print("=" * 80) - for entry in test_entries: - eid = entry['journal_entry_id'] - print(f"\n ID={eid} ({entry['description']}):") - cur.execute(""" - SELECT - a.account_code, - a.account_name, - l.debit, - l.credit - FROM journal_lines l - JOIN accounts a ON a.account_id = l.account_id - WHERE l.journal_entry_id = %s - ORDER BY a.account_code - """, (eid,)) - lines = cur.fetchall() - for line in lines: - print(f" {line['account_code']} {line['account_name']}: 借={line['debit']}, 貸={line['credit']}") - -conn.close()