# 자동차 과태료 비교 로직 명세서

## 개요

자동차 과태료 부과 대상을 검증하기 위한 비교 로직 정의서입니다.

### 기본 설정

- **API 선택**: YML flag 값에 따라 구/신 API 호출 결정
- **통합 모델**: 구/신 API 응답을 통일된 model object로 처리
  - 구 API: 자동차기본정보 API
  - 신 API: 자동차기본정보 API, 자동차등록원부(갑)
- **통합 오브젝트**: 자동차기본정보(구, 신)만 필요
- 자동차등록원부(갑) 이 신규 api 만 되도록 변경되면서 구조 필드 등 변경됨
     D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\model\ledger\NewLedgerRequest.java
     D:\workspace\git\VMIS-interface\src\main\java\com\vmis\interfaceapp\model\ledger\NewLedgerResponse.java
- 외부호출 url 변경 : /api/v1/vehicles/old-basic, /api/v1/vehicles/new-basic, /api/v1/vehicles/new-ledger
- 외부호출되는 프로젝트 : D:\workspace\git\VMIS-interface, jdk1.8 springboot 설정, profiles : prd 기준
- 외부호출되는 프로젝트에서 return 을 요청과 응답 모두 포함해서 던져주도록 변경
- ApiResponse 생성 시 txId 전달
```text
  응답 예시

  {
    "txId": "yyyyMMddHHmmssSSS12345678",
    "request": { "data": [...] },
    "response": { "data": [...] }
  }
```

### 처리 규칙

> **중요**: 순서가 중요함!
> - 조건에 걸리는 순간 다음 차량번호 비교로 진행
> - 각 비교 로직별로 개별 API 호출 수행

---

## 비교 로직 상세

### 1. 상품용 검증

**필요 API**: 자동차등록원부(갑)

#### API 호출 순서

| 순서 | API | 입력 파라미터 | 출력 데이터 |
|------|-----|--------------|-------------|
| 1 | 자동차기본정보 | `차량번호`, `부과일자=검사일` | `차대번호`, `소유자명` |
| 2 | 자동차기본정보 | `1.차대번호`, `부과일자=오늘일자` | `차량번호`, `성명`, `민원인주민번호`, `민원인법정동코드` |
| 3 | 자동차등록원본(갑) | `2.차량번호`, `2.성명`, `2.민원인주민번호`, `2.민원인법정동코드` | 갑부 상세 List |

#### 비교 조건

```java
// 조건 1: 소유자명에 '상품용' 포함 여부
api.MBER_NM.contains("상품용")

// 조건 2: 갑부 상세 목록에서 명의이전 이력 확인
for (LedgerRecord record : 갑부상세List) {
    if (record.CHG_YMD >= TB_CAR_FFNLG_TRGT.유효기간만료일
        && record.CHG_YMD <= TB_CAR_FFNLG_TRGT.검사종료일자
        && record.CHANGE_JOB_SE_CODE == "11") {  // 11 = 명의이전 코드
        return true;
    }
}
```

#### 결과 처리

- **비고 컬럼**: `"[상품용] 갑부정보"`

---

### 2. 이첩 검증 (이첩-1, 이첩-2 병합 로직)

**필요 API**: 자동차기본정보

#### 부과기준일 결정

```java
int dayCnt = TB_CAR_FFNLG_TRGT.DAYCNT;  // textFile 일수

if (dayCnt > 115) {
    // 이첩-2
    부과기준일 = TB_CAR_FFNLG_TRGT.검사종료일자.plusDays(115);
} else {
    // 이첩-1
    부과기준일 = TB_CAR_FFNLG_TRGT.검사일자;
}
```

#### API 호출

```java
// 부과기준일 기준으로 자동차기본정보 API 호출
BasicResponse response = 자동차기본정보API.call(부과기준일, 차량번호);
```

#### 법정동코드 비교 로직 (공통)

```java
/**
 * 이첩 조건: 법정동코드 불일치 검증
 * 사용본거지법정동코드 앞 4자리 != 사용자 조직코드 앞 4자리
 */
private boolean checkTransferCondition_LegalDongMismatch(
    BasicResponse.Record basicInfo,
    String userId,
    String vhclno
) {
    String useStrnghldLegaldongCode = basicInfo.getUseStrnghldLegaldongCode();

    // 1. 법정동코드 유효성 검사
    if (useStrnghldLegaldongCode == null || useStrnghldLegaldongCode.length() < 4) {
        log.debug("[이첩] 법정동코드 없음. 차량번호: {}", vhclno);
        return false;
    }

    // 2. 사용자 정보 조회
    SystemUserVO userInfo = userMapper.selectUser(userId);
    if (userInfo == null || userInfo.getOrgCd() == null) {
        log.debug("[이첩] 사용자 정보 없음. 사용자ID: {}", userId);
        return false;
    }

    // 3. 법정동코드 앞 4자리 vs 사용자 조직코드 앞 4자리 비교
    String legalDong4 = useStrnghldLegaldongCode.substring(0, 4);
    String userOrgCd = userInfo.getOrgCd();
    String userOrg4 = userOrgCd.length() >= 4
        ? userOrgCd.substring(0, 4)
        : userOrgCd;

    // 4. 일치 여부 판단
    if (legalDong4.equals(userOrg4)) {
        log.debug("[이첩] 법정동코드 일치. 차량번호: {}, 법정동: {}, 조직: {}",
            vhclno, legalDong4, userOrg4);
        return false;  // 일치하면 이첩 대상 아님
    }

    log.info("[이첩] 법정동코드 불일치! 차량번호: {}, 법정동: {}, 조직: {}",
        vhclno, legalDong4, userOrg4);
    return true;  // 불일치하면 이첩 대상
}
```

#### 결과 처리

| 구분 | 조건 | 비고 컬럼 형식 |
|------|------|---------------|
| 이첩-1 | `DAYCNT <= 115` | `"서울시 용산구/ 이경호, 검사일사용본거지, [검사대상, 사용자 조직코드 앞 4자리 및 법정동명]"` |
| 이첩-2 | `DAYCNT > 115` | `"전라남도 순천시 / 김정대, 115일 도래지, [2개의 api 법정동코드 및 법정동명]"` |

---

## 데이터 모델

### TB_CAR_FFNLG_TRGT (과태료 대상 테이블)

| 컬럼명 | 설명 | 용도 |
|--------|------|------|
| 검사일 | 검사 기준일 | API 호출 파라미터 |
| 검사종료일자 | 검사 종료 일자 | 115일 계산 기준 |
| 유효기간만료일 | 유효기간 만료일 | 상품용 갑부 비교 시작일 |
| DAYCNT | textFile 일수 | 이첩-1/2 분기 조건 |
| 비고 | 검증 결과 메시지 | 결과 저장 |

### 코드 정의

| 코드 | 코드값 | 설명 |
|------|--------|------|
| CHANGE_JOB_SE_CODE | 11 | 명의이전 |

---

## 처리 흐름도

```
시작
  │
  ▼
[차량번호 조회]
  │
  ▼
[1. 상품용 검증] ──(조건 충족)──> [비고 기록] ──> [다음 차량]
  │
  │ (조건 미충족)
  ▼
[2. DAYCNT 확인]
  │
  ├─ (> 115) ──> [이첩-2: 부과기준일 = 검사종료일자 + 115일]
  │
  └─ (<= 115) ──> [이첩-1: 부과기준일 = 검사일]
        │
        ▼
  [법정동코드 비교] (공통)
        │
        ├─ (불일치) ──> [비고 기록] ──> [다음 차량]
        │
        └─ (일치) ──> [다음 차량]
```

---

## 구현 시 주의사항

1. **API 호출 순서 준수**: 각 검증 단계별로 필요한 API만 호출
2. **조건 우선순위**: 상품용 > 이첩 순서로 검증
3. **조기 종료**: 조건 충족 시 즉시 다음 차량으로 이동
4. **비고 컬럼**: 각 조건별 정해진 형식으로 기록
5. **법정동코드 길이 검증**: 최소 4자리 이상 필요
