Coverage for src/inheritance_calculator_core/services/heir_validator.py: 0%
91 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-17 05:31 +0900
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-17 05:31 +0900
1"""相続人資格検証サービス
3日本の民法に基づいて相続人の資格を判定するサービス。
4"""
5from typing import List, Optional
6from datetime import date
8from ..models.person import Person
9from ..models.relationship import (
10 ChildOf,
11 SpouseOf,
12 SiblingOf,
13 Renounced,
14 Disqualified,
15 Disinherited,
16 BloodType,
17)
18from ..models.inheritance import HeritageRank, SubstitutionType
19from .base import BaseService
22class HeirValidator(BaseService[Person]):
23 """
24 相続人資格検証サービス
26 相続人の資格を判定し、相続順位を確定する。
27 """
29 def __init__(self) -> None:
30 """初期化"""
31 super().__init__()
32 self.decedent: Optional[Person] = None
33 self.spouses: List[Person] = []
34 self.children: List[Person] = []
35 self.parents: List[Person] = []
36 self.siblings: List[Person] = []
37 self.renounced_persons: List[Person] = []
38 self.disqualified_persons: List[Person] = []
39 self.disinherited_persons: List[Person] = []
41 def set_decedent(self, decedent: Person) -> None:
42 """
43 被相続人を設定
45 Args:
46 decedent: 被相続人
47 """
48 if not decedent.is_decedent:
49 self.log_warning("Person is not marked as decedent", person=decedent.name)
51 self.decedent = decedent
52 self.log_operation("Set decedent", name=decedent.name)
54 def is_valid_heir(self, person: Person) -> bool:
55 """
56 相続人として有効かチェック
58 Args:
59 person: チェック対象の人物
61 Returns:
62 相続人として有効な場合True
63 """
64 if self.decedent is None:
65 raise ValueError("Decedent must be set before validating heirs")
67 # 被相続人本人は相続人になれない
68 if person.id == self.decedent.id:
69 return False
71 # 死亡している場合の判定
72 if not person.is_alive:
73 # 遺産分割前に死亡した場合は再転相続の対象として一旦有効とする
74 # (後で再転相続処理で実際の相続人に置き換える)
75 if person.died_before_division:
76 return True
77 # それ以外の死亡者は相続人になれない(代襲相続を除く)
78 return False
80 # 相続放棄している場合は相続人になれない
81 if person in self.renounced_persons:
82 self.log_info("Person has renounced inheritance", person=person.name)
83 return False
85 # 相続欠格の場合は相続人になれない(ただし代襲相続は可能)
86 if person in self.disqualified_persons:
87 self.log_info("Person is disqualified", person=person.name)
88 return False
90 # 相続廃除の場合は相続人になれない(ただし代襲相続は可能)
91 if person in self.disinherited_persons:
92 self.log_info("Person is disinherited", person=person.name)
93 return False
95 return True
97 def validate_spouse(self, spouse: Person) -> bool:
98 """
99 配偶者の相続資格を検証
101 民法890条:配偶者は常に相続人となる
103 Args:
104 spouse: 配偶者
106 Returns:
107 相続人として有効な場合True
108 """
109 if not self.is_valid_heir(spouse):
110 return False
112 # 配偶者は常に相続人(民法890条)
113 self.log_operation(
114 "Validated spouse",
115 spouse=spouse.name,
116 basis="民法890条"
117 )
118 return True
120 def validate_child(self, child: Person) -> bool:
121 """
122 子の相続資格を検証
124 民法887条1項:子は第1順位の相続人
126 Args:
127 child: 子
129 Returns:
130 相続人として有効な場合True
131 """
132 if not self.is_valid_heir(child):
133 return False
135 # 子は第1順位の相続人(民法887条1項)
136 self.log_operation(
137 "Validated child",
138 child=child.name,
139 basis="民法887条1項"
140 )
141 return True
143 def validate_parent(self, parent: Person, has_first_rank: bool) -> bool:
144 """
145 直系尊属の相続資格を検証
147 民法889条1項1号:第1順位の相続人がいない場合のみ相続
149 Args:
150 parent: 直系尊属(父母、祖父母等)
151 has_first_rank: 第1順位の相続人が存在するか
153 Returns:
154 相続人として有効な場合True
155 """
156 if not self.is_valid_heir(parent):
157 return False
159 # 第1順位の相続人がいる場合は相続できない
160 if has_first_rank:
161 self.log_info(
162 "Parent cannot inherit (first rank heirs exist)",
163 parent=parent.name
164 )
165 return False
167 # 直系尊属は第2順位の相続人(民法889条1項1号)
168 self.log_operation(
169 "Validated parent",
170 parent=parent.name,
171 basis="民法889条1項1号"
172 )
173 return True
175 def validate_sibling(
176 self,
177 sibling: Person,
178 has_first_rank: bool,
179 has_second_rank: bool
180 ) -> bool:
181 """
182 兄弟姉妹の相続資格を検証
184 民法889条1項2号:第1順位、第2順位の相続人がいない場合のみ相続
186 Args:
187 sibling: 兄弟姉妹
188 has_first_rank: 第1順位の相続人が存在するか
189 has_second_rank: 第2順位の相続人が存在するか
191 Returns:
192 相続人として有効な場合True
193 """
194 if not self.is_valid_heir(sibling):
195 return False
197 # 第1順位または第2順位の相続人がいる場合は相続できない
198 if has_first_rank or has_second_rank:
199 self.log_info(
200 "Sibling cannot inherit (higher rank heirs exist)",
201 sibling=sibling.name
202 )
203 return False
205 # 兄弟姉妹は第3順位の相続人(民法889条1項2号)
206 self.log_operation(
207 "Validated sibling",
208 sibling=sibling.name,
209 basis="民法889条1項2号"
210 )
211 return True
213 def can_substitute(
214 self,
215 deceased_heir: Person,
216 substitute: Person,
217 rank: HeritageRank
218 ) -> bool:
219 """
220 代襲相続が可能かチェック
222 民法887条2項・3項:子の代襲相続(制限なし)
223 民法889条2項:兄弟姉妹の代襲相続(1代限り)
225 Args:
226 deceased_heir: 死亡した相続人(被代襲者)
227 substitute: 代襲相続人候補
228 rank: 相続順位
230 Returns:
231 代襲相続が可能な場合True
232 """
233 if self.decedent is None:
234 raise ValueError("Decedent must be set")
236 # 代襲相続人候補が生存していなければならない
237 if not substitute.is_alive:
238 return False
240 # 被代襲者が被相続人より先に死亡しているか、
241 # 相続欠格・相続廃除されている必要がある
242 valid_substitution_reason = (
243 (deceased_heir.death_date is not None and
244 self.decedent.death_date is not None and
245 deceased_heir.death_date < self.decedent.death_date) or
246 deceased_heir in self.disqualified_persons or
247 deceased_heir in self.disinherited_persons
248 )
250 if not valid_substitution_reason:
251 return False
253 # 相続放棄は代襲原因にならない
254 if deceased_heir in self.renounced_persons:
255 self.log_info(
256 "No substitution for renounced heir",
257 deceased=deceased_heir.name
258 )
259 return False
261 # 第1順位(子)の代襲:制限なし(民法887条2項・3項)
262 if rank == HeritageRank.FIRST:
263 self.log_operation(
264 "Substitution allowed for child",
265 substitute=substitute.name,
266 deceased=deceased_heir.name,
267 basis="民法887条2項・3項"
268 )
269 return True
271 # 第3順位(兄弟姉妹)の代襲:1代限り(民法889条2項)
272 if rank == HeritageRank.THIRD:
273 # 兄弟姉妹の子(甥・姪)までのみ代襲可能
274 self.log_operation(
275 "Substitution allowed for sibling (1 generation only)",
276 substitute=substitute.name,
277 deceased=deceased_heir.name,
278 basis="民法889条2項"
279 )
280 return True
282 return False
284 def get_substitution_type(self, rank: HeritageRank) -> SubstitutionType:
285 """
286 代襲相続のタイプを取得
288 Args:
289 rank: 相続順位
291 Returns:
292 代襲相続タイプ
293 """
294 if rank == HeritageRank.FIRST:
295 return SubstitutionType.CHILD
296 elif rank == HeritageRank.THIRD:
297 return SubstitutionType.SIBLING
298 else:
299 return SubstitutionType.NONE