From e5974bcca68f4ffe5ac1b29a9ad5979ec9c4ce51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=84=B1=EC=98=81?= Date: Tue, 30 Sep 2025 13:18:32 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9E=AC=EB=B6=80=EA=B3=BC=20=EC=8B=A0?= =?UTF-8?q?=EA=B7=9C=EB=A1=9C=EC=A7=81=20init?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DB-DDL/maria/ddl/ibmsdb/tb_act_info.sql | 57 ++- DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt.sql | 16 + DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt_2.sql | 14 + DB-DDL/maria/ddl/ibmsdb/tb_crdn.sql | 2 + .../maria/ddl/ibmsdb/tb_implt_trpr_info.sql | 3 +- DB-DDL/maria/ddl/ibmsdb/tb_res_ret.sql | 21 + DB-DDL/maria/ddl/ibmsdb/tb_res_ret_backup.sql | 21 + DB-DDL/maria/ddl/ibmsdb/tb_strct_idx.sql | 29 +- .../java/egovframework/util/FileUtil.java | 46 ++ .../service/impl/CrdnPhotoServiceImpl.java | 13 +- .../main/controller/CrdnRelevyController.java | 134 ++++++ .../main/mapper/CrdnRelevyMapper.java | 106 +++++ .../main/model/CrdnRelevyVO.java | 151 +++++++ .../main/service/CrdnRelevyService.java | 34 ++ .../service/impl/CrdnRelevyServiceImpl.java | 233 ++++++++++ .../main/CrdnRegistAndViewMapper_maria.xml | 2 +- .../main/CrdnRelevyMapper_maria.xml | 408 ++++++++++++++++++ .../main/crdnRelevy/relevyPopup.jsp | 226 ++++++++++ .../crdn/crndRegistAndView/main/list.jsp | 26 ++ .../webapp/resources/xit/xit-validation.js | 5 +- 20 files changed, 1496 insertions(+), 51 deletions(-) create mode 100644 DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt.sql create mode 100644 DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt_2.sql create mode 100644 DB-DDL/maria/ddl/ibmsdb/tb_res_ret.sql create mode 100644 DB-DDL/maria/ddl/ibmsdb/tb_res_ret_backup.sql create mode 100644 src/main/java/go/kr/project/crdn/crndRegistAndView/main/controller/CrdnRelevyController.java create mode 100644 src/main/java/go/kr/project/crdn/crndRegistAndView/main/mapper/CrdnRelevyMapper.java create mode 100644 src/main/java/go/kr/project/crdn/crndRegistAndView/main/model/CrdnRelevyVO.java create mode 100644 src/main/java/go/kr/project/crdn/crndRegistAndView/main/service/CrdnRelevyService.java create mode 100644 src/main/java/go/kr/project/crdn/crndRegistAndView/main/service/impl/CrdnRelevyServiceImpl.java create mode 100644 src/main/resources/mybatis/mapper/crdn/crndRegistAndView/main/CrdnRelevyMapper_maria.xml create mode 100644 src/main/webapp/WEB-INF/views/crdn/crndRegistAndView/main/crdnRelevy/relevyPopup.jsp diff --git a/DB-DDL/maria/ddl/ibmsdb/tb_act_info.sql b/DB-DDL/maria/ddl/ibmsdb/tb_act_info.sql index c51a8a5..0ba5359 100644 --- a/DB-DDL/maria/ddl/ibmsdb/tb_act_info.sql +++ b/DB-DDL/maria/ddl/ibmsdb/tb_act_info.sql @@ -1,36 +1,33 @@ create table tb_act_info ( - ACT_INFO_ID varchar(10) not null comment '행위 정보 ID' + ACT_INFO_ID varchar(10) not null comment '행위 정보 ID' primary key, - SGG_CD varchar(5) not null comment '시군구 코드', - CRDN_YR char(4) null comment '단속 연도', - CRDN_NO varchar(6) null comment '단속 번호', - PSTN_INFO_ID varchar(10) not null comment '위치 정보 ID', - ACT_BGNG_YMD char(8) null comment '행위 시작 일자', - ACT_TYPE_CD varchar(2) null comment '행위 유형 코드', - VLTN_LWRG_CD_1 varchar(3) null comment '위반 법규 코드 1', - VLTN_LWRG_CD_2 varchar(3) null comment '위반 법규 코드 2', - STRCT_IDX_CD varchar(3) null comment '구조 지수 코드', - USG_IDX_CD varchar(5) null comment '용도 지수 코드', - HGT decimal(10, 2) null comment '높이', - WDTH decimal(10, 2) null comment '가로', - VRTC decimal(10, 2) null comment '세로', - AREA decimal(10, 2) null comment '면적', - RMRK varchar(1000) null comment '비고', - ACTN_LAST_YMD varchar(8) null comment '조치 최종 일자', - ACTN_WHOL_AREA decimal(10, 2) null comment '조치 총 면적', - ACTN_PRCS_STTS_CD varchar(1) null comment '조치 처리 상태 코드', - REG_DT datetime null comment '등록 일시', - RGTR varchar(11) null comment '등록자', - MDFCN_DT datetime null comment '수정 일시', - MDFR varchar(11) null comment '수정자', - DEL_YN char not null comment '삭제 여부', - DEL_DT datetime null comment '삭제 일시', - DLTR varchar(11) null comment '삭제자', - ACT_NO varchar(1) null comment '행위 번호', - ACTN_YMD varchar(8) null, - ACTN_AREA decimal(10, 2) null, - ACTN_RMRK varchar(1000) null + SGG_CD varchar(5) not null comment '시군구 코드', + CRDN_YR char(4) null comment '단속 연도', + CRDN_NO varchar(6) null comment '단속 번호', + PSTN_INFO_ID varchar(10) not null comment '위치 정보 ID', + ACT_BGNG_YMD char(8) null comment '행위 시작 일자', + ACT_TYPE_CD varchar(3) null comment '행위 유형 코드', + VLTN_LWRG_CD_1 varchar(3) null comment '위반 법규 코드 1', + VLTN_LWRG_CD_2 varchar(3) null comment '위반 법규 코드 2', + STRCT_IDX_CD varchar(3) null comment '구조 지수 코드', + USG_IDX_CD varchar(5) null comment '용도 지수 코드', + HGT decimal(10, 2) null comment '높이', + WDTH decimal(10, 2) null comment '가로', + VRTC decimal(10, 2) null comment '세로', + AREA decimal(10, 2) null comment '면적', + RMRK varchar(1000) null comment '비고', + REG_DT datetime null comment '등록 일시', + RGTR varchar(11) null comment '등록자', + MDFCN_DT datetime null comment '수정 일시', + MDFR varchar(11) null comment '수정자', + DEL_YN char not null comment '삭제 여부', + DEL_DT datetime null comment '삭제 일시', + DLTR varchar(11) null comment '삭제자', + ACT_NO varchar(2) null comment '행위 번호', + ACTN_LAST_YMD varchar(8) null comment '조치 최종 일자', + ACTN_WHOL_AREA decimal(10, 2) null comment '조치 총 면적', + ACTN_PRCS_STTS_CD varchar(1) null comment '조치 처리 상태 코드' ) comment '행위 정보'; diff --git a/DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt.sql b/DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt.sql new file mode 100644 index 0000000..a63b39c --- /dev/null +++ b/DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt.sql @@ -0,0 +1,16 @@ +create table tb_cmpttn_rt +( + CMPTTN_RT_CD varchar(3) not null comment '산정 률 코드' + primary key, + VLTN_BDST varchar(100) null comment '위반 건축물', + LAWLPRVS varchar(100) null comment '법조문', + CMPTTN_RT decimal(3) null comment '산정 률', + VLTN_BDST_DTL varchar(1000) null comment '위반 건축물 상세', + USE_YN char not null comment '사용 여부', + REG_DT datetime null comment '등록 일시', + RGTR varchar(11) null comment '등록자', + MDFCN_DT datetime null comment '수정 일시', + MDFR varchar(11) null comment '수정자' +) + comment '산정 률'; + diff --git a/DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt_2.sql b/DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt_2.sql new file mode 100644 index 0000000..b745944 --- /dev/null +++ b/DB-DDL/maria/ddl/ibmsdb/tb_cmpttn_rt_2.sql @@ -0,0 +1,14 @@ +create table tb_cmpttn_rt_2 +( + CMPTTN_RT_2_CD varchar(1) not null comment '산정 률 2 코드' + primary key, + VLTN_MTTR varchar(100) null comment '위반 사항', + CMPTTN_RT_2 decimal(3) null comment '산정 률 2', + USE_YN char not null comment '사용 여부', + REG_DT datetime null comment '등록 일시', + RGTR varchar(11) null comment '등록자', + MDFCN_DT datetime null comment '수정 일시', + MDFR varchar(11) null comment '수정자' +) + comment '산정 률 2'; + diff --git a/DB-DDL/maria/ddl/ibmsdb/tb_crdn.sql b/DB-DDL/maria/ddl/ibmsdb/tb_crdn.sql index 252f288..87eaba8 100644 --- a/DB-DDL/maria/ddl/ibmsdb/tb_crdn.sql +++ b/DB-DDL/maria/ddl/ibmsdb/tb_crdn.sql @@ -31,6 +31,8 @@ create table tb_crdn DEL_YN char not null comment '삭제 여부', DEL_DT datetime null comment '삭제 일시', DLTR varchar(11) null comment '삭제자', + RELEVY_TRGT_CRDN_YR varchar(4) null comment '재부과 대상 단속 연도', + RELEVY_TRGT_CRDN_NO varchar(6) null comment '재부과 대상 단속 번호', primary key (CRDN_YR, CRDN_NO) ) comment '단속'; diff --git a/DB-DDL/maria/ddl/ibmsdb/tb_implt_trpr_info.sql b/DB-DDL/maria/ddl/ibmsdb/tb_implt_trpr_info.sql index 4f796db..fc5acd9 100644 --- a/DB-DDL/maria/ddl/ibmsdb/tb_implt_trpr_info.sql +++ b/DB-DDL/maria/ddl/ibmsdb/tb_implt_trpr_info.sql @@ -9,7 +9,8 @@ create table tb_implt_trpr_info IMPLT_TRPR_DADDR varchar(320) null comment '이행 대상자 상세주소', IMPLT_TRPR_ZIP varchar(6) null comment '이행 대상자 우편번호', IMPLT_TRPR_SE_CD varchar(1) null comment '이행 대상자 구분 코드', - OWNR_ACTR_INFO_ID varchar(1) null comment '소유자 행위자 정보 ID', + OWNR_ACTR_INFO_ID varchar(10) not null comment '소유자 행위자 정보 ID', + ACT_NO varchar(2) null comment '행위 번호', REG_DT datetime null comment '등록 일시', RGTR varchar(11) null comment '등록자', MDFCN_DT datetime null comment '수정 일시', diff --git a/DB-DDL/maria/ddl/ibmsdb/tb_res_ret.sql b/DB-DDL/maria/ddl/ibmsdb/tb_res_ret.sql new file mode 100644 index 0000000..893ce46 --- /dev/null +++ b/DB-DDL/maria/ddl/ibmsdb/tb_res_ret.sql @@ -0,0 +1,21 @@ +create table tb_res_ret +( + res_div int not null, + res_no varchar(20) not null, + res_name varchar(50) null, + addr_main varchar(100) null, + addr_sub varchar(100) null, + zip_code varchar(6) null, + tel_no varchar(50) null, + tel_no2 varchar(50) null, + mail_addr varchar(200) null, + del_yn int null, + createdate datetime null, + modifydate datetime null, + in_date datetime null, + up_date datetime null, + datain_user varchar(50) null, + dataup_user varchar(50) null +) + charset = euckr; + diff --git a/DB-DDL/maria/ddl/ibmsdb/tb_res_ret_backup.sql b/DB-DDL/maria/ddl/ibmsdb/tb_res_ret_backup.sql new file mode 100644 index 0000000..9df31c3 --- /dev/null +++ b/DB-DDL/maria/ddl/ibmsdb/tb_res_ret_backup.sql @@ -0,0 +1,21 @@ +create table tb_res_ret_backup +( + res_div int not null, + res_no varchar(20) not null, + res_name varchar(50) null, + addr_main varchar(100) null, + addr_sub varchar(100) null, + zip_code varchar(6) null, + tel_no varchar(50) null, + tel_no2 varchar(50) null, + mail_addr varchar(200) null, + del_yn int null, + createdate datetime null, + modifydate datetime null, + in_date datetime null, + up_date datetime null, + datain_user varchar(50) null, + dataup_user varchar(50) null +) + charset = euckr; + diff --git a/DB-DDL/maria/ddl/ibmsdb/tb_strct_idx.sql b/DB-DDL/maria/ddl/ibmsdb/tb_strct_idx.sql index 4ab73d5..3027dee 100644 --- a/DB-DDL/maria/ddl/ibmsdb/tb_strct_idx.sql +++ b/DB-DDL/maria/ddl/ibmsdb/tb_strct_idx.sql @@ -1,19 +1,22 @@ create table tb_strct_idx ( - STRCT_IDX_CD varchar(3) not null comment '구조 지수 코드' + STRCT_IDX_CD varchar(3) not null comment '구조 지수 코드' primary key, - STRCT_NM varchar(100) null comment '구조 명', - STRCT_IDX decimal(10, 2) null comment '구조 지수', - REG_DT datetime null comment '등록 일시', - RGTR varchar(11) null comment '등록자', - MDFCN_DT datetime null comment '수정 일시', - MDFR varchar(11) null comment '수정자', - DEL_YN char not null comment '삭제 여부', - DEL_DT datetime null comment '삭제 일시', - DLTR varchar(11) null comment '삭제자', - RDVLRT_CN_YR_CNT decimal(2) null comment '잔가율 내용 연도 수', - LAST_YR_RDVLRT decimal(4, 2) null comment '최종 연도 잔가율', - DPRT decimal(4, 4) null comment '감가상각률' + STRCT_NM varchar(100) null comment '구조 명', + STRCT_IDX decimal(10, 2) null comment '구조 지수', + RDVLRT_CN_YR_CNT decimal(2) null comment '잔가율 내용 연도 수', + LAST_YR_RDVLRT decimal(4, 2) null comment '최종 연도 잔가율', + DPRT decimal(4, 4) null comment '감가상각률', + BSCS_CSTRN_Y_BDST_CMPTTN_RT decimal(10, 2) null comment '기초 공사 Y 건축물 산정 비율', + BSCS_CSTRN_N_BDST_CMPTTN_RT decimal(10, 2) null comment '기초 공사 N 건축물 산정 비율', + DUP_ETBLDG_BDST_CMPTTN_RT decimal(10, 2) null comment '복층 증축 건축물 산정 비율', + REG_DT datetime null comment '등록 일시', + RGTR varchar(11) null comment '등록자', + MDFCN_DT datetime null comment '수정 일시', + MDFR varchar(11) null comment '수정자', + DEL_YN char not null comment '삭제 여부', + DEL_DT datetime null comment '삭제 일시', + DLTR varchar(11) null comment '삭제자' ) comment '구조 지수'; diff --git a/src/main/java/egovframework/util/FileUtil.java b/src/main/java/egovframework/util/FileUtil.java index 3843fde..1886bff 100644 --- a/src/main/java/egovframework/util/FileUtil.java +++ b/src/main/java/egovframework/util/FileUtil.java @@ -637,4 +637,50 @@ public class FileUtil { return filename.substring(lastDotIndex + 1).toLowerCase(); } + + /** + * 파일을 새로운 경로로 복사합니다. + * 원본 파일과 동일한 디렉토리 구조를 유지하며 복사합니다. + * + * @param sourcePath 원본 파일 경로 + * @param targetPath 대상 파일 경로 + * @return 복사 성공 여부 + * @throws IOException 파일 복사 실패 시 예외 발생 + */ + public boolean copyFile(String sourcePath, String targetPath) throws IOException { + if (sourcePath == null || targetPath == null) { + throw new IOException("원본 또는 대상 파일 경로가 null입니다."); + } + + File sourceFile = new File(sourcePath); + File targetFile = new File(targetPath); + + // 원본 파일 존재 여부 확인 + if (!sourceFile.exists()) { + throw new IOException("원본 파일이 존재하지 않습니다: " + sourcePath); + } + + // 원본 파일이 일반 파일인지 확인 + if (!sourceFile.isFile()) { + throw new IOException("원본이 일반 파일이 아닙니다: " + sourcePath); + } + + // 대상 디렉토리 생성 + File targetDir = targetFile.getParentFile(); + if (targetDir != null && !targetDir.exists()) { + if (!targetDir.mkdirs()) { + throw new IOException("대상 디렉토리 생성 실패: " + targetDir.getAbsolutePath()); + } + } + + // 파일 복사 + try { + Files.copy(sourceFile.toPath(), targetFile.toPath(), + java.nio.file.StandardCopyOption.REPLACE_EXISTING); + return true; + } catch (IOException e) { + throw new IOException("파일 복사 실패: " + sourcePath + " -> " + targetPath, e); + } + } + } diff --git a/src/main/java/go/kr/project/crdn/crndRegistAndView/crdnActInfo/service/impl/CrdnPhotoServiceImpl.java b/src/main/java/go/kr/project/crdn/crndRegistAndView/crdnActInfo/service/impl/CrdnPhotoServiceImpl.java index 9061e20..7e934aa 100644 --- a/src/main/java/go/kr/project/crdn/crndRegistAndView/crdnActInfo/service/impl/CrdnPhotoServiceImpl.java +++ b/src/main/java/go/kr/project/crdn/crndRegistAndView/crdnActInfo/service/impl/CrdnPhotoServiceImpl.java @@ -12,6 +12,7 @@ import go.kr.project.crdn.crndRegistAndView.crdnActInfo.service.CrdnPhotoService import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -44,6 +45,12 @@ public class CrdnPhotoServiceImpl extends EgovAbstractServiceImpl implements Crd private final CrdnPhotoMapper mapper; private final FileUtil fileUtil; + @Value("${file.upload.sub-dirs.crdn-act-photo}") + String atcFileStorePath; + + @Value("${file.upload.sub-dirs.crdn-actn-photo}") + String atcnFileStorePath; + public List selectPhotoListByActInfoIdAndPhotoSeCd(CrdnPhotoVO photoVO) { log.debug("단속 사진 목록 조회: actInfoId={}, CrdnPhotoSeCd={}", photoVO.getActInfoId(), photoVO.getCrdnPhotoSeCd()); return mapper.selectPhotoListByActInfoIdAndPhotoSeCd(photoVO); @@ -85,7 +92,7 @@ public class CrdnPhotoServiceImpl extends EgovAbstractServiceImpl implements Crd try { // 중요한 로직 주석: FileUtil을 통해 파일 업로드 처리 - List uploadedFiles = fileUtil.uploadFiles(files, "crdn-act-photo"); + List uploadedFiles = fileUtil.uploadFiles(files, atcFileStorePath); for (FileVO fileVO : uploadedFiles) { // 중요한 로직 주석: 다음 사진 순번 생성 @@ -151,7 +158,7 @@ public class CrdnPhotoServiceImpl extends EgovAbstractServiceImpl implements Crd } // 중요한 로직 주석: 새 파일 업로드 - List uploadedFiles = fileUtil.uploadFiles(Arrays.asList(file), "crdn-act-photo"); + List uploadedFiles = fileUtil.uploadFiles(Arrays.asList(file), atcFileStorePath); if (!uploadedFiles.isEmpty()) { FileVO newFileVO = uploadedFiles.get(0); @@ -317,7 +324,7 @@ public class CrdnPhotoServiceImpl extends EgovAbstractServiceImpl implements Crd try { // 중요한 로직 주석: FileUtil을 통한 파일 저장 (단일 파일을 리스트로 변환하여 처리) List singleFileList = Arrays.asList(file); - List uploadedFiles = fileUtil.uploadFiles(singleFileList, "crdn-act-photo"); + List uploadedFiles = fileUtil.uploadFiles(singleFileList, atcnFileStorePath); if (uploadedFiles.isEmpty()) { log.error("파일 저장 실패: {}", file.getOriginalFilename()); diff --git a/src/main/java/go/kr/project/crdn/crndRegistAndView/main/controller/CrdnRelevyController.java b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/controller/CrdnRelevyController.java new file mode 100644 index 0000000..5dd1a6a --- /dev/null +++ b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/controller/CrdnRelevyController.java @@ -0,0 +1,134 @@ +package go.kr.project.crdn.crndRegistAndView.main.controller; + +import egovframework.constant.MessageConstants; +import egovframework.constant.TilesConstants; +import egovframework.exception.MessageException; +import egovframework.util.ApiResponseUtil; +import egovframework.util.SessionUtil; +import go.kr.project.crdn.crndRegistAndView.main.model.CrdnRegistAndViewVO; +import go.kr.project.crdn.crndRegistAndView.main.model.CrdnRelevyVO; +import go.kr.project.crdn.crndRegistAndView.main.service.CrdnRelevyService; +import go.kr.project.crdn.crndRegistAndView.main.service.CrdnRegistAndViewService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import java.util.HashMap; +import java.util.Map; + +/** + * packageName : go.kr.project.crdn.crndRegistAndView.main.controller + * fileName : CrdnRelevyController + * author : 시스템 관리자 + * date : 2025-09-29 + * description : 재부과 관련 요청을 처리하는 컨트롤러 + * 중요한 로직 주석: 단속 재부과 기능을 제공하는 컨트롤러 - 기존 단속 정보를 복사하여 새로운 단속으로 등록 + * =========================================================== + * DATE AUTHOR NOTE + * ----------------------------------------------------------- + * 2025-09-29 시스템 관리자 최초 생성 + */ +@Controller +@RequestMapping("/crdn/crndRegistAndView/crdnRelevy") +@RequiredArgsConstructor +@Slf4j +@Tag(name = "재부과 관리", description = "재부과 관련 API") +public class CrdnRelevyController { + + /** 재부과 서비스 */ + private final CrdnRelevyService relevyService; + + /** 단속 서비스 */ + private final CrdnRegistAndViewService crdnService; + + /** + * 재부과 팝업 화면을 제공한다. + * @param model 모델 + * @return 재부과 팝업 화면 + */ + @GetMapping("/relevyPopup.do") + @Operation(summary = "재부과 팝업 화면", description = "재부과 등록을 위한 팝업 화면을 제공합니다.") + public String relevyPopup( + @Parameter(description = "단속 년도", required = true) @RequestParam String srcCrdnYr, + @Parameter(description = "단속 번호", required = true) @RequestParam String srcCrdnNo, + @Parameter(description = "팝업 모드", required = true) @RequestParam String mode, + Model model) { + log.debug("재부과 팝업 화면 요청"); + model.addAttribute("srcCrdnYr", srcCrdnYr); + model.addAttribute("srcCrdnNo", srcCrdnNo); + model.addAttribute("mode", mode); + return "crdn/crndRegistAndView/main/crdnRelevy/relevyPopup" + TilesConstants.POPUP; + } + + /** + * 원본 단속 정보를 조회한다. + * @param crdnYr 단속 년도 + * @param crdnNo 단속 번호 + * @return 원본 단속 정보 + */ + @GetMapping("/selectOrgCrdnInfo.ajax") + @Operation(summary = "원본 단속 정보 조회", description = "재부과 대상이 되는 원본 단속 정보를 조회합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "400", description = "잘못된 요청") + }) + public ResponseEntity selectOrgCrdnInfo( + @Parameter(description = "단속 년도", required = true) @RequestParam String crdnYr, + @Parameter(description = "단속 번호", required = true) @RequestParam String crdnNo) { + + log.debug("원본 단속 정보 조회 요청: crdnYr={}, crdnNo={}", crdnYr, crdnNo); + + CrdnRelevyVO searchVO = new CrdnRelevyVO(); + searchVO.setCrdnYr(crdnYr); + searchVO.setCrdnNo(crdnNo); + + CrdnRelevyVO orgCrdnInfo = relevyService.selectCrdnPstnInfoOne(searchVO); + if (orgCrdnInfo == null) { + throw new MessageException("원본 단속 정보가 존재하지 않습니다."); + } + + return ApiResponseUtil.success(orgCrdnInfo); + } + + /** + * 재부과를 저장한다. + * @param relevyVO 재부과 정보 + * @return 저장 결과 + */ + @PostMapping("/saveRelevy.ajax") + @Operation(summary = "재부과 저장", description = "재부과 정보를 저장하고 새로운 단속 건을 생성합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "400", description = "잘못된 요청") + }) + public ResponseEntity saveRelevy(@RequestBody CrdnRelevyVO relevyVO) { + + log.debug("재부과 저장 요청: {}", relevyVO); + + // 필수값 검증 + if (relevyVO.getSrcCrdnYr() == null || relevyVO.getSrcCrdnNo() == null) { + throw new MessageException("원본 단속 정보가 없습니다."); + } + if (relevyVO.getRelevyRsn() == null || relevyVO.getRelevyRsn().trim().isEmpty()) { + throw new MessageException("재부과 사유를 입력해주세요."); + } + + // 등록자 정보 설정 + relevyVO.setRgtr(SessionUtil.getUserId()); + + // 재부과 처리 (원본 단속 정보 복사 및 새로운 단속 생성) + Map result = relevyService.processRelevy(relevyVO); + + return ApiResponseUtil.success(result); + + } +} \ No newline at end of file diff --git a/src/main/java/go/kr/project/crdn/crndRegistAndView/main/mapper/CrdnRelevyMapper.java b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/mapper/CrdnRelevyMapper.java new file mode 100644 index 0000000..e4fa353 --- /dev/null +++ b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/mapper/CrdnRelevyMapper.java @@ -0,0 +1,106 @@ +package go.kr.project.crdn.crndRegistAndView.main.mapper; + +import go.kr.project.crdn.crndRegistAndView.main.model.CrdnRelevyVO; +import go.kr.project.crdn.crndRegistAndView.crdnActInfo.model.CrdnPhotoVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * packageName : go.kr.project.crdn.crndRegistAndView.main.mapper + * fileName : CrdnRelevyMapper + * author : 시스템 관리자 + * date : 2025-09-29 + * description : 재부과 관련 데이터베이스 접근을 위한 MyBatis 매퍼 인터페이스 + * 중요한 로직 주석: 원본 단속 정보를 복사하여 새로운 단속을 생성하는 복잡한 데이터베이스 작업을 수행 + * =========================================================== + * DATE AUTHOR NOTE + * ----------------------------------------------------------- + * 2025-09-29 시스템 관리자 최초 생성 + */ +@Mapper +public interface CrdnRelevyMapper { + + // 재부과 대상정보 조회 + CrdnRelevyVO selectCrdnPstnInfoOne(CrdnRelevyVO crdnRelevyVO); + + /** + * 지정된 년도의 다음 단속 번호를 조회한다. + * @param crdnYr 단속 년도 + * @return 다음 단속 번호 (10자리 LPAD 형태) + */ + String selectNextCrdnNo(@Param("crdnYr") String crdnYr); + + /** + * 기본 단속 정보를 복사하여 신규 등록한다. + * 원본 단속의 모든 기본 정보를 현재 년도로 복사하되, 재부과 여부를 'Y'로 설정한다. + * @param relevyVO 재부과 정보 + * @return 등록된 행의 수 + */ + int insertCrdnBasicInfo(CrdnRelevyVO relevyVO); + + /** + * 위치 정보를 복사하여 신규 등록한다. + * @param relevyVO 재부과 정보 + * @return 등록된 행의 수 + */ + int insertCrdnPstnInfo(CrdnRelevyVO relevyVO); + + /** + * 소유자 정보를 복사하여 신규 등록한다. + * @param relevyVO 재부과 정보 + * @return 등록된 행의 수 + */ + int insertCrdnOwnrInfo(CrdnRelevyVO relevyVO); + + /** + * 불법행위 정보를 복사하여 신규 등록한다. + * 조치완료된 항목은 제외하고 복사한다. + * @param relevyVO 재부과 정보 + * @return 등록된 행의 수 + */ + int insertCrdnActInfo(CrdnRelevyVO relevyVO); + + /** + * 첨부파일 정보를 복사하여 신규 등록한다. + * 조치완료된 항목과 연결된 파일은 제외하고 복사한다. + * @param relevyVO 재부과 정보 + * @return 등록된 행의 수 + */ + int insertCrdnPhotoInfo(CrdnRelevyVO relevyVO); + + /** + * 행위자 정보를 복사하여 신규 등록한다. + * 조치완료된 항목은 제외하고 복사한다. + * @param relevyVO 재부과 정보 + * @return 등록된 행의 수 + */ + int insertCrdnActrInfo(CrdnRelevyVO relevyVO); + + /** + * 단속 상태를 업데이트한다. + * 현재 진행 상태를 시정명령(CRDN_PRCS_STTS_CD_30_CRC_CMD)으로 설정하고 + * 최초단속년도, 최초단속번호를 원본 정보로 설정한다. + * @param relevyVO 재부과 정보 + * @return 수정된 행의 수 + */ + int updateCrdnStatus(CrdnRelevyVO relevyVO); + + /** + * 원본 단속의 첨부파일 목록을 조회한다. + * 조치완료된 항목은 제외하고 조회한다. + * @param srcCrdnYr 원본 단속 년도 + * @param srcCrdnNo 원본 단속 번호 + * @return 첨부파일 목록 + */ + List selectSrcPhotoList(@Param("srcCrdnYr") String srcCrdnYr, @Param("srcCrdnNo") String srcCrdnNo); + + /** + * 재부과 첨부파일 정보를 업데이트한다. + * 물리적 파일 복사 후 새로운 파일명으로 데이터베이스 정보를 갱신한다. + * @param updateParams 업데이트할 파라미터 (newCrdnYr, newCrdnNo, crdnPhotoSn, crdnPhotoNm) + * @return 수정된 행의 수 + */ + int updateRelevyPhotoInfo(java.util.Map updateParams); +} \ No newline at end of file diff --git a/src/main/java/go/kr/project/crdn/crndRegistAndView/main/model/CrdnRelevyVO.java b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/model/CrdnRelevyVO.java new file mode 100644 index 0000000..aef6edb --- /dev/null +++ b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/model/CrdnRelevyVO.java @@ -0,0 +1,151 @@ +package go.kr.project.crdn.crndRegistAndView.main.model; + +import com.fasterxml.jackson.annotation.JsonFormat; +import go.kr.project.common.model.PagingVO; +import lombok.*; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +/** + * packageName : go.kr.project.crdn.crndRegistAndView.main.model + * fileName : CrdnRelevyVO + * author : 시스템 관리자 + * date : 2025-09-29 + * description : 재부과 관련 데이터를 담는 Value Object 클래스 + * 중요한 로직 주석: 재부과 처리를 위한 VO 클래스 - 원본 단속 정보와 재부과 사유를 포함한다. + * =========================================================== + * DATE AUTHOR NOTE + * ----------------------------------------------------------- + * 2025-09-29 시스템 관리자 최초 생성 + */ +@EqualsAndHashCode(callSuper=true) +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class CrdnRelevyVO extends PagingVO { + + // ==================== 원본/신규 단속 정보 ==================== + /** 단속 연도 */ + private String crdnYr; + /** 단속 번호 */ + private String crdnNo; + /** 원본 단속 연도 */ + private String srcCrdnYr; + /** 원본 단속 번호 */ + private String srcCrdnNo; + /** 신규 단속 연도 (재부과 후 생성되는 단속 연도) */ + private String newCrdnYr; + /** 신규 단속 번호 (재부과 후 생성되는 단속 번호) */ + private String newCrdnNo; + + // ==================== 재부과 정보 ==================== + /** 재부과 사유 */ + private String relevyRsn; + + // ==================== 단속 기본 정보 ==================== + /** 시군구 코드 */ + private String sggCd; + /** 시군구 코드 명 */ + private String sggCdNm; + /** 지역 구분 코드 */ + private String rgnSeCd; + /** 지역 구분 코드 명 */ + private String rgnSeCdNm; + /** 적발 방법 코드 */ + private String dsclMthdCd; + /** 적발 방법 코드 명 */ + private String dsclMthdCdNm; + /** 적발 일자 */ + private String dsclYmd; + /** 조사원 */ + private String exmnr; + /** 비고 */ + private String rmrk; + /** 최초 단속 연도 */ + private String frstCrdnYr; + /** 최초 단속 번호 */ + private String frstCrdnNo; + /** 재부과 여부 */ + private String relevyYn; + /** 가중 부과 대상 여부 */ + private String agrvtnLevyTrgtYn; + /** 단속 처리 상태 코드 */ + private String crdnPrcsSttsCd; + /** 단속 처리 상태 코드 명 */ + private String crdnPrcsSttsCdNm; + /** 단속 처리 일자 */ + private String crdnPrcsYmd; + + // ==================== 처리 기간 정보 ==================== + /** 처분 사전 예고 시작일 */ + private String dspsBfhdBgngYmd; + /** 처분 사전 예고 종료일 */ + private String dspsBfhdEndYmd; + /** 시정명령 시작일 */ + private String crcCmdBgngYmd; + /** 시정명령 종료일 */ + private String crcCmdEndYmd; + /** 시정촉구 시작일 */ + private String crcUrgBgngYmd; + /** 시정촉구 종료일 */ + private String crcUrgEndYmd; + /** 부과 예고 시작일 */ + private String levyPrvntcBgngYmd; + /** 부과 예고 종료일 */ + private String levyPrvntcEndYmd; + /** 부과 시작일 */ + private String levyBgngYmd; + /** 부과 종료일 */ + private String levyEndYmd; + /** 납부 촉구 시작일 */ + private String payUrgBgngYmd; + /** 납부 촉구 종료일 */ + private String payUrgEndYmd; + + // ==================== 위치/주소 정보 ==================== + /** 소재지 행정동 코드 */ + private String stdgEmdCd; + /** 소재지 행정동 코드 명 */ + private String stdgEmdCdNm; + /** 지목 코드 */ + private String ldcgCd; + /** 지목 코드 명 */ + private String ldcgCdNm; + /** 지번 */ + private String ptout; + /** 공시지가 */ + private String oalp; + /** 지번 전체 주소 */ + private String lotnoWholAddr; + /** 도로명 전체 주소 */ + private String roadNmWholAddr; + /** 우편번호 */ + private String zip; + /** 지상지하 여부 코드 */ + private String udgdYnCd; + /** 산 여부 코드 */ + private String mtnYnCd; + + // ==================== 등록자 정보 ==================== + /** 등록자 계정 */ + private String rgtrAcnt; + /** 등록자 이름 */ + private String rgtrNm; + + // ==================== 공통 컬럼 ==================== + /** 등록자 */ + private String rgtr; + /** 등록 일시 */ + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime regDt; + /** 수정자 */ + private String mdfr; + /** 수정 일시 */ + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime mdfcnDt; +} \ No newline at end of file diff --git a/src/main/java/go/kr/project/crdn/crndRegistAndView/main/service/CrdnRelevyService.java b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/service/CrdnRelevyService.java new file mode 100644 index 0000000..f411cbe --- /dev/null +++ b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/service/CrdnRelevyService.java @@ -0,0 +1,34 @@ +package go.kr.project.crdn.crndRegistAndView.main.service; + +import go.kr.project.crdn.crndRegistAndView.main.model.CrdnRelevyVO; + +import java.util.Map; + +/** + * packageName : go.kr.project.crdn.crndRegistAndView.main.service + * fileName : CrdnRelevyService + * author : 시스템 관리자 + * date : 2025-09-29 + * description : 재부과 관련 비즈니스 로직을 처리하는 서비스 인터페이스 + * 중요한 로직 주석: 원본 단속 정보를 복사하여 새로운 단속으로 재부과하는 비즈니스 로직을 제공 + * =========================================================== + * DATE AUTHOR NOTE + * ----------------------------------------------------------- + * 2025-09-29 시스템 관리자 최초 생성 + */ +public interface CrdnRelevyService { + + /* + * 재부과 대상 원본 조회 + * */ + CrdnRelevyVO selectCrdnPstnInfoOne(CrdnRelevyVO crdnRelevyVO); + + /** + * 재부과 처리를 수행합니다. + * 원본 단속 정보를 복사하여 새로운 단속 건으로 등록하고, 관련 정보들을 모두 복사합니다. + * + * @param relevyVO 재부과 정보를 담은 VO 객체 + * @return 처리 결과 (신규 단속 번호 등) + */ + Map processRelevy(CrdnRelevyVO relevyVO); +} \ No newline at end of file diff --git a/src/main/java/go/kr/project/crdn/crndRegistAndView/main/service/impl/CrdnRelevyServiceImpl.java b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/service/impl/CrdnRelevyServiceImpl.java new file mode 100644 index 0000000..65f2356 --- /dev/null +++ b/src/main/java/go/kr/project/crdn/crndRegistAndView/main/service/impl/CrdnRelevyServiceImpl.java @@ -0,0 +1,233 @@ +package go.kr.project.crdn.crndRegistAndView.main.service.impl; + +import egovframework.exception.MessageException; +import egovframework.util.FileUtil; +import go.kr.project.crdn.crndRegistAndView.main.mapper.CrdnRegistAndViewMapper; +import go.kr.project.crdn.crndRegistAndView.main.mapper.CrdnRelevyMapper; +import go.kr.project.crdn.crndRegistAndView.main.model.CrdnRelevyVO; +import go.kr.project.crdn.crndRegistAndView.crdnActInfo.model.CrdnPhotoVO; +import go.kr.project.crdn.crndRegistAndView.main.service.CrdnRegistAndViewService; +import go.kr.project.crdn.crndRegistAndView.main.service.CrdnRelevyService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static egovframework.constant.SEQConstants.SEQ_CRDN; + +/** + * packageName : go.kr.project.crdn.crndRegistAndView.main.service + * fileName : CrdnRelevyServiceImpl + * author : 시스템 관리자 + * date : 2025-09-29 + * description : 재부과 관련 비즈니스 로직을 처리하는 서비스 구현체 + * 중요한 로직 주석: 원본 단속 정보를 현재 년도로 복사하여 새로운 단속을 생성하는 복잡한 비즈니스 로직 + * =========================================================== + * DATE AUTHOR NOTE + * ----------------------------------------------------------- + * 2025-09-29 시스템 관리자 최초 생성 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class CrdnRelevyServiceImpl implements CrdnRelevyService { + + private final CrdnRelevyMapper relevyMapper; + private final CrdnRegistAndViewMapper crdnRegistAndViewMapper; + private final CrdnRegistAndViewService crdnRegistAndViewService; + private final FileUtil fileUtil; + + + @Override + public CrdnRelevyVO selectCrdnPstnInfoOne(CrdnRelevyVO crdnRelevyVO) { + return relevyMapper.selectCrdnPstnInfoOne(crdnRelevyVO); + } + + /** + * 재부과 처리를 수행합니다. + * 트랜잭션 처리로 모든 데이터가 정상적으로 복사되거나 모두 롤백됩니다. + * + * @param relevyVO 재부과 정보를 담은 VO 객체 + * @return 처리 결과 (신규 단속 번호 등) + */ + @Override + @Transactional + public Map processRelevy(CrdnRelevyVO relevyVO) { + log.info("재부과 처리 시작: srcCrdnYr={}, srcCrdnNo={}", relevyVO.getSrcCrdnYr(), relevyVO.getSrcCrdnNo()); + + try { + // 1. 현재 년도 설정 + String currentYear = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy")); + + // 년도별 시퀀스 존재 여부 확인 및 생성 + ensureSequenceExists(currentYear); + + // 2. 신규 단속 번호 생성 (현재 년도 기준) + relevyVO.setNewCrdnYr(currentYear); + String newCrdnNo = relevyMapper.selectNextCrdnNo(currentYear); + relevyVO.setNewCrdnNo(newCrdnNo); + + // 3. 기본 단속 정보 복사 (tb_crdn) + int result = relevyMapper.insertCrdnBasicInfo(relevyVO); + if (result <= 0) { + throw new MessageException("기본 단속 정보 복사 실패"); + } + + // 4. 위치 정보 복사 (tb_crdn_pstn_info) + relevyMapper.insertCrdnPstnInfo(relevyVO); + + // 5. 소유자 정보 복사 (tb_crdn_ownr_info) + relevyMapper.insertCrdnOwnrInfo(relevyVO); + + // 6. 불법행위 정보 복사 (조치완료 제외) + // 6-1. 행위 정보 (tb_crdn_act_info) + relevyMapper.insertCrdnActInfo(relevyVO); + + // 6-2. 첨부파일 복사 (조치완료 제외) - 데이터베이스 레코드 복사 + relevyMapper.insertCrdnPhotoInfo(relevyVO); + + // 6-3. 물리적 파일 복사 + processPhysicalFileCopy(relevyVO); + + // 7. 조치 정보 복사 (조치완료 제외) + // 7-1. 행위자 정보 (tb_crdn_actr_info) + relevyMapper.insertCrdnActrInfo(relevyVO); + + // 8. 현재 진행 상태를 시정명령(30)으로 설정 및 최초단속 정보 업데이트 + relevyMapper.updateCrdnStatus(relevyVO); + + log.info("재부과 처리 완료: 신규 단속번호={}", newCrdnNo); + + // 결과 반환 + Map resultMap = new HashMap<>(); + resultMap.put("newCrdnYr", currentYear); + resultMap.put("newCrdnNo", newCrdnNo); + resultMap.put("message", "재부과가 성공적으로 처리되었습니다."); + + return resultMap; + + } catch (Exception e) { + log.error("재부과 처리 중 오류 발생", e); + throw new MessageException("재부과 처리 중 오류가 발생했습니다: " + e.getMessage()); + } + } + + /** + * 물리적 파일 복사를 처리합니다. + * 원본 첨부파일들을 새로운 경로로 복사하고 데이터베이스 정보를 업데이트합니다. + * + * @param relevyVO 재부과 정보 + * @throws MessageException 파일 복사 실패 시 예외 발생 + */ + private void processPhysicalFileCopy(CrdnRelevyVO relevyVO) throws MessageException { + log.info("물리적 파일 복사 시작: srcCrdnYr={}, srcCrdnNo={}", relevyVO.getSrcCrdnYr(), relevyVO.getSrcCrdnNo()); + + try { + // 원본 첨부파일 목록 조회 + List srcPhotoList = relevyMapper.selectSrcPhotoList(relevyVO.getSrcCrdnYr(), relevyVO.getSrcCrdnNo()); + + if (srcPhotoList == null || srcPhotoList.isEmpty()) { + log.info("복사할 첨부파일이 없습니다."); + return; + } + + log.info("복사할 첨부파일 개수: {}", srcPhotoList.size()); + + // 각 파일에 대해 복사 처리 + for (CrdnPhotoVO srcPhoto : srcPhotoList) { + copyPhysicalFile(srcPhoto, relevyVO); + } + + log.info("물리적 파일 복사 완료"); + + } catch (Exception e) { + log.error("물리적 파일 복사 중 오류 발생", e); + throw new MessageException("첨부파일 복사 중 오류가 발생했습니다: " + e.getMessage()); + } + } + + /** + * 개별 첨부파일의 물리적 복사를 처리합니다. + * + * @param srcPhoto 원본 첨부파일 정보 + * @param relevyVO 재부과 정보 + */ + private void copyPhysicalFile(CrdnPhotoVO srcPhoto, CrdnRelevyVO relevyVO) { + try { + // 원본 파일 전체 경로 구성 + String srcFilePath = srcPhoto.getCrdnPhotoPath() + "/" + srcPhoto.getCrdnPhotoNm(); + + // UUID를 이용한 새로운 저장 파일명 생성 (기존 로직 사용) + String fileExt = ""; + String orglFileName = srcPhoto.getOrgnlPhotoNm(); + if (orglFileName != null && orglFileName.contains(".")) { + fileExt = orglFileName.substring(orglFileName.lastIndexOf(".") + 1).toLowerCase(); + } + String newStrgFileNm = UUID.randomUUID() + "." + fileExt; + + // 새로운 파일 경로 구성 (동일한 디렉토리 구조 유지) + String newFilePath = srcPhoto.getCrdnPhotoPath(); // 동일한 경로 사용 + String targetFilePath = newFilePath + "/" + newStrgFileNm; + + // 물리적 파일 복사 + boolean copySuccess = fileUtil.copyFile(srcFilePath, targetFilePath); + + if (copySuccess) { + // 복사된 파일 정보로 데이터베이스 업데이트 + // 재부과된 단속 정보의 첨부파일명을 새로운 UUID 파일명으로 변경 + Map updateParams = new HashMap<>(); + updateParams.put("newCrdnYr", relevyVO.getNewCrdnYr()); + updateParams.put("newCrdnNo", relevyVO.getNewCrdnNo()); + updateParams.put("crdnPhotoSn", srcPhoto.getCrdnPhotoSn()); + updateParams.put("crdnPhotoNm", newStrgFileNm); + + int updateResult = relevyMapper.updateRelevyPhotoInfo(updateParams); + if (updateResult <= 0) { + throw new MessageException("첨부파일 정보 업데이트 실패: " + srcPhoto.getOrgnlPhotoNm()); + } + + log.debug("파일 복사 성공: {} -> {}", srcFilePath, targetFilePath); + } else { + throw new MessageException("파일 복사 실패: " + srcPhoto.getOrgnlPhotoNm()); + } + + } catch (IOException e) { + log.error("파일 복사 중 IOException 발생: {}", srcPhoto.getOrgnlPhotoNm(), e); + throw new MessageException("파일 복사 실패: " + srcPhoto.getOrgnlPhotoNm() + " - " + e.getMessage()); + } catch (Exception e) { + log.error("파일 복사 중 예외 발생: {}", srcPhoto.getOrgnlPhotoNm(), e); + throw new MessageException("파일 처리 중 오류 발생: " + srcPhoto.getOrgnlPhotoNm() + " - " + e.getMessage()); + } + } + + + /** + * 년도별 시퀀스 존재 여부를 확인하고 없으면 생성한다. + * @param year 년도 (YYYY 형태) + */ + private void ensureSequenceExists(String year) { + String sequenceName = SEQ_CRDN + year; + log.debug("년도별 시퀀스 확인 - 시퀀스명: {}", sequenceName); + + try { + // 시퀀스 존재 여부 확인 (SHOW CREATE SEQUENCE 실행) + String sequenceDefinition = crdnRegistAndViewMapper.checkSequenceExists(sequenceName); + log.debug("년도별 시퀀스 이미 존재 - 시퀀스명: {}, 정의: {}", sequenceName, sequenceDefinition); + } catch (Exception e) { + // 시퀀스가 존재하지 않으면 예외 발생 -> 시퀀스 생성 + log.info("년도별 시퀀스 생성 - 시퀀스명: {} (원인: {})", sequenceName, e.getMessage()); + crdnRegistAndViewMapper.createSequence(sequenceName); + log.debug("년도별 시퀀스 생성 완료 - 시퀀스명: {}", sequenceName); + } + } + +} \ No newline at end of file diff --git a/src/main/resources/mybatis/mapper/crdn/crndRegistAndView/main/CrdnRegistAndViewMapper_maria.xml b/src/main/resources/mybatis/mapper/crdn/crndRegistAndView/main/CrdnRegistAndViewMapper_maria.xml index aaa1113..78560e7 100644 --- a/src/main/resources/mybatis/mapper/crdn/crndRegistAndView/main/CrdnRegistAndViewMapper_maria.xml +++ b/src/main/resources/mybatis/mapper/crdn/crndRegistAndView/main/CrdnRegistAndViewMapper_maria.xml @@ -177,7 +177,7 @@ LEFT JOIN tb_cd_detail rgn ON rgn.CD_GROUP_ID = 'RGN_SE_CD' AND rgn.CD_ID = c.RGN_SE_CD LEFT JOIN tb_cd_detail dscl ON dscl.CD_GROUP_ID = 'DSCL_MTHD_CD' AND dscl.CD_ID = c.DSCL_MTHD_CD LEFT JOIN tb_cd_detail stts ON stts.CD_GROUP_ID = 'CRDN_PRCS_STTS_CD' AND stts.CD_ID = c.CRDN_PRCS_STTS_CD - LEFT JOIN tb_user u ON u.USER_ID = c.RGTR AND u.USE_YN = 'Y' + LEFT JOIN tb_user u ON u.USER_ID = c.RGTR WHERE c.DEL_YN = 'N' AND c.CRDN_YR = #{crdnYr} AND c.CRDN_NO = #{crdnNo} diff --git a/src/main/resources/mybatis/mapper/crdn/crndRegistAndView/main/CrdnRelevyMapper_maria.xml b/src/main/resources/mybatis/mapper/crdn/crndRegistAndView/main/CrdnRelevyMapper_maria.xml new file mode 100644 index 0000000..6cc7e34 --- /dev/null +++ b/src/main/resources/mybatis/mapper/crdn/crndRegistAndView/main/CrdnRelevyMapper_maria.xml @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + /* CrdnRelevyMapper.insertCrdnBasicInfo : 기본 단속 정보 복사 */ + INSERT INTO tb_crdn ( + CRDN_YR, /* 단속 연도 - 현재 년도 */ + CRDN_NO, /* 단속 번호 - 신규 생성 */ + SGG_CD, /* 시군구 코드 */ + RGN_SE_CD, /* 지역 구분 코드 */ + DSCL_MTHD_CD, /* 적발 방법 코드 */ + DSCL_YMD, /* 적발 일자 */ + EXMNR, /* 조사원 */ + RMRK, /* 비고 - 재부과 사유 추가 */ + FRST_CRDN_YR, /* 최초 단속 연도 - 원본 단속 연도 */ + FRST_CRDN_NO, /* 최초 단속 번호 - 원본 단속 번호 */ + RELEVY_YN, /* 재부과 여부 - 'Y' */ + AGRVTN_LEVY_TRGT_YN, /* 가중 부과 대상 여부 */ + CRDN_PRCS_STTS_CD, /* 단속 처리 상태 코드 - 30 (시정명령) */ + CRDN_PRCS_YMD, /* 단속 처리 일자 - 현재 일자 */ + REG_DT, + RGTR, + DEL_YN + ) + SELECT + #{newCrdnYr}, /* 현재 년도 */ + #{newCrdnNo}, /* 신규 단속 번호 */ + SGG_CD, + RGN_SE_CD, + DSCL_MTHD_CD, + DSCL_YMD, + EXMNR, + #{relevyRsn}, + #{srcCrdnYr}, /* 원본 단속 연도 */ + #{srcCrdnNo}, /* 원본 단속 번호 */ + 'Y', /* 재부과 여부 */ + AGRVTN_LEVY_TRGT_YN, + '30', /* 시정명령 상태 */ + NOW(), /* 현재 일자 */ + NOW(), + #{rgtr}, + 'N' + FROM tb_crdn + WHERE CRDN_YR = #{srcCrdnYr} + AND CRDN_NO = #{srcCrdnNo} + AND DEL_YN = 'N' + + + + + / CrdnRelevyMapper.insertCrdnPstnInfo : 위치 정보 복사 / + INSERT INTO tb_pstn_info ( + PSTN_INFO_ID, + CRDN_YR, + CRDN_NO, + SGG_CD, + STDG_EMD_CD, + LDCG_CD, + PTOUT, + OALP, + LOTNO_WHOL_ADDR, + ROAD_NM_WHOL_ADDR, + ZIP, + LOTNO_ADDR, + ROAD_NM_ADDR, + DTL_ADDR, + REF_ADDR, + PBADMS_ZONE_CD, + ROAD_NM_CD, + LOTNO_MNO, + LOTNO_SNO, + BLDG_MNO, + BLDG_SNO, + UDGD_YN_CD, + MTN_YN_CD, + RMRK, + REG_DT, + RGTR, + DEL_YN + ) + SELECT + LPAD(NEXTVAL(seq_pstn_info_id), 10, '0'), + #{newCrdnYr}, + #{newCrdnNo}, + SGG_CD, + STDG_EMD_CD, + LDCG_CD, + PTOUT, + OALP, + LOTNO_WHOL_ADDR, + ROAD_NM_WHOL_ADDR, + ZIP, + LOTNO_ADDR, + ROAD_NM_ADDR, + DTL_ADDR, + REF_ADDR, + PBADMS_ZONE_CD, + ROAD_NM_CD, + LOTNO_MNO, + LOTNO_SNO, + BLDG_MNO, + BLDG_SNO, + UDGD_YN_CD, + MTN_YN_CD, + RMRK, + NOW(), + #{rgtr}, + 'N' + FROM tb_pstn_info + WHERE CRDN_YR = #{srcCrdnYr} + AND CRDN_NO = #{srcCrdnNo} + AND DEL_YN = 'N' + + + + + /* CrdnRelevyMapper.insertCrdnOwnrInfo : 소유자 정보 복사 */ + INSERT INTO tb_ownr_info ( + OWNR_INFO_ID, + SGG_CD, + CRDN_YR, + CRDN_NO, + PSTN_INFO_ID, + OWNR_ID, + REG_DT, + RGTR, + DEL_YN + ) + SELECT + LPAD(NEXTVAL(seq_ownr_info_id), 10, '0'), + #{newCrdnYr}, + #{newCrdnNo}, + SGG_CD, + PSTN_INFO_ID, + OWNR_ID, + NOW(), + #{rgtr}, + 'N' + FROM tb_ownr_info + WHERE CRDN_YR = #{srcCrdnYr} + AND CRDN_NO = #{srcCrdnNo} + AND DEL_YN = 'N' + + + + + /* CrdnRelevyMapper.insertCrdnActInfo : 불법행위 정보 복사 (조치완료 제외) */ + INSERT INTO tb_act_info ( + ACT_INFO_ID, + SGG_CD, + CRDN_YR, + CRDN_NO, + PSTN_INFO_ID, + ACT_BGNG_YMD, + ACT_TYPE_CD, + ACT_NO, + VLTN_LWRG_CD_1, + VLTN_LWRG_CD_2, + STRCT_IDX_CD, + USG_IDX_CD, + HGT, + WDTH, + VRTC, + AREA, + RMRK, + ACTN_LAST_YMD, + ACTN_WHOL_AREA, + ACTN_PRCS_STTS_CD, + REG_DT, + RGTR, + DEL_YN + ) + SELECT + LPAD(NEXTVAL(seq_act_info_id), 10, '0'), + SGG_CD, + #{newCrdnYr}, + #{newCrdnNo}, + PSTN_INFO_ID, + ACT_BGNG_YMD, + ACT_TYPE_CD, + ACT_NO, + VLTN_LWRG_CD_1, + VLTN_LWRG_CD_2, + STRCT_IDX_CD, + USG_IDX_CD, + HGT, + WDTH, + VRTC, + AREA, + RMRK, + ACTN_LAST_YMD, + ACTN_WHOL_AREA, + ACTN_PRCS_STTS_CD, + NOW(), + #{rgtr}, + 'N' + FROM tb_act_info + WHERE CRDN_YR = #{srcCrdnYr} + AND CRDN_NO = #{srcCrdnNo} + AND DEL_YN = 'N' + AND (ACTN_PRCS_STTS_CD != '3' OR ACTN_PRCS_STTS_CD IS NULL) /* 조치완료 제외 */ + + + + + /* CrdnRelevyMapper.insertCrdnPhotoInfo : 첨부파일 정보 복사 (조치완료 제외) */ + INSERT INTO tb_crdn_photo ( + ACT_INFO_ID, + CRDN_PHOTO_SN, + SGG_CD, + CRDN_YR, + CRDN_NO, + CRDN_PHOTO_PATH, + CRDN_PHOTO_NM, + CRDN_PHOTO_SE_CD, + ORGNL_PHOTO_NM, + ACTN_INFO_ID, + REG_DT, + RGTR, + DEL_YN + ) + SELECT + a_new.ACT_INFO_ID, /* 새로 생성된 ACT_INFO_ID */ + p.CRDN_PHOTO_SN, + p.SGG_CD, + #{newCrdnYr}, + #{newCrdnNo}, + p.CRDN_PHOTO_PATH, + p.CRDN_PHOTO_NM, /* 물리적 파일 복사 후 서비스에서 업데이트 */ + p.CRDN_PHOTO_SE_CD, + p.ORGNL_PHOTO_NM, + p.ACTN_INFO_ID, + NOW(), + #{rgtr}, + 'N' + FROM tb_crdn_photo p + INNER JOIN tb_act_info a_src ON a_src.CRDN_YR = p.CRDN_YR + AND a_src.CRDN_NO = p.CRDN_NO + AND a_src.ACT_INFO_ID = p.ACT_INFO_ID + AND a_src.DEL_YN = 'N' + INNER JOIN tb_act_info a_new ON a_new.CRDN_YR = #{newCrdnYr} + AND a_new.CRDN_NO = #{newCrdnNo} + AND a_new.ACT_NO = a_src.ACT_NO + AND a_new.DEL_YN = 'N' + WHERE p.CRDN_YR = #{srcCrdnYr} + AND p.CRDN_NO = #{srcCrdnNo} + AND p.DEL_YN = 'N' + AND (a_src.ACTN_PRCS_STTS_CD != '3' OR a_src.ACTN_PRCS_STTS_CD IS NULL) /* 조치완료 제외 */ + + + + + /* CrdnRelevyMapper.insertCrdnActrInfo : 행위자 정보 복사 (조치완료 제외) */ + INSERT INTO tb_actr_info ( + ACTR_INFO_ID, + SGG_CD, + CRDN_YR, + CRDN_NO, + ACT_INFO_ID, + OWNR_ID, + REG_DT, + RGTR, + DEL_YN + ) + SELECT + LPAD(NEXTVAL(seq_actr_info_id), 10, '0'), + a_new.SGG_CD, + a_new.CRDN_YR, + a_new.CRDN_NO, + a_new.ACT_INFO_ID, /* 새로 생성된 ACT_INFO_ID */ + ai.OWNR_ID, + NOW(), + #{rgtr}, + 'N' + FROM tb_actr_info ai + INNER JOIN tb_act_info a_src ON a_src.ACT_INFO_ID = ai.ACT_INFO_ID + AND a_src.DEL_YN = 'N' + INNER JOIN tb_act_info a_new ON a_new.CRDN_YR = #{newCrdnYr} + AND a_new.CRDN_NO = #{newCrdnNo} + AND a_new.ACT_NO = a_src.ACT_NO + AND a_new.DEL_YN = 'N' + WHERE a_src.CRDN_YR = #{srcCrdnYr} + AND a_src.CRDN_NO = #{srcCrdnNo} + AND ai.DEL_YN = 'N' + AND (a_src.ACTN_PRCS_STTS_CD != '3' OR a_src.ACTN_PRCS_STTS_CD IS NULL) /* 조치완료 제외 */ + + + + + /* CrdnRelevyMapper.updateCrdnStatus : 단속 상태 업데이트 */ + UPDATE tb_crdn + SET CRDN_PRCS_STTS_CD = '30', /* 시정명령 */ + FRST_CRDN_YR = #{srcCrdnYr}, /* 최초 단속 연도 */ + FRST_CRDN_NO = #{srcCrdnNo}, /* 최초 단속 번호 */ + RELEVY_YN = 'Y' /* 재부과 여부 */ + WHERE CRDN_YR = #{newCrdnYr} + AND CRDN_NO = #{newCrdnNo} + AND DEL_YN = 'N' + + + + + + + + /* CrdnRelevyMapper.updateRelevyPhotoInfo : 재부과 첨부파일 정보 업데이트 */ + UPDATE tb_crdn_photo + SET CRDN_PHOTO_NM = #{crdnPhotoNm} + WHERE CRDN_YR = #{newCrdnYr} + AND CRDN_NO = #{newCrdnNo} + AND CRDN_PHOTO_SN = #{crdnPhotoSn} + AND DEL_YN = 'N' + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/views/crdn/crndRegistAndView/main/crdnRelevy/relevyPopup.jsp b/src/main/webapp/WEB-INF/views/crdn/crndRegistAndView/main/crdnRelevy/relevyPopup.jsp new file mode 100644 index 0000000..81b6ad3 --- /dev/null +++ b/src/main/webapp/WEB-INF/views/crdn/crndRegistAndView/main/crdnRelevy/relevyPopup.jsp @@ -0,0 +1,226 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%@ taglib prefix="dateUtil" uri="http://egovframework.go.kr/functions/date-util" %> + + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/views/crdn/crndRegistAndView/main/list.jsp b/src/main/webapp/WEB-INF/views/crdn/crndRegistAndView/main/list.jsp index f2c5d9a..55ca63c 100644 --- a/src/main/webapp/WEB-INF/views/crdn/crndRegistAndView/main/list.jsp +++ b/src/main/webapp/WEB-INF/views/crdn/crndRegistAndView/main/list.jsp @@ -101,6 +101,7 @@ + 총 0건