Coverage for src/inheritance_calculator_core/models/relationship.py: 100%

99 statements  

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

1"""関係性モデル""" 

2from datetime import date 

3from typing import Optional, Any 

4from enum import Enum 

5from uuid import UUID 

6 

7from pydantic import Field, field_validator 

8 

9from .base import Neo4jRelationship 

10 

11 

12class BloodType(str, Enum): 

13 """血縁タイプ""" 

14 FULL = "full" # 全血(父母が同じ) 

15 HALF = "half" # 半血(父または母が同じ) 

16 

17 

18class SharedParent(str, Enum): 

19 """共通の親""" 

20 BOTH = "both" # 両親とも同じ 

21 MOTHER = "mother" # 母のみ同じ 

22 FATHER = "father" # 父のみ同じ 

23 

24 

25class ChildOf(Neo4jRelationship): 

26 """ 

27 子関係(CHILD_OF) 

28 

29 子から親への関係を表現。 

30 """ 

31 

32 parent_id: UUID = Field(..., description="親のID") 

33 child_id: UUID = Field(..., description="子のID") 

34 is_adoption: bool = Field(default=False, description="養子縁組であるか") 

35 is_biological: bool = Field(default=True, description="実子であるか") 

36 adoption_date: Optional[date] = Field(default=None, description="養子縁組日") 

37 

38 @field_validator('is_biological') 

39 @classmethod 

40 def validate_biological(cls, v: bool, info: Any) -> bool: 

41 """実子フラグの検証""" 

42 # 養子の場合、実子ではない 

43 values = info.data 

44 if values.get('is_adoption', False) and v: 

45 raise ValueError("Adopted child cannot be biological") 

46 return v 

47 

48 

49class SpouseOf(Neo4jRelationship): 

50 """ 

51 配偶者関係(SPOUSE_OF) 

52 

53 配偶者間の関係を表現。 

54 """ 

55 

56 person1_id: UUID = Field(..., description="配偶者1のID") 

57 person2_id: UUID = Field(..., description="配偶者2のID") 

58 marriage_date: Optional[date] = Field(default=None, description="婚姻日") 

59 divorce_date: Optional[date] = Field(default=None, description="離婚日") 

60 is_current: bool = Field(default=True, description="現在の配偶者か") 

61 

62 @field_validator('is_current') 

63 @classmethod 

64 def validate_current(cls, v: bool, info: Any) -> bool: 

65 """現在の配偶者フラグの検証""" 

66 values = info.data 

67 # 離婚日がある場合、is_currentはFalseであるべき 

68 if values.get('divorce_date') is not None and v: 

69 raise ValueError("Divorced spouse cannot be current") 

70 return v 

71 

72 @field_validator('divorce_date') 

73 @classmethod 

74 def validate_divorce_date(cls, v: Optional[date], info: Any) -> Optional[date]: 

75 """離婚日の検証""" 

76 if v is not None: 

77 values = info.data 

78 marriage_date = values.get('marriage_date') 

79 if marriage_date is not None and v < marriage_date: 

80 raise ValueError("Divorce date cannot be before marriage date") 

81 return v 

82 

83 

84class SiblingOf(Neo4jRelationship): 

85 """ 

86 兄弟姉妹関係(SIBLING_OF) 

87 

88 兄弟姉妹間の関係を表現。 

89 """ 

90 

91 person1_id: UUID = Field(..., description="人物1のID") 

92 person2_id: UUID = Field(..., description="人物2のID") 

93 blood_type: BloodType = Field(..., description="血縁タイプ") 

94 shared_parent: SharedParent = Field(..., description="共通の親") 

95 

96 @field_validator('shared_parent') 

97 @classmethod 

98 def validate_shared_parent(cls, v: SharedParent, info: Any) -> SharedParent: 

99 """共通の親の検証""" 

100 values = info.data 

101 blood_type = values.get('blood_type') 

102 

103 # 全血の場合、両親とも同じでなければならない 

104 if blood_type == BloodType.FULL and v != SharedParent.BOTH: 

105 raise ValueError("Full blood siblings must share both parents") 

106 

107 # 半血の場合、片親のみ同じでなければならない 

108 if blood_type == BloodType.HALF and v == SharedParent.BOTH: 

109 raise ValueError("Half blood siblings cannot share both parents") 

110 

111 return v 

112 

113 

114class Renounced(Neo4jRelationship): 

115 """ 

116 相続放棄(RENOUNCED) 

117 

118 相続放棄の関係を表現。 

119 """ 

120 

121 heir_id: UUID = Field(..., description="相続人のID") 

122 decedent_id: UUID = Field(..., description="被相続人のID") 

123 renounce_date: date = Field(..., description="放棄日") 

124 reason: Optional[str] = Field(default=None, description="放棄理由") 

125 

126 @field_validator('renounce_date') 

127 @classmethod 

128 def validate_renounce_date(cls, v: date) -> date: 

129 """放棄日の検証""" 

130 from datetime import date as date_class 

131 # 未来の日付は不可 

132 if v > date_class.today(): 

133 raise ValueError("Renounce date cannot be in the future") 

134 return v 

135 

136 

137class Disqualified(Neo4jRelationship): 

138 """ 

139 相続欠格(DISQUALIFIED) 

140 

141 相続欠格の関係を表現。 

142 """ 

143 

144 heir_id: UUID = Field(..., description="相続人のID") 

145 decedent_id: UUID = Field(..., description="被相続人のID") 

146 reason: str = Field(..., description="欠格事由", min_length=1) 

147 determination_date: date = Field(..., description="確定日") 

148 

149 @field_validator('determination_date') 

150 @classmethod 

151 def validate_determination_date(cls, v: date) -> date: 

152 """確定日の検証""" 

153 from datetime import date as date_class 

154 if v > date_class.today(): 

155 raise ValueError("Determination date cannot be in the future") 

156 return v 

157 

158 

159class Disinherited(Neo4jRelationship): 

160 """ 

161 相続廃除(DISINHERITED) 

162 

163 相続廃除の関係を表現。 

164 """ 

165 

166 heir_id: UUID = Field(..., description="相続人のID") 

167 decedent_id: UUID = Field(..., description="被相続人のID") 

168 reason: str = Field(..., description="廃除事由", min_length=1) 

169 court_decision_date: date = Field(..., description="審判確定日") 

170 

171 @field_validator('court_decision_date') 

172 @classmethod 

173 def validate_court_decision_date(cls, v: date) -> date: 

174 """審判確定日の検証""" 

175 from datetime import date as date_class 

176 if v > date_class.today(): 

177 raise ValueError("Court decision date cannot be in the future") 

178 return v