### feat: 비고 상세 생성 및 관리 기능 추가

- **주요 변경 사항**
  - `RMRK_DTL`(비고 상세) 컬럼 추가:
    - `tb_car_ffnlg_trgt`, `tb_car_ffnlg_trgt_incmp` 테이블에 `RMRK_DTL`(비고 상세, 최대 4000자) 컬럼 추가.
  - MyBatis 매퍼 및 VO 수정:
    - 관련 쿼리(`SELECT`, `INSERT`, `UPDATE`)에 `RMRK_DTL` 필드 추가.
    - `CarFfnlgTrgtVO`, `CarFfnlgTrgtExcelVO` 등 데이터 모델에 `RMRK_DTL` 속성 추가.
  - 비고 상세 생성 로직 추가:
    - `ComparisonRemarkBuilder`, `ComparisonOmRemarkBuilder`에 비고 상세 생성 메서드 다수 추가(`buildProductUseRemarkDetail` 등).
    - 로직 내 기존 `RMRK` 생성 메서드와 함께 호출하여 상세 내용을 추가 저장.
  - Checker 개선:
    - `delay_checker`, `om_checker` 등 모든 체크 로직에서 비고 상세(`RMRK_DTL`) 생성 후 DB 업데이트.

- **화면 및 UI 변경**
  - JSP 업데이트:
    - 상세 화면 및 Excel 다운로드 시 ‘비고 상세’ 열 추가.
    - ‘비고’는 너비 증가(`200px → 300px`), ‘비고 상세’는 신규 추가(`200px`).
    - 내용이 길 경우 30자 요약 표시 및 팝업 기능 추가.

- **기타**
  - SQL 정리 및 누락된 매퍼 반영.
  - 가독성 개선을 위한 코드 리팩토링.
  - 주석 및 문서 업데이트 (`자동차과태료_비교로직_정리-[미필].md`).
main
박성영 5 days ago
parent 4691fb8073
commit fb63a0bc2b

@ -21,6 +21,7 @@ create table tb_car_ffnlg_trgt
TASK_PRCS_STTS_CD varchar(2) null comment '업무 처리 상태 코드',
TASK_PRCS_YMD varchar(8) null comment '업무 처리 일자',
RMRK varchar(4000) null comment '비고',
RMRK_DTL varchar(4000) null comment '비고 상세',
CAR_BASS_MATTER_INQIRE_ID varchar(20) null comment '자동차 기본 사항 조회 ID',
CAR_LEDGER_FRMBK_ID varchar(20) null comment '자동차 등록 원부 갑 ID',
CAR_BSC_MTTR_INQ_FLNM varchar(75) null comment '자동차 기본 사항 조회 성명',

@ -17,6 +17,7 @@ create table tb_car_ffnlg_trgt_incmp
TASK_PRCS_STTS_CD varchar(2) null comment '업무 처리 상태 코드',
TASK_PRCS_YMD varchar(8) null comment '업무 처리 일자',
RMRK varchar(4000) null comment '비고',
RMRK_DTL varchar(4000) null comment '비고 상세',
CAR_BASS_MATTER_INQIRE_ID varchar(20) null comment '자동차 기본 사항 조회 ID',
CAR_LEDGER_FRMBK_ID varchar(20) null comment '자동차 등록 원부 갑 ID',
CAR_BSC_MTTR_INQ_FLNM varchar(75) null comment '자동차 기본 사항 조회 성명',

@ -94,6 +94,10 @@ public class CarFfnlgTrgtExcelVO {
@ExcelColumn(headerName = "비고", headerWidth = 30, align = ExcelColumn.Align.LEFT)
private String rmrk;
/** 비고 상세 */
@ExcelColumn(headerName = "비고 상세", headerWidth = 50, align = ExcelColumn.Align.LEFT)
private String rmrkDtl;
/** 기본사항조회성명 */
@ExcelColumn(headerName = "기본사항조회성명", headerWidth = 18, align = ExcelColumn.Align.CENTER)
private String carBscMttrInqFlnm;

@ -43,6 +43,7 @@ public class CarFfnlgTrgtVO extends PagingVO {
private String taskPrcsSttsCd; // 업무 처리 상태 코드 (01=접수, 02=처리중, 03=완료)
private String taskPrcsYmd; // 업무 처리 일자
private String rmrk; // 비고
private String rmrkDtl; // 비고 상세
private String carBassMatterInqireId; // 자동차 기본 사항 조회 ID
private String carLedgerFrmbkId; // 자동차 등록 원부 갑 ID
private String carBscMttrInqFlnm; // 자동차 기본 사항 조회 성명 (상품용일 때 저장)

@ -85,6 +85,215 @@ public class ComparisonRemarkBuilder {
return String.format("%s/ %s, 115일 도래지", StringUtil.nvl(sggNm), StringUtil.nvl(ownerNm));
}
// ========================== 비고 상세 (RMRK_DTL) 생성 메서드 ==========================
/**
*
*
* @param vhclno
* @param inspYmd
* @param step1OwnerNm Step1
* @param targetChgYmd
* @param step4OwnerNm Step4 ( )
* @return
*/
public static String buildProductUseRemarkDetail(String vhclno, String inspYmd,
String step1OwnerNm, String targetChgYmd, String step4OwnerNm) {
StringBuilder sb = new StringBuilder();
sb.append("[상품용 판정]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사일자: ").append(DateUtil.formatDateString(inspYmd)).append("\n");
sb.append("검사일 기준 소유자명: ").append(StringUtil.nvl(step1OwnerNm)).append("\n");
sb.append("갑부 변경일자: ").append(DateUtil.formatDateString(targetChgYmd)).append("\n");
sb.append("변경일 기준 소유자명: ").append(StringUtil.nvl(step4OwnerNm)).append("\n");
sb.append("판정근거: 검사일 기준 소유자명에 '상품용' 포함되어 있고, ");
sb.append("갑부 상세에서 변경업무구분코드 '21'(변경등록) 레코드 확인됨");
return truncateToMaxLength(sb.toString());
}
/**
* -
*
* @param vhclno
* @param inspYmd
* @param step1OwnerNm Step1
* @param targetChgYmd
* @param step4OwnerNm Step4 ( )
* @param daysBetween
* @return
*/
public static String buildProductCloseLevyRemarkDetail(String vhclno, String inspYmd,
String step1OwnerNm, String targetChgYmd,
String step4OwnerNm, long daysBetween) {
StringBuilder sb = new StringBuilder();
sb.append("[내사종결 - 명의이전 이전소유자 상품용 판정]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사일자: ").append(DateUtil.formatDateString(inspYmd)).append("\n");
sb.append("검사일 기준 소유자명: ").append(StringUtil.nvl(step1OwnerNm)).append("\n");
sb.append("갑부 명의이전 일자: ").append(DateUtil.formatDateString(targetChgYmd)).append("\n");
sb.append("명의이전 전 소유자명: ").append(StringUtil.nvl(step4OwnerNm)).append("\n");
sb.append("검사일~명의이전일 일수: ").append(daysBetween).append("일\n");
sb.append("판정근거: 검사일 기준 소유자명에 '상품용' 미포함이나, ");
sb.append("갑부 상세에서 변경업무구분코드 '11'(명의이전) 레코드의 이전 소유자가 '상품용'이고, ");
sb.append("명의이전일이 검사일로부터 31일 이내임");
return truncateToMaxLength(sb.toString());
}
/**
* -
*
* @param vhclno
* @param inspYmd
* @param step1OwnerNm Step1
* @param targetChgYmd
* @param step4OwnerNm Step4 ( )
* @param daysBetween
* @return
*/
public static String buildOwnerChangeRemarkDetail(String vhclno, String inspYmd,
String step1OwnerNm, String targetChgYmd,
String step4OwnerNm, long daysBetween) {
StringBuilder sb = new StringBuilder();
sb.append("[내사종결 - 명의이전 판정]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사일자: ").append(DateUtil.formatDateString(inspYmd)).append("\n");
sb.append("검사일 기준 소유자명: ").append(StringUtil.nvl(step1OwnerNm)).append("\n");
sb.append("갑부 명의이전 일자: ").append(DateUtil.formatDateString(targetChgYmd)).append("\n");
sb.append("명의이전 전 소유자명: ").append(StringUtil.nvl(step4OwnerNm)).append("\n");
sb.append("검사일~명의이전일 일수: ").append(daysBetween).append("일\n");
sb.append("판정근거: 검사일 기준 소유자와 명의이전 전 소유자가 동일하고, ");
sb.append("명의이전일이 검사일로부터 31일 이내임");
return truncateToMaxLength(sb.toString());
}
/**
* -
*
* @param vhclno
* @param inspYmd
* @param step1OwnerNm Step1
* @param targetChgYmd
* @param step4OwnerNm Step4 ( )
* @param daysBetween
* @return
*/
public static String buildProductLevyOver31RemarkDetail(String vhclno, String inspYmd,
String step1OwnerNm, String targetChgYmd,
String step4OwnerNm, long daysBetween) {
StringBuilder sb = new StringBuilder();
sb.append("[날짜수정후부과 - 명의이전 이전소유자 상품용 판정]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사일자: ").append(DateUtil.formatDateString(inspYmd)).append("\n");
sb.append("검사일 기준 소유자명: ").append(StringUtil.nvl(step1OwnerNm)).append("\n");
sb.append("갑부 명의이전 일자: ").append(DateUtil.formatDateString(targetChgYmd)).append("\n");
sb.append("명의이전 전 소유자명: ").append(StringUtil.nvl(step4OwnerNm)).append("\n");
sb.append("검사일~명의이전일 일수: ").append(daysBetween).append("일\n");
sb.append("판정근거: 검사일 기준 소유자명에 '상품용' 미포함이나, ");
sb.append("갑부 상세에서 변경업무구분코드 '11'(명의이전) 레코드의 이전 소유자가 '상품용'이고, ");
sb.append("명의이전일이 검사일로부터 31일 초과함 (부과일자 수정 필요)");
return truncateToMaxLength(sb.toString());
}
/**
* -
*
* @param vhclno
* @param inspYmd
* @param step1OwnerNm Step1
* @param targetChgYmd
* @param step4OwnerNm Step4 ( )
* @param daysBetween
* @return
*/
public static String buildOwnerLevyOver31RemarkDetail(String vhclno, String inspYmd,
String step1OwnerNm, String targetChgYmd,
String step4OwnerNm, long daysBetween) {
StringBuilder sb = new StringBuilder();
sb.append("[날짜수정후부과 - 명의이전 판정]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사일자: ").append(DateUtil.formatDateString(inspYmd)).append("\n");
sb.append("검사일 기준 소유자명: ").append(StringUtil.nvl(step1OwnerNm)).append("\n");
sb.append("갑부 명의이전 일자: ").append(DateUtil.formatDateString(targetChgYmd)).append("\n");
sb.append("명의이전 전 소유자명: ").append(StringUtil.nvl(step4OwnerNm)).append("\n");
sb.append("검사일~명의이전일 일수: ").append(daysBetween).append("일\n");
sb.append("판정근거: 검사일 기준 소유자와 명의이전 전 소유자가 동일하고, ");
sb.append("명의이전일이 검사일로부터 31일 초과함 (부과일자 수정 필요)");
return truncateToMaxLength(sb.toString());
}
/**
* - Case -1 ( )
*
* @param vhclno
* @param inspYmd
* @param ownerNm
* @param usgsrhldStdgCd
* @param sggNm
* @param userOrgCd
* @return
*/
public static String buildTransferCase1RemarkDetail(String vhclno, String inspYmd,
String ownerNm, String usgsrhldStdgCd,
String sggNm, String userOrgCd) {
StringBuilder sb = new StringBuilder();
sb.append("[이첩 판정 - 검사일 사용본거지]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사일자: ").append(DateUtil.formatDateString(inspYmd)).append("\n");
sb.append("소유자명: ").append(StringUtil.nvl(ownerNm)).append("\n");
sb.append("사용본거지법정동코드: ").append(StringUtil.nvl(usgsrhldStdgCd)).append("\n");
sb.append("시군구명: ").append(StringUtil.nvl(sggNm)).append("\n");
sb.append("현재 사용자 조직코드: ").append(StringUtil.nvl(userOrgCd)).append("\n");
sb.append("판정근거: DAYCNT가 115일 이하이고, ");
sb.append("검사일 기준 사용본거지법정동코드 앞 4자리가 현재 사용자 조직코드 앞 4자리와 불일치하여 이첩 대상임");
return truncateToMaxLength(sb.toString());
}
/**
* - Case -2 (115 )
*
* @param vhclno
* @param inspEndYmd
* @param ownerNm
* @param usgsrhldStdgCd
* @param sggNm
* @param userOrgCd
* @param daycnt
* @return
*/
public static String buildTransferCase2RemarkDetail(String vhclno, String inspEndYmd,
String ownerNm, String usgsrhldStdgCd,
String sggNm, String userOrgCd, String daycnt) {
StringBuilder sb = new StringBuilder();
sb.append("[이첩 판정 - 115일 도래지]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사종료일자: ").append(DateUtil.formatDateString(inspEndYmd)).append("\n");
sb.append("소유자명: ").append(StringUtil.nvl(ownerNm)).append("\n");
sb.append("DAYCNT: ").append(StringUtil.nvl(daycnt)).append("일\n");
sb.append("사용본거지법정동코드: ").append(StringUtil.nvl(usgsrhldStdgCd)).append("\n");
sb.append("시군구명: ").append(StringUtil.nvl(sggNm)).append("\n");
sb.append("현재 사용자 조직코드: ").append(StringUtil.nvl(userOrgCd)).append("\n");
sb.append("판정근거: DAYCNT가 115일 초과이고, ");
sb.append("검사종료일+115일 기준 사용본거지법정동코드 앞 4자리가 현재 사용자 조직코드 앞 4자리와 불일치하여 이첩 대상임");
return truncateToMaxLength(sb.toString());
}
/**
* ( 3 1300)
*
* @param str
* @return
*/
private static String truncateToMaxLength(String str) {
if (str == null) {
return "";
}
// 4000바이트 / 3(한글) = 약 1333자, 여유있게 1300자로 제한
if (str.length() > 1300) {
return str.substring(0, 1297) + "...";
}
return str;
}
/**
*
*

@ -202,6 +202,8 @@ public class OwnerCloseWithin31Checker extends AbstractComparisonChecker {
// ========== 비고 생성 ==========
String rmrk = ComparisonRemarkBuilder.buildOwnerChangeRemark(targetRecord, sggNm, ownerNm);
String rmrkDtl = ComparisonRemarkBuilder.buildOwnerChangeRemarkDetail(
vhclno, inspYmd, step1OwnerName, targetChgYmd, step4OwnerName, daysBetween);
// ========== DB 업데이트 ==========
existingData.setCarBassMatterInqireId(step1Response.getGeneratedId());
@ -214,6 +216,7 @@ public class OwnerCloseWithin31Checker extends AbstractComparisonChecker {
existingData.setCarRegFrmbkChgYmd(targetRecord.getChgYmd().replace("-", ""));
existingData.setCarRegFrmbkDtl(ComparisonRemarkBuilder.buildLedgerRecordDetail(targetRecord));
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtMapper.update(existingData);
if (updateCount == 0) {

@ -202,6 +202,8 @@ public class OwnerLevyOver31Checker extends AbstractComparisonChecker {
// ========== 비고 생성 ==========
String rmrk = ComparisonRemarkBuilder.buildOwnerChangeRemark(targetRecord, sggNm, ownerNm);
String rmrkDtl = ComparisonRemarkBuilder.buildOwnerLevyOver31RemarkDetail(
vhclno, inspYmd, step1OwnerName, targetChgYmd, step4OwnerName, daysBetween);
// ========== DB 업데이트 ==========
existingData.setCarBassMatterInqireId(step1Response.getGeneratedId());
@ -214,6 +216,7 @@ public class OwnerLevyOver31Checker extends AbstractComparisonChecker {
existingData.setCarRegFrmbkChgYmd(targetRecord.getChgYmd().replace("-", ""));
existingData.setCarRegFrmbkDtl(ComparisonRemarkBuilder.buildLedgerRecordDetail(targetRecord));
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtMapper.update(existingData);
if (updateCount == 0) {

@ -199,6 +199,8 @@ public class ProductCloseWithin31Checker extends AbstractComparisonChecker {
// ========== 비고 생성 ==========
String rmrk = ComparisonRemarkBuilder.buildProductCloseLevyRemark(targetRecord, sggNm, ownerNm);
String rmrkDtl = ComparisonRemarkBuilder.buildProductCloseLevyRemarkDetail(
vhclno, inspYmd, step1OwnerName, targetChgYmd, step4OwnerName, daysBetween);
// ========== DB 업데이트 ==========
existingData.setCarBassMatterInqireId(step1Response.getGeneratedId());
@ -211,6 +213,7 @@ public class ProductCloseWithin31Checker extends AbstractComparisonChecker {
existingData.setCarRegFrmbkChgYmd(targetRecord.getChgYmd().replace("-", ""));
existingData.setCarRegFrmbkDtl(ComparisonRemarkBuilder.buildLedgerRecordDetail(targetRecord));
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtMapper.update(existingData);
if (updateCount == 0) {

@ -201,6 +201,8 @@ public class ProductLevyOver31Checker extends AbstractComparisonChecker {
// ========== 비고 생성 ==========
String rmrk = ComparisonRemarkBuilder.buildProductCloseLevyRemark(targetRecord, sggNm, ownerNm);
String rmrkDtl = ComparisonRemarkBuilder.buildProductLevyOver31RemarkDetail(
vhclno, inspYmd, step1OwnerName, targetChgYmd, step4OwnerName, daysBetween);
// ========== DB 업데이트 ==========
existingData.setCarBassMatterInqireId(step1Response.getGeneratedId());
@ -213,6 +215,7 @@ public class ProductLevyOver31Checker extends AbstractComparisonChecker {
existingData.setCarRegFrmbkChgYmd(targetRecord.getChgYmd().replace("-", ""));
existingData.setCarRegFrmbkDtl(ComparisonRemarkBuilder.buildLedgerRecordDetail(targetRecord));
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtMapper.update(existingData);
if (updateCount == 0) {

@ -206,6 +206,8 @@ public class ProductUseChecker extends AbstractComparisonChecker {
// ========== 비고 생성 ==========
String rmrk = ComparisonRemarkBuilder.buildProductUseRemark();
String rmrkDtl = ComparisonRemarkBuilder.buildProductUseRemarkDetail(
vhclno, inspYmd, step1OwnerName, targetChgYmd, step4OwnerName);
// ========== DB 업데이트 ==========
existingData.setCarBassMatterInqireId(step1Response.getGeneratedId());
@ -218,6 +220,7 @@ public class ProductUseChecker extends AbstractComparisonChecker {
existingData.setCarRegFrmbkChgYmd(targetRecord.getChgYmd().replace("-", ""));
existingData.setCarRegFrmbkDtl(ComparisonRemarkBuilder.buildLedgerRecordDetail(targetRecord));
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtMapper.update(existingData);
if (updateCount == 0) {

@ -211,6 +211,8 @@ public class ProductUseChnageChecker extends AbstractComparisonChecker {
// ========== 비고 생성 ==========
String rmrk = ComparisonRemarkBuilder.buildProductUseRemark();
String rmrkDtl = ComparisonRemarkBuilder.buildProductUseRemarkDetail(
vhclno, inspYmd, step1OwnerName, targetChgYmd, step4OwnerName);
// ========== DB 업데이트 ==========
existingData.setCarBassMatterInqireId(step1Response.getGeneratedId());
@ -223,6 +225,7 @@ public class ProductUseChnageChecker extends AbstractComparisonChecker {
existingData.setCarRegFrmbkChgYmd(targetRecord.getChgYmd().replace("-", ""));
existingData.setCarRegFrmbkDtl(ComparisonRemarkBuilder.buildLedgerRecordDetail(targetRecord));
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtMapper.update(existingData);
if (updateCount == 0) {

@ -127,10 +127,15 @@ public class TransferCase115DayChecker extends AbstractComparisonChecker {
// 비고 생성
String rmrk;
String rmrkDtl;
if ("이첩-1".equals(transferType)) { // 5번
rmrk = ComparisonRemarkBuilder.buildTransferCase1Remark(sggNm, ownerNm);
rmrkDtl = ComparisonRemarkBuilder.buildTransferCase1RemarkDetail(
vhclno, existingData.getInspYmd(), ownerNm, usgsrhldStdgCd, sggNm, userOrgCd);
} else { // 7번
rmrk = ComparisonRemarkBuilder.buildTransferCase2Remark(sggNm, ownerNm);
rmrkDtl = ComparisonRemarkBuilder.buildTransferCase2RemarkDetail(
vhclno, existingData.getInspEndYmd(), ownerNm, usgsrhldStdgCd, sggNm, userOrgCd, daycntStr);
}
// DB 업데이트
@ -141,6 +146,7 @@ public class TransferCase115DayChecker extends AbstractComparisonChecker {
existingData.setCarBscMttrInqSggCd(sggCd);
existingData.setCarBscMttrInqSggNm(sggNm);
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtMapper.update(existingData);
if (updateCount == 0) {

@ -74,6 +74,10 @@ public class CarFfnlgTrgtIncmpExcelVO {
@ExcelColumn(headerName = "비고", headerWidth = 30, align = ExcelColumn.Align.LEFT)
private String rmrk;
/** 비고 상세 */
@ExcelColumn(headerName = "비고 상세", headerWidth = 50, align = ExcelColumn.Align.LEFT)
private String rmrkDtl;
/** 기본사항조회성명 */
@ExcelColumn(headerName = "기본사항조회성명", headerWidth = 18, align = ExcelColumn.Align.CENTER)
private String carBscMttrInqFlnm;

@ -42,7 +42,8 @@ public class CarFfnlgTrgtIncmpVO extends PagingVO {
private String taskPrcsSttsCd; // 업무 처리 상태 코드 (01=접수, 02=처리중, 03=완료)
private String taskPrcsYmd; // 업무 처리 일자
private String rmrk; // 비고
private String rmrkDtl; // 비고 상세
// API 연동 필드
private String carBassMatterInqireId; // 자동차 기본 사항 조회 ID
private String carLedgerFrmbkId; // 자동차 등록 원부 갑 ID

@ -71,6 +71,135 @@ public class ComparisonOmRemarkBuilder {
return String.format("%s/ %s, 115일 도래지", StringUtil.nvl(sggNm), StringUtil.nvl(ownerNm));
}
// ========================== 비고 상세 (RMRK_DTL) 생성 메서드 ==========================
/**
* -
*
* @param vhclno
* @param inspVldPrdEnd
* @param levyCrtrYmd (+146)
* @param step1OwnerNm Step1 ( )
* @param targetChgYmd
* @param step4OwnerNm Step4 ( )
* @return
*/
public static String buildProductUseRemarkDetail(String vhclno, String inspVldPrdEnd,
String levyCrtrYmd, String step1OwnerNm,
String targetChgYmd, String step4OwnerNm) {
StringBuilder sb = new StringBuilder();
sb.append("[상품용 판정 - 미필]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사유효기간 종료일: ").append(DateUtil.formatDateString(inspVldPrdEnd)).append("\n");
sb.append("부과기준일자(+146일): ").append(DateUtil.formatDateString(levyCrtrYmd)).append("\n");
sb.append("부과일자 기준 소유자명: ").append(StringUtil.nvl(step1OwnerNm)).append("\n");
sb.append("갑부 변경일자: ").append(DateUtil.formatDateString(targetChgYmd)).append("\n");
sb.append("변경일 기준 소유자명: ").append(StringUtil.nvl(step4OwnerNm)).append("\n");
sb.append("판정근거: 부과일자 기준 소유자명에 '상품용' 포함되어 있고, ");
sb.append("갑부 상세에서 변경업무구분코드 '21'(변경등록) 레코드 확인됨");
return truncateToMaxLength(sb.toString());
}
/**
* -
*
* @param vhclno
* @param inspVldPrdEnd
* @param levyCrtrYmd (+146)
* @param step1OwnerNm Step1
* @param targetChgYmd
* @param step4OwnerNm Step4 ( )
* @return
*/
public static String buildProductCloseLevyRemarkDetail(String vhclno, String inspVldPrdEnd,
String levyCrtrYmd, String step1OwnerNm,
String targetChgYmd, String step4OwnerNm) {
StringBuilder sb = new StringBuilder();
sb.append("[명의이전 이전소유자 상품용 판정 - 미필]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사유효기간 종료일: ").append(DateUtil.formatDateString(inspVldPrdEnd)).append("\n");
sb.append("부과기준일자(+146일): ").append(DateUtil.formatDateString(levyCrtrYmd)).append("\n");
sb.append("부과일자 기준 소유자명: ").append(StringUtil.nvl(step1OwnerNm)).append("\n");
sb.append("갑부 명의이전 일자: ").append(DateUtil.formatDateString(targetChgYmd)).append("\n");
sb.append("명의이전 전 소유자명: ").append(StringUtil.nvl(step4OwnerNm)).append("\n");
sb.append("판정근거: 부과일자 기준 소유자명에 '상품용' 미포함이나, ");
sb.append("갑부 상세에서 변경업무구분코드 '11'(명의이전) 레코드의 이전 소유자가 '상품용'임");
return truncateToMaxLength(sb.toString());
}
/**
* -
*
* @param vhclno
* @param inspVldPrdEnd
* @param levyCrtrYmd (+146)
* @param step1OwnerNm Step1
* @param targetChgYmd
* @param step4OwnerNm Step4 ( )
* @return
*/
public static String buildOwnerChangeRemarkDetail(String vhclno, String inspVldPrdEnd,
String levyCrtrYmd, String step1OwnerNm,
String targetChgYmd, String step4OwnerNm) {
StringBuilder sb = new StringBuilder();
sb.append("[미수검명의이전 판정 - 미필]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사유효기간 종료일: ").append(DateUtil.formatDateString(inspVldPrdEnd)).append("\n");
sb.append("부과기준일자(+146일): ").append(DateUtil.formatDateString(levyCrtrYmd)).append("\n");
sb.append("부과일자 기준 소유자명: ").append(StringUtil.nvl(step1OwnerNm)).append("\n");
sb.append("갑부 명의이전 일자: ").append(DateUtil.formatDateString(targetChgYmd)).append("\n");
sb.append("명의이전 전 소유자명: ").append(StringUtil.nvl(step4OwnerNm)).append("\n");
sb.append("판정근거: 부과일자 기준 소유자와 명의이전 전 소유자가 동일하고, ");
sb.append("명의이전이 검사유효기간 종료일 이후에 발생함 (미수검 상태에서 명의이전)");
return truncateToMaxLength(sb.toString());
}
/**
* -
*
* @param vhclno
* @param inspVldPrdEnd
* @param levyCrtrYmd (+146)
* @param ownerNm
* @param usgsrhldStdgCd
* @param sggNm
* @param userOrgCd
* @return
*/
public static String buildTransferRemarkDetail(String vhclno, String inspVldPrdEnd,
String levyCrtrYmd, String ownerNm,
String usgsrhldStdgCd, String sggNm, String userOrgCd) {
StringBuilder sb = new StringBuilder();
sb.append("[이첩 판정 - 미필]\n");
sb.append("차량번호: ").append(StringUtil.nvl(vhclno)).append("\n");
sb.append("검사유효기간 종료일: ").append(DateUtil.formatDateString(inspVldPrdEnd)).append("\n");
sb.append("부과기준일자(+146일): ").append(DateUtil.formatDateString(levyCrtrYmd)).append("\n");
sb.append("소유자명: ").append(StringUtil.nvl(ownerNm)).append("\n");
sb.append("사용본거지법정동코드: ").append(StringUtil.nvl(usgsrhldStdgCd)).append("\n");
sb.append("시군구명: ").append(StringUtil.nvl(sggNm)).append("\n");
sb.append("현재 사용자 조직코드: ").append(StringUtil.nvl(userOrgCd)).append("\n");
sb.append("판정근거: 부과기준일자 기준 사용본거지법정동코드 앞 4자리가 ");
sb.append("현재 사용자 조직코드 앞 4자리와 불일치하여 이첩 대상임");
return truncateToMaxLength(sb.toString());
}
/**
* ( 3 1300)
*
* @param str
* @return
*/
private static String truncateToMaxLength(String str) {
if (str == null) {
return "";
}
// 4000바이트 / 3(한글) = 약 1333자, 여유있게 1300자로 제한
if (str.length() > 1300) {
return str.substring(0, 1297) + "...";
}
return str;
}
/**
*
*

@ -220,6 +220,7 @@ public class OwnerTransferOmChecker extends AbstractComparisonOmChecker {
// ========== 소유자명 상품용 포함 여부에 따라 처리 분기 ==========
String taskPrcsSttsCd;
String rmrk;
String rmrkDtl;
if (step4OwnerName != null && step4OwnerName.contains("상품용")) {
// 상품용 포함
@ -227,12 +228,16 @@ public class OwnerTransferOmChecker extends AbstractComparisonOmChecker {
taskPrcsSttsCd = TaskPrcsSttsConstants.TASK_PRCS_STTS_CD_01_RCPT; // 접수
rmrk = ComparisonOmRemarkBuilder.buildProductCloseLevyRemark(targetRecord, sggNm, ownerNm);
rmrkDtl = ComparisonOmRemarkBuilder.buildProductCloseLevyRemarkDetail(
vhclno, inspVldPrdEnd, levyCrtrYmd, step1OwnerName, targetChgYmd, step4OwnerName);
} else {
// 상품용 미포함
log.info("[명의이전-미필] 명의이전 전 소유자가 상품용 아님");
taskPrcsSttsCd = TaskPrcsSttsConstants.TASK_PRCS_STTS_CD_01_RCPT; // 접수
rmrk = ComparisonOmRemarkBuilder.buildOwnerChangeRemark(targetRecord, vhclno);
rmrkDtl = ComparisonOmRemarkBuilder.buildOwnerChangeRemarkDetail(
vhclno, inspVldPrdEnd, levyCrtrYmd, step1OwnerName, targetChgYmd, step4OwnerName);
}
log.info("[명의이전-미필] 모든 조건 충족! 차량번호: {}, 처리상태: {}", vhclno, taskPrcsSttsCd);
@ -248,6 +253,7 @@ public class OwnerTransferOmChecker extends AbstractComparisonOmChecker {
existingData.setCarRegFrmbkChgYmd(targetRecord.getChgYmd().replace("-", ""));
existingData.setCarRegFrmbkDtl(ComparisonOmRemarkBuilder.buildLedgerRecordDetail(targetRecord));
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtIncmpMapper.update(existingData);
if (updateCount == 0) {

@ -221,6 +221,8 @@ public class ProductUseOmChecker extends AbstractComparisonOmChecker {
// ========== 비고 생성 ==========
String rmrk = ComparisonOmRemarkBuilder.buildProductUseRemark();
String rmrkDtl = ComparisonOmRemarkBuilder.buildProductUseRemarkDetail(
vhclno, inspVldPrdEnd, levyCrtrYmd, step1OwnerName, targetChgYmd, step4OwnerName);
// ========== DB 업데이트 ==========
existingData.setCarBassMatterInqireId(step1Response.getGeneratedId());
@ -233,6 +235,7 @@ public class ProductUseOmChecker extends AbstractComparisonOmChecker {
existingData.setCarRegFrmbkChgYmd(targetRecord.getChgYmd().replace("-", ""));
existingData.setCarRegFrmbkDtl(ComparisonOmRemarkBuilder.buildLedgerRecordDetail(targetRecord));
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtIncmpMapper.update(existingData);
if (updateCount == 0) {

@ -184,6 +184,8 @@ public class TransferOmChecker extends AbstractComparisonOmChecker {
// 비고 생성 (이첩 케이스)
String rmrk = ComparisonOmRemarkBuilder.buildTransferRemark(sggNm, ownerNm);
String rmrkDtl = ComparisonOmRemarkBuilder.buildTransferRemarkDetail(
vhclno, inspVldPrdEnd, step1Ymd, ownerNm, step1UsgsrhldStdgCd, sggNm, userOrgCd);
// DB 업데이트
existingData.setCarBassMatterInqireId(step1Response.getGeneratedId());
@ -193,6 +195,7 @@ public class TransferOmChecker extends AbstractComparisonOmChecker {
existingData.setCarBscMttrInqSggCd(sggCd);
existingData.setCarBscMttrInqSggNm(sggNm);
existingData.setRmrk(rmrk);
existingData.setRmrkDtl(rmrkDtl);
int updateCount = carFfnlgTrgtIncmpMapper.update(existingData);
if (updateCount == 0) {

@ -70,6 +70,7 @@
t.TASK_PRCS_STTS_CD AS taskPrcsSttsCd,
t.TASK_PRCS_YMD AS taskPrcsYmd,
t.RMRK AS rmrk,
t.RMRK_DTL AS rmrkDtl,
t.CAR_BASS_MATTER_INQIRE_ID AS carBassMatterInqireId,
t.CAR_LEDGER_FRMBK_ID AS carLedgerFrmbkId,
t.CAR_BSC_MTTR_INQ_FLNM AS carBscMttrInqFlnm,
@ -125,6 +126,7 @@
t.TASK_PRCS_STTS_CD AS taskPrcsSttsCd,
t.TASK_PRCS_YMD AS taskPrcsYmd,
t.RMRK AS rmrk,
t.RMRK_DTL AS rmrkDtl,
t.CAR_BASS_MATTER_INQIRE_ID AS carBassMatterInqireId,
t.CAR_LEDGER_FRMBK_ID AS carLedgerFrmbkId,
t.CAR_BSC_MTTR_INQ_FLNM AS carBscMttrInqFlnm,
@ -176,6 +178,7 @@
cd.CD_NM AS taskPrcsSttsCdNm,
DATE_FORMAT(STR_TO_DATE(t.TASK_PRCS_YMD, '%Y%m%d'), '%Y-%m-%d') AS taskPrcsYmd,
t.RMRK AS rmrk,
t.RMRK_DTL AS rmrkDtl,
t.CAR_BSC_MTTR_INQ_FLNM AS carBscMttrInqFlnm,
t.CAR_BSC_MTTR_INQ_SGG_NM AS carBscMttrInqSggNm,
t.CAR_REG_FRMBK_CHG_TASK_SE_NM AS carRegFrmbkChgTaskSeNm,
@ -273,6 +276,7 @@
SET TASK_PRCS_STTS_CD = #{taskPrcsSttsCd},
TASK_PRCS_YMD = #{taskPrcsYmd},
RMRK = #{rmrk},
RMRK_DTL = #{rmrkDtl},
CAR_BASS_MATTER_INQIRE_ID = #{carBassMatterInqireId},
CAR_LEDGER_FRMBK_ID = #{carLedgerFrmbkId},
CAR_BSC_MTTR_INQ_FLNM = #{carBscMttrInqFlnm},

@ -66,6 +66,7 @@
t.TASK_PRCS_STTS_CD AS taskPrcsSttsCd,
t.TASK_PRCS_YMD AS taskPrcsYmd,
t.RMRK AS rmrk,
t.RMRK_DTL AS rmrkDtl,
t.CAR_BASS_MATTER_INQIRE_ID AS carBassMatterInqireId,
t.CAR_LEDGER_FRMBK_ID AS carLedgerFrmbkId,
t.CAR_BSC_MTTR_INQ_FLNM AS carBscMttrInqFlnm,
@ -117,6 +118,7 @@
t.TASK_PRCS_STTS_CD AS taskPrcsSttsCd,
t.TASK_PRCS_YMD AS taskPrcsYmd,
t.RMRK AS rmrk,
t.RMRK_DTL AS rmrkDtl,
t.CAR_BASS_MATTER_INQIRE_ID AS carBassMatterInqireId,
t.CAR_LEDGER_FRMBK_ID AS carLedgerFrmbkId,
t.CAR_BSC_MTTR_INQ_FLNM AS carBscMttrInqFlnm,
@ -162,6 +164,7 @@
cd.CD_NM AS taskPrcsSttsCdNm,
DATE_FORMAT(STR_TO_DATE(t.TASK_PRCS_YMD, '%Y%m%d'), '%Y-%m-%d') AS taskPrcsYmd,
t.RMRK AS rmrk,
t.RMRK_DTL AS rmrkDtl,
t.CAR_BSC_MTTR_INQ_FLNM AS carBscMttrInqFlnm,
t.CAR_BSC_MTTR_INQ_SGG_NM AS carBscMttrInqSggNm,
t.CAR_REG_FRMBK_CHG_TASK_SE_NM AS carRegFrmbkChgTaskSeNm,
@ -251,6 +254,7 @@
SET TASK_PRCS_STTS_CD = #{taskPrcsSttsCd},
TASK_PRCS_YMD = #{taskPrcsYmd},
RMRK = #{rmrk},
RMRK_DTL = #{rmrkDtl},
CAR_BASS_MATTER_INQIRE_ID = #{carBassMatterInqireId},
CAR_LEDGER_FRMBK_ID = #{carLedgerFrmbkId},
CAR_BSC_MTTR_INQ_FLNM = #{carBscMttrInqFlnm},

@ -432,7 +432,7 @@
header: '비고',
name: 'rmrk',
align: 'left',
width: 200,
width: 300,
editor: 'text',
formatter: function(e) {
var rmrk = e.value || '';
@ -447,6 +447,23 @@
return displayText;
}
},
{
header: '비고 상세',
name: 'rmrkDtl',
align: 'left',
width: 200,
formatter: function(e) {
var rmrkDtl = e.value || '';
var displayText = rmrkDtl.length > 30 ? rmrkDtl.substring(0, 30) + '...' : rmrkDtl;
if (rmrkDtl && rmrkDtl.trim()) {
var escapedRmrkDtl = rmrkDtl.replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, '');
return '<span class="mdi mdi-note-text" style="color: #4CAF50; cursor: pointer; margin-right: 5px;" onclick="showRmrkPopup(\'' + escapedRmrkDtl + '\')"></span>' +
'<span style="cursor: pointer;" onclick="showRmrkPopup(\'' + escapedRmrkDtl + '\')">' + displayText + '</span>';
}
return displayText;
}
},
{ header: '기본사항조회성명', name: 'carBscMttrInqFlnm', align: 'center', width: 100 },
{ header: '기본사항조회시군구코드', name: 'carBscMttrInqSggCd', align: 'center', width: 100, hidden: true },
{ header: '기본사항조회시군구명', name: 'carBscMttrInqSggNm', align: 'center', width: 120 },

@ -397,7 +397,7 @@
header: '비고',
name: 'rmrk',
align: 'left',
width: 200,
width: 300,
editor: 'text',
formatter: function(e) {
var rmrk = e.value || '';
@ -412,6 +412,23 @@
return displayText;
}
},
{
header: '비고 상세',
name: 'rmrkDtl',
align: 'left',
width: 200,
formatter: function(e) {
var rmrkDtl = e.value || '';
var displayText = rmrkDtl.length > 30 ? rmrkDtl.substring(0, 30) + '...' : rmrkDtl;
if (rmrkDtl && rmrkDtl.trim()) {
var escapedRmrkDtl = rmrkDtl.replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, '');
return '<span class="mdi mdi-note-text" style="color: #4CAF50; cursor: pointer; margin-right: 5px;" onclick="showRmrkPopup(\'' + escapedRmrkDtl + '\')"></span>' +
'<span style="cursor: pointer;" onclick="showRmrkPopup(\'' + escapedRmrkDtl + '\')">' + displayText + '</span>';
}
return displayText;
}
},
{ header: '기본사항조회성명', name: 'carBscMttrInqFlnm', align: 'center', width: 100 },
{ header: '기본사항조회시군구코드', name: 'carBscMttrInqSggCd', align: 'center', width: 100, hidden: true },
{ header: '기본사항조회시군구명', name: 'carBscMttrInqSggNm', align: 'center', width: 120 },

Loading…
Cancel
Save