Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
admin
2026-04-30 10:12:08 +09:00
parent 5026282136
commit 6669c7da77
11 changed files with 4060 additions and 295 deletions

View File

@@ -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=55月支払が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: