From 9c6f16e4b25e225aefb23833a9d9bdc34d7216a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=84=B1=EC=98=81?= Date: Thu, 11 Dec 2025 17:39:23 +0900 Subject: [PATCH] =?UTF-8?q?###=20feat:=20=EB=AA=85=EC=9D=98=EC=9D=B4?= =?UTF-8?q?=EC=A0=84=EC=9D=BC=EC=9E=90=20=EB=B0=8F=20=EA=B2=80=EC=82=AC?= =?UTF-8?q?=EC=9D=BC=20=EB=B9=84=EA=B5=90=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - **명의이전일자 ~ 검사일 계산 조건 보완** - `명의이전일자 < 검사종료일` 조건을 추가하여 검사종료일에 따른 비교 로직 세분화. - 검사일과 명의이전일자 간 기준 일수 비교 조건 명확화: - 검사종료일 기준 조건 추가. - 명의이전일자가 검사일 내 포함되는지 확인 로직 개선. - **적용 대상** - `OwnerCloseWithin31Checker` - `OwnerLevyOver31Checker` - `ProductCloseWithin31Checker` - `ProductLevyOver31Checker` - **로그 레벨 조정** - `TransferOmChecker` 관련 `log.debug`를 `log.info`로 변경하여 로그 가시성 강화. - **문서 업데이트** - `자동차과태료_비교로직_정리-[지연].md`에 관련 변경사항 반영: - 명의이전일자 비교 기준 및 로직 설명 수정. - **기타** - 중복 코드 제거 및 가독성을 위한 리팩토링. - 검사일자의 파싱 처리 및 최신 명의이전일자 계산 로직 정리. --- docs/자동차과태료_비교로직_정리-[지연].md | 2 +- .../OwnerCloseWithin31Checker.java | 32 ++++++++++++------- .../delay_checker/OwnerLevyOver31Checker.java | 32 ++++++++++++------- .../ProductCloseWithin31Checker.java | 27 ++++++++++++---- .../ProductLevyOver31Checker.java | 27 ++++++++++++---- .../impl/om_checker/TransferOmChecker.java | 14 ++++---- 6 files changed, 90 insertions(+), 44 deletions(-) diff --git a/docs/자동차과태료_비교로직_정리-[지연].md b/docs/자동차과태료_비교로직_정리-[지연].md index f4abe3d..48a5131 100644 --- a/docs/자동차과태료_비교로직_정리-[지연].md +++ b/docs/자동차과태료_비교로직_정리-[지연].md @@ -12,7 +12,7 @@ - `OwnerCloseWithin31Checker.java` - 3. 내사종결(순수 명의이전, 31일 이내) : 명의이전(25.8.28.) - `ProductLevyOver31Checker.java` - 4. 날짜수정후부과(명의이전 이전소유자 상품용, 31일 초과) : 경기도 고양시/ 장준혁, 미수검명의이전(25.8.19.) - `OwnerLevyOver31Checker.java` - 5. 날짜수정후부과(순수 명의이전, 31일 초과) : 대구광역시 달서구/ 하나캐피탈(주), 미수검명의이전(25.9.3.) - - `TransferCase115DayChecker.java` - 6. 이첩 : 경상남도 창원시/ 현대캐피탈 주식회사, 115일 도래지, 인천광역시 부평구/ (주)우리카드, 검사일사용본거지 + - `TransferCase115DayChecker.java` - 6. 이첩 : case 1 = 경상남도 창원시/ 현대캐피탈 주식회사, 115일 도래지 case 2 = 인천광역시 부평구/ (주)우리카드, 검사일사용본거지 ### 기본 설정 - 비교로직에 사용되는 API: `ExternalVehicleApiServiceImpl.getBasicInfo`, `getLedgerInfo` 호출 diff --git a/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/OwnerCloseWithin31Checker.java b/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/OwnerCloseWithin31Checker.java index 9f1a9f4..360b38a 100644 --- a/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/OwnerCloseWithin31Checker.java +++ b/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/OwnerCloseWithin31Checker.java @@ -119,6 +119,7 @@ public class OwnerCloseWithin31Checker extends AbstractComparisonChecker { LocalDate vldPrdExpryDateMinus90 = vldPrdExpryDate.minusDays(90); LocalDate inspEndDate = DateUtil.parseDate(inspEndYmd); LocalDate latestChgDate = null; + LocalDate inspDate = DateUtil.parseDate(inspYmd); for (NewLedgerResponse.Record record : ledgerRecords) { String chgYmd = record.getChgYmd(); @@ -156,19 +157,28 @@ public class OwnerCloseWithin31Checker extends AbstractComparisonChecker { log.info("[내사종결-명의이전] 검사기간 내 명의이전 발견! 변경일자: {}, 변경업무: {}", targetChgYmd, targetRecord.getChgTaskSeNm()); // ========== 명의이전일자 ~ 검사일 사이의 일수 계산 ========== - LocalDate chgDate = DateUtil.parseDate(targetChgYmd); - LocalDate inspDate = DateUtil.parseDate(inspYmd); - long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(chgDate, inspDate); - - if (daysBetween < 0 || daysBetween > DAYS_THRESHOLD) { - log.debug("[내사종결-명의이전] 명의이전일자가 검사일의 {}일 이내가 아님 - 변경일자: {}, 검사일: {}, 일수차이: {}일", - DAYS_THRESHOLD, targetChgYmd, inspYmd, daysBetween); - return null; + // 명의이전일자 < 검사종료일 + long daysBetween = 0; + if (latestChgDate.isBefore(inspEndDate)) { + // 검사일 - 검사종료일 + daysBetween = java.time.temporal.ChronoUnit.DAYS.between(inspEndDate, inspDate); + if (daysBetween < 0 || daysBetween > DAYS_THRESHOLD) { + log.debug("[내사종결-명의이전] 명의이전일자가 검사일의 {}일 이내가 아님 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); + return null; + } + } else { + // 조건: 가장 마지막 명의이전일자가 검사일의 기준일수 이내인지 확인, (검사일자 - 마지막 명의이전일자) + daysBetween = java.time.temporal.ChronoUnit.DAYS.between(latestChgDate, inspDate); + if (daysBetween < 0 || daysBetween > DAYS_THRESHOLD) { + log.debug("[내사종결-명의이전] 명의이전일자가 검사일의 {}일 이내가 아님 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); + return null; + } + log.info("[내사종결-명의이전] 명의이전일자가 검사일의 {}일 이내 확인 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); } - log.info("[내사종결-명의이전] 명의이전일자가 검사일의 {}일 이내 확인 - 변경일자: {}, 검사일: {}, 일수차이: {}일", - DAYS_THRESHOLD, targetChgYmd, inspYmd, daysBetween); - // ========== Step 4: 자동차기본정보 조회 (차대번호, 부과일자=CHG_YMD) ========== LocalDate targetDate = DateUtil.parseDate(targetChgYmd); NewBasicRequest step4Request = createBasicRequest(null, vin, targetDate.format(DATE_FORMATTER)); diff --git a/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/OwnerLevyOver31Checker.java b/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/OwnerLevyOver31Checker.java index a2c0a21..0efd81a 100644 --- a/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/OwnerLevyOver31Checker.java +++ b/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/OwnerLevyOver31Checker.java @@ -119,6 +119,7 @@ public class OwnerLevyOver31Checker extends AbstractComparisonChecker { LocalDate vldPrdExpryDateMinus90 = vldPrdExpryDate.minusDays(90); LocalDate inspEndDate = DateUtil.parseDate(inspEndYmd); LocalDate latestChgDate = null; + LocalDate inspDate = DateUtil.parseDate(inspYmd); for (NewLedgerResponse.Record record : ledgerRecords) { String chgYmd = record.getChgYmd(); @@ -156,19 +157,28 @@ public class OwnerLevyOver31Checker extends AbstractComparisonChecker { log.info("[날짜수정후부과-명의이전] 검사기간 내 명의이전 발견! 변경일자: {}, 변경업무: {}", targetChgYmd, targetRecord.getChgTaskSeNm()); // ========== 명의이전일자 ~ 검사일 사이의 일수 계산 ========== - LocalDate chgDate = DateUtil.parseDate(targetChgYmd); - LocalDate inspDate = DateUtil.parseDate(inspYmd); - long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(chgDate, inspDate); - - if (daysBetween <= DAYS_THRESHOLD) { - log.debug("[날짜수정후부과-명의이전] 명의이전일자가 검사일의 {}일 이내임 - 변경일자: {}, 검사일: {}, 일수차이: {}일", - DAYS_THRESHOLD, targetChgYmd, inspYmd, daysBetween); - return null; + // 명의이전일자 < 검사종료일 + long daysBetween = 0; + if (latestChgDate.isBefore(inspEndDate)) { + // 검사일 - 검사종료일 + daysBetween = java.time.temporal.ChronoUnit.DAYS.between(inspEndDate, inspDate); + if (daysBetween <= DAYS_THRESHOLD) { + log.debug("[날짜수정후부과-명의이전] 명의이전일자가 검사일의 {}일 이내임 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); + return null; + } + } else { + // 조건: 가장 마지막 명의이전일자가 검사일의 기준일수 초과인지 확인, (검사일자 - 마지막 명의이전일자) + daysBetween = java.time.temporal.ChronoUnit.DAYS.between(latestChgDate, inspDate); + if (daysBetween <= DAYS_THRESHOLD) { + log.debug("[날짜수정후부과-명의이전] 명의이전일자가 검사일의 {}일 이내임 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); + return null; + } + log.info("[날짜수정후부과-명의이전] 명의이전일자가 검사일의 {}일 초과 확인 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); } - log.info("[날짜수정후부과-명의이전] 명의이전일자가 검사일의 {}일 초과 확인 - 변경일자: {}, 검사일: {}, 일수차이: {}일", - DAYS_THRESHOLD, targetChgYmd, inspYmd, daysBetween); - // ========== Step 4: 자동차기본정보 조회 (차대번호, 부과일자=CHG_YMD) ========== LocalDate targetDate = DateUtil.parseDate(targetChgYmd); NewBasicRequest step4Request = createBasicRequest(null, vin, targetDate.format(DATE_FORMATTER)); diff --git a/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/ProductCloseWithin31Checker.java b/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/ProductCloseWithin31Checker.java index 6985b7b..1413c4d 100644 --- a/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/ProductCloseWithin31Checker.java +++ b/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/ProductCloseWithin31Checker.java @@ -151,15 +151,28 @@ public class ProductCloseWithin31Checker extends AbstractComparisonChecker { return null; } - // 조건: 가장 마지막 명의이전일자가 검사일의 기준일수 이내인지 확인 - long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(latestChgDate, inspDate); - if (daysBetween < 0 || daysBetween > DAYS_THRESHOLD) { - log.debug("[내사종결-명의이전 상품용] 명의이전일자가 검사일의 {}일 이내가 아님 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + // 명의이전일자 < 검사종료일 + long daysBetween = 0; + LocalDate inspEndDate = DateUtil.parseDate(inspEndYmd); + if (latestChgDate.isBefore(inspEndDate)) { + // 검사일 - 검사종료일 + daysBetween = java.time.temporal.ChronoUnit.DAYS.between(inspEndDate, inspDate); + if (daysBetween < 0 || daysBetween > DAYS_THRESHOLD) { + log.debug("[날짜수정후부과-명의이전 상품용] 명의이전일자가 검사일의 {}일 이내임 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); + return null; + } + } else { + // 조건: 가장 마지막 명의이전일자가 검사일의 기준일수 초과인지 확인, (검사일자 - 마지막 명의이전일자) + daysBetween = java.time.temporal.ChronoUnit.DAYS.between(latestChgDate, inspDate); + if (daysBetween < 0 || daysBetween > DAYS_THRESHOLD) { + log.debug("[날짜수정후부과-명의이전 상품용] 명의이전일자가 검사일의 {}일 이내임 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); + return null; + } + log.info("[날짜수정후부과-명의이전 상품용] 명의이전일자가 검사일의 {}일 초과 확인 - 변경일자: {}, 검사일: {}, 일수차이: {}일", DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); - return null; } - log.info("[내사종결-명의이전 상품용] 명의이전일자가 검사일의 {}일 이내 확인 - 변경일자: {}, 검사일: {}, 일수차이: {}일", - DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); String targetChgYmd = targetRecord.getChgYmd(); log.info("[내사종결-명의이전 상품용] 조건 충족 레코드 선택! 변경일자: {}, 변경업무: {}", targetChgYmd, targetRecord.getChgTaskSeNm()); diff --git a/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/ProductLevyOver31Checker.java b/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/ProductLevyOver31Checker.java index 1449ce7..f3887db 100644 --- a/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/ProductLevyOver31Checker.java +++ b/src/main/java/go/kr/project/carInspectionPenalty/registration/service/impl/delay_checker/ProductLevyOver31Checker.java @@ -151,15 +151,28 @@ public class ProductLevyOver31Checker extends AbstractComparisonChecker { return null; } - // 조건: 가장 마지막 명의이전일자가 검사일의 기준일수 초과인지 확인 - long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(latestChgDate, inspDate); - if (daysBetween <= DAYS_THRESHOLD) { - log.debug("[날짜수정후부과-명의이전 상품용] 명의이전일자가 검사일의 {}일 이내임 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + // 명의이전일자 < 검사종료일 + long daysBetween = 0; + LocalDate inspEndDate = DateUtil.parseDate(inspEndYmd); + if (latestChgDate.isBefore(inspEndDate)) { + // 검사일 - 검사종료일 + daysBetween = java.time.temporal.ChronoUnit.DAYS.between(inspEndDate, inspDate); + if (daysBetween <= DAYS_THRESHOLD) { + log.debug("[날짜수정후부과-명의이전 상품용] 명의이전일자가 검사일의 {}일 이내임 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); + return null; + } + } else { + // 조건: 가장 마지막 명의이전일자가 검사일의 기준일수 초과인지 확인, (검사일자 - 마지막 명의이전일자) + daysBetween = java.time.temporal.ChronoUnit.DAYS.between(latestChgDate, inspDate); + if (daysBetween <= DAYS_THRESHOLD) { + log.debug("[날짜수정후부과-명의이전 상품용] 명의이전일자가 검사일의 {}일 이내임 - 변경일자: {}, 검사일: {}, 일수차이: {}일", + DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); + return null; + } + log.info("[날짜수정후부과-명의이전 상품용] 명의이전일자가 검사일의 {}일 초과 확인 - 변경일자: {}, 검사일: {}, 일수차이: {}일", DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); - return null; } - log.info("[날짜수정후부과-명의이전 상품용] 명의이전일자가 검사일의 {}일 초과 확인 - 변경일자: {}, 검사일: {}, 일수차이: {}일", - DAYS_THRESHOLD, targetRecord.getChgYmd(), inspYmd, daysBetween); String targetChgYmd = targetRecord.getChgYmd(); log.info("[날짜수정후부과] 조건 충족 레코드 선택! 변경일자: {}, 변경업무: {}", targetChgYmd, targetRecord.getChgTaskSeNm()); diff --git a/src/main/java/go/kr/project/carInspectionPenalty/registrationOm/service/impl/om_checker/TransferOmChecker.java b/src/main/java/go/kr/project/carInspectionPenalty/registrationOm/service/impl/om_checker/TransferOmChecker.java index 4ecea37..52e3113 100644 --- a/src/main/java/go/kr/project/carInspectionPenalty/registrationOm/service/impl/om_checker/TransferOmChecker.java +++ b/src/main/java/go/kr/project/carInspectionPenalty/registrationOm/service/impl/om_checker/TransferOmChecker.java @@ -60,7 +60,7 @@ public class TransferOmChecker extends AbstractComparisonOmChecker { } if (inspVldPrdEnd == null) { - log.debug("[이첩-미필] 검사유효기간 종료일 없음 - 차량번호: {}", vhclno); + log.info("[이첩-미필] 검사유효기간 종료일 없음 - 차량번호: {}", vhclno); return null; } @@ -86,7 +86,7 @@ public class TransferOmChecker extends AbstractComparisonOmChecker { // 소유자명에 "상품용" 포함 여부 체크 if (step1RprsOwnrNm != null && step1RprsOwnrNm.contains("상품용")) { - log.debug("[이첩-미필] 소유자명에 '상품용' 포함 - 차량번호: {}, 소유자명: {}", vhclno, step1RprsOwnrNm); + log.info("[이첩-미필] 소유자명에 '상품용' 포함 - 차량번호: {}, 소유자명: {}", vhclno, step1RprsOwnrNm); return null; } @@ -115,7 +115,7 @@ public class TransferOmChecker extends AbstractComparisonOmChecker { // 2단계 비교: 1단계 소유자 = 2단계 소유자 동일 체크 if (step1RprsvOwnrIdecno != null && !step1RprsvOwnrIdecno.equals(step2RprsvOwnrIdecno)) { - log.debug("[이첩-미필] 1단계와 2단계 소유자 동일 - 차량번호: {}, 소유자: {}", vhclno, step1RprsOwnrNm); + log.info("[이첩-미필] 1단계와 2단계 소유자 동일 - 차량번호: {}, 소유자: {}", vhclno, step1RprsOwnrNm); return null; } @@ -140,20 +140,20 @@ public class TransferOmChecker extends AbstractComparisonOmChecker { // 3단계 비교: 1단계 소유자 = 3단계 소유자 동일 체크 if (step1RprsvOwnrIdecno != null && !step1RprsvOwnrIdecno.equals(step3RprsvOwnrIdecno)) { - log.debug("[이첩-미필] 1단계와 3단계 소유자 동일 - 차량번호: {}, 소유자: {}", vhclno, step1RprsOwnrNm); + log.info("[이첩-미필] 1단계와 3단계 소유자 동일 - 차량번호: {}, 소유자: {}", vhclno, step1RprsOwnrNm); return null; } // 법정동코드 유효성 검사 if (step1UsgsrhldStdgCd == null || step1UsgsrhldStdgCd.length() < 4) { - log.debug("[이첩-미필] 법정동코드 없음 - 차량번호: {}", vhclno); + log.info("[이첩-미필] 법정동코드 없음 - 차량번호: {}", vhclno); return null; } // 세션에서 사용자 정보 조회 LoginUserVO userInfo = SessionUtil.getLoginUser(); if (userInfo == null || userInfo.getOrgCd() == null) { - log.debug("[이첩-미필] 사용자 정보 없음"); + log.info("[이첩-미필] 사용자 정보 없음"); return null; } @@ -163,7 +163,7 @@ public class TransferOmChecker extends AbstractComparisonOmChecker { String userOrg4 = userOrgCd.length() >= 4 ? userOrgCd.substring(0, 4) : userOrgCd; if (legalDong4.equals(userOrg4)) { - log.debug("[이첩-미필] 법정동코드 일치 - 차량번호: {}, 법정동: {}, 조직: {}", + log.info("[이첩-미필] 법정동코드 일치 - 차량번호: {}, 법정동: {}, 조직: {}", vhclno, legalDong4, userOrg4); return null; }