Coverage for src/inheritance_calculator_core/services/inheritance_calculator.py: 0%

190 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-17 05:31 +0900

1"""相続計算サービス 

2 

3相続人の確定と相続割合の計算を統合して実行するサービス。 

4""" 

5from typing import List, Dict, Optional 

6from fractions import Fraction 

7 

8from ..models.person import Person 

9from ..models.relationship import BloodType 

10from ..models.inheritance import ( 

11 InheritanceResult, 

12 HeritageRank, 

13 SubstitutionType, 

14 Heir, 

15) 

16from ..utils.exceptions import RenunciationConflictError 

17from .heir_validator import HeirValidator 

18from .share_calculator import ShareCalculator 

19from .base import BaseService 

20 

21 

22class InheritanceCalculator(BaseService[InheritanceResult]): 

23 """ 

24 相続計算サービス 

25 

26 相続人の資格確定、相続割合の計算、結果の生成を統合的に実行する。 

27 """ 

28 

29 def __init__(self) -> None: 

30 """初期化""" 

31 super().__init__() 

32 self.validator = HeirValidator() 

33 self.calculator = ShareCalculator() 

34 

35 def calculate( 

36 self, 

37 decedent: Person, 

38 spouses: List[Person], 

39 children: List[Person], 

40 parents: List[Person], 

41 siblings: List[Person], 

42 renounced: Optional[List[Person]] = None, 

43 disqualified: Optional[List[Person]] = None, 

44 disinherited: Optional[List[Person]] = None, 

45 sibling_blood_types: Optional[Dict[str, BloodType]] = None, 

46 retransfer_heirs_info: Optional[Dict[str, List[Person]]] = None, 

47 retransfer_relationships: Optional[Dict[str, Dict[str, str]]] = None, 

48 second_inheritance_renounced: Optional[Dict[str, List[Person]]] = None, 

49 ) -> InheritanceResult: 

50 """ 

51 相続計算を実行 

52 

53 Args: 

54 decedent: 被相続人 

55 spouses: 配偶者候補 

56 children: 子候補 

57 parents: 直系尊属候補 

58 siblings: 兄弟姉妹候補 

59 renounced: 相続放棄者 

60 disqualified: 相続欠格者 

61 disinherited: 相続廃除者 

62 sibling_blood_types: 兄弟姉妹の血縁タイプ 

63 retransfer_heirs_info: 再転相続先の情報(相続人ID: 再転相続先リスト) 

64 retransfer_relationships: 再転相続先の関係情報(相続人ID: {人物ID: 関係タイプ}) 

65 例: {"deceased_heir_id": {"person1_id": "spouse", "person2_id": "child"}} 

66 second_inheritance_renounced: 第2次相続の放棄者情報(死亡相続人ID: 放棄者リスト) 

67 例: {"deceased_heir_id": [person1, person2]} 

68 判例により、第2次相続を放棄した者は第1次相続のみを承認できない 

69 

70 Returns: 

71 相続計算結果 

72 """ 

73 # デフォルト値の設定 

74 if renounced is None: 

75 renounced = [] 

76 if disqualified is None: 

77 disqualified = [] 

78 if disinherited is None: 

79 disinherited = [] 

80 if sibling_blood_types is None: 

81 sibling_blood_types = {} 

82 if retransfer_heirs_info is None: 

83 retransfer_heirs_info = {} 

84 if retransfer_relationships is None: 

85 retransfer_relationships = {} 

86 if second_inheritance_renounced is None: 

87 second_inheritance_renounced = {} 

88 

89 # バリデータの初期化 

90 self.validator.set_decedent(decedent) 

91 self.validator.renounced_persons = renounced 

92 self.validator.disqualified_persons = disqualified 

93 self.validator.disinherited_persons = disinherited 

94 

95 # 結果オブジェクトの作成 

96 result = InheritanceResult(decedent=decedent) 

97 

98 # 各順位の相続人を確定 

99 valid_spouses = self._validate_spouses(spouses, result) 

100 valid_children = self._validate_children(children, result) 

101 valid_parents = self._validate_parents(parents, result, bool(valid_children)) 

102 valid_siblings = self._validate_siblings( 

103 siblings, result, bool(valid_children), bool(valid_parents) 

104 ) 

105 

106 # 相続割合を計算 

107 shares = self.calculator.calculate_shares( 

108 valid_spouses, 

109 valid_children, 

110 valid_parents, 

111 valid_siblings, 

112 sibling_blood_types 

113 ) 

114 

115 # 相続人を結果に追加 

116 self._add_heirs_to_result( 

117 result, 

118 valid_spouses, 

119 valid_children, 

120 valid_parents, 

121 valid_siblings, 

122 shares 

123 ) 

124 

125 # フラグを設定 

126 result.has_spouse = len(valid_spouses) > 0 

127 result.has_children = len(valid_children) > 0 

128 result.has_parents = len(valid_parents) > 0 

129 result.has_siblings = len(valid_siblings) > 0 

130 

131 # 再転相続の処理 

132 if retransfer_heirs_info: 

133 all_persons = spouses + children + parents + siblings 

134 result = self._process_retransfer_inheritance_with_info( 

135 result, retransfer_heirs_info, retransfer_relationships, second_inheritance_renounced 

136 ) 

137 

138 self.log_operation( 

139 "Inheritance calculation completed", 

140 total_heirs=result.total_heirs 

141 ) 

142 

143 return result 

144 

145 def _validate_spouses( 

146 self, spouses: List[Person], result: InheritanceResult 

147 ) -> List[Person]: 

148 """配偶者の資格検証""" 

149 valid_spouses = [] 

150 for spouse in spouses: 

151 if self.validator.validate_spouse(spouse): 

152 valid_spouses.append(spouse) 

153 result.add_calculation_basis("民法890条(配偶者の相続権)") 

154 

155 return valid_spouses 

156 

157 def _validate_children( 

158 self, children: List[Person], result: InheritanceResult 

159 ) -> List[Person]: 

160 """子の資格検証""" 

161 valid_children = [] 

162 for child in children: 

163 if self.validator.validate_child(child): 

164 valid_children.append(child) 

165 

166 if valid_children: 

167 result.add_calculation_basis("民法887条1項(子の相続権)") 

168 

169 return valid_children 

170 

171 def _validate_parents( 

172 self, 

173 parents: List[Person], 

174 result: InheritanceResult, 

175 has_first_rank: bool 

176 ) -> List[Person]: 

177 """直系尊属の資格検証""" 

178 valid_parents = [] 

179 for parent in parents: 

180 if self.validator.validate_parent(parent, has_first_rank): 

181 valid_parents.append(parent) 

182 

183 if valid_parents: 

184 result.add_calculation_basis("民法889条1項1号(直系尊属の相続権)") 

185 

186 return valid_parents 

187 

188 def _validate_siblings( 

189 self, 

190 siblings: List[Person], 

191 result: InheritanceResult, 

192 has_first_rank: bool, 

193 has_second_rank: bool 

194 ) -> List[Person]: 

195 """兄弟姉妹の資格検証""" 

196 valid_siblings = [] 

197 for sibling in siblings: 

198 if self.validator.validate_sibling( 

199 sibling, has_first_rank, has_second_rank 

200 ): 

201 valid_siblings.append(sibling) 

202 

203 if valid_siblings: 

204 result.add_calculation_basis("民法889条1項2号(兄弟姉妹の相続権)") 

205 

206 return valid_siblings 

207 

208 def _add_heirs_to_result( 

209 self, 

210 result: InheritanceResult, 

211 spouses: List[Person], 

212 children: List[Person], 

213 parents: List[Person], 

214 siblings: List[Person], 

215 shares: Dict[str, Fraction] 

216 ) -> None: 

217 """相続人を結果に追加""" 

218 # 配偶者 

219 for spouse in spouses: 

220 share = shares.get(str(spouse.id), Fraction(0, 1)) 

221 result.add_heir(spouse, HeritageRank.SPOUSE, share) 

222 

223 # 子 

224 for child in children: 

225 share = shares.get(str(child.id), Fraction(0, 1)) 

226 result.add_heir(child, HeritageRank.FIRST, share) 

227 

228 # 直系尊属 

229 for parent in parents: 

230 share = shares.get(str(parent.id), Fraction(0, 1)) 

231 result.add_heir(parent, HeritageRank.SECOND, share) 

232 

233 # 兄弟姉妹 

234 for sibling in siblings: 

235 share = shares.get(str(sibling.id), Fraction(0, 1)) 

236 result.add_heir(sibling, HeritageRank.THIRD, share) 

237 

238 # 相続分の計算根拠を追加 

239 if spouses and children: 

240 result.add_calculation_basis("民法900条1号(配偶者1/2、子1/2)") 

241 elif spouses and parents: 

242 result.add_calculation_basis("民法900条2号(配偶者2/3、直系尊属1/3)") 

243 elif spouses and siblings: 

244 result.add_calculation_basis("民法900条3号(配偶者3/4、兄弟姉妹1/4)") 

245 

246 def _process_retransfer_inheritance_with_info( 

247 self, 

248 result: InheritanceResult, 

249 retransfer_info: Dict[str, List[Person]], 

250 retransfer_relationships: Dict[str, Dict[str, str]], 

251 second_inheritance_renounced: Dict[str, List[Person]] 

252 ) -> InheritanceResult: 

253 """ 

254 再転相続の処理(情報付き版) 

255 

256 Args: 

257 result: 現在の相続計算結果 

258 retransfer_info: 再転相続先の情報(相続人ID: 再転相続先リスト) 

259 retransfer_relationships: 再転相続先の関係情報(相続人ID: {人物ID: 関係タイプ}) 

260 second_inheritance_renounced: 第2次相続の放棄者情報(死亡相続人ID: 放棄者リスト) 

261 

262 Returns: 

263 再転相続処理後の相続計算結果 

264 """ 

265 # 遺産分割前に死亡した相続人を特定 

266 retransfer_heirs = [ 

267 heir for heir in result.heirs 

268 if heir.person.died_before_division and not heir.person.is_alive 

269 ] 

270 

271 if not retransfer_heirs: 

272 return result 

273 

274 # 再転相続が発生した旨を記録 

275 result.add_calculation_basis("民法第896条(相続人の相続、再転相続)") 

276 

277 new_heirs = [] 

278 

279 # 再転相続が発生しない相続人をそのまま追加 

280 for heir in result.heirs: 

281 if not heir.person.died_before_division: 

282 new_heirs.append(heir) 

283 

284 # 再転相続の処理 

285 for original_heir in retransfer_heirs: 

286 heir_id = str(original_heir.person.id) 

287 retransfer_targets = retransfer_info.get(heir_id, []) 

288 

289 if not retransfer_targets: 

290 # 再転相続先がいない場合は元の相続人をそのまま 

291 new_heirs.append(original_heir) 

292 continue 

293 

294 # 判例制約の検証: 第2次相続を放棄した者が第1次相続の再転相続先に含まれていないか 

295 self._validate_retransfer_renunciation( 

296 result.decedent, 

297 original_heir.person, 

298 retransfer_targets, 

299 second_inheritance_renounced.get(heir_id, []) 

300 ) 

301 

302 # 再転相続先を相続順位別に分類 

303 # retransfer_relationships から該当する相続人の関係情報を取得 

304 relationship_hints = retransfer_relationships.get(heir_id, None) 

305 

306 classified_heirs = self._classify_retransfer_heirs( 

307 retransfer_targets, 

308 original_heir.person, 

309 relationship_hints 

310 ) 

311 

312 # 再転相続分を計算(法定相続分に基づく) 

313 retransfer_shares = self._calculate_retransfer_shares_classified( 

314 original_heir.share, 

315 classified_heirs 

316 ) 

317 

318 # 再転相続人を追加 

319 for target, share in retransfer_shares: 

320 new_heir = Heir( 

321 person=target, 

322 rank=original_heir.rank, 

323 share=share, 

324 share_percentage=float(share) * 100, 

325 is_retransfer=True, 

326 retransfer_from=original_heir.person, 

327 original_share=original_heir.share 

328 ) 

329 new_heirs.append(new_heir) 

330 

331 # 相続人リストを更新 

332 result.heirs = new_heirs 

333 

334 return result 

335 

336 def _process_retransfer_inheritance( 

337 self, 

338 result: InheritanceResult, 

339 all_persons: List[Person] 

340 ) -> InheritanceResult: 

341 """ 

342 再転相続の処理 

343 

344 遺産分割前に死亡した相続人がいる場合、 

345 その相続分をその相続人の相続人に再転相続させる。 

346 

347 Args: 

348 result: 現在の相続計算結果 

349 all_persons: 再転相続先の候補となる全人物リスト 

350 

351 Returns: 

352 再転相続処理後の相続計算結果 

353 """ 

354 # 遺産分割前に死亡した相続人を特定 

355 retransfer_heirs = [ 

356 heir for heir in result.heirs 

357 if heir.person.died_before_division and not heir.person.is_alive 

358 ] 

359 

360 if not retransfer_heirs: 

361 return result 

362 

363 # 再転相続が発生した旨を記録 

364 result.add_calculation_basis("民法第896条(相続人の相続、再転相続)") 

365 

366 new_heirs = [] 

367 

368 # 再転相続が発生しない相続人をそのまま追加 

369 for heir in result.heirs: 

370 if not heir.person.died_before_division: 

371 new_heirs.append(heir) 

372 

373 # 再転相続の処理 

374 for original_heir in retransfer_heirs: 

375 # この相続人の相続人を探す 

376 retransfer_targets = self._find_retransfer_heirs( 

377 original_heir.person, 

378 all_persons 

379 ) 

380 

381 if not retransfer_targets: 

382 # 再転相続先がいない場合は元の相続人をそのまま 

383 new_heirs.append(original_heir) 

384 continue 

385 

386 # 再転相続分を計算 

387 retransfer_shares = self._calculate_retransfer_shares( 

388 original_heir.share, 

389 retransfer_targets 

390 ) 

391 

392 # 再転相続人を追加 

393 for target, share in retransfer_shares: 

394 new_heir = Heir( 

395 person=target, 

396 rank=original_heir.rank, 

397 share=share, 

398 share_percentage=float(share) * 100, 

399 is_retransfer=True, 

400 retransfer_from=original_heir.person, 

401 original_share=original_heir.share 

402 ) 

403 new_heirs.append(new_heir) 

404 

405 # 相続人リストを更新 

406 result.heirs = new_heirs 

407 

408 return result 

409 

410 def _find_retransfer_heirs( 

411 self, 

412 deceased_heir: Person, 

413 all_persons: List[Person] 

414 ) -> List[Person]: 

415 """ 

416 再転相続先の相続人を探す 

417 

418 Args: 

419 deceased_heir: 遺産分割前に死亡した相続人 

420 all_persons: 全人物リスト 

421 

422 Returns: 

423 再転相続先の相続人リスト 

424 """ 

425 # 簡易実装: 配偶者と子を再転相続先とする 

426 # 実際にはHeirValidatorを使って正確に判定すべき 

427 retransfer_heirs = [] 

428 

429 for person in all_persons: 

430 if person.is_alive and person.id != deceased_heir.id: 

431 # この実装では、配偶者・子・親などの関係を 

432 # 外部から渡される必要がある 

433 # 簡易実装として、すべての生存者を候補とする 

434 retransfer_heirs.append(person) 

435 

436 return retransfer_heirs 

437 

438 def _validate_retransfer_renunciation( 

439 self, 

440 decedent: Person, 

441 deceased_heir: Person, 

442 retransfer_targets: List[Person], 

443 second_inheritance_renounced: List[Person] 

444 ) -> None: 

445 """ 

446 再転相続における相続放棄の制約を検証 

447 

448 判例(最高裁昭和63年6月21日判決)により、再転相続において 

449 第2次相続(相続人の相続)を放棄した者は、第1次相続(被相続人の相続) 

450 のみを承認することはできない。 

451 

452 Args: 

453 decedent: 被相続人(第1次相続の被相続人) 

454 deceased_heir: 遺産分割前に死亡した相続人(第2次相続の被相続人) 

455 retransfer_targets: 再転相続先(第1次相続を承認しようとしている者) 

456 second_inheritance_renounced: 第2次相続の放棄者リスト 

457 

458 Raises: 

459 RenunciationConflictError: 第2次相続を放棄した者が第1次相続を承認しようとしている場合 

460 """ 

461 for renounced_person in second_inheritance_renounced: 

462 if renounced_person in retransfer_targets: 

463 raise RenunciationConflictError( 

464 f"{renounced_person.name}{deceased_heir.name}の相続を放棄しているため、" 

465 f"{decedent.name}の相続のみを承認することはできません " 

466 f"(最高裁昭和63年6月21日判決)。\n" 

467 f"再転相続においては、第2次相続を放棄した者は第1次相続のみを単独で承認できません。" 

468 ) 

469 

470 def _classify_retransfer_heirs( 

471 self, 

472 retransfer_targets: List[Person], 

473 deceased_heir: Person, 

474 relationship_hints: Optional[Dict[str, str]] = None 

475 ) -> Dict[str, List[Person]]: 

476 """ 

477 再転相続先を相続順位別に分類 

478 

479 relationship_hintsが提供されている場合は、それを使用して分類する。 

480 提供されていない場合は、暫定的に全員を子として扱う(後方互換性)。 

481 

482 Args: 

483 retransfer_targets: 再転相続先のリスト 

484 deceased_heir: 遺産分割前に死亡した相続人 

485 relationship_hints: 人物IDから関係タイプへのマッピング 

486 キー: 人物ID(str(person.id)) 

487 値: 'spouse' | 'child' | 'parent' | 'sibling' 

488 

489 Returns: 

490 相続順位別の分類 {'spouses': [...], 'children': [...], ...} 

491 """ 

492 classified: Dict[str, List[Person]] = { 

493 'spouses': [], 

494 'children': [], 

495 'parents': [], 

496 'siblings': [] 

497 } 

498 

499 # relationship_hintsが提供されていない場合は全員を子として扱う(後方互換性) 

500 if relationship_hints is None: 

501 classified['children'] = retransfer_targets 

502 return classified 

503 

504 # relationship_hintsを使って分類 

505 for person in retransfer_targets: 

506 person_id = str(person.id) 

507 relationship = relationship_hints.get(person_id, 'child') # デフォルトは子 

508 

509 if relationship == 'spouse': 

510 classified['spouses'].append(person) 

511 elif relationship == 'child': 

512 classified['children'].append(person) 

513 elif relationship == 'parent': 

514 classified['parents'].append(person) 

515 elif relationship == 'sibling': 

516 classified['siblings'].append(person) 

517 else: 

518 # 不明な関係タイプの場合は子として扱う 

519 classified['children'].append(person) 

520 

521 return classified 

522 

523 def _calculate_retransfer_shares_classified( 

524 self, 

525 original_share: Fraction, 

526 classified_heirs: Dict[str, List[Person]] 

527 ) -> List[tuple[Person, Fraction]]: 

528 """ 

529 分類済み再転相続先の相続分を計算(民法第896条に基づく) 

530 

531 遺産分割前に死亡した相続人の相続分を、その相続人の法定相続人に 

532 法定相続分に従って分配する。 

533 

534 計算フロー: 

535 1. 分類済みの相続人リストを使用 

536 2. ShareCalculatorで法定相続分を計算 

537 3. 元の相続分に法定相続分を乗じて最終的な相続分を算出 

538 

539 Args: 

540 original_share: 元の相続分(遺産分割前に死亡した相続人の相続分) 

541 classified_heirs: 相続順位別に分類された再転相続先 

542 

543 Returns: 

544 各再転相続人と相続分のタプルのリスト 

545 

546 Example: 

547 元の相続分が1/1で、配偶者1人・子2人の場合: 

548 - 配偶者: 1/1 × 1/2 = 1/2(民法900条1号) 

549 - 子1: 1/1 × 1/4 = 1/4(民法900条1号) 

550 - 子2: 1/1 × 1/4 = 1/4(民法900条1号) 

551 """ 

552 spouses = classified_heirs.get('spouses', []) 

553 children = classified_heirs.get('children', []) 

554 parents = classified_heirs.get('parents', []) 

555 siblings = classified_heirs.get('siblings', []) 

556 

557 # 再転相続先がいない場合 

558 if not (spouses or children or parents or siblings): 

559 return [] 

560 

561 # ShareCalculatorを使って法定相続分を計算 

562 statutory_shares = self.calculator.calculate_shares( 

563 spouses=spouses, 

564 first_rank=children, 

565 second_rank=parents, 

566 third_rank=siblings, 

567 third_rank_blood_types={} # TODO: 必要に応じて血縁タイプ情報を渡す 

568 ) 

569 

570 # 元の相続分を法定相続分で按分 

571 result = [] 

572 all_heirs = spouses + children + parents + siblings 

573 for person in all_heirs: 

574 person_id = str(person.id) 

575 if person_id in statutory_shares: 

576 # 元の相続分 × 再転相続先の法定相続分 

577 final_share = original_share * statutory_shares[person_id] 

578 result.append((person, final_share)) 

579 

580 return result 

581 

582 def _calculate_retransfer_shares( 

583 self, 

584 original_share: Fraction, 

585 retransfer_targets: List[Person] 

586 ) -> List[tuple[Person, Fraction]]: 

587 """ 

588 再転相続分を計算(後方互換性のためのラッパー) 

589 

590 Args: 

591 original_share: 元の相続分 

592 retransfer_targets: 再転相続先のリスト 

593 

594 Returns: 

595 各再転相続人と相続分のタプルのリスト 

596 """ 

597 # 暫定的な分類(全員を子として扱う) 

598 classified: Dict[str, List[Person]] = { 

599 'spouses': [], 

600 'children': retransfer_targets, 

601 'parents': [], 

602 'siblings': [] 

603 } 

604 return self._calculate_retransfer_shares_classified(original_share, classified)