From f6de95afb6e3f2ecf68688e62f75998ddaa812c0 Mon Sep 17 00:00:00 2001 From: gahusb Date: Fri, 1 May 2026 10:12:21 +0900 Subject: [PATCH] =?UTF-8?q?feat(realestate):=20=EC=86=8C=EB=93=9D=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(=ED=8A=B9=EB=B3=84=EA=B3=B5=EA=B8=89=20=EC=9E=90=EA=B2=A9=20?= =?UTF-8?q?=ED=8C=90=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit income_level(도시근로자 월평균 대비 %) 필드를 활용하여 특별공급 자격 검증: - 신혼부부·생애최초: 160% 이하 (맞벌이 민간분양 상한) - 신생아: 200% 이하 (맞벌이 기준) - 청년: 140% 이하 - 다자녀·노부모부양: 소득 기준 없음 - 미입력 시 검증 생략 (기존 동작 유지) Co-Authored-By: Claude Sonnet 4.6 --- realestate-lab/app/matcher.py | 40 +++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/realestate-lab/app/matcher.py b/realestate-lab/app/matcher.py index 3ccd5be..b1699cb 100644 --- a/realestate-lab/app/matcher.py +++ b/realestate-lab/app/matcher.py @@ -54,13 +54,31 @@ _HOUSE_TYPE_MAP = { } +def _parse_income_pct(profile: Dict[str, Any]) -> float | None: + """income_level 필드를 float으로 파싱. 미입력·파싱 실패 시 None 반환.""" + raw = profile.get("income_level") or "" + try: + return float(str(raw).strip()) if str(raw).strip() else None + except ValueError: + return None + + def _check_eligible_types(profile: Dict[str, Any], ann: Dict[str, Any]) -> List[str]: - """프로필 기반으로 신청 가능한 공급유형 목록을 반환한다.""" + """프로필 기반으로 신청 가능한 공급유형 목록을 반환한다. + + 소득 기준(도시근로자 월평균소득 대비 %): + 신혼부부·생애최초: 160% 이하 (맞벌이 기준, 민간분양 상한) + 신생아: 200% 이하 (맞벌이 기준) + 청년: 140% 이하 + 다자녀·노부모: 소득 기준 없음 + income_level 미입력 시 소득 검증 생략 (혜택 부여). + """ eligible: List[str] = [] is_homeless = profile.get("is_homeless", False) is_speculative = ann.get("is_speculative_area") == "Y" required_months = 24 if is_speculative else 12 subscription_months = profile.get("subscription_months") or 0 + income_pct = _parse_income_pct(profile) # 일반공급 if is_homeless and profile.get("is_householder") and subscription_months >= required_months: @@ -68,27 +86,35 @@ def _check_eligible_types(profile: Dict[str, Any], ann: Dict[str, Any]) -> List[ elif is_homeless: eligible.append("일반2순위") - # 특별공급 — 신혼부부 - # NOTE: 소득기준 검증은 향후 구현 예정 (income_level 필드 활용) + # 특별공급 — 신혼부부 (소득 160% 이하) if profile.get("is_newlywed") and is_homeless: - eligible.append("특별-신혼부부") + if income_pct is None or income_pct <= 160: + eligible.append("특별-신혼부부") + # 특별공급 — 생애최초 (소득 160% 이하) if profile.get("is_first_home") and is_homeless: - eligible.append("특별-생애최초") + if income_pct is None or income_pct <= 160: + eligible.append("특별-생애최초") + # 특별공급 — 다자녀 (소득 기준 없음) children_count = profile.get("children_count") or 0 if children_count >= 2 and is_homeless: eligible.append("특별-다자녀") + # 특별공급 — 노부모부양 (소득 기준 없음) if profile.get("has_dependents") and is_homeless: eligible.append("특별-노부모부양") + # 특별공급 — 청년 (소득 140% 이하) age = profile.get("age") or 0 if 19 <= age <= 39 and is_homeless: - eligible.append("특별-청년") + if income_pct is None or income_pct <= 140: + eligible.append("특별-청년") + # 특별공급 — 신생아 (소득 200% 이하) if profile.get("has_newborn") and is_homeless: - eligible.append("특별-신생아") + if income_pct is None or income_pct <= 200: + eligible.append("특별-신생아") return eligible